Commit 0d509f2b112b21411712f0bf789b372987967e49

Authored by Mark Brown
1 parent 07c320dc31

regmap: Add asynchronous I/O support

Some use cases like firmware download can transfer a lot of data in quick
succession. With high speed buses these use cases can benefit from having
multiple transfers scheduled at once since this allows the bus to minimise
the delay between transfers.

Support this by adding regmap_raw_write_async(), allowing raw transfers to
be scheduled, and regmap_async_complete() to wait for them to finish.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>

Showing 3 changed files with 215 additions and 10 deletions Side-by-side Diff

drivers/base/regmap/internal.h
... ... @@ -16,6 +16,7 @@
16 16 #include <linux/regmap.h>
17 17 #include <linux/fs.h>
18 18 #include <linux/list.h>
  19 +#include <linux/wait.h>
19 20  
20 21 struct regmap;
21 22 struct regcache_ops;
... ... @@ -39,6 +40,13 @@
39 40 unsigned int (*parse_val)(void *buf);
40 41 };
41 42  
  43 +struct regmap_async {
  44 + struct list_head list;
  45 + struct work_struct cleanup;
  46 + struct regmap *map;
  47 + void *work_buf;
  48 +};
  49 +
42 50 struct regmap {
43 51 struct mutex mutex;
44 52 spinlock_t spinlock;
... ... @@ -53,6 +61,11 @@
53 61 void *bus_context;
54 62 const char *name;
55 63  
  64 + spinlock_t async_lock;
  65 + wait_queue_head_t async_waitq;
  66 + struct list_head async_list;
  67 + int async_ret;
  68 +
56 69 #ifdef CONFIG_DEBUG_FS
57 70 struct dentry *debugfs;
58 71 const char *debugfs_name;
... ... @@ -177,6 +190,8 @@
177 190 bool regcache_set_val(void *base, unsigned int idx,
178 191 unsigned int val, unsigned int word_size);
179 192 int regcache_lookup_reg(struct regmap *map, unsigned int reg);
  193 +
  194 +void regmap_async_complete_cb(struct regmap_async *async, int ret);
180 195  
181 196 extern struct regcache_ops regcache_rbtree_ops;
182 197 extern struct regcache_ops regcache_lzo_ops;
drivers/base/regmap/regmap.c
... ... @@ -41,6 +41,15 @@
41 41 static int _regmap_bus_raw_write(void *context, unsigned int reg,
42 42 unsigned int val);
43 43  
  44 +static void async_cleanup(struct work_struct *work)
  45 +{
  46 + struct regmap_async *async = container_of(work, struct regmap_async,
  47 + cleanup);
  48 +
  49 + kfree(async->work_buf);
  50 + kfree(async);
  51 +}
  52 +
44 53 bool regmap_reg_in_ranges(unsigned int reg,
45 54 const struct regmap_range *ranges,
46 55 unsigned int nranges)
... ... @@ -430,6 +439,10 @@
430 439 map->cache_type = config->cache_type;
431 440 map->name = config->name;
432 441  
  442 + spin_lock_init(&map->async_lock);
  443 + INIT_LIST_HEAD(&map->async_list);
  444 + init_waitqueue_head(&map->async_waitq);
  445 +
433 446 if (config->read_flag_mask || config->write_flag_mask) {
434 447 map->read_flag_mask = config->read_flag_mask;
435 448 map->write_flag_mask = config->write_flag_mask;
436 449  
437 450  
... ... @@ -884,10 +897,13 @@
884 897 }
885 898  
886 899 static int _regmap_raw_write(struct regmap *map, unsigned int reg,
887   - const void *val, size_t val_len)
  900 + const void *val, size_t val_len, bool async)
888 901 {
889 902 struct regmap_range_node *range;
  903 + unsigned long flags;
890 904 u8 *u8 = map->work_buf;
  905 + void *work_val = map->work_buf + map->format.reg_bytes +
  906 + map->format.pad_bytes;
891 907 void *buf;
892 908 int ret = -ENOTSUPP;
893 909 size_t len;
... ... @@ -932,7 +948,7 @@
932 948 dev_dbg(map->dev, "Writing window %d/%zu\n",
933 949 win_residue, val_len / map->format.val_bytes);
934 950 ret = _regmap_raw_write(map, reg, val, win_residue *
935   - map->format.val_bytes);
  951 + map->format.val_bytes, async);
