2023-05-15 14:56:53

by Jim Wylder

[permalink] [raw]
Subject: [PATCH] regmap: Account for register length when chunking

Currently, when regmap_raw_write() splits the data, it uses the
max_raw_write value calculated from the bus. For I2C, the actual
transmission will include that data plus the target register.
Since the register length is not included in the calculation of the data
chunk, the transmission will always exceed the maximum transmission
length.

To avoid this problem, add a flag in the regmap_bus structure to declare
that, for a given bus, the register length should be accounted for. Set
the flag to true for I2C buses, and subtract the length of the register
from the maximum transmission value if the flag is set.

Signed-off-by: Jim Wylder <[email protected]>
---
drivers/base/regmap/regmap-i2c.c | 1 +
drivers/base/regmap/regmap.c | 8 ++++++--
include/linux/regmap.h | 2 ++
3 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/drivers/base/regmap/regmap-i2c.c b/drivers/base/regmap/regmap-i2c.c
index 980e5ce6a3a35..793ff8ea3266d 100644
--- a/drivers/base/regmap/regmap-i2c.c
+++ b/drivers/base/regmap/regmap-i2c.c
@@ -198,6 +198,7 @@ static int regmap_i2c_read(void *context,
}

static const struct regmap_bus regmap_i2c = {
+ .reg_in_write = true,
.write = regmap_i2c_write,
.gather_write = regmap_i2c_gather_write,
.read = regmap_i2c_read,
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index db7851f0e3b8c..9de5f4b272aee 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -2083,14 +2083,18 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg,
size_t chunk_count, chunk_bytes;
size_t chunk_regs = val_count;
int ret, i;
+ size_t max_raw_write = map->max_raw_write;

if (!val_count)
return -EINVAL;

+ if ((map->bus) && (map->bus->reg_in_write))
+ max_raw_write -= map->format.reg_bytes;
+
if (map->use_single_write)
chunk_regs = 1;
- else if (map->max_raw_write && val_len > map->max_raw_write)
- chunk_regs = map->max_raw_write / val_bytes;
+ else if (max_raw_write && val_len > max_raw_write)
+ chunk_regs = max_raw_write / val_bytes;

chunk_count = val_count / chunk_regs;
chunk_bytes = chunk_regs * val_bytes;
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index c2b9cc5db8241..20ac78d8777a3 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -556,6 +556,7 @@ typedef void (*regmap_hw_free_context)(void *context);
* @val_format_endian_default: Default endianness for formatted register
* values. Used when the regmap_config specifies DEFAULT. If this is
* DEFAULT, BIG is assumed.
+ * @reg_in_write: Does max_raw_write include register length.
* @max_raw_read: Max raw read size that can be used on the bus.
* @max_raw_write: Max raw write size that can be used on the bus.
*/
@@ -576,6 +577,7 @@ struct regmap_bus {
u8 read_flag_mask;
enum regmap_endian reg_format_endian_default;
enum regmap_endian val_format_endian_default;
+ bool reg_in_write;
size_t max_raw_read;
size_t max_raw_write;
};

base-commit: ad2fd53a7870a395b8564697bef6c329d017c6c9
--
2.40.1.606.ga4b1b128d6-goog



2023-05-15 15:09:51

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH] regmap: Account for register length when chunking

On Mon, May 15, 2023 at 09:39:26AM -0500, Jim Wylder wrote:

> To avoid this problem, add a flag in the regmap_bus structure to declare
> that, for a given bus, the register length should be accounted for. Set
> the flag to true for I2C buses, and subtract the length of the register
> from the maximum transmission value if the flag is set.

This will be needed for any bus with a format operation so we should
just check for that and it should also take account of any pad bytes.


Attachments:
(No filename) (492.00 B)
signature.asc (499.00 B)
Download all attachments

2023-05-16 16:09:00

by Jim Wylder

[permalink] [raw]
Subject: [PATCH] regmap: Account for register length when chunking

Currently, when regmap_raw_write() splits the data, it uses the
max_raw_write value defined for the bus. For any bus that includes
the target register address in the max_raw_write value, the chunked
transmission will always exceed the maximum transmission length.
To avoid this problem, subtract the length of the register from the
maximum transmission.

