forked from luck/tmp_suning_uos_patched
Merge remote-tracking branch 'regmap/topic/cache' into regmap-next
This commit is contained in:
commit
feff98f550
@ -52,6 +52,7 @@ struct regmap_async {
|
|||||||
struct regmap {
|
struct regmap {
|
||||||
struct mutex mutex;
|
struct mutex mutex;
|
||||||
spinlock_t spinlock;
|
spinlock_t spinlock;
|
||||||
|
unsigned long spinlock_flags;
|
||||||
regmap_lock lock;
|
regmap_lock lock;
|
||||||
regmap_unlock unlock;
|
regmap_unlock unlock;
|
||||||
void *lock_arg; /* This is passed to lock/unlock functions */
|
void *lock_arg; /* This is passed to lock/unlock functions */
|
||||||
@ -148,6 +149,7 @@ struct regcache_ops {
|
|||||||
int (*read)(struct regmap *map, unsigned int reg, unsigned int *value);
|
int (*read)(struct regmap *map, unsigned int reg, unsigned int *value);
|
||||||
int (*write)(struct regmap *map, unsigned int reg, unsigned int value);
|
int (*write)(struct regmap *map, unsigned int reg, unsigned int value);
|
||||||
int (*sync)(struct regmap *map, unsigned int min, unsigned int max);
|
int (*sync)(struct regmap *map, unsigned int min, unsigned int max);
|
||||||
|
int (*drop)(struct regmap *map, unsigned int min, unsigned int max);
|
||||||
};
|
};
|
||||||
|
|
||||||
bool regmap_writeable(struct regmap *map, unsigned int reg);
|
bool regmap_writeable(struct regmap *map, unsigned int reg);
|
||||||
|
@ -304,6 +304,48 @@ static int regcache_rbtree_insert_to_block(struct regmap *map,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct regcache_rbtree_node *
|
||||||
|
regcache_rbtree_node_alloc(struct regmap *map, unsigned int reg)
|
||||||
|
{
|
||||||
|
struct regcache_rbtree_node *rbnode;
|
||||||
|
const struct regmap_range *range;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
rbnode = kzalloc(sizeof(*rbnode), GFP_KERNEL);
|
||||||
|
if (!rbnode)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* If there is a read table then use it to guess at an allocation */
|
||||||
|
if (map->rd_table) {
|
||||||
|
for (i = 0; i < map->rd_table->n_yes_ranges; i++) {
|
||||||
|
if (regmap_reg_in_range(reg,
|
||||||
|
&map->rd_table->yes_ranges[i]))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i != map->rd_table->n_yes_ranges) {
|
||||||
|
range = &map->rd_table->yes_ranges[i];
|
||||||
|
rbnode->blklen = range->range_max - range->range_min
|
||||||
|
+ 1;
|
||||||
|
rbnode->base_reg = range->range_min;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rbnode->blklen) {
|
||||||
|
rbnode->blklen = sizeof(*rbnode);
|
||||||
|
rbnode->base_reg = reg;
|
||||||
|
}
|
||||||
|
|
||||||
|
rbnode->block = kmalloc(rbnode->blklen * map->cache_word_size,
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!rbnode->block) {
|
||||||
|
kfree(rbnode);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rbnode;
|
||||||
|
}
|
||||||
|
|
||||||
static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
|
static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
|
||||||
unsigned int value)
|
unsigned int value)
|
||||||
{
|
{
|
||||||
@ -354,23 +396,15 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* we did not manage to find a place to insert it in an existing
|
|
||||||
* block so create a new rbnode with a single register in its block.
|
/* We did not manage to find a place to insert it in
|
||||||
* This block will get populated further if any other adjacent
|
* an existing block so create a new rbnode.
|
||||||
* registers get modified in the future.
|
|
||||||
*/
|
*/
|
||||||
rbnode = kzalloc(sizeof *rbnode, GFP_KERNEL);
|
rbnode = regcache_rbtree_node_alloc(map, reg);
|
||||||
if (!rbnode)
|
if (!rbnode)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
rbnode->blklen = sizeof(*rbnode);
|
regcache_rbtree_set_register(map, rbnode,
|
||||||
rbnode->base_reg = reg;
|
reg - rbnode->base_reg, value);
|
||||||
rbnode->block = kmalloc(rbnode->blklen * map->cache_word_size,
|
|
||||||
GFP_KERNEL);
|
|
||||||
if (!rbnode->block) {
|
|
||||||
kfree(rbnode);
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
regcache_rbtree_set_register(map, rbnode, 0, value);
|
|
||||||
regcache_rbtree_insert(map, &rbtree_ctx->root, rbnode);
|
regcache_rbtree_insert(map, &rbtree_ctx->root, rbnode);
|
||||||
rbtree_ctx->cached_rbnode = rbnode;
|
rbtree_ctx->cached_rbnode = rbnode;
|
||||||
}
|
}
|
||||||
|
@ -250,6 +250,38 @@ int regcache_write(struct regmap *map,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int regcache_default_sync(struct regmap *map, unsigned int min,
|
||||||
|
unsigned int max)
|
||||||
|
{
|
||||||
|
unsigned int reg;
|
||||||
|
|
||||||
|
for (reg = min; reg <= max; reg++) {
|
||||||
|
unsigned int val;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (regmap_volatile(map, reg))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ret = regcache_read(map, reg, &val);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* Is this the hardware default? If so skip. */
|
||||||
|
ret = regcache_lookup_reg(map, reg);
|
||||||
|
if (ret >= 0 && val == map->reg_defaults[ret].def)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
map->cache_bypass = 1;
|
||||||
|
ret = _regmap_write(map, reg, val);
|
||||||
|
map->cache_bypass = 0;
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
dev_dbg(map->dev, "Synced register %#x, value %#x\n", reg, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* regcache_sync: Sync the register cache with the hardware.
|
* regcache_sync: Sync the register cache with the hardware.
|
||||||
*
|
*
|
||||||
@ -268,7 +300,7 @@ int regcache_sync(struct regmap *map)
|
|||||||
const char *name;
|
const char *name;
|
||||||
unsigned int bypass;
|
unsigned int bypass;
|
||||||
|
|
||||||
BUG_ON(!map->cache_ops || !map->cache_ops->sync);
|
BUG_ON(!map->cache_ops);
|
||||||
|
|
||||||
map->lock(map->lock_arg);
|
map->lock(map->lock_arg);
|
||||||
/* Remember the initial bypass state */
|
/* Remember the initial bypass state */
|
||||||
@ -297,7 +329,10 @@ int regcache_sync(struct regmap *map)
|
|||||||
}
|
}
|
||||||
map->cache_bypass = 0;
|
map->cache_bypass = 0;
|
||||||
|
|
||||||
ret = map->cache_ops->sync(map, 0, map->max_register);
|
if (map->cache_ops->sync)
|
||||||
|
ret = map->cache_ops->sync(map, 0, map->max_register);
|
||||||
|
else
|
||||||
|
ret = regcache_default_sync(map, 0, map->max_register);
|
||||||
|
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
map->cache_dirty = false;
|
map->cache_dirty = false;
|
||||||
@ -331,7 +366,7 @@ int regcache_sync_region(struct regmap *map, unsigned int min,
|
|||||||
const char *name;
|
const char *name;
|
||||||
unsigned int bypass;
|
unsigned int bypass;
|
||||||
|
|
||||||
BUG_ON(!map->cache_ops || !map->cache_ops->sync);
|
BUG_ON(!map->cache_ops);
|
||||||
|
|
||||||
map->lock(map->lock_arg);
|
map->lock(map->lock_arg);
|
||||||
|
|
||||||
@ -346,7 +381,10 @@ int regcache_sync_region(struct regmap *map, unsigned int min,
|
|||||||
if (!map->cache_dirty)
|
if (!map->cache_dirty)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
ret = map->cache_ops->sync(map, min, max);
|
if (map->cache_ops->sync)
|
||||||
|
ret = map->cache_ops->sync(map, min, max);
|
||||||
|
else
|
||||||
|
ret = regcache_default_sync(map, min, max);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
trace_regcache_sync(map->dev, name, "stop region");
|
trace_regcache_sync(map->dev, name, "stop region");
|
||||||
@ -358,6 +396,43 @@ int regcache_sync_region(struct regmap *map, unsigned int min,
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(regcache_sync_region);
|
EXPORT_SYMBOL_GPL(regcache_sync_region);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* regcache_drop_region: Discard part of the register cache
|
||||||
|
*
|
||||||
|
* @map: map to operate on
|
||||||
|
* @min: first register to discard
|
||||||
|
* @max: last register to discard
|
||||||
|
*
|
||||||
|
* Discard part of the register cache.
|
||||||
|
*
|
||||||
|
* Return a negative value on failure, 0 on success.
|
||||||
|
*/
|
||||||
|
int regcache_drop_region(struct regmap *map, unsigned int min,
|
||||||
|
unsigned int max)
|
||||||
|
{
|
||||||
|
unsigned int reg;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (!map->cache_present && !(map->cache_ops && map->cache_ops->drop))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
map->lock(map->lock_arg);
|
||||||
|
|
||||||
|
trace_regcache_drop_region(map->dev, min, max);
|
||||||
|
|
||||||
|
if (map->cache_present)
|
||||||
|
for (reg = min; reg < max + 1; reg++)
|
||||||
|
clear_bit(reg, map->cache_present);
|
||||||
|
|
||||||
|
if (map->cache_ops && map->cache_ops->drop)
|
||||||
|
ret = map->cache_ops->drop(map, min, max);
|
||||||
|
|
||||||
|
map->unlock(map->lock_arg);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(regcache_drop_region);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* regcache_cache_only: Put a register map into cache only mode
|
* regcache_cache_only: Put a register map into cache only mode
|
||||||
*
|
*
|
||||||
|
@ -84,6 +84,10 @@ static unsigned int regmap_debugfs_get_dump_start(struct regmap *map,
|
|||||||
unsigned int fpos_offset;
|
unsigned int fpos_offset;
|
||||||
unsigned int reg_offset;
|
unsigned int reg_offset;
|
||||||
|
|
||||||
|
/* Suppress the cache if we're using a subrange */
|
||||||
|
if (from)
|
||||||
|
return from;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we don't have a cache build one so we don't have to do a
|
* If we don't have a cache build one so we don't have to do a
|
||||||
* linear scan each time.
|
* linear scan each time.
|
||||||
|
@ -65,9 +65,8 @@ bool regmap_reg_in_ranges(unsigned int reg,
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(regmap_reg_in_ranges);
|
EXPORT_SYMBOL_GPL(regmap_reg_in_ranges);
|
||||||
|
|
||||||
static bool _regmap_check_range_table(struct regmap *map,
|
bool regmap_check_range_table(struct regmap *map, unsigned int reg,
|
||||||
unsigned int reg,
|
const struct regmap_access_table *table)
|
||||||
const struct regmap_access_table *table)
|
|
||||||
{
|
{
|
||||||
/* Check "no ranges" first */
|
/* Check "no ranges" first */
|
||||||
if (regmap_reg_in_ranges(reg, table->no_ranges, table->n_no_ranges))
|
if (regmap_reg_in_ranges(reg, table->no_ranges, table->n_no_ranges))
|
||||||
@ -80,6 +79,7 @@ static bool _regmap_check_range_table(struct regmap *map,
|
|||||||
return regmap_reg_in_ranges(reg, table->yes_ranges,
|
return regmap_reg_in_ranges(reg, table->yes_ranges,
|
||||||
table->n_yes_ranges);
|
table->n_yes_ranges);
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(regmap_check_range_table);
|
||||||
|
|
||||||
bool regmap_writeable(struct regmap *map, unsigned int reg)
|
bool regmap_writeable(struct regmap *map, unsigned int reg)
|
||||||
{
|
{
|
||||||
@ -90,7 +90,7 @@ bool regmap_writeable(struct regmap *map, unsigned int reg)
|
|||||||
return map->writeable_reg(map->dev, reg);
|
return map->writeable_reg(map->dev, reg);
|
||||||
|
|
||||||
if (map->wr_table)
|
if (map->wr_table)
|
||||||
return _regmap_check_range_table(map, reg, map->wr_table);
|
return regmap_check_range_table(map, reg, map->wr_table);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -107,7 +107,7 @@ bool regmap_readable(struct regmap *map, unsigned int reg)
|
|||||||
return map->readable_reg(map->dev, reg);
|
return map->readable_reg(map->dev, reg);
|
||||||
|
|
||||||
if (map->rd_table)
|
if (map->rd_table)
|
||||||
return _regmap_check_range_table(map, reg, map->rd_table);
|
return regmap_check_range_table(map, reg, map->rd_table);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -121,7 +121,7 @@ bool regmap_volatile(struct regmap *map, unsigned int reg)
|
|||||||
return map->volatile_reg(map->dev, reg);
|
return map->volatile_reg(map->dev, reg);
|
||||||
|
|
||||||
if (map->volatile_table)
|
if (map->volatile_table)
|
||||||
return _regmap_check_range_table(map, reg, map->volatile_table);
|
return regmap_check_range_table(map, reg, map->volatile_table);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -135,7 +135,7 @@ bool regmap_precious(struct regmap *map, unsigned int reg)
|
|||||||
return map->precious_reg(map->dev, reg);
|
return map->precious_reg(map->dev, reg);
|
||||||
|
|
||||||
if (map->precious_table)
|
if (map->precious_table)
|
||||||
return _regmap_check_range_table(map, reg, map->precious_table);
|
return regmap_check_range_table(map, reg, map->precious_table);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -302,13 +302,16 @@ static void regmap_unlock_mutex(void *__map)
|
|||||||
static void regmap_lock_spinlock(void *__map)
|
static void regmap_lock_spinlock(void *__map)
|
||||||
{
|
{
|
||||||
struct regmap *map = __map;
|
struct regmap *map = __map;
|
||||||
spin_lock(&map->spinlock);
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&map->spinlock, flags);
|
||||||
|
map->spinlock_flags = flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void regmap_unlock_spinlock(void *__map)
|
static void regmap_unlock_spinlock(void *__map)
|
||||||
{
|
{
|
||||||
struct regmap *map = __map;
|
struct regmap *map = __map;
|
||||||
spin_unlock(&map->spinlock);
|
spin_unlock_irqrestore(&map->spinlock, map->spinlock_flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dev_get_regmap_release(struct device *dev, void *res)
|
static void dev_get_regmap_release(struct device *dev, void *res)
|
||||||
|
@ -394,10 +394,15 @@ bool regmap_can_raw_write(struct regmap *map);
|
|||||||
int regcache_sync(struct regmap *map);
|
int regcache_sync(struct regmap *map);
|
||||||
int regcache_sync_region(struct regmap *map, unsigned int min,
|
int regcache_sync_region(struct regmap *map, unsigned int min,
|
||||||
unsigned int max);
|
unsigned int max);
|
||||||
|
int regcache_drop_region(struct regmap *map, unsigned int min,
|
||||||
|
unsigned int max);
|
||||||
void regcache_cache_only(struct regmap *map, bool enable);
|
void regcache_cache_only(struct regmap *map, bool enable);
|
||||||
void regcache_cache_bypass(struct regmap *map, bool enable);
|
void regcache_cache_bypass(struct regmap *map, bool enable);
|
||||||
void regcache_mark_dirty(struct regmap *map);
|
void regcache_mark_dirty(struct regmap *map);
|
||||||
|
|
||||||
|
bool regmap_check_range_table(struct regmap *map, unsigned int reg,
|
||||||
|
const struct regmap_access_table *table);
|
||||||
|
|
||||||
int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
|
int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
|
||||||
int num_regs);
|
int num_regs);
|
||||||
|
|
||||||
@ -562,6 +567,13 @@ static inline int regcache_sync_region(struct regmap *map, unsigned int min,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int regcache_drop_region(struct regmap *map, unsigned int min,
|
||||||
|
unsigned int max)
|
||||||
|
{
|
||||||
|
WARN_ONCE(1, "regmap API is disabled");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void regcache_cache_only(struct regmap *map, bool enable)
|
static inline void regcache_cache_only(struct regmap *map, bool enable)
|
||||||
{
|
{
|
||||||
WARN_ONCE(1, "regmap API is disabled");
|
WARN_ONCE(1, "regmap API is disabled");
|
||||||
|
@ -223,6 +223,29 @@ DEFINE_EVENT(regmap_async, regmap_async_complete_done,
|
|||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
TRACE_EVENT(regcache_drop_region,
|
||||||
|
|
||||||
|
TP_PROTO(struct device *dev, unsigned int from,
|
||||||
|
unsigned int to),
|
||||||
|
|
||||||
|
TP_ARGS(dev, from, to),
|
||||||
|
|
||||||
|
TP_STRUCT__entry(
|
||||||
|
__string( name, dev_name(dev) )
|
||||||
|
__field( unsigned int, from )
|
||||||
|
__field( unsigned int, to )
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_fast_assign(
|
||||||
|
__assign_str(name, dev_name(dev));
|
||||||
|
__entry->from = from;
|
||||||
|
__entry->to = to;
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_printk("%s %u-%u", __get_str(name), (unsigned int)__entry->from,
|
||||||
|
(unsigned int)__entry->to)
|
||||||
|
);
|
||||||
|
|
||||||
#endif /* _TRACE_REGMAP_H */
|
#endif /* _TRACE_REGMAP_H */
|
||||||
|
|
||||||
/* This part must be outside protection */
|
/* This part must be outside protection */
|
||||||
|
Loading…
Reference in New Issue
Block a user