All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH net-next 00/13] Xilinx axienet driver updates
@ 2019-05-31 18:15 Robert Hancock
  2019-05-31 18:15 ` [PATCH net-next 01/13] net: axienet: Fixed 64-bit compile, enable build on X86 and ARM Robert Hancock
                   ` (12 more replies)
  0 siblings, 13 replies; 22+ messages in thread
From: Robert Hancock @ 2019-05-31 18:15 UTC (permalink / raw)
  To: netdev; +Cc: anirudh, John.Linn, Robert Hancock

This is a series of enhancements and bug fixes in order to get the mainline
version of this driver into a more generally usable state, including on
x86 or ARM platforms. It also converts the driver to use the phylink API
in order to provide support for SFP modules.

Robert Hancock (13):
  net: axienet: Fixed 64-bit compile, enable build on X86 and ARM
  net: axienet: clean up MDIO handling
  net: axienet: Cleanup DMA device reset and halt process
  net: axienet: Make RX/TX ring sizes configurable
  net: axienet: Add DMA registers to ethtool register dump
  net: axienet: Support shared interrupts
  net: axienet: Add optional support for Ethernet core interrupt
  net: axienet: Fix race condition causing TX hang
  net: axienet: Make missing MAC address non-fatal
  net: axienet: stop interface during shutdown
  net: axienet: document axistream-connected attribute
  net: axienet: make use of axistream-connected attribute optional
  net: axienet: convert to phylink API

 .../devicetree/bindings/net/xilinx_axienet.txt     |  24 +-
 drivers/net/ethernet/xilinx/Kconfig                |   6 +-
 drivers/net/ethernet/xilinx/xilinx_axienet.h       |  43 +-
 drivers/net/ethernet/xilinx/xilinx_axienet_main.c  | 652 ++++++++++++++-------
 drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c  | 171 +++---
 5 files changed, 602 insertions(+), 294 deletions(-)

-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH net-next 01/13] net: axienet: Fixed 64-bit compile, enable build on X86 and ARM
  2019-05-31 18:15 [PATCH net-next 00/13] Xilinx axienet driver updates Robert Hancock
@ 2019-05-31 18:15 ` Robert Hancock
  2019-05-31 21:10   ` Andrew Lunn
  2019-06-02  6:37   ` kbuild test robot
  2019-05-31 18:15 ` [PATCH net-next 02/13] net: axienet: clean up MDIO handling Robert Hancock
                   ` (11 subsequent siblings)
  12 siblings, 2 replies; 22+ messages in thread
From: Robert Hancock @ 2019-05-31 18:15 UTC (permalink / raw)
  To: netdev; +Cc: anirudh, John.Linn, Robert Hancock

Fixed some 64-bit issues in this driver, such as casting skb pointers to
32-bit values. Also changed the way the MDIO bus name was constructed so
that it works in all cases.

Signed-off-by: Robert Hancock <hancock@sedsystems.ca>
---
 drivers/net/ethernet/xilinx/Kconfig               |  4 +--
 drivers/net/ethernet/xilinx/xilinx_axienet.h      | 25 +++++++++------
 drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 39 +++++++++++++++--------
 drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c | 11 +++----
 4 files changed, 47 insertions(+), 32 deletions(-)

diff --git a/drivers/net/ethernet/xilinx/Kconfig b/drivers/net/ethernet/xilinx/Kconfig
index af96e05..f0b6896 100644
--- a/drivers/net/ethernet/xilinx/Kconfig
+++ b/drivers/net/ethernet/xilinx/Kconfig
@@ -6,7 +6,7 @@
 config NET_VENDOR_XILINX
 	bool "Xilinx devices"
 	default y
-	depends on PPC || PPC32 || MICROBLAZE || ARCH_ZYNQ || MIPS || X86 || COMPILE_TEST
+	depends on PPC || PPC32 || MICROBLAZE || ARCH_ZYNQ || MIPS || X86 || ARM || COMPILE_TEST
 	---help---
 	  If you have a network (Ethernet) card belonging to this class, say Y.
 
@@ -26,7 +26,7 @@ config XILINX_EMACLITE
 
 config XILINX_AXI_EMAC
 	tristate "Xilinx 10/100/1000 AXI Ethernet support"
-	depends on MICROBLAZE
+	depends on MICROBLAZE || X86 || ARM
 	select PHYLIB
 	---help---
 	  This driver supports the 10/100/1000 Ethernet from Xilinx for the
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h b/drivers/net/ethernet/xilinx/xilinx_axienet.h
index 011adae..0d89ebc 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet.h
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h
@@ -356,9 +356,6 @@
  * @app2:         MM2S/S2MM User Application Field 2.
  * @app3:         MM2S/S2MM User Application Field 3.
  * @app4:         MM2S/S2MM User Application Field 4.
- * @sw_id_offset: MM2S/S2MM Sw ID
- * @reserved5:    Reserved and not used
- * @reserved6:    Reserved and not used
  */
 struct axidma_bd {
 	u32 next;	/* Physical address of next buffer descriptor */
@@ -373,11 +370,9 @@ struct axidma_bd {
 	u32 app1;	/* TX start << 16 | insert */
 	u32 app2;	/* TX csum seed */
 	u32 app3;
-	u32 app4;
-	u32 sw_id_offset;
-	u32 reserved5;
-	u32 reserved6;
-};
+	u32 app4;   /* Last field used by HW */
+	struct sk_buff *skb;
+} __aligned(XAXIDMA_BD_MINIMUM_ALIGNMENT);
 
 /**
  * struct axienet_local - axienet private per device data
@@ -385,6 +380,7 @@ struct axidma_bd {
  * @dev:	Pointer to device structure
  * @phy_node:	Pointer to device node structure
  * @mii_bus:	Pointer to MII bus structure
+ * @regs_start: Resource start for axienet device addresses
  * @regs:	Base address for the axienet_local device address space
  * @dma_regs:	Base address for the axidma device address space
  * @dma_err_tasklet: Tasklet structure to process Axi DMA errors
@@ -426,6 +422,7 @@ struct axienet_local {
 	struct mii_bus *mii_bus;	/* MII bus reference */
 
 	/* IO registers, dma functions and IRQs */
+	resource_size_t regs_start;
 	void __iomem *regs;
 	void __iomem *dma_regs;
 
@@ -481,7 +478,11 @@ struct axienet_option {
  */
 static inline u32 axienet_ior(struct axienet_local *lp, off_t offset)
 {
-	return in_be32(lp->regs + offset);
+#ifdef CONFIG_MICROBLAZE
+	return __raw_readl(lp->regs + offset);
+#else
+	return ioread32(lp->regs + offset);
+#endif
 }
 
 static inline u32 axinet_ior_read_mcr(struct axienet_local *lp)
@@ -501,7 +502,11 @@ static inline u32 axinet_ior_read_mcr(struct axienet_local *lp)
 static inline void axienet_iow(struct axienet_local *lp, off_t offset,
 			       u32 value)
 {
-	out_be32((lp->regs + offset), value);
+#ifdef CONFIG_MICROBLAZE
+	__raw_writel(value, lp->regs + offset);
+#else
+	iowrite32(value, lp->regs + offset);
+#endif
 }
 
 /* Function prototypes visible in xilinx_axienet_mdio.c for other files */
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index 831967f..c0a8861 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -125,7 +125,11 @@
  */
 static inline u32 axienet_dma_in32(struct axienet_local *lp, off_t reg)
 {
-	return in_be32(lp->dma_regs + reg);
+#ifdef CONFIG_MICROBLAZE
+	return __raw_readl(lp->dma_regs + reg);
+#else
+	return ioread32(lp->dma_regs + reg);
+#endif
 }
 
 /**
@@ -140,7 +144,11 @@ static inline u32 axienet_dma_in32(struct axienet_local *lp, off_t reg)
 static inline void axienet_dma_out32(struct axienet_local *lp,
 				     off_t reg, u32 value)
 {
-	out_be32((lp->dma_regs + reg), value);
+#ifdef CONFIG_MICROBLAZE
+	__raw_writel(value, lp->dma_regs + reg);
+#else
+	iowrite32(value, lp->dma_regs + reg);
+#endif
 }
 
 /**
@@ -159,8 +167,7 @@ static void axienet_dma_bd_release(struct net_device *ndev)
 	for (i = 0; i < RX_BD_NUM; i++) {
 		dma_unmap_single(ndev->dev.parent, lp->rx_bd_v[i].phys,
 				 lp->max_frm_size, DMA_FROM_DEVICE);
-		dev_kfree_skb((struct sk_buff *)
-			      (lp->rx_bd_v[i].sw_id_offset));
+		dev_kfree_skb(lp->rx_bd_v[i].skb);
 	}
 
 	if (lp->rx_bd_v) {
@@ -227,7 +234,7 @@ static int axienet_dma_bd_init(struct net_device *ndev)
 		if (!skb)
 			goto out;
 
-		lp->rx_bd_v[i].sw_id_offset = (u32) skb;
+		lp->rx_bd_v[i].skb = skb;
 		lp->rx_bd_v[i].phys = dma_map_single(ndev->dev.parent,
 						     skb->data,
 						     lp->max_frm_size,
@@ -595,14 +602,15 @@ static void axienet_start_xmit_done(struct net_device *ndev)
 		dma_unmap_single(ndev->dev.parent, cur_p->phys,
 				(cur_p->cntrl & XAXIDMA_BD_CTRL_LENGTH_MASK),
 				DMA_TO_DEVICE);
-		if (cur_p->app4)
-			dev_consume_skb_irq((struct sk_buff *)cur_p->app4);
+		if (cur_p->skb)
+			dev_consume_skb_irq(cur_p->skb);
 		/*cur_p->phys = 0;*/
 		cur_p->app0 = 0;
 		cur_p->app1 = 0;
 		cur_p->app2 = 0;
 		cur_p->app4 = 0;
 		cur_p->status = 0;
+		cur_p->skb = NULL;
 
 		size += status & XAXIDMA_BD_STS_ACTUAL_LEN_MASK;
 		packets++;
@@ -707,7 +715,7 @@ static inline int axienet_check_tx_bd_space(struct axienet_local *lp,
 	}
 
 	cur_p->cntrl |= XAXIDMA_BD_CTRL_TXEOF_MASK;
-	cur_p->app4 = (unsigned long)skb;
+	cur_p->skb = skb;
 
 	tail_p = lp->tx_bd_p + sizeof(*lp->tx_bd_v) * lp->tx_bd_tail;
 	/* Start the transfer */
@@ -742,13 +750,15 @@ static void axienet_recv(struct net_device *ndev)
 
 	while ((cur_p->status & XAXIDMA_BD_STS_COMPLETE_MASK)) {
 		tail_p = lp->rx_bd_p + sizeof(*lp->rx_bd_v) * lp->rx_bd_ci;
-		skb = (struct sk_buff *) (cur_p->sw_id_offset);
-		length = cur_p->app4 & 0x0000FFFF;
 
 		dma_unmap_single(ndev->dev.parent, cur_p->phys,
 				 lp->max_frm_size,
 				 DMA_FROM_DEVICE);
 
+		skb = cur_p->skb;
+		cur_p->skb = NULL;
+		length = cur_p->app4 & 0x0000FFFF;
+
 		skb_put(skb, length);
 		skb->protocol = eth_type_trans(skb, ndev);
 		/*skb_checksum_none_assert(skb);*/
@@ -783,7 +793,7 @@ static void axienet_recv(struct net_device *ndev)
 					     DMA_FROM_DEVICE);
 		cur_p->cntrl = lp->max_frm_size;
 		cur_p->status = 0;
-		cur_p->sw_id_offset = (u32) new_skb;
+		cur_p->skb = new_skb;
 
 		++lp->rx_bd_ci;
 		lp->rx_bd_ci %= RX_BD_NUM;
@@ -1343,8 +1353,8 @@ static void axienet_dma_err_handler(unsigned long data)
 					 (cur_p->cntrl &
 					  XAXIDMA_BD_CTRL_LENGTH_MASK),
 					 DMA_TO_DEVICE);
-		if (cur_p->app4)
-			dev_kfree_skb_irq((struct sk_buff *) cur_p->app4);
+		if (cur_p->skb)
+			dev_kfree_skb_irq(cur_p->skb);
 		cur_p->phys = 0;
 		cur_p->cntrl = 0;
 		cur_p->status = 0;
@@ -1353,7 +1363,7 @@ static void axienet_dma_err_handler(unsigned long data)
 		cur_p->app2 = 0;
 		cur_p->app3 = 0;
 		cur_p->app4 = 0;
-		cur_p->sw_id_offset = 0;
+		cur_p->skb = NULL;
 	}
 
 	for (i = 0; i < RX_BD_NUM; i++) {
@@ -1478,6 +1488,7 @@ static int axienet_probe(struct platform_device *pdev)
 	lp->options = XAE_OPTION_DEFAULTS;
 	/* Map device registers */
 	ethres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	lp->regs_start = ethres->start;
 	lp->regs = devm_ioremap_resource(&pdev->dev, ethres);
 	if (IS_ERR(lp->regs)) {
 		dev_err(&pdev->dev, "could not map Axi Ethernet regs.\n");
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c b/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c
index 704babd..665ae1d 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c
@@ -127,7 +127,7 @@ int axienet_mdio_setup(struct axienet_local *lp, struct device_node *np)
 	int ret;
 	u32 clk_div, host_clock;
 	struct mii_bus *bus;
-	struct resource res;
+	struct device_node *mdio_node;
 	struct device_node *np1;
 
 	/* clk_div can be calculated by deriving it from the equation:
@@ -199,10 +199,9 @@ int axienet_mdio_setup(struct axienet_local *lp, struct device_node *np)
 	if (!bus)
 		return -ENOMEM;
 
-	np1 = of_get_parent(lp->phy_node);
-	of_address_to_resource(np1, 0, &res);
-	snprintf(bus->id, MII_BUS_ID_SIZE, "%.8llx",
-		 (unsigned long long) res.start);
+	mdio_node = of_get_parent(lp->phy_node);
+	snprintf(bus->id, MII_BUS_ID_SIZE, "axienet-%.8llx",
+		 (unsigned long long)lp->regs_start);
 
 	bus->priv = lp;
 	bus->name = "Xilinx Axi Ethernet MDIO";
@@ -211,7 +210,7 @@ int axienet_mdio_setup(struct axienet_local *lp, struct device_node *np)
 	bus->parent = lp->dev;
 	lp->mii_bus = bus;
 
-	ret = of_mdiobus_register(bus, np1);
+	ret = of_mdiobus_register(bus, mdio_node);
 	if (ret) {
 		mdiobus_free(bus);
 		lp->mii_bus = NULL;
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH net-next 02/13] net: axienet: clean up MDIO handling
  2019-05-31 18:15 [PATCH net-next 00/13] Xilinx axienet driver updates Robert Hancock
  2019-05-31 18:15 ` [PATCH net-next 01/13] net: axienet: Fixed 64-bit compile, enable build on X86 and ARM Robert Hancock
@ 2019-05-31 18:15 ` Robert Hancock
  2019-05-31 21:13   ` Andrew Lunn
  2019-05-31 18:15 ` [PATCH net-next 03/13] net: axienet: Cleanup DMA device reset and halt process Robert Hancock
                   ` (10 subsequent siblings)
  12 siblings, 1 reply; 22+ messages in thread
From: Robert Hancock @ 2019-05-31 18:15 UTC (permalink / raw)
  To: netdev; +Cc: anirudh, John.Linn, Robert Hancock

