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

Merge remote-tracking branch 'regmap/topic/cache' into regmap-next

+180 -27
+2
drivers/base/regmap/internal.h
··· 52 52 struct regmap { 53 53 struct mutex mutex; 54 54 spinlock_t spinlock; 55 + unsigned long spinlock_flags; 55 56 regmap_lock lock; 56 57 regmap_unlock unlock; 57 58 void *lock_arg; /* This is passed to lock/unlock functions */ ··· 149 148 int (*read)(struct regmap *map, unsigned int reg, unsigned int *value); 150 149 int (*write)(struct regmap *map, unsigned int reg, unsigned int value); 151 150 int (*sync)(struct regmap *map, unsigned int min, unsigned int max); 151 + int (*drop)(struct regmap *map, unsigned int min, unsigned int max); 152 152 }; 153 153 154 154 bool regmap_writeable(struct regmap *map, unsigned int reg);
+48 -14
drivers/base/regmap/regcache-rbtree.c
··· 304 304 return 0; 305 305 } 306 306 307 + static struct regcache_rbtree_node * 308 + regcache_rbtree_node_alloc(struct regmap *map, unsigned int reg) 309 + { 310 + struct regcache_rbtree_node *rbnode; 311 + const struct regmap_range *range; 312 + int i; 313 + 314 + rbnode = kzalloc(sizeof(*rbnode), GFP_KERNEL); 315 + if (!rbnode) 316 + return NULL; 317 + 318 + /* If there is a read table then use it to guess at an allocation */ 319 + if (map->rd_table) { 320 + for (i = 0; i < map->rd_table->n_yes_ranges; i++) { 321 + if (regmap_reg_in_range(reg, 322 + &map->rd_table->yes_ranges[i])) 323 + break; 324 + } 325 + 326 + if (i != map->rd_table->n_yes_ranges) { 327 + range = &map->rd_table->yes_ranges[i]; 328 + rbnode->blklen = range->range_max - range->range_min 329 + + 1; 330 + rbnode->base_reg = range->range_min; 331 + } 332 + } 333 + 334 + if (!rbnode->blklen) { 335 + rbnode->blklen = sizeof(*rbnode); 336 + rbnode->base_reg = reg; 337 + } 338 + 339 + rbnode->block = kmalloc(rbnode->blklen * map->cache_word_size, 340 + GFP_KERNEL); 341 + if (!rbnode->block) { 342 + kfree(rbnode); 343 + return NULL; 344 + } 345 + 346 + return rbnode; 347 + } 348 + 307 349 static int regcache_rbtree_write(struct regmap *map, unsigned int reg, 308 350 unsigned int value) 309 351 { ··· 396 354 return 0; 397 355 } 398 356 } 399 - /* we did not manage to find a place to insert it in an existing 400 - * block so create a new rbnode with a single register in its block. 401 - * This block will get populated further if any other adjacent 402 - * registers get modified in the future. 357 + 358 + /* We did not manage to find a place to insert it in 359 + * an existing block so create a new rbnode. 403 360 */ 404 - rbnode = kzalloc(sizeof *rbnode, GFP_KERNEL); 361 + rbnode = regcache_rbtree_node_alloc(map, reg); 405 362 if (!rbnode) 406 363 return -ENOMEM; 407 - rbnode->blklen = sizeof(*rbnode); 408 - rbnode->base_reg = reg; 409 - rbnode->block = kmalloc(rbnode->blklen * map->cache_word_size, 410 - GFP_KERNEL); 411 - if (!rbnode->block) { 412 - kfree(rbnode); 413 - return -ENOMEM; 414 - } 415 - regcache_rbtree_set_register(map, rbnode, 0, value); 364 + regcache_rbtree_set_register(map, rbnode, 365 + reg - rbnode->base_reg, value); 416 366 regcache_rbtree_insert(map, &rbtree_ctx->root, rbnode); 417 367 rbtree_ctx->cached_rbnode = rbnode; 418 368 }
+79 -4
drivers/base/regmap/regcache.c
··· 250 250 return 0; 251 251 } 252 252 253 + static int regcache_default_sync(struct regmap *map, unsigned int min, 254 + unsigned int max) 255 + { 256 + unsigned int reg; 257 + 258 + for (reg = min; reg <= max; reg++) { 259 + unsigned int val; 260 + int ret; 261 + 262 + if (regmap_volatile(map, reg)) 263 + continue; 264 + 265 + ret = regcache_read(map, reg, &val); 266 + if (ret) 267 + return ret; 268 + 269 + /* Is this the hardware default? If so skip. */ 270 + ret = regcache_lookup_reg(map, reg); 271 + if (ret >= 0 && val == map->reg_defaults[ret].def) 272 + continue; 273 + 274 + map->cache_bypass = 1; 275 + ret = _regmap_write(map, reg, val); 276 + map->cache_bypass = 0; 277 + if (ret) 278 + return ret; 279 + dev_dbg(map->dev, "Synced register %#x, value %#x\n", reg, val); 280 + } 281 + 282 + return 0; 283 + } 284 + 253 285 /** 254 286 * regcache_sync: Sync the register cache with the hardware. 255 287 * ··· 300 268 const char *name; 301 269 unsigned int bypass; 302 270 303 - BUG_ON(!map->cache_ops || !map->cache_ops->sync); 271 + BUG_ON(!map->cache_ops); 304 272 305 273 map->lock(map->lock_arg); 306 274 /* Remember the initial bypass state */ ··· 329 297 } 330 298 map->cache_bypass = 0; 331 299 332 - ret = map->cache_ops->sync(map, 0, map->max_register); 300 + if (map->cache_ops->sync) 301 + ret = map->cache_ops->sync(map, 0, map->max_register); 302 + else 303 + ret = regcache_default_sync(map, 0, map->max_register); 333 304 334 305 if (ret == 0) 335 306 map->cache_dirty = false; ··· 366 331 const char *name; 367 332 unsigned int bypass; 368 333 369 - BUG_ON(!map->cache_ops || !map->cache_ops->sync); 334 + BUG_ON(!map->cache_ops); 370 335 371 336 map->lock(map->lock_arg); 372 337 ··· 381 346 if (!map->cache_dirty) 382 347 goto out; 383 348 384 - ret = map->cache_ops->sync(map, min, max); 349 + if (map->cache_ops->sync) 350 + ret = map->cache_ops->sync(map, min, max); 351 + else 352 + ret = regcache_default_sync(map, min, max); 385 353 386 354 out: 387 355 trace_regcache_sync(map->dev, name, "stop region"); ··· 395 357 return ret; 396 358 } 397 359 EXPORT_SYMBOL_GPL(regcache_sync_region); 360 + 361 + /** 362 + * regcache_drop_region: Discard part of the register cache 363 + * 364 + * @map: map to operate on 365 + * @min: first register to discard 366 + * @max: last register to discard 367 + * 368 + * Discard part of the register cache. 369 + * 370 + * Return a negative value on failure, 0 on success. 371 + */ 372 + int regcache_drop_region(struct regmap *map, unsigned int min, 373 + unsigned int max) 374 + { 375 + unsigned int reg; 376 + int ret = 0; 377 + 378 + if (!map->cache_present && !(map->cache_ops && map->cache_ops->drop)) 379 + return -EINVAL; 380 + 381 + map->lock(map->lock_arg); 382 + 383 + trace_regcache_drop_region(map->dev, min, max); 384 + 385 + if (map->cache_present) 386 + for (reg = min; reg < max + 1; reg++) 387 + clear_bit(reg, map->cache_present); 388 + 389 + if (map->cache_ops && map->cache_ops->drop) 390 + ret = map->cache_ops->drop(map, min, max); 391 + 392 + map->unlock(map->lock_arg); 393 + 394 + return ret; 395 + } 396 + EXPORT_SYMBOL_GPL(regcache_drop_region); 398 397 399 398 /** 400 399 * regcache_cache_only: Put a register map into cache only mode
+4
drivers/base/regmap/regmap-debugfs.c
··· 84 84 unsigned int fpos_offset; 85 85 unsigned int reg_offset; 86 86 87 + /* Suppress the cache if we're using a subrange */ 88 + if (from) 89 + return from; 90 + 87 91 /* 88 92 * If we don't have a cache build one so we don't have to do a 89 93 * linear scan each time.
+12 -9
drivers/base/regmap/regmap.c
··· 65 65 } 66 66 EXPORT_SYMBOL_GPL(regmap_reg_in_ranges); 67 67 68 - static bool _regmap_check_range_table(struct regmap *map, 69 - unsigned int reg, 70 - const struct regmap_access_table *table) 68 + bool regmap_check_range_table(struct regmap *map, unsigned int reg, 69 + const struct regmap_access_table *table) 71 70 { 72 71 /* Check "no ranges" first */ 73 72 if (regmap_reg_in_ranges(reg, table->no_ranges, table->n_no_ranges)) ··· 79 80 return regmap_reg_in_ranges(reg, table->yes_ranges, 80 81 table->n_yes_ranges); 81 82 } 83 + EXPORT_SYMBOL_GPL(regmap_check_range_table); 82 84 83 85 bool regmap_writeable(struct regmap *map, unsigned int reg) 84 86 { ··· 90 90 return map->writeable_reg(map->dev, reg); 91 91 92 92 if (map->wr_table) 93 - return _regmap_check_range_table(map, reg, map->wr_table); 93 + return regmap_check_range_table(map, reg, map->wr_table); 94 94 95 95 return true; 96 96 } ··· 107 107 return map->readable_reg(map->dev, reg); 108 108 109 109 if (map->rd_table) 110 - return _regmap_check_range_table(map, reg, map->rd_table); 110 + return regmap_check_range_table(map, reg, map->rd_table); 111 111 112 112 return true; 113 113 } ··· 121 121 return map->volatile_reg(map->dev, reg); 122 122 123 123 if (map->volatile_table) 124 - return _regmap_check_range_table(map, reg, map->volatile_table); 124 + return regmap_check_range_table(map, reg, map->volatile_table); 125 125 126 126 return true; 127 127 } ··· 135 135 return map->precious_reg(map->dev, reg); 136 136 137 137 if (map->precious_table) 138 - return _regmap_check_range_table(map, reg, map->precious_table); 138 + return regmap_check_range_table(map, reg, map->precious_table); 139 139 140 140 return false; 141 141 } ··· 302 302 static void regmap_lock_spinlock(void *__map) 303 303 { 304 304 struct regmap *map = __map; 305 - spin_lock(&map->spinlock); 305 + unsigned long flags; 306 + 307 + spin_lock_irqsave(&map->spinlock, flags); 308 + map->spinlock_flags = flags; 306 309 } 307 310 308 311 static void regmap_unlock_spinlock(void *__map) 309 312 { 310 313 struct regmap *map = __map; 311 - spin_unlock(&map->spinlock); 314 + spin_unlock_irqrestore(&map->spinlock, map->spinlock_flags); 312 315 } 313 316 314 317 static void dev_get_regmap_release(struct device *dev, void *res)
+12
include/linux/regmap.h
··· 394 394 int regcache_sync(struct regmap *map); 395 395 int regcache_sync_region(struct regmap *map, unsigned int min, 396 396 unsigned int max); 397 + int regcache_drop_region(struct regmap *map, unsigned int min, 398 + unsigned int max); 397 399 void regcache_cache_only(struct regmap *map, bool enable); 398 400 void regcache_cache_bypass(struct regmap *map, bool enable); 399 401 void regcache_mark_dirty(struct regmap *map); 402 + 403 + bool regmap_check_range_table(struct regmap *map, unsigned int reg, 404 + const struct regmap_access_table *table); 400 405 401 406 int regmap_register_patch(struct regmap *map, const struct reg_default *regs, 402 407 int num_regs); ··· 561 556 } 562 557 563 558 static inline int regcache_sync_region(struct regmap *map, unsigned int min, 559 + unsigned int max) 560 + { 561 + WARN_ONCE(1, "regmap API is disabled"); 562 + return -EINVAL; 563 + } 564 + 565 + static inline int regcache_drop_region(struct regmap *map, unsigned int min, 564 566 unsigned int max) 565 567 { 566 568 WARN_ONCE(1, "regmap API is disabled");
+23
include/trace/events/regmap.h
··· 223 223 224 224 ); 225 225 226 + TRACE_EVENT(regcache_drop_region, 227 + 228 + TP_PROTO(struct device *dev, unsigned int from, 229 + unsigned int to), 230 + 231 + TP_ARGS(dev, from, to), 232 + 233 + TP_STRUCT__entry( 234 + __string( name, dev_name(dev) ) 235 + __field( unsigned int, from ) 236 + __field( unsigned int, to ) 237 + ), 238 + 239 + TP_fast_assign( 240 + __assign_str(name, dev_name(dev)); 241 + __entry->from = from; 242 + __entry->to = to; 243 + ), 244 + 245 + TP_printk("%s %u-%u", __get_str(name), (unsigned int)__entry->from, 246 + (unsigned int)__entry->to) 247 + ); 248 + 226 249 #endif /* _TRACE_REGMAP_H */ 227 250 228 251 /* This part must be outside protection */