|
@@ -42,15 +42,6 @@ static int _regmap_bus_formatted_write(void *context, unsigned int reg,
|
|
|
static int _regmap_bus_raw_write(void *context, unsigned int reg,
|
|
|
unsigned int val);
|
|
|
|
|
|
-static void async_cleanup(struct work_struct *work)
|
|
|
-{
|
|
|
- struct regmap_async *async = container_of(work, struct regmap_async,
|
|
|
- cleanup);
|
|
|
-
|
|
|
- kfree(async->work_buf);
|
|
|
- kfree(async);
|
|
|
-}
|
|
|
-
|
|
|
bool regmap_reg_in_ranges(unsigned int reg,
|
|
|
const struct regmap_range *ranges,
|
|
|
unsigned int nranges)
|
|
@@ -465,6 +456,7 @@ struct regmap *regmap_init(struct device *dev,
|
|
|
|
|
|
spin_lock_init(&map->async_lock);
|
|
|
INIT_LIST_HEAD(&map->async_list);
|
|
|
+ INIT_LIST_HEAD(&map->async_free);
|
|
|
init_waitqueue_head(&map->async_waitq);
|
|
|
|
|
|
if (config->read_flag_mask || config->write_flag_mask) {
|
|
@@ -942,12 +934,22 @@ EXPORT_SYMBOL_GPL(regmap_reinit_cache);
|
|
|
*/
|
|
|
void regmap_exit(struct regmap *map)
|
|
|
{
|
|
|
+ struct regmap_async *async;
|
|
|
+
|
|
|
regcache_exit(map);
|
|
|
regmap_debugfs_exit(map);
|
|
|
regmap_range_exit(map);
|
|
|
if (map->bus && map->bus->free_context)
|
|
|
map->bus->free_context(map->bus_context);
|
|
|
kfree(map->work_buf);
|
|
|
+ while (!list_empty(&map->async_free)) {
|
|
|
+ async = list_first_entry_or_null(&map->async_free,
|
|
|
+ struct regmap_async,
|
|
|
+ list);
|
|
|
+ list_del(&async->list);
|
|
|
+ kfree(async->work_buf);
|
|
|
+ kfree(async);
|
|
|
+ }
|
|
|
kfree(map);
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(regmap_exit);
|
|
@@ -1115,20 +1117,31 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg,
|
|
|
u8[0] |= map->write_flag_mask;
|
|
|
|
|
|
if (async && map->bus->async_write) {
|
|
|
- struct regmap_async *async = map->bus->async_alloc();
|
|
|
- if (!async)
|
|
|
- return -ENOMEM;
|
|
|
+ struct regmap_async *async;
|
|
|
|
|
|
trace_regmap_async_write_start(map->dev, reg, val_len);
|
|
|
|
|
|
- async->work_buf = kzalloc(map->format.buf_size,
|
|
|
- GFP_KERNEL | GFP_DMA);
|
|
|
- if (!async->work_buf) {
|
|
|
- kfree(async);
|
|
|
- return -ENOMEM;
|
|
|
+ spin_lock_irqsave(&map->async_lock, flags);
|
|
|
+ async = list_first_entry_or_null(&map->async_free,
|
|
|
+ struct regmap_async,
|
|
|
+ list);
|
|
|
+ if (async)
|
|
|
+ list_del(&async->list);
|
|
|
+ spin_unlock_irqrestore(&map->async_lock, flags);
|
|
|
+
|
|
|
+ if (!async) {
|
|
|
+ async = map->bus->async_alloc();
|
|
|
+ if (!async)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ async->work_buf = kzalloc(map->format.buf_size,
|
|
|
+ GFP_KERNEL | GFP_DMA);
|
|
|
+ if (!async->work_buf) {
|
|
|
+ kfree(async);
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- INIT_WORK(&async->cleanup, async_cleanup);
|
|
|
async->map = map;
|
|
|
|
|
|
/* If the caller supplied the value we can use it safely. */
|
|
@@ -1152,11 +1165,8 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg,
|
|
|
ret);
|
|
|
|
|
|
spin_lock_irqsave(&map->async_lock, flags);
|
|
|
- list_del(&async->list);
|
|
|
+ list_move(&async->list, &map->async_free);
|
|
|
spin_unlock_irqrestore(&map->async_lock, flags);
|
|
|
-
|
|
|
- kfree(async->work_buf);
|
|
|
- kfree(async);
|
|
|
}
|
|
|
|
|
|
return ret;
|
|
@@ -1820,8 +1830,7 @@ void regmap_async_complete_cb(struct regmap_async *async, int ret)
|
|
|
trace_regmap_async_io_complete(map->dev);
|
|
|
|
|
|
spin_lock(&map->async_lock);
|
|
|
-
|
|
|
- list_del(&async->list);
|
|
|
+ list_move(&async->list, &map->async_free);
|
|
|
wake = list_empty(&map->async_list);
|
|
|
|
|
|
if (ret != 0)
|
|
@@ -1829,8 +1838,6 @@ void regmap_async_complete_cb(struct regmap_async *async, int ret)
|
|
|
|
|
|
spin_unlock(&map->async_lock);
|
|
|
|
|
|
- schedule_work(&async->cleanup);
|
|
|
-
|
|
|
if (wake)
|
|
|
wake_up(&map->async_waitq);
|
|
|
}
|