diff options
author | Andrey Smirnov <andrew.smirnov@gmail.com> | 2018-09-17 22:21:22 -0700 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2018-09-19 09:55:54 +0200 |
commit | 82ec28929cc960d4c62d97963ec627c944e17f66 (patch) | |
tree | e0f0c9dc25242c3ff8f5a8cbb28a4e469a52a07e /drivers/net/fec_imx.c | |
parent | 26e76f9f88d523de0b97ecb4dcc046ce76754f63 (diff) | |
download | barebox-82ec28929cc960d4c62d97963ec627c944e17f66.tar.gz barebox-82ec28929cc960d4c62d97963ec627c944e17f66.tar.xz |
net: fec_imx: Do not use DMA coherent memory for Rx buffers
Trying to do unaligned access of coherent memory on AArch64 will lead
to an abort and some parts of our IP stack will do exactly that with
received packet buffer by using memcpy() to extracts parts of it.
Convert the driver to use regular memory for received data buffers to
prevent the issue from happening.
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'drivers/net/fec_imx.c')
-rw-r--r-- | drivers/net/fec_imx.c | 29 |
1 files changed, 25 insertions, 4 deletions
diff --git a/drivers/net/fec_imx.c b/drivers/net/fec_imx.c index 33f2da84af..d304b94c56 100644 --- a/drivers/net/fec_imx.c +++ b/drivers/net/fec_imx.c @@ -558,6 +558,14 @@ static int fec_recv(struct eth_device *dev) if (data_length - 4 > 14) { void *frame = phys_to_virt(readl(&rbd->data_pointer)); + /* + * Sync the data for CPU so that endianness + * fixup and net_receive below would get + * proper data + */ + dma_sync_single_for_cpu((unsigned long)frame, + data_length, + DMA_FROM_DEVICE); if (fec_is_imx28(fec)) imx28_fix_endianess_rd(frame, (data_length + 3) >> 2); @@ -567,6 +575,9 @@ static int fec_recv(struct eth_device *dev) */ len = data_length - 4; net_receive(dev, frame, len); + dma_sync_single_for_device((unsigned long)frame, + data_length, + DMA_FROM_DEVICE); } } /* @@ -585,13 +596,23 @@ static int fec_alloc_receive_packets(struct fec_priv *fec, int count, int size) void *p; int i; - /* reserve data memory and consider alignment */ - p = dma_alloc_coherent(size * count, DMA_ADDRESS_BROKEN); + + p = dma_alloc(size * count); if (!p) return -ENOMEM; for (i = 0; i < count; i++) { - writel(virt_to_phys(p), &fec->rbd_base[i].data_pointer); + dma_addr_t dma; + /* + * Make sure there are no outstanding writes to the + * region of memory we are going to use as receive + * buffers as well as check that DMA mapping is valid + */ + dma = dma_map_single(fec->dev, p, size, DMA_FROM_DEVICE); + if (dma_mapping_error(fec->dev, dma)) + return -EFAULT; + + writel(dma, &fec->rbd_base[i].data_pointer); p += size; } @@ -601,7 +622,7 @@ static int fec_alloc_receive_packets(struct fec_priv *fec, int count, int size) static void fec_free_receive_packets(struct fec_priv *fec, int count, int size) { void *p = phys_to_virt(fec->rbd_base[0].data_pointer); - dma_free_coherent(p, 0, size * count); + dma_free(p); } #ifdef CONFIG_OFDEVICE |