| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282 | From f2ce8a9e48385f444389e75cfe293637c3eb5410 Mon Sep 17 00:00:00 2001From: Andy Shevchenko <andriy.shevchenko@linux.intel.com>Date: Fri, 24 Jul 2015 21:23:59 +0300Subject: [PATCH] net/macb: improve big endian CPU supportThe commit a50dad355a53 (net: macb: Add big endian CPU support) converted I/Oaccessors to readl_relaxed() and writel_relaxed() and consequentially brokeMACB driver on AVR32 platforms such as ATNGW100.This patch improves I/O access by checking endiannes first and use thecorresponding 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.cindex 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.hindex 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
 |