-Allow specifying the MDIO clock divisor explicitly in the device tree,
rather than always detecting it from the CPU clock which only works on
the MicroBlaze platform.

-Centralize all MDIO handling in xilinx_axienet_mdio.c

-Ensure that MDIO clock divisor is always re-set after resetting the
device, since it will be cleared.

-Fixed ordering of MDIO teardown vs. netdev teardown

Signed-off-by: Robert Hancock <hancock@sedsystems.ca>
---
 .../devicetree/bindings/net/xilinx_axienet.txt     |   4 +
 drivers/net/ethernet/xilinx/xilinx_axienet.h       |   8 +-
 drivers/net/ethernet/xilinx/xilinx_axienet_main.c  |  36 ++---
 drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c  | 160 ++++++++++++---------
 4 files changed, 117 insertions(+), 91 deletions(-)

diff --git a/Documentation/devicetree/bindings/net/xilinx_axienet.txt b/Documentation/devicetree/bindings/net/xilinx_axienet.txt
index 38f9ec0..708722e 100644
--- a/Documentation/devicetree/bindings/net/xilinx_axienet.txt
+++ b/Documentation/devicetree/bindings/net/xilinx_axienet.txt
@@ -31,6 +31,10 @@ Optional properties:
 		  1 to enable partial TX checksum offload,
 		  2 to enable full TX checksum offload
 - xlnx,rxcsum	: Same values as xlnx,txcsum but for RX checksum offload
