* [PATCH 1/4] regmap: Add support for discarding parts of the register cache
@ 2013-05-08 12:55 Mark Brown
2013-05-08 12:55 ` [PATCH 2/4] regmap: Make regmap_check_range_table() a public API Mark Brown
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Mark Brown @ 2013-05-08 12:55 UTC (permalink / raw)
To: Mark Brown; +Cc: linux-kernel, Mark Brown
Allow drivers to discard parts of the register cache, for example if part
of the hardware has been reset.
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
drivers/base/regmap/internal.h | 1 +
drivers/base/regmap/regcache.c | 37 +++++++++++++++++++++++++++++++++++++
include/linux/regmap.h | 9 +++++++++
include/trace/events/regmap.h | 23 +++++++++++++++++++++++
4 files changed, 70 insertions(+)
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index c130536..b33a4ff 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -148,6 +148,7 @@ struct regcache_ops {
int (*read)(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 (*drop)(struct regmap *map, unsigned int min, unsigned int max);
};
bool regmap_writeable(struct regmap *map, unsigned int reg);
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c
index 1196c21..14c6eef 100644
--- a/drivers/base/regmap/regcache.c
+++ b/drivers/base/regmap/regcache.c
@@ -359,6 +359,43 @@ out:
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);
+
+ 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);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(regcache_drop_region);
+
+/**
* regcache_cache_only: Put a register map into cache only mode
*
* @map: map to configure
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index 02d84e2..5067ee9 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -394,6 +394,8 @@ bool regmap_can_raw_write(struct regmap *map);
int regcache_sync(struct regmap *map);
int regcache_sync_region(struct regmap *map, unsigned int min,
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_bypass(struct regmap *map, bool enable);
void regcache_mark_dirty(struct regmap *map);
@@ -562,6 +564,13 @@ static inline int regcache_sync_region(struct regmap *map, unsigned int min,
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)
{
WARN_ONCE(1, "regmap API is disabled");
diff --git a/include/trace/events/regmap.h b/include/trace/events/regmap.h
index a43a2f6..23d5615 100644
--- a/include/trace/events/regmap.h
+++ b/include/trace/events/regmap.h
@@ -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 */
/* This part must be outside protection */
--
1.7.10.4
^ permalink raw reply [flat|nested] 4+ messages in thread* [PATCH 2/4] regmap: Make regmap_check_range_table() a public API
2013-05-08 12:55 [PATCH 1/4] regmap: Add support for discarding parts of the register cache Mark Brown
@ 2013-05-08 12:55 ` Mark Brown
2013-05-08 12:55 ` [PATCH 3/4] regmap: rbtree: Factor out node allocation Mark Brown
2013-05-08 12:55 ` [PATCH 4/4] regmap: rbtree: Use range information to allocate nodes Mark Brown
2 siblings, 0 replies; 4+ messages in thread
From: Mark Brown @ 2013-05-08 12:55 UTC (permalink / raw)
To: Mark Brown; +Cc: linux-kernel, Mark Brown
Allow drivers to use an access table as part of their implementation.
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
drivers/base/regmap/regmap.c | 14 +++++++-------
include/linux/regmap.h | 3 +++
2 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index a941dcf..307f5a1 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -65,9 +65,8 @@ bool regmap_reg_in_ranges(unsigned int reg,
}
EXPORT_SYMBOL_GPL(regmap_reg_in_ranges);
-static bool _regmap_check_range_table(struct regmap *map,
- unsigned int reg,
- const struct regmap_access_table *table)
+bool regmap_check_range_table(struct regmap *map, unsigned int reg,
+ const struct regmap_access_table *table)
{
/* Check "no ranges" first */
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,
table->n_yes_ranges);
}
+EXPORT_SYMBOL_GPL(regmap_check_range_table);
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);
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;
}
@@ -107,7 +107,7 @@ bool regmap_readable(struct regmap *map, unsigned int reg)
return map->readable_reg(map->dev, reg);
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;
}
@@ -121,7 +121,7 @@ bool regmap_volatile(struct regmap *map, unsigned int reg)
return map->volatile_reg(map->dev, reg);
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;
}
@@ -135,7 +135,7 @@ bool regmap_precious(struct regmap *map, unsigned int reg)
return map->precious_reg(map->dev, reg);
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;
}
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index 5067ee9..d6f3221 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -400,6 +400,9 @@ void regcache_cache_only(struct regmap *map, bool enable);
void regcache_cache_bypass(struct regmap *map, bool enable);
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 num_regs);
--
1.7.10.4
^ permalink raw reply [flat|nested] 4+ messages in thread* [PATCH 3/4] regmap: rbtree: Factor out node allocation
2013-05-08 12:55 [PATCH 1/4] regmap: Add support for discarding parts of the register cache Mark Brown
2013-05-08 12:55 ` [PATCH 2/4] regmap: Make regmap_check_range_table() a public API Mark Brown
@ 2013-05-08 12:55 ` Mark Brown
2013-05-08 12:55 ` [PATCH 4/4] regmap: rbtree: Use range information to allocate nodes Mark Brown
2 siblings, 0 replies; 4+ messages in thread
From: Mark Brown @ 2013-05-08 12:55 UTC (permalink / raw)
To: Mark Brown; +Cc: linux-kernel, Mark Brown
In preparation for being slightly smarter about how we allocate memory
factor out the node allocation.
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
drivers/base/regmap/regcache-rbtree.c | 41 ++++++++++++++++++++++-----------
1 file changed, 27 insertions(+), 14 deletions(-)
diff --git a/drivers/base/regmap/regcache-rbtree.c b/drivers/base/regmap/regcache-rbtree.c
index e9316b3..47f8047 100644
--- a/drivers/base/regmap/regcache-rbtree.c
+++ b/drivers/base/regmap/regcache-rbtree.c
@@ -304,6 +304,27 @@ static int regcache_rbtree_insert_to_block(struct regmap *map,
return 0;
}
+static struct regcache_rbtree_node *
+regcache_rbtree_node_alloc(struct regmap *map, unsigned int reg)
+{
+ struct regcache_rbtree_node *rbnode;
+
+ rbnode = kzalloc(sizeof(*rbnode), GFP_KERNEL);
+ if (!rbnode)
+ return NULL;
+
+ 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,
unsigned int value)
{
@@ -354,23 +375,15 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
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.
- * This block will get populated further if any other adjacent
- * registers get modified in the future.
+
+ /* We did not manage to find a place to insert it in
+ * an existing block so create a new rbnode.
*/
- rbnode = kzalloc(sizeof *rbnode, GFP_KERNEL);
+ rbnode = regcache_rbtree_node_alloc(map, reg);
if (!rbnode)
return -ENOMEM;
- 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 -ENOMEM;
- }
- regcache_rbtree_set_register(map, rbnode, 0, value);
+ regcache_rbtree_set_register(map, rbnode,
+ reg - rbnode->base_reg, value);
regcache_rbtree_insert(map, &rbtree_ctx->root, rbnode);
rbtree_ctx->cached_rbnode = rbnode;
}
--
1.7.10.4
^ permalink raw reply [flat|nested] 4+ messages in thread* [PATCH 4/4] regmap: rbtree: Use range information to allocate nodes
2013-05-08 12:55 [PATCH 1/4] regmap: Add support for discarding parts of the register cache Mark Brown
2013-05-08 12:55 ` [PATCH 2/4] regmap: Make regmap_check_range_table() a public API Mark Brown
2013-05-08 12:55 ` [PATCH 3/4] regmap: rbtree: Factor out node allocation Mark Brown
@ 2013-05-08 12:55 ` Mark Brown
2 siblings, 0 replies; 4+ messages in thread
From: Mark Brown @ 2013-05-08 12:55 UTC (permalink / raw)
To: Mark Brown; +Cc: linux-kernel, Mark Brown
If range information has been provided then when we allocate a rbnode
within a range allocate the entire range. The goal is to minimise the
number of reallocations done when combining or extending blocks. At
present only readability and yes_ranges are taken into account, this is
expected to cover most cases efficiently.
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
drivers/base/regmap/regcache-rbtree.c | 25 +++++++++++++++++++++++--
1 file changed, 23 insertions(+), 2 deletions(-)
diff --git a/drivers/base/regmap/regcache-rbtree.c b/drivers/base/regmap/regcache-rbtree.c
index 47f8047..24b06a4 100644
--- a/drivers/base/regmap/regcache-rbtree.c
+++ b/drivers/base/regmap/regcache-rbtree.c
@@ -308,13 +308,34 @@ 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;
- rbnode->blklen = sizeof(*rbnode);
- rbnode->base_reg = reg;
+ /* 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) {
--
1.7.10.4
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2013-05-08 12:59 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-05-08 12:55 [PATCH 1/4] regmap: Add support for discarding parts of the register cache Mark Brown
2013-05-08 12:55 ` [PATCH 2/4] regmap: Make regmap_check_range_table() a public API Mark Brown
2013-05-08 12:55 ` [PATCH 3/4] regmap: rbtree: Factor out node allocation Mark Brown
2013-05-08 12:55 ` [PATCH 4/4] regmap: rbtree: Use range information to allocate nodes Mark Brown
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Powered by JetHome