* [PATCH 1/3] regmap: flat: use the cache_present bitmap @ 2013-08-09 10:09 Ionut Nicu 2013-08-09 11:44 ` Mark Brown 0 siblings, 1 reply; 6+ messages in thread From: Ionut Nicu @ 2013-08-09 10:09 UTC (permalink / raw) To: Mark Brown; +Cc: Greg Kroah-Hartman, linux-kernel As opposed to the other regmap cache implementations, regcache_flat didn't use the cache_present bitmap for figuring out whether a register was cached or not, nor did it mark a register as present in the cache when regcache_flat_write() was called. This caused incorrect behaviour, such as returning value 0 for non-volatile registers without first reading their value from the device and storing it in the cache. Signed-off-by: Ionut Nicu <ioan.nicu.ext@nsn.com> --- drivers/base/regmap/regcache-flat.c | 25 ++++++++++++++++++++++--- 1 files changed, 22 insertions(+), 3 deletions(-) diff --git a/drivers/base/regmap/regcache-flat.c b/drivers/base/regmap/regcache-flat.c index d9762e4..f47278e 100644 --- a/drivers/base/regmap/regcache-flat.c +++ b/drivers/base/regmap/regcache-flat.c @@ -16,9 +16,13 @@ #include "internal.h" +static int regcache_flat_write(struct regmap *map, unsigned int reg, + unsigned int value); +static int regcache_flat_exit(struct regmap *map); + static int regcache_flat_init(struct regmap *map) { - int i; + int i, ret; unsigned int *cache; map->cache = kzalloc(sizeof(unsigned int) * (map->max_register + 1), @@ -28,8 +32,15 @@ static int regcache_flat_init(struct regmap *map) cache = map->cache; - for (i = 0; i < map->num_reg_defaults; i++) - cache[map->reg_defaults[i].reg] = map->reg_defaults[i].def; + for (i = 0; i < map->num_reg_defaults; i++) { + ret = regcache_flat_write(map, + map->reg_defaults[i].reg, + map->reg_defaults[i].def); + if (ret) { + regcache_flat_exit(map); + return ret; + } + } return 0; } @@ -47,6 +58,9 @@ static int regcache_flat_read(struct regmap *map, { unsigned int *cache = map->cache; + if (!regcache_reg_present(map, reg)) + return -ENOENT; + *value = cache[reg]; return 0; @@ -56,6 +70,11 @@ static int regcache_flat_write(struct regmap *map, unsigned int reg, unsigned int value) { unsigned int *cache = map->cache; + int ret; + + ret = regcache_set_reg_present(map, reg); + if (ret < 0) + return ret; cache[reg] = value; -- 1.7.1 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH 1/3] regmap: flat: use the cache_present bitmap 2013-08-09 10:09 [PATCH 1/3] regmap: flat: use the cache_present bitmap Ionut Nicu @ 2013-08-09 11:44 ` Mark Brown 2013-08-09 17:16 ` Ionut Nicu 0 siblings, 1 reply; 6+ messages in thread From: Mark Brown @ 2013-08-09 11:44 UTC (permalink / raw) To: Ionut Nicu; +Cc: Greg Kroah-Hartman, linux-kernel [-- Attachment #1: Type: text/plain, Size: 970 bytes --] On Fri, Aug 09, 2013 at 12:09:11PM +0200, Ionut Nicu wrote: > As opposed to the other regmap cache implementations, > regcache_flat didn't use the cache_present bitmap for > figuring out whether a register was cached or not, nor > did it mark a register as present in the cache when > regcache_flat_write() was called. > This caused incorrect behaviour, such as returning > value 0 for non-volatile registers without first reading > their value from the device and storing it in the cache. The goal with the flat cache is to do as little work as possible for things like memory mapped devices where the cache operations are actually noticable in comparison with the I/O costs. I would therefore exapect that anything using the flat cache would want to ensure that the cache is fully populated at init time, reading back from the device if nothing else (by setting num_reg_defaults_raw but not providing values), rather than do additional operations in the data path. [-- Attachment #2: Digital signature --] [-- Type: application/pgp-signature, Size: 836 bytes --] ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 1/3] regmap: flat: use the cache_present bitmap 2013-08-09 11:44 ` Mark Brown @ 2013-08-09 17:16 ` Ionut Nicu 2013-08-13 7:17 ` Ionut Nicu [not found] ` <5211D68C.1070608@nsn.com> 0 siblings, 2 replies; 6+ messages in thread From: Ionut Nicu @ 2013-08-09 17:16 UTC (permalink / raw) To: ext Mark Brown; +Cc: Greg Kroah-Hartman, linux-kernel On 09.08.2013 13:44, ext Mark Brown wrote: > On Fri, Aug 09, 2013 at 12:09:11PM +0200, Ionut Nicu wrote: >> As opposed to the other regmap cache implementations, >> regcache_flat didn't use the cache_present bitmap for >> figuring out whether a register was cached or not, nor >> did it mark a register as present in the cache when >> regcache_flat_write() was called. > >> This caused incorrect behaviour, such as returning >> value 0 for non-volatile registers without first reading >> their value from the device and storing it in the cache. > > The goal with the flat cache is to do as little work as possible for > things like memory mapped devices where the cache operations are > actually noticable in comparison with the I/O costs. I would therefore > exapect that anything using the flat cache would want to ensure that the > cache is fully populated at init time, reading back from the device if > nothing else (by setting num_reg_defaults_raw but not providing values), > rather than do additional operations in the data path. > Ok, I get your point. I've tried using this approach, but the thing is that I have a device which supports only single rw operations. The regcache_hw_init() function calls regmap_raw_read which in turn calls _regmap_raw_read() when cache_bypass is enabled. But _regmap_raw_read() doesn't take the use_single_rw flag into account and tries to read num_reg_defaults_raw registers in a single bus transfer. Unfortunately this doesn't work with my device. I thought about changing regcache_hw_init() to check for this flag in the same way regmap_bulk_read() does, but I think this is pretty ugly. What do you think about moving the check to use_single_rw inside _regmap_raw_read(), right where the bus accesses are done? Something like in the following patch: diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 42b45ac..de7f353 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -1486,14 +1486,16 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val, { struct regmap_range_node *range; u8 *u8 = map->work_buf; - int ret; + size_t val_bytes = map->format.val_bytes; + size_t reg_size = map->format.reg_bytes + map->format.pad_bytes; + int ret, i; WARN_ON(!map->bus); range = _regmap_range_lookup(map, reg); if (range) { ret = _regmap_select_page(map, ®, range, - val_len / map->format.val_bytes); + val_len / val_bytes); if (ret != 0) return ret; } @@ -1508,15 +1510,41 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val, */ u8[0] |= map->read_flag_mask; - trace_regmap_hw_read_start(map->dev, reg, - val_len / map->format.val_bytes); + /* + * Some devices does not support bulk read, for + * them we have a series of single read operations. + */ + if (map->use_single_rw) { + for (i = 0; i < val_len; i++) { + trace_regmap_hw_read_start(map->dev, + reg + (i * map->reg_stride), 1); + + map->format.format_reg(map->work_buf, + reg + (i * map->reg_stride), + map->reg_shift); + u8[0] |= map->read_flag_mask; + + ret = map->bus->read(map->bus_context, + map->work_buf, + reg_size, + val + (i * val_bytes), + val_bytes); + if (ret != 0) + return ret; - ret = map->bus->read(map->bus_context, map->work_buf, - map->format.reg_bytes + map->format.pad_bytes, - val, val_len); + trace_regmap_hw_read_done(map->dev, + reg + (i * map->reg_stride), 1); + } + } else { + trace_regmap_hw_read_start(map->dev, reg, val_len / val_bytes); - trace_regmap_hw_read_done(map->dev, reg, - val_len / map->format.val_bytes); + ret = map->bus->read(map->bus_context, map->work_buf, + reg_size, val, val_len); + if (ret != 0) + return ret; + + trace_regmap_hw_read_done(map->dev, reg, val_len / val_bytes); + } return ret; } @@ -1702,25 +1730,9 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val, return -EINVAL; if (vol || map->cache_type == REGCACHE_NONE) { - /* - * Some devices does not support bulk read, for - * them we have a series of single read operations. - */ - if (map->use_single_rw) { - for (i = 0; i < val_count; i++) { - ret = regmap_raw_read(map, - reg + (i * map->reg_stride), - val + (i * val_bytes), - val_bytes); - if (ret != 0) - return ret; - } - } else { - ret = regmap_raw_read(map, reg, val, - val_bytes * val_count); - if (ret != 0) - return ret; - } + ret = regmap_raw_read(map, reg, val, val_bytes * val_count); + if (ret != 0) + return ret; for (i = 0; i < val_count * val_bytes; i += val_bytes) map->format.parse_inplace(val + i); ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH 1/3] regmap: flat: use the cache_present bitmap 2013-08-09 17:16 ` Ionut Nicu @ 2013-08-13 7:17 ` Ionut Nicu 2013-08-13 11:06 ` Mark Brown [not found] ` <5211D68C.1070608@nsn.com> 1 sibling, 1 reply; 6+ messages in thread From: Ionut Nicu @ 2013-08-13 7:17 UTC (permalink / raw) To: Mark Brown; +Cc: Greg Kroah-Hartman, linux-kernel Hi Mark, On 09.08.2013 19:16, Ionut Nicu wrote: > On 09.08.2013 13:44, ext Mark Brown wrote: >> On Fri, Aug 09, 2013 at 12:09:11PM +0200, Ionut Nicu wrote: >>> As opposed to the other regmap cache implementations, >>> regcache_flat didn't use the cache_present bitmap for >>> figuring out whether a register was cached or not, nor >>> did it mark a register as present in the cache when >>> regcache_flat_write() was called. >> >>> This caused incorrect behaviour, such as returning >>> value 0 for non-volatile registers without first reading >>> their value from the device and storing it in the cache. >> >> The goal with the flat cache is to do as little work as possible for >> things like memory mapped devices where the cache operations are >> actually noticable in comparison with the I/O costs. I would therefore >> exapect that anything using the flat cache would want to ensure that the >> cache is fully populated at init time, reading back from the device if >> nothing else (by setting num_reg_defaults_raw but not providing values), >> rather than do additional operations in the data path. >> > > Ok, I get your point. I've tried using this approach, but the thing is > that I have a device which supports only single rw operations. The > regcache_hw_init() function calls regmap_raw_read which in turn calls > _regmap_raw_read() when cache_bypass is enabled. But _regmap_raw_read() > doesn't take the use_single_rw flag into account and tries to read > num_reg_defaults_raw registers in a single bus transfer. Unfortunately > this doesn't work with my device. > > I thought about changing regcache_hw_init() to check for this flag in > the same way regmap_bulk_read() does, but I think this is pretty ugly. > > What do you think about moving the check to use_single_rw inside > _regmap_raw_read(), right where the bus accesses are done? > > Something like in the following patch: > > > diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c > index 42b45ac..de7f353 100644 > --- a/drivers/base/regmap/regmap.c > +++ b/drivers/base/regmap/regmap.c > @@ -1486,14 +1486,16 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val, > { > struct regmap_range_node *range; > u8 *u8 = map->work_buf; > - int ret; > + size_t val_bytes = map->format.val_bytes; > + size_t reg_size = map->format.reg_bytes + map->format.pad_bytes; > + int ret, i; > > WARN_ON(!map->bus); > > range = _regmap_range_lookup(map, reg); > if (range) { > ret = _regmap_select_page(map, ®, range, > - val_len / map->format.val_bytes); > + val_len / val_bytes); > if (ret != 0) > return ret; > } > @@ -1508,15 +1510,41 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val, > */ > u8[0] |= map->read_flag_mask; > > - trace_regmap_hw_read_start(map->dev, reg, > - val_len / map->format.val_bytes); > + /* > + * Some devices does not support bulk read, for > + * them we have a series of single read operations. > + */ > + if (map->use_single_rw) { > + for (i = 0; i < val_len; i++) { > + trace_regmap_hw_read_start(map->dev, > + reg + (i * map->reg_stride), 1); > + > + map->format.format_reg(map->work_buf, > + reg + (i * map->reg_stride), > + map->reg_shift); > + u8[0] |= map->read_flag_mask; > + > + ret = map->bus->read(map->bus_context, > + map->work_buf, > + reg_size, > + val + (i * val_bytes), > + val_bytes); > + if (ret != 0) > + return ret; > > - ret = map->bus->read(map->bus_context, map->work_buf, > - map->format.reg_bytes + map->format.pad_bytes, > - val, val_len); > + trace_regmap_hw_read_done(map->dev, > + reg + (i * map->reg_stride), 1); > + } > + } else { > + trace_regmap_hw_read_start(map->dev, reg, val_len / val_bytes); > > - trace_regmap_hw_read_done(map->dev, reg, > - val_len / map->format.val_bytes); > + ret = map->bus->read(map->bus_context, map->work_buf, > + reg_size, val, val_len); > + if (ret != 0) > + return ret; > + > + trace_regmap_hw_read_done(map->dev, reg, val_len / val_bytes); > + } > > return ret; > } > @@ -1702,25 +1730,9 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val, > return -EINVAL; > > if (vol || map->cache_type == REGCACHE_NONE) { > - /* > - * Some devices does not support bulk read, for > - * them we have a series of single read operations. > - */ > - if (map->use_single_rw) { > - for (i = 0; i < val_count; i++) { > - ret = regmap_raw_read(map, > - reg + (i * map->reg_stride), > - val + (i * val_bytes), > - val_bytes); > - if (ret != 0) > - return ret; > - } > - } else { > - ret = regmap_raw_read(map, reg, val, > - val_bytes * val_count); > - if (ret != 0) > - return ret; > - } > + ret = regmap_raw_read(map, reg, val, val_bytes * val_count); > + if (ret != 0) > + return ret; > > for (i = 0; i < val_count * val_bytes; i += val_bytes) > map->format.parse_inplace(val + i); > Do you have any feedback for this patch? If you think the change is too complex, I have a simpler solution that could make things work with devices that set use_single_rw. Instead of enabling cache_bypass in regcache_hw_init(), we could temporarily set map->cache_type to REGCACHE_NONE and then call regmap_bulk_read() instead of regmap_raw_read(). Please let me know your opinion on any of the two solutions. Best regards, Ionut Nicu. ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 1/3] regmap: flat: use the cache_present bitmap 2013-08-13 7:17 ` Ionut Nicu @ 2013-08-13 11:06 ` Mark Brown 0 siblings, 0 replies; 6+ messages in thread From: Mark Brown @ 2013-08-13 11:06 UTC (permalink / raw) To: Ionut Nicu; +Cc: Greg Kroah-Hartman, linux-kernel [-- Attachment #1: Type: text/plain, Size: 708 bytes --] On Tue, Aug 13, 2013 at 09:17:12AM +0200, Ionut Nicu wrote: > Do you have any feedback for this patch? Not yet, please allow some time for response especially over weekends. > If you think the change is too complex, I have a simpler solution that could make > things work with devices that set use_single_rw. Instead of enabling cache_bypass > in regcache_hw_init(), we could temporarily set map->cache_type to REGCACHE_NONE > and then call regmap_bulk_read() instead of regmap_raw_read(). Well, we probably don't want to be doing raw reads on random devices though - they should really only be being done if the device can actuallly support them. Too much room for confusion otherwise. [-- Attachment #2: Digital signature --] [-- Type: application/pgp-signature, Size: 836 bytes --] ^ permalink raw reply [flat|nested] 6+ messages in thread
[parent not found: <5211D68C.1070608@nsn.com>]
* Re: Fwd: Re: [PATCH 1/3] regmap: flat: use the cache_present bitmap [not found] ` <5211D68C.1070608@nsn.com> @ 2013-08-19 11:18 ` Alexander Sverdlin 0 siblings, 0 replies; 6+ messages in thread From: Alexander Sverdlin @ 2013-08-19 11:18 UTC (permalink / raw) To: Ionut Nicu, linux-kernel; +Cc: Mark Brown, Greg Kroah-Hartman Hello! On 08/19/2013 10:25 AM, Ionut Nicu wrote: > -------- Original Message -------- > Subject: Re: [PATCH 1/3] regmap: flat: use the cache_present bitmap > Date: Fri, 09 Aug 2013 19:16:49 +0200 > From: Ionut Nicu <ioan.nicu.ext@nsn.com> > To: ext Mark Brown <broonie@kernel.org> > CC: Greg Kroah-Hartman <gregkh@linuxfoundation.org>, linux-kernel@vger.kernel.org > > On 09.08.2013 13:44, ext Mark Brown wrote: >> On Fri, Aug 09, 2013 at 12:09:11PM +0200, Ionut Nicu wrote: >>> As opposed to the other regmap cache implementations, >>> regcache_flat didn't use the cache_present bitmap for >>> figuring out whether a register was cached or not, nor >>> did it mark a register as present in the cache when >>> regcache_flat_write() was called. >> >>> This caused incorrect behaviour, such as returning >>> value 0 for non-volatile registers without first reading >>> their value from the device and storing it in the cache. >> >> The goal with the flat cache is to do as little work as possible for >> things like memory mapped devices where the cache operations are >> actually noticable in comparison with the I/O costs. I would therefore >> exapect that anything using the flat cache would want to ensure that the >> cache is fully populated at init time, reading back from the device if >> nothing else (by setting num_reg_defaults_raw but not providing values), >> rather than do additional operations in the data path. >> > > Ok, I get your point. I've tried using this approach, but the thing is > that I have a device which supports only single rw operations. The > regcache_hw_init() function calls regmap_raw_read which in turn calls > _regmap_raw_read() when cache_bypass is enabled. But _regmap_raw_read() > doesn't take the use_single_rw flag into account and tries to read > num_reg_defaults_raw registers in a single bus transfer. Unfortunately > this doesn't work with my device. > > I thought about changing regcache_hw_init() to check for this flag in > the same way regmap_bulk_read() does, but I think this is pretty ugly. > > What do you think about moving the check to use_single_rw inside > _regmap_raw_read(), right where the bus accesses are done? > > Something like in the following patch: Acked-by: Alexander Sverdlin <alexander.sverdlin@nsn.com> > > diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c > index 42b45ac..de7f353 100644 > --- a/drivers/base/regmap/regmap.c > +++ b/drivers/base/regmap/regmap.c > @@ -1486,14 +1486,16 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val, > { > struct regmap_range_node *range; > u8 *u8 = map->work_buf; > - int ret; > + size_t val_bytes = map->format.val_bytes; > + size_t reg_size = map->format.reg_bytes + map->format.pad_bytes; > + int ret, i; > > WARN_ON(!map->bus); > > range = _regmap_range_lookup(map, reg); > if (range) { > ret = _regmap_select_page(map, ®, range, > - val_len / map->format.val_bytes); > + val_len / val_bytes); > if (ret != 0) > return ret; > } > @@ -1508,15 +1510,41 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val, > */ > u8[0] |= map->read_flag_mask; > > - trace_regmap_hw_read_start(map->dev, reg, > - val_len / map->format.val_bytes); > + /* > + * Some devices does not support bulk read, for > + * them we have a series of single read operations. > + */ > + if (map->use_single_rw) { > + for (i = 0; i < val_len; i++) { > + trace_regmap_hw_read_start(map->dev, > + reg + (i * map->reg_stride), 1); > + > + map->format.format_reg(map->work_buf, > + reg + (i * map->reg_stride), > + map->reg_shift); > + u8[0] |= map->read_flag_mask; > + > + ret = map->bus->read(map->bus_context, > + map->work_buf, > + reg_size, > + val + (i * val_bytes), > + val_bytes); > + if (ret != 0) > + return ret; > > - ret = map->bus->read(map->bus_context, map->work_buf, > - map->format.reg_bytes + map->format.pad_bytes, > - val, val_len); > + trace_regmap_hw_read_done(map->dev, > + reg + (i * map->reg_stride), 1); > + } > + } else { > + trace_regmap_hw_read_start(map->dev, reg, val_len / val_bytes); > > - trace_regmap_hw_read_done(map->dev, reg, > - val_len / map->format.val_bytes); > + ret = map->bus->read(map->bus_context, map->work_buf, > + reg_size, val, val_len); > + if (ret != 0) > + return ret; > + > + trace_regmap_hw_read_done(map->dev, reg, val_len / val_bytes); > + } > > return ret; > } > @@ -1702,25 +1730,9 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val, > return -EINVAL; > > if (vol || map->cache_type == REGCACHE_NONE) { > - /* > - * Some devices does not support bulk read, for > - * them we have a series of single read operations. > - */ > - if (map->use_single_rw) { > - for (i = 0; i < val_count; i++) { > - ret = regmap_raw_read(map, > - reg + (i * map->reg_stride), > - val + (i * val_bytes), > - val_bytes); > - if (ret != 0) > - return ret; > - } > - } else { > - ret = regmap_raw_read(map, reg, val, > - val_bytes * val_count); > - if (ret != 0) > - return ret; > - } > + ret = regmap_raw_read(map, reg, val, val_bytes * val_count); > + if (ret != 0) > + return ret; > > for (i = 0; i < val_count * val_bytes; i += val_bytes) > map->format.parse_inplace(val + i); > > > > > -- Best regards, Alexander Sverdlin. ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2013-08-19 11:19 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-08-09 10:09 [PATCH 1/3] regmap: flat: use the cache_present bitmap Ionut Nicu
2013-08-09 11:44 ` Mark Brown
2013-08-09 17:16 ` Ionut Nicu
2013-08-13 7:17 ` Ionut Nicu
2013-08-13 11:06 ` Mark Brown
[not found] ` <5211D68C.1070608@nsn.com>
2013-08-19 11:18 ` Fwd: " Alexander Sverdlin
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox