Skip to content

Commit d212dcf

Browse files
HiassofTDigitalDreamtime
authored andcommitted
dmaengine: bcm2835: Avoid splitting periods into very small chunks
The current cyclic DMA period splitting implementation can generate very small chunks at the end of each period. For example a 65536 byte period will be split into a 65532 byte chunk and a 4 byte chunk on the "lite" DMA channels. This increases pressure on the RAM controller as the DMA controller needs to fetch two control blocks from RAM in quick succession and could potentially cause latency issues if the RAM is tied up by other devices. We can easily avoid these situations by distributing the remaining length evenly between the last-but-one and the last chunk, making sure that split chunks will be at least half the maximum length the DMA controller can handle. This patch checks if the last chunk would be less than half of the maximum DMA length and if yes distributes the max len+4...max_len*1.5 bytes evenly between the last 2 chunks. This results in chunk sizes between max_len/2 and max_len*0.75 bytes. Signed-off-by: Matthias Reichl <[email protected]> Signed-off-by: Martin Sperl <[email protected]> Tested-by: Clive Messer <[email protected]>
1 parent 51c0665 commit d212dcf

File tree

1 file changed

+14
-0
lines changed

1 file changed

+14
-0
lines changed

drivers/dma/bcm2835-dma.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,20 @@ static void bcm2835_dma_create_cb_set_length(
253253

254254
/* have we filled in period_length yet? */
255255
if (*total_len + control_block->length < period_len) {
256+
/*
257+
* If the next control block is the last in the period
258+
* and it's length would be less than half of max_len
259+
* change it so that both control blocks are (almost)
260+
* equally long. This avoids generating very short
261+
* control blocks (worst case would be 4 bytes) which
262+
* might be problematic. We also have to make sure the
263+
* new length is a multiple of 4 bytes.
264+
*/
265+
if (*total_len + control_block->length + max_len / 2 >
266+
period_len) {
267+
control_block->length =
268+
DIV_ROUND_UP(period_len - *total_len, 8) * 4;
269+
}
256270
/* update number of bytes in this period so far */
257271
*total_len += control_block->length;
258272
return;

0 commit comments

Comments
 (0)