936 952 if (ret != 0)
937 953 return ret;
938 954  
... ... @@ -955,6 +971,50 @@
955 971  
956 972 u8[0] |= map->write_flag_mask;
957 973  
  974 + if (async && map->bus->async_write) {
  975 + struct regmap_async *async = map->bus->async_alloc();
  976 + if (!async)
  977 + return -ENOMEM;
  978 +
  979 + async->work_buf = kzalloc(map->format.buf_size,
  980 + GFP_KERNEL | GFP_DMA);
  981 + if (!async->work_buf) {
  982 + kfree(async);
  983 + return -ENOMEM;
  984 + }
  985 +
  986 + INIT_WORK(&async->cleanup, async_cleanup);
  987 + async->map = map;
  988 +
  989 + /* If the caller supplied the value we can use it safely. */
  990 + memcpy(async->work_buf, map->work_buf, map->format.pad_bytes +
  991 + map->format.reg_bytes + map->format.val_bytes);
  992 + if (val == work_val)
  993 + val = async->work_buf + map->format.pad_bytes +
  994 + map->format.reg_bytes;
  995 +
  996 + spin_lock_irqsave(&map->async_lock, flags);
  997 + list_add_tail(&async->list, &map->async_list);
  998 + spin_unlock_irqrestore(&map->async_lock, flags);
  999 +
  1000 + ret = map->bus->async_write(map->bus_context, async->work_buf,
  1001 + map->format.reg_bytes +
  1002 + map->format.pad_bytes,
  1003 + val, val_len, async);
  1004 +
  1005 + if (ret != 0) {
  1006 + dev_err(map->dev, "Failed to schedule write: %d\n",
  1007 + ret);
  1008 +
  1009 + spin_lock_irqsave(&map->async_lock, flags);
  1010 + list_del(&async->list);
  1011 + spin_unlock_irqrestore(&map->async_lock, flags);
  1012 +
  1013 + kfree(async->work_buf);
  1014 + kfree(async);
  1015 + }
  1016 + }
  1017 +
958 1018 trace_regmap_hw_write_start(map->dev, reg,
959 1019 val_len / map->format.val_bytes);
960 1020  
... ... @@ -962,8 +1022,7 @@
962 1022 * send the work_buf directly, otherwise try to do a gather
963 1023 * write.
964 1024 */
965   - if (val == (map->work_buf + map->format.pad_bytes +
966   - map->format.reg_bytes))
  1025 + if (val == work_val)
967 1026 ret = map->bus->write(map->bus_context, map->work_buf,
968 1027 map->format.reg_bytes +
969 1028 map->format.pad_bytes +
... ... @@ -1036,7 +1095,7 @@
1036 1095 map->work_buf +
1037 1096 map->format.reg_bytes +
1038 1097 map->format.pad_bytes,
1039   - map->format.val_bytes);
  1098 + map->format.val_bytes, false);
