diff options
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/core.c | 11 | ||||
-rw-r--r-- | drivers/base/dd.c | 2 | ||||
-rw-r--r-- | drivers/base/regmap/regcache-maple.c | 70 | ||||
-rw-r--r-- | drivers/base/regmap/regcache-rbtree.c | 10 | ||||
-rw-r--r-- | drivers/base/test/test_async_driver_probe.c | 2 |
5 files changed, 77 insertions, 18 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c index 3dff5037943e..6ceaf50f5a67 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -3817,6 +3817,17 @@ void device_del(struct device *dev) device_platform_notify_remove(dev); device_links_purge(dev); + /* + * If a device does not have a driver attached, we need to clean + * up any managed resources. We do this in device_release(), but + * it's never called (and we leak the device) if a managed + * resource holds a reference to the device. So release all + * managed resources here, like we do in driver_detach(). We + * still need to do so again in device_release() in case someone + * adds a new resource after this point, though. + */ + devres_release_all(dev); + bus_notify(dev, BUS_NOTIFY_REMOVED_DEVICE); kobject_uevent(&dev->kobj, KOBJ_REMOVE); glue_dir = get_glue_dir(dev); diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 9c09ca5c4ab6..7145d9b940b1 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -693,6 +693,8 @@ re_probe: device_remove(dev); driver_sysfs_remove(dev); + if (dev->bus && dev->bus->dma_cleanup) + dev->bus->dma_cleanup(dev); device_unbind_cleanup(dev); goto re_probe; diff --git a/drivers/base/regmap/regcache-maple.c b/drivers/base/regmap/regcache-maple.c index c2e3a0f6c218..08316d578be2 100644 --- a/drivers/base/regmap/regcache-maple.c +++ b/drivers/base/regmap/regcache-maple.c @@ -74,7 +74,7 @@ static int regcache_maple_write(struct regmap *map, unsigned int reg, rcu_read_unlock(); entry = kmalloc((last - index + 1) * sizeof(unsigned long), - GFP_KERNEL); + map->alloc_flags); if (!entry) return -ENOMEM; @@ -92,7 +92,7 @@ static int regcache_maple_write(struct regmap *map, unsigned int reg, mas_lock(&mas); mas_set_range(&mas, index, last); - ret = mas_store_gfp(&mas, entry, GFP_KERNEL); + ret = mas_store_gfp(&mas, entry, map->alloc_flags); mas_unlock(&mas); @@ -134,7 +134,7 @@ static int regcache_maple_drop(struct regmap *map, unsigned int min, lower = kmemdup(entry, ((min - mas.index) * sizeof(unsigned long)), - GFP_KERNEL); + map->alloc_flags); if (!lower) { ret = -ENOMEM; goto out_unlocked; @@ -148,7 +148,7 @@ static int regcache_maple_drop(struct regmap *map, unsigned int min, upper = kmemdup(&entry[max + 1], ((mas.last - max) * sizeof(unsigned long)), - GFP_KERNEL); + map->alloc_flags); if (!upper) { ret = -ENOMEM; goto out_unlocked; @@ -162,7 +162,7 @@ static int regcache_maple_drop(struct regmap *map, unsigned int min, /* Insert new nodes with the saved data */ if (lower) { mas_set_range(&mas, lower_index, lower_last); - ret = mas_store_gfp(&mas, lower, GFP_KERNEL); + ret = mas_store_gfp(&mas, lower, map->alloc_flags); if (ret != 0) goto out; lower = NULL; @@ -170,7 +170,7 @@ static int regcache_maple_drop(struct regmap *map, unsigned int min, if (upper) { mas_set_range(&mas, upper_index, upper_last); - ret = mas_store_gfp(&mas, upper, GFP_KERNEL); + ret = mas_store_gfp(&mas, upper, map->alloc_flags); if (ret != 0) goto out; upper = NULL; @@ -242,11 +242,41 @@ static int regcache_maple_exit(struct regmap *map) return 0; } +static int regcache_maple_insert_block(struct regmap *map, int first, + int last) +{ + struct maple_tree *mt = map->cache; + MA_STATE(mas, mt, first, last); + unsigned long *entry; + int i, ret; + + entry = kcalloc(last - first + 1, sizeof(unsigned long), map->alloc_flags); + if (!entry) + return -ENOMEM; + + for (i = 0; i < last - first + 1; i++) + entry[i] = map->reg_defaults[first + i].def; + + mas_lock(&mas); + + mas_set_range(&mas, map->reg_defaults[first].reg, + map->reg_defaults[last].reg); + ret = mas_store_gfp(&mas, entry, map->alloc_flags); + + mas_unlock(&mas); + + if (ret) + kfree(entry); + + return ret; +} + static int regcache_maple_init(struct regmap *map) { struct maple_tree *mt; int i; int ret; + int range_start; mt = kmalloc(sizeof(*mt), GFP_KERNEL); if (!mt) @@ -255,14 +285,30 @@ static int regcache_maple_init(struct regmap *map) mt_init(mt); - for (i = 0; i < map->num_reg_defaults; i++) { - ret = regcache_maple_write(map, - map->reg_defaults[i].reg, - map->reg_defaults[i].def); - if (ret) - goto err; + if (!map->num_reg_defaults) + return 0; + + range_start = 0; + + /* Scan for ranges of contiguous registers */ + for (i = 1; i < map->num_reg_defaults; i++) { + if (map->reg_defaults[i].reg != + map->reg_defaults[i - 1].reg + 1) { + ret = regcache_maple_insert_block(map, range_start, + i - 1); + if (ret != 0) + goto err; + + range_start = i; + } } + /* Add the last block */ + ret = regcache_maple_insert_block(map, range_start, + map->num_reg_defaults - 1); + if (ret != 0) + goto err; + return 0; err: diff --git a/drivers/base/regmap/regcache-rbtree.c b/drivers/base/regmap/regcache-rbtree.c index fabf87058d80..ae6b8788d5f3 100644 --- a/drivers/base/regmap/regcache-rbtree.c +++ b/drivers/base/regmap/regcache-rbtree.c @@ -277,7 +277,7 @@ static int regcache_rbtree_insert_to_block(struct regmap *map, blk = krealloc(rbnode->block, blklen * map->cache_word_size, - GFP_KERNEL); + map->alloc_flags); if (!blk) return -ENOMEM; @@ -286,7 +286,7 @@ static int regcache_rbtree_insert_to_block(struct regmap *map, if (BITS_TO_LONGS(blklen) > BITS_TO_LONGS(rbnode->blklen)) { present = krealloc(rbnode->cache_present, BITS_TO_LONGS(blklen) * sizeof(*present), - GFP_KERNEL); + map->alloc_flags); if (!present) return -ENOMEM; @@ -320,7 +320,7 @@ regcache_rbtree_node_alloc(struct regmap *map, unsigned int reg) const struct regmap_range *range; int i; - rbnode = kzalloc(sizeof(*rbnode), GFP_KERNEL); + rbnode = kzalloc(sizeof(*rbnode), map->alloc_flags); if (!rbnode) return NULL; @@ -346,13 +346,13 @@ regcache_rbtree_node_alloc(struct regmap *map, unsigned int reg) } rbnode->block = kmalloc_array(rbnode->blklen, map->cache_word_size, - GFP_KERNEL); + map->alloc_flags); if (!rbnode->block) goto err_free; rbnode->cache_present = kcalloc(BITS_TO_LONGS(rbnode->blklen), sizeof(*rbnode->cache_present), - GFP_KERNEL); + map->alloc_flags); if (!rbnode->cache_present) goto err_free_block; diff --git a/drivers/base/test/test_async_driver_probe.c b/drivers/base/test/test_async_driver_probe.c index 929410d0dd6f..3465800baa6c 100644 --- a/drivers/base/test/test_async_driver_probe.c +++ b/drivers/base/test/test_async_driver_probe.c @@ -84,7 +84,7 @@ test_platform_device_register_node(char *name, int id, int nid) pdev = platform_device_alloc(name, id); if (!pdev) - return NULL; + return ERR_PTR(-ENOMEM); if (nid != NUMA_NO_NODE) set_dev_node(&pdev->dev, nid); |