+- xlnx,mdio-clock-divisor: Explicitly set clock divisor from AXI bus clock
+                           to MDIO bus. If not specified, it is auto-detected
+                           from the CPU clock (but only on platforms where this
+                           is possible).
 
 Example:
 	axi_ethernet_eth: ethernet@40c00000 {
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h b/drivers/net/ethernet/xilinx/xilinx_axienet.h
index 0d89ebc..dfe0e4c 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet.h
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h
@@ -418,6 +418,9 @@ struct axienet_local {
 	/* Connection to PHY device */
 	struct device_node *phy_node;
 
+	/* MDIO clock divisor (0=detected from CPU clock) */
+	u32 mdio_clock_divisor;
+
 	/* MDIO bus data */
 	struct mii_bus *mii_bus;	/* MII bus reference */
 
@@ -510,8 +513,9 @@ static inline void axienet_iow(struct axienet_local *lp, off_t offset,
 }
 
 /* Function prototypes visible in xilinx_axienet_mdio.c for other files */
-int axienet_mdio_setup(struct axienet_local *lp, struct device_node *np);
-int axienet_mdio_wait_until_ready(struct axienet_local *lp);
+int axienet_mdio_enable(struct axienet_local *lp);
+void axienet_mdio_disable(struct axienet_local *lp);
+int axienet_mdio_setup(struct axienet_local *lp);
 void axienet_mdio_teardown(struct axienet_local *lp);
 
 #endif /* XILINX_AXI_ENET_H */
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index c0a8861..2e69755 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -921,27 +921,20 @@ static irqreturn_t axienet_rx_irq(int irq, void *_ndev)
  */
 static int axienet_open(struct net_device *ndev)
 {
-	int ret, mdio_mcreg;
+	int ret;
 	struct axienet_local *lp = netdev_priv(ndev);
 	struct phy_device *phydev = NULL;
 
 	dev_dbg(&ndev->dev, "axienet_open()\n");
 
-	mdio_mcreg = axienet_ior(lp, XAE_MDIO_MC_OFFSET);
-	ret = axienet_mdio_wait_until_ready(lp);
-	if (ret < 0)
-		return ret;
 	/* Disable the MDIO interface till Axi Ethernet Reset is completed.
 	 * When we do an Axi Ethernet reset, it resets the complete core
 	 * including the MDIO. If MDIO is not disabled when the reset
 	 * process is started, MDIO will be broken afterwards.
 	 */
-	axienet_iow(lp, XAE_MDIO_MC_OFFSET,
-		    (mdio_mcreg & (~XAE_MDIO_MC_MDIOEN_MASK)));
+	axienet_mdio_disable(lp);
 	axienet_device_reset(ndev);
-	/* Enable the MDIO */
-	axienet_iow(lp, XAE_MDIO_MC_OFFSET, mdio_mcreg);
-	ret = axienet_mdio_wait_until_ready(lp);
+	ret = axienet_mdio_enable(lp);
 	if (ret < 0)
 		return ret;
 
@@ -1323,28 +1316,21 @@ static void axienet_dma_err_handler(unsigned long data)
 {
 	u32 axienet_status;
 	u32 cr, i;
-	int mdio_mcreg;
 	struct axienet_local *lp = (struct axienet_local *) data;
 	struct net_device *ndev = lp->ndev;
 	struct axidma_bd *cur_p;
 
 	axienet_setoptions(ndev, lp->options &
 			   ~(XAE_OPTION_TXEN | XAE_OPTION_RXEN));
-	mdio_mcreg = axienet_ior(lp, XAE_MDIO_MC_OFFSET);
-	axienet_mdio_wait_until_ready(lp);
 	/* Disable the MDIO interface till Axi Ethernet Reset is completed.
 	 * When we do an Axi Ethernet reset, it resets the complete core
 	 * including the MDIO. So if MDIO is not disabled when the reset
 	 * process is started, MDIO will be broken afterwards.
 	 */
-	axienet_iow(lp, XAE_MDIO_MC_OFFSET, (mdio_mcreg &
-		    ~XAE_MDIO_MC_MDIOEN_MASK));
-
+	axienet_mdio_disable(lp);
 	__axienet_device_reset(lp, XAXIDMA_TX_CR_OFFSET);
 	__axienet_device_reset(lp, XAXIDMA_RX_CR_OFFSET);
-
-	axienet_iow(lp, XAE_MDIO_MC_OFFSET, mdio_mcreg);
-	axienet_mdio_wait_until_ready(lp);
+	axienet_mdio_enable(lp);
 
 	for (i = 0; i < TX_BD_NUM; i++) {
 		cur_p = &lp->tx_bd_v[i];
@@ -1619,9 +1605,15 @@ static int axienet_probe(struct platform_device *pdev)
 
 	lp->phy_node = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0);
 	if (lp->phy_node) {
-		ret = axienet_mdio_setup(lp, pdev->dev.of_node);
+		/* Defaults to 0 if not present */
+		of_property_read_u32(pdev->dev.of_node,
+				     "xlnx,mdio-clock-divisor",
+				     &lp->mdio_clock_divisor);
+
+		ret = axienet_mdio_setup(lp);
 		if (ret)
-			dev_warn(&pdev->dev, "error registering MDIO bus\n");
+			dev_warn(&pdev->dev,
+				 "error registering MDIO bus: %d\n", ret);
 	}
 
 	ret = register_netdev(lp->ndev);
@@ -1643,8 +1635,8 @@ static int axienet_remove(struct platform_device *pdev)
 	struct net_device *ndev = platform_get_drvdata(pdev);
 	struct axienet_local *lp = netdev_priv(ndev);
 
-	axienet_mdio_teardown(lp);
 	unregister_netdev(ndev);
+	axienet_mdio_teardown(lp);
 
 	of_node_put(lp->phy_node);
 	lp->phy_node = NULL;
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c b/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c
index 665ae1d..662e005 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c
@@ -5,6 +5,7 @@
  * Copyright (c) 2009 Secret Lab Technologies, Ltd.
  * Copyright (c) 2010 - 2011 Michal Simek <monstr@monstr.eu>
  * Copyright (c) 2010 - 2011 PetaLogix
+ * Copyright (c) 2019 SED Systems, a division of Calian Ltd.
  * Copyright (c) 2010 - 2012 Xilinx, Inc. All rights reserved.
  */
 
@@ -19,7 +20,7 @@
 #define DEFAULT_CLOCK_DIVISOR	XAE_MDIO_DIV_DFT
 
 /* Wait till MDIO interface is ready to accept a new transaction.*/
-int axienet_mdio_wait_until_ready(struct axienet_local *lp)
+static int axienet_mdio_wait_until_ready(struct axienet_local *lp)
 {
 	u32 val;
 
@@ -112,9 +113,97 @@ static int axienet_mdio_write(struct mii_bus *bus, int phy_id, int reg,
 }
 
 /**
+ * axienet_mdio_enable - MDIO hardware setup function
+ * @lp:		Pointer to axienet local data structure.
+ *
+ * Return:	0 on success, -ETIMEDOUT on a timeout.
+ *
+ * Sets up the MDIO interface by initializing the MDIO clock and enabling the
+ * MDIO interface in hardware.
+ **/
+int axienet_mdio_enable(struct axienet_local *lp)
+{
+	u32 clk_div = lp->mdio_clock_divisor, host_clock;
+
+	if (!clk_div) {
+		/* clk_div can be calculated by deriving it from the equation:
+		 * fMDIO = fHOST / ((1 + clk_div) * 2)
+		 *
+		 * Where fMDIO <= 2500000, so we get:
+		 * fHOST / ((1 + clk_div) * 2) <= 2500000
+		 *
+		 * Then we get:
+		 * 1 / ((1 + clk_div) * 2) <= (2500000 / fHOST)
+		 *
+		 * Then we get:
+		 * 1 / (1 + clk_div) <= ((2500000 * 2) / fHOST)
+		 *
+		 * Then we get:
+		 * 1 / (1 + clk_div) <= (5000000 / fHOST)
+		 *
+		 * So:
+		 * (1 + clk_div) >= (fHOST / 5000000)
+		 *
+		 * And finally:
+		 * clk_div >= (fHOST / 5000000) - 1
+		 *
+		 * fHOST can be read from the flattened device tree as property
+		 * "clock-frequency" from the CPU
+		 */
+		struct device_node *np1 = of_find_node_by_name(NULL, "cpu");
+
+		if (!np1) {
+			netdev_warn(lp->ndev, "Could not find CPU device node.\n");
+			netdev_warn(lp->ndev,
+				    "Setting MDIO clock divisor to default %d\n",
+				    DEFAULT_CLOCK_DIVISOR);
+			clk_div = DEFAULT_CLOCK_DIVISOR;
+			goto issue;
+		}
+		if (of_property_read_u32(np1, "clock-frequency", &host_clock)) {
+			netdev_warn(lp->ndev, "clock-frequency property not found.\n");
+			netdev_warn(lp->ndev,
+				    "Setting MDIO clock divisor to default %d\n",
+				    DEFAULT_CLOCK_DIVISOR);
+			clk_div = DEFAULT_CLOCK_DIVISOR;
+			of_node_put(np1);
+			goto issue;
+		}
+
+		clk_div = (host_clock / (MAX_MDIO_FREQ * 2)) - 1;
+		/* If there is any remainder from the division of
+		 * fHOST / (MAX_MDIO_FREQ * 2), then we need to add
+		 * 1 to the clock divisor or we will surely be above 2.5 MHz
+		 */
+		if (host_clock % (MAX_MDIO_FREQ * 2))
+			clk_div++;
+
+		netdev_dbg(lp->ndev,
+			   "Setting MDIO clock divisor to %u/%u Hz host clock.\n",
+			   clk_div, host_clock);
+
+		of_node_put(np1);
+	}
+issue:
+	axienet_iow(lp, XAE_MDIO_MC_OFFSET, clk_div | XAE_MDIO_MC_MDIOEN_MASK);
+
+	return axienet_mdio_wait_until_ready(lp);
+}
+
+/**
+ * axienet_mdio_disable - MDIO hardware disable function
+ * @lp:		Pointer to axienet local data structure.
+ *
+ * Disable the MDIO interface in hardware.
+ **/
+void axienet_mdio_disable(struct axienet_local *lp)
+{
+	axienet_iow(lp, XAE_MDIO_MC_OFFSET, 0);
+}
+
+/**
  * axienet_mdio_setup - MDIO setup function
  * @lp:		Pointer to axienet local data structure.
- * @np:		Pointer to device node
  *
  * Return:	0 on success, -ETIMEDOUT on a timeout, -ENOMEM when
  *		mdiobus_alloc (to allocate memory for mii bus structure) fails.
@@ -122,76 +211,13 @@ static int axienet_mdio_write(struct mii_bus *bus, int phy_id, int reg,
  * Sets up the MDIO interface by initializing the MDIO clock and enabling the
  * MDIO interface in hardware. Register the MDIO interface.
  **/
-int axienet_mdio_setup(struct axienet_local *lp, struct device_node *np)
+int axienet_mdio_setup(struct axienet_local *lp)
 {
 	int ret;
-	u32 clk_div, host_clock;
 	struct mii_bus *bus;
 	struct device_node *mdio_node;
-	struct device_node *np1;
-
-	/* clk_div can be calculated by deriving it from the equation:
-	 * fMDIO = fHOST / ((1 + clk_div) * 2)
-	 *
-	 * Where fMDIO <= 2500000, so we get:
-	 * fHOST / ((1 + clk_div) * 2) <= 2500000
-	 *
-	 * Then we get:
-	 * 1 / ((1 + clk_div) * 2) <= (2500000 / fHOST)
-	 *
-	 * Then we get:
-	 * 1 / (1 + clk_div) <= ((2500000 * 2) / fHOST)
-	 *
-	 * Then we get:
-	 * 1 / (1 + clk_div) <= (5000000 / fHOST)
-	 *
-	 * So:
-	 * (1 + clk_div) >= (fHOST / 5000000)
-	 *
-	 * And finally:
-	 * clk_div >= (fHOST / 5000000) - 1
-	 *
-	 * fHOST can be read from the flattened device tree as property
-	 * "clock-frequency" from the CPU
-	 */
-
-	np1 = of_find_node_by_name(NULL, "cpu");
-	if (!np1) {
-		netdev_warn(lp->ndev, "Could not find CPU device node.\n");
-		netdev_warn(lp->ndev,
-			    "Setting MDIO clock divisor to default %d\n",
-			    DEFAULT_CLOCK_DIVISOR);
-		clk_div = DEFAULT_CLOCK_DIVISOR;
-		goto issue;
-	}
-	if (of_property_read_u32(np1, "clock-frequency", &host_clock)) {
-		netdev_warn(lp->ndev, "clock-frequency property not found.\n");
-		netdev_warn(lp->ndev,
-			    "Setting MDIO clock divisor to default %d\n",
-			    DEFAULT_CLOCK_DIVISOR);
-		clk_div = DEFAULT_CLOCK_DIVISOR;
-		of_node_put(np1);
-		goto issue;
-	}
-
-	clk_div = (host_clock / (MAX_MDIO_FREQ * 2)) - 1;
-	/* If there is any remainder from the division of
-	 * fHOST / (MAX_MDIO_FREQ * 2), then we need to add
-	 * 1 to the clock divisor or we will surely be above 2.5 MHz
-	 */
-	if (host_clock % (MAX_MDIO_FREQ * 2))
-		clk_div++;
 
-	netdev_dbg(lp->ndev,
-		   "Setting MDIO clock divisor to %u/%u Hz host clock.\n",
-		   clk_div, host_clock);
-
-	of_node_put(np1);
-issue:
-	axienet_iow(lp, XAE_MDIO_MC_OFFSET,
-		    (((u32) clk_div) | XAE_MDIO_MC_MDIOEN_MASK));
-
-	ret = axienet_mdio_wait_until_ready(lp);
+	ret = axienet_mdio_enable(lp);
 	if (ret < 0)
 		return ret;
 
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH net-next 03/13] net: axienet: Cleanup DMA device reset and halt process
  2019-05-31 18:15 [PATCH net-next 00/13] Xilinx axienet driver updates Robert Hancock
  2019-05-31 18:15 ` [PATCH net-next 01/13] net: axienet: Fixed 64-bit compile, enable build on X86 and ARM Robert Hancock
  2019-05-31 18:15 ` [PATCH net-next 02/13] net: axienet: clean up MDIO handling Robert Hancock
@ 2019-05-31 18:15 ` Robert Hancock
  2019-05-31 18:15 ` [PATCH net-next 04/13] net: axienet: Make RX/TX ring sizes configurable Robert Hancock
                   ` (9 subsequent siblings)
  12 siblings, 0 replies; 22+ messages in thread
From: Robert Hancock @ 2019-05-31 18:15 UTC (permalink / raw)
  To: netdev; +Cc: anirudh, John.Linn, Robert Hancock

The Xilinx DMA blocks each have their own reset register, but they both
reset the entire DMA engine, so only one of them needs to be reset.

Also, when stopping the device, we need to not just command the DMA
blocks to stop, but wait for them to stop, and trigger a device reset
to ensure that they are completely stopped.

Signed-off-by: Robert Hancock <hancock@sedsystems.ca>
---
 drivers/net/ethernet/xilinx/xilinx_axienet.h      |  2 +
 drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 50 ++++++++++++++++-------
 2 files changed, 38 insertions(+), 14 deletions(-)

diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h b/drivers/net/ethernet/xilinx/xilinx_axienet.h
index dfe0e4c..4d39164 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet.h
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h
@@ -83,6 +83,8 @@
 #define XAXIDMA_CR_RUNSTOP_MASK	0x00000001 /* Start/stop DMA channel */
 #define XAXIDMA_CR_RESET_MASK	0x00000004 /* Reset DMA engine */
 
+#define XAXIDMA_SR_HALT_MASK	0x00000001 /* Indicates DMA channel halted */
+
 #define XAXIDMA_BD_NDESC_OFFSET		0x00 /* Next descriptor pointer */
 #define XAXIDMA_BD_BUFA_OFFSET		0x08 /* Buffer address */
 #define XAXIDMA_BD_CTRL_LEN_OFFSET	0x18 /* Control/buffer length */
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index 2e69755..3b683ea 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -441,17 +441,20 @@ static void axienet_setoptions(struct net_device *ndev, u32 options)
 	lp->options |= options;
 }
 
-static void __axienet_device_reset(struct axienet_local *lp, off_t offset)
+static void __axienet_device_reset(struct axienet_local *lp)
 {
 	u32 timeout;
 	/* Reset Axi DMA. This would reset Axi Ethernet core as well. The reset
 	 * process of Axi DMA takes a while to complete as all pending
 	 * commands/transfers will be flushed or completed during this
 	 * reset process.
+	 * Note that even though both TX and RX have their own reset register,
+	 * they both reset the entire DMA core, so only one needs to be used.
 	 */
-	axienet_dma_out32(lp, offset, XAXIDMA_CR_RESET_MASK);
+	axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET, XAXIDMA_CR_RESET_MASK);
 	timeout = DELAY_OF_ONE_MILLISEC;
-	while (axienet_dma_in32(lp, offset) & XAXIDMA_CR_RESET_MASK) {
+	while (axienet_dma_in32(lp, XAXIDMA_TX_CR_OFFSET) &
+				XAXIDMA_CR_RESET_MASK) {
 		udelay(1);
 		if (--timeout == 0) {
 			netdev_err(lp->ndev, "%s: DMA reset timeout!\n",
@@ -477,8 +480,7 @@ static void axienet_device_reset(struct net_device *ndev)
 	u32 axienet_status;
 	struct axienet_local *lp = netdev_priv(ndev);
 
-	__axienet_device_reset(lp, XAXIDMA_TX_CR_OFFSET);
-	__axienet_device_reset(lp, XAXIDMA_RX_CR_OFFSET);
+	__axienet_device_reset(lp);
 
 	lp->max_frm_size = XAE_MAX_VLAN_FRAME_SIZE;
 	lp->options |= XAE_OPTION_VLAN;
@@ -985,20 +987,41 @@ static int axienet_open(struct net_device *ndev)
  */
 static int axienet_stop(struct net_device *ndev)
 {
-	u32 cr;
+	u32 cr, sr;
+	int count;
 	struct axienet_local *lp = netdev_priv(ndev);
 
 	dev_dbg(&ndev->dev, "axienet_close()\n");
 
-	cr = axienet_dma_in32(lp, XAXIDMA_RX_CR_OFFSET);
-	axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET,
-			  cr & (~XAXIDMA_CR_RUNSTOP_MASK));
-	cr = axienet_dma_in32(lp, XAXIDMA_TX_CR_OFFSET);
-	axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET,
-			  cr & (~XAXIDMA_CR_RUNSTOP_MASK));
 	axienet_setoptions(ndev, lp->options &
 			   ~(XAE_OPTION_TXEN | XAE_OPTION_RXEN));
 
+	cr = axienet_dma_in32(lp, XAXIDMA_RX_CR_OFFSET);
+	cr &= ~(XAXIDMA_CR_RUNSTOP_MASK | XAXIDMA_IRQ_ALL_MASK);
+	axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET, cr);
+
+	cr = axienet_dma_in32(lp, XAXIDMA_TX_CR_OFFSET);
+	cr &= ~(XAXIDMA_CR_RUNSTOP_MASK | XAXIDMA_IRQ_ALL_MASK);
+	axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET, cr);
+
+	axienet_iow(lp, XAE_IE_OFFSET, 0);
+
+	/* Give DMAs a chance to halt gracefully */
+	sr = axienet_dma_in32(lp, XAXIDMA_RX_SR_OFFSET);
+	for (count = 0; !(sr & XAXIDMA_SR_HALT_MASK) && count < 5; ++count) {
+		msleep(20);
+		sr = axienet_dma_in32(lp, XAXIDMA_RX_SR_OFFSET);
+	}
+
+	sr = axienet_dma_in32(lp, XAXIDMA_TX_SR_OFFSET);
+	for (count = 0; !(sr & XAXIDMA_SR_HALT_MASK) && count < 5; ++count) {
+		msleep(20);
+		sr = axienet_dma_in32(lp, XAXIDMA_TX_SR_OFFSET);
+	}
+
+	/* Do a reset to ensure DMA is really stopped */
+	__axienet_device_reset(lp);
+
 	tasklet_kill(&lp->dma_err_tasklet);
 
 	free_irq(lp->tx_irq, ndev);
@@ -1328,8 +1351,7 @@ static void axienet_dma_err_handler(unsigned long data)
 	 * process is started, MDIO will be broken afterwards.
 	 */
 	axienet_mdio_disable(lp);
-	__axienet_device_reset(lp, XAXIDMA_TX_CR_OFFSET);
-	__axienet_device_reset(lp, XAXIDMA_RX_CR_OFFSET);
+	__axienet_device_reset(lp);
 	axienet_mdio_enable(lp);
 
 	for (i = 0; i < TX_BD_NUM; i++) {
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH net-next 04/13] net: axienet: Make RX/TX ring sizes configurable
  2019-05-31 18:15 [PATCH net-next 00/13] Xilinx axienet driver updates Robert Hancock
                   ` (2 preceding siblings ...)
  2019-05-31 18:15 ` [PATCH net-next 03/13] net: axienet: Cleanup DMA device reset and halt process Robert Hancock
@ 2019-05-31 18:15 ` Robert Hancock
  2019-05-31 18:15 ` [PATCH net-next 05/13] net: axienet: Add DMA registers to ethtool register dump Robert Hancock
                   ` (8 subsequent siblings)
  12 siblings, 0 replies; 22+ messages in thread
From: Robert Hancock @ 2019-05-31 18:15 UTC (permalink / raw)
  To: netdev; +Cc: anirudh, John.Linn, Robert Hancock

Add support for setting the RX and TX ring sizes for this driver using
ethtool. Also increase the default RX ring size as the previous default
was far too low for good performance in some configurations.

Signed-off-by: Robert Hancock <hancock@sedsystems.ca>
---
 drivers/net/ethernet/xilinx/xilinx_axienet.h      |  2 +
 drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 90 ++++++++++++++++-------
 2 files changed, 67 insertions(+), 25 deletions(-)

diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h b/drivers/net/ethernet/xilinx/xilinx_axienet.h
index 4d39164..4cd92fe 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet.h
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h
@@ -444,8 +444,10 @@ struct axienet_local {
 	/* Buffer descriptors */
 	struct axidma_bd *tx_bd_v;
 	dma_addr_t tx_bd_p;
+	u32 tx_bd_num;
 	struct axidma_bd *rx_bd_v;
 	dma_addr_t rx_bd_p;
+	u32 rx_bd_num;
 	u32 tx_bd_ci;
 	u32 tx_bd_tail;
 	u32 rx_bd_ci;
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index 3b683ea..decd16e 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -38,9 +38,11 @@
 
 #include "xilinx_axienet.h"
 
-/* Descriptors defines for Tx and Rx DMA - 2^n for the best performance */
-#define TX_BD_NUM		64
-#define RX_BD_NUM		128
+/* Descriptors defines for Tx and Rx DMA */
+#define TX_BD_NUM_DEFAULT		64
+#define RX_BD_NUM_DEFAULT		1024
+#define TX_BD_NUM_MAX			4096
+#define RX_BD_NUM_MAX			4096
 
 /* Must be shorter than length of ethtool_drvinfo.driver field to fit */
 #define DRIVER_NAME		"xaxienet"
@@ -164,7 +166,7 @@ static void axienet_dma_bd_release(struct net_device *ndev)
 	int i;
 	struct axienet_local *lp = netdev_priv(ndev);
 
-	for (i = 0; i < RX_BD_NUM; i++) {
+	for (i = 0; i < lp->rx_bd_num; i++) {
 		dma_unmap_single(ndev->dev.parent, lp->rx_bd_v[i].phys,
 				 lp->max_frm_size, DMA_FROM_DEVICE);
 		dev_kfree_skb(lp->rx_bd_v[i].skb);
@@ -172,13 +174,13 @@ static void axienet_dma_bd_release(struct net_device *ndev)
 
 	if (lp->rx_bd_v) {
 		dma_free_coherent(ndev->dev.parent,
-				  sizeof(*lp->rx_bd_v) * RX_BD_NUM,
+				  sizeof(*lp->rx_bd_v) * lp->rx_bd_num,
 				  lp->rx_bd_v,
 				  lp->rx_bd_p);
 	}
 	if (lp->tx_bd_v) {
 		dma_free_coherent(ndev->dev.parent,
-				  sizeof(*lp->tx_bd_v) * TX_BD_NUM,
+				  sizeof(*lp->tx_bd_v) * lp->tx_bd_num,
 				  lp->tx_bd_v,
 				  lp->tx_bd_p);
 	}
@@ -208,27 +210,27 @@ static int axienet_dma_bd_init(struct net_device *ndev)
 
 	/* Allocate the Tx and Rx buffer descriptors. */
 	lp->tx_bd_v = dma_alloc_coherent(ndev->dev.parent,
-					 sizeof(*lp->tx_bd_v) * TX_BD_NUM,
+					 sizeof(*lp->tx_bd_v) * lp->tx_bd_num,
 					 &lp->tx_bd_p, GFP_KERNEL);
 	if (!lp->tx_bd_v)
 		goto out;
 
 	lp->rx_bd_v = dma_alloc_coherent(ndev->dev.parent,
-					 sizeof(*lp->rx_bd_v) * RX_BD_NUM,
+					 sizeof(*lp->rx_bd_v) * lp->rx_bd_num,
 					 &lp->rx_bd_p, GFP_KERNEL);
 	if (!lp->rx_bd_v)
 		goto out;
 
-	for (i = 0; i < TX_BD_NUM; i++) {
+	for (i = 0; i < lp->tx_bd_num; i++) {
 		lp->tx_bd_v[i].next = lp->tx_bd_p +
 				      sizeof(*lp->tx_bd_v) *
-				      ((i + 1) % TX_BD_NUM);
+				      ((i + 1) % lp->tx_bd_num);
 	}
 
-	for (i = 0; i < RX_BD_NUM; i++) {
+	for (i = 0; i < lp->rx_bd_num; i++) {
 		lp->rx_bd_v[i].next = lp->rx_bd_p +
 				      sizeof(*lp->rx_bd_v) *
-				      ((i + 1) % RX_BD_NUM);
+				      ((i + 1) % lp->rx_bd_num);
 
 		skb = netdev_alloc_skb_ip_align(ndev, lp->max_frm_size);
 		if (!skb)
@@ -276,7 +278,7 @@ static int axienet_dma_bd_init(struct net_device *ndev)
 	axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET,
 			  cr | XAXIDMA_CR_RUNSTOP_MASK);
 	axienet_dma_out32(lp, XAXIDMA_RX_TDESC_OFFSET, lp->rx_bd_p +
-			  (sizeof(*lp->rx_bd_v) * (RX_BD_NUM - 1)));
+			  (sizeof(*lp->rx_bd_v) * (lp->rx_bd_num - 1)));
 
 	/* Write to the RS (Run-stop) bit in the Tx channel control register.
 	 * Tx channel is now ready to run. But only after we write to the
@@ -617,8 +619,8 @@ static void axienet_start_xmit_done(struct net_device *ndev)
 		size += status & XAXIDMA_BD_STS_ACTUAL_LEN_MASK;
 		packets++;
 
-		++lp->tx_bd_ci;
-		lp->tx_bd_ci %= TX_BD_NUM;
+		if (++lp->tx_bd_ci >= lp->tx_bd_num)
+			lp->tx_bd_ci = 0;
 		cur_p = &lp->tx_bd_v[lp->tx_bd_ci];
 		status = cur_p->status;
 	}
@@ -645,7 +647,7 @@ static inline int axienet_check_tx_bd_space(struct axienet_local *lp,
 					    int num_frag)
 {
 	struct axidma_bd *cur_p;
-	cur_p = &lp->tx_bd_v[(lp->tx_bd_tail + num_frag) % TX_BD_NUM];
+	cur_p = &lp->tx_bd_v[(lp->tx_bd_tail + num_frag) % lp->tx_bd_num];
 	if (cur_p->status & XAXIDMA_BD_STS_ALL_MASK)
 		return NETDEV_TX_BUSY;
 	return 0;
@@ -705,8 +707,8 @@ static inline int axienet_check_tx_bd_space(struct axienet_local *lp,
 				     skb_headlen(skb), DMA_TO_DEVICE);
 
 	for (ii = 0; ii < num_frag; ii++) {
-		++lp->tx_bd_tail;
-		lp->tx_bd_tail %= TX_BD_NUM;
+		if (++lp->tx_bd_tail >= lp->tx_bd_num)
+			lp->tx_bd_tail = 0;
 		cur_p = &lp->tx_bd_v[lp->tx_bd_tail];
 		frag = &skb_shinfo(skb)->frags[ii];
 		cur_p->phys = dma_map_single(ndev->dev.parent,
@@ -722,8 +724,8 @@ static inline int axienet_check_tx_bd_space(struct axienet_local *lp,
 	tail_p = lp->tx_bd_p + sizeof(*lp->tx_bd_v) * lp->tx_bd_tail;
 	/* Start the transfer */
 	axienet_dma_out32(lp, XAXIDMA_TX_TDESC_OFFSET, tail_p);
-	++lp->tx_bd_tail;
-	lp->tx_bd_tail %= TX_BD_NUM;
+	if (++lp->tx_bd_tail >= lp->tx_bd_num)
+		lp->tx_bd_tail = 0;
 
 	return NETDEV_TX_OK;
 }
@@ -797,8 +799,8 @@ static void axienet_recv(struct net_device *ndev)
 		cur_p->status = 0;
 		cur_p->skb = new_skb;
 
-		++lp->rx_bd_ci;
-		lp->rx_bd_ci %= RX_BD_NUM;
+		if (++lp->rx_bd_ci >= lp->rx_bd_num)
+			lp->rx_bd_ci = 0;
 		cur_p = &lp->rx_bd_v[lp->rx_bd_ci];
 	}
 
@@ -1179,6 +1181,40 @@ static void axienet_ethtools_get_regs(struct net_device *ndev,
 	data[31] = axienet_ior(lp, XAE_AF1_OFFSET);
 }
 
+static void axienet_ethtools_get_ringparam(struct net_device *ndev,
+					   struct ethtool_ringparam *ering)
+{
+	struct axienet_local *lp = netdev_priv(ndev);
+
+	ering->rx_max_pending = RX_BD_NUM_MAX;
+	ering->rx_mini_max_pending = 0;
+	ering->rx_jumbo_max_pending = 0;
+	ering->tx_max_pending = TX_BD_NUM_MAX;
+	ering->rx_pending = lp->rx_bd_num;
+	ering->rx_mini_pending = 0;
+	ering->rx_jumbo_pending = 0;
+	ering->tx_pending = lp->tx_bd_num;
+}
+
+static int axienet_ethtools_set_ringparam(struct net_device *ndev,
+					  struct ethtool_ringparam *ering)
+{
+	struct axienet_local *lp = netdev_priv(ndev);
+
+	if (ering->rx_pending > RX_BD_NUM_MAX ||
+	    ering->rx_mini_pending ||
+	    ering->rx_jumbo_pending ||
+	    ering->rx_pending > TX_BD_NUM_MAX)
+		return -EINVAL;
+
+	if (netif_running(ndev))
+		return -EBUSY;
+
+	lp->rx_bd_num = ering->rx_pending;
+	lp->tx_bd_num = ering->tx_pending;
+	return 0;
+}
+
 /**
  * axienet_ethtools_get_pauseparam - Get the pause parameter setting for
  *				     Tx and Rx paths.
@@ -1320,6 +1356,8 @@ static int axienet_ethtools_set_coalesce(struct net_device *ndev,
 	.get_regs_len   = axienet_ethtools_get_regs_len,
 	.get_regs       = axienet_ethtools_get_regs,
 	.get_link       = ethtool_op_get_link,
+	.get_ringparam	= axienet_ethtools_get_ringparam,
+	.set_ringparam	= axienet_ethtools_set_ringparam,
 	.get_pauseparam = axienet_ethtools_get_pauseparam,
 	.set_pauseparam = axienet_ethtools_set_pauseparam,
 	.get_coalesce   = axienet_ethtools_get_coalesce,
@@ -1354,7 +1392,7 @@ static void axienet_dma_err_handler(unsigned long data)
 	__axienet_device_reset(lp);
 	axienet_mdio_enable(lp);
 
-	for (i = 0; i < TX_BD_NUM; i++) {
+	for (i = 0; i < lp->tx_bd_num; i++) {
 		cur_p = &lp->tx_bd_v[i];
 		if (cur_p->phys)
 			dma_unmap_single(ndev->dev.parent, cur_p->phys,
@@ -1374,7 +1412,7 @@ static void axienet_dma_err_handler(unsigned long data)
 		cur_p->skb = NULL;
 	}
 
-	for (i = 0; i < RX_BD_NUM; i++) {
+	for (i = 0; i < lp->rx_bd_num; i++) {
 		cur_p = &lp->rx_bd_v[i];
 		cur_p->status = 0;
 		cur_p->app0 = 0;
@@ -1422,7 +1460,7 @@ static void axienet_dma_err_handler(unsigned long data)
 	axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET,
 			  cr | XAXIDMA_CR_RUNSTOP_MASK);
 	axienet_dma_out32(lp, XAXIDMA_RX_TDESC_OFFSET, lp->rx_bd_p +
-			  (sizeof(*lp->rx_bd_v) * (RX_BD_NUM - 1)));
+			  (sizeof(*lp->rx_bd_v) * (lp->rx_bd_num - 1)));
 
 	/* Write to the RS (Run-stop) bit in the Tx channel control register.
 	 * Tx channel is now ready to run. But only after we write to the
@@ -1494,6 +1532,8 @@ static int axienet_probe(struct platform_device *pdev)
 	lp->ndev = ndev;
 	lp->dev = &pdev->dev;
 	lp->options = XAE_OPTION_DEFAULTS;
+	lp->rx_bd_num = RX_BD_NUM_DEFAULT;
+	lp->tx_bd_num = TX_BD_NUM_DEFAULT;
 	/* Map device registers */
 	ethres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	lp->regs_start = ethres->start;
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH net-next 05/13] net: axienet: Add DMA registers to ethtool register dump
  2019-05-31 18:15 [PATCH net-next 00/13] Xilinx axienet driver updates Robert Hancock
                   ` (3 preceding siblings ...)
  2019-05-31 18:15 ` [PATCH net-next 04/13] net: axienet: Make RX/TX ring sizes configurable Robert Hancock
@ 2019-05-31 18:15 ` Robert Hancock
  2019-05-31 18:15 ` [PATCH net-next 06/13] net: axienet: Support shared interrupts Robert Hancock
                   ` (7 subsequent siblings)
  12 siblings, 0 replies; 22+ messages in thread
From: Robert Hancock @ 2019-05-31 18:15 UTC (permalink / raw)
  To: netdev; +Cc: anirudh, John.Linn, Robert Hancock

These registers are important for troubleshooting the state of the DMA
cores.

Signed-off-by: Robert Hancock <hancock@sedsystems.ca>
---
 drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index decd16e..fad5750 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -49,7 +49,7 @@
 #define DRIVER_DESCRIPTION	"Xilinx Axi Ethernet driver"
 #define DRIVER_VERSION		"1.00a"
 
-#define AXIENET_REGS_N		32
+#define AXIENET_REGS_N		40
 
 /* Match table for of_platform binding */
 static const struct of_device_id axienet_of_match[] = {
@@ -1179,6 +1179,14 @@ static void axienet_ethtools_get_regs(struct net_device *ndev,
 	data[29] = axienet_ior(lp, XAE_FMI_OFFSET);
 	data[30] = axienet_ior(lp, XAE_AF0_OFFSET);
 	data[31] = axienet_ior(lp, XAE_AF1_OFFSET);
+	data[32] = axienet_dma_in32(lp, XAXIDMA_TX_CR_OFFSET);
+	data[33] = axienet_dma_in32(lp, XAXIDMA_TX_SR_OFFSET);
+	data[34] = axienet_dma_in32(lp, XAXIDMA_TX_CDESC_OFFSET);
+	data[35] = axienet_dma_in32(lp, XAXIDMA_TX_TDESC_OFFSET);
+	data[36] = axienet_dma_in32(lp, XAXIDMA_RX_CR_OFFSET);
+	data[37] = axienet_dma_in32(lp, XAXIDMA_RX_SR_OFFSET);
+	data[38] = axienet_dma_in32(lp, XAXIDMA_RX_CDESC_OFFSET);
+	data[39] = axienet_dma_in32(lp, XAXIDMA_RX_TDESC_OFFSET);
 }
 
 static void axienet_ethtools_get_ringparam(struct net_device *ndev,
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH net-next 06/13] net: axienet: Support shared interrupts
  2019-05-31 18:15 [PATCH net-next 00/13] Xilinx axienet driver updates Robert Hancock
                   ` (4 preceding siblings ...)
  2019-05-31 18:15 ` [PATCH net-next 05/13] net: axienet: Add DMA registers to ethtool register dump Robert Hancock
@ 2019-05-31 18:15 ` Robert Hancock
  2019-05-31 18:15 ` [PATCH net-next 07/13] net: axienet: Add optional support for Ethernet core interrupt Robert Hancock
                   ` (6 subsequent siblings)
  12 siblings, 0 replies; 22+ messages in thread
From: Robert Hancock @ 2019-05-31 18:15 UTC (permalink / raw)
  To: netdev; +Cc: anirudh, John.Linn, Robert Hancock

Specify IRQF_SHARED to support shared interrupts. If the interrupt
handler is called and the device is not indicating an interrupt,
just return IRQ_NONE rather than spewing error messages.

Signed-off-by: Robert Hancock <hancock@sedsystems.ca>
---
 drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index fad5750..6e5613b 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -816,7 +816,7 @@ static void axienet_recv(struct net_device *ndev)
  * @irq:	irq number
  * @_ndev:	net_device pointer
  *
- * Return: IRQ_HANDLED for all cases.
+ * Return: IRQ_HANDLED if device generated a TX interrupt, IRQ_NONE otherwise.
  *
  * This is the Axi DMA Tx done Isr. It invokes "axienet_start_xmit_done"
  * to complete the BD processing.
@@ -835,7 +835,7 @@ static irqreturn_t axienet_tx_irq(int irq, void *_ndev)
 		goto out;
 	}
 	if (!(status & XAXIDMA_IRQ_ALL_MASK))
-		dev_err(&ndev->dev, "No interrupts asserted in Tx path\n");
+		return IRQ_NONE;
 	if (status & XAXIDMA_IRQ_ERROR_MASK) {
 		dev_err(&ndev->dev, "DMA Tx error 0x%x\n", status);
 		dev_err(&ndev->dev, "Current BD is at: 0x%x\n",
@@ -865,7 +865,7 @@ static irqreturn_t axienet_tx_irq(int irq, void *_ndev)
  * @irq:	irq number
  * @_ndev:	net_device pointer
  *
- * Return: IRQ_HANDLED for all cases.
+ * Return: IRQ_HANDLED if device generated a RX interrupt, IRQ_NONE otherwise.
  *
  * This is the Axi DMA Rx Isr. It invokes "axienet_recv" to complete the BD
  * processing.
@@ -884,7 +884,7 @@ static irqreturn_t axienet_rx_irq(int irq, void *_ndev)
 		goto out;
 	}
 	if (!(status & XAXIDMA_IRQ_ALL_MASK))
-		dev_err(&ndev->dev, "No interrupts asserted in Rx path\n");
+		return IRQ_NONE;
 	if (status & XAXIDMA_IRQ_ERROR_MASK) {
 		dev_err(&ndev->dev, "DMA Rx error 0x%x\n", status);
 		dev_err(&ndev->dev, "Current BD is at: 0x%x\n",
@@ -957,11 +957,13 @@ static int axienet_open(struct net_device *ndev)
 		     (unsigned long) lp);
 
 	/* Enable interrupts for Axi DMA Tx */
-	ret = request_irq(lp->tx_irq, axienet_tx_irq, 0, ndev->name, ndev);
+	ret = request_irq(lp->tx_irq, axienet_tx_irq, IRQF_SHARED,
+			  ndev->name, ndev);
 	if (ret)
 		goto err_tx_irq;
 	/* Enable interrupts for Axi DMA Rx */
-	ret = request_irq(lp->rx_irq, axienet_rx_irq, 0, ndev->name, ndev);
+	ret = request_irq(lp->rx_irq, axienet_rx_irq, IRQF_SHARED,
+			  ndev->name, ndev);
 	if (ret)
 		goto err_rx_irq;
 
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH net-next 07/13] net: axienet: Add optional support for Ethernet core interrupt
  2019-05-31 18:15 [PATCH net-next 00/13] Xilinx axienet driver updates Robert Hancock
                   ` (5 preceding siblings ...)
  2019-05-31 18:15 ` [PATCH net-next 06/13] net: axienet: Support shared interrupts Robert Hancock
@ 2019-05-31 18:15 ` Robert Hancock
  2019-05-31 18:15 ` [PATCH net-next 08/13] net: axienet: Fix race condition causing TX hang Robert Hancock
                   ` (5 subsequent siblings)
  12 siblings, 0 replies; 22+ messages in thread
From: Robert Hancock @ 2019-05-31 18:15 UTC (permalink / raw)
  To: netdev; +Cc: anirudh, John.Linn, Robert Hancock

Previously this driver only handled interrupts from the DMA RX and TX
blocks, not from the Ethernet core itself. Add optional support for
the Ethernet core interrupt, which is used to detect rx_missed and
framing errors signalled by the hardware. In order to use this
interrupt, a third interrupt needs to be specified in the device tree.

Signed-off-by: Robert Hancock <hancock@sedsystems.ca>
---
 .../devicetree/bindings/net/xilinx_axienet.txt     |  3 +-
 drivers/net/ethernet/xilinx/xilinx_axienet.h       |  1 +
 drivers/net/ethernet/xilinx/xilinx_axienet_main.c  | 49 ++++++++++++++++++++++
 3 files changed, 52 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/net/xilinx_axienet.txt b/Documentation/devicetree/bindings/net/xilinx_axienet.txt
index 708722e..3f7b65e 100644
--- a/Documentation/devicetree/bindings/net/xilinx_axienet.txt
+++ b/Documentation/devicetree/bindings/net/xilinx_axienet.txt
@@ -18,7 +18,8 @@ Required properties:
 - compatible	: Must be one of "xlnx,axi-ethernet-1.00.a",
 		  "xlnx,axi-ethernet-1.01.a", "xlnx,axi-ethernet-2.01.a"
 - reg		: Address and length of the IO space.
-- interrupts	: Should be a list of two interrupt, TX and RX.
+- interrupts	: Should be a list of 2 or 3 interrupts: TX DMA, RX DMA,
+		  and optionally Ethernet core.
 - phy-handle	: Should point to the external phy device.
 		  See ethernet.txt file in the same directory.
 - xlnx,rxmem	: Set to allocated memory buffer for Rx/Tx in the hardware
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h b/drivers/net/ethernet/xilinx/xilinx_axienet.h
index 4cd92fe..e14a6e7 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet.h
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h
@@ -435,6 +435,7 @@ struct axienet_local {
 
 	int tx_irq;
 	int rx_irq;
+	int eth_irq;
 	phy_interface_t phy_mode;
 
 	u32 options;			/* Current options word */
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index 6e5613b..f2a8c5c 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -509,6 +509,8 @@ static void axienet_device_reset(struct net_device *ndev)
 	axienet_status = axienet_ior(lp, XAE_IP_OFFSET);
 	if (axienet_status & XAE_INT_RXRJECT_MASK)
 		axienet_iow(lp, XAE_IS_OFFSET, XAE_INT_RXRJECT_MASK);
+	axienet_iow(lp, XAE_IE_OFFSET, lp->eth_irq > 0 ?
+		    XAE_INT_RECV_ERROR_MASK : 0);
 
 	axienet_iow(lp, XAE_FCC_OFFSET, XAE_FCC_FCRX_MASK);
 
@@ -909,6 +911,35 @@ static irqreturn_t axienet_rx_irq(int irq, void *_ndev)
 	return IRQ_HANDLED;
 }
 
+/**
+ * axienet_eth_irq - Ethernet core Isr.
+ * @irq:	irq number
+ * @_ndev:	net_device pointer
+ *
+ * Return: IRQ_HANDLED if device generated a core interrupt, IRQ_NONE otherwise.
+ *
+ * Handle miscellaneous conditions indicated by Ethernet core IRQ.
+ */
+static irqreturn_t axienet_eth_irq(int irq, void *_ndev)
+{
+	unsigned int pending;
+	struct net_device *ndev = _ndev;
+	struct axienet_local *lp = netdev_priv(ndev);
+
+	pending = axienet_ior(lp, XAE_IP_OFFSET);
+	if (!pending)
+		return IRQ_NONE;
+
+	if (pending & XAE_INT_RXFIFOOVR_MASK)
+		ndev->stats.rx_missed_errors++;
+
+	if (pending & XAE_INT_RXRJECT_MASK)
+		ndev->stats.rx_frame_errors++;
+
+	axienet_iow(lp, XAE_IS_OFFSET, pending);
+	return IRQ_HANDLED;
+}
+
 static void axienet_dma_err_handler(unsigned long data);
 
 /**
@@ -966,9 +997,18 @@ static int axienet_open(struct net_device *ndev)
 			  ndev->name, ndev);
 	if (ret)
 		goto err_rx_irq;
+	/* Enable interrupts for Axi Ethernet core (if defined) */
+	if (lp->eth_irq > 0) {
+		ret = request_irq(lp->eth_irq, axienet_eth_irq, IRQF_SHARED,
+				  ndev->name, ndev);
+		if (ret)
+			goto err_eth_irq;
+	}
 
 	return 0;
 
+err_eth_irq:
+	free_irq(lp->rx_irq, ndev);
 err_rx_irq:
 	free_irq(lp->tx_irq, ndev);
 err_tx_irq:
@@ -1028,6 +1068,8 @@ static int axienet_stop(struct net_device *ndev)
 
 	tasklet_kill(&lp->dma_err_tasklet);
 
+	if (lp->eth_irq > 0)
+		free_irq(lp->eth_irq, ndev);
 	free_irq(lp->tx_irq, ndev);
 	free_irq(lp->rx_irq, ndev);
 
@@ -1488,6 +1530,8 @@ static void axienet_dma_err_handler(unsigned long data)
 	axienet_status = axienet_ior(lp, XAE_IP_OFFSET);
 	if (axienet_status & XAE_INT_RXRJECT_MASK)
 		axienet_iow(lp, XAE_IS_OFFSET, XAE_INT_RXRJECT_MASK);
+	axienet_iow(lp, XAE_IE_OFFSET, lp->eth_irq > 0 ?
+		    XAE_INT_RECV_ERROR_MASK : 0);
 	axienet_iow(lp, XAE_FCC_OFFSET, XAE_FCC_FCRX_MASK);
 
 	/* Sync default options with HW but leave receiver and
@@ -1657,6 +1701,7 @@ static int axienet_probe(struct platform_device *pdev)
 	}
 	lp->rx_irq = irq_of_parse_and_map(np, 1);
 	lp->tx_irq = irq_of_parse_and_map(np, 0);
+	lp->eth_irq = irq_of_parse_and_map(np, 2);
 	of_node_put(np);
 	if ((lp->rx_irq <= 0) || (lp->tx_irq <= 0)) {
 		dev_err(&pdev->dev, "could not determine irqs\n");
@@ -1664,6 +1709,10 @@ static int axienet_probe(struct platform_device *pdev)
 		goto free_netdev;
 	}
 
+	/* Check for Ethernet core IRQ (optional) */
+	if (lp->eth_irq <= 0)
+		dev_info(&pdev->dev, "Ethernet core IRQ not defined\n");
+
 	/* Retrieve the MAC address */
 	mac_addr = of_get_mac_address(pdev->dev.of_node);
 	if (IS_ERR(mac_addr)) {
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH net-next 08/13] net: axienet: Fix race condition causing TX hang
  2019-05-31 18:15 [PATCH net-next 00/13] Xilinx axienet driver updates Robert Hancock
                   ` (6 preceding siblings ...)
  2019-05-31 18:15 ` [PATCH net-next 07/13] net: axienet: Add optional support for Ethernet core interrupt Robert Hancock
@ 2019-05-31 18:15 ` Robert Hancock
  2019-05-31 18:15 ` [PATCH net-next 09/13] net: axienet: Make missing MAC address non-fatal Robert Hancock
                   ` (4 subsequent siblings)
  12 siblings, 0 replies; 22+ messages in thread
From: Robert Hancock @ 2019-05-31 18:15 UTC (permalink / raw)
  To: netdev; +Cc: anirudh, John.Linn, Robert Hancock

It is possible that the interrupt handler fires and frees up space in
the TX ring in between checking for sufficient TX ring space and
stopping the TX queue in axienet_start_xmit. If this happens, the
queue wake from the interrupt handler will occur before the queue is
stopped, causing a lost wakeup and the adapter's transmit hanging.

To avoid this, after stopping the queue, check again whether there is
sufficient space in the TX ring. If so, wake up the queue again.

Signed-off-by: Robert Hancock <hancock@sedsystems.ca>
---
 drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 20 +++++++++++++++++---
 1 file changed, 17 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index f2a8c5c..9949e67 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -629,6 +629,10 @@ static void axienet_start_xmit_done(struct net_device *ndev)
 
 	ndev->stats.tx_packets += packets;
 	ndev->stats.tx_bytes += size;
+
+	/* Matches barrier in axienet_start_xmit */
+	smp_mb();
+
 	netif_wake_queue(ndev);
 }
 
@@ -684,9 +688,19 @@ static inline int axienet_check_tx_bd_space(struct axienet_local *lp,
 	cur_p = &lp->tx_bd_v[lp->tx_bd_tail];
 
 	if (axienet_check_tx_bd_space(lp, num_frag)) {
-		if (!netif_queue_stopped(ndev))
-			netif_stop_queue(ndev);
-		return NETDEV_TX_BUSY;
+		if (netif_queue_stopped(ndev))
+			return NETDEV_TX_BUSY;
+
+		netif_stop_queue(ndev);
+
+		/* Matches barrier in axienet_start_xmit_done */
+		smp_mb();
+
+		/* Space might have just been freed - check again */
+		if (axienet_check_tx_bd_space(lp, num_frag))
+			return NETDEV_TX_BUSY;
+
+		netif_wake_queue(ndev);
 	}
 
 	if (skb->ip_summed == CHECKSUM_PARTIAL) {
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH net-next 09/13] net: axienet: Make missing MAC address non-fatal
  2019-05-31 18:15 [PATCH net-next 00/13] Xilinx axienet driver updates Robert Hancock
                   ` (7 preceding siblings ...)
  2019-05-31 18:15 ` [PATCH net-next 08/13] net: axienet: Fix race condition causing TX hang Robert Hancock
@ 2019-05-31 18:15 ` Robert Hancock
  2019-05-31 21:16   ` Andrew Lunn
  2019-06-03 13:22   ` David Laight
  2019-05-31 18:15 ` [PATCH net-next 10/13] net: axienet: stop interface during shutdown Robert Hancock
                   ` (3 subsequent siblings)
  12 siblings, 2 replies; 22+ messages in thread
From: Robert Hancock @ 2019-05-31 18:15 UTC (permalink / raw)
  To: netdev; +Cc: anirudh, John.Linn, Robert Hancock

Failing initialization on a missing MAC address property is excessive.
We can just fall back to using a random MAC instead, which at least
leaves the interface in a functioning state.

Signed-off-by: Robert Hancock <hancock@sedsystems.ca>
---
 drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index 9949e67..947fa5d 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -308,7 +308,7 @@ static void axienet_set_mac_address(struct net_device *ndev,
 {
 	struct axienet_local *lp = netdev_priv(ndev);
 
-	if (address)
+	if (!IS_ERR(address))
 		memcpy(ndev->dev_addr, address, ETH_ALEN);
 	if (!is_valid_ether_addr(ndev->dev_addr))
 		eth_hw_addr_random(ndev);
@@ -1730,8 +1730,7 @@ static int axienet_probe(struct platform_device *pdev)
 	/* Retrieve the MAC address */
 	mac_addr = of_get_mac_address(pdev->dev.of_node);
 	if (IS_ERR(mac_addr)) {
-		dev_err(&pdev->dev, "could not find MAC address\n");
-		goto free_netdev;
+		dev_warn(&pdev->dev, "could not find MAC address property\n");
 	}
 	axienet_set_mac_address(ndev, mac_addr);
 
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH net-next 10/13] net: axienet: stop interface during shutdown
  2019-05-31 18:15 [PATCH net-next 00/13] Xilinx axienet driver updates Robert Hancock
                   ` (8 preceding siblings ...)
  2019-05-31 18:15 ` [PATCH net-next 09/13] net: axienet: Make missing MAC address non-fatal Robert Hancock
@ 2019-05-31 18:15 ` Robert Hancock
  2019-05-31 18:15 ` [PATCH net-next 11/13] net: axienet: document axistream-connected attribute Robert Hancock
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 22+ messages in thread
From: Robert Hancock @ 2019-05-31 18:15 UTC (permalink / raw)
  To: netdev; +Cc: anirudh, John.Linn, Robert Hancock

On some platforms, such as iMX6 with PCIe devices, crashes or hangs can
occur if the axienet device continues to perform DMA transfers after
parent devices/busses have been shut down. Shut down the axienet
interface during its shutdown callback in order to avoid this.

Signed-off-by: Robert Hancock <hancock@sedsystems.ca>
---
 drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index 947fa5d..3112724 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -1780,9 +1780,23 @@ static int axienet_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static void axienet_shutdown(struct platform_device *pdev)
+{
+	struct net_device *ndev = platform_get_drvdata(pdev);
+
+	rtnl_lock();
+	netif_device_detach(ndev);
+
+	if (netif_running(ndev))
+		dev_close(ndev);
+
+	rtnl_unlock();
+}
+
 static struct platform_driver axienet_driver = {
 	.probe = axienet_probe,
 	.remove = axienet_remove,
+	.shutdown = axienet_shutdown,
 	.driver = {
 		 .name = "xilinx_axienet",
 		 .of_match_table = axienet_of_match,
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH net-next 11/13] net: axienet: document axistream-connected attribute
  2019-05-31 18:15 [PATCH net-next 00/13] Xilinx axienet driver updates Robert Hancock
                   ` (9 preceding siblings ...)
  2019-05-31 18:15 ` [PATCH net-next 10/13] net: axienet: stop interface during shutdown Robert Hancock
@ 2019-05-31 18:15 ` Robert Hancock
  2019-05-31 18:15 ` [PATCH net-next 12/13] net: axienet: make use of axistream-connected attribute optional Robert Hancock
  2019-05-31 18:15 ` [PATCH net-next 13/13] net: axienet: convert to phylink API Robert Hancock
  12 siblings, 0 replies; 22+ messages in thread
From: Robert Hancock @ 2019-05-31 18:15 UTC (permalink / raw)
  To: netdev; +Cc: anirudh, John.Linn, Robert Hancock

The axienet driver requires the use of an axistream-connected attribute,
but this isn't documented in the devicetree bindings. Document how this
attribute is supposed to be used, including the upcoming change to make
the usage of this attribute optional.

Signed-off-by: Robert Hancock <hancock@sedsystems.ca>
---
 .../devicetree/bindings/net/xilinx_axienet.txt        | 19 +++++++++++++++----
 1 file changed, 15 insertions(+), 4 deletions(-)

diff --git a/Documentation/devicetree/bindings/net/xilinx_axienet.txt b/Documentation/devicetree/bindings/net/xilinx_axienet.txt
index 3f7b65e..da4eac2 100644
--- a/Documentation/devicetree/bindings/net/xilinx_axienet.txt
+++ b/Documentation/devicetree/bindings/net/xilinx_axienet.txt
@@ -17,9 +17,15 @@ For more details about mdio please refer phy.txt file in the same directory.
 Required properties:
 - compatible	: Must be one of "xlnx,axi-ethernet-1.00.a",
 		  "xlnx,axi-ethernet-1.01.a", "xlnx,axi-ethernet-2.01.a"
-- reg		: Address and length of the IO space.
+- reg		: Address and length of the IO space, as well as the address
+                  and length of the AXI DMA controller IO space, unless
+                  axistream-connected is specified, in which case the reg
+                  attribute of the node referenced by it is used.
 - interrupts	: Should be a list of 2 or 3 interrupts: TX DMA, RX DMA,
-		  and optionally Ethernet core.
+		  and optionally Ethernet core. If axistream-connected is
+		  specified, the TX/RX DMA interrupts should be on that node
+		  instead, and only the Ethernet core interrupt is optionally
+		  specified here.
 - phy-handle	: Should point to the external phy device.
 		  See ethernet.txt file in the same directory.
 - xlnx,rxmem	: Set to allocated memory buffer for Rx/Tx in the hardware
@@ -36,15 +42,20 @@ Optional properties:
                            to MDIO bus. If not specified, it is auto-detected
                            from the CPU clock (but only on platforms where this
                            is possible).
+- axistream-connected: Reference to another node which contains the resources
+		       for the AXI DMA controller used by this device.
+		       If this is specified, the DMA-related resources from that
+		       device (DMA registers and DMA TX/RX interrupts) rather
+		       than this one will be used.
 
 Example:
 	axi_ethernet_eth: ethernet@40c00000 {
 		compatible = "xlnx,axi-ethernet-1.00.a";
 		device_type = "network";
 		interrupt-parent = <&microblaze_0_axi_intc>;
-		interrupts = <2 0>;
+		interrupts = <2 0 1>;
 		phy-mode = "mii";
-		reg = <0x40c00000 0x40000>;
+		reg = <0x40c00000 0x40000 0x50c00000 0x40000>;
 		xlnx,rxcsum = <0x2>;
 		xlnx,rxmem = <0x800>;
 		xlnx,txcsum = <0x2>;
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH net-next 12/13] net: axienet: make use of axistream-connected attribute optional
  2019-05-31 18:15 [PATCH net-next 00/13] Xilinx axienet driver updates Robert Hancock
                   ` (10 preceding siblings ...)
  2019-05-31 18:15 ` [PATCH net-next 11/13] net: axienet: document axistream-connected attribute Robert Hancock
@ 2019-05-31 18:15 ` Robert Hancock
  2019-05-31 18:15 ` [PATCH net-next 13/13] net: axienet: convert to phylink API Robert Hancock
  12 siblings, 0 replies; 22+ messages in thread
From: Robert Hancock @ 2019-05-31 18:15 UTC (permalink / raw)
  To: netdev; +Cc: anirudh, John.Linn, Robert Hancock

Currently the axienet driver requires the use of a second devicetree
node, referenced by an axistream-connected attribute on the Ethernet
device node, which contains the resources for the AXI DMA block used by the
device. This setup is problematic for a use case we have where the Ethernet
and DMA cores are behind a PCIe to AXI bridge and the memory resources for
the nodes are injected into the platform devices using the multifunction
device subsystem - it's not easily possible for the driver to obtain the
platform-level resources from the linked device.

In order to simplify that usage model, and simplify the overall use of
this driver in general, allow for all of the resources to be kept on one
node where the resources are retrieved using platform device APIs rather
than device-tree-specific ones. The previous usage setup is still
supported if the axistream-connected attribute is specified.

Signed-off-by: Robert Hancock <hancock@sedsystems.ca>
---
 drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 43 +++++++++++++++--------
 1 file changed, 28 insertions(+), 15 deletions(-)

diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index 3112724..82caf04 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -1577,7 +1577,7 @@ static int axienet_probe(struct platform_device *pdev)
 	struct axienet_local *lp;
 	struct net_device *ndev;
 	const void *mac_addr;
-	struct resource *ethres, dmares;
+	struct resource *ethres;
 	u32 value;
 
 	ndev = alloc_etherdev(sizeof(*lp));
@@ -1695,28 +1695,41 @@ static int axienet_probe(struct platform_device *pdev)
 
 	/* Find the DMA node, map the DMA registers, and decode the DMA IRQs */
 	np = of_parse_phandle(pdev->dev.of_node, "axistream-connected", 0);
-	if (!np) {
-		dev_err(&pdev->dev, "could not find DMA node\n");
-		ret = -ENODEV;
-		goto free_netdev;
-	}
-	ret = of_address_to_resource(np, 0, &dmares);
-	if (ret) {
-		dev_err(&pdev->dev, "unable to get DMA resource\n");
+	if (np) {
+		struct resource dmares;
+
+		ret = of_address_to_resource(np, 0, &dmares);
+		if (ret) {
+			dev_err(&pdev->dev,
+				"unable to get DMA resource\n");
+			of_node_put(np);
+			goto free_netdev;
+		}
+		lp->dma_regs = devm_ioremap_resource(&pdev->dev,
+						     &dmares);
+		lp->rx_irq = irq_of_parse_and_map(np, 1);
+		lp->tx_irq = irq_of_parse_and_map(np, 0);
 		of_node_put(np);
-		goto free_netdev;
+		lp->eth_irq = platform_get_irq(pdev, 0);
+	} else {
+		/* Check for these resources directly on the Ethernet node. */
+		struct resource *res = platform_get_resource(pdev,
+							     IORESOURCE_MEM, 1);
+		if (!res) {
+			dev_err(&pdev->dev, "unable to get DMA memory resource\n");
+			goto free_netdev;
+		}
+		lp->dma_regs = devm_ioremap_resource(&pdev->dev, res);
+		lp->rx_irq = platform_get_irq(pdev, 1);
+		lp->tx_irq = platform_get_irq(pdev, 0);
+		lp->eth_irq = platform_get_irq(pdev, 2);
 	}
-	lp->dma_regs = devm_ioremap_resource(&pdev->dev, &dmares);
 	if (IS_ERR(lp->dma_regs)) {
 		dev_err(&pdev->dev, "could not map DMA regs\n");
 		ret = PTR_ERR(lp->dma_regs);
 		of_node_put(np);
 		goto free_netdev;
 	}
-	lp->rx_irq = irq_of_parse_and_map(np, 1);
-	lp->tx_irq = irq_of_parse_and_map(np, 0);
-	lp->eth_irq = irq_of_parse_and_map(np, 2);
-	of_node_put(np);
 	if ((lp->rx_irq <= 0) || (lp->tx_irq <= 0)) {
 		dev_err(&pdev->dev, "could not determine irqs\n");
 		ret = -ENOMEM;
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH net-next 13/13] net: axienet: convert to phylink API
  2019-05-31 18:15 [PATCH net-next 00/13] Xilinx axienet driver updates Robert Hancock
                   ` (11 preceding siblings ...)
  2019-05-31 18:15 ` [PATCH net-next 12/13] net: axienet: make use of axistream-connected attribute optional Robert Hancock
@ 2019-05-31 18:15 ` Robert Hancock
  12 siblings, 0 replies; 22+ messages in thread
From: Robert Hancock @ 2019-05-31 18:15 UTC (permalink / raw)
  To: netdev; +Cc: anirudh, John.Linn, Robert Hancock

Convert this driver to use the phylink API rather than the legacy PHY
API. This allows for better support for SFP modules connected using a
1000BaseX or SGMII interface.

Signed-off-by: Robert Hancock <hancock@sedsystems.ca>
---
 drivers/net/ethernet/xilinx/Kconfig               |   2 +-
 drivers/net/ethernet/xilinx/xilinx_axienet.h      |   5 +-
 drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 284 ++++++++++++++--------
 3 files changed, 190 insertions(+), 101 deletions(-)

diff --git a/drivers/net/ethernet/xilinx/Kconfig b/drivers/net/ethernet/xilinx/Kconfig
index f0b6896..de4eeda 100644
--- a/drivers/net/ethernet/xilinx/Kconfig
+++ b/drivers/net/ethernet/xilinx/Kconfig
@@ -27,7 +27,7 @@ config XILINX_EMACLITE
 config XILINX_AXI_EMAC
 	tristate "Xilinx 10/100/1000 AXI Ethernet support"
 	depends on MICROBLAZE || X86 || ARM
-	select PHYLIB
+	select PHYLINK
 	---help---
 	  This driver supports the 10/100/1000 Ethernet from Xilinx for the
 	  AXI bus interface used in Xilinx Virtex FPGAs.
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h b/drivers/net/ethernet/xilinx/xilinx_axienet.h
index e14a6e7..7963ffd 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet.h
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h
@@ -13,6 +13,7 @@
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
 #include <linux/if_vlan.h>
+#include <linux/phylink.h>
 
 /* Packet size info */
 #define XAE_HDR_SIZE			14 /* Size of Ethernet header */
@@ -420,6 +421,9 @@ struct axienet_local {
 	/* Connection to PHY device */
 	struct device_node *phy_node;
 
+	struct phylink *phylink;
+	struct phylink_config phylink_config;
+
 	/* MDIO clock divisor (0=detected from CPU clock) */
 	u32 mdio_clock_divisor;
 
@@ -439,7 +443,6 @@ struct axienet_local {
 	phy_interface_t phy_mode;
 
 	u32 options;			/* Current options word */
-	u32 last_link;
 	u32 features;
 
 	/* Buffer descriptors */
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index 82caf04..b7c7892 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -7,6 +7,7 @@
  * Copyright (c) 2008-2009 Secret Lab Technologies Ltd.
  * Copyright (c) 2010 - 2011 Michal Simek <monstr@monstr.eu>
  * Copyright (c) 2010 - 2011 PetaLogix
+ * Copyright (c) 2019 SED Systems, a division of Calian Ltd.
  * Copyright (c) 2010 - 2012 Xilinx, Inc. All rights reserved.
  *
  * This is a driver for the Xilinx Axi Ethernet which is used in the Virtex6
@@ -527,63 +528,6 @@ static void axienet_device_reset(struct net_device *ndev)
 }
 
 /**
- * axienet_adjust_link - Adjust the PHY link speed/duplex.
- * @ndev:	Pointer to the net_device structure
- *
- * This function is called to change the speed and duplex setting after
- * auto negotiation is done by the PHY. This is the function that gets
- * registered with the PHY interface through the "of_phy_connect" call.
- */
-static void axienet_adjust_link(struct net_device *ndev)
-{
-	u32 emmc_reg;
-	u32 link_state;
-	u32 setspeed = 1;
-	struct axienet_local *lp = netdev_priv(ndev);
-	struct phy_device *phy = ndev->phydev;
-
-	link_state = phy->speed | (phy->duplex << 1) | phy->link;
-	if (lp->last_link != link_state) {
-		if ((phy->speed == SPEED_10) || (phy->speed == SPEED_100)) {
-			if (lp->phy_mode == PHY_INTERFACE_MODE_1000BASEX)
-				setspeed = 0;
-		} else {
-			if ((phy->speed == SPEED_1000) &&
-			    (lp->phy_mode == PHY_INTERFACE_MODE_MII))
-				setspeed = 0;
-		}
-
-		if (setspeed == 1) {
-			emmc_reg = axienet_ior(lp, XAE_EMMC_OFFSET);
-			emmc_reg &= ~XAE_EMMC_LINKSPEED_MASK;
-
-			switch (phy->speed) {
-			case SPEED_1000:
-				emmc_reg |= XAE_EMMC_LINKSPD_1000;
-				break;
-			case SPEED_100:
-				emmc_reg |= XAE_EMMC_LINKSPD_100;
-				break;
-			case SPEED_10:
-				emmc_reg |= XAE_EMMC_LINKSPD_10;
-				break;
-			default:
-				dev_err(&ndev->dev, "Speed other than 10, 100 "
-					"or 1Gbps is not supported\n");
-				break;
-			}
-
-			axienet_iow(lp, XAE_EMMC_OFFSET, emmc_reg);
-			lp->last_link = link_state;
-			phy_print_status(phy);
-		} else {
-			netdev_err(ndev,
-				   "Error setting Axi Ethernet mac speed\n");
-		}
-	}
-}
-
-/**
  * axienet_start_xmit_done - Invoked once a transmit is completed by the
  * Axi DMA Tx channel.
  * @ndev:	Pointer to the net_device structure
@@ -963,7 +907,8 @@ static irqreturn_t axienet_eth_irq(int irq, void *_ndev)
  * Return: 0, on success.
  *	    non-zero error value on failure
  *
- * This is the driver open routine. It calls phy_start to start the PHY device.
+ * This is the driver open routine. It calls phylink_start to start the
+ * PHY device.
  * It also allocates interrupt service routines, enables the interrupt lines
  * and ISR handling. Axi Ethernet core is reset through Axi DMA core. Buffer
  * descriptors are initialized.
@@ -972,7 +917,6 @@ static int axienet_open(struct net_device *ndev)
 {
 	int ret;
 	struct axienet_local *lp = netdev_priv(ndev);
-	struct phy_device *phydev = NULL;
 
 	dev_dbg(&ndev->dev, "axienet_open()\n");
 
@@ -987,16 +931,14 @@ static int axienet_open(struct net_device *ndev)
 	if (ret < 0)
 		return ret;
 
-	if (lp->phy_node) {
-		phydev = of_phy_connect(lp->ndev, lp->phy_node,
-					axienet_adjust_link, 0, lp->phy_mode);
-
-		if (!phydev)
-			dev_err(lp->dev, "of_phy_connect() failed\n");
-		else
-			phy_start(phydev);
+	ret = phylink_of_phy_connect(lp->phylink, lp->dev->of_node, 0);
+	if (ret) {
+		dev_err(lp->dev, "phylink_of_phy_connect() failed: %d\n", ret);
+		return ret;
 	}
 
+	phylink_start(lp->phylink);
+
 	/* Enable tasklets for Axi DMA error handling */
 	tasklet_init(&lp->dma_err_tasklet, axienet_dma_err_handler,
 		     (unsigned long) lp);
@@ -1026,8 +968,8 @@ static int axienet_open(struct net_device *ndev)
 err_rx_irq:
 	free_irq(lp->tx_irq, ndev);
 err_tx_irq:
-	if (phydev)
-		phy_disconnect(phydev);
+	phylink_stop(lp->phylink);
+	phylink_disconnect_phy(lp->phylink);
 	tasklet_kill(&lp->dma_err_tasklet);
 	dev_err(lp->dev, "request_irq() failed\n");
 	return ret;
@@ -1039,7 +981,7 @@ static int axienet_open(struct net_device *ndev)
  *
  * Return: 0, on success.
  *
- * This is the driver stop routine. It calls phy_disconnect to stop the PHY
+ * This is the driver stop routine. It calls phylink_disconnect to stop the PHY
  * device. It also removes the interrupt handlers and disables the interrupts.
  * The Axi DMA Tx/Rx BDs are released.
  */
@@ -1051,6 +993,9 @@ static int axienet_stop(struct net_device *ndev)
 
 	dev_dbg(&ndev->dev, "axienet_close()\n");
 
+	phylink_stop(lp->phylink);
+	phylink_disconnect_phy(lp->phylink);
+
 	axienet_setoptions(ndev, lp->options &
 			   ~(XAE_OPTION_TXEN | XAE_OPTION_RXEN));
 
@@ -1087,9 +1032,6 @@ static int axienet_stop(struct net_device *ndev)
 	free_irq(lp->tx_irq, ndev);
 	free_irq(lp->rx_irq, ndev);
 
-	if (ndev->phydev)
-		phy_disconnect(ndev->phydev);
-
 	axienet_dma_bd_release(ndev);
 	return 0;
 }
@@ -1294,12 +1236,9 @@ static int axienet_ethtools_set_ringparam(struct net_device *ndev,
 axienet_ethtools_get_pauseparam(struct net_device *ndev,
 				struct ethtool_pauseparam *epauseparm)
 {
-	u32 regval;
 	struct axienet_local *lp = netdev_priv(ndev);
-	epauseparm->autoneg  = 0;
-	regval = axienet_ior(lp, XAE_FCC_OFFSET);
-	epauseparm->tx_pause = regval & XAE_FCC_FCTX_MASK;
-	epauseparm->rx_pause = regval & XAE_FCC_FCRX_MASK;
+
+	phylink_ethtool_get_pauseparam(lp->phylink, epauseparm);
 }
 
 /**
@@ -1318,27 +1257,9 @@ static int axienet_ethtools_set_ringparam(struct net_device *ndev,
 axienet_ethtools_set_pauseparam(struct net_device *ndev,
 				struct ethtool_pauseparam *epauseparm)
 {
-	u32 regval = 0;
 	struct axienet_local *lp = netdev_priv(ndev);
 
-	if (netif_running(ndev)) {
-		netdev_err(ndev,
-			   "Please stop netif before applying configuration\n");
-		return -EFAULT;
-	}
-
-	regval = axienet_ior(lp, XAE_FCC_OFFSET);
-	if (epauseparm->tx_pause)
-		regval |= XAE_FCC_FCTX_MASK;
-	else
-		regval &= ~XAE_FCC_FCTX_MASK;
-	if (epauseparm->rx_pause)
-		regval |= XAE_FCC_FCRX_MASK;
-	else
-		regval &= ~XAE_FCC_FCRX_MASK;
-	axienet_iow(lp, XAE_FCC_OFFSET, regval);
-
-	return 0;
+	return phylink_ethtool_set_pauseparam(lp->phylink, epauseparm);
 }
 
 /**
@@ -1417,6 +1338,24 @@ static int axienet_ethtools_set_coalesce(struct net_device *ndev,
 	return 0;
 }
 
+static int
+axienet_ethtools_get_link_ksettings(struct net_device *ndev,
+				    struct ethtool_link_ksettings *cmd)
+{
+	struct axienet_local *lp = netdev_priv(ndev);
+
+	return phylink_ethtool_ksettings_get(lp->phylink, cmd);
+}
+
+static int
+axienet_ethtools_set_link_ksettings(struct net_device *ndev,
+				    const struct ethtool_link_ksettings *cmd)
+{
+	struct axienet_local *lp = netdev_priv(ndev);
+
+	return phylink_ethtool_ksettings_set(lp->phylink, cmd);
+}
+
 static const struct ethtool_ops axienet_ethtool_ops = {
 	.get_drvinfo    = axienet_ethtools_get_drvinfo,
 	.get_regs_len   = axienet_ethtools_get_regs_len,
@@ -1428,8 +1367,141 @@ static int axienet_ethtools_set_coalesce(struct net_device *ndev,
 	.set_pauseparam = axienet_ethtools_set_pauseparam,
 	.get_coalesce   = axienet_ethtools_get_coalesce,
 	.set_coalesce   = axienet_ethtools_set_coalesce,
-	.get_link_ksettings = phy_ethtool_get_link_ksettings,
-	.set_link_ksettings = phy_ethtool_set_link_ksettings,
+	.get_link_ksettings = axienet_ethtools_get_link_ksettings,
+	.set_link_ksettings = axienet_ethtools_set_link_ksettings,
+};
+
+static void axienet_validate(struct phylink_config *config,
+			     unsigned long *supported,
+			     struct phylink_link_state *state)
+{
+	struct net_device *ndev = to_net_dev(config->dev);
+	struct axienet_local *lp = netdev_priv(ndev);
+	__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
+
+	/* Only support the mode we are configured for */
+	if (state->interface != PHY_INTERFACE_MODE_NA &&
+	    state->interface != lp->phy_mode) {
+		netdev_warn(ndev, "Cannot use PHY mode %s, supported: %s\n",
+			    phy_modes(state->interface),
+			    phy_modes(lp->phy_mode));
+		bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
+		return;
+	}
+
+	phylink_set(mask, Autoneg);
+	phylink_set_port_modes(mask);
+
+	phylink_set(mask, Asym_Pause);
+	phylink_set(mask, Pause);
+	phylink_set(mask, 1000baseX_Full);
+	phylink_set(mask, 10baseT_Full);
+	phylink_set(mask, 100baseT_Full);
+	phylink_set(mask, 1000baseT_Full);
+
+	bitmap_and(supported, supported, mask,
+		   __ETHTOOL_LINK_MODE_MASK_NBITS);
+	bitmap_and(state->advertising, state->advertising, mask,
+		   __ETHTOOL_LINK_MODE_MASK_NBITS);
+}
+
+static int axienet_mac_link_state(struct phylink_config *config,
+				  struct phylink_link_state *state)
+{
+	u32 emmc_reg, fcc_reg;
+	struct net_device *ndev = to_net_dev(config->dev);
+	struct axienet_local *lp = netdev_priv(ndev);
+
+	state->interface = lp->phy_mode;
+
+	emmc_reg = axienet_ior(lp, XAE_EMMC_OFFSET);
+	if (emmc_reg & XAE_EMMC_LINKSPD_1000)
+		state->speed = SPEED_1000;
+	else if (emmc_reg & XAE_EMMC_LINKSPD_100)
+		state->speed = SPEED_100;
+	else
+		state->speed = SPEED_10;
+
+	state->pause = 0;
+	fcc_reg = axienet_ior(lp, XAE_FCC_OFFSET);
+	if (fcc_reg & XAE_FCC_FCTX_MASK)
+		state->pause |= MLO_PAUSE_TX;
+	if (fcc_reg & XAE_FCC_FCRX_MASK)
+		state->pause |= MLO_PAUSE_RX;
+
+	state->an_complete = 0;
+	state->duplex = 1;
+
+	return 1;
+}
+
+static void axienet_mac_an_restart(struct phylink_config *config)
+{
+	/* Unsupported, do nothing */
+}
+
+static void axienet_mac_config(struct phylink_config *config, unsigned int mode,
+			       const struct phylink_link_state *state)
+{
+	u32 emmc_reg, fcc_reg;
+	struct net_device *ndev = to_net_dev(config->dev);
+	struct axienet_local *lp = netdev_priv(ndev);
+
+	emmc_reg = axienet_ior(lp, XAE_EMMC_OFFSET);
+	emmc_reg &= ~XAE_EMMC_LINKSPEED_MASK;
+
+	switch (state->speed) {
+	case SPEED_1000:
+		emmc_reg |= XAE_EMMC_LINKSPD_1000;
+		break;
+	case SPEED_100:
+		emmc_reg |= XAE_EMMC_LINKSPD_100;
+		break;
+	case SPEED_10:
+		emmc_reg |= XAE_EMMC_LINKSPD_10;
+		break;
+	default:
+		dev_err(&ndev->dev,
+			"Speed other than 10, 100 or 1Gbps is not supported\n");
+		break;
+	}
+
+	axienet_iow(lp, XAE_EMMC_OFFSET, emmc_reg);
+
+	fcc_reg = axienet_ior(lp, XAE_FCC_OFFSET);
+	if (state->pause & MLO_PAUSE_TX)
+		fcc_reg |= XAE_FCC_FCTX_MASK;
+	else
+		fcc_reg &= ~XAE_FCC_FCTX_MASK;
+	if (state->pause & MLO_PAUSE_RX)
+		fcc_reg |= XAE_FCC_FCRX_MASK;
+	else
+		fcc_reg &= ~XAE_FCC_FCRX_MASK;
+	axienet_iow(lp, XAE_FCC_OFFSET, fcc_reg);
+}
+
+static void axienet_mac_link_down(struct phylink_config *config,
+				  unsigned int mode,
+				  phy_interface_t interface)
+{
+	/* nothing meaningful to do */
+}
+
+static void axienet_mac_link_up(struct phylink_config *config,
+				unsigned int mode,
+				phy_interface_t interface,
+				struct phy_device *phy)
+{
+	/* nothing meaningful to do */
+}
+
+static const struct phylink_mac_ops axienet_phylink_ops = {
+	.validate = axienet_validate,
+	.mac_link_state = axienet_mac_link_state,
+	.mac_an_restart = axienet_mac_an_restart,
+	.mac_config = axienet_mac_config,
+	.mac_link_down = axienet_mac_link_down,
+	.mac_link_up = axienet_mac_link_up,
 };
 
 /**
@@ -1763,6 +1835,18 @@ static int axienet_probe(struct platform_device *pdev)
 				 "error registering MDIO bus: %d\n", ret);
 	}
 
+	lp->phylink_config.dev = &ndev->dev;
+	lp->phylink_config.type = PHYLINK_NETDEV;
+
+	lp->phylink = phylink_create(&lp->phylink_config, pdev->dev.fwnode,
+				     lp->phy_mode,
+				     &axienet_phylink_ops);
+	if (IS_ERR(lp->phylink)) {
+		ret = PTR_ERR(lp->phylink);
+		dev_err(&pdev->dev, "phylink_create error (%i)\n", ret);
+		goto free_netdev;
+	}
+
 	ret = register_netdev(lp->ndev);
 	if (ret) {
 		dev_err(lp->dev, "register_netdev() error (%i)\n", ret);
@@ -1785,6 +1869,8 @@ static int axienet_remove(struct platform_device *pdev)
 	unregister_netdev(ndev);
 	axienet_mdio_teardown(lp);
 
+	if (lp->phylink)
+		phylink_destroy(lp->phylink);
 	of_node_put(lp->phy_node);
 	lp->phy_node = NULL;
 
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* Re: [PATCH net-next 01/13] net: axienet: Fixed 64-bit compile, enable build on X86 and ARM
  2019-05-31 18:15 ` [PATCH net-next 01/13] net: axienet: Fixed 64-bit compile, enable build on X86 and ARM Robert Hancock
@ 2019-05-31 21:10   ` Andrew Lunn
  2019-05-31 23:28     ` Robert Hancock
  2019-06-02  6:37   ` kbuild test robot
  1 sibling, 1 reply; 22+ messages in thread
From: Andrew Lunn @ 2019-05-31 21:10 UTC (permalink / raw)
  To: Robert Hancock; +Cc: netdev, anirudh, John.Linn

Hi Robert

I think you can split this into three patches, in order to make it
easier to review:

IO accessors
skb in the control block
MDIO changes.

>  static inline u32 axienet_ior(struct axienet_local *lp, off_t offset)
>  {
> -	return in_be32(lp->regs + offset);
> +#ifdef CONFIG_MICROBLAZE
> +	return __raw_readl(lp->regs + offset);
> +#else
> +	return ioread32(lp->regs + offset);
> +#endif
>  }

Please dig deeper into the available accessor functions. There should
be a set which works without this #defery. 

   Andrew

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH net-next 02/13] net: axienet: clean up MDIO handling
  2019-05-31 18:15 ` [PATCH net-next 02/13] net: axienet: clean up MDIO handling Robert Hancock
@ 2019-05-31 21:13   ` Andrew Lunn
  0 siblings, 0 replies; 22+ messages in thread
From: Andrew Lunn @ 2019-05-31 21:13 UTC (permalink / raw)
  To: Robert Hancock; +Cc: netdev, anirudh, John.Linn

On Fri, May 31, 2019 at 12:15:34PM -0600, Robert Hancock wrote:
> -Allow specifying the MDIO clock divisor explicitly in the device tree,
> rather than always detecting it from the CPU clock which only works on
> the MicroBlaze platform.
> 
> -Centralize all MDIO handling in xilinx_axienet_mdio.c
> 
> -Ensure that MDIO clock divisor is always re-set after resetting the
> device, since it will be cleared.
> 
> -Fixed ordering of MDIO teardown vs. netdev teardown

That sounds like 4 patches, not one.

There are too many thinks mixed up in this patchset. I'm not reviewing
it. Sorry.

    Andrew

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH net-next 09/13] net: axienet: Make missing MAC address non-fatal
  2019-05-31 18:15 ` [PATCH net-next 09/13] net: axienet: Make missing MAC address non-fatal Robert Hancock
@ 2019-05-31 21:16   ` Andrew Lunn
  2019-06-03 13:22   ` David Laight
  1 sibling, 0 replies; 22+ messages in thread
From: Andrew Lunn @ 2019-05-31 21:16 UTC (permalink / raw)
  To: Robert Hancock; +Cc: netdev, anirudh, John.Linn

On Fri, May 31, 2019 at 12:15:41PM -0600, Robert Hancock wrote:
> Failing initialization on a missing MAC address property is excessive.
> We can just fall back to using a random MAC instead, which at least
> leaves the interface in a functioning state.
> 
> Signed-off-by: Robert Hancock <hancock@sedsystems.ca>

Reviewed-by: Andrew Lunn <andrew@lunn.ch>

    Andrew

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH net-next 01/13] net: axienet: Fixed 64-bit compile, enable build on X86 and ARM
  2019-05-31 21:10   ` Andrew Lunn
@ 2019-05-31 23:28     ` Robert Hancock
  2019-06-01  3:04       ` Andrew Lunn
  0 siblings, 1 reply; 22+ messages in thread
From: Robert Hancock @ 2019-05-31 23:28 UTC (permalink / raw)
  To: Andrew Lunn; +Cc: netdev, anirudh, John.Linn

On 2019-05-31 3:10 p.m., Andrew Lunn wrote:
>>  static inline u32 axienet_ior(struct axienet_local *lp, off_t offset)
>>  {
>> -	return in_be32(lp->regs + offset);
>> +#ifdef CONFIG_MICROBLAZE
>> +	return __raw_readl(lp->regs + offset);
>> +#else
>> +	return ioread32(lp->regs + offset);
>> +#endif
>>  }
> 
> Please dig deeper into the available accessor functions. There should
> be a set which works without this #defery. 

This driver previously only compiled on MicroBlaze, and on that
platform, in_be32 is mapped to __raw_readl which reads with no byte
swapping. The confusing this is that MicroBlaze can apparently be set up
as either LE or BE, so I'm guessing that the hardware setup just
arranges that the reads are natively in the right byte order depending
on the mode. If I were to just use ioread32, there would be no change on
LE Microblaze, but BE Microblaze would start byte-swapping, which I
assume would break things.

The Xilinx version of this driver also supports Zynq (arm) and ZynqMP
(aarch64) platforms, and for those platforms it defines in_be32 to
__raw_readl as well. Since those are little-endian that ends up being
the same byte order as ioread32.

Finally, the setup we're using this hardware with on ARM over a PCIe to
AXI bridge exposes the device with the same byte order as any other PCIe
device, so the regular ioread32 accessors are correct.

I'm not quite sure what to make of that.. most platforms either would
need or work fine with the "regular" accessors, but I'm not sure that
wouldn't break big-endian MicroBlaze. It would be useful if one of the
Xilinx people could confirm that..

-- 
Robert Hancock
Senior Software Developer
SED Systems, a division of Calian Ltd.
Email: hancock@sedsystems.ca

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH net-next 01/13] net: axienet: Fixed 64-bit compile, enable build on X86 and ARM
  2019-05-31 23:28     ` Robert Hancock
@ 2019-06-01  3:04       ` Andrew Lunn
  0 siblings, 0 replies; 22+ messages in thread
From: Andrew Lunn @ 2019-06-01  3:04 UTC (permalink / raw)
  To: Robert Hancock; +Cc: netdev, anirudh, John.Linn

On Fri, May 31, 2019 at 05:28:45PM -0600, Robert Hancock wrote:
> On 2019-05-31 3:10 p.m., Andrew Lunn wrote:
> >>  static inline u32 axienet_ior(struct axienet_local *lp, off_t offset)
> >>  {
> >> -	return in_be32(lp->regs + offset);
> >> +#ifdef CONFIG_MICROBLAZE
> >> +	return __raw_readl(lp->regs + offset);
> >> +#else
> >> +	return ioread32(lp->regs + offset);
> >> +#endif
> >>  }
> > 
> > Please dig deeper into the available accessor functions. There should
> > be a set which works without this #defery. 
> 
> This driver previously only compiled on MicroBlaze, and on that
> platform, in_be32 is mapped to __raw_readl which reads with no byte
> swapping. The confusing this is that MicroBlaze can apparently be set up
> as either LE or BE, so I'm guessing that the hardware setup just
> arranges that the reads are natively in the right byte order depending
> on the mode. If I were to just use ioread32, there would be no change on
> LE Microblaze, but BE Microblaze would start byte-swapping, which I
> assume would break things.
> 
> The Xilinx version of this driver also supports Zynq (arm) and ZynqMP
> (aarch64) platforms, and for those platforms it defines in_be32 to
> __raw_readl as well. Since those are little-endian that ends up being
> the same byte order as ioread32.
> 
> Finally, the setup we're using this hardware with on ARM over a PCIe to
> AXI bridge exposes the device with the same byte order as any other PCIe
> device, so the regular ioread32 accessors are correct.
> 
> I'm not quite sure what to make of that.. most platforms either would
> need or work fine with the "regular" accessors, but I'm not sure that
> wouldn't break big-endian MicroBlaze. It would be useful if one of the
> Xilinx people could confirm that..

What matter here is the endianness of the devices register. Once you
know that, there should be macros which work independent of the
endianness of the CPU and compile to the right thing.  Assuming the
endianness of the device is fixed and not a synthesis option? If it is
synthesis option, i would hope there is a register you can read to
determine its endianennes.

	Andrew

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH net-next 01/13] net: axienet: Fixed 64-bit compile, enable build on X86 and ARM
  2019-05-31 18:15 ` [PATCH net-next 01/13] net: axienet: Fixed 64-bit compile, enable build on X86 and ARM Robert Hancock
  2019-05-31 21:10   ` Andrew Lunn
@ 2019-06-02  6:37   ` kbuild test robot
  1 sibling, 0 replies; 22+ messages in thread
From: kbuild test robot @ 2019-06-02  6:37 UTC (permalink / raw)
  To: Robert Hancock; +Cc: kbuild-all, netdev, anirudh, John.Linn, Robert Hancock

Hi Robert,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on net-next/master]

url:    https://github.com/0day-ci/linux/commits/Robert-Hancock/Xilinx-axienet-driver-updates/20190602-124146
reproduce:
        # apt-get install sparse
        # sparse version: v0.6.1-rc1-7-g2b96cd8-dirty
        make ARCH=x86_64 allmodconfig
        make C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__'

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>


sparse warnings: (new ones prefixed by >>)

>> drivers/net/ethernet/xilinx/xilinx_axienet_main.c:778:37: sparse: sparse: cast to restricted __be32
>> drivers/net/ethernet/xilinx/xilinx_axienet_main.c:778:37: sparse: sparse: cast to restricted __be32
>> drivers/net/ethernet/xilinx/xilinx_axienet_main.c:778:37: sparse: sparse: cast to restricted __be32
>> drivers/net/ethernet/xilinx/xilinx_axienet_main.c:778:37: sparse: sparse: cast to restricted __be32
>> drivers/net/ethernet/xilinx/xilinx_axienet_main.c:778:37: sparse: sparse: cast to restricted __be32
>> drivers/net/ethernet/xilinx/xilinx_axienet_main.c:778:37: sparse: sparse: cast to restricted __be32
>> drivers/net/ethernet/xilinx/xilinx_axienet_main.c:778:35: sparse: sparse: incorrect type in assignment (different base types) @@    expected restricted __wsum [usertype] csum @@    got  [usertype] csum @@
>> drivers/net/ethernet/xilinx/xilinx_axienet_main.c:778:35: sparse:    expected restricted __wsum [usertype] csum
>> drivers/net/ethernet/xilinx/xilinx_axienet_main.c:778:35: sparse:    got unsigned int

vim +778 drivers/net/ethernet/xilinx/xilinx_axienet_main.c

8a3b7a25 Daniel Borkmann   2012-01-19  728  
8a3b7a25 Daniel Borkmann   2012-01-19  729  /**
8a3b7a25 Daniel Borkmann   2012-01-19  730   * axienet_recv - Is called from Axi DMA Rx Isr to complete the received
8a3b7a25 Daniel Borkmann   2012-01-19  731   *		  BD processing.
8a3b7a25 Daniel Borkmann   2012-01-19  732   * @ndev:	Pointer to net_device structure.
8a3b7a25 Daniel Borkmann   2012-01-19  733   *
8a3b7a25 Daniel Borkmann   2012-01-19  734   * This function is invoked from the Axi DMA Rx isr to process the Rx BDs. It
8a3b7a25 Daniel Borkmann   2012-01-19  735   * does minimal processing and invokes "netif_rx" to complete further
8a3b7a25 Daniel Borkmann   2012-01-19  736   * processing.
8a3b7a25 Daniel Borkmann   2012-01-19  737   */
8a3b7a25 Daniel Borkmann   2012-01-19  738  static void axienet_recv(struct net_device *ndev)
8a3b7a25 Daniel Borkmann   2012-01-19  739  {
8a3b7a25 Daniel Borkmann   2012-01-19  740  	u32 length;
8a3b7a25 Daniel Borkmann   2012-01-19  741  	u32 csumstatus;
8a3b7a25 Daniel Borkmann   2012-01-19  742  	u32 size = 0;
8a3b7a25 Daniel Borkmann   2012-01-19  743  	u32 packets = 0;
38e96b35 Peter Crosthwaite 2015-05-05  744  	dma_addr_t tail_p = 0;
8a3b7a25 Daniel Borkmann   2012-01-19  745  	struct axienet_local *lp = netdev_priv(ndev);
8a3b7a25 Daniel Borkmann   2012-01-19  746  	struct sk_buff *skb, *new_skb;
8a3b7a25 Daniel Borkmann   2012-01-19  747  	struct axidma_bd *cur_p;
8a3b7a25 Daniel Borkmann   2012-01-19  748  
8a3b7a25 Daniel Borkmann   2012-01-19  749  	cur_p = &lp->rx_bd_v[lp->rx_bd_ci];
8a3b7a25 Daniel Borkmann   2012-01-19  750  
8a3b7a25 Daniel Borkmann   2012-01-19  751  	while ((cur_p->status & XAXIDMA_BD_STS_COMPLETE_MASK)) {
38e96b35 Peter Crosthwaite 2015-05-05  752  		tail_p = lp->rx_bd_p + sizeof(*lp->rx_bd_v) * lp->rx_bd_ci;
8a3b7a25 Daniel Borkmann   2012-01-19  753  
8a3b7a25 Daniel Borkmann   2012-01-19  754  		dma_unmap_single(ndev->dev.parent, cur_p->phys,
8a3b7a25 Daniel Borkmann   2012-01-19  755  				 lp->max_frm_size,
8a3b7a25 Daniel Borkmann   2012-01-19  756  				 DMA_FROM_DEVICE);
8a3b7a25 Daniel Borkmann   2012-01-19  757  
2f148c6d Robert Hancock    2019-05-31  758  		skb = cur_p->skb;
2f148c6d Robert Hancock    2019-05-31  759  		cur_p->skb = NULL;
2f148c6d Robert Hancock    2019-05-31  760  		length = cur_p->app4 & 0x0000FFFF;
2f148c6d Robert Hancock    2019-05-31  761  
8a3b7a25 Daniel Borkmann   2012-01-19  762  		skb_put(skb, length);
8a3b7a25 Daniel Borkmann   2012-01-19  763  		skb->protocol = eth_type_trans(skb, ndev);
8a3b7a25 Daniel Borkmann   2012-01-19  764  		/*skb_checksum_none_assert(skb);*/
8a3b7a25 Daniel Borkmann   2012-01-19  765  		skb->ip_summed = CHECKSUM_NONE;
8a3b7a25 Daniel Borkmann   2012-01-19  766  
8a3b7a25 Daniel Borkmann   2012-01-19  767  		/* if we're doing Rx csum offload, set it up */
8a3b7a25 Daniel Borkmann   2012-01-19  768  		if (lp->features & XAE_FEATURE_FULL_RX_CSUM) {
8a3b7a25 Daniel Borkmann   2012-01-19  769  			csumstatus = (cur_p->app2 &
8a3b7a25 Daniel Borkmann   2012-01-19  770  				      XAE_FULL_CSUM_STATUS_MASK) >> 3;
8a3b7a25 Daniel Borkmann   2012-01-19  771  			if ((csumstatus == XAE_IP_TCP_CSUM_VALIDATED) ||
8a3b7a25 Daniel Borkmann   2012-01-19  772  			    (csumstatus == XAE_IP_UDP_CSUM_VALIDATED)) {
8a3b7a25 Daniel Borkmann   2012-01-19  773  				skb->ip_summed = CHECKSUM_UNNECESSARY;
8a3b7a25 Daniel Borkmann   2012-01-19  774  			}
8a3b7a25 Daniel Borkmann   2012-01-19  775  		} else if ((lp->features & XAE_FEATURE_PARTIAL_RX_CSUM) != 0 &&
ceffc4ac Joe Perches       2014-03-12  776  			   skb->protocol == htons(ETH_P_IP) &&
8a3b7a25 Daniel Borkmann   2012-01-19  777  			   skb->len > 64) {
8a3b7a25 Daniel Borkmann   2012-01-19 @778  			skb->csum = be32_to_cpu(cur_p->app3 & 0xFFFF);
8a3b7a25 Daniel Borkmann   2012-01-19  779  			skb->ip_summed = CHECKSUM_COMPLETE;
8a3b7a25 Daniel Borkmann   2012-01-19  780  		}
8a3b7a25 Daniel Borkmann   2012-01-19  781  
8a3b7a25 Daniel Borkmann   2012-01-19  782  		netif_rx(skb);
8a3b7a25 Daniel Borkmann   2012-01-19  783  
8a3b7a25 Daniel Borkmann   2012-01-19  784  		size += length;
8a3b7a25 Daniel Borkmann   2012-01-19  785  		packets++;
8a3b7a25 Daniel Borkmann   2012-01-19  786  
8a3b7a25 Daniel Borkmann   2012-01-19  787  		new_skb = netdev_alloc_skb_ip_align(ndev, lp->max_frm_size);
720a43ef Joe Perches       2013-03-08  788  		if (!new_skb)
8a3b7a25 Daniel Borkmann   2012-01-19  789  			return;
720a43ef Joe Perches       2013-03-08  790  
8a3b7a25 Daniel Borkmann   2012-01-19  791  		cur_p->phys = dma_map_single(ndev->dev.parent, new_skb->data,
8a3b7a25 Daniel Borkmann   2012-01-19  792  					     lp->max_frm_size,
8a3b7a25 Daniel Borkmann   2012-01-19  793  					     DMA_FROM_DEVICE);
8a3b7a25 Daniel Borkmann   2012-01-19  794  		cur_p->cntrl = lp->max_frm_size;
8a3b7a25 Daniel Borkmann   2012-01-19  795  		cur_p->status = 0;
2f148c6d Robert Hancock    2019-05-31  796  		cur_p->skb = new_skb;
8a3b7a25 Daniel Borkmann   2012-01-19  797  
91ff37ff Michal Simek      2014-02-13  798  		++lp->rx_bd_ci;
91ff37ff Michal Simek      2014-02-13  799  		lp->rx_bd_ci %= RX_BD_NUM;
8a3b7a25 Daniel Borkmann   2012-01-19  800  		cur_p = &lp->rx_bd_v[lp->rx_bd_ci];
8a3b7a25 Daniel Borkmann   2012-01-19  801  	}
8a3b7a25 Daniel Borkmann   2012-01-19  802  
8a3b7a25 Daniel Borkmann   2012-01-19  803  	ndev->stats.rx_packets += packets;
8a3b7a25 Daniel Borkmann   2012-01-19  804  	ndev->stats.rx_bytes += size;
8a3b7a25 Daniel Borkmann   2012-01-19  805  
38e96b35 Peter Crosthwaite 2015-05-05  806  	if (tail_p)
8a3b7a25 Daniel Borkmann   2012-01-19  807  		axienet_dma_out32(lp, XAXIDMA_RX_TDESC_OFFSET, tail_p);
8a3b7a25 Daniel Borkmann   2012-01-19  808  }
8a3b7a25 Daniel Borkmann   2012-01-19  809  

:::::: The code at line 778 was first introduced by commit
:::::: 8a3b7a252dca9fb28c23b5bf76c49180a2b60d3b drivers/net/ethernet/xilinx: added Xilinx AXI Ethernet driver

:::::: TO: danborkmann@iogearbox.net <danborkmann@iogearbox.net>
:::::: CC: David S. Miller <davem@davemloft.net>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

^ permalink raw reply	[flat|nested] 22+ messages in thread

* RE: [PATCH net-next 09/13] net: axienet: Make missing MAC address non-fatal
  2019-05-31 18:15 ` [PATCH net-next 09/13] net: axienet: Make missing MAC address non-fatal Robert Hancock
  2019-05-31 21:16   ` Andrew Lunn
@ 2019-06-03 13:22   ` David Laight
  2019-06-03 15:49     ` Robert Hancock
  1 sibling, 1 reply; 22+ messages in thread
From: David Laight @ 2019-06-03 13:22 UTC (permalink / raw)
  To: 'Robert Hancock', netdev; +Cc: anirudh, John.Linn

From: Robert Hancock
> Sent: 31 May 2019 19:16
> Failing initialization on a missing MAC address property is excessive.
> We can just fall back to using a random MAC instead, which at least
> leaves the interface in a functioning state.
> 
> Signed-off-by: Robert Hancock <hancock@sedsystems.ca>
> ---
>  drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 5 ++---
>  1 file changed, 2 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
> b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
> index 9949e67..947fa5d 100644
> --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
> +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
> @@ -308,7 +308,7 @@ static void axienet_set_mac_address(struct net_device *ndev,
>  {
>  	struct axienet_local *lp = netdev_priv(ndev);
> 
> -	if (address)
> +	if (!IS_ERR(address))
>  		memcpy(ndev->dev_addr, address, ETH_ALEN);
>  	if (!is_valid_ether_addr(ndev->dev_addr))
>  		eth_hw_addr_random(ndev);
> @@ -1730,8 +1730,7 @@ static int axienet_probe(struct platform_device *pdev)
>  	/* Retrieve the MAC address */
>  	mac_addr = of_get_mac_address(pdev->dev.of_node);
>  	if (IS_ERR(mac_addr)) {
> -		dev_err(&pdev->dev, "could not find MAC address\n");
> -		goto free_netdev;
> +		dev_warn(&pdev->dev, "could not find MAC address property\n");
>  	}
>  	axienet_set_mac_address(ndev, mac_addr);

Isn't that going to read from an invalid address on error?
Seems you didn't test of_get_mac_address() failing :-)

	David

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH net-next 09/13] net: axienet: Make missing MAC address non-fatal
  2019-06-03 13:22   ` David Laight
@ 2019-06-03 15:49     ` Robert Hancock
  0 siblings, 0 replies; 22+ messages in thread
From: Robert Hancock @ 2019-06-03 15:49 UTC (permalink / raw)
  To: David Laight, netdev; +Cc: anirudh, John.Linn

On 2019-06-03 7:22 a.m., David Laight wrote:
> From: Robert Hancock
>> Sent: 31 May 2019 19:16
>> Failing initialization on a missing MAC address property is excessive.
>> We can just fall back to using a random MAC instead, which at least
>> leaves the interface in a functioning state.
>>
>> Signed-off-by: Robert Hancock <hancock@sedsystems.ca>
>> ---
>>  drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 5 ++---
>>  1 file changed, 2 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
>> b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
>> index 9949e67..947fa5d 100644
>> --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
>> +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
>> @@ -308,7 +308,7 @@ static void axienet_set_mac_address(struct net_device *ndev,
>>  {
>>  	struct axienet_local *lp = netdev_priv(ndev);
>>
>> -	if (address)
>> +	if (!IS_ERR(address))
>>  		memcpy(ndev->dev_addr, address, ETH_ALEN);
>>  	if (!is_valid_ether_addr(ndev->dev_addr))
>>  		eth_hw_addr_random(ndev);
>> @@ -1730,8 +1730,7 @@ static int axienet_probe(struct platform_device *pdev)
>>  	/* Retrieve the MAC address */
>>  	mac_addr = of_get_mac_address(pdev->dev.of_node);
>>  	if (IS_ERR(mac_addr)) {
>> -		dev_err(&pdev->dev, "could not find MAC address\n");
>> -		goto free_netdev;
>> +		dev_warn(&pdev->dev, "could not find MAC address property\n");
>>  	}
>>  	axienet_set_mac_address(ndev, mac_addr);
> 
> Isn't that going to read from an invalid address on error?
> Seems you didn't test of_get_mac_address() failing :-)

axienet_set_mac_address checks IS_ERR(mac_addr) as well before reading
from it, so the invalid address should not be accessed.

-- 
Robert Hancock
Senior Software Developer
SED Systems, a division of Calian Ltd.
Email: hancock@sedsystems.ca

^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2019-06-03 15:50 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-05-31 18:15 [PATCH net-next 00/13] Xilinx axienet driver updates Robert Hancock
2019-05-31 18:15 ` [PATCH net-next 01/13] net: axienet: Fixed 64-bit compile, enable build on X86 and ARM Robert Hancock
2019-05-31 21:10   ` Andrew Lunn
2019-05-31 23:28     ` Robert Hancock
2019-06-01  3:04       ` Andrew Lunn
2019-06-02  6:37   ` kbuild test robot
2019-05-31 18:15 ` [PATCH net-next 02/13] net: axienet: clean up MDIO handling Robert Hancock
2019-05-31 21:13   ` Andrew Lunn
2019-05-31 18:15 ` [PATCH net-next 03/13] net: axienet: Cleanup DMA device reset and halt process Robert Hancock
2019-05-31 18:15 ` [PATCH net-next 04/13] net: axienet: Make RX/TX ring sizes configurable Robert Hancock
2019-05-31 18:15 ` [PATCH net-next 05/13] net: axienet: Add DMA registers to ethtool register dump Robert Hancock
2019-05-31 18:15 ` [PATCH net-next 06/13] net: axienet: Support shared interrupts Robert Hancock
2019-05-31 18:15 ` [PATCH net-next 07/13] net: axienet: Add optional support for Ethernet core interrupt Robert Hancock
2019-05-31 18:15 ` [PATCH net-next 08/13] net: axienet: Fix race condition causing TX hang Robert Hancock
2019-05-31 18:15 ` [PATCH net-next 09/13] net: axienet: Make missing MAC address non-fatal Robert Hancock
2019-05-31 21:16   ` Andrew Lunn
2019-06-03 13:22   ` David Laight
2019-06-03 15:49     ` Robert Hancock
2019-05-31 18:15 ` [PATCH net-next 10/13] net: axienet: stop interface during shutdown Robert Hancock
2019-05-31 18:15 ` [PATCH net-next 11/13] net: axienet: document axistream-connected attribute Robert Hancock
2019-05-31 18:15 ` [PATCH net-next 12/13] net: axienet: make use of axistream-connected attribute optional Robert Hancock
2019-05-31 18:15 ` [PATCH net-next 13/13] net: axienet: convert to phylink API Robert Hancock

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.