analogdevicesinc / linux

Linux kernel variant from Analog Devices; see README.md for details

Home Page:https://github.com/analogdevicesinc/linux

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

dma: axi-dmac: integer overflow when DMA_LENGTH_WIDTH is set to 32 in the FPGA design

IsaacJT opened this issue · comments

This issue appears in the axi_dmac_fill_linear_sg function in dma-axi-dmac.c:

num_segments = DIV_ROUND_UP(period_len, chan->max_length);

When the DMA_LENGTH_WIDTH is 32, the chan->max_length variable is set to 2^32, and the formula used in the DIV_ROUND_UP macro creates an integer overflow:

#define __KERNEL_DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))

This results in the macro returning 0 and a divide-by-zero error in the next line of code, causing the following stack trace:

[   79.624443] divide error: 0000 [#1] PREEMPT SMP PTI
[   79.624450] CPU: 0 PID: 4225 Comm: iiod Not tainted 4.19.0 #31
[   79.624455] Hardware name: AMI AM F5x/msd/AM F5x/msd, BIOS 4.09.01 12/06/2019
[   79.624468] RIP: 0010:axi_dmac_fill_linear_sg.isra.23+0x70/0xe5
[   79.624474] Code: 48 c7 c7 38 c6 6f b2 42 8d 44 31 ff f7 f1 ba 2c 02 00 00 44 89 f1 41 89 c7 41 89 c0 e8 33 0d b5 ff 43 8d 44 3e ff 31 d2 31 f6 <41> f7 f7 ff c8 41 0b 45 00 44 8d 40 01 48 8b 44 24 38 4c 89 c2 39
[   79.624485] RSP: 0018:ffffaba281bf3c00 EFLAGS: 00010246
[   79.624492] RAX: 00000000000fffff RBX: 0000000088100000 RCX: 0000000000000000
[   79.624497] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 00000000ffffffff
[   79.624503] RBP: 0000000000000001 R08: ffffffffb1958250 R09: 0000000000000498
[   79.624508] R10: ffffffffb16f1fc0 R11: ffffffffb30c0f0d R12: 0000000000000002
[   79.624514] R13: ffffa1761af13684 R14: 0000000000100000 R15: 0000000000000000
[   79.624520] FS:  00007f04bdc2b640(0000) GS:ffffa1761da00000(0000) knlGS:0000000000000000
[   79.624527] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   79.624532] CR2: 00007f04b4001db8 CR3: 0000000457b24004 CR4: 00000000003606f0
[   79.624538] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[   79.624543] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
[   79.624548] Call Trace:
[   79.624558]  axi_dmac_prep_slave_sg.cold.29+0xf5/0x14e
[   79.624568]  iio_dmaengine_buffer_submit_block+0x19f/0x1e0
[   79.624578]  axiadc_hw_submit_block+0x1c/0x50
[   79.624585]  iio_dma_buffer_submit_block.part.9+0x29/0x50
[   79.624591]  iio_dma_buffer_enable+0x8f/0x130
[   79.624599]  __iio_update_buffers+0x3bf/0x8b0
[   79.624607]  iio_buffer_store_enable+0x7f/0xe0
[   79.624615]  kernfs_fop_write+0x107/0x180
[   79.624624]  __vfs_write+0x35/0x180
[   79.624632]  vfs_write+0xa4/0x1a0
[   79.624638]  ksys_write+0x4e/0xb0
[   79.624646]  do_syscall_64+0x47/0xf0
[   79.624653]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
[   79.624659] RIP: 0033:0x7f04bf0d94cf
[   79.624664] Code: 89 54 24 18 48 89 74 24 10 89 7c 24 08 e8 79 3f f9 ff 48 8b 54 24 18 48 8b 74 24 10 41 89 c0 8b 7c 24 08 b8 01 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 31 44 89 c7 48 89 44 24 08 e8 cc 3f f9 ff 48
[   79.624675] RSP: 002b:00007f04bdc2a2b0 EFLAGS: 00000293 ORIG_RAX: 0000000000000001
[   79.624682] RAX: ffffffffffffffda RBX: 0000000000000002 RCX: 00007f04bf0d94cf
[   79.624688] RDX: 0000000000000002 RSI: 00007f04b4000e70 RDI: 000000000000000a
[   79.624693] RBP: 00007f04b4000e70 R08: 0000000000000000 R09: 00007f04b4000000
[   79.624699] R10: 0000000000000070 R11: 0000000000000293 R12: 0000000000000002
[   79.624704] R13: 00007f04b4000bd0 R14: 0000000000000002 R15: 00007f04bf1ad720
[   79.624711] Modules linked in:
[   79.624743] ---[ end trace 963fe9dc5135c760 ]---
[   79.624752] RIP: 0010:axi_dmac_fill_linear_sg.isra.23+0x70/0xe5
[   79.624758] Code: 48 c7 c7 38 c6 6f b2 42 8d 44 31 ff f7 f1 ba 2c 02 00 00 44 89 f1 41 89 c7 41 89 c0 e8 33 0d b5 ff 43 8d 44 3e ff 31 d2 31 f6 <41> f7 f7 ff c8 41 0b 45 00 44 8d 40 01 48 8b 44 24 38 4c 89 c2 39
[   79.624768] RSP: 0018:ffffaba281bf3c00 EFLAGS: 00010246
[   79.624777] RAX: 00000000000fffff RBX: 0000000088100000 RCX: 0000000000000000
[   79.624782] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 00000000ffffffff
[   79.624788] RBP: 0000000000000001 R08: ffffffffb1958250 R09: 0000000000000498
[   79.624793] R10: ffffffffb16f1fc0 R11: ffffffffb30c0f0d R12: 0000000000000002
[   79.624799] R13: ffffa1761af13684 R14: 0000000000100000 R15: 0000000000000000
[   79.624805] FS:  00007f04bdc2b640(0000) GS:ffffa1761da00000(0000) knlGS:0000000000000000
[   79.624811] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   79.624816] CR2: 00007f04b4001db8 CR3: 0000000457b24004 CR4: 00000000003606f0
[   79.624822] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[   79.624829] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400

Hi @IsaacJT,

it looks like you have it all figured 😄 . I can see the problem here but I'm not really that familiarized with our dma driver. Nevertheless, as a quick thought DIV_ROUND_UP_ULL() should prevent the overflow... Not sure if this would be needed in some other place in the driver. Feel free to try this and if it works, to send a PR...

Was there a particular reason to increase DMA_LENGTH_WIDTH from 24 to 32?

Was there a particular reason to increase DMA_LENGTH_WIDTH from 24 to 32?

No particular reason - I'm mostly doing performance tests and trying out different combinations of settings, and I noticed this while testing DMA transfer sizes (we're doing DMA over PCIe, so a bigger block size is helpful).

Feel free to try this and if it works, to send a PR...

I'll give it a go