1040 1099 }
1041 1100  
1042 1101 int _regmap_write(struct regmap *map, unsigned int reg,
... ... @@ -1119,7 +1178,7 @@
1119 1178  
1120 1179 map->lock(map->lock_arg);
1121 1180  
1122   - ret = _regmap_raw_write(map, reg, val, val_len);
  1181 + ret = _regmap_raw_write(map, reg, val, val_len, false);
1123 1182  
1124 1183 map->unlock(map->lock_arg);
1125 1184  
1126 1185  
... ... @@ -1175,14 +1234,15 @@
1175 1234 if (map->use_single_rw) {
1176 1235 for (i = 0; i < val_count; i++) {
1177 1236 ret = regmap_raw_write(map,
1178   - reg + (i * map->reg_stride),
1179   - val + (i * val_bytes),
1180   - val_bytes);
  1237 + reg + (i * map->reg_stride),
  1238 + val + (i * val_bytes),
  1239 + val_bytes);
1181 1240 if (ret != 0)
1182 1241 return ret;
1183 1242 }
1184 1243 } else {
1185   - ret = _regmap_raw_write(map, reg, wval, val_bytes * val_count);
  1244 + ret = _regmap_raw_write(map, reg, wval, val_bytes * val_count,
  1245 + false);
1186 1246 }
1187 1247  
1188 1248 if (val_bytes != 1)
... ... @@ -1194,6 +1254,48 @@
1194 1254 }
1195 1255 EXPORT_SYMBOL_GPL(regmap_bulk_write);
1196 1256  
  1257 +/**
  1258 + * regmap_raw_write_async(): Write raw values to one or more registers
  1259 + * asynchronously
  1260 + *
  1261 + * @map: Register map to write to
  1262 + * @reg: Initial register to write to
  1263 + * @val: Block of data to be written, laid out for direct transmission to the
  1264 + * device. Must be valid until regmap_async_complete() is called.
  1265 + * @val_len: Length of data pointed to by val.
  1266 + *
  1267 + * This function is intended to be used for things like firmware
  1268 + * download where a large block of data needs to be transferred to the
  1269 + * device. No formatting will be done on the data provided.
  1270 + *
  1271 + * If supported by the underlying bus the write will be scheduled
  1272 + * asynchronously, helping maximise I/O speed on higher speed buses
  1273 + * like SPI. regmap_async_complete() can be called to ensure that all
  1274 + * asynchrnous writes have been completed.
  1275 + *
  1276 + * A value of zero will be returned on success, a negative errno will
  1277 + * be returned in error cases.
  1278 + */
  1279 +int regmap_raw_write_async(struct regmap *map, unsigned int reg,
  1280 + const void *val, size_t val_len)
  1281 +{
  1282 + int ret;
  1283 +
  1284 + if (val_len % map->format.val_bytes)
  1285 + return -EINVAL;
  1286 + if (reg % map->reg_stride)
  1287 + return -EINVAL;
  1288 +
  1289 + map->lock(map->lock_arg);
  1290 +
  1291 + ret = _regmap_raw_write(map, reg, val, val_len, true);
  1292 +
  1293 + map->unlock(map->lock_arg);
  1294 +
  1295 + return ret;
  1296 +}
  1297 +EXPORT_SYMBOL_GPL(regmap_raw_write_async);
  1298 +
1197 1299 static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
1198 1300 unsigned int val_len)
1199 1301 {
... ... @@ -1491,6 +1593,66 @@
1491 1593 return ret;
1492 1594 }
1493 1595 EXPORT_SYMBOL_GPL(regmap_update_bits_check);
  1596 +
  1597 +void regmap_async_complete_cb(struct regmap_async *async, int ret)
  1598 +{
  1599 + struct regmap *map = async->map;
  1600 + bool wake;
  1601 +
  1602 + spin_lock(&map->async_lock);
  1603 +
  1604 + list_del(&async->list);
  1605 + wake = list_empty(&map->async_list);
  1606 +
  1607 + if (ret != 0)
  1608 + map->async_ret = ret;
  1609 +
  1610 + spin_unlock(&map->async_lock);
  1611 +
  1612 + schedule_work(&async->cleanup);
  1613 +
  1614 + if (wake)
  1615 + wake_up(&map->async_waitq);
  1616 +}
  1617 +
  1618 +static int regmap_async_is_done(struct regmap *map)
  1619 +{
  1620 + unsigned long flags;
  1621 + int ret;
  1622 +
  1623 + spin_lock_irqsave(&map->async_lock, flags);
  1624 + ret = list_empty(&map->async_list);
  1625 + spin_unlock_irqrestore(&map->async_lock, flags);
  1626 +
  1627 + return ret;
  1628 +}
  1629 +
  1630 +/**
  1631 + * regmap_async_complete: Ensure all asynchronous I/O has completed.
  1632 + *
  1633 + * @map: Map to operate on.
  1634 + *
  1635 + * Blocks until any pending asynchronous I/O has completed. Returns
  1636 + * an error code for any failed I/O operations.
  1637 + */
  1638 +int regmap_async_complete(struct regmap *map)
  1639 +{
  1640 + unsigned long flags;
  1641 + int ret;
  1642 +
  1643 + /* Nothing to do with no async support */
  1644 + if (!map->bus->async_write)
  1645 + return 0;
  1646 +
  1647 + wait_event(map->async_waitq, regmap_async_is_done(map));
  1648 +
  1649 + spin_lock_irqsave(&map->async_lock, flags);
  1650 + ret = map->async_ret;
  1651 + map->async_ret = 0;
  1652 + spin_unlock_irqrestore(&map->async_lock, flags);
  1653 +
  1654 + return ret;
  1655 +}
