diff options
author | Ben Dooks <ben.dooks@codethink.co.uk> | 2015-03-13 18:14:52 +0000 |
---|---|---|
committer | Ben Dooks <ben.dooks@codethink.co.uk> | 2015-03-13 19:07:54 +0000 |
commit | 1ce30392e7393441cc2e26877f35aa580291b869 (patch) | |
tree | 1997071aa6cfd7c4a71fd6aa108704cab00526a3 | |
parent | 37fdc802818fb512d2143ffaf07ddd734405afb2 (diff) | |
download | linux-1ce30392e7393441cc2e26877f35aa580291b869.tar.gz |
macb: fix issues with running on ARM big-endianbaserock/bjdooks/zynq-be
The macb driver does not work on an ARM cpu running in big-endian
mode due to two issues with register access and ring building.
The register code uses __raw_readl and __raw_writel which do not
take into account CPU versus bus endian-ness. This is fixed by
changing to use the readl_relaxed and writel_relaxed accesors
which deal with endianness without adding strict ordering.
When building the ring, the data must also be written in le32
format as the hardware expects to be reading data in little-edian
wheras the cpu is writing to memory in big endian. Use the
appropriate __le32 conversion functions.
Tested on an Xilinx Zynq on a Digilent Zybo board.
Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>
--
CC: Nicolas Ferre <nicolas.ferre@atmel.com>
CC: Linux Networking <netdev@vger.kernel.org>
-rw-r--r-- | drivers/net/ethernet/cadence/macb.c | 44 | ||||
-rw-r--r-- | drivers/net/ethernet/cadence/macb.h | 12 |
2 files changed, 28 insertions, 28 deletions
diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index ad76b8e35a00..e668d82b069c 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -533,7 +533,7 @@ static void macb_tx_error_task(struct work_struct *work) u32 ctrl; desc = macb_tx_desc(queue, tail); - ctrl = desc->ctrl; + ctrl = le32_to_cpu(desc->ctrl); tx_skb = macb_tx_skb(queue, tail); skb = tx_skb->skb; @@ -565,7 +565,7 @@ static void macb_tx_error_task(struct work_struct *work) netdev_err(bp->dev, "BUG: TX buffers exhausted mid-frame\n"); - desc->ctrl = ctrl | MACB_BIT(TX_USED); + desc->ctrl = cpu_to_le32(ctrl | MACB_BIT(TX_USED)); } macb_tx_unmap(bp, tx_skb); @@ -574,7 +574,7 @@ static void macb_tx_error_task(struct work_struct *work) /* Set end of TX queue */ desc = macb_tx_desc(queue, 0); desc->addr = 0; - desc->ctrl = MACB_BIT(TX_USED); + desc->ctrl = cpu_to_le32(MACB_BIT(TX_USED)); /* Make descriptor updates visible to hardware */ wmb(); @@ -625,7 +625,7 @@ static void macb_tx_interrupt(struct macb_queue *queue) /* Make hw descriptor updates visible to CPU */ rmb(); - ctrl = desc->ctrl; + ctrl = le32_to_cpu(desc->ctrl); /* TX_USED bit is only set by hardware on the very first buffer * descriptor of the transmitted frame. @@ -700,7 +700,7 @@ static void gem_rx_refill(struct macb *bp) if (entry == RX_RING_SIZE - 1) paddr |= MACB_BIT(RX_WRAP); - bp->rx_ring[entry].addr = paddr; + bp->rx_ring[entry].addr = cpu_to_le32(paddr); bp->rx_ring[entry].ctrl = 0; /* properly align Ethernet header */ @@ -723,7 +723,7 @@ static void discard_partial_frame(struct macb *bp, unsigned int begin, for (frag = begin; frag != end; frag++) { struct macb_dma_desc *desc = macb_rx_desc(bp, frag); - desc->addr &= ~MACB_BIT(RX_USED); + desc->addr &= cpu_to_le32(~MACB_BIT(RX_USED)); } /* Make descriptor updates visible to hardware */ @@ -753,8 +753,8 @@ static int gem_rx(struct macb *bp, int budget) /* Make hw descriptor updates visible to CPU */ rmb(); - addr = desc->addr; - ctrl = desc->ctrl; + addr = le32_to_cpu(desc->addr); + ctrl = le32_to_cpu(desc->ctrl); if (!(addr & MACB_BIT(RX_USED))) break; @@ -823,7 +823,7 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag, struct macb_dma_desc *desc; desc = macb_rx_desc(bp, last_frag); - len = MACB_BFEXT(RX_FRMLEN, desc->ctrl); + len = MACB_BFEXT(RX_FRMLEN, le32_to_cpu(desc->ctrl)); netdev_vdbg(bp->dev, "macb_rx_frame frags %u - %u (len %u)\n", macb_rx_ring_wrap(first_frag), @@ -843,7 +843,7 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag, bp->stats.rx_dropped++; for (frag = first_frag; ; frag++) { desc = macb_rx_desc(bp, frag); - desc->addr &= ~MACB_BIT(RX_USED); + desc->addr &= cpu_to_le32(~MACB_BIT(RX_USED)); if (frag == last_frag) break; } @@ -904,8 +904,8 @@ static int macb_rx(struct macb *bp, int budget) /* Make hw descriptor updates visible to CPU */ rmb(); - addr = desc->addr; - ctrl = desc->ctrl; + addr = le32_to_cpu(desc->addr); + ctrl = le32_to_cpu(desc->ctrl); if (!(addr & MACB_BIT(RX_USED))) break; @@ -1176,7 +1176,7 @@ static unsigned int macb_tx_map(struct macb *bp, entry = macb_tx_ring_wrap(i); ctrl = MACB_BIT(TX_USED); desc = &queue->tx_ring[entry]; - desc->ctrl = ctrl; + desc->ctrl = cpu_to_le32(ctrl); do { i--; @@ -1193,12 +1193,12 @@ static unsigned int macb_tx_map(struct macb *bp, ctrl |= MACB_BIT(TX_WRAP); /* Set TX buffer descriptor */ - desc->addr = tx_skb->mapping; + desc->addr = cpu_to_le32(tx_skb->mapping); /* desc->addr must be visible to hardware before clearing * 'TX_USED' bit in desc->ctrl. */ wmb(); - desc->ctrl = ctrl; + desc->ctrl = cpu_to_le32(ctrl); } while (i != queue->tx_head); queue->tx_head = tx_head; @@ -1315,7 +1315,7 @@ static void gem_free_rx_buffers(struct macb *bp) continue; desc = &bp->rx_ring[i]; - addr = MACB_BF(RX_WADDR, MACB_BFEXT(RX_WADDR, desc->addr)); + addr = MACB_BF(RX_WADDR, MACB_BFEXT(RX_WADDR, le32_to_cpu(desc->addr))); dma_unmap_single(&bp->pdev->dev, addr, bp->rx_buffer_size, DMA_FROM_DEVICE); dev_kfree_skb_any(skb); @@ -1442,9 +1442,9 @@ static void gem_init_rings(struct macb *bp) for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) { for (i = 0; i < TX_RING_SIZE; i++) { queue->tx_ring[i].addr = 0; - queue->tx_ring[i].ctrl = MACB_BIT(TX_USED); + queue->tx_ring[i].ctrl = cpu_to_le32(MACB_BIT(TX_USED)); } - queue->tx_ring[TX_RING_SIZE - 1].ctrl |= MACB_BIT(TX_WRAP); + queue->tx_ring[TX_RING_SIZE - 1].ctrl |= cpu_to_le32(MACB_BIT(TX_WRAP)); queue->tx_head = 0; queue->tx_tail = 0; } @@ -1462,19 +1462,19 @@ static void macb_init_rings(struct macb *bp) addr = bp->rx_buffers_dma; for (i = 0; i < RX_RING_SIZE; i++) { - bp->rx_ring[i].addr = addr; + bp->rx_ring[i].addr = cpu_to_le32(addr); bp->rx_ring[i].ctrl = 0; addr += bp->rx_buffer_size; } - bp->rx_ring[RX_RING_SIZE - 1].addr |= MACB_BIT(RX_WRAP); + bp->rx_ring[RX_RING_SIZE - 1].addr |= cpu_to_le32(MACB_BIT(RX_WRAP)); for (i = 0; i < TX_RING_SIZE; i++) { bp->queues[0].tx_ring[i].addr = 0; - bp->queues[0].tx_ring[i].ctrl = MACB_BIT(TX_USED); + bp->queues[0].tx_ring[i].ctrl = cpu_to_le32(MACB_BIT(TX_USED)); bp->queues[0].tx_head = 0; bp->queues[0].tx_tail = 0; } - bp->queues[0].tx_ring[TX_RING_SIZE - 1].ctrl |= MACB_BIT(TX_WRAP); + bp->queues[0].tx_ring[TX_RING_SIZE - 1].ctrl |= cpu_to_le32(MACB_BIT(TX_WRAP)); bp->rx_tail = 0; } diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index 31dc080f2437..22d66a73c781 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -423,17 +423,17 @@ /* Register access macros */ #define macb_readl(port,reg) \ - __raw_readl((port)->regs + MACB_##reg) + readl_relaxed((port)->regs + MACB_##reg) #define macb_writel(port,reg,value) \ - __raw_writel((value), (port)->regs + MACB_##reg) + writel_relaxed((value), (port)->regs + MACB_##reg) #define gem_readl(port, reg) \ - __raw_readl((port)->regs + GEM_##reg) + readl_relaxed((port)->regs + GEM_##reg) #define gem_writel(port, reg, value) \ - __raw_writel((value), (port)->regs + GEM_##reg) + writel_relaxed((value), (port)->regs + GEM_##reg) #define queue_readl(queue, reg) \ - __raw_readl((queue)->bp->regs + (queue)->reg) + readl_relaxed((queue)->bp->regs + (queue)->reg) #define queue_writel(queue, reg, value) \ - __raw_writel((value), (queue)->bp->regs + (queue)->reg) + writel_relaxed((value), (queue)->bp->regs + (queue)->reg) /* Conditional GEM/MACB macros. These perform the operation to the correct * register dependent on whether the device is a GEM or a MACB. For registers |