Skip to content

Commit a053083

Browse files
alxelaxrlubos
authored andcommitted
[nrf fromtree] bluetooth: mesh: fix BLOB IO flash write alignment for non-erase devices
The wr_chunk function had a fast path for devices without explicit erase (e.g. nRF54L RRAM) that wrote chunk data directly without aligning the offset or size to the flash write block size. On RRAM with write-block-size=16, this caused -EINVAL from the flash driver for every chunk write since chunk_size (161) and most chunk offsets are not 16-byte aligned. The failed writes caused the BLOB server to never mark chunks as received, resulting in block_status_rsp always reporting all chunks missing. This led to infinite retransmission of block 0 and eventual DFU timeout. Fix by using a read-modify-write approach for non-erase devices: read existing data at the aligned boundaries, overlay the chunk data, and write back the full aligned buffer. This satisfies the driver's alignment requirements while preserving neighboring bytes. Signed-off-by: Aleksandr Khromykh <aleksandr.khromykh@nordicsemi.no> (cherry picked from commit a9ad258)
1 parent b4fc048 commit a053083

1 file changed

Lines changed: 23 additions & 15 deletions

File tree

subsys/bluetooth/mesh/blob_io_flash.c

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -142,17 +142,6 @@ static int wr_chunk(const struct bt_mesh_blob_io *io,
142142

143143
const struct flash_parameters *fparam = flash_get_parameters(fdev);
144144

145-
/*
146-
* If device has no erase requirement then write directly.
147-
* This is required since trick with padding using the erase value will
148-
* not work in this case.
149-
*/
150-
if (!(flash_params_get_erase_cap(fparam) & FLASH_ERASE_C_EXPLICIT)) {
151-
return flash_area_write(flash->area,
152-
flash->offset + block->offset + chunk->offset,
153-
chunk->data, chunk->size);
154-
}
155-
156145
/*
157146
* Allocate one additional write block for the case where a chunk will need
158147
* an extra write block on both sides to fit.
@@ -162,6 +151,28 @@ static int wr_chunk(const struct bt_mesh_blob_io *io,
162151
uint32_t write_block_size = flash_area_align(flash->area);
163152
off_t area_offset = flash->offset + block->offset + chunk->offset;
164153
int start_pad = area_offset % write_block_size;
154+
off_t aligned_offset = ROUND_DOWN(area_offset, write_block_size);
155+
size_t write_size = ROUND_UP(start_pad + chunk->size, write_block_size);
156+
157+
if (!(flash_params_get_erase_cap(fparam) & FLASH_ERASE_C_EXPLICIT)) {
158+
/*
159+
* For devices without explicit erase (e.g. RRAM), read existing
160+
* data at alignment boundaries to preserve bytes outside the
161+
* chunk region, then overlay the chunk data and write back.
162+
* The erase-value padding trick cannot be used here because
163+
* writes are destructive regardless of the value written.
164+
*/
165+
int err;
166+
167+
err = flash_area_read(flash->area, aligned_offset, buf, write_size);
168+
if (err) {
169+
return err;
170+
}
171+
172+
memcpy(&buf[start_pad], chunk->data, chunk->size);
173+
174+
return flash_area_write(flash->area, aligned_offset, buf, write_size);
175+
}
165176

166177
/*
167178
* Fill buffer with erase value, to make sure only the part of the
@@ -173,10 +184,7 @@ static int wr_chunk(const struct bt_mesh_blob_io *io,
173184

174185
memcpy(&buf[start_pad], chunk->data, chunk->size);
175186

176-
return flash_area_write(flash->area,
177-
ROUND_DOWN(area_offset, write_block_size),
178-
buf,
179-
ROUND_UP(start_pad + chunk->size, write_block_size));
187+
return flash_area_write(flash->area, aligned_offset, buf, write_size);
180188
}
181189

182190
int bt_mesh_blob_io_flash_init(struct bt_mesh_blob_io_flash *flash,

0 commit comments

Comments
 (0)