1494 1656  
1495 1657 /**
1496 1658 * regmap_register_patch: Register and apply register updates to be applied
include/linux/regmap.h
... ... @@ -235,14 +235,21 @@
235 235 unsigned int window_len;
236 236 };
237 237  
  238 +struct regmap_async;
  239 +
238 240 typedef int (*regmap_hw_write)(void *context, const void *data,
239 241 size_t count);
240 242 typedef int (*regmap_hw_gather_write)(void *context,
241 243 const void *reg, size_t reg_len,
242 244 const void *val, size_t val_len);
  245 +typedef int (*regmap_hw_async_write)(void *context,
  246 + const void *reg, size_t reg_len,
  247 + const void *val, size_t val_len,
  248 + struct regmap_async *async);
243 249 typedef int (*regmap_hw_read)(void *context,
244 250 const void *reg_buf, size_t reg_size,
245 251 void *val_buf, size_t val_size);
  252 +typedef struct regmap_async *(*regmap_hw_async_alloc)(void);
246 253 typedef void (*regmap_hw_free_context)(void *context);
247 254  
248 255 /**
249 256  
... ... @@ -255,8 +262,11 @@
255 262 * @write: Write operation.
256 263 * @gather_write: Write operation with split register/value, return -ENOTSUPP
257 264 * if not implemented on a given device.
  265 + * @async_write: Write operation which completes asynchronously, optional and
  266 + * must serialise with respect to non-async I/O.
258 267 * @read: Read operation. Data is returned in the buffer used to transmit
259 268 * data.
  269 + * @async_alloc: Allocate a regmap_async() structure.
260 270 * @read_flag_mask: Mask to be set in the top byte of the register when doing
261 271 * a read.
262 272 * @reg_format_endian_default: Default endianness for formatted register
263 273  
264 274  
... ... @@ -265,13 +275,16 @@
265 275 * @val_format_endian_default: Default endianness for formatted register
266 276 * values. Used when the regmap_config specifies DEFAULT. If this is
267 277 * DEFAULT, BIG is assumed.
  278 + * @async_size: Size of struct used for async work.
268 279 */
269 280 struct regmap_bus {
270 281 bool fast_io;
271 282 regmap_hw_write write;
272 283 regmap_hw_gather_write gather_write;
  284 + regmap_hw_async_write async_write;
273 285 regmap_hw_read read;
274 286 regmap_hw_free_context free_context;
  287 + regmap_hw_async_alloc async_alloc;
275 288 u8 read_flag_mask;
276 289 enum regmap_endian reg_format_endian_default;
277 290 enum regmap_endian val_format_endian_default;
... ... @@ -310,6 +323,8 @@
310 323 const void *val, size_t val_len);
311 324 int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
312 325 size_t val_count);
  326 +int regmap_raw_write_async(struct regmap *map, unsigned int reg,
  327 + const void *val, size_t val_len);
313 328 int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val);
314 329 int regmap_raw_read(struct regmap *map, unsigned int reg,
315 330 void *val, size_t val_len);
... ... @@ -321,6 +336,7 @@
321 336 unsigned int mask, unsigned int val,
322 337 bool *change);
323 338 int regmap_get_val_bytes(struct regmap *map);
  339 +int regmap_async_complete(struct regmap *map);
324 340  
325 341 int regcache_sync(struct regmap *map);
326 342 int regcache_sync_region(struct regmap *map, unsigned int min,
... ... @@ -422,6 +438,13 @@
422 438 return -EINVAL;
423 439 }
424 440  
  441 +static inline int regmap_raw_write_async(struct regmap *map, unsigned int reg,
  442 + const void *val, size_t val_len)
  443 +{
  444 + WARN_ONCE(1, "regmap API is disabled");
  445 + return -EINVAL;
  446 +}
  447 +
425 448 static inline int regmap_bulk_write(struct regmap *map, unsigned int reg,
426 449 const void *val, size_t val_count)
427 450 {
... ... @@ -496,6 +519,11 @@
496 519 }
497 520  
498 521 static inline void regcache_mark_dirty(struct regmap *map)
  522 +{
  523 + WARN_ONCE(1, "regmap API is disabled");
  524 +}
  525 +
  526 +static inline void regmap_async_complete(struct regmap *map)
499 527 {
500 528 WARN_ONCE(1, "regmap API is disabled");
501 529 }