Signed-off-by: Jim Wylder <[email protected]>
---
drivers/base/regmap/regmap.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index db7851f0e3b8c..1d1496c253ca6 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -2083,14 +2083,15 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg,
size_t chunk_count, chunk_bytes;
size_t chunk_regs = val_count;
int ret, i;
+ size_t max_data = map->max_raw_write - map->format.reg_bytes;

if (!val_count)
return -EINVAL;

if (map->use_single_write)
chunk_regs = 1;
- else if (map->max_raw_write && val_len > map->max_raw_write)
- chunk_regs = map->max_raw_write / val_bytes;
+ else if (map->max_raw_write && val_len > max_data)
+ chunk_regs = max_data / val_bytes;

chunk_count = val_count / chunk_regs;
chunk_bytes = chunk_regs * val_bytes;

base-commit: ad2fd53a7870a395b8564697bef6c329d017c6c9
--
2.40.1.606.ga4b1b128d6-goog


2023-05-17 01:20:20

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH] regmap: Account for register length when chunking

On Tue, May 16, 2023 at 10:52:23AM -0500, Jim Wylder wrote:

> + size_t max_data = map->max_raw_write - map->format.reg_bytes;

This still doesn't take account of padding bytes.

Please don't ignore review comments, people are generally making them
for a reason and are likely to have the same concerns if issues remain
unaddressed. Having to repeat the same comments can get repetitive and
make people question the value of time spent reviewing. If you disagree
with the review comments that's fine but you need to reply and discuss
your concerns so that the reviewer can understand your decisions.


Attachments:
(No filename) (614.00 B)
signature.asc (499.00 B)
Download all attachments

2023-05-17 15:26:46

by Jim Wylder

[permalink] [raw]
Subject: regmap: Account for register length when chunking

Sorry, I didn't intend to ignore your point about pad_bytes. I had
misread the second half of the sentences as being the result of the
first half - rather than as an additional correction needed.

Thanks for the feedback.



2023-05-17 15:29:09

by Jim Wylder

[permalink] [raw]
Subject: [PATCH] regmap: Account for register length when chunking

Currently, when regmap_raw_write() splits the data, it uses the
max_raw_write value defined for the bus. For any bus that includes
the target register address in the max_raw_write value, the chunked
transmission will always exceed the maximum transmission length.
To avoid this problem, subtract the length of the register and the
padding from the maximum transmission.

Signed-off-by: Jim Wylder <[email protected]>
---
drivers/base/regmap/regmap.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index db7851f0e3b8c..fa2d3fba6ac9d 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -2082,6 +2082,8 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg,
size_t val_count = val_len / val_bytes;
size_t chunk_count, chunk_bytes;
size_t chunk_regs = val_count;
+ size_t max_data = map->max_raw_write - map->format.reg_bytes -
+ map->format.pad_bytes;
int ret, i;

if (!val_count)
@@ -2089,8 +2091,8 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg,

if (map->use_single_write)
chunk_regs = 1;
- else if (map->max_raw_write && val_len > map->max_raw_write)
- chunk_regs = map->max_raw_write / val_bytes;
+ else if (map->max_raw_write && val_len > max_data)
+ chunk_regs = max_data / val_bytes;

chunk_count = val_count / chunk_regs;
chunk_bytes = chunk_regs * val_bytes;

base-commit: ad2fd53a7870a395b8564697bef6c329d017c6c9
--
2.40.1.606.ga4b1b128d6-goog


2023-05-18 17:48:08

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH] regmap: Account for register length when chunking

On Wed, 17 May 2023 10:20:11 -0500, Jim Wylder wrote:
> Currently, when regmap_raw_write() splits the data, it uses the
> max_raw_write value defined for the bus. For any bus that includes
> the target register address in the max_raw_write value, the chunked
> transmission will always exceed the maximum transmission length.
> To avoid this problem, subtract the length of the register and the
> padding from the maximum transmission.
>
> [...]

Applied to

https://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap.git for-next

Thanks!

[1/1] regmap: Account for register length when chunking
commit: 3981514180c987a79ea98f0ae06a7cbf58a9ac0f

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark