Skip to content

Commit 9ed0ded

Browse files
Martinhoff-makerMaureenHelm
authored andcommitted
drivers: dma: silabs: add dma block splitting for high transfer size
The LDMA driver currently has a 1:1 mapping between hardware LDMA descriptors and struct dma_block_config. This patch allows multiple hardware descriptors to be allocated for a single struct dma_block_config if the block size exceeds the transfer capacity of a single hardware LDMA descriptor. This is beneficial for other peripheral drivers: it is no longer necessary to split the payload by the transfer capacity of a single hardware LDMA descriptor. Signed-off-by: Martin Hoff <[email protected]>
1 parent 3d2f8b1 commit 9ed0ded

File tree

1 file changed

+45
-21
lines changed

1 file changed

+45
-21
lines changed

drivers/dma/dma_silabs_ldma.c

Lines changed: 45 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,12 @@ static int dma_silabs_get_blocksize(uint32_t src_blen, uint32_t dst_blen, uint32
8989

9090
static int dma_silabs_block_to_descriptor(struct dma_config *config,
9191
struct dma_silabs_channel *chan_conf,
92-
struct dma_block_config *block, LDMA_Descriptor_t *desc)
92+
struct dma_block_config *block, LDMA_Descriptor_t *desc,
93+
int *offset)
9394
{
94-
int ret, src_size, xfer_count;
95+
int ret, src_size, xfer_count, loc_offset, mod, rem_bsize;
96+
97+
loc_offset = *offset;
9598

9699
if (block->dest_scatter_count || block->source_gather_count ||
97100
block->source_gather_interval || block->dest_scatter_interval ||
@@ -123,17 +126,27 @@ static int dma_silabs_block_to_descriptor(struct dma_config *config,
123126
src_size = config->source_data_size;
124127
desc->xfer.size = LOG2(src_size);
125128

126-
if (block->block_size % config->source_data_size) {
127-
xfer_count = block->block_size / config->source_data_size;
129+
if (loc_offset) {
130+
rem_bsize = block->block_size - loc_offset * config->source_data_size;
128131
} else {
129-
xfer_count = block->block_size / config->source_data_size - 1;
132+
rem_bsize = block->block_size;
130133
}
131134

135+
xfer_count = rem_bsize / config->source_data_size;
136+
mod = rem_bsize % config->source_data_size;
137+
132138
if (xfer_count > LDMA_DESCRIPTOR_MAX_XFER_SIZE) {
133-
return -ENOTSUP;
134-
}
139+
desc->xfer.xferCnt = LDMA_DESCRIPTOR_MAX_XFER_SIZE - 1;
140+
*offset = loc_offset + LDMA_DESCRIPTOR_MAX_XFER_SIZE;
135141

136-
desc->xfer.xferCnt = xfer_count;
142+
} else {
143+
if (!mod || xfer_count == LDMA_DESCRIPTOR_MAX_XFER_SIZE) {
144+
xfer_count--;
145+
}
146+
147+
desc->xfer.xferCnt = xfer_count;
148+
*offset = 0;
149+
}
137150

138151
/* Warning : High LDMA blockSize (high burst) mean a large transfer
139152
* without LDMA controller re-arbitration.
@@ -195,8 +208,8 @@ static int dma_silabs_block_to_descriptor(struct dma_config *config,
195208
LOG_WRN("dest_buffer address is null.");
196209
}
197210

198-
desc->xfer.srcAddr = block->source_address;
199-
desc->xfer.dstAddr = block->dest_address;
211+
desc->xfer.srcAddr = block->source_address + loc_offset * config->source_data_size;
212+
desc->xfer.dstAddr = block->dest_address + loc_offset * config->dest_data_size;
200213

201214
return 0;
202215
}
@@ -229,21 +242,22 @@ static int dma_silabs_configure_descriptor(struct dma_config *config, struct dma
229242
struct dma_block_config *head_block = config->head_block;
230243
struct dma_block_config *block = config->head_block;
231244
LDMA_Descriptor_t *desc, *prev_desc;
232-
int ret;
245+
int ret, offset;
233246

234247
/* Descriptors configuration
235248
* block refers to user configured block (dma_block_config structure from dma.h)
236249
* desc refers to driver configured block (LDMA_Descriptor_t structure from silabs
237250
* hal)
238251
*/
239252
prev_desc = NULL;
253+
offset = 0;
240254
while (block) {
241255
ret = sys_mem_blocks_alloc(data->dma_desc_pool, 1, (void **)&desc);
242256
if (ret) {
243257
goto err;
244258
}
245259

246-
ret = dma_silabs_block_to_descriptor(config, chan_conf, block, desc);
260+
ret = dma_silabs_block_to_descriptor(config, chan_conf, block, desc, &offset);
247261
if (ret) {
248262
goto err;
249263
}
@@ -257,13 +271,15 @@ static int dma_silabs_configure_descriptor(struct dma_config *config, struct dma
257271
}
258272

259273
prev_desc = desc;
260-
block = block->next_block;
261-
if (block == head_block) {
262-
block = NULL;
263-
prev_desc->xfer.linkAddr =
264-
LDMA_DESCRIPTOR_LINKABS_ADDR_TO_LINKADDR(chan_conf->desc);
265-
prev_desc->xfer.linkMode = ldmaLinkModeAbs;
266-
prev_desc->xfer.link = 1;
274+
if (!offset) {
275+
block = block->next_block;
276+
if (block == head_block) {
277+
block = NULL;
278+
prev_desc->xfer.linkAddr =
279+
LDMA_DESCRIPTOR_LINKABS_ADDR_TO_LINKADDR(chan_conf->desc);
280+
prev_desc->xfer.linkMode = ldmaLinkModeAbs;
281+
prev_desc->xfer.link = 1;
282+
}
267283
}
268284
}
269285

@@ -525,7 +541,9 @@ int silabs_ldma_append_block(const struct device *dev, uint32_t channel, struct
525541
struct dma_block_config *block_config = config->head_block;
526542
LDMA_Descriptor_t *desc = data->dma_chan_table[channel].desc;
527543
unsigned int key;
528-
int ret;
544+
int ret, offset;
545+
546+
offset = 0;
529547

530548
__ASSERT(!((uintptr_t)desc & ~_LDMA_CH_LINK_LINKADDR_MASK),
531549
"DMA Descriptor is not 32 bits aligned");
@@ -552,9 +570,15 @@ int silabs_ldma_append_block(const struct device *dev, uint32_t channel, struct
552570
return -EINVAL;
553571
}
554572

555-
ret = dma_silabs_block_to_descriptor(config, chan_conf, block_config, desc);
573+
ret = dma_silabs_block_to_descriptor(config, chan_conf, block_config, desc, &offset);
556574
if (ret) {
557575
return ret;
576+
} else if (offset) {
577+
/* If the offset is not 0, it means that the block size is larger than the transfer
578+
* capacity of a single hardware LDMA descriptor. It is not supported with the
579+
* append function.
580+
*/
581+
return -EINVAL;
558582
}
559583

560584
key = irq_lock();

0 commit comments

Comments
 (0)