summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAndrey Smirnov <andrew.smirnov@gmail.com>2018-09-17 22:21:22 -0700
committerSascha Hauer <s.hauer@pengutronix.de>2018-09-19 09:55:54 +0200
commit82ec28929cc960d4c62d97963ec627c944e17f66 (patch)
treee0f0c9dc25242c3ff8f5a8cbb28a4e469a52a07e /drivers
parent26e76f9f88d523de0b97ecb4dcc046ce76754f63 (diff)
downloadbarebox-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')
-rw-r--r--drivers/net/fec_imx.c29
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