Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'regmap-v6.19' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap

Pull regmap updates from Mark Brown:
"Another small update for regmap, we have one new feature plus a little
bit of cleanup:

- Support for sparseness information in the flat cache, allowing
users that really need the performance properties it provides to
benefit from the interface and startup time improvements that
sparsness provides without needing to go all the way to a more
fancy data structure

- Cleanup work from Andy Shevchenko, refactoring the cache interface
in preparation for some future stuff he's working on"

* tag 'regmap-v6.19' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap:
regmap: sdw-mbq: Reorder regmap_mbq_context struct for better packing
regmap: i3c: Use ARRAY_SIZE()
regcache: maple: Split ->populate() from ->init()
regcache: flat: Split ->populate() from ->init()
regcache: flat: Remove unneeded check and error message for -ENOMEM
regcache: rbtree: Split ->populate() from ->init()
regcache: Add ->populate() callback to separate from ->init()
regmap: warn users about uninitialized flat cache
regmap: add flat cache with sparse validity

+189 -68
+2
drivers/base/regmap/internal.h
··· 186 186 enum regcache_type type; 187 187 int (*init)(struct regmap *map); 188 188 int (*exit)(struct regmap *map); 189 + int (*populate)(struct regmap *map); 189 190 #ifdef CONFIG_DEBUG_FS 190 191 void (*debugfs_init)(struct regmap *map); 191 192 #endif ··· 289 288 const struct regmap_bus *bus, 290 289 const struct regmap_config *config); 291 290 291 + extern struct regcache_ops regcache_flat_sparse_ops; 292 292 extern struct regcache_ops regcache_rbtree_ops; 293 293 extern struct regcache_ops regcache_maple_ops; 294 294 extern struct regcache_ops regcache_flat_ops;
+94 -19
drivers/base/regmap/regcache-flat.c
··· 6 6 // 7 7 // Author: Mark Brown <broonie@opensource.wolfsonmicro.com> 8 8 9 + #include <linux/bitmap.h> 10 + #include <linux/bitops.h> 9 11 #include <linux/device.h> 12 + #include <linux/limits.h> 13 + #include <linux/overflow.h> 10 14 #include <linux/seq_file.h> 11 15 #include <linux/slab.h> 12 16 ··· 22 18 return regcache_get_index_by_order(map, reg); 23 19 } 24 20 21 + struct regcache_flat_data { 22 + unsigned long *valid; 23 + unsigned int data[]; 24 + }; 25 + 25 26 static int regcache_flat_init(struct regmap *map) 26 27 { 27 - int i; 28 - unsigned int *cache; 28 + unsigned int cache_size; 29 + struct regcache_flat_data *cache; 29 30 30 31 if (!map || map->reg_stride_order < 0 || !map->max_register_is_set) 31 32 return -EINVAL; 32 33 33 - map->cache = kcalloc(regcache_flat_get_index(map, map->max_register) 34 - + 1, sizeof(unsigned int), map->alloc_flags); 35 - if (!map->cache) 34 + cache_size = regcache_flat_get_index(map, map->max_register) + 1; 35 + cache = kzalloc(struct_size(cache, data, cache_size), map->alloc_flags); 36 + if (!cache) 36 37 return -ENOMEM; 37 38 38 - cache = map->cache; 39 + cache->valid = bitmap_zalloc(cache_size, map->alloc_flags); 40 + if (!cache->valid) 41 + goto err_free; 42 + 43 + map->cache = cache; 44 + 45 + return 0; 46 + 47 + err_free: 48 + kfree(cache); 49 + return -ENOMEM; 50 + } 51 + 52 + static int regcache_flat_exit(struct regmap *map) 53 + { 54 + struct regcache_flat_data *cache = map->cache; 55 + 56 + if (cache) 57 + bitmap_free(cache->valid); 58 + 59 + kfree(cache); 60 + map->cache = NULL; 61 + 62 + return 0; 63 + } 64 + 65 + static int regcache_flat_populate(struct regmap *map) 66 + { 67 + struct regcache_flat_data *cache = map->cache; 68 + unsigned int i; 39 69 40 70 for (i = 0; i < map->num_reg_defaults; i++) { 41 71 unsigned int reg = map->reg_defaults[i].reg; 42 72 unsigned int index = regcache_flat_get_index(map, reg); 43 73 44 - cache[index] = map->reg_defaults[i].def; 74 + cache->data[index] = map->reg_defaults[i].def; 75 + __set_bit(index, cache->valid); 45 76 } 46 - 47 - return 0; 48 - } 49 - 50 - static int regcache_flat_exit(struct regmap *map) 51 - { 52 - kfree(map->cache); 53 - map->cache = NULL; 54 77 55 78 return 0; 56 79 } ··· 85 54 static int regcache_flat_read(struct regmap *map, 86 55 unsigned int reg, unsigned int *value) 87 56 { 88 - unsigned int *cache = map->cache; 57 + struct regcache_flat_data *cache = map->cache; 89 58 unsigned int index = regcache_flat_get_index(map, reg); 90 59 91 - *value = cache[index]; 60 + /* legacy behavior: ignore validity, but warn the user */ 61 + if (unlikely(!test_bit(index, cache->valid))) 62 + dev_warn_once(map->dev, 63 + "using zero-initialized flat cache, this may cause unexpected behavior"); 64 + 65 + *value = cache->data[index]; 66 + 67 + return 0; 68 + } 69 + 70 + static int regcache_flat_sparse_read(struct regmap *map, 71 + unsigned int reg, unsigned int *value) 72 + { 73 + struct regcache_flat_data *cache = map->cache; 74 + unsigned int index = regcache_flat_get_index(map, reg); 75 + 76 + if (unlikely(!test_bit(index, cache->valid))) 77 + return -ENOENT; 78 + 79 + *value = cache->data[index]; 92 80 93 81 return 0; 94 82 } ··· 115 65 static int regcache_flat_write(struct regmap *map, unsigned int reg, 116 66 unsigned int value) 117 67 { 118 - unsigned int *cache = map->cache; 68 + struct regcache_flat_data *cache = map->cache; 119 69 unsigned int index = regcache_flat_get_index(map, reg); 120 70 121 - cache[index] = value; 71 + cache->data[index] = value; 72 + __set_bit(index, cache->valid); 73 + 74 + return 0; 75 + } 76 + 77 + static int regcache_flat_drop(struct regmap *map, unsigned int min, 78 + unsigned int max) 79 + { 80 + struct regcache_flat_data *cache = map->cache; 81 + unsigned int bitmap_min = regcache_flat_get_index(map, min); 82 + unsigned int bitmap_max = regcache_flat_get_index(map, max); 83 + 84 + bitmap_clear(cache->valid, bitmap_min, bitmap_max + 1 - bitmap_min); 122 85 123 86 return 0; 124 87 } ··· 141 78 .name = "flat", 142 79 .init = regcache_flat_init, 143 80 .exit = regcache_flat_exit, 81 + .populate = regcache_flat_populate, 144 82 .read = regcache_flat_read, 145 83 .write = regcache_flat_write, 84 + }; 85 + 86 + struct regcache_ops regcache_flat_sparse_ops = { 87 + .type = REGCACHE_FLAT_S, 88 + .name = "flat-sparse", 89 + .init = regcache_flat_init, 90 + .exit = regcache_flat_exit, 91 + .populate = regcache_flat_populate, 92 + .read = regcache_flat_sparse_read, 93 + .write = regcache_flat_write, 94 + .drop = regcache_flat_drop, 146 95 };
+21 -26
drivers/base/regmap/regcache-maple.c
··· 289 289 return ret; 290 290 } 291 291 292 + static int regcache_maple_init(struct regmap *map) 293 + { 294 + struct maple_tree *mt; 295 + 296 + mt = kmalloc(sizeof(*mt), map->alloc_flags); 297 + if (!mt) 298 + return -ENOMEM; 299 + map->cache = mt; 300 + 301 + mt_init(mt); 302 + 303 + if (!mt_external_lock(mt) && map->lock_key) 304 + lockdep_set_class_and_subclass(&mt->ma_lock, map->lock_key, 1); 305 + 306 + return 0; 307 + } 308 + 292 309 static int regcache_maple_exit(struct regmap *map) 293 310 { 294 311 struct maple_tree *mt = map->cache; ··· 357 340 return ret; 358 341 } 359 342 360 - static int regcache_maple_init(struct regmap *map) 343 + static int regcache_maple_populate(struct regmap *map) 361 344 { 362 - struct maple_tree *mt; 363 345 int i; 364 346 int ret; 365 347 int range_start; 366 - 367 - mt = kmalloc(sizeof(*mt), map->alloc_flags); 368 - if (!mt) 369 - return -ENOMEM; 370 - map->cache = mt; 371 - 372 - mt_init(mt); 373 - 374 - if (!mt_external_lock(mt) && map->lock_key) 375 - lockdep_set_class_and_subclass(&mt->ma_lock, map->lock_key, 1); 376 - 377 - if (!map->num_reg_defaults) 378 - return 0; 379 348 380 349 range_start = 0; 381 350 ··· 372 369 ret = regcache_maple_insert_block(map, range_start, 373 370 i - 1); 374 371 if (ret != 0) 375 - goto err; 372 + return ret; 376 373 377 374 range_start = i; 378 375 } 379 376 } 380 377 381 378 /* Add the last block */ 382 - ret = regcache_maple_insert_block(map, range_start, 383 - map->num_reg_defaults - 1); 384 - if (ret != 0) 385 - goto err; 386 - 387 - return 0; 388 - 389 - err: 390 - regcache_maple_exit(map); 391 - return ret; 379 + return regcache_maple_insert_block(map, range_start, map->num_reg_defaults - 1); 392 380 } 393 381 394 382 struct regcache_ops regcache_maple_ops = { ··· 387 393 .name = "maple", 388 394 .init = regcache_maple_init, 389 395 .exit = regcache_maple_exit, 396 + .populate = regcache_maple_populate, 390 397 .read = regcache_maple_read, 391 398 .write = regcache_maple_write, 392 399 .drop = regcache_maple_drop,
+17 -14
drivers/base/regmap/regcache-rbtree.c
··· 184 184 static int regcache_rbtree_init(struct regmap *map) 185 185 { 186 186 struct regcache_rbtree_ctx *rbtree_ctx; 187 - int i; 188 - int ret; 189 187 190 188 map->cache = kmalloc(sizeof *rbtree_ctx, map->alloc_flags); 191 189 if (!map->cache) ··· 193 195 rbtree_ctx->root = RB_ROOT; 194 196 rbtree_ctx->cached_rbnode = NULL; 195 197 196 - for (i = 0; i < map->num_reg_defaults; i++) { 197 - ret = regcache_rbtree_write(map, 198 - map->reg_defaults[i].reg, 199 - map->reg_defaults[i].def); 200 - if (ret) 201 - goto err; 202 - } 203 - 204 198 return 0; 205 - 206 - err: 207 - regcache_rbtree_exit(map); 208 - return ret; 209 199 } 210 200 211 201 static int regcache_rbtree_exit(struct regmap *map) ··· 221 235 /* release the resources */ 222 236 kfree(map->cache); 223 237 map->cache = NULL; 238 + 239 + return 0; 240 + } 241 + 242 + static int regcache_rbtree_populate(struct regmap *map) 243 + { 244 + unsigned int i; 245 + int ret; 246 + 247 + for (i = 0; i < map->num_reg_defaults; i++) { 248 + ret = regcache_rbtree_write(map, 249 + map->reg_defaults[i].reg, 250 + map->reg_defaults[i].def); 251 + if (ret) 252 + return ret; 253 + } 224 254 225 255 return 0; 226 256 } ··· 548 546 .name = "rbtree", 549 547 .init = regcache_rbtree_init, 550 548 .exit = regcache_rbtree_exit, 549 + .populate = regcache_rbtree_populate, 551 550 #ifdef CONFIG_DEBUG_FS 552 551 .debugfs_init = rbtree_debugfs_init, 553 552 #endif
+17
drivers/base/regmap/regcache.c
··· 16 16 #include "internal.h" 17 17 18 18 static const struct regcache_ops *cache_types[] = { 19 + &regcache_flat_sparse_ops, 19 20 &regcache_rbtree_ops, 20 21 &regcache_maple_ops, 21 22 &regcache_flat_ops, ··· 222 221 if (ret) 223 222 goto err_free; 224 223 } 224 + 225 + if (map->num_reg_defaults && map->cache_ops->populate) { 226 + dev_dbg(map->dev, "Populating %s cache\n", map->cache_ops->name); 227 + map->lock(map->lock_arg); 228 + ret = map->cache_ops->populate(map); 229 + map->unlock(map->lock_arg); 230 + if (ret) 231 + goto err_exit; 232 + } 225 233 return 0; 226 234 235 + err_exit: 236 + if (map->cache_ops->exit) { 237 + dev_dbg(map->dev, "Destroying %s cache\n", map->cache_ops->name); 238 + map->lock(map->lock_arg); 239 + ret = map->cache_ops->exit(map); 240 + map->unlock(map->lock_arg); 241 + } 227 242 err_free: 228 243 kfree(map->reg_defaults); 229 244 if (map->cache_free)
+3 -2
drivers/base/regmap/regmap-i3c.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 // Copyright (c) 2018 Synopsys, Inc. and/or its affiliates. 3 3 4 + #include <linux/array_size.h> 4 5 #include <linux/regmap.h> 5 6 #include <linux/i3c/device.h> 6 7 #include <linux/i3c/master.h> ··· 19 18 }, 20 19 }; 21 20 22 - return i3c_device_do_priv_xfers(i3c, xfers, 1); 21 + return i3c_device_do_priv_xfers(i3c, xfers, ARRAY_SIZE(xfers)); 23 22 } 24 23 25 24 static int regmap_i3c_read(void *context, ··· 38 37 xfers[1].len = val_size; 39 38 xfers[1].data.in = val; 40 39 41 - return i3c_device_do_priv_xfers(i3c, xfers, 2); 40 + return i3c_device_do_priv_xfers(i3c, xfers, ARRAY_SIZE(xfers)); 42 41 } 43 42 44 43 static const struct regmap_bus regmap_i3c = {
+22
drivers/base/regmap/regmap-kunit.c
··· 54 54 return "none"; 55 55 case REGCACHE_FLAT: 56 56 return "flat"; 57 + case REGCACHE_FLAT_S: 58 + return "flat-sparse"; 57 59 case REGCACHE_RBTREE: 58 60 return "rbtree"; 59 61 case REGCACHE_MAPLE: ··· 95 93 { .cache = REGCACHE_NONE, .fast_io = true }, 96 94 { .cache = REGCACHE_FLAT }, 97 95 { .cache = REGCACHE_FLAT, .fast_io = true }, 96 + { .cache = REGCACHE_FLAT_S }, 97 + { .cache = REGCACHE_FLAT_S, .fast_io = true }, 98 98 { .cache = REGCACHE_RBTREE }, 99 99 { .cache = REGCACHE_RBTREE, .fast_io = true }, 100 100 { .cache = REGCACHE_MAPLE }, ··· 108 104 static const struct regmap_test_param real_cache_types_only_list[] = { 109 105 { .cache = REGCACHE_FLAT }, 110 106 { .cache = REGCACHE_FLAT, .fast_io = true }, 107 + { .cache = REGCACHE_FLAT_S }, 108 + { .cache = REGCACHE_FLAT_S, .fast_io = true }, 111 109 { .cache = REGCACHE_RBTREE }, 112 110 { .cache = REGCACHE_RBTREE, .fast_io = true }, 113 111 { .cache = REGCACHE_MAPLE }, ··· 125 119 { .cache = REGCACHE_FLAT, .from_reg = 0x2002 }, 126 120 { .cache = REGCACHE_FLAT, .from_reg = 0x2003 }, 127 121 { .cache = REGCACHE_FLAT, .from_reg = 0x2004 }, 122 + { .cache = REGCACHE_FLAT_S, .from_reg = 0 }, 123 + { .cache = REGCACHE_FLAT_S, .from_reg = 0, .fast_io = true }, 124 + { .cache = REGCACHE_FLAT_S, .from_reg = 0x2001 }, 125 + { .cache = REGCACHE_FLAT_S, .from_reg = 0x2002 }, 126 + { .cache = REGCACHE_FLAT_S, .from_reg = 0x2003 }, 127 + { .cache = REGCACHE_FLAT_S, .from_reg = 0x2004 }, 128 128 { .cache = REGCACHE_RBTREE, .from_reg = 0 }, 129 129 { .cache = REGCACHE_RBTREE, .from_reg = 0, .fast_io = true }, 130 130 { .cache = REGCACHE_RBTREE, .from_reg = 0x2001 }, ··· 148 136 KUNIT_ARRAY_PARAM(real_cache_types, real_cache_types_list, param_to_desc); 149 137 150 138 static const struct regmap_test_param sparse_cache_types_list[] = { 139 + { .cache = REGCACHE_FLAT_S, .from_reg = 0 }, 140 + { .cache = REGCACHE_FLAT_S, .from_reg = 0, .fast_io = true }, 141 + { .cache = REGCACHE_FLAT_S, .from_reg = 0x2001 }, 142 + { .cache = REGCACHE_FLAT_S, .from_reg = 0x2002 }, 143 + { .cache = REGCACHE_FLAT_S, .from_reg = 0x2003 }, 144 + { .cache = REGCACHE_FLAT_S, .from_reg = 0x2004 }, 151 145 { .cache = REGCACHE_RBTREE, .from_reg = 0 }, 152 146 { .cache = REGCACHE_RBTREE, .from_reg = 0, .fast_io = true }, 153 147 { .cache = REGCACHE_RBTREE, .from_reg = 0x2001 }, ··· 1615 1597 { .cache = REGCACHE_NONE, .val_endian = REGMAP_ENDIAN_BIG }, 1616 1598 { .cache = REGCACHE_FLAT, .val_endian = REGMAP_ENDIAN_LITTLE }, 1617 1599 { .cache = REGCACHE_FLAT, .val_endian = REGMAP_ENDIAN_BIG }, 1600 + { .cache = REGCACHE_FLAT_S, .val_endian = REGMAP_ENDIAN_LITTLE }, 1601 + { .cache = REGCACHE_FLAT_S, .val_endian = REGMAP_ENDIAN_BIG }, 1618 1602 { .cache = REGCACHE_RBTREE, .val_endian = REGMAP_ENDIAN_LITTLE }, 1619 1603 { .cache = REGCACHE_RBTREE, .val_endian = REGMAP_ENDIAN_BIG }, 1620 1604 { .cache = REGCACHE_MAPLE, .val_endian = REGMAP_ENDIAN_LITTLE }, ··· 1628 1608 static const struct regmap_test_param raw_cache_types_list[] = { 1629 1609 { .cache = REGCACHE_FLAT, .val_endian = REGMAP_ENDIAN_LITTLE }, 1630 1610 { .cache = REGCACHE_FLAT, .val_endian = REGMAP_ENDIAN_BIG }, 1611 + { .cache = REGCACHE_FLAT_S, .val_endian = REGMAP_ENDIAN_LITTLE }, 1612 + { .cache = REGCACHE_FLAT_S, .val_endian = REGMAP_ENDIAN_BIG }, 1631 1613 { .cache = REGCACHE_RBTREE, .val_endian = REGMAP_ENDIAN_LITTLE }, 1632 1614 { .cache = REGCACHE_RBTREE, .val_endian = REGMAP_ENDIAN_BIG }, 1633 1615 { .cache = REGCACHE_MAPLE, .val_endian = REGMAP_ENDIAN_LITTLE },
+2 -1
drivers/base/regmap/regmap-sdw-mbq.c
··· 17 17 struct device *dev; 18 18 struct sdw_slave *sdw; 19 19 20 + bool (*readable_reg)(struct device *dev, unsigned int reg); 21 + 20 22 struct regmap_sdw_mbq_cfg cfg; 21 23 22 24 int val_size; 23 - bool (*readable_reg)(struct device *dev, unsigned int reg); 24 25 }; 25 26 26 27 static int regmap_sdw_mbq_size(struct regmap_mbq_context *ctx, unsigned int reg)
+11 -6
include/linux/regmap.h
··· 55 55 #define REGMAP_DOWNSHIFT(s) (s) 56 56 57 57 /* 58 - * The supported cache types, the default is no cache. Any new caches 59 - * should usually use the maple tree cache unless they specifically 60 - * require that there are never any allocations at runtime and can't 61 - * provide defaults in which case they should use the flat cache. The 62 - * rbtree cache *may* have some performance advantage for very low end 63 - * systems that make heavy use of cache syncs but is mainly legacy. 58 + * The supported cache types, the default is no cache. Any new caches should 59 + * usually use the maple tree cache unless they specifically require that there 60 + * are never any allocations at runtime in which case they should use the sparse 61 + * flat cache. The rbtree cache *may* have some performance advantage for very 62 + * low end systems that make heavy use of cache syncs but is mainly legacy. 63 + * These caches are sparse and entries will be initialized from hardware if no 64 + * default has been provided. 65 + * The non-sparse flat cache is provided for compatibility with existing users 66 + * and will zero-initialize cache entries for which no defaults are provided. 67 + * New users should use the sparse flat cache. 64 68 */ 65 69 enum regcache_type { 66 70 REGCACHE_NONE, 67 71 REGCACHE_RBTREE, 68 72 REGCACHE_FLAT, 69 73 REGCACHE_MAPLE, 74 + REGCACHE_FLAT_S, 70 75 }; 71 76 72 77 /**