Skip to content

Commit 7a06ef7

Browse files
lumaggregkh
authored andcommitted
nvmem: core: fix bit offsets of more than one byte
If the NVMEM specifies a stride to access data, reading particular cell might require bit offset that is bigger than one byte. Rework NVMEM core code to support bit offsets of more than 8 bits. Signed-off-by: Dmitry Baryshkov <[email protected]> Signed-off-by: Srinivas Kandagatla <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent eed6d95 commit 7a06ef7

File tree

1 file changed

+17
-7
lines changed

1 file changed

+17
-7
lines changed

drivers/nvmem/core.c

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -837,7 +837,9 @@ static int nvmem_add_cells_from_dt(struct nvmem_device *nvmem, struct device_nod
837837
if (addr && len == (2 * sizeof(u32))) {
838838
info.bit_offset = be32_to_cpup(addr++);
839839
info.nbits = be32_to_cpup(addr);
840-
if (info.bit_offset >= BITS_PER_BYTE || info.nbits < 1) {
840+
if (info.bit_offset >= BITS_PER_BYTE * info.bytes ||
841+
info.nbits < 1 ||
842+
info.bit_offset + info.nbits > BITS_PER_BYTE * info.bytes) {
841843
dev_err(dev, "nvmem: invalid bits on %pOF\n", child);
842844
of_node_put(child);
843845
return -EINVAL;
@@ -1630,21 +1632,29 @@ EXPORT_SYMBOL_GPL(nvmem_cell_put);
16301632
static void nvmem_shift_read_buffer_in_place(struct nvmem_cell_entry *cell, void *buf)
16311633
{
16321634
u8 *p, *b;
1633-
int i, extra, bit_offset = cell->bit_offset;
1635+
int i, extra, bytes_offset;
1636+
int bit_offset = cell->bit_offset;
16341637

16351638
p = b = buf;
1636-
if (bit_offset) {
1639+
1640+
bytes_offset = bit_offset / BITS_PER_BYTE;
1641+
b += bytes_offset;
1642+
bit_offset %= BITS_PER_BYTE;
1643+
1644+
if (bit_offset % BITS_PER_BYTE) {
16371645
/* First shift */
1638-
*b++ >>= bit_offset;
1646+
*p = *b++ >> bit_offset;
16391647

16401648
/* setup rest of the bytes if any */
16411649
for (i = 1; i < cell->bytes; i++) {
16421650
/* Get bits from next byte and shift them towards msb */
1643-
*p |= *b << (BITS_PER_BYTE - bit_offset);
1651+
*p++ |= *b << (BITS_PER_BYTE - bit_offset);
16441652

1645-
p = b;
1646-
*b++ >>= bit_offset;
1653+
*p = *b++ >> bit_offset;
16471654
}
1655+
} else if (p != b) {
1656+
memmove(p, b, cell->bytes - bytes_offset);
1657+
p += cell->bytes - 1;
16481658
} else {
16491659
/* point to the msb */
16501660
p += cell->bytes - 1;

0 commit comments

Comments
 (0)