From 408fca0abe9e8b608c8eb78a47a6ced801fdb149 Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Tue, 8 Sep 2015 21:48:59 +0200 Subject: add fix for macb driver for avr32 from Linux git --- ...1-net-macb-improve-big-endian-CPU-support.patch | 282 +++++++++++++++++++++ 1 file changed, 282 insertions(+) create mode 100644 target/avr32/atmel-ngw100/patches/4.1.6/0001-net-macb-improve-big-endian-CPU-support.patch (limited to 'target/avr32') diff --git a/target/avr32/atmel-ngw100/patches/4.1.6/0001-net-macb-improve-big-endian-CPU-support.patch b/target/avr32/atmel-ngw100/patches/4.1.6/0001-net-macb-improve-big-endian-CPU-support.patch new file mode 100644 index 000000000..96a0a96b6 --- /dev/null +++ b/target/avr32/atmel-ngw100/patches/4.1.6/0001-net-macb-improve-big-endian-CPU-support.patch @@ -0,0 +1,282 @@ +From f2ce8a9e48385f444389e75cfe293637c3eb5410 Mon Sep 17 00:00:00 2001 +From: Andy Shevchenko +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 +Signed-off-by: David S. Miller +Signed-off-by: Waldemar Brodkorb +--- + 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 ++++ b/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 ++++ b/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 + -- cgit v1.2.3