|
@@ -0,0 +1,282 @@
|
|
|
+From f2ce8a9e48385f444389e75cfe293637c3eb5410 Mon Sep 17 00:00:00 2001
|
|
|
+From: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
|
|
|
+Date: Fri, 24 Jul 2015 21:23:59 +0300
|
|
|
+Subject: [PATCH] net/macb: improve big endian CPU support
|
|
|
+
|
|
|
+The commit a50dad355a53 (net: macb: Add big endian CPU support) converted I/O
|
|
|
+accessors to readl_relaxed() and writel_relaxed() and consequentially broke
|
|
|
+MACB driver on AVR32 platforms such as ATNGW100.
|
|
|
+
|
|
|
+This patch improves I/O access by checking endiannes first and use the
|
|
|
+corresponding methods.
|
|
|
+
|
|
|
+Fixes: a50dad355a53 (net: macb: Add big endian CPU support)
|
|
|
+Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
|
|
|
+Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
|
+Signed-off-by: Waldemar Brodkorb <wbx@openadk.org>
|
|
|
+---
|
|
|
+ drivers/net/ethernet/cadence/macb.c | 103 ++++++++++++++++++++++++++---------
|
|
|
+ drivers/net/ethernet/cadence/macb.h | 28 ++++------
|
|
|
+ 2 files changed, 87 insertions(+), 44 deletions(-)
|
|
|
+
|
|
|
+diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
|
|
|
+index caeb395..9d06e3d 100644
|
|
|
+--- a/drivers/net/ethernet/cadence/macb.c
|
|
|
|
|
|
+@@ -104,6 +104,57 @@ static void *macb_rx_buffer(struct macb *bp, unsigned int index)
|
|
|
+ return bp->rx_buffers + bp->rx_buffer_size * macb_rx_ring_wrap(index);
|
|
|
+ }
|
|
|
+
|
|
|
++/* I/O accessors */
|
|
|
++static u32 hw_readl_native(struct macb *bp, int offset)
|
|
|
++{
|
|
|
++ return __raw_readl(bp->regs + offset);
|
|
|
++}
|
|
|
++
|
|
|
++static void hw_writel_native(struct macb *bp, int offset, u32 value)
|
|
|
++{
|
|
|
++ __raw_writel(value, bp->regs + offset);
|
|
|
++}
|
|
|
++
|
|
|
++static u32 hw_readl(struct macb *bp, int offset)
|
|
|
++{
|
|
|
++ return readl_relaxed(bp->regs + offset);
|
|
|
++}
|
|
|
++
|
|
|
++static void hw_writel(struct macb *bp, int offset, u32 value)
|
|
|
++{
|
|
|
++ writel_relaxed(value, bp->regs + offset);
|
|
|
++}
|
|
|
++
|
|
|
++/*
|
|
|
++ * Find the CPU endianness by using the loopback bit of NCR register. When the
|
|
|
++ * CPU is in big endian we need to program swaped mode for management
|
|
|
++ * descriptor access.
|
|
|
++ */
|
|
|
++static bool hw_is_native_io(void __iomem *addr)
|
|
|
++{
|
|
|
++ u32 value = MACB_BIT(LLB);
|
|
|
++
|
|
|
++ __raw_writel(value, addr + MACB_NCR);
|
|
|
++ value = __raw_readl(addr + MACB_NCR);
|
|
|
++
|
|
|
++ /* Write 0 back to disable everything */
|
|
|
++ __raw_writel(0, addr + MACB_NCR);
|
|
|
++
|
|
|
++ return value == MACB_BIT(LLB);
|
|
|
++}
|
|
|
++
|
|
|
++static bool hw_is_gem(void __iomem *addr, bool native_io)
|
|
|
++{
|
|
|
++ u32 id;
|
|
|
++
|
|
|
++ if (native_io)
|
|
|
++ id = __raw_readl(addr + MACB_MID);
|
|
|
++ else
|
|
|
++ id = readl_relaxed(addr + MACB_MID);
|
|
|
++
|
|
|
++ return MACB_BFEXT(IDNUM, id) >= 0x2;
|
|
|
++}
|
|
|
++
|
|
|
+ static void macb_set_hwaddr(struct macb *bp)
|
|
|
+ {
|
|
|
+ u32 bottom;
|
|
|
+@@ -449,14 +500,14 @@ err_out:
|
|
|
+
|
|
|
+ static void macb_update_stats(struct macb *bp)
|
|
|
+ {
|
|
|
+- u32 __iomem *reg = bp->regs + MACB_PFR;
|
|
|
+ u32 *p = &bp->hw_stats.macb.rx_pause_frames;
|
|
|
+ u32 *end = &bp->hw_stats.macb.tx_pause_frames + 1;
|
|
|
++ int offset = MACB_PFR;
|
|
|
+
|
|
|
+ WARN_ON((unsigned long)(end - p - 1) != (MACB_TPF - MACB_PFR) / 4);
|
|
|
+
|
|
|
+- for(; p < end; p++, reg++)
|
|
|
+- *p += readl_relaxed(reg);
|
|
|
++ for(; p < end; p++, offset += 4)
|
|
|
++ *p += bp->readl(bp, offset);
|
|
|
+ }
|
|
|
+
|
|
|
+ static int macb_halt_tx(struct macb *bp)
|
|
|
+@@ -1603,7 +1654,6 @@ static u32 macb_dbw(struct macb *bp)
|
|
|
+ static void macb_configure_dma(struct macb *bp)
|
|
|
+ {
|
|
|
+ u32 dmacfg;
|
|
|
+- u32 tmp, ncr;
|
|
|
+
|
|
|
+ if (macb_is_gem(bp)) {
|
|
|
+ dmacfg = gem_readl(bp, DMACFG) & ~GEM_BF(RXBS, -1L);
|
|
|
+@@ -1613,22 +1663,11 @@ static void macb_configure_dma(struct macb *bp)
|
|
|
+ dmacfg |= GEM_BIT(TXPBMS) | GEM_BF(RXBMS, -1L);
|
|
|
+ dmacfg &= ~GEM_BIT(ENDIA_PKT);
|
|
|
+
|
|
|
+- /* Find the CPU endianness by using the loopback bit of net_ctrl
|
|
|
+- * register. save it first. When the CPU is in big endian we
|
|
|
+- * need to program swaped mode for management descriptor access.
|
|
|
+- */
|
|
|
+- ncr = macb_readl(bp, NCR);
|
|
|
+- __raw_writel(MACB_BIT(LLB), bp->regs + MACB_NCR);
|
|
|
+- tmp = __raw_readl(bp->regs + MACB_NCR);
|
|
|
+-
|
|
|
+- if (tmp == MACB_BIT(LLB))
|
|
|
++ if (bp->native_io)
|
|
|
+ dmacfg &= ~GEM_BIT(ENDIA_DESC);
|
|
|
+ else
|
|
|
+ dmacfg |= GEM_BIT(ENDIA_DESC); /* CPU in big endian */
|
|
|
+
|
|
|
+- /* Restore net_ctrl */
|
|
|
+- macb_writel(bp, NCR, ncr);
|
|
|
+-
|
|
|
+ if (bp->dev->features & NETIF_F_HW_CSUM)
|
|
|
+ dmacfg |= GEM_BIT(TXCOEN);
|
|
|
+ else
|
|
|
+@@ -1902,14 +1941,14 @@ static void gem_update_stats(struct macb *bp)
|
|
|
+
|
|
|
+ for (i = 0; i < GEM_STATS_LEN; ++i, ++p) {
|
|
|
+ u32 offset = gem_statistics[i].offset;
|
|
|
+- u64 val = readl_relaxed(bp->regs + offset);
|
|
|
++ u64 val = bp->readl(bp, offset);
|
|
|
+
|
|
|
+ bp->ethtool_stats[i] += val;
|
|
|
+ *p += val;
|
|
|
+
|
|
|
+ if (offset == GEM_OCTTXL || offset == GEM_OCTRXL) {
|
|
|
+ /* Add GEM_OCTTXH, GEM_OCTRXH */
|
|
|
+- val = readl_relaxed(bp->regs + offset + 4);
|
|
|
++ val = bp->readl(bp, offset + 4);
|
|
|
+ bp->ethtool_stats[i] += ((u64)val) << 32;
|
|
|
+ *(++p) += val;
|
|
|
+ }
|
|
|
+@@ -2190,7 +2229,7 @@ static void macb_configure_caps(struct macb *bp, const struct macb_config *dt_co
|
|
|
+ if (dt_conf)
|
|
|
+ bp->caps = dt_conf->caps;
|
|
|
+
|
|
|
+- if (macb_is_gem_hw(bp->regs)) {
|
|
|
++ if (hw_is_gem(bp->regs, bp->native_io)) {
|
|
|
+ bp->caps |= MACB_CAPS_MACB_IS_GEM;
|
|
|
+
|
|
|
+ dcfg = gem_readl(bp, DCFG1);
|
|
|
+@@ -2205,6 +2244,7 @@ static void macb_configure_caps(struct macb *bp, const struct macb_config *dt_co
|
|
|
+ }
|
|
|
+
|
|
|
+ static void macb_probe_queues(void __iomem *mem,
|
|
|
++ bool native_io,
|
|
|
+ unsigned int *queue_mask,
|
|
|
+ unsigned int *num_queues)
|
|
|
+ {
|
|
|
+@@ -2219,7 +2259,7 @@ static void macb_probe_queues(void __iomem *mem,
|
|
|
+ * we are early in the probe process and don't have the
|
|
|
+ * MACB_CAPS_MACB_IS_GEM flag positioned
|
|
|
+ */
|
|
|
+- if (!macb_is_gem_hw(mem))
|
|
|
++ if (!hw_is_gem(mem, native_io))
|
|
|
+ return;
|
|
|
+
|
|
|
+ /* bit 0 is never set but queue 0 always exists */
|
|
|
+@@ -2786,6 +2826,7 @@ static int macb_probe(struct platform_device *pdev)
|
|
|
+ struct clk *pclk, *hclk, *tx_clk;
|
|
|
+ unsigned int queue_mask, num_queues;
|
|
|
+ struct macb_platform_data *pdata;
|
|
|
++ bool native_io;
|
|
|
+ struct phy_device *phydev;
|
|
|
+ struct net_device *dev;
|
|
|
+ struct resource *regs;
|
|
|
+@@ -2794,6 +2835,11 @@ static int macb_probe(struct platform_device *pdev)
|
|
|
+ struct macb *bp;
|
|
|
+ int err;
|
|
|
+
|
|
|
++ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
|
++ mem = devm_ioremap_resource(&pdev->dev, regs);
|
|
|
++ if (IS_ERR(mem))
|
|
|
++ return PTR_ERR(mem);
|
|
|
++
|
|
|
+ if (np) {
|
|
|
+ const struct of_device_id *match;
|
|
|
+
|
|
|
+@@ -2809,14 +2855,9 @@ static int macb_probe(struct platform_device *pdev)
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+
|
|
|
+- regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
|
+- mem = devm_ioremap_resource(&pdev->dev, regs);
|
|
|
+- if (IS_ERR(mem)) {
|
|
|
+- err = PTR_ERR(mem);
|
|
|
+- goto err_disable_clocks;
|
|
|
+- }
|
|
|
++ native_io = hw_is_native_io(mem);
|
|
|
+
|
|
|
+- macb_probe_queues(mem, &queue_mask, &num_queues);
|
|
|
++ macb_probe_queues(mem, native_io, &queue_mask, &num_queues);
|
|
|
+ dev = alloc_etherdev_mq(sizeof(*bp), num_queues);
|
|
|
+ if (!dev) {
|
|
|
+ err = -ENOMEM;
|
|
|
+@@ -2831,6 +2872,14 @@ static int macb_probe(struct platform_device *pdev)
|
|
|
+ bp->pdev = pdev;
|
|
|
+ bp->dev = dev;
|
|
|
+ bp->regs = mem;
|
|
|
++ bp->native_io = native_io;
|
|
|
++ if (native_io) {
|
|
|
++ bp->readl = hw_readl_native;
|
|
|
++ bp->writel = hw_writel_native;
|
|
|
++ } else {
|
|
|
++ bp->readl = hw_readl;
|
|
|
++ bp->writel = hw_writel;
|
|
|
++ }
|
|
|
+ bp->num_queues = num_queues;
|
|
|
+ bp->queue_mask = queue_mask;
|
|
|
+ if (macb_config)
|
|
|
+diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
|
|
|
+index d746559..f245340 100644
|
|
|
+--- a/drivers/net/ethernet/cadence/macb.h
|
|
|
|
|
|
+@@ -429,18 +429,12 @@
|
|
|
+ | GEM_BF(name, value))
|
|
|
+
|
|
|
+ /* Register access macros */
|
|
|
+-#define macb_readl(port,reg) \
|
|
|
+- readl_relaxed((port)->regs + MACB_##reg)
|
|
|
+-#define macb_writel(port,reg,value) \
|
|
|
+- writel_relaxed((value), (port)->regs + MACB_##reg)
|
|
|
+-#define gem_readl(port, reg) \
|
|
|
+- readl_relaxed((port)->regs + GEM_##reg)
|
|
|
+-#define gem_writel(port, reg, value) \
|
|
|
+- writel_relaxed((value), (port)->regs + GEM_##reg)
|
|
|
+-#define queue_readl(queue, reg) \
|
|
|
+- readl_relaxed((queue)->bp->regs + (queue)->reg)
|
|
|
+-#define queue_writel(queue, reg, value) \
|
|
|
+- writel_relaxed((value), (queue)->bp->regs + (queue)->reg)
|
|
|
++#define macb_readl(port, reg) (port)->readl((port), MACB_##reg)
|
|
|
++#define macb_writel(port, reg, value) (port)->writel((port), MACB_##reg, (value))
|
|
|
++#define gem_readl(port, reg) (port)->readl((port), GEM_##reg)
|
|
|
++#define gem_writel(port, reg, value) (port)->writel((port), GEM_##reg, (value))
|
|
|
++#define queue_readl(queue, reg) (queue)->bp->readl((queue)->bp, (queue)->reg)
|
|
|
++#define queue_writel(queue, reg, value) (queue)->bp->writel((queue)->bp, (queue)->reg, (value))
|
|
|
+
|
|
|
+ /* 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
|
|
|
+@@ -785,6 +779,11 @@ struct macb_queue {
|
|
|
+
|
|
|
+ struct macb {
|
|
|
+ void __iomem *regs;
|
|
|
++ bool native_io;
|
|
|
++
|
|
|
++ /* hardware IO accessors */
|
|
|
++ u32 (*readl)(struct macb *bp, int offset);
|
|
|
++ void (*writel)(struct macb *bp, int offset, u32 value);
|
|
|
+
|
|
|
+ unsigned int rx_tail;
|
|
|
+ unsigned int rx_prepared_head;
|
|
|
+@@ -843,9 +842,4 @@ static inline bool macb_is_gem(struct macb *bp)
|
|
|
+ return !!(bp->caps & MACB_CAPS_MACB_IS_GEM);
|
|
|
+ }
|
|
|
+
|
|
|
+-static inline bool macb_is_gem_hw(void __iomem *addr)
|
|
|
+-{
|
|
|
+- return !!(MACB_BFEXT(IDNUM, readl_relaxed(addr + MACB_MID)) >= 0x2);
|
|
|
+-}
|
|
|
+-
|
|
|
+ #endif /* _MACB_H */
|
|
|
+--
|
|
|
+1.7.10.4
|
|
|
+
|