linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/12] net: ll_temac: x86_64 support
@ 2019-04-26  7:32 Esben Haabendal
  2019-04-26  7:32 ` [PATCH 01/12] net: ll_temac: Fix and simplify error handling by using devres functions Esben Haabendal
                   ` (12 more replies)
  0 siblings, 13 replies; 59+ messages in thread
From: Esben Haabendal @ 2019-04-26  7:32 UTC (permalink / raw)
  To: netdev
  Cc: Michal Simek, David S. Miller, Luis Chamberlain, Yang Wei,
	YueHaibing, linux-kernel, linux-arm-kernel

This patch series adds support for use of ll_temac driver with
platform_data configuration and fixes endianess and 64-bit problems so
that it can be used on x86_64 platform.

A few bugfixes are also included.

Esben Haabendal (12):
  net: ll_temac: Fix and simplify error handling by using devres
    functions
  net: ll_temac: Extend support to non-device-tree platforms
  net: ll_temac: Fix support for 64-bit platforms
  net: ll_temac: Add support for non-native register endianness
  net: ll_temac: Fix support for little-endian platforms
  net: ll_temac: Allow use on x86 platforms
  net: ll_temac: Support indirect_mutex share within TEMAC IP
  net: ll_temac: Fix iommu/swiotlb leak
  net: ll_temac: Fix bug causing buffer descriptor overrun
  net: ll_temac: Replace bad usage of msleep() with usleep_range()
  net: ll_temac: Allow configuration of IRQ coalescing
  net: ll_temac: Enable DMA when ready, not before

 drivers/net/ethernet/xilinx/Kconfig         |   5 +-
 drivers/net/ethernet/xilinx/ll_temac.h      |  26 +-
 drivers/net/ethernet/xilinx/ll_temac_main.c | 514 ++++++++++++++++++----------
 drivers/net/ethernet/xilinx/ll_temac_mdio.c |  53 +--
 include/linux/xilinx_ll_temac.h             |  31 ++
 5 files changed, 426 insertions(+), 203 deletions(-)
 create mode 100644 include/linux/xilinx_ll_temac.h

-- 
2.4.11


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

* [PATCH 01/12] net: ll_temac: Fix and simplify error handling by using devres functions
  2019-04-26  7:32 [PATCH 00/12] net: ll_temac: x86_64 support Esben Haabendal
@ 2019-04-26  7:32 ` Esben Haabendal
  2019-04-26  7:32 ` [PATCH 02/12] net: ll_temac: Extend support to non-device-tree platforms Esben Haabendal
                   ` (11 subsequent siblings)
  12 siblings, 0 replies; 59+ messages in thread
From: Esben Haabendal @ 2019-04-26  7:32 UTC (permalink / raw)
  To: netdev
  Cc: David S. Miller, Michal Simek, YueHaibing, Luis Chamberlain,
	Yang Wei, linux-arm-kernel, linux-kernel

As a side effect, a few error cases are fixed.

If of_iomap() of sdma_regs failed, no error code was returned.  Fixed to
return -ENOMEM similar to of_iomap() fail of regs.

If sysfs_create_group() or register_netdev() failed, lp->phy_node was not
released.

Finally, the order in remove function is corrected to be reverse order
of what is done in probe, i.e. calling temac_mdio_teardown() last, so we
unregister the netdev that most likely is using the mdio_bus first.

Signed-off-by: Esben Haabendal <esben@geanix.com>
---
 drivers/net/ethernet/xilinx/ll_temac.h      |  2 +-
 drivers/net/ethernet/xilinx/ll_temac_main.c | 48 ++++++++++-------------------
 drivers/net/ethernet/xilinx/ll_temac_mdio.c | 14 +++------
 3 files changed, 22 insertions(+), 42 deletions(-)

diff --git a/drivers/net/ethernet/xilinx/ll_temac.h b/drivers/net/ethernet/xilinx/ll_temac.h
index 1075752..4557578 100644
--- a/drivers/net/ethernet/xilinx/ll_temac.h
+++ b/drivers/net/ethernet/xilinx/ll_temac.h
@@ -378,7 +378,7 @@ void temac_indirect_out32(struct temac_local *lp, int reg, u32 value);
 
 
 /* xilinx_temac_mdio.c */
-int temac_mdio_setup(struct temac_local *lp, struct device_node *np);
+int temac_mdio_setup(struct temac_local *lp, struct platform_device *pdev);
 void temac_mdio_teardown(struct temac_local *lp);
 
 #endif /* XILINX_LL_TEMAC_H */
diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index 44efffb..c4e85a9 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -225,7 +225,6 @@ static void temac_dma_bd_release(struct net_device *ndev)
 		dma_free_coherent(ndev->dev.parent,
 				sizeof(*lp->tx_bd_v) * TX_BD_NUM,
 				lp->tx_bd_v, lp->tx_bd_p);
-	kfree(lp->rx_skb);
 }
 
 /**
@@ -237,7 +236,8 @@ static int temac_dma_bd_init(struct net_device *ndev)
 	struct sk_buff *skb;
 	int i;
 
-	lp->rx_skb = kcalloc(RX_BD_NUM, sizeof(*lp->rx_skb), GFP_KERNEL);
+	lp->rx_skb = devm_kcalloc(&ndev->dev, RX_BD_NUM, sizeof(*lp->rx_skb),
+				  GFP_KERNEL);
 	if (!lp->rx_skb)
 		goto out;
 
@@ -987,7 +987,7 @@ static int temac_of_probe(struct platform_device *op)
 	int rc = 0;
 
 	/* Init network device structure */
-	ndev = alloc_etherdev(sizeof(*lp));
+	ndev = devm_alloc_etherdev(&pdev->dev, sizeof(*lp));
 	if (!ndev)
 		return -ENOMEM;
 
@@ -1020,11 +1020,10 @@ static int temac_of_probe(struct platform_device *op)
 	mutex_init(&lp->indirect_mutex);
 
 	/* map device registers */
-	lp->regs = of_iomap(op->dev.of_node, 0);
+	lp->regs = devm_of_iomap(&op->dev, op->dev.of_node, 0, NULL);
 	if (!lp->regs) {
 		dev_err(&op->dev, "could not map temac regs.\n");
-		rc = -ENOMEM;
-		goto nodev;
+		return -ENOMEM;
 	}
 
 	/* Setup checksum offload, but default to off if not specified */
@@ -1043,15 +1042,14 @@ static int temac_of_probe(struct platform_device *op)
 	np = of_parse_phandle(op->dev.of_node, "llink-connected", 0);
 	if (!np) {
 		dev_err(&op->dev, "could not find DMA node\n");
-		rc = -ENODEV;
-		goto err_iounmap;
+		return -ENODEV;
 	}
 
 	/* Setup the DMA register accesses, could be DCR or memory mapped */
 	if (temac_dcr_setup(lp, op, np)) {
 
 		/* no DCR in the device tree, try non-DCR */
-		lp->sdma_regs = of_iomap(np, 0);
+		lp->sdma_regs = devm_of_iomap(&op->dev, np, 0, NULL);
 		if (lp->sdma_regs) {
 			lp->dma_in = temac_dma_in32;
 			lp->dma_out = temac_dma_out32;
@@ -1059,7 +1057,7 @@ static int temac_of_probe(struct platform_device *op)
 		} else {
 			dev_err(&op->dev, "unable to map DMA registers\n");
 			of_node_put(np);
-			goto err_iounmap;
+			return -ENOMEM;
 		}
 	}
 
@@ -1070,8 +1068,7 @@ static int temac_of_probe(struct platform_device *op)
 
 	if (!lp->rx_irq || !lp->tx_irq) {
 		dev_err(&op->dev, "could not determine irqs\n");
-		rc = -ENOMEM;
-		goto err_iounmap_2;
+		return -ENOMEM;
 	}
 
 
@@ -1079,12 +1076,11 @@ static int temac_of_probe(struct platform_device *op)
 	addr = of_get_mac_address(op->dev.of_node);
 	if (!addr) {
 		dev_err(&op->dev, "could not find MAC address\n");
-		rc = -ENODEV;
-		goto err_iounmap_2;
+		return -ENODEV;
 	}
 	temac_init_mac_address(ndev, addr);
 
-	rc = temac_mdio_setup(lp, op->dev.of_node);
+	rc = temac_mdio_setup(lp, pdev);
 	if (rc)
 		dev_warn(&op->dev, "error registering MDIO bus\n");
 
@@ -1096,7 +1092,7 @@ static int temac_of_probe(struct platform_device *op)
 	rc = sysfs_create_group(&lp->dev->kobj, &temac_attr_group);
 	if (rc) {
 		dev_err(lp->dev, "Error creating sysfs files\n");
-		goto err_iounmap_2;
+		goto err_sysfs_create;
 	}
 
 	rc = register_netdev(lp->ndev);
@@ -1107,16 +1103,11 @@ static int temac_of_probe(struct platform_device *op)
 
 	return 0;
 
- err_register_ndev:
+err_register_ndev:
 	sysfs_remove_group(&lp->dev->kobj, &temac_attr_group);
- err_iounmap_2:
-	if (lp->sdma_regs)
-		iounmap(lp->sdma_regs);
- err_iounmap:
-	iounmap(lp->regs);
- nodev:
-	free_netdev(ndev);
-	ndev = NULL;
+err_sysfs_create:
+	of_node_put(lp->phy_node);
+	temac_mdio_teardown(lp);
 	return rc;
 }
 
@@ -1125,15 +1116,10 @@ static int temac_of_remove(struct platform_device *op)
 	struct net_device *ndev = platform_get_drvdata(op);
 	struct temac_local *lp = netdev_priv(ndev);
 
-	temac_mdio_teardown(lp);
 	unregister_netdev(ndev);
 	sysfs_remove_group(&lp->dev->kobj, &temac_attr_group);
 	of_node_put(lp->phy_node);
-	lp->phy_node = NULL;
-	iounmap(lp->regs);
-	if (lp->sdma_regs)
-		iounmap(lp->sdma_regs);
-	free_netdev(ndev);
+	temac_mdio_teardown(lp);
 	return 0;
 }
 
diff --git a/drivers/net/ethernet/xilinx/ll_temac_mdio.c b/drivers/net/ethernet/xilinx/ll_temac_mdio.c
index f5e83ac..a0b365e 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_mdio.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_mdio.c
@@ -57,8 +57,9 @@ static int temac_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 val)
 	return 0;
 }
 
-int temac_mdio_setup(struct temac_local *lp, struct device_node *np)
+int temac_mdio_setup(struct temac_local *lp, struct platform_device *pdev)
 {
+	struct device_node *np = dev_of_node(&pdev->dev);
 	struct mii_bus *bus;
 	u32 bus_hz;
 	int clk_div;
@@ -81,7 +82,7 @@ int temac_mdio_setup(struct temac_local *lp, struct device_node *np)
 	temac_indirect_out32(lp, XTE_MC_OFFSET, 1 << 6 | clk_div);
 	mutex_unlock(&lp->indirect_mutex);
 
-	bus = mdiobus_alloc();
+	bus = devm_mdiobus_alloc(&pdev->dev);
 	if (!bus)
 		return -ENOMEM;
 
@@ -98,23 +99,16 @@ int temac_mdio_setup(struct temac_local *lp, struct device_node *np)
 
 	rc = of_mdiobus_register(bus, np);
 	if (rc)
-		goto err_register;
+		return rc;
 
 	mutex_lock(&lp->indirect_mutex);
 	dev_dbg(lp->dev, "MDIO bus registered;  MC:%x\n",
 		temac_indirect_in32(lp, XTE_MC_OFFSET));
 	mutex_unlock(&lp->indirect_mutex);
 	return 0;
-
- err_register:
-	mdiobus_free(bus);
-	return rc;
 }
 
 void temac_mdio_teardown(struct temac_local *lp)
 {
 	mdiobus_unregister(lp->mii_bus);
-	mdiobus_free(lp->mii_bus);
-	lp->mii_bus = NULL;
 }
-
-- 
2.4.11


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

* [PATCH 02/12] net: ll_temac: Extend support to non-device-tree platforms
  2019-04-26  7:32 [PATCH 00/12] net: ll_temac: x86_64 support Esben Haabendal
  2019-04-26  7:32 ` [PATCH 01/12] net: ll_temac: Fix and simplify error handling by using devres functions Esben Haabendal
@ 2019-04-26  7:32 ` Esben Haabendal
  2019-04-26 13:58   ` Andrew Lunn
  2019-04-26  7:32 ` [PATCH 03/12] net: ll_temac: Fix support for 64-bit platforms Esben Haabendal
                   ` (10 subsequent siblings)
  12 siblings, 1 reply; 59+ messages in thread
From: Esben Haabendal @ 2019-04-26  7:32 UTC (permalink / raw)
  To: netdev
  Cc: David S. Miller, Michal Simek, Luis Chamberlain, YueHaibing,
	Yang Wei, linux-kernel, linux-arm-kernel

Support initialization with platdata, so the driver can be used on
non-device-tree platforms.

For currently supported device-tree platforms, the driver should behave
as before.

Signed-off-by: Esben Haabendal <esben@geanix.com>
---
 drivers/net/ethernet/xilinx/ll_temac.h      |   3 +
 drivers/net/ethernet/xilinx/ll_temac_main.c | 187 +++++++++++++++++++---------
 drivers/net/ethernet/xilinx/ll_temac_mdio.c |  23 +++-
 include/linux/xilinx_ll_temac.h             |  18 +++
 4 files changed, 165 insertions(+), 66 deletions(-)
 create mode 100644 include/linux/xilinx_ll_temac.h

diff --git a/drivers/net/ethernet/xilinx/ll_temac.h b/drivers/net/ethernet/xilinx/ll_temac.h
index 4557578..e338b4f 100644
--- a/drivers/net/ethernet/xilinx/ll_temac.h
+++ b/drivers/net/ethernet/xilinx/ll_temac.h
@@ -334,6 +334,9 @@ struct temac_local {
 
 	/* Connection to PHY device */
 	struct device_node *phy_node;
+	/* For non-device-tree devices */
+	char phy_name[MII_BUS_ID_SIZE + 3];
+	phy_interface_t phy_interface;
 
 	/* MDIO bus data */
 	struct mii_bus *mii_bus;	/* MII bus reference */
diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index c4e85a9..4594fe3 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -33,6 +33,7 @@
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/netdevice.h>
+#include <linux/if_ether.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_irq.h>
@@ -51,6 +52,7 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/dma-mapping.h>
+#include <linux/xilinx_ll_temac.h>
 
 #include "ll_temac.h"
 
@@ -187,7 +189,7 @@ static int temac_dcr_setup(struct temac_local *lp, struct platform_device *op,
 
 /*
  * temac_dcr_setup - This is a stub for when DCR is not supported,
- * such as with MicroBlaze
+ * such as with MicroBlaze and x86
  */
 static int temac_dcr_setup(struct temac_local *lp, struct platform_device *op,
 				struct device_node *np)
@@ -857,7 +859,14 @@ static int temac_open(struct net_device *ndev)
 			dev_err(lp->dev, "of_phy_connect() failed\n");
 			return -ENODEV;
 		}
-
+		phy_start(phydev);
+	} else if (strlen(lp->phy_name) > 0) {
+		phydev = phy_connect(lp->ndev, lp->phy_name, temac_adjust_link,
+				     lp->phy_interface);
+		if (!phydev) {
+			dev_err(lp->dev, "phy_connect() failed\n");
+			return -ENODEV;
+		}
 		phy_start(phydev);
 	}
 
@@ -977,11 +986,13 @@ static const struct ethtool_ops temac_ethtool_ops = {
 	.set_link_ksettings = phy_ethtool_set_link_ksettings,
 };
 
-static int temac_of_probe(struct platform_device *op)
+static int temac_probe(struct platform_device *pdev)
 {
-	struct device_node *np;
+	struct ll_temac_platform_data *pdata = dev_get_platdata(&pdev->dev);
+	struct device_node *temac_np = dev_of_node(&pdev->dev), *dma_np;
 	struct temac_local *lp;
 	struct net_device *ndev;
+	struct resource *res;
 	const void *addr;
 	__be32 *p;
 	int rc = 0;
@@ -991,8 +1002,8 @@ static int temac_of_probe(struct platform_device *op)
 	if (!ndev)
 		return -ENOMEM;
 
-	platform_set_drvdata(op, ndev);
-	SET_NETDEV_DEV(ndev, &op->dev);
+	platform_set_drvdata(pdev, ndev);
+	SET_NETDEV_DEV(ndev, &pdev->dev);
 	ndev->flags &= ~IFF_MULTICAST;  /* clear multicast */
 	ndev->features = NETIF_F_SG;
 	ndev->netdev_ops = &temac_netdev_ops;
@@ -1014,79 +1025,129 @@ static int temac_of_probe(struct platform_device *op)
 	/* setup temac private info structure */
 	lp = netdev_priv(ndev);
 	lp->ndev = ndev;
-	lp->dev = &op->dev;
+	lp->dev = &pdev->dev;
 	lp->options = XTE_OPTION_DEFAULTS;
 	spin_lock_init(&lp->rx_lock);
 	mutex_init(&lp->indirect_mutex);
 
 	/* map device registers */
-	lp->regs = devm_of_iomap(&op->dev, op->dev.of_node, 0, NULL);
-	if (!lp->regs) {
-		dev_err(&op->dev, "could not map temac regs.\n");
-		return -ENOMEM;
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	lp->regs = devm_ioremap_nocache(&pdev->dev, res->start,
+					resource_size(res));
+	if (IS_ERR(lp->regs)) {
+		dev_err(&pdev->dev, "could not map TEMAC registers\n");
+		return PTR_ERR(lp->regs);
 	}
 
 	/* Setup checksum offload, but default to off if not specified */
 	lp->temac_features = 0;
-	p = (__be32 *)of_get_property(op->dev.of_node, "xlnx,txcsum", NULL);
-	if (p && be32_to_cpu(*p)) {
-		lp->temac_features |= TEMAC_FEATURE_TX_CSUM;
+	if (temac_np) {
+		p = (__be32 *)of_get_property(temac_np, "xlnx,txcsum", NULL);
+		if (p && be32_to_cpu(*p))
+			lp->temac_features |= TEMAC_FEATURE_TX_CSUM;
+		p = (__be32 *)of_get_property(temac_np, "xlnx,rxcsum", NULL);
+		if (p && be32_to_cpu(*p))
+			lp->temac_features |= TEMAC_FEATURE_RX_CSUM;
+	} else if (pdata) {
+		if (pdata->txcsum)
+			lp->temac_features |= TEMAC_FEATURE_TX_CSUM;
+		if (pdata->rxcsum)
+			lp->temac_features |= TEMAC_FEATURE_RX_CSUM;
+	}
+	if (lp->temac_features & TEMAC_FEATURE_TX_CSUM)
 		/* Can checksum TCP/UDP over IPv4. */
 		ndev->features |= NETIF_F_IP_CSUM;
-	}
-	p = (__be32 *)of_get_property(op->dev.of_node, "xlnx,rxcsum", NULL);
-	if (p && be32_to_cpu(*p))
-		lp->temac_features |= TEMAC_FEATURE_RX_CSUM;
-
-	/* Find the DMA node, map the DMA registers, and decode the DMA IRQs */
-	np = of_parse_phandle(op->dev.of_node, "llink-connected", 0);
-	if (!np) {
-		dev_err(&op->dev, "could not find DMA node\n");
-		return -ENODEV;
-	}
 
-	/* Setup the DMA register accesses, could be DCR or memory mapped */
-	if (temac_dcr_setup(lp, op, np)) {
+	/* Setup LocalLink DMA */
+	if (temac_np) {
+		/* Find the DMA node, map the DMA registers, and
+		 * decode the DMA IRQs.
+		 */
+		dma_np = of_parse_phandle(temac_np, "llink-connected", 0);
+		if (!dma_np) {
+			dev_err(&pdev->dev, "could not find DMA node\n");
+			return -ENODEV;
+		}
 
-		/* no DCR in the device tree, try non-DCR */
-		lp->sdma_regs = devm_of_iomap(&op->dev, np, 0, NULL);
-		if (lp->sdma_regs) {
+		/* Setup the DMA register accesses, could be DCR or
+		 * memory mapped.
+		 */
+		if (temac_dcr_setup(lp, pdev, dma_np)) {
+			/* no DCR in the device tree, try non-DCR */
+			lp->sdma_regs = devm_of_iomap(&pdev->dev, dma_np, 0,
+						      NULL);
+			if (IS_ERR(lp->sdma_regs)) {
+				dev_err(&pdev->dev,
+					"unable to map DMA registers\n");
+				of_node_put(dma_np);
+				return PTR_ERR(lp->sdma_regs);
+			}
 			lp->dma_in = temac_dma_in32;
 			lp->dma_out = temac_dma_out32;
-			dev_dbg(&op->dev, "MEM base: %p\n", lp->sdma_regs);
-		} else {
-			dev_err(&op->dev, "unable to map DMA registers\n");
-			of_node_put(np);
-			return -ENOMEM;
+			dev_dbg(&pdev->dev, "MEM base: %p\n", lp->sdma_regs);
 		}
-	}
-
-	lp->rx_irq = irq_of_parse_and_map(np, 0);
-	lp->tx_irq = irq_of_parse_and_map(np, 1);
 
-	of_node_put(np); /* Finished with the DMA node; drop the reference */
+		/* Get DMA RX and TX interrupts */
+		lp->rx_irq = irq_of_parse_and_map(dma_np, 0);
+		lp->tx_irq = irq_of_parse_and_map(dma_np, 1);
+
+		/* Finished with the DMA node; drop the reference */
+		of_node_put(dma_np);
+	} else if (pdata) {
+		/* 2nd memory resource specifies DMA registers */
+		res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+		lp->sdma_regs = devm_ioremap_nocache(&pdev->dev, res->start,
+						     resource_size(res));
+		if (IS_ERR(lp->sdma_regs)) {
+			dev_err(&pdev->dev,
+				"could not map DMA registers\n");
+			return PTR_ERR(lp->sdma_regs);
+		}
+		lp->dma_in = temac_dma_in32;
+		lp->dma_out = temac_dma_out32;
 
-	if (!lp->rx_irq || !lp->tx_irq) {
-		dev_err(&op->dev, "could not determine irqs\n");
-		return -ENOMEM;
+		/* Get DMA RX and TX interrupts */
+		lp->rx_irq = platform_get_irq(pdev, 0);
+		lp->tx_irq = platform_get_irq(pdev, 1);
 	}
 
+	/* Error handle returned DMA RX and TX interrupts */
+	if (lp->rx_irq < 0) {
+		if (lp->rx_irq != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "could not get DMA RX irq\n");
+		return lp->rx_irq;
+	}
+	if (lp->tx_irq < 0) {
+		if (lp->tx_irq != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "could not get DMA TX irq\n");
+		return lp->tx_irq;
+	}
 
-	/* Retrieve the MAC address */
-	addr = of_get_mac_address(op->dev.of_node);
-	if (!addr) {
-		dev_err(&op->dev, "could not find MAC address\n");
-		return -ENODEV;
+	if (temac_np) {
+		/* Retrieve the MAC address */
+		addr = of_get_mac_address(temac_np);
+		if (!addr) {
+			dev_err(&pdev->dev, "could not find MAC address\n");
+			return -ENODEV;
+		}
+		temac_init_mac_address(ndev, addr);
+	} else if (pdata) {
+		temac_init_mac_address(ndev, pdata->mac_addr);
 	}
-	temac_init_mac_address(ndev, addr);
 
 	rc = temac_mdio_setup(lp, pdev);
 	if (rc)
-		dev_warn(&op->dev, "error registering MDIO bus\n");
-
-	lp->phy_node = of_parse_phandle(op->dev.of_node, "phy-handle", 0);
-	if (lp->phy_node)
-		dev_dbg(lp->dev, "using PHY node %pOF (%p)\n", np, np);
+		dev_warn(&pdev->dev, "error registering MDIO bus\n");
+
+	if (temac_np) {
+		lp->phy_node = of_parse_phandle(temac_np, "phy-handle", 0);
+		if (lp->phy_node)
+			dev_dbg(lp->dev, "using PHY node %pOF\n", temac_np);
+	} else if (pdata) {
+		snprintf(lp->phy_name, sizeof(lp->phy_name),
+			 PHY_ID_FMT, lp->mii_bus->id, pdata->phy_addr);
+		lp->phy_interface = pdata->phy_interface;
+	}
 
 	/* Add the device attributes */
 	rc = sysfs_create_group(&lp->dev->kobj, &temac_attr_group);
@@ -1106,19 +1167,21 @@ static int temac_of_probe(struct platform_device *op)
 err_register_ndev:
 	sysfs_remove_group(&lp->dev->kobj, &temac_attr_group);
 err_sysfs_create:
-	of_node_put(lp->phy_node);
+	if (lp->phy_node)
+		of_node_put(lp->phy_node);
 	temac_mdio_teardown(lp);
 	return rc;
 }
 
-static int temac_of_remove(struct platform_device *op)
+static int temac_remove(struct platform_device *pdev)
 {
-	struct net_device *ndev = platform_get_drvdata(op);
+	struct net_device *ndev = platform_get_drvdata(pdev);
 	struct temac_local *lp = netdev_priv(ndev);
 
 	unregister_netdev(ndev);
 	sysfs_remove_group(&lp->dev->kobj, &temac_attr_group);
-	of_node_put(lp->phy_node);
+	if (lp->phy_node)
+		of_node_put(lp->phy_node);
 	temac_mdio_teardown(lp);
 	return 0;
 }
@@ -1132,16 +1195,16 @@ static const struct of_device_id temac_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, temac_of_match);
 
-static struct platform_driver temac_of_driver = {
-	.probe = temac_of_probe,
-	.remove = temac_of_remove,
+static struct platform_driver temac_driver = {
+	.probe = temac_probe,
+	.remove = temac_remove,
 	.driver = {
 		.name = "xilinx_temac",
 		.of_match_table = temac_of_match,
 	},
 };
 
-module_platform_driver(temac_of_driver);
+module_platform_driver(temac_driver);
 
 MODULE_DESCRIPTION("Xilinx LL_TEMAC Ethernet driver");
 MODULE_AUTHOR("Yoshio Kashiwagi");
diff --git a/drivers/net/ethernet/xilinx/ll_temac_mdio.c b/drivers/net/ethernet/xilinx/ll_temac_mdio.c
index a0b365e..61b832f 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_mdio.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_mdio.c
@@ -14,6 +14,7 @@
 #include <linux/of_address.h>
 #include <linux/slab.h>
 #include <linux/of_mdio.h>
+#include <linux/xilinx_ll_temac.h>
 
 #include "ll_temac.h"
 
@@ -59,6 +60,7 @@ static int temac_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 val)
 
 int temac_mdio_setup(struct temac_local *lp, struct platform_device *pdev)
 {
+	struct ll_temac_platform_data *pdata = dev_get_platdata(&pdev->dev);
 	struct device_node *np = dev_of_node(&pdev->dev);
 	struct mii_bus *bus;
 	u32 bus_hz;
@@ -66,9 +68,16 @@ int temac_mdio_setup(struct temac_local *lp, struct platform_device *pdev)
 	int rc;
 	struct resource res;
 
+	/* Get MDIO bus frequency (if specified) */
+	bus_hz = 0;
+	if (np)
+		of_property_read_u32(np, "clock-frequency", &bus_hz);
+	else if (pdata)
+		bus_hz = pdata->mdio_clk_freq;
+
 	/* Calculate a reasonable divisor for the clock rate */
 	clk_div = 0x3f; /* worst-case default setting */
-	if (of_property_read_u32(np, "clock-frequency", &bus_hz) == 0) {
+	if (bus_hz != 0) {
 		clk_div = bus_hz / (2500 * 1000 * 2) - 1;
 		if (clk_div < 1)
 			clk_div = 1;
@@ -86,9 +95,15 @@ int temac_mdio_setup(struct temac_local *lp, struct platform_device *pdev)
 	if (!bus)
 		return -ENOMEM;
 
-	of_address_to_resource(np, 0, &res);
-	snprintf(bus->id, MII_BUS_ID_SIZE, "%.8llx",
-		 (unsigned long long)res.start);
+	if (np) {
+		of_address_to_resource(np, 0, &res);
+		snprintf(bus->id, MII_BUS_ID_SIZE, "%.8llx",
+			 (unsigned long long)res.start);
+	} else if (pdata && pdata->mdio_bus_id >= 0) {
+		snprintf(bus->id, MII_BUS_ID_SIZE, "%.8llx",
+			 pdata->mdio_bus_id);
+	}
+
 	bus->priv = lp;
 	bus->name = "Xilinx TEMAC MDIO";
 	bus->read = temac_mdio_read;
diff --git a/include/linux/xilinx_ll_temac.h b/include/linux/xilinx_ll_temac.h
new file mode 100644
index 0000000..44d7dd6
--- /dev/null
+++ b/include/linux/xilinx_ll_temac.h
@@ -0,0 +1,18 @@
+#ifndef __LINUX_XILINX_LL_TEMAC_H
+#define __LINUX_XILINX_LL_TEMAC_H
+
+#include <linux/if_ether.h>
+#include <linux/phy.h>
+
+struct ll_temac_platform_data {
+	bool txcsum;		/* Enable/disable TX checksum */
+	bool rxcsum;		/* Enable/disable RX checksum */
+	u8 mac_addr[ETH_ALEN];	/* MAC address (6 bytes) */
+	/* Clock frequency for input to MDIO clock generator */
+	u32 mdio_clk_freq;
+	unsigned long long mdio_bus_id; /* Unique id for MDIO bus */
+	int phy_addr;		/* Address of the PHY to connect to */
+	phy_interface_t phy_interface; /* PHY interface mode */
+};
+
+#endif /* __LINUX_XILINX_LL_TEMAC_H */
-- 
2.4.11


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

* [PATCH 03/12] net: ll_temac: Fix support for 64-bit platforms
  2019-04-26  7:32 [PATCH 00/12] net: ll_temac: x86_64 support Esben Haabendal
  2019-04-26  7:32 ` [PATCH 01/12] net: ll_temac: Fix and simplify error handling by using devres functions Esben Haabendal
  2019-04-26  7:32 ` [PATCH 02/12] net: ll_temac: Extend support to non-device-tree platforms Esben Haabendal
@ 2019-04-26  7:32 ` Esben Haabendal
  2019-04-26 18:40   ` Jakub Kicinski
  2019-04-26  7:32 ` [PATCH 04/12] net: ll_temac: Add support for non-native register endianness Esben Haabendal
                   ` (9 subsequent siblings)
  12 siblings, 1 reply; 59+ messages in thread
From: Esben Haabendal @ 2019-04-26  7:32 UTC (permalink / raw)
  To: netdev
  Cc: David S. Miller, Michal Simek, Yang Wei, YueHaibing,
	Luis Chamberlain, linux-arm-kernel, linux-kernel

The use of buffer descriptor APP4 field (32-bit) for storing skb pointer
obviously does not work on 64-bit platforms.
As APP3 is also unused, we can use that to store the other half of 64-bit
pointer values.

Contrary to what is hinted at in commit message of commit 15bfe05c8d63
("net: ethernet: xilinx: Mark XILINX_LL_TEMAC broken on 64-bit")
there are no other pointers stored in cdmac_bd.

Signed-off-by: Esben Haabendal <esben@geanix.com>
---
 drivers/net/ethernet/xilinx/Kconfig         |  1 -
 drivers/net/ethernet/xilinx/ll_temac_main.c | 35 ++++++++++++++++++++++++++---
 2 files changed, 32 insertions(+), 4 deletions(-)

diff --git a/drivers/net/ethernet/xilinx/Kconfig b/drivers/net/ethernet/xilinx/Kconfig
index da4ec57..6d68c8a 100644
--- a/drivers/net/ethernet/xilinx/Kconfig
+++ b/drivers/net/ethernet/xilinx/Kconfig
@@ -34,7 +34,6 @@ config XILINX_AXI_EMAC
 config XILINX_LL_TEMAC
 	tristate "Xilinx LL TEMAC (LocalLink Tri-mode Ethernet MAC) driver"
 	depends on (PPC || MICROBLAZE)
-	depends on !64BIT || BROKEN
 	select PHYLIB
 	---help---
 	  This driver supports the Xilinx 10/100/1000 LocalLink TEMAC
diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index 4594fe3..a365bfd 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -619,11 +619,39 @@ static void temac_adjust_link(struct net_device *ndev)
 	mutex_unlock(&lp->indirect_mutex);
 }
 
+#ifdef CONFIG_64BIT
+
+void ptr_to_txbd(void *p, struct cdmac_bd *bd)
+{
+	bd->app3 = (u32)(((u64)p) >> 32);
+	bd->app4 = (u32)((u64)p & 0xFFFFFFFF);
+}
+
+void *ptr_from_txbd(struct cdmac_bd *bd)
+{
+	return (void *)(((u64)(bd->app3) << 32) | bd->app4);
+}
+
+#else
+
+void ptr_to_txbd(void *p, struct cmdac_bd *bd)
+{
+	bd->app4 = (u32)p;
+}
+
+void *ptr_from_txbd(struct cdmac_bd *bd)
+{
+	return (void *)(bd->app4);
+}
+
+#endif
+
 static void temac_start_xmit_done(struct net_device *ndev)
 {
 	struct temac_local *lp = netdev_priv(ndev);
 	struct cdmac_bd *cur_p;
 	unsigned int stat = 0;
+	struct sk_buff *skb;
 
 	cur_p = &lp->tx_bd_v[lp->tx_bd_ci];
 	stat = cur_p->app0;
@@ -631,8 +659,9 @@ static void temac_start_xmit_done(struct net_device *ndev)
 	while (stat & STS_CTRL_APP0_CMPLT) {
 		dma_unmap_single(ndev->dev.parent, cur_p->phys, cur_p->len,
 				 DMA_TO_DEVICE);
-		if (cur_p->app4)
-			dev_consume_skb_irq((struct sk_buff *)cur_p->app4);
+		skb = (struct sk_buff *)ptr_from_txbd(cur_p);
+		if (skb)
+			dev_consume_skb_irq(skb);
 		cur_p->app0 = 0;
 		cur_p->app1 = 0;
 		cur_p->app2 = 0;
@@ -711,7 +740,7 @@ temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 	cur_p->len = skb_headlen(skb);
 	cur_p->phys = dma_map_single(ndev->dev.parent, skb->data,
 				     skb_headlen(skb), DMA_TO_DEVICE);
-	cur_p->app4 = (unsigned long)skb;
+	ptr_to_txbd((void *)skb, cur_p);
 
 	for (ii = 0; ii < num_frag; ii++) {
 		lp->tx_bd_tail++;
-- 
2.4.11


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

* [PATCH 04/12] net: ll_temac: Add support for non-native register endianness
  2019-04-26  7:32 [PATCH 00/12] net: ll_temac: x86_64 support Esben Haabendal
                   ` (2 preceding siblings ...)
  2019-04-26  7:32 ` [PATCH 03/12] net: ll_temac: Fix support for 64-bit platforms Esben Haabendal
@ 2019-04-26  7:32 ` Esben Haabendal
  2019-04-26  7:32 ` [PATCH 05/12] net: ll_temac: Fix support for little-endian platforms Esben Haabendal
                   ` (8 subsequent siblings)
  12 siblings, 0 replies; 59+ messages in thread
From: Esben Haabendal @ 2019-04-26  7:32 UTC (permalink / raw)
  To: netdev
  Cc: David S. Miller, Michal Simek, Yang Wei, YueHaibing,
	Luis Chamberlain, linux-arm-kernel, linux-kernel

Replace the powerpc specific MMIO register access functions with the
generic big-endian mmio access functions, and add support for
little-endian access depending on configuration.

Big-endian access is maintained as the default, but little-endian can
be configured in device-tree binding or in platform data.

The temac_ior()/temac_iow() functions are replaced with macro wrappers
to avoid modifying existing code more than necessary.

Signed-off-by: Esben Haabendal <esben@geanix.com>
---
 drivers/net/ethernet/xilinx/ll_temac.h      | 12 ++--
 drivers/net/ethernet/xilinx/ll_temac_main.c | 87 +++++++++++++++++++++++------
 include/linux/xilinx_ll_temac.h             |  2 +
 3 files changed, 79 insertions(+), 22 deletions(-)

diff --git a/drivers/net/ethernet/xilinx/ll_temac.h b/drivers/net/ethernet/xilinx/ll_temac.h
index e338b4f..23d8dd5 100644
--- a/drivers/net/ethernet/xilinx/ll_temac.h
+++ b/drivers/net/ethernet/xilinx/ll_temac.h
@@ -347,8 +347,10 @@ struct temac_local {
 #ifdef CONFIG_PPC_DCR
 	dcr_host_t sdma_dcrs;
 #endif
-	u32 (*dma_in)(struct temac_local *, int);
-	void (*dma_out)(struct temac_local *, int, u32);
+	u32 (*temac_ior)(struct temac_local *lp, int offset);
+	void (*temac_iow)(struct temac_local *lp, int offset, u32 value);
+	u32 (*dma_in)(struct temac_local *lp, int reg);
+	void (*dma_out)(struct temac_local *lp, int reg, u32 value);
 
 	int tx_irq;
 	int rx_irq;
@@ -372,9 +374,11 @@ struct temac_local {
 	int rx_bd_ci;
 };
 
+/* Wrappers for temac_ior()/temac_iow() function pointers above */
+#define temac_ior(lp, o) ((lp)->temac_ior(lp, o))
+#define temac_iow(lp, o, v) ((lp)->temac_iow(lp, o, v))
+
 /* xilinx_temac.c */
-u32 temac_ior(struct temac_local *lp, int offset);
-void temac_iow(struct temac_local *lp, int offset, u32 value);
 int temac_indirect_busywait(struct temac_local *lp);
 u32 temac_indirect_in32(struct temac_local *lp, int reg);
 void temac_indirect_out32(struct temac_local *lp, int reg, u32 value);
diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index a365bfd..9c1fb9b 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -63,14 +63,24 @@
  * Low level register access functions
  */
 
-u32 temac_ior(struct temac_local *lp, int offset)
+u32 _temac_ior_be(struct temac_local *lp, int offset)
 {
-	return in_be32(lp->regs + offset);
+	return ioread32be(lp->regs + offset);
 }
 
-void temac_iow(struct temac_local *lp, int offset, u32 value)
+void _temac_iow_be(struct temac_local *lp, int offset, u32 value)
 {
-	out_be32(lp->regs + offset, value);
+	return iowrite32be(value, lp->regs + offset);
+}
+
+u32 _temac_ior_le(struct temac_local *lp, int offset)
+{
+	return ioread32(lp->regs + offset);
+}
+
+void _temac_iow_le(struct temac_local *lp, int offset, u32 value)
+{
+	return iowrite32(value, lp->regs + offset);
 }
 
 int temac_indirect_busywait(struct temac_local *lp)
@@ -121,23 +131,35 @@ void temac_indirect_out32(struct temac_local *lp, int reg, u32 value)
 }
 
 /**
- * temac_dma_in32 - Memory mapped DMA read, this function expects a
- * register input that is based on DCR word addresses which
- * are then converted to memory mapped byte addresses
+ * temac_dma_in32_* - Memory mapped DMA read, these function expects a
+ * register input that is based on DCR word addresses which are then
+ * converted to memory mapped byte addresses.  To be assigned to
+ * lp->dma_in32.
  */
-static u32 temac_dma_in32(struct temac_local *lp, int reg)
+static u32 temac_dma_in32_be(struct temac_local *lp, int reg)
 {
-	return in_be32(lp->sdma_regs + (reg << 2));
+	return ioread32be(lp->sdma_regs + (reg << 2));
+}
+
+static u32 temac_dma_in32_le(struct temac_local *lp, int reg)
+{
+	return ioread32(lp->sdma_regs + (reg << 2));
 }
 
 /**
- * temac_dma_out32 - Memory mapped DMA read, this function expects a
- * register input that is based on DCR word addresses which
- * are then converted to memory mapped byte addresses
+ * temac_dma_out32_* - Memory mapped DMA read, these function expects
+ * a register input that is based on DCR word addresses which are then
+ * converted to memory mapped byte addresses.  To be assigned to
+ * lp->dma_out32.
  */
-static void temac_dma_out32(struct temac_local *lp, int reg, u32 value)
+static void temac_dma_out32_be(struct temac_local *lp, int reg, u32 value)
+{
+	iowrite32be(value, lp->sdma_regs + (reg << 2));
+}
+
+static void temac_dma_out32_le(struct temac_local *lp, int reg, u32 value)
 {
-	out_be32(lp->sdma_regs + (reg << 2), value);
+	iowrite32(value, lp->sdma_regs + (reg << 2));
 }
 
 /* DMA register access functions can be DCR based or memory mapped.
@@ -1024,6 +1046,7 @@ static int temac_probe(struct platform_device *pdev)
 	struct resource *res;
 	const void *addr;
 	__be32 *p;
+	bool little_endian;
 	int rc = 0;
 
 	/* Init network device structure */
@@ -1068,6 +1091,24 @@ static int temac_probe(struct platform_device *pdev)
 		return PTR_ERR(lp->regs);
 	}
 
+	/* Select register access functions with the specified
+	 * endianness mode.  Default for OF devices is big-endian.
+	 */
+	little_endian = false;
+	if (temac_np) {
+		if (of_get_property(temac_np, "little-endian", NULL))
+			little_endian = true;
+	} else if (pdata) {
+		little_endian = pdata->reg_little_endian;
+	}
+	if (little_endian) {
+		lp->temac_ior = _temac_ior_le;
+		lp->temac_iow = _temac_iow_le;
+	} else {
+		lp->temac_ior = _temac_ior_be;
+		lp->temac_iow = _temac_iow_be;
+	}
+
 	/* Setup checksum offload, but default to off if not specified */
 	lp->temac_features = 0;
 	if (temac_np) {
@@ -1111,8 +1152,13 @@ static int temac_probe(struct platform_device *pdev)
 				of_node_put(dma_np);
 				return PTR_ERR(lp->sdma_regs);
 			}
-			lp->dma_in = temac_dma_in32;
-			lp->dma_out = temac_dma_out32;
+			if (of_get_property(dma_np, "little-endian", NULL)) {
+				lp->dma_in = temac_dma_in32_le;
+				lp->dma_out = temac_dma_out32_le;
+			} else {
+				lp->dma_in = temac_dma_in32_be;
+				lp->dma_out = temac_dma_out32_be;
+			}
 			dev_dbg(&pdev->dev, "MEM base: %p\n", lp->sdma_regs);
 		}
 
@@ -1132,8 +1178,13 @@ static int temac_probe(struct platform_device *pdev)
 				"could not map DMA registers\n");
 			return PTR_ERR(lp->sdma_regs);
 		}
-		lp->dma_in = temac_dma_in32;
-		lp->dma_out = temac_dma_out32;
+		if (pdata->dma_little_endian) {
+			lp->dma_in = temac_dma_in32_le;
+			lp->dma_out = temac_dma_out32_le;
+		} else {
+			lp->dma_in = temac_dma_in32_be;
+			lp->dma_out = temac_dma_out32_be;
+		}
 
 		/* Get DMA RX and TX interrupts */
 		lp->rx_irq = platform_get_irq(pdev, 0);
diff --git a/include/linux/xilinx_ll_temac.h b/include/linux/xilinx_ll_temac.h
index 44d7dd6..53f9203 100644
--- a/include/linux/xilinx_ll_temac.h
+++ b/include/linux/xilinx_ll_temac.h
@@ -13,6 +13,8 @@ struct ll_temac_platform_data {
 	unsigned long long mdio_bus_id; /* Unique id for MDIO bus */
 	int phy_addr;		/* Address of the PHY to connect to */
 	phy_interface_t phy_interface; /* PHY interface mode */
+	bool reg_little_endian;	/* Little endian TEMAC register access  */
+	bool dma_little_endian;	/* Little endian DMA register access  */
 };
 
 #endif /* __LINUX_XILINX_LL_TEMAC_H */
-- 
2.4.11


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

* [PATCH 05/12] net: ll_temac: Fix support for little-endian platforms
  2019-04-26  7:32 [PATCH 00/12] net: ll_temac: x86_64 support Esben Haabendal
                   ` (3 preceding siblings ...)
  2019-04-26  7:32 ` [PATCH 04/12] net: ll_temac: Add support for non-native register endianness Esben Haabendal
@ 2019-04-26  7:32 ` Esben Haabendal
  2019-04-26  7:32 ` [PATCH 06/12] net: ll_temac: Allow use on x86 platforms Esben Haabendal
                   ` (7 subsequent siblings)
  12 siblings, 0 replies; 59+ messages in thread
From: Esben Haabendal @ 2019-04-26  7:32 UTC (permalink / raw)
  To: netdev
  Cc: David S. Miller, Michal Simek, Yang Wei, Luis Chamberlain,
	YueHaibing, linux-arm-kernel, linux-kernel

Both TEMAC and SDMA is big-endian, so make sure that all values in SDMA
buffer descriptors (cmdac_bd) are handled as big-endian, independent of the
host endianness. With all currently supported platforms being big-endian,
this change does not make a change for any of them.

Note, when using app3 and app4 for piggybacking skb pointers there is no
need to care about endianness, as neither TEMAC nor SDMA access app3 and
app4 in TX buffer descriptors.

Signed-off-by: Esben Haabendal <esben@geanix.com>
---
 drivers/net/ethernet/xilinx/ll_temac_main.c | 90 ++++++++++++++++-------------
 1 file changed, 51 insertions(+), 39 deletions(-)

diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index 9c1fb9b..817bc57 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -258,6 +258,7 @@ static int temac_dma_bd_init(struct net_device *ndev)
 {
 	struct temac_local *lp = netdev_priv(ndev);
 	struct sk_buff *skb;
+	dma_addr_t skb_dma_addr;
 	int i;
 
 	lp->rx_skb = devm_kcalloc(&ndev->dev, RX_BD_NUM, sizeof(*lp->rx_skb),
@@ -280,13 +281,15 @@ static int temac_dma_bd_init(struct net_device *ndev)
 		goto out;
 
 	for (i = 0; i < TX_BD_NUM; i++) {
-		lp->tx_bd_v[i].next = lp->tx_bd_p +
-				sizeof(*lp->tx_bd_v) * ((i + 1) % TX_BD_NUM);
+		lp->tx_bd_v[i].next = cpu_to_be32(
+			lp->tx_bd_p
+			+ sizeof(*lp->tx_bd_v) * ((i + 1) % TX_BD_NUM));
 	}
 
 	for (i = 0; i < RX_BD_NUM; i++) {
-		lp->rx_bd_v[i].next = lp->rx_bd_p +
-				sizeof(*lp->rx_bd_v) * ((i + 1) % RX_BD_NUM);
+		lp->rx_bd_v[i].next = cpu_to_be32(
+			lp->rx_bd_p
+			+ sizeof(*lp->rx_bd_v) * ((i + 1) % RX_BD_NUM));
 
 		skb = netdev_alloc_skb_ip_align(ndev,
 						XTE_MAX_JUMBO_FRAME_SIZE);
@@ -295,12 +298,12 @@ static int temac_dma_bd_init(struct net_device *ndev)
 
 		lp->rx_skb[i] = skb;
 		/* returns physical address of skb->data */
-		lp->rx_bd_v[i].phys = dma_map_single(ndev->dev.parent,
-						     skb->data,
-						     XTE_MAX_JUMBO_FRAME_SIZE,
-						     DMA_FROM_DEVICE);
-		lp->rx_bd_v[i].len = XTE_MAX_JUMBO_FRAME_SIZE;
-		lp->rx_bd_v[i].app0 = STS_CTRL_APP0_IRQONEND;
+		skb_dma_addr = dma_map_single(ndev->dev.parent, skb->data,
+					      XTE_MAX_JUMBO_FRAME_SIZE,
+					      DMA_FROM_DEVICE);
+		lp->rx_bd_v[i].phys = cpu_to_be32(skb_dma_addr);
+		lp->rx_bd_v[i].len = cpu_to_be32(XTE_MAX_JUMBO_FRAME_SIZE);
+		lp->rx_bd_v[i].app0 = cpu_to_be32(STS_CTRL_APP0_IRQONEND);
 	}
 
 	lp->dma_out(lp, TX_CHNL_CTRL, 0x10220400 |
@@ -676,11 +679,11 @@ static void temac_start_xmit_done(struct net_device *ndev)
 	struct sk_buff *skb;
 
 	cur_p = &lp->tx_bd_v[lp->tx_bd_ci];
-	stat = cur_p->app0;
+	stat = be32_to_cpu(cur_p->app0);
 
 	while (stat & STS_CTRL_APP0_CMPLT) {
-		dma_unmap_single(ndev->dev.parent, cur_p->phys, cur_p->len,
-				 DMA_TO_DEVICE);
+		dma_unmap_single(ndev->dev.parent, be32_to_cpu(cur_p->phys),
+				 be32_to_cpu(cur_p->len), DMA_TO_DEVICE);
 		skb = (struct sk_buff *)ptr_from_txbd(cur_p);
 		if (skb)
 			dev_consume_skb_irq(skb);
@@ -691,14 +694,14 @@ static void temac_start_xmit_done(struct net_device *ndev)
 		cur_p->app4 = 0;
 
 		ndev->stats.tx_packets++;
-		ndev->stats.tx_bytes += cur_p->len;
+		ndev->stats.tx_bytes += be32_to_cpu(cur_p->len);
 
 		lp->tx_bd_ci++;
 		if (lp->tx_bd_ci >= TX_BD_NUM)
 			lp->tx_bd_ci = 0;
 
 		cur_p = &lp->tx_bd_v[lp->tx_bd_ci];
-		stat = cur_p->app0;
+		stat = be32_to_cpu(cur_p->app0);
 	}
 
 	netif_wake_queue(ndev);
@@ -732,7 +735,7 @@ temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 {
 	struct temac_local *lp = netdev_priv(ndev);
 	struct cdmac_bd *cur_p;
-	dma_addr_t start_p, tail_p;
+	dma_addr_t start_p, tail_p, skb_dma_addr;
 	int ii;
 	unsigned long num_frag;
 	skb_frag_t *frag;
@@ -753,15 +756,17 @@ temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 		unsigned int csum_start_off = skb_checksum_start_offset(skb);
 		unsigned int csum_index_off = csum_start_off + skb->csum_offset;
 
-		cur_p->app0 |= 1; /* TX Checksum Enabled */
-		cur_p->app1 = (csum_start_off << 16) | csum_index_off;
+		cur_p->app0 |= cpu_to_be32(0x000001); /* TX Checksum Enabled */
+		cur_p->app1 = cpu_to_be32((csum_start_off << 16)
+					  | csum_index_off);
 		cur_p->app2 = 0;  /* initial checksum seed */
 	}
 
-	cur_p->app0 |= STS_CTRL_APP0_SOP;
-	cur_p->len = skb_headlen(skb);
-	cur_p->phys = dma_map_single(ndev->dev.parent, skb->data,
-				     skb_headlen(skb), DMA_TO_DEVICE);
+	cur_p->app0 |= cpu_to_be32(STS_CTRL_APP0_SOP);
+	skb_dma_addr = dma_map_single(ndev->dev.parent, skb->data,
+				      skb_headlen(skb), DMA_TO_DEVICE);
+	cur_p->len = cpu_to_be32(skb_headlen(skb));
+	cur_p->phys = cpu_to_be32(skb_dma_addr);
 	ptr_to_txbd((void *)skb, cur_p);
 
 	for (ii = 0; ii < num_frag; ii++) {
@@ -770,14 +775,15 @@ temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 			lp->tx_bd_tail = 0;
 
 		cur_p = &lp->tx_bd_v[lp->tx_bd_tail];
-		cur_p->phys = dma_map_single(ndev->dev.parent,
-					     skb_frag_address(frag),
-					     skb_frag_size(frag), DMA_TO_DEVICE);
-		cur_p->len = skb_frag_size(frag);
+		skb_dma_addr = dma_map_single(
+			ndev->dev.parent, skb_frag_address(frag),
+			skb_frag_size(frag), DMA_TO_DEVICE);
+		cur_p->phys = cpu_to_be32(skb_dma_addr);
+		cur_p->len = cpu_to_be32(skb_frag_size(frag));
 		cur_p->app0 = 0;
 		frag++;
 	}
-	cur_p->app0 |= STS_CTRL_APP0_EOP;
+	cur_p->app0 |= cpu_to_be32(STS_CTRL_APP0_EOP);
 
 	tail_p = lp->tx_bd_p + sizeof(*lp->tx_bd_v) * lp->tx_bd_tail;
 	lp->tx_bd_tail++;
@@ -799,7 +805,7 @@ static void ll_temac_recv(struct net_device *ndev)
 	struct sk_buff *skb, *new_skb;
 	unsigned int bdstat;
 	struct cdmac_bd *cur_p;
-	dma_addr_t tail_p;
+	dma_addr_t tail_p, skb_dma_addr;
 	int length;
 	unsigned long flags;
 
@@ -808,14 +814,14 @@ static void ll_temac_recv(struct net_device *ndev)
 	tail_p = lp->rx_bd_p + sizeof(*lp->rx_bd_v) * lp->rx_bd_ci;
 	cur_p = &lp->rx_bd_v[lp->rx_bd_ci];
 
-	bdstat = cur_p->app0;
+	bdstat = be32_to_cpu(cur_p->app0);
 	while ((bdstat & STS_CTRL_APP0_CMPLT)) {
 
 		skb = lp->rx_skb[lp->rx_bd_ci];
-		length = cur_p->app4 & 0x3FFF;
+		length = be32_to_cpu(cur_p->app4) & 0x3FFF;
 
-		dma_unmap_single(ndev->dev.parent, cur_p->phys, length,
-				 DMA_FROM_DEVICE);
+		dma_unmap_single(ndev->dev.parent, be32_to_cpu(cur_p->phys),
+				 length, DMA_FROM_DEVICE);
 
 		skb_put(skb, length);
 		skb->protocol = eth_type_trans(skb, ndev);
@@ -826,7 +832,12 @@ static void ll_temac_recv(struct net_device *ndev)
 		    (skb->protocol == htons(ETH_P_IP)) &&
 		    (skb->len > 64)) {
 
-			skb->csum = cur_p->app3 & 0xFFFF;
+			/* Convert from device endianness (be32) to cpu
+			 * endiannes, and if necessary swap the bytes
+			 * (back) for proper IP checksum byte order
+			 * (be16).
+			 */
+			skb->csum = htons(be32_to_cpu(cur_p->app3) & 0xFFFF);
 			skb->ip_summed = CHECKSUM_COMPLETE;
 		}
 
@@ -843,11 +854,12 @@ static void ll_temac_recv(struct net_device *ndev)
 			return;
 		}
 
-		cur_p->app0 = STS_CTRL_APP0_IRQONEND;
-		cur_p->phys = dma_map_single(ndev->dev.parent, new_skb->data,
-					     XTE_MAX_JUMBO_FRAME_SIZE,
-					     DMA_FROM_DEVICE);
-		cur_p->len = XTE_MAX_JUMBO_FRAME_SIZE;
+		cur_p->app0 = cpu_to_be32(STS_CTRL_APP0_IRQONEND);
+		skb_dma_addr = dma_map_single(ndev->dev.parent, new_skb->data,
+					      XTE_MAX_JUMBO_FRAME_SIZE,
+					      DMA_FROM_DEVICE);
+		cur_p->phys = cpu_to_be32(skb_dma_addr);
+		cur_p->len = cpu_to_be32(XTE_MAX_JUMBO_FRAME_SIZE);
 		lp->rx_skb[lp->rx_bd_ci] = new_skb;
 
 		lp->rx_bd_ci++;
@@ -855,7 +867,7 @@ static void ll_temac_recv(struct net_device *ndev)
 			lp->rx_bd_ci = 0;
 
 		cur_p = &lp->rx_bd_v[lp->rx_bd_ci];
-		bdstat = cur_p->app0;
+		bdstat = be32_to_cpu(cur_p->app0);
 	}
 	lp->dma_out(lp, RX_TAILDESC_PTR, tail_p);
 
-- 
2.4.11


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

* [PATCH 06/12] net: ll_temac: Allow use on x86 platforms
  2019-04-26  7:32 [PATCH 00/12] net: ll_temac: x86_64 support Esben Haabendal
                   ` (4 preceding siblings ...)
  2019-04-26  7:32 ` [PATCH 05/12] net: ll_temac: Fix support for little-endian platforms Esben Haabendal
@ 2019-04-26  7:32 ` Esben Haabendal
  2019-04-26 14:05   ` Andrew Lunn
  2019-04-26  7:32 ` [PATCH 07/12] net: ll_temac: Support indirect_mutex share within TEMAC IP Esben Haabendal
                   ` (6 subsequent siblings)
  12 siblings, 1 reply; 59+ messages in thread
From: Esben Haabendal @ 2019-04-26  7:32 UTC (permalink / raw)
  To: netdev; +Cc: David S. Miller, Michal Simek, linux-arm-kernel, linux-kernel

With little-endian and 64-bit support in place, the ll_temac driver can
now be used on x86 and x86_64 platforms.

Signed-off-by: Esben Haabendal <esben@geanix.com>
---
 drivers/net/ethernet/xilinx/Kconfig | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/xilinx/Kconfig b/drivers/net/ethernet/xilinx/Kconfig
index 6d68c8a..6f858f6 100644
--- a/drivers/net/ethernet/xilinx/Kconfig
+++ b/drivers/net/ethernet/xilinx/Kconfig
@@ -5,7 +5,7 @@
 config NET_VENDOR_XILINX
 	bool "Xilinx devices"
 	default y
-	depends on PPC || PPC32 || MICROBLAZE || ARCH_ZYNQ || MIPS
+	depends on PPC || PPC32 || MICROBLAZE || ARCH_ZYNQ || MIPS || X86
 	---help---
 	  If you have a network (Ethernet) card belonging to this class, say Y.
 
@@ -33,7 +33,7 @@ config XILINX_AXI_EMAC
 
 config XILINX_LL_TEMAC
 	tristate "Xilinx LL TEMAC (LocalLink Tri-mode Ethernet MAC) driver"
-	depends on (PPC || MICROBLAZE)
+	depends on PPC || MICROBLAZE || X86
 	select PHYLIB
 	---help---
 	  This driver supports the Xilinx 10/100/1000 LocalLink TEMAC
-- 
2.4.11


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

* [PATCH 07/12] net: ll_temac: Support indirect_mutex share within TEMAC IP
  2019-04-26  7:32 [PATCH 00/12] net: ll_temac: x86_64 support Esben Haabendal
                   ` (5 preceding siblings ...)
  2019-04-26  7:32 ` [PATCH 06/12] net: ll_temac: Allow use on x86 platforms Esben Haabendal
@ 2019-04-26  7:32 ` Esben Haabendal
  2019-04-26 14:14   ` Andrew Lunn
  2019-04-26  7:32 ` [PATCH 08/12] net: ll_temac: Fix iommu/swiotlb leak Esben Haabendal
                   ` (5 subsequent siblings)
  12 siblings, 1 reply; 59+ messages in thread
From: Esben Haabendal @ 2019-04-26  7:32 UTC (permalink / raw)
  To: netdev
  Cc: David S. Miller, Michal Simek, YueHaibing, Yang Wei,
	Luis Chamberlain, linux-arm-kernel, linux-kernel

Indirect register access goes through a DCR bus bridge, which
allows only one outstanding transaction.  And to make matters
worse, each TEMAC IP block contains two Ethernet interfaces, and
although they seem to have separate registers for indirect access,
they actually share the registers.  Or to be more specific, MSW, LSW
and CTL registers are physically shared between Ethernet interfaces
in same TEMAC IP, with RDY register being (almost) specificic to
the Ethernet interface.  The 0x10000 bit in RDY reflects combined
bus ready state though.

So we need to take care to synchronize not only within a single
device, but also between devices in same TEMAC IP.

This commit allows to do that with legacy platform devices.

For OF devices, the xlnx,compound parent of the temac node should be
used to find siblings, and setup a shared indirect_mutex between them.
I will leave this work to somebody else, as I don't have hardware to
test that.  No regression is introduced by that, as before this commit
using two Ethernet interfaces in same TEMAC block is simply broken.

Signed-off-by: Esben Haabendal <esben@geanix.com>
---
 drivers/net/ethernet/xilinx/ll_temac.h      |  5 ++++-
 drivers/net/ethernet/xilinx/ll_temac_main.c | 30 ++++++++++++++++++-----------
 drivers/net/ethernet/xilinx/ll_temac_mdio.c | 16 +++++++--------
 include/linux/xilinx_ll_temac.h             |  6 ++++++
 4 files changed, 37 insertions(+), 20 deletions(-)

diff --git a/drivers/net/ethernet/xilinx/ll_temac.h b/drivers/net/ethernet/xilinx/ll_temac.h
index 23d8dd5..990f9ed 100644
--- a/drivers/net/ethernet/xilinx/ll_temac.h
+++ b/drivers/net/ethernet/xilinx/ll_temac.h
@@ -358,7 +358,10 @@ struct temac_local {
 
 	struct sk_buff **rx_skb;
 	spinlock_t rx_lock;
-	struct mutex indirect_mutex;
+	/* For synchronization of indirect register access.  Must be
+	 * shared mutex between interfaces in same TEMAC block.
+	 */
+	struct mutex *indirect_mutex;
 	u32 options;			/* Current options word */
 	int last_link;
 	unsigned int temac_features;
diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index 817bc57..309f149 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -346,7 +346,7 @@ static void temac_do_set_mac_address(struct net_device *ndev)
 	struct temac_local *lp = netdev_priv(ndev);
 
 	/* set up unicast MAC address filter set its mac address */
-	mutex_lock(&lp->indirect_mutex);
+	mutex_lock(lp->indirect_mutex);
 	temac_indirect_out32(lp, XTE_UAW0_OFFSET,
 			     (ndev->dev_addr[0]) |
 			     (ndev->dev_addr[1] << 8) |
@@ -357,7 +357,7 @@ static void temac_do_set_mac_address(struct net_device *ndev)
 	temac_indirect_out32(lp, XTE_UAW1_OFFSET,
 			     (ndev->dev_addr[4] & 0x000000ff) |
 			     (ndev->dev_addr[5] << 8));
-	mutex_unlock(&lp->indirect_mutex);
+	mutex_unlock(lp->indirect_mutex);
 }
 
 static int temac_init_mac_address(struct net_device *ndev, const void *address)
@@ -386,7 +386,7 @@ static void temac_set_multicast_list(struct net_device *ndev)
 	u32 multi_addr_msw, multi_addr_lsw, val;
 	int i;
 
-	mutex_lock(&lp->indirect_mutex);
+	mutex_lock(lp->indirect_mutex);
 	if (ndev->flags & (IFF_ALLMULTI | IFF_PROMISC) ||
 	    netdev_mc_count(ndev) > MULTICAST_CAM_TABLE_NUM) {
 		/*
@@ -425,7 +425,7 @@ static void temac_set_multicast_list(struct net_device *ndev)
 		temac_indirect_out32(lp, XTE_MAW1_OFFSET, 0);
 		dev_info(&ndev->dev, "Promiscuous mode disabled.\n");
 	}
-	mutex_unlock(&lp->indirect_mutex);
+	mutex_unlock(lp->indirect_mutex);
 }
 
 static struct temac_option {
@@ -517,7 +517,7 @@ static u32 temac_setoptions(struct net_device *ndev, u32 options)
 	struct temac_option *tp = &temac_options[0];
 	int reg;
 
-	mutex_lock(&lp->indirect_mutex);
+	mutex_lock(lp->indirect_mutex);
 	while (tp->opt) {
 		reg = temac_indirect_in32(lp, tp->reg) & ~tp->m_or;
 		if (options & tp->opt)
@@ -526,7 +526,7 @@ static u32 temac_setoptions(struct net_device *ndev, u32 options)
 		tp++;
 	}
 	lp->options |= options;
-	mutex_unlock(&lp->indirect_mutex);
+	mutex_unlock(lp->indirect_mutex);
 
 	return 0;
 }
@@ -545,7 +545,7 @@ static void temac_device_reset(struct net_device *ndev)
 
 	dev_dbg(&ndev->dev, "%s()\n", __func__);
 
-	mutex_lock(&lp->indirect_mutex);
+	mutex_lock(lp->indirect_mutex);
 	/* Reset the receiver and wait for it to finish reset */
 	temac_indirect_out32(lp, XTE_RXC1_OFFSET, XTE_RXC1_RXRST_MASK);
 	timeout = 1000;
@@ -597,7 +597,7 @@ static void temac_device_reset(struct net_device *ndev)
 	temac_indirect_out32(lp, XTE_TXC_OFFSET, 0);
 	temac_indirect_out32(lp, XTE_FCC_OFFSET, XTE_FCC_RXFLO_MASK);
 
-	mutex_unlock(&lp->indirect_mutex);
+	mutex_unlock(lp->indirect_mutex);
 
 	/* Sync default options with HW
 	 * but leave receiver and transmitter disabled.  */
@@ -625,7 +625,7 @@ static void temac_adjust_link(struct net_device *ndev)
 	/* hash together the state values to decide if something has changed */
 	link_state = phy->speed | (phy->duplex << 1) | phy->link;
 
-	mutex_lock(&lp->indirect_mutex);
+	mutex_lock(lp->indirect_mutex);
 	if (lp->last_link != link_state) {
 		mii_speed = temac_indirect_in32(lp, XTE_EMCFG_OFFSET);
 		mii_speed &= ~XTE_EMCFG_LINKSPD_MASK;
@@ -641,7 +641,7 @@ static void temac_adjust_link(struct net_device *ndev)
 		lp->last_link = link_state;
 		phy_print_status(phy);
 	}
-	mutex_unlock(&lp->indirect_mutex);
+	mutex_unlock(lp->indirect_mutex);
 }
 
 #ifdef CONFIG_64BIT
@@ -1092,7 +1092,15 @@ static int temac_probe(struct platform_device *pdev)
 	lp->dev = &pdev->dev;
 	lp->options = XTE_OPTION_DEFAULTS;
 	spin_lock_init(&lp->rx_lock);
-	mutex_init(&lp->indirect_mutex);
+
+	/* Setup mutex for synchronization of indirect register access */
+	if (pdata && pdata->indirect_mutex) {
+		lp->indirect_mutex = pdata->indirect_mutex;
+	} else {
+		lp->indirect_mutex = devm_kmalloc(
+			&pdev->dev, sizeof(*lp->indirect_mutex), GFP_KERNEL);
+		mutex_init(lp->indirect_mutex);
+	}
 
 	/* map device registers */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
diff --git a/drivers/net/ethernet/xilinx/ll_temac_mdio.c b/drivers/net/ethernet/xilinx/ll_temac_mdio.c
index 61b832f..c8707f1 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_mdio.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_mdio.c
@@ -29,10 +29,10 @@ static int temac_mdio_read(struct mii_bus *bus, int phy_id, int reg)
 	/* Write the PHY address to the MIIM Access Initiator register.
 	 * When the transfer completes, the PHY register value will appear
 	 * in the LSW0 register */
-	mutex_lock(&lp->indirect_mutex);
+	mutex_lock(lp->indirect_mutex);
 	temac_iow(lp, XTE_LSW0_OFFSET, (phy_id << 5) | reg);
 	rc = temac_indirect_in32(lp, XTE_MIIMAI_OFFSET);
-	mutex_unlock(&lp->indirect_mutex);
+	mutex_unlock(lp->indirect_mutex);
 
 	dev_dbg(lp->dev, "temac_mdio_read(phy_id=%i, reg=%x) == %x\n",
 		phy_id, reg, rc);
@@ -50,10 +50,10 @@ static int temac_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 val)
 	/* First write the desired value into the write data register
 	 * and then write the address into the access initiator register
 	 */
-	mutex_lock(&lp->indirect_mutex);
+	mutex_lock(lp->indirect_mutex);
 	temac_indirect_out32(lp, XTE_MGTDR_OFFSET, val);
 	temac_indirect_out32(lp, XTE_MIIMAI_OFFSET, (phy_id << 5) | reg);
-	mutex_unlock(&lp->indirect_mutex);
+	mutex_unlock(lp->indirect_mutex);
 
 	return 0;
 }
@@ -87,9 +87,9 @@ int temac_mdio_setup(struct temac_local *lp, struct platform_device *pdev)
 
 	/* Enable the MDIO bus by asserting the enable bit and writing
 	 * in the clock config */
-	mutex_lock(&lp->indirect_mutex);
+	mutex_lock(lp->indirect_mutex);
 	temac_indirect_out32(lp, XTE_MC_OFFSET, 1 << 6 | clk_div);
-	mutex_unlock(&lp->indirect_mutex);
+	mutex_unlock(lp->indirect_mutex);
 
 	bus = devm_mdiobus_alloc(&pdev->dev);
 	if (!bus)
@@ -116,10 +116,10 @@ int temac_mdio_setup(struct temac_local *lp, struct platform_device *pdev)
 	if (rc)
 		return rc;
 
-	mutex_lock(&lp->indirect_mutex);
+	mutex_lock(lp->indirect_mutex);
 	dev_dbg(lp->dev, "MDIO bus registered;  MC:%x\n",
 		temac_indirect_in32(lp, XTE_MC_OFFSET));
-	mutex_unlock(&lp->indirect_mutex);
+	mutex_unlock(lp->indirect_mutex);
 	return 0;
 }
 
diff --git a/include/linux/xilinx_ll_temac.h b/include/linux/xilinx_ll_temac.h
index 53f9203..c4c66be 100644
--- a/include/linux/xilinx_ll_temac.h
+++ b/include/linux/xilinx_ll_temac.h
@@ -15,6 +15,12 @@ struct ll_temac_platform_data {
 	phy_interface_t phy_interface; /* PHY interface mode */
 	bool reg_little_endian;	/* Little endian TEMAC register access  */
 	bool dma_little_endian;	/* Little endian DMA register access  */
+	/* Pre-initialized mutex to use for synchronizing indirect
+	 * register access.  When using both interfaces of a single
+	 * TEMAC IP block, the same mutex should be passed here, as
+	 * they share the same DCR bus bridge.
+	 */
+	struct mutex *indirect_mutex;
 };
 
 #endif /* __LINUX_XILINX_LL_TEMAC_H */
-- 
2.4.11


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

* [PATCH 08/12] net: ll_temac: Fix iommu/swiotlb leak
  2019-04-26  7:32 [PATCH 00/12] net: ll_temac: x86_64 support Esben Haabendal
                   ` (6 preceding siblings ...)
  2019-04-26  7:32 ` [PATCH 07/12] net: ll_temac: Support indirect_mutex share within TEMAC IP Esben Haabendal
@ 2019-04-26  7:32 ` Esben Haabendal
  2019-04-26 14:21   ` Andrew Lunn
  2019-04-26  7:32 ` [PATCH 09/12] net: ll_temac: Fix bug causing buffer descriptor overrun Esben Haabendal
                   ` (4 subsequent siblings)
  12 siblings, 1 reply; 59+ messages in thread
From: Esben Haabendal @ 2019-04-26  7:32 UTC (permalink / raw)
  To: netdev
  Cc: David S. Miller, Michal Simek, Luis Chamberlain, YueHaibing,
	Yang Wei, linux-arm-kernel, linux-kernel

Unmap the actual buffer length, not the amount of data received.

Signed-off-by: Esben Haabendal <esben@geanix.com>
---
 drivers/net/ethernet/xilinx/ll_temac_main.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index 309f149..56d8077 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -821,7 +821,7 @@ static void ll_temac_recv(struct net_device *ndev)
 		length = be32_to_cpu(cur_p->app4) & 0x3FFF;
 
 		dma_unmap_single(ndev->dev.parent, be32_to_cpu(cur_p->phys),
-				 length, DMA_FROM_DEVICE);
+				 XTE_MAX_JUMBO_FRAME_SIZE, DMA_FROM_DEVICE);
 
 		skb_put(skb, length);
 		skb->protocol = eth_type_trans(skb, ndev);
-- 
2.4.11


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

* [PATCH 09/12] net: ll_temac: Fix bug causing buffer descriptor overrun
  2019-04-26  7:32 [PATCH 00/12] net: ll_temac: x86_64 support Esben Haabendal
                   ` (7 preceding siblings ...)
  2019-04-26  7:32 ` [PATCH 08/12] net: ll_temac: Fix iommu/swiotlb leak Esben Haabendal
@ 2019-04-26  7:32 ` Esben Haabendal
  2019-04-26  7:32 ` [PATCH 10/12] net: ll_temac: Replace bad usage of msleep() with usleep_range() Esben Haabendal
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 59+ messages in thread
From: Esben Haabendal @ 2019-04-26  7:32 UTC (permalink / raw)
  To: netdev
  Cc: David S. Miller, Michal Simek, Luis Chamberlain, YueHaibing,
	Yang Wei, linux-arm-kernel, linux-kernel

As we are actually using a BD for both the skb and each frag contained in
it, the oldest TX BD would be overwritten when there was exactly one BD
less than needed.

Signed-off-by: Esben Haabendal <esben@geanix.com>
---
 drivers/net/ethernet/xilinx/ll_temac_main.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index 56d8077..def3886 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -745,7 +745,7 @@ temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 	start_p = lp->tx_bd_p + sizeof(*lp->tx_bd_v) * lp->tx_bd_tail;
 	cur_p = &lp->tx_bd_v[lp->tx_bd_tail];
 
-	if (temac_check_tx_bd_space(lp, num_frag)) {
+	if (temac_check_tx_bd_space(lp, num_frag + 1)) {
 		if (!netif_queue_stopped(ndev))
 			netif_stop_queue(ndev);
 		return NETDEV_TX_BUSY;
-- 
2.4.11


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

* [PATCH 10/12] net: ll_temac: Replace bad usage of msleep() with usleep_range()
  2019-04-26  7:32 [PATCH 00/12] net: ll_temac: x86_64 support Esben Haabendal
                   ` (8 preceding siblings ...)
  2019-04-26  7:32 ` [PATCH 09/12] net: ll_temac: Fix bug causing buffer descriptor overrun Esben Haabendal
@ 2019-04-26  7:32 ` Esben Haabendal
  2019-04-26 14:01   ` Andrew Lunn
  2019-04-26  7:32 ` [PATCH 11/12] net: ll_temac: Allow configuration of IRQ coalescing Esben Haabendal
                   ` (2 subsequent siblings)
  12 siblings, 1 reply; 59+ messages in thread
From: Esben Haabendal @ 2019-04-26  7:32 UTC (permalink / raw)
  To: netdev
  Cc: David S. Miller, Michal Simek, Luis Chamberlain, Yang Wei,
	YueHaibing, linux-arm-kernel, linux-kernel

Use usleep_range() to avoid problems with msleep() actually sleeping
much longer than expected.

Signed-off-by: Esben Haabendal <esben@geanix.com>
---
 drivers/net/ethernet/xilinx/ll_temac_main.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index def3886..a5ec8ba 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -92,7 +92,7 @@ int temac_indirect_busywait(struct temac_local *lp)
 			WARN_ON(1);
 			return -ETIMEDOUT;
 		}
-		msleep(1);
+		usleep_range(500, 1000);
 	}
 	return 0;
 }
-- 
2.4.11


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

* [PATCH 11/12] net: ll_temac: Allow configuration of IRQ coalescing
  2019-04-26  7:32 [PATCH 00/12] net: ll_temac: x86_64 support Esben Haabendal
                   ` (9 preceding siblings ...)
  2019-04-26  7:32 ` [PATCH 10/12] net: ll_temac: Replace bad usage of msleep() with usleep_range() Esben Haabendal
@ 2019-04-26  7:32 ` Esben Haabendal
  2019-04-26  7:32 ` [PATCH 12/12] net: ll_temac: Enable DMA when ready, not before Esben Haabendal
  2019-04-29  8:34 ` [PATCH 00/12] net: ll_temac: x86_64 support Esben Haabendal
  12 siblings, 0 replies; 59+ messages in thread
From: Esben Haabendal @ 2019-04-26  7:32 UTC (permalink / raw)
  To: netdev
  Cc: David S. Miller, Michal Simek, Yang Wei, YueHaibing,
	Luis Chamberlain, linux-arm-kernel, linux-kernel

This allows custom setup of IRQ coalescing for platforms using legacy
platform_device. The irq timeout and count parameters can be used for
tuning cpu load vs. latency.

I have maintained the 0x00000400 bit in TX_CHNL_CTRL.  It is specified as
unused in the documentation I have available.  It does not make any
difference in the hardware I have available, so it is left in to not risk
breaking other platforms where it might be used.

Signed-off-by: Esben Haabendal <esben@geanix.com>
---
 drivers/net/ethernet/xilinx/ll_temac.h      |  4 +++
 drivers/net/ethernet/xilinx/ll_temac_main.c | 40 ++++++++++++++++++++---------
 include/linux/xilinx_ll_temac.h             |  5 ++++
 3 files changed, 37 insertions(+), 12 deletions(-)

diff --git a/drivers/net/ethernet/xilinx/ll_temac.h b/drivers/net/ethernet/xilinx/ll_temac.h
index 990f9ed..1aeda08 100644
--- a/drivers/net/ethernet/xilinx/ll_temac.h
+++ b/drivers/net/ethernet/xilinx/ll_temac.h
@@ -375,6 +375,10 @@ struct temac_local {
 	int tx_bd_next;
 	int tx_bd_tail;
 	int rx_bd_ci;
+
+	/* DMA channel control setup */
+	u32 tx_chnl_ctrl;
+	u32 rx_chnl_ctrl;
 };
 
 /* Wrappers for temac_ior()/temac_iow() function pointers above */
diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index a5ec8ba..a30ac11 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -306,18 +306,15 @@ static int temac_dma_bd_init(struct net_device *ndev)
 		lp->rx_bd_v[i].app0 = cpu_to_be32(STS_CTRL_APP0_IRQONEND);
 	}
 
-	lp->dma_out(lp, TX_CHNL_CTRL, 0x10220400 |
-					  CHNL_CTRL_IRQ_EN |
-					  CHNL_CTRL_IRQ_DLY_EN |
-					  CHNL_CTRL_IRQ_COAL_EN);
-	/* 0x10220483 */
-	/* 0x00100483 */
-	lp->dma_out(lp, RX_CHNL_CTRL, 0xff070000 |
-					  CHNL_CTRL_IRQ_EN |
-					  CHNL_CTRL_IRQ_DLY_EN |
-					  CHNL_CTRL_IRQ_COAL_EN |
-					  CHNL_CTRL_IRQ_IOE);
-	/* 0xff010283 */
+	/* Configure DMA channel (irq setup) */
+	lp->dma_out(lp, TX_CHNL_CTRL, lp->tx_chnl_ctrl |
+		    0x00000400 | // Use 1 Bit Wide Counters. Currently Not Used!
+		    CHNL_CTRL_IRQ_EN | CHNL_CTRL_IRQ_ERR_EN |
+		    CHNL_CTRL_IRQ_DLY_EN | CHNL_CTRL_IRQ_COAL_EN);
+	lp->dma_out(lp, RX_CHNL_CTRL, lp->rx_chnl_ctrl |
+		    CHNL_CTRL_IRQ_IOE |
+		    CHNL_CTRL_IRQ_EN | CHNL_CTRL_IRQ_ERR_EN |
+		    CHNL_CTRL_IRQ_DLY_EN | CHNL_CTRL_IRQ_COAL_EN);
 
 	lp->dma_out(lp, RX_CURDESC_PTR,  lp->rx_bd_p);
 	lp->dma_out(lp, RX_TAILDESC_PTR,
@@ -1186,6 +1183,13 @@ static int temac_probe(struct platform_device *pdev)
 		lp->rx_irq = irq_of_parse_and_map(dma_np, 0);
 		lp->tx_irq = irq_of_parse_and_map(dma_np, 1);
 
+		/* Use defaults for IRQ delay/coalescing setup.  These
+		 * are configuration values, so does not belong in
+		 * device-tree.
+		 */
+		lp->tx_chnl_ctrl = 0x10220000;
+		lp->rx_chnl_ctrl = 0xff070000;
+
 		/* Finished with the DMA node; drop the reference */
 		of_node_put(dma_np);
 	} else if (pdata) {
@@ -1209,6 +1213,18 @@ static int temac_probe(struct platform_device *pdev)
 		/* Get DMA RX and TX interrupts */
 		lp->rx_irq = platform_get_irq(pdev, 0);
 		lp->tx_irq = platform_get_irq(pdev, 1);
+
+		/* IRQ delay/coalescing setup */
+		if (pdata->tx_irq_timeout || pdata->tx_irq_count)
+			lp->tx_chnl_ctrl = (pdata->tx_irq_timeout << 24) |
+				(pdata->tx_irq_count << 16);
+		else
+			lp->tx_chnl_ctrl = 0x10220000;
+		if (pdata->rx_irq_timeout || pdata->rx_irq_count)
+			lp->rx_chnl_ctrl = (pdata->rx_irq_timeout << 24) |
+				(pdata->rx_irq_count << 16);
+		else
+			lp->rx_chnl_ctrl = 0xff070000;
 	}
 
 	/* Error handle returned DMA RX and TX interrupts */
diff --git a/include/linux/xilinx_ll_temac.h b/include/linux/xilinx_ll_temac.h
index c4c66be..e8d4c09 100644
--- a/include/linux/xilinx_ll_temac.h
+++ b/include/linux/xilinx_ll_temac.h
@@ -21,6 +21,11 @@ struct ll_temac_platform_data {
 	 * they share the same DCR bus bridge.
 	 */
 	struct mutex *indirect_mutex;
+	/* DMA channel control setup */
+	u8 tx_irq_timeout;	/* TX Interrupt Delay Time-out */
+	u8 tx_irq_count;	/* TX Interrupt Coalescing Threshold Count */
+	u8 rx_irq_timeout;	/* RX Interrupt Delay Time-out */
+	u8 rx_irq_count;	/* RX Interrupt Coalescing Threshold Count */
 };
 
 #endif /* __LINUX_XILINX_LL_TEMAC_H */
-- 
2.4.11


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

* [PATCH 12/12] net: ll_temac: Enable DMA when ready, not before
  2019-04-26  7:32 [PATCH 00/12] net: ll_temac: x86_64 support Esben Haabendal
                   ` (10 preceding siblings ...)
  2019-04-26  7:32 ` [PATCH 11/12] net: ll_temac: Allow configuration of IRQ coalescing Esben Haabendal
@ 2019-04-26  7:32 ` Esben Haabendal
  2019-04-29  8:34 ` [PATCH 00/12] net: ll_temac: x86_64 support Esben Haabendal
  12 siblings, 0 replies; 59+ messages in thread
From: Esben Haabendal @ 2019-04-26  7:32 UTC (permalink / raw)
  To: netdev
  Cc: David S. Miller, Michal Simek, Luis Chamberlain, Yang Wei,
	YueHaibing, linux-arm-kernel, linux-kernel

As soon as TAILDESCR_PTR is written, DMA transfers might start.
Let's ensure we are ready to receive DMA IRQ's before doing that.

Signed-off-by: Esben Haabendal <esben@geanix.com>
---
 drivers/net/ethernet/xilinx/ll_temac_main.c | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index a30ac11..b8e3dbd 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -316,17 +316,21 @@ static int temac_dma_bd_init(struct net_device *ndev)
 		    CHNL_CTRL_IRQ_EN | CHNL_CTRL_IRQ_ERR_EN |
 		    CHNL_CTRL_IRQ_DLY_EN | CHNL_CTRL_IRQ_COAL_EN);
 
-	lp->dma_out(lp, RX_CURDESC_PTR,  lp->rx_bd_p);
-	lp->dma_out(lp, RX_TAILDESC_PTR,
-		       lp->rx_bd_p + (sizeof(*lp->rx_bd_v) * (RX_BD_NUM - 1)));
-	lp->dma_out(lp, TX_CURDESC_PTR, lp->tx_bd_p);
-
 	/* Init descriptor indexes */
 	lp->tx_bd_ci = 0;
 	lp->tx_bd_next = 0;
 	lp->tx_bd_tail = 0;
 	lp->rx_bd_ci = 0;
 
+	/* Enable RX DMA transfers */
+	wmb();
+	lp->dma_out(lp, RX_CURDESC_PTR,  lp->rx_bd_p);
+	lp->dma_out(lp, RX_TAILDESC_PTR,
+		       lp->rx_bd_p + (sizeof(*lp->rx_bd_v) * (RX_BD_NUM - 1)));
+
+	/* Prepare for TX DMA transfer */
+	lp->dma_out(lp, TX_CURDESC_PTR, lp->tx_bd_p);
+
 	return 0;
 
 out:
@@ -790,6 +794,7 @@ temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 	skb_tx_timestamp(skb);
 
 	/* Kick off the transfer */
+	wmb();
 	lp->dma_out(lp, TX_TAILDESC_PTR, tail_p); /* DMA start */
 
 	return NETDEV_TX_OK;
-- 
2.4.11


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

* Re: [PATCH 02/12] net: ll_temac: Extend support to non-device-tree platforms
  2019-04-26  7:32 ` [PATCH 02/12] net: ll_temac: Extend support to non-device-tree platforms Esben Haabendal
@ 2019-04-26 13:58   ` Andrew Lunn
  0 siblings, 0 replies; 59+ messages in thread
From: Andrew Lunn @ 2019-04-26 13:58 UTC (permalink / raw)
  To: Esben Haabendal
  Cc: netdev, David S. Miller, Michal Simek, Luis Chamberlain,
	YueHaibing, Yang Wei, linux-kernel, linux-arm-kernel

On Fri, Apr 26, 2019 at 09:32:21AM +0200, Esben Haabendal wrote:
> Support initialization with platdata, so the driver can be used on
> non-device-tree platforms.
> 
> For currently supported device-tree platforms, the driver should behave
> as before.
> 
> Signed-off-by: Esben Haabendal <esben@geanix.com>
> ---
>  drivers/net/ethernet/xilinx/ll_temac.h      |   3 +
>  drivers/net/ethernet/xilinx/ll_temac_main.c | 187 +++++++++++++++++++---------
>  drivers/net/ethernet/xilinx/ll_temac_mdio.c |  23 +++-
>  include/linux/xilinx_ll_temac.h             |  18 +++

Hi Esben

Please place platform data include files in include/linux/platform_data/

Thanks
	Andrew

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

* Re: [PATCH 10/12] net: ll_temac: Replace bad usage of msleep() with usleep_range()
  2019-04-26  7:32 ` [PATCH 10/12] net: ll_temac: Replace bad usage of msleep() with usleep_range() Esben Haabendal
@ 2019-04-26 14:01   ` Andrew Lunn
  0 siblings, 0 replies; 59+ messages in thread
From: Andrew Lunn @ 2019-04-26 14:01 UTC (permalink / raw)
  To: Esben Haabendal
  Cc: netdev, David S. Miller, Michal Simek, Luis Chamberlain,
	Yang Wei, YueHaibing, linux-arm-kernel, linux-kernel

On Fri, Apr 26, 2019 at 09:32:29AM +0200, Esben Haabendal wrote:
> Use usleep_range() to avoid problems with msleep() actually sleeping
> much longer than expected.
> 
> Signed-off-by: Esben Haabendal <esben@geanix.com>

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

    Andrew

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

* Re: [PATCH 06/12] net: ll_temac: Allow use on x86 platforms
  2019-04-26  7:32 ` [PATCH 06/12] net: ll_temac: Allow use on x86 platforms Esben Haabendal
@ 2019-04-26 14:05   ` Andrew Lunn
  0 siblings, 0 replies; 59+ messages in thread
From: Andrew Lunn @ 2019-04-26 14:05 UTC (permalink / raw)
  To: Esben Haabendal
  Cc: netdev, David S. Miller, Michal Simek, linux-arm-kernel, linux-kernel

On Fri, Apr 26, 2019 at 09:32:25AM +0200, Esben Haabendal wrote:
> With little-endian and 64-bit support in place, the ll_temac driver can
> now be used on x86 and x86_64 platforms.
> 
> Signed-off-by: Esben Haabendal <esben@geanix.com>
> ---
>  drivers/net/ethernet/xilinx/Kconfig | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/net/ethernet/xilinx/Kconfig b/drivers/net/ethernet/xilinx/Kconfig
> index 6d68c8a..6f858f6 100644
> --- a/drivers/net/ethernet/xilinx/Kconfig
> +++ b/drivers/net/ethernet/xilinx/Kconfig
> @@ -5,7 +5,7 @@
>  config NET_VENDOR_XILINX
>  	bool "Xilinx devices"
>  	default y
> -	depends on PPC || PPC32 || MICROBLAZE || ARCH_ZYNQ || MIPS
> +	depends on PPC || PPC32 || MICROBLAZE || ARCH_ZYNQ || MIPS || X86

Hi Esben

While you are here, maybe also add COMPILE_TEST here and to
XILINX_LL_TEMAC?

	Andrew

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

* Re: [PATCH 07/12] net: ll_temac: Support indirect_mutex share within TEMAC IP
  2019-04-26  7:32 ` [PATCH 07/12] net: ll_temac: Support indirect_mutex share within TEMAC IP Esben Haabendal
@ 2019-04-26 14:14   ` Andrew Lunn
  0 siblings, 0 replies; 59+ messages in thread
From: Andrew Lunn @ 2019-04-26 14:14 UTC (permalink / raw)
  To: Esben Haabendal
  Cc: netdev, David S. Miller, Michal Simek, YueHaibing, Yang Wei,
	Luis Chamberlain, linux-arm-kernel, linux-kernel

On Fri, Apr 26, 2019 at 09:32:26AM +0200, Esben Haabendal wrote:
> @@ -1092,7 +1092,15 @@ static int temac_probe(struct platform_device *pdev)
>  	lp->dev = &pdev->dev;
>  	lp->options = XTE_OPTION_DEFAULTS;
>  	spin_lock_init(&lp->rx_lock);
> -	mutex_init(&lp->indirect_mutex);
> +
> +	/* Setup mutex for synchronization of indirect register access */
> +	if (pdata && pdata->indirect_mutex) {
> +		lp->indirect_mutex = pdata->indirect_mutex;
> +	} else {
> +		lp->indirect_mutex = devm_kmalloc(
> +			&pdev->dev, sizeof(*lp->indirect_mutex), GFP_KERNEL);
> +		mutex_init(lp->indirect_mutex);
> +	}

Hi Esben

I would make the mutex mandatory, not optional. I think there will be
less hard to debug errors that way. You want the developer to actually
think about this mutex, should it be shared, or individual. Forcing
them to provide it means they are more likely to read the
documentation, and more likely to over share it than under share
it. That is maybe not so good for performance, but safer.

    Andrew

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

* Re: [PATCH 08/12] net: ll_temac: Fix iommu/swiotlb leak
  2019-04-26  7:32 ` [PATCH 08/12] net: ll_temac: Fix iommu/swiotlb leak Esben Haabendal
@ 2019-04-26 14:21   ` Andrew Lunn
  2019-04-26 14:43     ` Robin Murphy
  0 siblings, 1 reply; 59+ messages in thread
From: Andrew Lunn @ 2019-04-26 14:21 UTC (permalink / raw)
  To: Esben Haabendal
  Cc: netdev, David S. Miller, Michal Simek, Luis Chamberlain,
	YueHaibing, Yang Wei, linux-arm-kernel, linux-kernel

On Fri, Apr 26, 2019 at 09:32:27AM +0200, Esben Haabendal wrote:
> Unmap the actual buffer length, not the amount of data received.

Hi Esben

The patch Subject does not seem to match the content?

Also, there can be performance advantages of just unmapping the
received length. The unmap operation does a cache invalidate, which
can be expensive. Consider the effort of unmapping a 64 byte ACK vs 9K
jumbo frame?

      Andrew
 
> Signed-off-by: Esben Haabendal <esben@geanix.com>
> ---
>  drivers/net/ethernet/xilinx/ll_temac_main.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
> index 309f149..56d8077 100644
> --- a/drivers/net/ethernet/xilinx/ll_temac_main.c
> +++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
> @@ -821,7 +821,7 @@ static void ll_temac_recv(struct net_device *ndev)
>  		length = be32_to_cpu(cur_p->app4) & 0x3FFF;
>  
>  		dma_unmap_single(ndev->dev.parent, be32_to_cpu(cur_p->phys),
> -				 length, DMA_FROM_DEVICE);
> +				 XTE_MAX_JUMBO_FRAME_SIZE, DMA_FROM_DEVICE);
>  
>  		skb_put(skb, length);
>  		skb->protocol = eth_type_trans(skb, ndev);
> -- 
> 2.4.11
> 

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

* Re: [PATCH 08/12] net: ll_temac: Fix iommu/swiotlb leak
  2019-04-26 14:21   ` Andrew Lunn
@ 2019-04-26 14:43     ` Robin Murphy
  2019-04-26 15:37       ` Andrew Lunn
  0 siblings, 1 reply; 59+ messages in thread
From: Robin Murphy @ 2019-04-26 14:43 UTC (permalink / raw)
  To: Andrew Lunn, Esben Haabendal
  Cc: netdev, YueHaibing, Michal Simek, linux-kernel, Yang Wei,
	Luis Chamberlain, David S. Miller, linux-arm-kernel

On 26/04/2019 15:21, Andrew Lunn wrote:
> On Fri, Apr 26, 2019 at 09:32:27AM +0200, Esben Haabendal wrote:
>> Unmap the actual buffer length, not the amount of data received.
> 
> Hi Esben
> 
> The patch Subject does not seem to match the content?
> 
> Also, there can be performance advantages of just unmapping the
> received length. The unmap operation does a cache invalidate, which
> can be expensive. Consider the effort of unmapping a 64 byte ACK vs 9K
> jumbo frame?

If the size passed to dma_unmap_*() is not the same as was passed to the 
corresponding dma_map_*(), that is fundamentally incorrect use of the 
API and may lead to warnings, resource exhaustion, or possibly even 
corruption and crashes for some DMA API implementations.

If there's a case where you just need to look at a small part of the 
buffer right now, but can unmap the whole thing properly later. then 
dma_sync_single_*() does allow operating on partial buffers. Even 
better, if you're able to recycle buffers in your Rx pool you could 
potentially replace the unmap/map dance altogether with some careful use 
of sync_single.

Robin.

> 
>        Andrew
>   
>> Signed-off-by: Esben Haabendal <esben@geanix.com>
>> ---
>>   drivers/net/ethernet/xilinx/ll_temac_main.c | 2 +-
>>   1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
>> index 309f149..56d8077 100644
>> --- a/drivers/net/ethernet/xilinx/ll_temac_main.c
>> +++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
>> @@ -821,7 +821,7 @@ static void ll_temac_recv(struct net_device *ndev)
>>   		length = be32_to_cpu(cur_p->app4) & 0x3FFF;
>>   
>>   		dma_unmap_single(ndev->dev.parent, be32_to_cpu(cur_p->phys),
>> -				 length, DMA_FROM_DEVICE);
>> +				 XTE_MAX_JUMBO_FRAME_SIZE, DMA_FROM_DEVICE);
>>   
>>   		skb_put(skb, length);
>>   		skb->protocol = eth_type_trans(skb, ndev);
>> -- 
>> 2.4.11
>>
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> 

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

* Re: [PATCH 08/12] net: ll_temac: Fix iommu/swiotlb leak
  2019-04-26 14:43     ` Robin Murphy
@ 2019-04-26 15:37       ` Andrew Lunn
  0 siblings, 0 replies; 59+ messages in thread
From: Andrew Lunn @ 2019-04-26 15:37 UTC (permalink / raw)
  To: Robin Murphy
  Cc: Esben Haabendal, netdev, YueHaibing, Michal Simek, linux-kernel,
	Yang Wei, Luis Chamberlain, David S. Miller, linux-arm-kernel

On Fri, Apr 26, 2019 at 03:43:20PM +0100, Robin Murphy wrote:
> On 26/04/2019 15:21, Andrew Lunn wrote:
> >On Fri, Apr 26, 2019 at 09:32:27AM +0200, Esben Haabendal wrote:
> >>Unmap the actual buffer length, not the amount of data received.
> >
> >Hi Esben
> >
> >The patch Subject does not seem to match the content?
> >
> >Also, there can be performance advantages of just unmapping the
> >received length. The unmap operation does a cache invalidate, which
> >can be expensive. Consider the effort of unmapping a 64 byte ACK vs 9K
> >jumbo frame?
> 
> If the size passed to dma_unmap_*() is not the same as was passed to the
> corresponding dma_map_*(), that is fundamentally incorrect use of the API
> and may lead to warnings, resource exhaustion, or possibly even corruption
> and crashes for some DMA API implementations.
> 
> If there's a case where you just need to look at a small part of the buffer
> right now, but can unmap the whole thing properly later. then
> dma_sync_single_*() does allow operating on partial buffers. Even better, if
> you're able to recycle buffers in your Rx pool you could potentially replace
> the unmap/map dance altogether with some careful use of sync_single.

Hi Robin

Thanks for the info.

I went back to the driver i was thinking of, and it is using
dma_sync_single_range_for_cpu() for just the received packet length.

Sorry for the mixup.

      Andrew

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

* Re: [PATCH 03/12] net: ll_temac: Fix support for 64-bit platforms
  2019-04-26  7:32 ` [PATCH 03/12] net: ll_temac: Fix support for 64-bit platforms Esben Haabendal
@ 2019-04-26 18:40   ` Jakub Kicinski
  2019-04-26 20:59     ` Andrew Lunn
  0 siblings, 1 reply; 59+ messages in thread
From: Jakub Kicinski @ 2019-04-26 18:40 UTC (permalink / raw)
  To: Esben Haabendal
  Cc: netdev, David S. Miller, Michal Simek, Yang Wei, YueHaibing,
	Luis Chamberlain, linux-arm-kernel, linux-kernel

On Fri, 26 Apr 2019 09:32:22 +0200, Esben Haabendal wrote:
> The use of buffer descriptor APP4 field (32-bit) for storing skb pointer
> obviously does not work on 64-bit platforms.
> As APP3 is also unused, we can use that to store the other half of 64-bit
> pointer values.
> 
> Contrary to what is hinted at in commit message of commit 15bfe05c8d63
> ("net: ethernet: xilinx: Mark XILINX_LL_TEMAC broken on 64-bit")
> there are no other pointers stored in cdmac_bd.
> 
> Signed-off-by: Esben Haabendal <esben@geanix.com>

This is a bit strange, the driver stores the host's virtual address into
the HW descriptor?

> diff --git a/drivers/net/ethernet/xilinx/Kconfig b/drivers/net/ethernet/xilinx/Kconfig
> index da4ec57..6d68c8a 100644
> --- a/drivers/net/ethernet/xilinx/Kconfig
> +++ b/drivers/net/ethernet/xilinx/Kconfig
> @@ -34,7 +34,6 @@ config XILINX_AXI_EMAC
>  config XILINX_LL_TEMAC
>  	tristate "Xilinx LL TEMAC (LocalLink Tri-mode Ethernet MAC) driver"
>  	depends on (PPC || MICROBLAZE)
> -	depends on !64BIT || BROKEN
>  	select PHYLIB
>  	---help---
>  	  This driver supports the Xilinx 10/100/1000 LocalLink TEMAC
> diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
> index 4594fe3..a365bfd 100644
> --- a/drivers/net/ethernet/xilinx/ll_temac_main.c
> +++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
> @@ -619,11 +619,39 @@ static void temac_adjust_link(struct net_device *ndev)
>  	mutex_unlock(&lp->indirect_mutex);
>  }
>  
> +#ifdef CONFIG_64BIT
> +
> +void ptr_to_txbd(void *p, struct cdmac_bd *bd)
> +{
> +	bd->app3 = (u32)(((u64)p) >> 32);
> +	bd->app4 = (u32)((u64)p & 0xFFFFFFFF);
> +}
> +
> +void *ptr_from_txbd(struct cdmac_bd *bd)
> +{
> +	return (void *)(((u64)(bd->app3) << 32) | bd->app4);
> +}
> +
> +#else
> +
> +void ptr_to_txbd(void *p, struct cmdac_bd *bd)
> +{
> +	bd->app4 = (u32)p;
> +}
> +
> +void *ptr_from_txbd(struct cdmac_bd *bd)
> +{
> +	return (void *)(bd->app4);
> +}
> +
> +#endif
> +
>  static void temac_start_xmit_done(struct net_device *ndev)
>  {
>  	struct temac_local *lp = netdev_priv(ndev);
>  	struct cdmac_bd *cur_p;
>  	unsigned int stat = 0;
> +	struct sk_buff *skb;
>  
>  	cur_p = &lp->tx_bd_v[lp->tx_bd_ci];
>  	stat = cur_p->app0;
> @@ -631,8 +659,9 @@ static void temac_start_xmit_done(struct net_device *ndev)
>  	while (stat & STS_CTRL_APP0_CMPLT) {
>  		dma_unmap_single(ndev->dev.parent, cur_p->phys, cur_p->len,
>  				 DMA_TO_DEVICE);
> -		if (cur_p->app4)
> -			dev_consume_skb_irq((struct sk_buff *)cur_p->app4);
> +		skb = (struct sk_buff *)ptr_from_txbd(cur_p);
> +		if (skb)
> +			dev_consume_skb_irq(skb);
>  		cur_p->app0 = 0;
>  		cur_p->app1 = 0;
>  		cur_p->app2 = 0;
> @@ -711,7 +740,7 @@ temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
>  	cur_p->len = skb_headlen(skb);
>  	cur_p->phys = dma_map_single(ndev->dev.parent, skb->data,
>  				     skb_headlen(skb), DMA_TO_DEVICE);
> -	cur_p->app4 = (unsigned long)skb;
> +	ptr_to_txbd((void *)skb, cur_p);
>  
>  	for (ii = 0; ii < num_frag; ii++) {
>  		lp->tx_bd_tail++;


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

* Re: [PATCH 03/12] net: ll_temac: Fix support for 64-bit platforms
  2019-04-26 18:40   ` Jakub Kicinski
@ 2019-04-26 20:59     ` Andrew Lunn
  2019-04-26 21:08       ` Jakub Kicinski
  0 siblings, 1 reply; 59+ messages in thread
From: Andrew Lunn @ 2019-04-26 20:59 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: Esben Haabendal, netdev, David S. Miller, Michal Simek, Yang Wei,
	YueHaibing, Luis Chamberlain, linux-arm-kernel, linux-kernel

On Fri, Apr 26, 2019 at 11:40:13AM -0700, Jakub Kicinski wrote:
> On Fri, 26 Apr 2019 09:32:22 +0200, Esben Haabendal wrote:
> > The use of buffer descriptor APP4 field (32-bit) for storing skb pointer
> > obviously does not work on 64-bit platforms.
> > As APP3 is also unused, we can use that to store the other half of 64-bit
> > pointer values.
> > 
> > Contrary to what is hinted at in commit message of commit 15bfe05c8d63
> > ("net: ethernet: xilinx: Mark XILINX_LL_TEMAC broken on 64-bit")
> > there are no other pointers stored in cdmac_bd.
> > 
> > Signed-off-by: Esben Haabendal <esben@geanix.com>
> 
> This is a bit strange, the driver stores the host's virtual address into
> the HW descriptor?

Hi Jukub

This is reasonably common. You need some sort of cookie which links
the hardware descriptor to the skbuf it points to. The hardware makes
no use of it, it is just a cookie.

    Andrew

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

* Re: [PATCH 03/12] net: ll_temac: Fix support for 64-bit platforms
  2019-04-26 20:59     ` Andrew Lunn
@ 2019-04-26 21:08       ` Jakub Kicinski
  2019-04-26 22:02         ` Andrew Lunn
  0 siblings, 1 reply; 59+ messages in thread
From: Jakub Kicinski @ 2019-04-26 21:08 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Esben Haabendal, netdev, David S. Miller, Michal Simek, Yang Wei,
	YueHaibing, Luis Chamberlain, linux-arm-kernel, linux-kernel

On Fri, 26 Apr 2019 22:59:12 +0200, Andrew Lunn wrote:
> On Fri, Apr 26, 2019 at 11:40:13AM -0700, Jakub Kicinski wrote:
> > On Fri, 26 Apr 2019 09:32:22 +0200, Esben Haabendal wrote:  
> > > The use of buffer descriptor APP4 field (32-bit) for storing skb pointer
> > > obviously does not work on 64-bit platforms.
> > > As APP3 is also unused, we can use that to store the other half of 64-bit
> > > pointer values.
> > > 
> > > Contrary to what is hinted at in commit message of commit 15bfe05c8d63
> > > ("net: ethernet: xilinx: Mark XILINX_LL_TEMAC broken on 64-bit")
> > > there are no other pointers stored in cdmac_bd.
> > > 
> > > Signed-off-by: Esben Haabendal <esben@geanix.com>  
> > 
> > This is a bit strange, the driver stores the host's virtual address into
> > the HW descriptor?  
> 
> Hi Jukub

I need to start keeping track of all the ways my name gets spelled :)
I find it entertaining :)

> This is reasonably common. You need some sort of cookie which links
> the hardware descriptor to the skbuf it points to. The hardware makes
> no use of it, it is just a cookie.

Right, but accesses to HW descriptor memory ring are significantly 
more expensive, especially on platforms which are not coherent with 
DMA operations (everything but x86?)

A preferable design is to have two descriptor rings - one for HW
descriptors and one for software context, no?

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

* Re: [PATCH 03/12] net: ll_temac: Fix support for 64-bit platforms
  2019-04-26 21:08       ` Jakub Kicinski
@ 2019-04-26 22:02         ` Andrew Lunn
  2019-04-26 22:30           ` Jakub Kicinski
  0 siblings, 1 reply; 59+ messages in thread
From: Andrew Lunn @ 2019-04-26 22:02 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: Esben Haabendal, netdev, David S. Miller, Michal Simek, Yang Wei,
	YueHaibing, Luis Chamberlain, linux-arm-kernel, linux-kernel

On Fri, Apr 26, 2019 at 02:08:56PM -0700, Jakub Kicinski wrote:
> On Fri, 26 Apr 2019 22:59:12 +0200, Andrew Lunn wrote:
> > On Fri, Apr 26, 2019 at 11:40:13AM -0700, Jakub Kicinski wrote:
> > > On Fri, 26 Apr 2019 09:32:22 +0200, Esben Haabendal wrote:  
> > > > The use of buffer descriptor APP4 field (32-bit) for storing skb pointer
> > > > obviously does not work on 64-bit platforms.
> > > > As APP3 is also unused, we can use that to store the other half of 64-bit
> > > > pointer values.
> > > > 
> > > > Contrary to what is hinted at in commit message of commit 15bfe05c8d63
> > > > ("net: ethernet: xilinx: Mark XILINX_LL_TEMAC broken on 64-bit")
> > > > there are no other pointers stored in cdmac_bd.
> > > > 
> > > > Signed-off-by: Esben Haabendal <esben@geanix.com>  
> > > 
> > > This is a bit strange, the driver stores the host's virtual address into
> > > the HW descriptor?  

Lets try that again

Hi Jakub

> > Hi Jukub
> 
> I need to start keeping track of all the ways my name gets spelled :)
> I find it entertaining :)

Sorry. 

And i prefer entertaining over offended :-)

> > This is reasonably common. You need some sort of cookie which links
> > the hardware descriptor to the skbuf it points to. The hardware makes
> > no use of it, it is just a cookie.
> 
> Right, but accesses to HW descriptor memory ring are significantly 
> more expensive, especially on platforms which are not coherent with 
> DMA operations (everything but x86?)
>
> A preferable design is to have two descriptor rings - one for HW
> descriptors and one for software context, no?

Modern drivers do that. But this driver seems to be quite old.  And if
you look at what it is used on, PPC & MICROBLAZE, they are old
architectures, i don't think hardware access are that as expensive as
for modern architectures.

	  Andrew

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

* Re: [PATCH 03/12] net: ll_temac: Fix support for 64-bit platforms
  2019-04-26 22:02         ` Andrew Lunn
@ 2019-04-26 22:30           ` Jakub Kicinski
  2019-04-27  8:49             ` Esben Haabendal
  0 siblings, 1 reply; 59+ messages in thread
From: Jakub Kicinski @ 2019-04-26 22:30 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Esben Haabendal, netdev, David S. Miller, Michal Simek, Yang Wei,
	YueHaibing, Luis Chamberlain, linux-arm-kernel, linux-kernel

On Sat, 27 Apr 2019 00:02:26 +0200, Andrew Lunn wrote:
> On Fri, Apr 26, 2019 at 02:08:56PM -0700, Jakub Kicinski wrote:
> > On Fri, 26 Apr 2019 22:59:12 +0200, Andrew Lunn wrote:  
> > > On Fri, Apr 26, 2019 at 11:40:13AM -0700, Jakub Kicinski wrote:  
> > > > On Fri, 26 Apr 2019 09:32:22 +0200, Esben Haabendal wrote:    
> > > > > The use of buffer descriptor APP4 field (32-bit) for storing skb pointer
> > > > > obviously does not work on 64-bit platforms.
> > > > > As APP3 is also unused, we can use that to store the other half of 64-bit
> > > > > pointer values.
> > > > > 
> > > > > Contrary to what is hinted at in commit message of commit 15bfe05c8d63
> > > > > ("net: ethernet: xilinx: Mark XILINX_LL_TEMAC broken on 64-bit")
> > > > > there are no other pointers stored in cdmac_bd.
> > > > > 
> > > > > Signed-off-by: Esben Haabendal <esben@geanix.com>    
> > > > 
> > > > This is a bit strange, the driver stores the host's virtual address into
> > > > the HW descriptor?    
> 
> Lets try that again
> 
> Hi Jakub

:)

> > > Hi Jukub  
> > 
> > I need to start keeping track of all the ways my name gets spelled :)
> > I find it entertaining :)  
> 
> Sorry. 
> 
> And i prefer entertaining over offended :-)

Certainly no offence taken! :)

> > > This is reasonably common. You need some sort of cookie which links
> > > the hardware descriptor to the skbuf it points to. The hardware makes
> > > no use of it, it is just a cookie.  
> > 
> > Right, but accesses to HW descriptor memory ring are significantly 
> > more expensive, especially on platforms which are not coherent with 
> > DMA operations (everything but x86?)
> >
> > A preferable design is to have two descriptor rings - one for HW
> > descriptors and one for software context, no?  
> 
> Modern drivers do that. But this driver seems to be quite old.  And if
> you look at what it is used on, PPC & MICROBLAZE, they are old
> architectures, i don't think hardware access are that as expensive as
> for modern architectures.

True, my comment was certainly more of a suggestion than a blocker.

Looking closer at the series it kind of looks like a soft IP.
Esben, is there anything architecture specific here?  Should we perhaps
drop the dependency on the architectures in patch 6 completely?

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

* Re: [PATCH 03/12] net: ll_temac: Fix support for 64-bit platforms
  2019-04-26 22:30           ` Jakub Kicinski
@ 2019-04-27  8:49             ` Esben Haabendal
  0 siblings, 0 replies; 59+ messages in thread
From: Esben Haabendal @ 2019-04-27  8:49 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: Andrew Lunn, netdev, David S. Miller, Michal Simek, Yang Wei,
	YueHaibing, Luis Chamberlain, linux-arm-kernel, linux-kernel

Jakub Kicinski <jakub.kicinski@netronome.com> writes:

> Looking closer at the series it kind of looks like a soft IP.

It is a soft IP.

> Esben, is there anything architecture specific here?  Should we perhaps
> drop the dependency on the architectures in patch 6 completely?

No, I don't think there is anything really architecture specific here.
Anything with PCIe should be able to utilize the LL TEMAC soft IP and
use this driver.

I don't mind dropping the architecture dependencies.

/Esben

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

* [PATCH 00/12] net: ll_temac: x86_64 support
  2019-04-26  7:32 [PATCH 00/12] net: ll_temac: x86_64 support Esben Haabendal
                   ` (11 preceding siblings ...)
  2019-04-26  7:32 ` [PATCH 12/12] net: ll_temac: Enable DMA when ready, not before Esben Haabendal
@ 2019-04-29  8:34 ` Esben Haabendal
  2019-04-29  8:34   ` [PATCH 01/12] net: ll_temac: Fix and simplify error handling by using devres functions Esben Haabendal
                     ` (12 more replies)
  12 siblings, 13 replies; 59+ messages in thread
From: Esben Haabendal @ 2019-04-29  8:34 UTC (permalink / raw)
  To: netdev, linux-arm-kernel
  Cc: Michal Simek, David S. Miller, Luis Chamberlain, Yang Wei,
	YueHaibing, linux-kernel

This patch series adds support for use of ll_temac driver with
platform_data configuration and fixes endianess and 64-bit problems so
that it can be used on x86_64 platform.

A few bugfixes are also included.

Changes since v1:

  - Make indirect_mutex specification mandatory when using platform_data
  - Move header to include/linux/platform_data
  - Enable COMPILE_TEST for XILINX_LL_TEMAC
  - Rebased to v5.1-rc7

Esben Haabendal (12):
  net: ll_temac: Fix and simplify error handling by using devres
    functions
  net: ll_temac: Extend support to non-device-tree platforms
  net: ll_temac: Fix support for 64-bit platforms
  net: ll_temac: Add support for non-native register endianness
  net: ll_temac: Fix support for little-endian platforms
  net: ll_temac: Allow use on x86 platforms
  net: ll_temac: Support indirect_mutex share within TEMAC IP
  net: ll_temac: Fix iommu/swiotlb leak
  net: ll_temac: Fix bug causing buffer descriptor overrun
  net: ll_temac: Replace bad usage of msleep() with usleep_range()
  net: ll_temac: Allow configuration of IRQ coalescing
  net: ll_temac: Enable DMA when ready, not before

 drivers/net/ethernet/xilinx/Kconfig           |   5 +-
 drivers/net/ethernet/xilinx/ll_temac.h        |  26 +-
 drivers/net/ethernet/xilinx/ll_temac_main.c   | 515 +++++++++++++++++---------
 drivers/net/ethernet/xilinx/ll_temac_mdio.c   |  53 +--
 include/linux/platform_data/xilinx-ll-temac.h |  32 ++
 5 files changed, 428 insertions(+), 203 deletions(-)
 create mode 100644 include/linux/platform_data/xilinx-ll-temac.h

-- 
2.4.11


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

* [PATCH 01/12] net: ll_temac: Fix and simplify error handling by using devres functions
  2019-04-29  8:34 ` [PATCH 00/12] net: ll_temac: x86_64 support Esben Haabendal
@ 2019-04-29  8:34   ` Esben Haabendal
  2019-04-29  8:34   ` [PATCH 02/12] net: ll_temac: Extend support to non-device-tree platforms Esben Haabendal
                     ` (11 subsequent siblings)
  12 siblings, 0 replies; 59+ messages in thread
From: Esben Haabendal @ 2019-04-29  8:34 UTC (permalink / raw)
  To: netdev
  Cc: David S. Miller, Michal Simek, YueHaibing, Luis Chamberlain,
	Yang Wei, linux-arm-kernel, linux-kernel

As a side effect, a few error cases are fixed.

If of_iomap() of sdma_regs failed, no error code was returned.  Fixed to
return -ENOMEM similar to of_iomap() fail of regs.

If sysfs_create_group() or register_netdev() failed, lp->phy_node was not
released.

Finally, the order in remove function is corrected to be reverse order
of what is done in probe, i.e. calling temac_mdio_teardown() last, so we
unregister the netdev that most likely is using the mdio_bus first.

Signed-off-by: Esben Haabendal <esben@geanix.com>
---
 drivers/net/ethernet/xilinx/ll_temac.h      |  2 +-
 drivers/net/ethernet/xilinx/ll_temac_main.c | 48 ++++++++++-------------------
 drivers/net/ethernet/xilinx/ll_temac_mdio.c | 14 +++------
 3 files changed, 22 insertions(+), 42 deletions(-)

diff --git a/drivers/net/ethernet/xilinx/ll_temac.h b/drivers/net/ethernet/xilinx/ll_temac.h
index 1075752..4557578 100644
--- a/drivers/net/ethernet/xilinx/ll_temac.h
+++ b/drivers/net/ethernet/xilinx/ll_temac.h
@@ -378,7 +378,7 @@ void temac_indirect_out32(struct temac_local *lp, int reg, u32 value);
 
 
 /* xilinx_temac_mdio.c */
-int temac_mdio_setup(struct temac_local *lp, struct device_node *np);
+int temac_mdio_setup(struct temac_local *lp, struct platform_device *pdev);
 void temac_mdio_teardown(struct temac_local *lp);
 
 #endif /* XILINX_LL_TEMAC_H */
diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index 44efffb..c4e85a9 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -225,7 +225,6 @@ static void temac_dma_bd_release(struct net_device *ndev)
 		dma_free_coherent(ndev->dev.parent,
 				sizeof(*lp->tx_bd_v) * TX_BD_NUM,
 				lp->tx_bd_v, lp->tx_bd_p);
-	kfree(lp->rx_skb);
 }
 
 /**
@@ -237,7 +236,8 @@ static int temac_dma_bd_init(struct net_device *ndev)
 	struct sk_buff *skb;
 	int i;
 
-	lp->rx_skb = kcalloc(RX_BD_NUM, sizeof(*lp->rx_skb), GFP_KERNEL);
+	lp->rx_skb = devm_kcalloc(&ndev->dev, RX_BD_NUM, sizeof(*lp->rx_skb),
+				  GFP_KERNEL);
 	if (!lp->rx_skb)
 		goto out;
 
@@ -987,7 +987,7 @@ static int temac_of_probe(struct platform_device *op)
 	int rc = 0;
 
 	/* Init network device structure */
-	ndev = alloc_etherdev(sizeof(*lp));
+	ndev = devm_alloc_etherdev(&pdev->dev, sizeof(*lp));
 	if (!ndev)
 		return -ENOMEM;
 
@@ -1020,11 +1020,10 @@ static int temac_of_probe(struct platform_device *op)
 	mutex_init(&lp->indirect_mutex);
 
 	/* map device registers */
-	lp->regs = of_iomap(op->dev.of_node, 0);
+	lp->regs = devm_of_iomap(&op->dev, op->dev.of_node, 0, NULL);
 	if (!lp->regs) {
 		dev_err(&op->dev, "could not map temac regs.\n");
-		rc = -ENOMEM;
-		goto nodev;
+		return -ENOMEM;
 	}
 
 	/* Setup checksum offload, but default to off if not specified */
@@ -1043,15 +1042,14 @@ static int temac_of_probe(struct platform_device *op)
 	np = of_parse_phandle(op->dev.of_node, "llink-connected", 0);
 	if (!np) {
 		dev_err(&op->dev, "could not find DMA node\n");
-		rc = -ENODEV;
-		goto err_iounmap;
+		return -ENODEV;
 	}
 
 	/* Setup the DMA register accesses, could be DCR or memory mapped */
 	if (temac_dcr_setup(lp, op, np)) {
 
 		/* no DCR in the device tree, try non-DCR */
-		lp->sdma_regs = of_iomap(np, 0);
+		lp->sdma_regs = devm_of_iomap(&op->dev, np, 0, NULL);
 		if (lp->sdma_regs) {
 			lp->dma_in = temac_dma_in32;
 			lp->dma_out = temac_dma_out32;
@@ -1059,7 +1057,7 @@ static int temac_of_probe(struct platform_device *op)
 		} else {
 			dev_err(&op->dev, "unable to map DMA registers\n");
 			of_node_put(np);
-			goto err_iounmap;
+			return -ENOMEM;
 		}
 	}
 
@@ -1070,8 +1068,7 @@ static int temac_of_probe(struct platform_device *op)
 
 	if (!lp->rx_irq || !lp->tx_irq) {
 		dev_err(&op->dev, "could not determine irqs\n");
-		rc = -ENOMEM;
-		goto err_iounmap_2;
+		return -ENOMEM;
 	}
 
 
@@ -1079,12 +1076,11 @@ static int temac_of_probe(struct platform_device *op)
 	addr = of_get_mac_address(op->dev.of_node);
 	if (!addr) {
 		dev_err(&op->dev, "could not find MAC address\n");
-		rc = -ENODEV;
-		goto err_iounmap_2;
+		return -ENODEV;
 	}
 	temac_init_mac_address(ndev, addr);
 
-	rc = temac_mdio_setup(lp, op->dev.of_node);
+	rc = temac_mdio_setup(lp, pdev);
 	if (rc)
 		dev_warn(&op->dev, "error registering MDIO bus\n");
 
@@ -1096,7 +1092,7 @@ static int temac_of_probe(struct platform_device *op)
 	rc = sysfs_create_group(&lp->dev->kobj, &temac_attr_group);
 	if (rc) {
 		dev_err(lp->dev, "Error creating sysfs files\n");
-		goto err_iounmap_2;
+		goto err_sysfs_create;
 	}
 
 	rc = register_netdev(lp->ndev);
@@ -1107,16 +1103,11 @@ static int temac_of_probe(struct platform_device *op)
 
 	return 0;
 
- err_register_ndev:
+err_register_ndev:
 	sysfs_remove_group(&lp->dev->kobj, &temac_attr_group);
- err_iounmap_2:
-	if (lp->sdma_regs)
-		iounmap(lp->sdma_regs);
- err_iounmap:
-	iounmap(lp->regs);
- nodev:
-	free_netdev(ndev);
-	ndev = NULL;
+err_sysfs_create:
+	of_node_put(lp->phy_node);
+	temac_mdio_teardown(lp);
 	return rc;
 }
 
@@ -1125,15 +1116,10 @@ static int temac_of_remove(struct platform_device *op)
 	struct net_device *ndev = platform_get_drvdata(op);
 	struct temac_local *lp = netdev_priv(ndev);
 
-	temac_mdio_teardown(lp);
 	unregister_netdev(ndev);
 	sysfs_remove_group(&lp->dev->kobj, &temac_attr_group);
 	of_node_put(lp->phy_node);
-	lp->phy_node = NULL;
-	iounmap(lp->regs);
-	if (lp->sdma_regs)
-		iounmap(lp->sdma_regs);
-	free_netdev(ndev);
+	temac_mdio_teardown(lp);
 	return 0;
 }
 
diff --git a/drivers/net/ethernet/xilinx/ll_temac_mdio.c b/drivers/net/ethernet/xilinx/ll_temac_mdio.c
index f5e83ac..a0b365e 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_mdio.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_mdio.c
@@ -57,8 +57,9 @@ static int temac_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 val)
 	return 0;
 }
 
-int temac_mdio_setup(struct temac_local *lp, struct device_node *np)
+int temac_mdio_setup(struct temac_local *lp, struct platform_device *pdev)
 {
+	struct device_node *np = dev_of_node(&pdev->dev);
 	struct mii_bus *bus;
 	u32 bus_hz;
 	int clk_div;
@@ -81,7 +82,7 @@ int temac_mdio_setup(struct temac_local *lp, struct device_node *np)
 	temac_indirect_out32(lp, XTE_MC_OFFSET, 1 << 6 | clk_div);
 	mutex_unlock(&lp->indirect_mutex);
 
-	bus = mdiobus_alloc();
+	bus = devm_mdiobus_alloc(&pdev->dev);
 	if (!bus)
 		return -ENOMEM;
 
@@ -98,23 +99,16 @@ int temac_mdio_setup(struct temac_local *lp, struct device_node *np)
 
 	rc = of_mdiobus_register(bus, np);
 	if (rc)
-		goto err_register;
+		return rc;
 
 	mutex_lock(&lp->indirect_mutex);
 	dev_dbg(lp->dev, "MDIO bus registered;  MC:%x\n",
 		temac_indirect_in32(lp, XTE_MC_OFFSET));
 	mutex_unlock(&lp->indirect_mutex);
 	return 0;
-
- err_register:
-	mdiobus_free(bus);
-	return rc;
 }
 
 void temac_mdio_teardown(struct temac_local *lp)
 {
 	mdiobus_unregister(lp->mii_bus);
-	mdiobus_free(lp->mii_bus);
-	lp->mii_bus = NULL;
 }
-
-- 
2.4.11


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

* [PATCH 02/12] net: ll_temac: Extend support to non-device-tree platforms
  2019-04-29  8:34 ` [PATCH 00/12] net: ll_temac: x86_64 support Esben Haabendal
  2019-04-29  8:34   ` [PATCH 01/12] net: ll_temac: Fix and simplify error handling by using devres functions Esben Haabendal
@ 2019-04-29  8:34   ` Esben Haabendal
  2019-04-29  8:34   ` [PATCH 03/12] net: ll_temac: Fix support for 64-bit platforms Esben Haabendal
                     ` (10 subsequent siblings)
  12 siblings, 0 replies; 59+ messages in thread
From: Esben Haabendal @ 2019-04-29  8:34 UTC (permalink / raw)
  To: netdev
  Cc: David S. Miller, Michal Simek, YueHaibing, Yang Wei,
	Luis Chamberlain, linux-kernel, linux-arm-kernel

Support initialization with platdata, so the driver can be used on
non-device-tree platforms.

For currently supported device-tree platforms, the driver should behave
as before.

Signed-off-by: Esben Haabendal <esben@geanix.com>
---
 drivers/net/ethernet/xilinx/ll_temac.h        |   3 +
 drivers/net/ethernet/xilinx/ll_temac_main.c   | 187 +++++++++++++++++---------
 drivers/net/ethernet/xilinx/ll_temac_mdio.c   |  23 +++-
 include/linux/platform_data/xilinx-ll-temac.h |  19 +++
 4 files changed, 166 insertions(+), 66 deletions(-)
 create mode 100644 include/linux/platform_data/xilinx-ll-temac.h

diff --git a/drivers/net/ethernet/xilinx/ll_temac.h b/drivers/net/ethernet/xilinx/ll_temac.h
index 4557578..e338b4f 100644
--- a/drivers/net/ethernet/xilinx/ll_temac.h
+++ b/drivers/net/ethernet/xilinx/ll_temac.h
@@ -334,6 +334,9 @@ struct temac_local {
 
 	/* Connection to PHY device */
 	struct device_node *phy_node;
+	/* For non-device-tree devices */
+	char phy_name[MII_BUS_ID_SIZE + 3];
+	phy_interface_t phy_interface;
 
 	/* MDIO bus data */
 	struct mii_bus *mii_bus;	/* MII bus reference */
diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index c4e85a9..fddd1b3 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -33,6 +33,7 @@
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/netdevice.h>
+#include <linux/if_ether.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_irq.h>
@@ -51,6 +52,7 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/dma-mapping.h>
+#include <linux/platform_data/xilinx-ll-temac.h>
 
 #include "ll_temac.h"
 
@@ -187,7 +189,7 @@ static int temac_dcr_setup(struct temac_local *lp, struct platform_device *op,
 
 /*
  * temac_dcr_setup - This is a stub for when DCR is not supported,
- * such as with MicroBlaze
+ * such as with MicroBlaze and x86
  */
 static int temac_dcr_setup(struct temac_local *lp, struct platform_device *op,
 				struct device_node *np)
@@ -857,7 +859,14 @@ static int temac_open(struct net_device *ndev)
 			dev_err(lp->dev, "of_phy_connect() failed\n");
 			return -ENODEV;
 		}
-
+		phy_start(phydev);
+	} else if (strlen(lp->phy_name) > 0) {
+		phydev = phy_connect(lp->ndev, lp->phy_name, temac_adjust_link,
+				     lp->phy_interface);
+		if (!phydev) {
+			dev_err(lp->dev, "phy_connect() failed\n");
+			return -ENODEV;
+		}
 		phy_start(phydev);
 	}
 
@@ -977,11 +986,13 @@ static const struct ethtool_ops temac_ethtool_ops = {
 	.set_link_ksettings = phy_ethtool_set_link_ksettings,
 };
 
-static int temac_of_probe(struct platform_device *op)
+static int temac_probe(struct platform_device *pdev)
 {
-	struct device_node *np;
+	struct ll_temac_platform_data *pdata = dev_get_platdata(&pdev->dev);
+	struct device_node *temac_np = dev_of_node(&pdev->dev), *dma_np;
 	struct temac_local *lp;
 	struct net_device *ndev;
+	struct resource *res;
 	const void *addr;
 	__be32 *p;
 	int rc = 0;
@@ -991,8 +1002,8 @@ static int temac_of_probe(struct platform_device *op)
 	if (!ndev)
 		return -ENOMEM;
 
-	platform_set_drvdata(op, ndev);
-	SET_NETDEV_DEV(ndev, &op->dev);
+	platform_set_drvdata(pdev, ndev);
+	SET_NETDEV_DEV(ndev, &pdev->dev);
 	ndev->flags &= ~IFF_MULTICAST;  /* clear multicast */
 	ndev->features = NETIF_F_SG;
 	ndev->netdev_ops = &temac_netdev_ops;
@@ -1014,79 +1025,129 @@ static int temac_of_probe(struct platform_device *op)
 	/* setup temac private info structure */
 	lp = netdev_priv(ndev);
 	lp->ndev = ndev;
-	lp->dev = &op->dev;
+	lp->dev = &pdev->dev;
 	lp->options = XTE_OPTION_DEFAULTS;
 	spin_lock_init(&lp->rx_lock);
 	mutex_init(&lp->indirect_mutex);
 
 	/* map device registers */
-	lp->regs = devm_of_iomap(&op->dev, op->dev.of_node, 0, NULL);
-	if (!lp->regs) {
-		dev_err(&op->dev, "could not map temac regs.\n");
-		return -ENOMEM;
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	lp->regs = devm_ioremap_nocache(&pdev->dev, res->start,
+					resource_size(res));
+	if (IS_ERR(lp->regs)) {
+		dev_err(&pdev->dev, "could not map TEMAC registers\n");
+		return PTR_ERR(lp->regs);
 	}
 
 	/* Setup checksum offload, but default to off if not specified */
 	lp->temac_features = 0;
-	p = (__be32 *)of_get_property(op->dev.of_node, "xlnx,txcsum", NULL);
-	if (p && be32_to_cpu(*p)) {
-		lp->temac_features |= TEMAC_FEATURE_TX_CSUM;
+	if (temac_np) {
+		p = (__be32 *)of_get_property(temac_np, "xlnx,txcsum", NULL);
+		if (p && be32_to_cpu(*p))
+			lp->temac_features |= TEMAC_FEATURE_TX_CSUM;
+		p = (__be32 *)of_get_property(temac_np, "xlnx,rxcsum", NULL);
+		if (p && be32_to_cpu(*p))
+			lp->temac_features |= TEMAC_FEATURE_RX_CSUM;
+	} else if (pdata) {
+		if (pdata->txcsum)
+			lp->temac_features |= TEMAC_FEATURE_TX_CSUM;
+		if (pdata->rxcsum)
+			lp->temac_features |= TEMAC_FEATURE_RX_CSUM;
+	}
+	if (lp->temac_features & TEMAC_FEATURE_TX_CSUM)
 		/* Can checksum TCP/UDP over IPv4. */
 		ndev->features |= NETIF_F_IP_CSUM;
-	}
-	p = (__be32 *)of_get_property(op->dev.of_node, "xlnx,rxcsum", NULL);
-	if (p && be32_to_cpu(*p))
-		lp->temac_features |= TEMAC_FEATURE_RX_CSUM;
-
-	/* Find the DMA node, map the DMA registers, and decode the DMA IRQs */
-	np = of_parse_phandle(op->dev.of_node, "llink-connected", 0);
-	if (!np) {
-		dev_err(&op->dev, "could not find DMA node\n");
-		return -ENODEV;
-	}
 
-	/* Setup the DMA register accesses, could be DCR or memory mapped */
-	if (temac_dcr_setup(lp, op, np)) {
+	/* Setup LocalLink DMA */
+	if (temac_np) {
+		/* Find the DMA node, map the DMA registers, and
+		 * decode the DMA IRQs.
+		 */
+		dma_np = of_parse_phandle(temac_np, "llink-connected", 0);
+		if (!dma_np) {
+			dev_err(&pdev->dev, "could not find DMA node\n");
+			return -ENODEV;
+		}
 
-		/* no DCR in the device tree, try non-DCR */
-		lp->sdma_regs = devm_of_iomap(&op->dev, np, 0, NULL);
-		if (lp->sdma_regs) {
+		/* Setup the DMA register accesses, could be DCR or
+		 * memory mapped.
+		 */
+		if (temac_dcr_setup(lp, pdev, dma_np)) {
+			/* no DCR in the device tree, try non-DCR */
+			lp->sdma_regs = devm_of_iomap(&pdev->dev, dma_np, 0,
+						      NULL);
+			if (IS_ERR(lp->sdma_regs)) {
+				dev_err(&pdev->dev,
+					"unable to map DMA registers\n");
+				of_node_put(dma_np);
+				return PTR_ERR(lp->sdma_regs);
+			}
 			lp->dma_in = temac_dma_in32;
 			lp->dma_out = temac_dma_out32;
-			dev_dbg(&op->dev, "MEM base: %p\n", lp->sdma_regs);
-		} else {
-			dev_err(&op->dev, "unable to map DMA registers\n");
-			of_node_put(np);
-			return -ENOMEM;
+			dev_dbg(&pdev->dev, "MEM base: %p\n", lp->sdma_regs);
 		}
-	}
-
-	lp->rx_irq = irq_of_parse_and_map(np, 0);
-	lp->tx_irq = irq_of_parse_and_map(np, 1);
 
-	of_node_put(np); /* Finished with the DMA node; drop the reference */
+		/* Get DMA RX and TX interrupts */
+		lp->rx_irq = irq_of_parse_and_map(dma_np, 0);
+		lp->tx_irq = irq_of_parse_and_map(dma_np, 1);
+
+		/* Finished with the DMA node; drop the reference */
+		of_node_put(dma_np);
+	} else if (pdata) {
+		/* 2nd memory resource specifies DMA registers */
+		res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+		lp->sdma_regs = devm_ioremap_nocache(&pdev->dev, res->start,
+						     resource_size(res));
+		if (IS_ERR(lp->sdma_regs)) {
+			dev_err(&pdev->dev,
+				"could not map DMA registers\n");
+			return PTR_ERR(lp->sdma_regs);
+		}
+		lp->dma_in = temac_dma_in32;
+		lp->dma_out = temac_dma_out32;
 
-	if (!lp->rx_irq || !lp->tx_irq) {
-		dev_err(&op->dev, "could not determine irqs\n");
-		return -ENOMEM;
+		/* Get DMA RX and TX interrupts */
+		lp->rx_irq = platform_get_irq(pdev, 0);
+		lp->tx_irq = platform_get_irq(pdev, 1);
 	}
 
+	/* Error handle returned DMA RX and TX interrupts */
+	if (lp->rx_irq < 0) {
+		if (lp->rx_irq != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "could not get DMA RX irq\n");
+		return lp->rx_irq;
+	}
+	if (lp->tx_irq < 0) {
+		if (lp->tx_irq != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "could not get DMA TX irq\n");
+		return lp->tx_irq;
+	}
 
-	/* Retrieve the MAC address */
-	addr = of_get_mac_address(op->dev.of_node);
-	if (!addr) {
-		dev_err(&op->dev, "could not find MAC address\n");
-		return -ENODEV;
+	if (temac_np) {
+		/* Retrieve the MAC address */
+		addr = of_get_mac_address(temac_np);
+		if (!addr) {
+			dev_err(&pdev->dev, "could not find MAC address\n");
+			return -ENODEV;
+		}
+		temac_init_mac_address(ndev, addr);
+	} else if (pdata) {
+		temac_init_mac_address(ndev, pdata->mac_addr);
 	}
-	temac_init_mac_address(ndev, addr);
 
 	rc = temac_mdio_setup(lp, pdev);
 	if (rc)
-		dev_warn(&op->dev, "error registering MDIO bus\n");
-
-	lp->phy_node = of_parse_phandle(op->dev.of_node, "phy-handle", 0);
-	if (lp->phy_node)
-		dev_dbg(lp->dev, "using PHY node %pOF (%p)\n", np, np);
+		dev_warn(&pdev->dev, "error registering MDIO bus\n");
+
+	if (temac_np) {
+		lp->phy_node = of_parse_phandle(temac_np, "phy-handle", 0);
+		if (lp->phy_node)
+			dev_dbg(lp->dev, "using PHY node %pOF\n", temac_np);
+	} else if (pdata) {
+		snprintf(lp->phy_name, sizeof(lp->phy_name),
+			 PHY_ID_FMT, lp->mii_bus->id, pdata->phy_addr);
+		lp->phy_interface = pdata->phy_interface;
+	}
 
 	/* Add the device attributes */
 	rc = sysfs_create_group(&lp->dev->kobj, &temac_attr_group);
@@ -1106,19 +1167,21 @@ static int temac_of_probe(struct platform_device *op)
 err_register_ndev:
 	sysfs_remove_group(&lp->dev->kobj, &temac_attr_group);
 err_sysfs_create:
-	of_node_put(lp->phy_node);
+	if (lp->phy_node)
+		of_node_put(lp->phy_node);
 	temac_mdio_teardown(lp);
 	return rc;
 }
 
-static int temac_of_remove(struct platform_device *op)
+static int temac_remove(struct platform_device *pdev)
 {
-	struct net_device *ndev = platform_get_drvdata(op);
+	struct net_device *ndev = platform_get_drvdata(pdev);
 	struct temac_local *lp = netdev_priv(ndev);
 
 	unregister_netdev(ndev);
 	sysfs_remove_group(&lp->dev->kobj, &temac_attr_group);
-	of_node_put(lp->phy_node);
+	if (lp->phy_node)
+		of_node_put(lp->phy_node);
 	temac_mdio_teardown(lp);
 	return 0;
 }
@@ -1132,16 +1195,16 @@ static const struct of_device_id temac_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, temac_of_match);
 
-static struct platform_driver temac_of_driver = {
-	.probe = temac_of_probe,
-	.remove = temac_of_remove,
+static struct platform_driver temac_driver = {
+	.probe = temac_probe,
+	.remove = temac_remove,
 	.driver = {
 		.name = "xilinx_temac",
 		.of_match_table = temac_of_match,
 	},
 };
 
-module_platform_driver(temac_of_driver);
+module_platform_driver(temac_driver);
 
 MODULE_DESCRIPTION("Xilinx LL_TEMAC Ethernet driver");
 MODULE_AUTHOR("Yoshio Kashiwagi");
diff --git a/drivers/net/ethernet/xilinx/ll_temac_mdio.c b/drivers/net/ethernet/xilinx/ll_temac_mdio.c
index a0b365e..c5307e5 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_mdio.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_mdio.c
@@ -14,6 +14,7 @@
 #include <linux/of_address.h>
 #include <linux/slab.h>
 #include <linux/of_mdio.h>
+#include <linux/platform_data/xilinx-ll-temac.h>
 
 #include "ll_temac.h"
 
@@ -59,6 +60,7 @@ static int temac_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 val)
 
 int temac_mdio_setup(struct temac_local *lp, struct platform_device *pdev)
 {
+	struct ll_temac_platform_data *pdata = dev_get_platdata(&pdev->dev);
 	struct device_node *np = dev_of_node(&pdev->dev);
 	struct mii_bus *bus;
 	u32 bus_hz;
@@ -66,9 +68,16 @@ int temac_mdio_setup(struct temac_local *lp, struct platform_device *pdev)
 	int rc;
 	struct resource res;
 
+	/* Get MDIO bus frequency (if specified) */
+	bus_hz = 0;
+	if (np)
+		of_property_read_u32(np, "clock-frequency", &bus_hz);
+	else if (pdata)
+		bus_hz = pdata->mdio_clk_freq;
+
 	/* Calculate a reasonable divisor for the clock rate */
 	clk_div = 0x3f; /* worst-case default setting */
-	if (of_property_read_u32(np, "clock-frequency", &bus_hz) == 0) {
+	if (bus_hz != 0) {
 		clk_div = bus_hz / (2500 * 1000 * 2) - 1;
 		if (clk_div < 1)
 			clk_div = 1;
@@ -86,9 +95,15 @@ int temac_mdio_setup(struct temac_local *lp, struct platform_device *pdev)
 	if (!bus)
 		return -ENOMEM;
 
-	of_address_to_resource(np, 0, &res);
-	snprintf(bus->id, MII_BUS_ID_SIZE, "%.8llx",
-		 (unsigned long long)res.start);
+	if (np) {
+		of_address_to_resource(np, 0, &res);
+		snprintf(bus->id, MII_BUS_ID_SIZE, "%.8llx",
+			 (unsigned long long)res.start);
+	} else if (pdata && pdata->mdio_bus_id >= 0) {
+		snprintf(bus->id, MII_BUS_ID_SIZE, "%.8llx",
+			 pdata->mdio_bus_id);
+	}
+
 	bus->priv = lp;
 	bus->name = "Xilinx TEMAC MDIO";
 	bus->read = temac_mdio_read;
diff --git a/include/linux/platform_data/xilinx-ll-temac.h b/include/linux/platform_data/xilinx-ll-temac.h
new file mode 100644
index 0000000..82e2f80
--- /dev/null
+++ b/include/linux/platform_data/xilinx-ll-temac.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __LINUX_XILINX_LL_TEMAC_H
+#define __LINUX_XILINX_LL_TEMAC_H
+
+#include <linux/if_ether.h>
+#include <linux/phy.h>
+
+struct ll_temac_platform_data {
+	bool txcsum;		/* Enable/disable TX checksum */
+	bool rxcsum;		/* Enable/disable RX checksum */
+	u8 mac_addr[ETH_ALEN];	/* MAC address (6 bytes) */
+	/* Clock frequency for input to MDIO clock generator */
+	u32 mdio_clk_freq;
+	unsigned long long mdio_bus_id; /* Unique id for MDIO bus */
+	int phy_addr;		/* Address of the PHY to connect to */
+	phy_interface_t phy_interface; /* PHY interface mode */
+};
+
+#endif /* __LINUX_XILINX_LL_TEMAC_H */
-- 
2.4.11


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

* [PATCH 03/12] net: ll_temac: Fix support for 64-bit platforms
  2019-04-29  8:34 ` [PATCH 00/12] net: ll_temac: x86_64 support Esben Haabendal
  2019-04-29  8:34   ` [PATCH 01/12] net: ll_temac: Fix and simplify error handling by using devres functions Esben Haabendal
  2019-04-29  8:34   ` [PATCH 02/12] net: ll_temac: Extend support to non-device-tree platforms Esben Haabendal
@ 2019-04-29  8:34   ` Esben Haabendal
  2019-04-29 22:06     ` Andrew Lunn
  2019-04-29  8:34   ` [PATCH 04/12] net: ll_temac: Add support for non-native register endianness Esben Haabendal
                     ` (9 subsequent siblings)
  12 siblings, 1 reply; 59+ messages in thread
From: Esben Haabendal @ 2019-04-29  8:34 UTC (permalink / raw)
  To: netdev
  Cc: David S. Miller, Michal Simek, Yang Wei, Luis Chamberlain,
	YueHaibing, linux-arm-kernel, linux-kernel

The use of buffer descriptor APP4 field (32-bit) for storing skb pointer
obviously does not work on 64-bit platforms.
As APP3 is also unused, we can use that to store the other half of 64-bit
pointer values.

Contrary to what is hinted at in commit message of commit 15bfe05c8d63
("net: ethernet: xilinx: Mark XILINX_LL_TEMAC broken on 64-bit")
there are no other pointers stored in cdmac_bd.

Signed-off-by: Esben Haabendal <esben@geanix.com>
---
 drivers/net/ethernet/xilinx/Kconfig         |  1 -
 drivers/net/ethernet/xilinx/ll_temac_main.c | 35 ++++++++++++++++++++++++++---
 2 files changed, 32 insertions(+), 4 deletions(-)

diff --git a/drivers/net/ethernet/xilinx/Kconfig b/drivers/net/ethernet/xilinx/Kconfig
index da4ec57..6d68c8a 100644
--- a/drivers/net/ethernet/xilinx/Kconfig
+++ b/drivers/net/ethernet/xilinx/Kconfig
@@ -34,7 +34,6 @@ config XILINX_AXI_EMAC
 config XILINX_LL_TEMAC
 	tristate "Xilinx LL TEMAC (LocalLink Tri-mode Ethernet MAC) driver"
 	depends on (PPC || MICROBLAZE)
-	depends on !64BIT || BROKEN
 	select PHYLIB
 	---help---
 	  This driver supports the Xilinx 10/100/1000 LocalLink TEMAC
diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index fddd1b3..bcafb89 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -619,11 +619,39 @@ static void temac_adjust_link(struct net_device *ndev)
 	mutex_unlock(&lp->indirect_mutex);
 }
 
+#ifdef CONFIG_64BIT
+
+void ptr_to_txbd(void *p, struct cdmac_bd *bd)
+{
+	bd->app3 = (u32)(((u64)p) >> 32);
+	bd->app4 = (u32)((u64)p & 0xFFFFFFFF);
+}
+
+void *ptr_from_txbd(struct cdmac_bd *bd)
+{
+	return (void *)(((u64)(bd->app3) << 32) | bd->app4);
+}
+
+#else
+
+void ptr_to_txbd(void *p, struct cmdac_bd *bd)
+{
+	bd->app4 = (u32)p;
+}
+
+void *ptr_from_txbd(struct cdmac_bd *bd)
+{
+	return (void *)(bd->app4);
+}
+
+#endif
+
 static void temac_start_xmit_done(struct net_device *ndev)
 {
 	struct temac_local *lp = netdev_priv(ndev);
 	struct cdmac_bd *cur_p;
 	unsigned int stat = 0;
+	struct sk_buff *skb;
 
 	cur_p = &lp->tx_bd_v[lp->tx_bd_ci];
 	stat = cur_p->app0;
@@ -631,8 +659,9 @@ static void temac_start_xmit_done(struct net_device *ndev)
 	while (stat & STS_CTRL_APP0_CMPLT) {
 		dma_unmap_single(ndev->dev.parent, cur_p->phys, cur_p->len,
 				 DMA_TO_DEVICE);
-		if (cur_p->app4)
-			dev_consume_skb_irq((struct sk_buff *)cur_p->app4);
+		skb = (struct sk_buff *)ptr_from_txbd(cur_p);
+		if (skb)
+			dev_consume_skb_irq(skb);
 		cur_p->app0 = 0;
 		cur_p->app1 = 0;
 		cur_p->app2 = 0;
@@ -711,7 +740,7 @@ temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 	cur_p->len = skb_headlen(skb);
 	cur_p->phys = dma_map_single(ndev->dev.parent, skb->data,
 				     skb_headlen(skb), DMA_TO_DEVICE);
-	cur_p->app4 = (unsigned long)skb;
+	ptr_to_txbd((void *)skb, cur_p);
 
 	for (ii = 0; ii < num_frag; ii++) {
 		lp->tx_bd_tail++;
-- 
2.4.11


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

* [PATCH 04/12] net: ll_temac: Add support for non-native register endianness
  2019-04-29  8:34 ` [PATCH 00/12] net: ll_temac: x86_64 support Esben Haabendal
                     ` (2 preceding siblings ...)
  2019-04-29  8:34   ` [PATCH 03/12] net: ll_temac: Fix support for 64-bit platforms Esben Haabendal
@ 2019-04-29  8:34   ` Esben Haabendal
  2019-04-29  8:34   ` [PATCH 05/12] net: ll_temac: Fix support for little-endian platforms Esben Haabendal
                     ` (8 subsequent siblings)
  12 siblings, 0 replies; 59+ messages in thread
From: Esben Haabendal @ 2019-04-29  8:34 UTC (permalink / raw)
  To: netdev
  Cc: David S. Miller, Michal Simek, Luis Chamberlain, YueHaibing,
	Yang Wei, linux-arm-kernel, linux-kernel

Replace the powerpc specific MMIO register access functions with the
generic big-endian mmio access functions, and add support for
little-endian access depending on configuration.

Big-endian access is maintained as the default, but little-endian can
be configured in device-tree binding or in platform data.

The temac_ior()/temac_iow() functions are replaced with macro wrappers
to avoid modifying existing code more than necessary.

Signed-off-by: Esben Haabendal <esben@geanix.com>
---
 drivers/net/ethernet/xilinx/ll_temac.h        | 12 ++--
 drivers/net/ethernet/xilinx/ll_temac_main.c   | 87 +++++++++++++++++++++------
 include/linux/platform_data/xilinx-ll-temac.h |  2 +
 3 files changed, 79 insertions(+), 22 deletions(-)

diff --git a/drivers/net/ethernet/xilinx/ll_temac.h b/drivers/net/ethernet/xilinx/ll_temac.h
index e338b4f..23d8dd5 100644
--- a/drivers/net/ethernet/xilinx/ll_temac.h
+++ b/drivers/net/ethernet/xilinx/ll_temac.h
@@ -347,8 +347,10 @@ struct temac_local {
 #ifdef CONFIG_PPC_DCR
 	dcr_host_t sdma_dcrs;
 #endif
-	u32 (*dma_in)(struct temac_local *, int);
-	void (*dma_out)(struct temac_local *, int, u32);
+	u32 (*temac_ior)(struct temac_local *lp, int offset);
+	void (*temac_iow)(struct temac_local *lp, int offset, u32 value);
+	u32 (*dma_in)(struct temac_local *lp, int reg);
+	void (*dma_out)(struct temac_local *lp, int reg, u32 value);
 
 	int tx_irq;
 	int rx_irq;
@@ -372,9 +374,11 @@ struct temac_local {
 	int rx_bd_ci;
 };
 
+/* Wrappers for temac_ior()/temac_iow() function pointers above */
+#define temac_ior(lp, o) ((lp)->temac_ior(lp, o))
+#define temac_iow(lp, o, v) ((lp)->temac_iow(lp, o, v))
+
 /* xilinx_temac.c */
-u32 temac_ior(struct temac_local *lp, int offset);
-void temac_iow(struct temac_local *lp, int offset, u32 value);
 int temac_indirect_busywait(struct temac_local *lp);
 u32 temac_indirect_in32(struct temac_local *lp, int reg);
 void temac_indirect_out32(struct temac_local *lp, int reg, u32 value);
diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index bcafb89..58c6713 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -63,14 +63,24 @@
  * Low level register access functions
  */
 
-u32 temac_ior(struct temac_local *lp, int offset)
+u32 _temac_ior_be(struct temac_local *lp, int offset)
 {
-	return in_be32(lp->regs + offset);
+	return ioread32be(lp->regs + offset);
 }
 
-void temac_iow(struct temac_local *lp, int offset, u32 value)
+void _temac_iow_be(struct temac_local *lp, int offset, u32 value)
 {
-	out_be32(lp->regs + offset, value);
+	return iowrite32be(value, lp->regs + offset);
+}
+
+u32 _temac_ior_le(struct temac_local *lp, int offset)
+{
+	return ioread32(lp->regs + offset);
+}
+
+void _temac_iow_le(struct temac_local *lp, int offset, u32 value)
+{
+	return iowrite32(value, lp->regs + offset);
 }
 
 int temac_indirect_busywait(struct temac_local *lp)
@@ -121,23 +131,35 @@ void temac_indirect_out32(struct temac_local *lp, int reg, u32 value)
 }
 
 /**
- * temac_dma_in32 - Memory mapped DMA read, this function expects a
- * register input that is based on DCR word addresses which
- * are then converted to memory mapped byte addresses
+ * temac_dma_in32_* - Memory mapped DMA read, these function expects a
+ * register input that is based on DCR word addresses which are then
+ * converted to memory mapped byte addresses.  To be assigned to
+ * lp->dma_in32.
  */
-static u32 temac_dma_in32(struct temac_local *lp, int reg)
+static u32 temac_dma_in32_be(struct temac_local *lp, int reg)
 {
-	return in_be32(lp->sdma_regs + (reg << 2));
+	return ioread32be(lp->sdma_regs + (reg << 2));
+}
+
+static u32 temac_dma_in32_le(struct temac_local *lp, int reg)
+{
+	return ioread32(lp->sdma_regs + (reg << 2));
 }
 
 /**
- * temac_dma_out32 - Memory mapped DMA read, this function expects a
- * register input that is based on DCR word addresses which
- * are then converted to memory mapped byte addresses
+ * temac_dma_out32_* - Memory mapped DMA read, these function expects
+ * a register input that is based on DCR word addresses which are then
+ * converted to memory mapped byte addresses.  To be assigned to
+ * lp->dma_out32.
  */
-static void temac_dma_out32(struct temac_local *lp, int reg, u32 value)
+static void temac_dma_out32_be(struct temac_local *lp, int reg, u32 value)
+{
+	iowrite32be(value, lp->sdma_regs + (reg << 2));
+}
+
+static void temac_dma_out32_le(struct temac_local *lp, int reg, u32 value)
 {
-	out_be32(lp->sdma_regs + (reg << 2), value);
+	iowrite32(value, lp->sdma_regs + (reg << 2));
 }
 
 /* DMA register access functions can be DCR based or memory mapped.
@@ -1024,6 +1046,7 @@ static int temac_probe(struct platform_device *pdev)
 	struct resource *res;
 	const void *addr;
 	__be32 *p;
+	bool little_endian;
 	int rc = 0;
 
 	/* Init network device structure */
@@ -1068,6 +1091,24 @@ static int temac_probe(struct platform_device *pdev)
 		return PTR_ERR(lp->regs);
 	}
 
+	/* Select register access functions with the specified
+	 * endianness mode.  Default for OF devices is big-endian.
+	 */
+	little_endian = false;
+	if (temac_np) {
+		if (of_get_property(temac_np, "little-endian", NULL))
+			little_endian = true;
+	} else if (pdata) {
+		little_endian = pdata->reg_little_endian;
+	}
+	if (little_endian) {
+		lp->temac_ior = _temac_ior_le;
+		lp->temac_iow = _temac_iow_le;
+	} else {
+		lp->temac_ior = _temac_ior_be;
+		lp->temac_iow = _temac_iow_be;
+	}
+
 	/* Setup checksum offload, but default to off if not specified */
 	lp->temac_features = 0;
 	if (temac_np) {
@@ -1111,8 +1152,13 @@ static int temac_probe(struct platform_device *pdev)
 				of_node_put(dma_np);
 				return PTR_ERR(lp->sdma_regs);
 			}
-			lp->dma_in = temac_dma_in32;
-			lp->dma_out = temac_dma_out32;
+			if (of_get_property(dma_np, "little-endian", NULL)) {
+				lp->dma_in = temac_dma_in32_le;
+				lp->dma_out = temac_dma_out32_le;
+			} else {
+				lp->dma_in = temac_dma_in32_be;
+				lp->dma_out = temac_dma_out32_be;
+			}
 			dev_dbg(&pdev->dev, "MEM base: %p\n", lp->sdma_regs);
 		}
 
@@ -1132,8 +1178,13 @@ static int temac_probe(struct platform_device *pdev)
 				"could not map DMA registers\n");
 			return PTR_ERR(lp->sdma_regs);
 		}
-		lp->dma_in = temac_dma_in32;
-		lp->dma_out = temac_dma_out32;
+		if (pdata->dma_little_endian) {
+			lp->dma_in = temac_dma_in32_le;
+			lp->dma_out = temac_dma_out32_le;
+		} else {
+			lp->dma_in = temac_dma_in32_be;
+			lp->dma_out = temac_dma_out32_be;
+		}
 
 		/* Get DMA RX and TX interrupts */
 		lp->rx_irq = platform_get_irq(pdev, 0);
diff --git a/include/linux/platform_data/xilinx-ll-temac.h b/include/linux/platform_data/xilinx-ll-temac.h
index 82e2f80..af87927 100644
--- a/include/linux/platform_data/xilinx-ll-temac.h
+++ b/include/linux/platform_data/xilinx-ll-temac.h
@@ -14,6 +14,8 @@ struct ll_temac_platform_data {
 	unsigned long long mdio_bus_id; /* Unique id for MDIO bus */
 	int phy_addr;		/* Address of the PHY to connect to */
 	phy_interface_t phy_interface; /* PHY interface mode */
+	bool reg_little_endian;	/* Little endian TEMAC register access  */
+	bool dma_little_endian;	/* Little endian DMA register access  */
 };
 
 #endif /* __LINUX_XILINX_LL_TEMAC_H */
-- 
2.4.11


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

* [PATCH 05/12] net: ll_temac: Fix support for little-endian platforms
  2019-04-29  8:34 ` [PATCH 00/12] net: ll_temac: x86_64 support Esben Haabendal
                     ` (3 preceding siblings ...)
  2019-04-29  8:34   ` [PATCH 04/12] net: ll_temac: Add support for non-native register endianness Esben Haabendal
@ 2019-04-29  8:34   ` Esben Haabendal
  2019-04-29  8:34   ` [PATCH 06/12] net: ll_temac: Allow use on x86 platforms Esben Haabendal
                     ` (7 subsequent siblings)
  12 siblings, 0 replies; 59+ messages in thread
From: Esben Haabendal @ 2019-04-29  8:34 UTC (permalink / raw)
  To: netdev
  Cc: David S. Miller, Michal Simek, YueHaibing, Yang Wei,
	Luis Chamberlain, linux-arm-kernel, linux-kernel

Both TEMAC and SDMA is big-endian, so make sure that all values in SDMA
buffer descriptors (cmdac_bd) are handled as big-endian, independent of the
host endianness. With all currently supported platforms being big-endian,
this change does not make a change for any of them.

Note, when using app3 and app4 for piggybacking skb pointers there is no
need to care about endianness, as neither TEMAC nor SDMA access app3 and
app4 in TX buffer descriptors.

Signed-off-by: Esben Haabendal <esben@geanix.com>
---
 drivers/net/ethernet/xilinx/ll_temac_main.c | 90 ++++++++++++++++-------------
 1 file changed, 51 insertions(+), 39 deletions(-)

diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index 58c6713..25d9a35 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -258,6 +258,7 @@ static int temac_dma_bd_init(struct net_device *ndev)
 {
 	struct temac_local *lp = netdev_priv(ndev);
 	struct sk_buff *skb;
+	dma_addr_t skb_dma_addr;
 	int i;
 
 	lp->rx_skb = devm_kcalloc(&ndev->dev, RX_BD_NUM, sizeof(*lp->rx_skb),
@@ -280,13 +281,15 @@ static int temac_dma_bd_init(struct net_device *ndev)
 		goto out;
 
 	for (i = 0; i < TX_BD_NUM; i++) {
-		lp->tx_bd_v[i].next = lp->tx_bd_p +
-				sizeof(*lp->tx_bd_v) * ((i + 1) % TX_BD_NUM);
+		lp->tx_bd_v[i].next = cpu_to_be32(
+			lp->tx_bd_p
+			+ sizeof(*lp->tx_bd_v) * ((i + 1) % TX_BD_NUM));
 	}
 
 	for (i = 0; i < RX_BD_NUM; i++) {
-		lp->rx_bd_v[i].next = lp->rx_bd_p +
-				sizeof(*lp->rx_bd_v) * ((i + 1) % RX_BD_NUM);
+		lp->rx_bd_v[i].next = cpu_to_be32(
+			lp->rx_bd_p
+			+ sizeof(*lp->rx_bd_v) * ((i + 1) % RX_BD_NUM));
 
 		skb = netdev_alloc_skb_ip_align(ndev,
 						XTE_MAX_JUMBO_FRAME_SIZE);
@@ -295,12 +298,12 @@ static int temac_dma_bd_init(struct net_device *ndev)
 
 		lp->rx_skb[i] = skb;
 		/* returns physical address of skb->data */
-		lp->rx_bd_v[i].phys = dma_map_single(ndev->dev.parent,
-						     skb->data,
-						     XTE_MAX_JUMBO_FRAME_SIZE,
-						     DMA_FROM_DEVICE);
-		lp->rx_bd_v[i].len = XTE_MAX_JUMBO_FRAME_SIZE;
-		lp->rx_bd_v[i].app0 = STS_CTRL_APP0_IRQONEND;
+		skb_dma_addr = dma_map_single(ndev->dev.parent, skb->data,
+					      XTE_MAX_JUMBO_FRAME_SIZE,
+					      DMA_FROM_DEVICE);
+		lp->rx_bd_v[i].phys = cpu_to_be32(skb_dma_addr);
+		lp->rx_bd_v[i].len = cpu_to_be32(XTE_MAX_JUMBO_FRAME_SIZE);
+		lp->rx_bd_v[i].app0 = cpu_to_be32(STS_CTRL_APP0_IRQONEND);
 	}
 
 	lp->dma_out(lp, TX_CHNL_CTRL, 0x10220400 |
@@ -676,11 +679,11 @@ static void temac_start_xmit_done(struct net_device *ndev)
 	struct sk_buff *skb;
 
 	cur_p = &lp->tx_bd_v[lp->tx_bd_ci];
-	stat = cur_p->app0;
+	stat = be32_to_cpu(cur_p->app0);
 
 	while (stat & STS_CTRL_APP0_CMPLT) {
-		dma_unmap_single(ndev->dev.parent, cur_p->phys, cur_p->len,
-				 DMA_TO_DEVICE);
+		dma_unmap_single(ndev->dev.parent, be32_to_cpu(cur_p->phys),
+				 be32_to_cpu(cur_p->len), DMA_TO_DEVICE);
 		skb = (struct sk_buff *)ptr_from_txbd(cur_p);
 		if (skb)
 			dev_consume_skb_irq(skb);
@@ -691,14 +694,14 @@ static void temac_start_xmit_done(struct net_device *ndev)
 		cur_p->app4 = 0;
 
 		ndev->stats.tx_packets++;
-		ndev->stats.tx_bytes += cur_p->len;
+		ndev->stats.tx_bytes += be32_to_cpu(cur_p->len);
 
 		lp->tx_bd_ci++;
 		if (lp->tx_bd_ci >= TX_BD_NUM)
 			lp->tx_bd_ci = 0;
 
 		cur_p = &lp->tx_bd_v[lp->tx_bd_ci];
-		stat = cur_p->app0;
+		stat = be32_to_cpu(cur_p->app0);
 	}
 
 	netif_wake_queue(ndev);
@@ -732,7 +735,7 @@ temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 {
 	struct temac_local *lp = netdev_priv(ndev);
 	struct cdmac_bd *cur_p;
-	dma_addr_t start_p, tail_p;
+	dma_addr_t start_p, tail_p, skb_dma_addr;
 	int ii;
 	unsigned long num_frag;
 	skb_frag_t *frag;
@@ -753,15 +756,17 @@ temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 		unsigned int csum_start_off = skb_checksum_start_offset(skb);
 		unsigned int csum_index_off = csum_start_off + skb->csum_offset;
 
-		cur_p->app0 |= 1; /* TX Checksum Enabled */
-		cur_p->app1 = (csum_start_off << 16) | csum_index_off;
+		cur_p->app0 |= cpu_to_be32(0x000001); /* TX Checksum Enabled */
+		cur_p->app1 = cpu_to_be32((csum_start_off << 16)
+					  | csum_index_off);
 		cur_p->app2 = 0;  /* initial checksum seed */
 	}
 
-	cur_p->app0 |= STS_CTRL_APP0_SOP;
-	cur_p->len = skb_headlen(skb);
-	cur_p->phys = dma_map_single(ndev->dev.parent, skb->data,
-				     skb_headlen(skb), DMA_TO_DEVICE);
+	cur_p->app0 |= cpu_to_be32(STS_CTRL_APP0_SOP);
+	skb_dma_addr = dma_map_single(ndev->dev.parent, skb->data,
+				      skb_headlen(skb), DMA_TO_DEVICE);
+	cur_p->len = cpu_to_be32(skb_headlen(skb));
+	cur_p->phys = cpu_to_be32(skb_dma_addr);
 	ptr_to_txbd((void *)skb, cur_p);
 
 	for (ii = 0; ii < num_frag; ii++) {
@@ -770,14 +775,15 @@ temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 			lp->tx_bd_tail = 0;
 
 		cur_p = &lp->tx_bd_v[lp->tx_bd_tail];
-		cur_p->phys = dma_map_single(ndev->dev.parent,
-					     skb_frag_address(frag),
-					     skb_frag_size(frag), DMA_TO_DEVICE);
-		cur_p->len = skb_frag_size(frag);
+		skb_dma_addr = dma_map_single(
+			ndev->dev.parent, skb_frag_address(frag),
+			skb_frag_size(frag), DMA_TO_DEVICE);
+		cur_p->phys = cpu_to_be32(skb_dma_addr);
+		cur_p->len = cpu_to_be32(skb_frag_size(frag));
 		cur_p->app0 = 0;
 		frag++;
 	}
-	cur_p->app0 |= STS_CTRL_APP0_EOP;
+	cur_p->app0 |= cpu_to_be32(STS_CTRL_APP0_EOP);
 
 	tail_p = lp->tx_bd_p + sizeof(*lp->tx_bd_v) * lp->tx_bd_tail;
 	lp->tx_bd_tail++;
@@ -799,7 +805,7 @@ static void ll_temac_recv(struct net_device *ndev)
 	struct sk_buff *skb, *new_skb;
 	unsigned int bdstat;
 	struct cdmac_bd *cur_p;
-	dma_addr_t tail_p;
+	dma_addr_t tail_p, skb_dma_addr;
 	int length;
 	unsigned long flags;
 
@@ -808,14 +814,14 @@ static void ll_temac_recv(struct net_device *ndev)
 	tail_p = lp->rx_bd_p + sizeof(*lp->rx_bd_v) * lp->rx_bd_ci;
 	cur_p = &lp->rx_bd_v[lp->rx_bd_ci];
 
-	bdstat = cur_p->app0;
+	bdstat = be32_to_cpu(cur_p->app0);
 	while ((bdstat & STS_CTRL_APP0_CMPLT)) {
 
 		skb = lp->rx_skb[lp->rx_bd_ci];
-		length = cur_p->app4 & 0x3FFF;
+		length = be32_to_cpu(cur_p->app4) & 0x3FFF;
 
-		dma_unmap_single(ndev->dev.parent, cur_p->phys, length,
-				 DMA_FROM_DEVICE);
+		dma_unmap_single(ndev->dev.parent, be32_to_cpu(cur_p->phys),
+				 length, DMA_FROM_DEVICE);
 
 		skb_put(skb, length);
 		skb->protocol = eth_type_trans(skb, ndev);
@@ -826,7 +832,12 @@ static void ll_temac_recv(struct net_device *ndev)
 		    (skb->protocol == htons(ETH_P_IP)) &&
 		    (skb->len > 64)) {
 
-			skb->csum = cur_p->app3 & 0xFFFF;
+			/* Convert from device endianness (be32) to cpu
+			 * endiannes, and if necessary swap the bytes
+			 * (back) for proper IP checksum byte order
+			 * (be16).
+			 */
+			skb->csum = htons(be32_to_cpu(cur_p->app3) & 0xFFFF);
 			skb->ip_summed = CHECKSUM_COMPLETE;
 		}
 
@@ -843,11 +854,12 @@ static void ll_temac_recv(struct net_device *ndev)
 			return;
 		}
 
-		cur_p->app0 = STS_CTRL_APP0_IRQONEND;
-		cur_p->phys = dma_map_single(ndev->dev.parent, new_skb->data,
-					     XTE_MAX_JUMBO_FRAME_SIZE,
-					     DMA_FROM_DEVICE);
-		cur_p->len = XTE_MAX_JUMBO_FRAME_SIZE;
+		cur_p->app0 = cpu_to_be32(STS_CTRL_APP0_IRQONEND);
+		skb_dma_addr = dma_map_single(ndev->dev.parent, new_skb->data,
+					      XTE_MAX_JUMBO_FRAME_SIZE,
+					      DMA_FROM_DEVICE);
+		cur_p->phys = cpu_to_be32(skb_dma_addr);
+		cur_p->len = cpu_to_be32(XTE_MAX_JUMBO_FRAME_SIZE);
 		lp->rx_skb[lp->rx_bd_ci] = new_skb;
 
 		lp->rx_bd_ci++;
@@ -855,7 +867,7 @@ static void ll_temac_recv(struct net_device *ndev)
 			lp->rx_bd_ci = 0;
 
 		cur_p = &lp->rx_bd_v[lp->rx_bd_ci];
-		bdstat = cur_p->app0;
+		bdstat = be32_to_cpu(cur_p->app0);
 	}
 	lp->dma_out(lp, RX_TAILDESC_PTR, tail_p);
 
-- 
2.4.11


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

* [PATCH 06/12] net: ll_temac: Allow use on x86 platforms
  2019-04-29  8:34 ` [PATCH 00/12] net: ll_temac: x86_64 support Esben Haabendal
                     ` (4 preceding siblings ...)
  2019-04-29  8:34   ` [PATCH 05/12] net: ll_temac: Fix support for little-endian platforms Esben Haabendal
@ 2019-04-29  8:34   ` Esben Haabendal
  2019-04-29 22:06     ` Andrew Lunn
  2019-04-29  8:34   ` [PATCH 07/12] net: ll_temac: Support indirect_mutex share within TEMAC IP Esben Haabendal
                     ` (6 subsequent siblings)
  12 siblings, 1 reply; 59+ messages in thread
From: Esben Haabendal @ 2019-04-29  8:34 UTC (permalink / raw)
  To: netdev; +Cc: David S. Miller, Michal Simek, linux-arm-kernel, linux-kernel

With little-endian and 64-bit support in place, the ll_temac driver can
now be used on x86 and x86_64 platforms.

And while at it, enable COMPILE_TEST also.

Signed-off-by: Esben Haabendal <esben@geanix.com>
---
 drivers/net/ethernet/xilinx/Kconfig | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/xilinx/Kconfig b/drivers/net/ethernet/xilinx/Kconfig
index 6d68c8a..db448fa 100644
--- a/drivers/net/ethernet/xilinx/Kconfig
+++ b/drivers/net/ethernet/xilinx/Kconfig
@@ -5,7 +5,7 @@
 config NET_VENDOR_XILINX
 	bool "Xilinx devices"
 	default y
-	depends on PPC || PPC32 || MICROBLAZE || ARCH_ZYNQ || MIPS
+	depends on PPC || PPC32 || MICROBLAZE || ARCH_ZYNQ || MIPS || X86 || COMPILE_TEST
 	---help---
 	  If you have a network (Ethernet) card belonging to this class, say Y.
 
@@ -33,7 +33,7 @@ config XILINX_AXI_EMAC
 
 config XILINX_LL_TEMAC
 	tristate "Xilinx LL TEMAC (LocalLink Tri-mode Ethernet MAC) driver"
-	depends on (PPC || MICROBLAZE)
+	depends on PPC || MICROBLAZE || X86 || COMPILE_TEST
 	select PHYLIB
 	---help---
 	  This driver supports the Xilinx 10/100/1000 LocalLink TEMAC
-- 
2.4.11


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

* [PATCH 07/12] net: ll_temac: Support indirect_mutex share within TEMAC IP
  2019-04-29  8:34 ` [PATCH 00/12] net: ll_temac: x86_64 support Esben Haabendal
                     ` (5 preceding siblings ...)
  2019-04-29  8:34   ` [PATCH 06/12] net: ll_temac: Allow use on x86 platforms Esben Haabendal
@ 2019-04-29  8:34   ` Esben Haabendal
  2019-04-29 22:12     ` Andrew Lunn
  2019-04-29  8:34   ` [PATCH 08/12] net: ll_temac: Fix iommu/swiotlb leak Esben Haabendal
                     ` (5 subsequent siblings)
  12 siblings, 1 reply; 59+ messages in thread
From: Esben Haabendal @ 2019-04-29  8:34 UTC (permalink / raw)
  To: netdev
  Cc: David S. Miller, Michal Simek, Luis Chamberlain, YueHaibing,
	Yang Wei, linux-arm-kernel, linux-kernel

Indirect register access goes through a DCR bus bridge, which
allows only one outstanding transaction.  And to make matters
worse, each TEMAC IP block contains two Ethernet interfaces, and
although they seem to have separate registers for indirect access,
they actually share the registers.  Or to be more specific, MSW, LSW
and CTL registers are physically shared between Ethernet interfaces
in same TEMAC IP, with RDY register being (almost) specificic to
the Ethernet interface.  The 0x10000 bit in RDY reflects combined
bus ready state though.

So we need to take care to synchronize not only within a single
device, but also between devices in same TEMAC IP.

This commit allows to do that with legacy platform devices.

For OF devices, the xlnx,compound parent of the temac node should be
used to find siblings, and setup a shared indirect_mutex between them.
I will leave this work to somebody else, as I don't have hardware to
test that.  No regression is introduced by that, as before this commit
using two Ethernet interfaces in same TEMAC block is simply broken.

Signed-off-by: Esben Haabendal <esben@geanix.com>
---
 drivers/net/ethernet/xilinx/ll_temac.h        |  5 ++++-
 drivers/net/ethernet/xilinx/ll_temac_main.c   | 31 +++++++++++++++++----------
 drivers/net/ethernet/xilinx/ll_temac_mdio.c   | 16 +++++++-------
 include/linux/platform_data/xilinx-ll-temac.h |  6 ++++++
 4 files changed, 38 insertions(+), 20 deletions(-)

diff --git a/drivers/net/ethernet/xilinx/ll_temac.h b/drivers/net/ethernet/xilinx/ll_temac.h
index 23d8dd5..990f9ed 100644
--- a/drivers/net/ethernet/xilinx/ll_temac.h
+++ b/drivers/net/ethernet/xilinx/ll_temac.h
@@ -358,7 +358,10 @@ struct temac_local {
 
 	struct sk_buff **rx_skb;
 	spinlock_t rx_lock;
-	struct mutex indirect_mutex;
+	/* For synchronization of indirect register access.  Must be
+	 * shared mutex between interfaces in same TEMAC block.
+	 */
+	struct mutex *indirect_mutex;
 	u32 options;			/* Current options word */
 	int last_link;
 	unsigned int temac_features;
diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index 25d9a35..1c5d126 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -346,7 +346,7 @@ static void temac_do_set_mac_address(struct net_device *ndev)
 	struct temac_local *lp = netdev_priv(ndev);
 
 	/* set up unicast MAC address filter set its mac address */
-	mutex_lock(&lp->indirect_mutex);
+	mutex_lock(lp->indirect_mutex);
 	temac_indirect_out32(lp, XTE_UAW0_OFFSET,
 			     (ndev->dev_addr[0]) |
 			     (ndev->dev_addr[1] << 8) |
@@ -357,7 +357,7 @@ static void temac_do_set_mac_address(struct net_device *ndev)
 	temac_indirect_out32(lp, XTE_UAW1_OFFSET,
 			     (ndev->dev_addr[4] & 0x000000ff) |
 			     (ndev->dev_addr[5] << 8));
-	mutex_unlock(&lp->indirect_mutex);
+	mutex_unlock(lp->indirect_mutex);
 }
 
 static int temac_init_mac_address(struct net_device *ndev, const void *address)
@@ -386,7 +386,7 @@ static void temac_set_multicast_list(struct net_device *ndev)
 	u32 multi_addr_msw, multi_addr_lsw, val;
 	int i;
 
-	mutex_lock(&lp->indirect_mutex);
+	mutex_lock(lp->indirect_mutex);
 	if (ndev->flags & (IFF_ALLMULTI | IFF_PROMISC) ||
 	    netdev_mc_count(ndev) > MULTICAST_CAM_TABLE_NUM) {
 		/*
@@ -425,7 +425,7 @@ static void temac_set_multicast_list(struct net_device *ndev)
 		temac_indirect_out32(lp, XTE_MAW1_OFFSET, 0);
 		dev_info(&ndev->dev, "Promiscuous mode disabled.\n");
 	}
-	mutex_unlock(&lp->indirect_mutex);
+	mutex_unlock(lp->indirect_mutex);
 }
 
 static struct temac_option {
@@ -517,7 +517,7 @@ static u32 temac_setoptions(struct net_device *ndev, u32 options)
 	struct temac_option *tp = &temac_options[0];
 	int reg;
 
-	mutex_lock(&lp->indirect_mutex);
+	mutex_lock(lp->indirect_mutex);
 	while (tp->opt) {
 		reg = temac_indirect_in32(lp, tp->reg) & ~tp->m_or;
 		if (options & tp->opt)
@@ -526,7 +526,7 @@ static u32 temac_setoptions(struct net_device *ndev, u32 options)
 		tp++;
 	}
 	lp->options |= options;
-	mutex_unlock(&lp->indirect_mutex);
+	mutex_unlock(lp->indirect_mutex);
 
 	return 0;
 }
@@ -545,7 +545,7 @@ static void temac_device_reset(struct net_device *ndev)
 
 	dev_dbg(&ndev->dev, "%s()\n", __func__);
 
-	mutex_lock(&lp->indirect_mutex);
+	mutex_lock(lp->indirect_mutex);
 	/* Reset the receiver and wait for it to finish reset */
 	temac_indirect_out32(lp, XTE_RXC1_OFFSET, XTE_RXC1_RXRST_MASK);
 	timeout = 1000;
@@ -597,7 +597,7 @@ static void temac_device_reset(struct net_device *ndev)
 	temac_indirect_out32(lp, XTE_TXC_OFFSET, 0);
 	temac_indirect_out32(lp, XTE_FCC_OFFSET, XTE_FCC_RXFLO_MASK);
 
-	mutex_unlock(&lp->indirect_mutex);
+	mutex_unlock(lp->indirect_mutex);
 
 	/* Sync default options with HW
 	 * but leave receiver and transmitter disabled.  */
@@ -625,7 +625,7 @@ static void temac_adjust_link(struct net_device *ndev)
 	/* hash together the state values to decide if something has changed */
 	link_state = phy->speed | (phy->duplex << 1) | phy->link;
 
-	mutex_lock(&lp->indirect_mutex);
+	mutex_lock(lp->indirect_mutex);
 	if (lp->last_link != link_state) {
 		mii_speed = temac_indirect_in32(lp, XTE_EMCFG_OFFSET);
 		mii_speed &= ~XTE_EMCFG_LINKSPD_MASK;
@@ -641,7 +641,7 @@ static void temac_adjust_link(struct net_device *ndev)
 		lp->last_link = link_state;
 		phy_print_status(phy);
 	}
-	mutex_unlock(&lp->indirect_mutex);
+	mutex_unlock(lp->indirect_mutex);
 }
 
 #ifdef CONFIG_64BIT
@@ -1092,7 +1092,16 @@ static int temac_probe(struct platform_device *pdev)
 	lp->dev = &pdev->dev;
 	lp->options = XTE_OPTION_DEFAULTS;
 	spin_lock_init(&lp->rx_lock);
-	mutex_init(&lp->indirect_mutex);
+
+	/* Setup mutex for synchronization of indirect register access */
+	if (pdata) {
+		if (!pdata->indirect_mutex) {
+			dev_err(&pdev->dev,
+				"indirect_mutex missing in platform_data\n");
+			return -EINVAL;
+		}
+		lp->indirect_mutex = pdata->indirect_mutex;
+	}
 
 	/* map device registers */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
diff --git a/drivers/net/ethernet/xilinx/ll_temac_mdio.c b/drivers/net/ethernet/xilinx/ll_temac_mdio.c
index c5307e5..c2a1170 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_mdio.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_mdio.c
@@ -29,10 +29,10 @@ static int temac_mdio_read(struct mii_bus *bus, int phy_id, int reg)
 	/* Write the PHY address to the MIIM Access Initiator register.
 	 * When the transfer completes, the PHY register value will appear
 	 * in the LSW0 register */
-	mutex_lock(&lp->indirect_mutex);
+	mutex_lock(lp->indirect_mutex);
 	temac_iow(lp, XTE_LSW0_OFFSET, (phy_id << 5) | reg);
 	rc = temac_indirect_in32(lp, XTE_MIIMAI_OFFSET);
-	mutex_unlock(&lp->indirect_mutex);
+	mutex_unlock(lp->indirect_mutex);
 
 	dev_dbg(lp->dev, "temac_mdio_read(phy_id=%i, reg=%x) == %x\n",
 		phy_id, reg, rc);
@@ -50,10 +50,10 @@ static int temac_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 val)
 	/* First write the desired value into the write data register
 	 * and then write the address into the access initiator register
 	 */
-	mutex_lock(&lp->indirect_mutex);
+	mutex_lock(lp->indirect_mutex);
 	temac_indirect_out32(lp, XTE_MGTDR_OFFSET, val);
 	temac_indirect_out32(lp, XTE_MIIMAI_OFFSET, (phy_id << 5) | reg);
-	mutex_unlock(&lp->indirect_mutex);
+	mutex_unlock(lp->indirect_mutex);
 
 	return 0;
 }
@@ -87,9 +87,9 @@ int temac_mdio_setup(struct temac_local *lp, struct platform_device *pdev)
 
 	/* Enable the MDIO bus by asserting the enable bit and writing
 	 * in the clock config */
-	mutex_lock(&lp->indirect_mutex);
+	mutex_lock(lp->indirect_mutex);
 	temac_indirect_out32(lp, XTE_MC_OFFSET, 1 << 6 | clk_div);
-	mutex_unlock(&lp->indirect_mutex);
+	mutex_unlock(lp->indirect_mutex);
 
 	bus = devm_mdiobus_alloc(&pdev->dev);
 	if (!bus)
@@ -116,10 +116,10 @@ int temac_mdio_setup(struct temac_local *lp, struct platform_device *pdev)
 	if (rc)
 		return rc;
 
-	mutex_lock(&lp->indirect_mutex);
+	mutex_lock(lp->indirect_mutex);
 	dev_dbg(lp->dev, "MDIO bus registered;  MC:%x\n",
 		temac_indirect_in32(lp, XTE_MC_OFFSET));
-	mutex_unlock(&lp->indirect_mutex);
+	mutex_unlock(lp->indirect_mutex);
 	return 0;
 }
 
diff --git a/include/linux/platform_data/xilinx-ll-temac.h b/include/linux/platform_data/xilinx-ll-temac.h
index af87927..b0b8238 100644
--- a/include/linux/platform_data/xilinx-ll-temac.h
+++ b/include/linux/platform_data/xilinx-ll-temac.h
@@ -16,6 +16,12 @@ struct ll_temac_platform_data {
 	phy_interface_t phy_interface; /* PHY interface mode */
 	bool reg_little_endian;	/* Little endian TEMAC register access  */
 	bool dma_little_endian;	/* Little endian DMA register access  */
+	/* Pre-initialized mutex to use for synchronizing indirect
+	 * register access.  When using both interfaces of a single
+	 * TEMAC IP block, the same mutex should be passed here, as
+	 * they share the same DCR bus bridge.
+	 */
+	struct mutex *indirect_mutex;
 };
 
 #endif /* __LINUX_XILINX_LL_TEMAC_H */
-- 
2.4.11


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

* [PATCH 08/12] net: ll_temac: Fix iommu/swiotlb leak
  2019-04-29  8:34 ` [PATCH 00/12] net: ll_temac: x86_64 support Esben Haabendal
                     ` (6 preceding siblings ...)
  2019-04-29  8:34   ` [PATCH 07/12] net: ll_temac: Support indirect_mutex share within TEMAC IP Esben Haabendal
@ 2019-04-29  8:34   ` Esben Haabendal
  2019-04-29  8:34   ` [PATCH 09/12] net: ll_temac: Fix bug causing buffer descriptor overrun Esben Haabendal
                     ` (4 subsequent siblings)
  12 siblings, 0 replies; 59+ messages in thread
From: Esben Haabendal @ 2019-04-29  8:34 UTC (permalink / raw)
  To: netdev
  Cc: David S. Miller, Michal Simek, YueHaibing, Yang Wei,
	Luis Chamberlain, linux-arm-kernel, linux-kernel

Unmap the actual buffer length, not the amount of data received, avoiding
resource exhaustion of swiotlb (seen on x86_64 platform).

Signed-off-by: Esben Haabendal <esben@geanix.com>
---
 drivers/net/ethernet/xilinx/ll_temac_main.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index 1c5d126..72ec338 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -821,7 +821,7 @@ static void ll_temac_recv(struct net_device *ndev)
 		length = be32_to_cpu(cur_p->app4) & 0x3FFF;
 
 		dma_unmap_single(ndev->dev.parent, be32_to_cpu(cur_p->phys),
-				 length, DMA_FROM_DEVICE);
+				 XTE_MAX_JUMBO_FRAME_SIZE, DMA_FROM_DEVICE);
 
 		skb_put(skb, length);
 		skb->protocol = eth_type_trans(skb, ndev);
-- 
2.4.11


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

* [PATCH 09/12] net: ll_temac: Fix bug causing buffer descriptor overrun
  2019-04-29  8:34 ` [PATCH 00/12] net: ll_temac: x86_64 support Esben Haabendal
                     ` (7 preceding siblings ...)
  2019-04-29  8:34   ` [PATCH 08/12] net: ll_temac: Fix iommu/swiotlb leak Esben Haabendal
@ 2019-04-29  8:34   ` Esben Haabendal
  2019-04-29  8:34   ` [PATCH 10/12] net: ll_temac: Replace bad usage of msleep() with usleep_range() Esben Haabendal
                     ` (3 subsequent siblings)
  12 siblings, 0 replies; 59+ messages in thread
From: Esben Haabendal @ 2019-04-29  8:34 UTC (permalink / raw)
  To: netdev
  Cc: David S. Miller, Michal Simek, Luis Chamberlain, YueHaibing,
	Yang Wei, linux-arm-kernel, linux-kernel

As we are actually using a BD for both the skb and each frag contained in
it, the oldest TX BD would be overwritten when there was exactly one BD
less than needed.

Signed-off-by: Esben Haabendal <esben@geanix.com>
---
 drivers/net/ethernet/xilinx/ll_temac_main.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index 72ec338..2d50646 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -745,7 +745,7 @@ temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 	start_p = lp->tx_bd_p + sizeof(*lp->tx_bd_v) * lp->tx_bd_tail;
 	cur_p = &lp->tx_bd_v[lp->tx_bd_tail];
 
-	if (temac_check_tx_bd_space(lp, num_frag)) {
+	if (temac_check_tx_bd_space(lp, num_frag + 1)) {
 		if (!netif_queue_stopped(ndev))
 			netif_stop_queue(ndev);
 		return NETDEV_TX_BUSY;
-- 
2.4.11


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

* [PATCH 10/12] net: ll_temac: Replace bad usage of msleep() with usleep_range()
  2019-04-29  8:34 ` [PATCH 00/12] net: ll_temac: x86_64 support Esben Haabendal
                     ` (8 preceding siblings ...)
  2019-04-29  8:34   ` [PATCH 09/12] net: ll_temac: Fix bug causing buffer descriptor overrun Esben Haabendal
@ 2019-04-29  8:34   ` Esben Haabendal
  2019-04-29  8:34   ` [PATCH 11/12] net: ll_temac: Allow configuration of IRQ coalescing Esben Haabendal
                     ` (2 subsequent siblings)
  12 siblings, 0 replies; 59+ messages in thread
From: Esben Haabendal @ 2019-04-29  8:34 UTC (permalink / raw)
  To: netdev
  Cc: Andrew Lunn, David S. Miller, Michal Simek, YueHaibing,
	Luis Chamberlain, Yang Wei, linux-arm-kernel, linux-kernel

Use usleep_range() to avoid problems with msleep() actually sleeping
much longer than expected.

Signed-off-by: Esben Haabendal <esben@geanix.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
---
 drivers/net/ethernet/xilinx/ll_temac_main.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index 2d50646..5e7b8f0 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -92,7 +92,7 @@ int temac_indirect_busywait(struct temac_local *lp)
 			WARN_ON(1);
 			return -ETIMEDOUT;
 		}
-		msleep(1);
+		usleep_range(500, 1000);
 	}
 	return 0;
 }
-- 
2.4.11


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

* [PATCH 11/12] net: ll_temac: Allow configuration of IRQ coalescing
  2019-04-29  8:34 ` [PATCH 00/12] net: ll_temac: x86_64 support Esben Haabendal
                     ` (9 preceding siblings ...)
  2019-04-29  8:34   ` [PATCH 10/12] net: ll_temac: Replace bad usage of msleep() with usleep_range() Esben Haabendal
@ 2019-04-29  8:34   ` Esben Haabendal
  2019-04-29  8:34   ` [PATCH 12/12] net: ll_temac: Enable DMA when ready, not before Esben Haabendal
  2019-04-30  7:17   ` [PATCH v3 00/12] net: ll_temac: x86_64 support Esben Haabendal
  12 siblings, 0 replies; 59+ messages in thread
From: Esben Haabendal @ 2019-04-29  8:34 UTC (permalink / raw)
  To: netdev
  Cc: David S. Miller, Michal Simek, YueHaibing, Luis Chamberlain,
	Yang Wei, linux-arm-kernel, linux-kernel

This allows custom setup of IRQ coalescing for platforms using legacy
platform_device. The irq timeout and count parameters can be used for
tuning cpu load vs. latency.

I have maintained the 0x00000400 bit in TX_CHNL_CTRL.  It is specified as
unused in the documentation I have available.  It does not make any
difference in the hardware I have available, so it is left in to not risk
breaking other platforms where it might be used.

Signed-off-by: Esben Haabendal <esben@geanix.com>
---
 drivers/net/ethernet/xilinx/ll_temac.h        |  4 +++
 drivers/net/ethernet/xilinx/ll_temac_main.c   | 40 +++++++++++++++++++--------
 include/linux/platform_data/xilinx-ll-temac.h |  5 ++++
 3 files changed, 37 insertions(+), 12 deletions(-)

diff --git a/drivers/net/ethernet/xilinx/ll_temac.h b/drivers/net/ethernet/xilinx/ll_temac.h
index 990f9ed..1aeda08 100644
--- a/drivers/net/ethernet/xilinx/ll_temac.h
+++ b/drivers/net/ethernet/xilinx/ll_temac.h
@@ -375,6 +375,10 @@ struct temac_local {
 	int tx_bd_next;
 	int tx_bd_tail;
 	int rx_bd_ci;
+
+	/* DMA channel control setup */
+	u32 tx_chnl_ctrl;
+	u32 rx_chnl_ctrl;
 };
 
 /* Wrappers for temac_ior()/temac_iow() function pointers above */
diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index 5e7b8f0..5833f02 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -306,18 +306,15 @@ static int temac_dma_bd_init(struct net_device *ndev)
 		lp->rx_bd_v[i].app0 = cpu_to_be32(STS_CTRL_APP0_IRQONEND);
 	}
 
-	lp->dma_out(lp, TX_CHNL_CTRL, 0x10220400 |
-					  CHNL_CTRL_IRQ_EN |
-					  CHNL_CTRL_IRQ_DLY_EN |
-					  CHNL_CTRL_IRQ_COAL_EN);
-	/* 0x10220483 */
-	/* 0x00100483 */
-	lp->dma_out(lp, RX_CHNL_CTRL, 0xff070000 |
-					  CHNL_CTRL_IRQ_EN |
-					  CHNL_CTRL_IRQ_DLY_EN |
-					  CHNL_CTRL_IRQ_COAL_EN |
-					  CHNL_CTRL_IRQ_IOE);
-	/* 0xff010283 */
+	/* Configure DMA channel (irq setup) */
+	lp->dma_out(lp, TX_CHNL_CTRL, lp->tx_chnl_ctrl |
+		    0x00000400 | // Use 1 Bit Wide Counters. Currently Not Used!
+		    CHNL_CTRL_IRQ_EN | CHNL_CTRL_IRQ_ERR_EN |
+		    CHNL_CTRL_IRQ_DLY_EN | CHNL_CTRL_IRQ_COAL_EN);
+	lp->dma_out(lp, RX_CHNL_CTRL, lp->rx_chnl_ctrl |
+		    CHNL_CTRL_IRQ_IOE |
+		    CHNL_CTRL_IRQ_EN | CHNL_CTRL_IRQ_ERR_EN |
+		    CHNL_CTRL_IRQ_DLY_EN | CHNL_CTRL_IRQ_COAL_EN);
 
 	lp->dma_out(lp, RX_CURDESC_PTR,  lp->rx_bd_p);
 	lp->dma_out(lp, RX_TAILDESC_PTR,
@@ -1187,6 +1184,13 @@ static int temac_probe(struct platform_device *pdev)
 		lp->rx_irq = irq_of_parse_and_map(dma_np, 0);
 		lp->tx_irq = irq_of_parse_and_map(dma_np, 1);
 
+		/* Use defaults for IRQ delay/coalescing setup.  These
+		 * are configuration values, so does not belong in
+		 * device-tree.
+		 */
+		lp->tx_chnl_ctrl = 0x10220000;
+		lp->rx_chnl_ctrl = 0xff070000;
+
 		/* Finished with the DMA node; drop the reference */
 		of_node_put(dma_np);
 	} else if (pdata) {
@@ -1210,6 +1214,18 @@ static int temac_probe(struct platform_device *pdev)
 		/* Get DMA RX and TX interrupts */
 		lp->rx_irq = platform_get_irq(pdev, 0);
 		lp->tx_irq = platform_get_irq(pdev, 1);
+
+		/* IRQ delay/coalescing setup */
+		if (pdata->tx_irq_timeout || pdata->tx_irq_count)
+			lp->tx_chnl_ctrl = (pdata->tx_irq_timeout << 24) |
+				(pdata->tx_irq_count << 16);
+		else
+			lp->tx_chnl_ctrl = 0x10220000;
+		if (pdata->rx_irq_timeout || pdata->rx_irq_count)
+			lp->rx_chnl_ctrl = (pdata->rx_irq_timeout << 24) |
+				(pdata->rx_irq_count << 16);
+		else
+			lp->rx_chnl_ctrl = 0xff070000;
 	}
 
 	/* Error handle returned DMA RX and TX interrupts */
diff --git a/include/linux/platform_data/xilinx-ll-temac.h b/include/linux/platform_data/xilinx-ll-temac.h
index b0b8238..368530f 100644
--- a/include/linux/platform_data/xilinx-ll-temac.h
+++ b/include/linux/platform_data/xilinx-ll-temac.h
@@ -22,6 +22,11 @@ struct ll_temac_platform_data {
 	 * they share the same DCR bus bridge.
 	 */
 	struct mutex *indirect_mutex;
+	/* DMA channel control setup */
+	u8 tx_irq_timeout;	/* TX Interrupt Delay Time-out */
+	u8 tx_irq_count;	/* TX Interrupt Coalescing Threshold Count */
+	u8 rx_irq_timeout;	/* RX Interrupt Delay Time-out */
+	u8 rx_irq_count;	/* RX Interrupt Coalescing Threshold Count */
 };
 
 #endif /* __LINUX_XILINX_LL_TEMAC_H */
-- 
2.4.11


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

* [PATCH 12/12] net: ll_temac: Enable DMA when ready, not before
  2019-04-29  8:34 ` [PATCH 00/12] net: ll_temac: x86_64 support Esben Haabendal
                     ` (10 preceding siblings ...)
  2019-04-29  8:34   ` [PATCH 11/12] net: ll_temac: Allow configuration of IRQ coalescing Esben Haabendal
@ 2019-04-29  8:34   ` Esben Haabendal
  2019-04-30  7:17   ` [PATCH v3 00/12] net: ll_temac: x86_64 support Esben Haabendal
  12 siblings, 0 replies; 59+ messages in thread
From: Esben Haabendal @ 2019-04-29  8:34 UTC (permalink / raw)
  To: netdev
  Cc: David S. Miller, Michal Simek, Yang Wei, YueHaibing,
	Luis Chamberlain, linux-arm-kernel, linux-kernel

As soon as TAILDESCR_PTR is written, DMA transfers might start.
Let's ensure we are ready to receive DMA IRQ's before doing that.

Signed-off-by: Esben Haabendal <esben@geanix.com>
---
 drivers/net/ethernet/xilinx/ll_temac_main.c | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index 5833f02..a230f6a 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -316,17 +316,21 @@ static int temac_dma_bd_init(struct net_device *ndev)
 		    CHNL_CTRL_IRQ_EN | CHNL_CTRL_IRQ_ERR_EN |
 		    CHNL_CTRL_IRQ_DLY_EN | CHNL_CTRL_IRQ_COAL_EN);
 
-	lp->dma_out(lp, RX_CURDESC_PTR,  lp->rx_bd_p);
-	lp->dma_out(lp, RX_TAILDESC_PTR,
-		       lp->rx_bd_p + (sizeof(*lp->rx_bd_v) * (RX_BD_NUM - 1)));
-	lp->dma_out(lp, TX_CURDESC_PTR, lp->tx_bd_p);
-
 	/* Init descriptor indexes */
 	lp->tx_bd_ci = 0;
 	lp->tx_bd_next = 0;
 	lp->tx_bd_tail = 0;
 	lp->rx_bd_ci = 0;
 
+	/* Enable RX DMA transfers */
+	wmb();
+	lp->dma_out(lp, RX_CURDESC_PTR,  lp->rx_bd_p);
+	lp->dma_out(lp, RX_TAILDESC_PTR,
+		       lp->rx_bd_p + (sizeof(*lp->rx_bd_v) * (RX_BD_NUM - 1)));
+
+	/* Prepare for TX DMA transfer */
+	lp->dma_out(lp, TX_CURDESC_PTR, lp->tx_bd_p);
+
 	return 0;
 
 out:
@@ -790,6 +794,7 @@ temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 	skb_tx_timestamp(skb);
 
 	/* Kick off the transfer */
+	wmb();
 	lp->dma_out(lp, TX_TAILDESC_PTR, tail_p); /* DMA start */
 
 	return NETDEV_TX_OK;
-- 
2.4.11


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

* Re: [PATCH 03/12] net: ll_temac: Fix support for 64-bit platforms
  2019-04-29  8:34   ` [PATCH 03/12] net: ll_temac: Fix support for 64-bit platforms Esben Haabendal
@ 2019-04-29 22:06     ` Andrew Lunn
  0 siblings, 0 replies; 59+ messages in thread
From: Andrew Lunn @ 2019-04-29 22:06 UTC (permalink / raw)
  To: Esben Haabendal
  Cc: netdev, David S. Miller, Michal Simek, Yang Wei,
	Luis Chamberlain, YueHaibing, linux-arm-kernel, linux-kernel

On Mon, Apr 29, 2019 at 10:34:13AM +0200, Esben Haabendal wrote:
> The use of buffer descriptor APP4 field (32-bit) for storing skb pointer
> obviously does not work on 64-bit platforms.
> As APP3 is also unused, we can use that to store the other half of 64-bit
> pointer values.
> 
> Contrary to what is hinted at in commit message of commit 15bfe05c8d63
> ("net: ethernet: xilinx: Mark XILINX_LL_TEMAC broken on 64-bit")
> there are no other pointers stored in cdmac_bd.
> 
> Signed-off-by: Esben Haabendal <esben@geanix.com>

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

    Andrew

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

* Re: [PATCH 06/12] net: ll_temac: Allow use on x86 platforms
  2019-04-29  8:34   ` [PATCH 06/12] net: ll_temac: Allow use on x86 platforms Esben Haabendal
@ 2019-04-29 22:06     ` Andrew Lunn
  0 siblings, 0 replies; 59+ messages in thread
From: Andrew Lunn @ 2019-04-29 22:06 UTC (permalink / raw)
  To: Esben Haabendal
  Cc: netdev, David S. Miller, Michal Simek, linux-arm-kernel, linux-kernel

On Mon, Apr 29, 2019 at 10:34:16AM +0200, Esben Haabendal wrote:
> With little-endian and 64-bit support in place, the ll_temac driver can
> now be used on x86 and x86_64 platforms.
> 
> And while at it, enable COMPILE_TEST also.
> 
> Signed-off-by: Esben Haabendal <esben@geanix.com>

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

    Andrew

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

* Re: [PATCH 07/12] net: ll_temac: Support indirect_mutex share within TEMAC IP
  2019-04-29  8:34   ` [PATCH 07/12] net: ll_temac: Support indirect_mutex share within TEMAC IP Esben Haabendal
@ 2019-04-29 22:12     ` Andrew Lunn
  2019-04-30  6:54       ` Esben Haabendal
  0 siblings, 1 reply; 59+ messages in thread
From: Andrew Lunn @ 2019-04-29 22:12 UTC (permalink / raw)
  To: Esben Haabendal
  Cc: netdev, David S. Miller, Michal Simek, Luis Chamberlain,
	YueHaibing, Yang Wei, linux-arm-kernel, linux-kernel

> For OF devices, the xlnx,compound parent of the temac node should be
> used to find siblings, and setup a shared indirect_mutex between them.
> I will leave this work to somebody else, as I don't have hardware to
> test that.  No regression is introduced by that, as before this commit
> using two Ethernet interfaces in same TEMAC block is simply broken.

Is that true?

> @@ -1092,7 +1092,16 @@ static int temac_probe(struct platform_device *pdev)
>  	lp->dev = &pdev->dev;
>  	lp->options = XTE_OPTION_DEFAULTS;
>  	spin_lock_init(&lp->rx_lock);
> -	mutex_init(&lp->indirect_mutex);
> +
> +	/* Setup mutex for synchronization of indirect register access */
> +	if (pdata) {
> +		if (!pdata->indirect_mutex) {
> +			dev_err(&pdev->dev,
> +				"indirect_mutex missing in platform_data\n");
> +			return -EINVAL;
> +		}
> +		lp->indirect_mutex = pdata->indirect_mutex;
> +	}

In the OF case, isn't lp->indirect_mutex now a NULL pointer, where as
before it was a valid mutex?

Or did i miss something somewhere?

   Andrew

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

* Re: [PATCH 07/12] net: ll_temac: Support indirect_mutex share within TEMAC IP
  2019-04-29 22:12     ` Andrew Lunn
@ 2019-04-30  6:54       ` Esben Haabendal
  0 siblings, 0 replies; 59+ messages in thread
From: Esben Haabendal @ 2019-04-30  6:54 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: netdev, David S. Miller, Michal Simek, Luis Chamberlain,
	YueHaibing, Yang Wei, linux-arm-kernel, linux-kernel

Andrew Lunn <andrew@lunn.ch> writes:

>> For OF devices, the xlnx,compound parent of the temac node should be
>> used to find siblings, and setup a shared indirect_mutex between them.
>> I will leave this work to somebody else, as I don't have hardware to
>> test that.  No regression is introduced by that, as before this commit
>> using two Ethernet interfaces in same TEMAC block is simply broken.
>
> Is that true?

Ouch, it was in v1.  But I messed up here in v2.  I will fix for v3.

>> @@ -1092,7 +1092,16 @@ static int temac_probe(struct platform_device *pdev)
>>  	lp->dev = &pdev->dev;
>>  	lp->options = XTE_OPTION_DEFAULTS;
>>  	spin_lock_init(&lp->rx_lock);
>> -	mutex_init(&lp->indirect_mutex);
>> +
>> +	/* Setup mutex for synchronization of indirect register access */
>> +	if (pdata) {
>> +		if (!pdata->indirect_mutex) {
>> +			dev_err(&pdev->dev,
>> +				"indirect_mutex missing in platform_data\n");
>> +			return -EINVAL;
>> +		}
>> +		lp->indirect_mutex = pdata->indirect_mutex;
>> +	}
>
> In the OF case, isn't lp->indirect_mutex now a NULL pointer, where as
> before it was a valid mutex?
>
> Or did i miss something somewhere?

No, you did not miss something.  But I did messed up the OF case in v2
of this series.  Sorry.

/Esben

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

* [PATCH v3 00/12] net: ll_temac: x86_64 support
  2019-04-29  8:34 ` [PATCH 00/12] net: ll_temac: x86_64 support Esben Haabendal
                     ` (11 preceding siblings ...)
  2019-04-29  8:34   ` [PATCH 12/12] net: ll_temac: Enable DMA when ready, not before Esben Haabendal
@ 2019-04-30  7:17   ` Esben Haabendal
  2019-04-30  7:17     ` [PATCH v3 01/12] net: ll_temac: Fix and simplify error handling by using devres functions Esben Haabendal
                       ` (12 more replies)
  12 siblings, 13 replies; 59+ messages in thread
From: Esben Haabendal @ 2019-04-30  7:17 UTC (permalink / raw)
  To: netdev, linux-arm-kernel
  Cc: Michal Simek, David S. Miller, Luis Chamberlain, Yang Wei,
	YueHaibing, linux-kernel

This patch series adds support for use of ll_temac driver with
platform_data configuration and fixes endianess and 64-bit problems so
that it can be used on x86_64 platform.

A few bugfixes are also included.

Changes since v2:
  - Fixed lp->indirect_mutex initialization regression for OF
    platforms introduced in v2

Changes since v1:
  - Make indirect_mutex specification mandatory when using platform_data
  - Move header to include/linux/platform_data
  - Enable COMPILE_TEST for XILINX_LL_TEMAC
  - Rebased to v5.1-rc7


Esben Haabendal (12):
  net: ll_temac: Fix and simplify error handling by using devres
    functions
  net: ll_temac: Extend support to non-device-tree platforms
  net: ll_temac: Fix support for 64-bit platforms
  net: ll_temac: Add support for non-native register endianness
  net: ll_temac: Fix support for little-endian platforms
  net: ll_temac: Allow use on x86 platforms
  net: ll_temac: Support indirect_mutex share within TEMAC IP
  net: ll_temac: Fix iommu/swiotlb leak
  net: ll_temac: Fix bug causing buffer descriptor overrun
  net: ll_temac: Replace bad usage of msleep() with usleep_range()
  net: ll_temac: Allow configuration of IRQ coalescing
  net: ll_temac: Enable DMA when ready, not before

 drivers/net/ethernet/xilinx/Kconfig           |   5 +-
 drivers/net/ethernet/xilinx/ll_temac.h        |  26 +-
 drivers/net/ethernet/xilinx/ll_temac_main.c   | 519 +++++++++++++++++---------
 drivers/net/ethernet/xilinx/ll_temac_mdio.c   |  53 +--
 include/linux/platform_data/xilinx-ll-temac.h |  32 ++
 5 files changed, 432 insertions(+), 203 deletions(-)
 create mode 100644 include/linux/platform_data/xilinx-ll-temac.h

-- 
2.4.11


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

* [PATCH v3 01/12] net: ll_temac: Fix and simplify error handling by using devres functions
  2019-04-30  7:17   ` [PATCH v3 00/12] net: ll_temac: x86_64 support Esben Haabendal
@ 2019-04-30  7:17     ` Esben Haabendal
  2019-04-30  7:17     ` [PATCH v3 02/12] net: ll_temac: Extend support to non-device-tree platforms Esben Haabendal
                       ` (11 subsequent siblings)
  12 siblings, 0 replies; 59+ messages in thread
From: Esben Haabendal @ 2019-04-30  7:17 UTC (permalink / raw)
  To: netdev
  Cc: David S. Miller, Michal Simek, YueHaibing, Luis Chamberlain,
	Yang Wei, linux-arm-kernel, linux-kernel

As a side effect, a few error cases are fixed.

If of_iomap() of sdma_regs failed, no error code was returned.  Fixed to
return -ENOMEM similar to of_iomap() fail of regs.

If sysfs_create_group() or register_netdev() failed, lp->phy_node was not
released.

Finally, the order in remove function is corrected to be reverse order
of what is done in probe, i.e. calling temac_mdio_teardown() last, so we
unregister the netdev that most likely is using the mdio_bus first.

Signed-off-by: Esben Haabendal <esben@geanix.com>
---
 drivers/net/ethernet/xilinx/ll_temac.h      |  2 +-
 drivers/net/ethernet/xilinx/ll_temac_main.c | 48 ++++++++++-------------------
 drivers/net/ethernet/xilinx/ll_temac_mdio.c | 14 +++------
 3 files changed, 22 insertions(+), 42 deletions(-)

diff --git a/drivers/net/ethernet/xilinx/ll_temac.h b/drivers/net/ethernet/xilinx/ll_temac.h
index 1075752..4557578 100644
--- a/drivers/net/ethernet/xilinx/ll_temac.h
+++ b/drivers/net/ethernet/xilinx/ll_temac.h
@@ -378,7 +378,7 @@ void temac_indirect_out32(struct temac_local *lp, int reg, u32 value);
 
 
 /* xilinx_temac_mdio.c */
-int temac_mdio_setup(struct temac_local *lp, struct device_node *np);
+int temac_mdio_setup(struct temac_local *lp, struct platform_device *pdev);
 void temac_mdio_teardown(struct temac_local *lp);
 
 #endif /* XILINX_LL_TEMAC_H */
diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index 44efffb..c4e85a9 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -225,7 +225,6 @@ static void temac_dma_bd_release(struct net_device *ndev)
 		dma_free_coherent(ndev->dev.parent,
 				sizeof(*lp->tx_bd_v) * TX_BD_NUM,
 				lp->tx_bd_v, lp->tx_bd_p);
-	kfree(lp->rx_skb);
 }
 
 /**
@@ -237,7 +236,8 @@ static int temac_dma_bd_init(struct net_device *ndev)
 	struct sk_buff *skb;
 	int i;
 
-	lp->rx_skb = kcalloc(RX_BD_NUM, sizeof(*lp->rx_skb), GFP_KERNEL);
+	lp->rx_skb = devm_kcalloc(&ndev->dev, RX_BD_NUM, sizeof(*lp->rx_skb),
+				  GFP_KERNEL);
 	if (!lp->rx_skb)
 		goto out;
 
@@ -987,7 +987,7 @@ static int temac_of_probe(struct platform_device *op)
 	int rc = 0;
 
 	/* Init network device structure */
-	ndev = alloc_etherdev(sizeof(*lp));
+	ndev = devm_alloc_etherdev(&pdev->dev, sizeof(*lp));
 	if (!ndev)
 		return -ENOMEM;
 
@@ -1020,11 +1020,10 @@ static int temac_of_probe(struct platform_device *op)
 	mutex_init(&lp->indirect_mutex);
 
 	/* map device registers */
-	lp->regs = of_iomap(op->dev.of_node, 0);
+	lp->regs = devm_of_iomap(&op->dev, op->dev.of_node, 0, NULL);
 	if (!lp->regs) {
 		dev_err(&op->dev, "could not map temac regs.\n");
-		rc = -ENOMEM;
-		goto nodev;
+		return -ENOMEM;
 	}
 
 	/* Setup checksum offload, but default to off if not specified */
@@ -1043,15 +1042,14 @@ static int temac_of_probe(struct platform_device *op)
 	np = of_parse_phandle(op->dev.of_node, "llink-connected", 0);
 	if (!np) {
 		dev_err(&op->dev, "could not find DMA node\n");
-		rc = -ENODEV;
-		goto err_iounmap;
+		return -ENODEV;
 	}
 
 	/* Setup the DMA register accesses, could be DCR or memory mapped */
 	if (temac_dcr_setup(lp, op, np)) {
 
 		/* no DCR in the device tree, try non-DCR */
-		lp->sdma_regs = of_iomap(np, 0);
+		lp->sdma_regs = devm_of_iomap(&op->dev, np, 0, NULL);
 		if (lp->sdma_regs) {
 			lp->dma_in = temac_dma_in32;
 			lp->dma_out = temac_dma_out32;
@@ -1059,7 +1057,7 @@ static int temac_of_probe(struct platform_device *op)
 		} else {
 			dev_err(&op->dev, "unable to map DMA registers\n");
 			of_node_put(np);
-			goto err_iounmap;
+			return -ENOMEM;
 		}
 	}
 
@@ -1070,8 +1068,7 @@ static int temac_of_probe(struct platform_device *op)
 
 	if (!lp->rx_irq || !lp->tx_irq) {
 		dev_err(&op->dev, "could not determine irqs\n");
-		rc = -ENOMEM;
-		goto err_iounmap_2;
+		return -ENOMEM;
 	}
 
 
@@ -1079,12 +1076,11 @@ static int temac_of_probe(struct platform_device *op)
 	addr = of_get_mac_address(op->dev.of_node);
 	if (!addr) {
 		dev_err(&op->dev, "could not find MAC address\n");
-		rc = -ENODEV;
-		goto err_iounmap_2;
+		return -ENODEV;
 	}
 	temac_init_mac_address(ndev, addr);
 
-	rc = temac_mdio_setup(lp, op->dev.of_node);
+	rc = temac_mdio_setup(lp, pdev);
 	if (rc)
 		dev_warn(&op->dev, "error registering MDIO bus\n");
 
@@ -1096,7 +1092,7 @@ static int temac_of_probe(struct platform_device *op)
 	rc = sysfs_create_group(&lp->dev->kobj, &temac_attr_group);
 	if (rc) {
 		dev_err(lp->dev, "Error creating sysfs files\n");
-		goto err_iounmap_2;
+		goto err_sysfs_create;
 	}
 
 	rc = register_netdev(lp->ndev);
@@ -1107,16 +1103,11 @@ static int temac_of_probe(struct platform_device *op)
 
 	return 0;
 
- err_register_ndev:
+err_register_ndev:
 	sysfs_remove_group(&lp->dev->kobj, &temac_attr_group);
- err_iounmap_2:
-	if (lp->sdma_regs)
-		iounmap(lp->sdma_regs);
- err_iounmap:
-	iounmap(lp->regs);
- nodev:
-	free_netdev(ndev);
-	ndev = NULL;
+err_sysfs_create:
+	of_node_put(lp->phy_node);
+	temac_mdio_teardown(lp);
 	return rc;
 }
 
@@ -1125,15 +1116,10 @@ static int temac_of_remove(struct platform_device *op)
 	struct net_device *ndev = platform_get_drvdata(op);
 	struct temac_local *lp = netdev_priv(ndev);
 
-	temac_mdio_teardown(lp);
 	unregister_netdev(ndev);
 	sysfs_remove_group(&lp->dev->kobj, &temac_attr_group);
 	of_node_put(lp->phy_node);
-	lp->phy_node = NULL;
-	iounmap(lp->regs);
-	if (lp->sdma_regs)
-		iounmap(lp->sdma_regs);
-	free_netdev(ndev);
+	temac_mdio_teardown(lp);
 	return 0;
 }
 
diff --git a/drivers/net/ethernet/xilinx/ll_temac_mdio.c b/drivers/net/ethernet/xilinx/ll_temac_mdio.c
index f5e83ac..a0b365e 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_mdio.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_mdio.c
@@ -57,8 +57,9 @@ static int temac_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 val)
 	return 0;
 }
 
-int temac_mdio_setup(struct temac_local *lp, struct device_node *np)
+int temac_mdio_setup(struct temac_local *lp, struct platform_device *pdev)
 {
+	struct device_node *np = dev_of_node(&pdev->dev);
 	struct mii_bus *bus;
 	u32 bus_hz;
 	int clk_div;
@@ -81,7 +82,7 @@ int temac_mdio_setup(struct temac_local *lp, struct device_node *np)
 	temac_indirect_out32(lp, XTE_MC_OFFSET, 1 << 6 | clk_div);
 	mutex_unlock(&lp->indirect_mutex);
 
-	bus = mdiobus_alloc();
+	bus = devm_mdiobus_alloc(&pdev->dev);
 	if (!bus)
 		return -ENOMEM;
 
@@ -98,23 +99,16 @@ int temac_mdio_setup(struct temac_local *lp, struct device_node *np)
 
 	rc = of_mdiobus_register(bus, np);
 	if (rc)
-		goto err_register;
+		return rc;
 
 	mutex_lock(&lp->indirect_mutex);
 	dev_dbg(lp->dev, "MDIO bus registered;  MC:%x\n",
 		temac_indirect_in32(lp, XTE_MC_OFFSET));
 	mutex_unlock(&lp->indirect_mutex);
 	return 0;
-
- err_register:
-	mdiobus_free(bus);
-	return rc;
 }
 
 void temac_mdio_teardown(struct temac_local *lp)
 {
 	mdiobus_unregister(lp->mii_bus);
-	mdiobus_free(lp->mii_bus);
-	lp->mii_bus = NULL;
 }
-
-- 
2.4.11


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

* [PATCH v3 02/12] net: ll_temac: Extend support to non-device-tree platforms
  2019-04-30  7:17   ` [PATCH v3 00/12] net: ll_temac: x86_64 support Esben Haabendal
  2019-04-30  7:17     ` [PATCH v3 01/12] net: ll_temac: Fix and simplify error handling by using devres functions Esben Haabendal
@ 2019-04-30  7:17     ` Esben Haabendal
  2019-04-30  7:17     ` [PATCH v3 03/12] net: ll_temac: Fix support for 64-bit platforms Esben Haabendal
                       ` (10 subsequent siblings)
  12 siblings, 0 replies; 59+ messages in thread
From: Esben Haabendal @ 2019-04-30  7:17 UTC (permalink / raw)
  To: netdev
  Cc: David S. Miller, Michal Simek, Luis Chamberlain, Yang Wei,
	YueHaibing, linux-kernel, linux-arm-kernel

Support initialization with platdata, so the driver can be used on
non-device-tree platforms.

For currently supported device-tree platforms, the driver should behave
as before.

Signed-off-by: Esben Haabendal <esben@geanix.com>
---
 drivers/net/ethernet/xilinx/ll_temac.h        |   3 +
 drivers/net/ethernet/xilinx/ll_temac_main.c   | 187 +++++++++++++++++---------
 drivers/net/ethernet/xilinx/ll_temac_mdio.c   |  23 +++-
 include/linux/platform_data/xilinx-ll-temac.h |  19 +++
 4 files changed, 166 insertions(+), 66 deletions(-)
 create mode 100644 include/linux/platform_data/xilinx-ll-temac.h

diff --git a/drivers/net/ethernet/xilinx/ll_temac.h b/drivers/net/ethernet/xilinx/ll_temac.h
index 4557578..e338b4f 100644
--- a/drivers/net/ethernet/xilinx/ll_temac.h
+++ b/drivers/net/ethernet/xilinx/ll_temac.h
@@ -334,6 +334,9 @@ struct temac_local {
 
 	/* Connection to PHY device */
 	struct device_node *phy_node;
+	/* For non-device-tree devices */
+	char phy_name[MII_BUS_ID_SIZE + 3];
+	phy_interface_t phy_interface;
 
 	/* MDIO bus data */
 	struct mii_bus *mii_bus;	/* MII bus reference */
diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index c4e85a9..fddd1b3 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -33,6 +33,7 @@
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/netdevice.h>
+#include <linux/if_ether.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_irq.h>
@@ -51,6 +52,7 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/dma-mapping.h>
+#include <linux/platform_data/xilinx-ll-temac.h>
 
 #include "ll_temac.h"
 
@@ -187,7 +189,7 @@ static int temac_dcr_setup(struct temac_local *lp, struct platform_device *op,
 
 /*
  * temac_dcr_setup - This is a stub for when DCR is not supported,
- * such as with MicroBlaze
+ * such as with MicroBlaze and x86
  */
 static int temac_dcr_setup(struct temac_local *lp, struct platform_device *op,
 				struct device_node *np)
@@ -857,7 +859,14 @@ static int temac_open(struct net_device *ndev)
 			dev_err(lp->dev, "of_phy_connect() failed\n");
 			return -ENODEV;
 		}
-
+		phy_start(phydev);
+	} else if (strlen(lp->phy_name) > 0) {
+		phydev = phy_connect(lp->ndev, lp->phy_name, temac_adjust_link,
+				     lp->phy_interface);
+		if (!phydev) {
+			dev_err(lp->dev, "phy_connect() failed\n");
+			return -ENODEV;
+		}
 		phy_start(phydev);
 	}
 
@@ -977,11 +986,13 @@ static const struct ethtool_ops temac_ethtool_ops = {
 	.set_link_ksettings = phy_ethtool_set_link_ksettings,
 };
 
-static int temac_of_probe(struct platform_device *op)
+static int temac_probe(struct platform_device *pdev)
 {
-	struct device_node *np;
+	struct ll_temac_platform_data *pdata = dev_get_platdata(&pdev->dev);
+	struct device_node *temac_np = dev_of_node(&pdev->dev), *dma_np;
 	struct temac_local *lp;
 	struct net_device *ndev;
+	struct resource *res;
 	const void *addr;
 	__be32 *p;
 	int rc = 0;
@@ -991,8 +1002,8 @@ static int temac_of_probe(struct platform_device *op)
 	if (!ndev)
 		return -ENOMEM;
 
-	platform_set_drvdata(op, ndev);
-	SET_NETDEV_DEV(ndev, &op->dev);
+	platform_set_drvdata(pdev, ndev);
+	SET_NETDEV_DEV(ndev, &pdev->dev);
 	ndev->flags &= ~IFF_MULTICAST;  /* clear multicast */
 	ndev->features = NETIF_F_SG;
 	ndev->netdev_ops = &temac_netdev_ops;
@@ -1014,79 +1025,129 @@ static int temac_of_probe(struct platform_device *op)
 	/* setup temac private info structure */
 	lp = netdev_priv(ndev);
 	lp->ndev = ndev;
-	lp->dev = &op->dev;
+	lp->dev = &pdev->dev;
 	lp->options = XTE_OPTION_DEFAULTS;
 	spin_lock_init(&lp->rx_lock);
 	mutex_init(&lp->indirect_mutex);
 
 	/* map device registers */
-	lp->regs = devm_of_iomap(&op->dev, op->dev.of_node, 0, NULL);
-	if (!lp->regs) {
-		dev_err(&op->dev, "could not map temac regs.\n");
-		return -ENOMEM;
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	lp->regs = devm_ioremap_nocache(&pdev->dev, res->start,
+					resource_size(res));
+	if (IS_ERR(lp->regs)) {
+		dev_err(&pdev->dev, "could not map TEMAC registers\n");
+		return PTR_ERR(lp->regs);
 	}
 
 	/* Setup checksum offload, but default to off if not specified */
 	lp->temac_features = 0;
-	p = (__be32 *)of_get_property(op->dev.of_node, "xlnx,txcsum", NULL);
-	if (p && be32_to_cpu(*p)) {
-		lp->temac_features |= TEMAC_FEATURE_TX_CSUM;
+	if (temac_np) {
+		p = (__be32 *)of_get_property(temac_np, "xlnx,txcsum", NULL);
+		if (p && be32_to_cpu(*p))
+			lp->temac_features |= TEMAC_FEATURE_TX_CSUM;
+		p = (__be32 *)of_get_property(temac_np, "xlnx,rxcsum", NULL);
+		if (p && be32_to_cpu(*p))
+			lp->temac_features |= TEMAC_FEATURE_RX_CSUM;
+	} else if (pdata) {
+		if (pdata->txcsum)
+			lp->temac_features |= TEMAC_FEATURE_TX_CSUM;
+		if (pdata->rxcsum)
+			lp->temac_features |= TEMAC_FEATURE_RX_CSUM;
+	}
+	if (lp->temac_features & TEMAC_FEATURE_TX_CSUM)
 		/* Can checksum TCP/UDP over IPv4. */
 		ndev->features |= NETIF_F_IP_CSUM;
-	}
-	p = (__be32 *)of_get_property(op->dev.of_node, "xlnx,rxcsum", NULL);
-	if (p && be32_to_cpu(*p))
-		lp->temac_features |= TEMAC_FEATURE_RX_CSUM;
-
-	/* Find the DMA node, map the DMA registers, and decode the DMA IRQs */
-	np = of_parse_phandle(op->dev.of_node, "llink-connected", 0);
-	if (!np) {
-		dev_err(&op->dev, "could not find DMA node\n");
-		return -ENODEV;
-	}
 
-	/* Setup the DMA register accesses, could be DCR or memory mapped */
-	if (temac_dcr_setup(lp, op, np)) {
+	/* Setup LocalLink DMA */
+	if (temac_np) {
+		/* Find the DMA node, map the DMA registers, and
+		 * decode the DMA IRQs.
+		 */
+		dma_np = of_parse_phandle(temac_np, "llink-connected", 0);
+		if (!dma_np) {
+			dev_err(&pdev->dev, "could not find DMA node\n");
+			return -ENODEV;
+		}
 
-		/* no DCR in the device tree, try non-DCR */
-		lp->sdma_regs = devm_of_iomap(&op->dev, np, 0, NULL);
-		if (lp->sdma_regs) {
+		/* Setup the DMA register accesses, could be DCR or
+		 * memory mapped.
+		 */
+		if (temac_dcr_setup(lp, pdev, dma_np)) {
+			/* no DCR in the device tree, try non-DCR */
+			lp->sdma_regs = devm_of_iomap(&pdev->dev, dma_np, 0,
+						      NULL);
+			if (IS_ERR(lp->sdma_regs)) {
+				dev_err(&pdev->dev,
+					"unable to map DMA registers\n");
+				of_node_put(dma_np);
+				return PTR_ERR(lp->sdma_regs);
+			}
 			lp->dma_in = temac_dma_in32;
 			lp->dma_out = temac_dma_out32;
-			dev_dbg(&op->dev, "MEM base: %p\n", lp->sdma_regs);
-		} else {
-			dev_err(&op->dev, "unable to map DMA registers\n");
-			of_node_put(np);
-			return -ENOMEM;
+			dev_dbg(&pdev->dev, "MEM base: %p\n", lp->sdma_regs);
 		}
-	}
-
-	lp->rx_irq = irq_of_parse_and_map(np, 0);
-	lp->tx_irq = irq_of_parse_and_map(np, 1);
 
-	of_node_put(np); /* Finished with the DMA node; drop the reference */
+		/* Get DMA RX and TX interrupts */
+		lp->rx_irq = irq_of_parse_and_map(dma_np, 0);
+		lp->tx_irq = irq_of_parse_and_map(dma_np, 1);
+
+		/* Finished with the DMA node; drop the reference */
+		of_node_put(dma_np);
+	} else if (pdata) {
+		/* 2nd memory resource specifies DMA registers */
+		res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+		lp->sdma_regs = devm_ioremap_nocache(&pdev->dev, res->start,
+						     resource_size(res));
+		if (IS_ERR(lp->sdma_regs)) {
+			dev_err(&pdev->dev,
+				"could not map DMA registers\n");
+			return PTR_ERR(lp->sdma_regs);
+		}
+		lp->dma_in = temac_dma_in32;
+		lp->dma_out = temac_dma_out32;
 
-	if (!lp->rx_irq || !lp->tx_irq) {
-		dev_err(&op->dev, "could not determine irqs\n");
-		return -ENOMEM;
+		/* Get DMA RX and TX interrupts */
+		lp->rx_irq = platform_get_irq(pdev, 0);
+		lp->tx_irq = platform_get_irq(pdev, 1);
 	}
 
+	/* Error handle returned DMA RX and TX interrupts */
+	if (lp->rx_irq < 0) {
+		if (lp->rx_irq != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "could not get DMA RX irq\n");
+		return lp->rx_irq;
+	}
+	if (lp->tx_irq < 0) {
+		if (lp->tx_irq != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "could not get DMA TX irq\n");
+		return lp->tx_irq;
+	}
 
-	/* Retrieve the MAC address */
-	addr = of_get_mac_address(op->dev.of_node);
-	if (!addr) {
-		dev_err(&op->dev, "could not find MAC address\n");
-		return -ENODEV;
+	if (temac_np) {
+		/* Retrieve the MAC address */
+		addr = of_get_mac_address(temac_np);
+		if (!addr) {
+			dev_err(&pdev->dev, "could not find MAC address\n");
+			return -ENODEV;
+		}
+		temac_init_mac_address(ndev, addr);
+	} else if (pdata) {
+		temac_init_mac_address(ndev, pdata->mac_addr);
 	}
-	temac_init_mac_address(ndev, addr);
 
 	rc = temac_mdio_setup(lp, pdev);
 	if (rc)
-		dev_warn(&op->dev, "error registering MDIO bus\n");
-
-	lp->phy_node = of_parse_phandle(op->dev.of_node, "phy-handle", 0);
-	if (lp->phy_node)
-		dev_dbg(lp->dev, "using PHY node %pOF (%p)\n", np, np);
+		dev_warn(&pdev->dev, "error registering MDIO bus\n");
+
+	if (temac_np) {
+		lp->phy_node = of_parse_phandle(temac_np, "phy-handle", 0);
+		if (lp->phy_node)
+			dev_dbg(lp->dev, "using PHY node %pOF\n", temac_np);
+	} else if (pdata) {
+		snprintf(lp->phy_name, sizeof(lp->phy_name),
+			 PHY_ID_FMT, lp->mii_bus->id, pdata->phy_addr);
+		lp->phy_interface = pdata->phy_interface;
+	}
 
 	/* Add the device attributes */
 	rc = sysfs_create_group(&lp->dev->kobj, &temac_attr_group);
@@ -1106,19 +1167,21 @@ static int temac_of_probe(struct platform_device *op)
 err_register_ndev:
 	sysfs_remove_group(&lp->dev->kobj, &temac_attr_group);
 err_sysfs_create:
-	of_node_put(lp->phy_node);
+	if (lp->phy_node)
+		of_node_put(lp->phy_node);
 	temac_mdio_teardown(lp);
 	return rc;
 }
 
-static int temac_of_remove(struct platform_device *op)
+static int temac_remove(struct platform_device *pdev)
 {
-	struct net_device *ndev = platform_get_drvdata(op);
+	struct net_device *ndev = platform_get_drvdata(pdev);
 	struct temac_local *lp = netdev_priv(ndev);
 
 	unregister_netdev(ndev);
 	sysfs_remove_group(&lp->dev->kobj, &temac_attr_group);
-	of_node_put(lp->phy_node);
+	if (lp->phy_node)
+		of_node_put(lp->phy_node);
 	temac_mdio_teardown(lp);
 	return 0;
 }
@@ -1132,16 +1195,16 @@ static const struct of_device_id temac_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, temac_of_match);
 
-static struct platform_driver temac_of_driver = {
-	.probe = temac_of_probe,
-	.remove = temac_of_remove,
+static struct platform_driver temac_driver = {
+	.probe = temac_probe,
+	.remove = temac_remove,
 	.driver = {
 		.name = "xilinx_temac",
 		.of_match_table = temac_of_match,
 	},
 };
 
-module_platform_driver(temac_of_driver);
+module_platform_driver(temac_driver);
 
 MODULE_DESCRIPTION("Xilinx LL_TEMAC Ethernet driver");
 MODULE_AUTHOR("Yoshio Kashiwagi");
diff --git a/drivers/net/ethernet/xilinx/ll_temac_mdio.c b/drivers/net/ethernet/xilinx/ll_temac_mdio.c
index a0b365e..c5307e5 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_mdio.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_mdio.c
@@ -14,6 +14,7 @@
 #include <linux/of_address.h>
 #include <linux/slab.h>
 #include <linux/of_mdio.h>
+#include <linux/platform_data/xilinx-ll-temac.h>
 
 #include "ll_temac.h"
 
@@ -59,6 +60,7 @@ static int temac_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 val)
 
 int temac_mdio_setup(struct temac_local *lp, struct platform_device *pdev)
 {
+	struct ll_temac_platform_data *pdata = dev_get_platdata(&pdev->dev);
 	struct device_node *np = dev_of_node(&pdev->dev);
 	struct mii_bus *bus;
 	u32 bus_hz;
@@ -66,9 +68,16 @@ int temac_mdio_setup(struct temac_local *lp, struct platform_device *pdev)
 	int rc;
 	struct resource res;
 
+	/* Get MDIO bus frequency (if specified) */
+	bus_hz = 0;
+	if (np)
+		of_property_read_u32(np, "clock-frequency", &bus_hz);
+	else if (pdata)
+		bus_hz = pdata->mdio_clk_freq;
+
 	/* Calculate a reasonable divisor for the clock rate */
 	clk_div = 0x3f; /* worst-case default setting */
-	if (of_property_read_u32(np, "clock-frequency", &bus_hz) == 0) {
+	if (bus_hz != 0) {
 		clk_div = bus_hz / (2500 * 1000 * 2) - 1;
 		if (clk_div < 1)
 			clk_div = 1;
@@ -86,9 +95,15 @@ int temac_mdio_setup(struct temac_local *lp, struct platform_device *pdev)
 	if (!bus)
 		return -ENOMEM;
 
-	of_address_to_resource(np, 0, &res);
-	snprintf(bus->id, MII_BUS_ID_SIZE, "%.8llx",
-		 (unsigned long long)res.start);
+	if (np) {
+		of_address_to_resource(np, 0, &res);
+		snprintf(bus->id, MII_BUS_ID_SIZE, "%.8llx",
+			 (unsigned long long)res.start);
+	} else if (pdata && pdata->mdio_bus_id >= 0) {
+		snprintf(bus->id, MII_BUS_ID_SIZE, "%.8llx",
+			 pdata->mdio_bus_id);
+	}
+
 	bus->priv = lp;
 	bus->name = "Xilinx TEMAC MDIO";
 	bus->read = temac_mdio_read;
diff --git a/include/linux/platform_data/xilinx-ll-temac.h b/include/linux/platform_data/xilinx-ll-temac.h
new file mode 100644
index 0000000..82e2f80
--- /dev/null
+++ b/include/linux/platform_data/xilinx-ll-temac.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __LINUX_XILINX_LL_TEMAC_H
+#define __LINUX_XILINX_LL_TEMAC_H
+
+#include <linux/if_ether.h>
+#include <linux/phy.h>
+
+struct ll_temac_platform_data {
+	bool txcsum;		/* Enable/disable TX checksum */
+	bool rxcsum;		/* Enable/disable RX checksum */
+	u8 mac_addr[ETH_ALEN];	/* MAC address (6 bytes) */
+	/* Clock frequency for input to MDIO clock generator */
+	u32 mdio_clk_freq;
+	unsigned long long mdio_bus_id; /* Unique id for MDIO bus */
+	int phy_addr;		/* Address of the PHY to connect to */
+	phy_interface_t phy_interface; /* PHY interface mode */
+};
+
+#endif /* __LINUX_XILINX_LL_TEMAC_H */
-- 
2.4.11


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

* [PATCH v3 03/12] net: ll_temac: Fix support for 64-bit platforms
  2019-04-30  7:17   ` [PATCH v3 00/12] net: ll_temac: x86_64 support Esben Haabendal
  2019-04-30  7:17     ` [PATCH v3 01/12] net: ll_temac: Fix and simplify error handling by using devres functions Esben Haabendal
  2019-04-30  7:17     ` [PATCH v3 02/12] net: ll_temac: Extend support to non-device-tree platforms Esben Haabendal
@ 2019-04-30  7:17     ` Esben Haabendal
  2019-04-30  7:17     ` [PATCH v3 04/12] net: ll_temac: Add support for non-native register endianness Esben Haabendal
                       ` (9 subsequent siblings)
  12 siblings, 0 replies; 59+ messages in thread
From: Esben Haabendal @ 2019-04-30  7:17 UTC (permalink / raw)
  To: netdev
  Cc: Andrew Lunn, David S. Miller, Michal Simek, Luis Chamberlain,
	YueHaibing, Yang Wei, linux-arm-kernel, linux-kernel

The use of buffer descriptor APP4 field (32-bit) for storing skb pointer
obviously does not work on 64-bit platforms.
As APP3 is also unused, we can use that to store the other half of 64-bit
pointer values.

Contrary to what is hinted at in commit message of commit 15bfe05c8d63
("net: ethernet: xilinx: Mark XILINX_LL_TEMAC broken on 64-bit")
there are no other pointers stored in cdmac_bd.

Signed-off-by: Esben Haabendal <esben@geanix.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
---
 drivers/net/ethernet/xilinx/Kconfig         |  1 -
 drivers/net/ethernet/xilinx/ll_temac_main.c | 35 ++++++++++++++++++++++++++---
 2 files changed, 32 insertions(+), 4 deletions(-)

diff --git a/drivers/net/ethernet/xilinx/Kconfig b/drivers/net/ethernet/xilinx/Kconfig
index da4ec57..6d68c8a 100644
--- a/drivers/net/ethernet/xilinx/Kconfig
+++ b/drivers/net/ethernet/xilinx/Kconfig
@@ -34,7 +34,6 @@ config XILINX_AXI_EMAC
 config XILINX_LL_TEMAC
 	tristate "Xilinx LL TEMAC (LocalLink Tri-mode Ethernet MAC) driver"
 	depends on (PPC || MICROBLAZE)
-	depends on !64BIT || BROKEN
 	select PHYLIB
 	---help---
 	  This driver supports the Xilinx 10/100/1000 LocalLink TEMAC
diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index fddd1b3..bcafb89 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -619,11 +619,39 @@ static void temac_adjust_link(struct net_device *ndev)
 	mutex_unlock(&lp->indirect_mutex);
 }
 
+#ifdef CONFIG_64BIT
+
+void ptr_to_txbd(void *p, struct cdmac_bd *bd)
+{
+	bd->app3 = (u32)(((u64)p) >> 32);
+	bd->app4 = (u32)((u64)p & 0xFFFFFFFF);
+}
+
+void *ptr_from_txbd(struct cdmac_bd *bd)
+{
+	return (void *)(((u64)(bd->app3) << 32) | bd->app4);
+}
+
+#else
+
+void ptr_to_txbd(void *p, struct cmdac_bd *bd)
+{
+	bd->app4 = (u32)p;
+}
+
+void *ptr_from_txbd(struct cdmac_bd *bd)
+{
+	return (void *)(bd->app4);
+}
+
+#endif
+
 static void temac_start_xmit_done(struct net_device *ndev)
 {
 	struct temac_local *lp = netdev_priv(ndev);
 	struct cdmac_bd *cur_p;
 	unsigned int stat = 0;
+	struct sk_buff *skb;
 
 	cur_p = &lp->tx_bd_v[lp->tx_bd_ci];
 	stat = cur_p->app0;
@@ -631,8 +659,9 @@ static void temac_start_xmit_done(struct net_device *ndev)
 	while (stat & STS_CTRL_APP0_CMPLT) {
 		dma_unmap_single(ndev->dev.parent, cur_p->phys, cur_p->len,
 				 DMA_TO_DEVICE);
-		if (cur_p->app4)
-			dev_consume_skb_irq((struct sk_buff *)cur_p->app4);
+		skb = (struct sk_buff *)ptr_from_txbd(cur_p);
+		if (skb)
+			dev_consume_skb_irq(skb);
 		cur_p->app0 = 0;
 		cur_p->app1 = 0;
 		cur_p->app2 = 0;
@@ -711,7 +740,7 @@ temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 	cur_p->len = skb_headlen(skb);
 	cur_p->phys = dma_map_single(ndev->dev.parent, skb->data,
 				     skb_headlen(skb), DMA_TO_DEVICE);
-	cur_p->app4 = (unsigned long)skb;
+	ptr_to_txbd((void *)skb, cur_p);
 
 	for (ii = 0; ii < num_frag; ii++) {
 		lp->tx_bd_tail++;
-- 
2.4.11


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

* [PATCH v3 04/12] net: ll_temac: Add support for non-native register endianness
  2019-04-30  7:17   ` [PATCH v3 00/12] net: ll_temac: x86_64 support Esben Haabendal
                       ` (2 preceding siblings ...)
  2019-04-30  7:17     ` [PATCH v3 03/12] net: ll_temac: Fix support for 64-bit platforms Esben Haabendal
@ 2019-04-30  7:17     ` Esben Haabendal
  2019-04-30  7:17     ` [PATCH v3 05/12] net: ll_temac: Fix support for little-endian platforms Esben Haabendal
                       ` (8 subsequent siblings)
  12 siblings, 0 replies; 59+ messages in thread
From: Esben Haabendal @ 2019-04-30  7:17 UTC (permalink / raw)
  To: netdev
  Cc: David S. Miller, Michal Simek, Luis Chamberlain, YueHaibing,
	Yang Wei, linux-arm-kernel, linux-kernel

Replace the powerpc specific MMIO register access functions with the
generic big-endian mmio access functions, and add support for
little-endian access depending on configuration.

Big-endian access is maintained as the default, but little-endian can
be configured in device-tree binding or in platform data.

The temac_ior()/temac_iow() functions are replaced with macro wrappers
to avoid modifying existing code more than necessary.

Signed-off-by: Esben Haabendal <esben@geanix.com>
---
 drivers/net/ethernet/xilinx/ll_temac.h        | 12 ++--
 drivers/net/ethernet/xilinx/ll_temac_main.c   | 87 +++++++++++++++++++++------
 include/linux/platform_data/xilinx-ll-temac.h |  2 +
 3 files changed, 79 insertions(+), 22 deletions(-)

diff --git a/drivers/net/ethernet/xilinx/ll_temac.h b/drivers/net/ethernet/xilinx/ll_temac.h
index e338b4f..23d8dd5 100644
--- a/drivers/net/ethernet/xilinx/ll_temac.h
+++ b/drivers/net/ethernet/xilinx/ll_temac.h
@@ -347,8 +347,10 @@ struct temac_local {
 #ifdef CONFIG_PPC_DCR
 	dcr_host_t sdma_dcrs;
 #endif
-	u32 (*dma_in)(struct temac_local *, int);
-	void (*dma_out)(struct temac_local *, int, u32);
+	u32 (*temac_ior)(struct temac_local *lp, int offset);
+	void (*temac_iow)(struct temac_local *lp, int offset, u32 value);
+	u32 (*dma_in)(struct temac_local *lp, int reg);
+	void (*dma_out)(struct temac_local *lp, int reg, u32 value);
 
 	int tx_irq;
 	int rx_irq;
@@ -372,9 +374,11 @@ struct temac_local {
 	int rx_bd_ci;
 };
 
+/* Wrappers for temac_ior()/temac_iow() function pointers above */
+#define temac_ior(lp, o) ((lp)->temac_ior(lp, o))
+#define temac_iow(lp, o, v) ((lp)->temac_iow(lp, o, v))
+
 /* xilinx_temac.c */
-u32 temac_ior(struct temac_local *lp, int offset);
-void temac_iow(struct temac_local *lp, int offset, u32 value);
 int temac_indirect_busywait(struct temac_local *lp);
 u32 temac_indirect_in32(struct temac_local *lp, int reg);
 void temac_indirect_out32(struct temac_local *lp, int reg, u32 value);
diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index bcafb89..58c6713 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -63,14 +63,24 @@
  * Low level register access functions
  */
 
-u32 temac_ior(struct temac_local *lp, int offset)
+u32 _temac_ior_be(struct temac_local *lp, int offset)
 {
-	return in_be32(lp->regs + offset);
+	return ioread32be(lp->regs + offset);
 }
 
-void temac_iow(struct temac_local *lp, int offset, u32 value)
+void _temac_iow_be(struct temac_local *lp, int offset, u32 value)
 {
-	out_be32(lp->regs + offset, value);
+	return iowrite32be(value, lp->regs + offset);
+}
+
+u32 _temac_ior_le(struct temac_local *lp, int offset)
+{
+	return ioread32(lp->regs + offset);
+}
+
+void _temac_iow_le(struct temac_local *lp, int offset, u32 value)
+{
+	return iowrite32(value, lp->regs + offset);
 }
 
 int temac_indirect_busywait(struct temac_local *lp)
@@ -121,23 +131,35 @@ void temac_indirect_out32(struct temac_local *lp, int reg, u32 value)
 }
 
 /**
- * temac_dma_in32 - Memory mapped DMA read, this function expects a
- * register input that is based on DCR word addresses which
- * are then converted to memory mapped byte addresses
+ * temac_dma_in32_* - Memory mapped DMA read, these function expects a
+ * register input that is based on DCR word addresses which are then
+ * converted to memory mapped byte addresses.  To be assigned to
+ * lp->dma_in32.
  */
-static u32 temac_dma_in32(struct temac_local *lp, int reg)
+static u32 temac_dma_in32_be(struct temac_local *lp, int reg)
 {
-	return in_be32(lp->sdma_regs + (reg << 2));
+	return ioread32be(lp->sdma_regs + (reg << 2));
+}
+
+static u32 temac_dma_in32_le(struct temac_local *lp, int reg)
+{
+	return ioread32(lp->sdma_regs + (reg << 2));
 }
 
 /**
- * temac_dma_out32 - Memory mapped DMA read, this function expects a
- * register input that is based on DCR word addresses which
- * are then converted to memory mapped byte addresses
+ * temac_dma_out32_* - Memory mapped DMA read, these function expects
+ * a register input that is based on DCR word addresses which are then
+ * converted to memory mapped byte addresses.  To be assigned to
+ * lp->dma_out32.
  */
-static void temac_dma_out32(struct temac_local *lp, int reg, u32 value)
+static void temac_dma_out32_be(struct temac_local *lp, int reg, u32 value)
+{
+	iowrite32be(value, lp->sdma_regs + (reg << 2));
+}
+
+static void temac_dma_out32_le(struct temac_local *lp, int reg, u32 value)
 {
-	out_be32(lp->sdma_regs + (reg << 2), value);
+	iowrite32(value, lp->sdma_regs + (reg << 2));
 }
 
 /* DMA register access functions can be DCR based or memory mapped.
@@ -1024,6 +1046,7 @@ static int temac_probe(struct platform_device *pdev)
 	struct resource *res;
 	const void *addr;
 	__be32 *p;
+	bool little_endian;
 	int rc = 0;
 
 	/* Init network device structure */
@@ -1068,6 +1091,24 @@ static int temac_probe(struct platform_device *pdev)
 		return PTR_ERR(lp->regs);
 	}
 
+	/* Select register access functions with the specified
+	 * endianness mode.  Default for OF devices is big-endian.
+	 */
+	little_endian = false;
+	if (temac_np) {
+		if (of_get_property(temac_np, "little-endian", NULL))
+			little_endian = true;
+	} else if (pdata) {
+		little_endian = pdata->reg_little_endian;
+	}
+	if (little_endian) {
+		lp->temac_ior = _temac_ior_le;
+		lp->temac_iow = _temac_iow_le;
+	} else {
+		lp->temac_ior = _temac_ior_be;
+		lp->temac_iow = _temac_iow_be;
+	}
+
 	/* Setup checksum offload, but default to off if not specified */
 	lp->temac_features = 0;
 	if (temac_np) {
@@ -1111,8 +1152,13 @@ static int temac_probe(struct platform_device *pdev)
 				of_node_put(dma_np);
 				return PTR_ERR(lp->sdma_regs);
 			}
-			lp->dma_in = temac_dma_in32;
-			lp->dma_out = temac_dma_out32;
+			if (of_get_property(dma_np, "little-endian", NULL)) {
+				lp->dma_in = temac_dma_in32_le;
+				lp->dma_out = temac_dma_out32_le;
+			} else {
+				lp->dma_in = temac_dma_in32_be;
+				lp->dma_out = temac_dma_out32_be;
+			}
 			dev_dbg(&pdev->dev, "MEM base: %p\n", lp->sdma_regs);
 		}
 
@@ -1132,8 +1178,13 @@ static int temac_probe(struct platform_device *pdev)
 				"could not map DMA registers\n");
 			return PTR_ERR(lp->sdma_regs);
 		}
-		lp->dma_in = temac_dma_in32;
-		lp->dma_out = temac_dma_out32;
+		if (pdata->dma_little_endian) {
+			lp->dma_in = temac_dma_in32_le;
+			lp->dma_out = temac_dma_out32_le;
+		} else {
+			lp->dma_in = temac_dma_in32_be;
+			lp->dma_out = temac_dma_out32_be;
+		}
 
 		/* Get DMA RX and TX interrupts */
 		lp->rx_irq = platform_get_irq(pdev, 0);
diff --git a/include/linux/platform_data/xilinx-ll-temac.h b/include/linux/platform_data/xilinx-ll-temac.h
index 82e2f80..af87927 100644
--- a/include/linux/platform_data/xilinx-ll-temac.h
+++ b/include/linux/platform_data/xilinx-ll-temac.h
@@ -14,6 +14,8 @@ struct ll_temac_platform_data {
 	unsigned long long mdio_bus_id; /* Unique id for MDIO bus */
 	int phy_addr;		/* Address of the PHY to connect to */
 	phy_interface_t phy_interface; /* PHY interface mode */
+	bool reg_little_endian;	/* Little endian TEMAC register access  */
+	bool dma_little_endian;	/* Little endian DMA register access  */
 };
 
 #endif /* __LINUX_XILINX_LL_TEMAC_H */
-- 
2.4.11


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

* [PATCH v3 05/12] net: ll_temac: Fix support for little-endian platforms
  2019-04-30  7:17   ` [PATCH v3 00/12] net: ll_temac: x86_64 support Esben Haabendal
                       ` (3 preceding siblings ...)
  2019-04-30  7:17     ` [PATCH v3 04/12] net: ll_temac: Add support for non-native register endianness Esben Haabendal
@ 2019-04-30  7:17     ` Esben Haabendal
  2019-04-30  7:17     ` [PATCH v3 06/12] net: ll_temac: Allow use on x86 platforms Esben Haabendal
                       ` (7 subsequent siblings)
  12 siblings, 0 replies; 59+ messages in thread
From: Esben Haabendal @ 2019-04-30  7:17 UTC (permalink / raw)
  To: netdev
  Cc: David S. Miller, Michal Simek, Luis Chamberlain, YueHaibing,
	Yang Wei, linux-arm-kernel, linux-kernel

Both TEMAC and SDMA is big-endian, so make sure that all values in SDMA
buffer descriptors (cmdac_bd) are handled as big-endian, independent of the
host endianness. With all currently supported platforms being big-endian,
this change does not make a change for any of them.

Note, when using app3 and app4 for piggybacking skb pointers there is no
need to care about endianness, as neither TEMAC nor SDMA access app3 and
app4 in TX buffer descriptors.

Signed-off-by: Esben Haabendal <esben@geanix.com>
---
 drivers/net/ethernet/xilinx/ll_temac_main.c | 89 ++++++++++++++++-------------
 1 file changed, 50 insertions(+), 39 deletions(-)

diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index 58c6713..179a998 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -258,6 +258,7 @@ static int temac_dma_bd_init(struct net_device *ndev)
 {
 	struct temac_local *lp = netdev_priv(ndev);
 	struct sk_buff *skb;
+	dma_addr_t skb_dma_addr;
 	int i;
 
 	lp->rx_skb = devm_kcalloc(&ndev->dev, RX_BD_NUM, sizeof(*lp->rx_skb),
@@ -280,13 +281,13 @@ static int temac_dma_bd_init(struct net_device *ndev)
 		goto out;
 
 	for (i = 0; i < TX_BD_NUM; i++) {
-		lp->tx_bd_v[i].next = lp->tx_bd_p +
-				sizeof(*lp->tx_bd_v) * ((i + 1) % TX_BD_NUM);
+		lp->tx_bd_v[i].next = cpu_to_be32(lp->tx_bd_p
+				+ sizeof(*lp->tx_bd_v) * ((i + 1) % TX_BD_NUM));
 	}
 
 	for (i = 0; i < RX_BD_NUM; i++) {
-		lp->rx_bd_v[i].next = lp->rx_bd_p +
-				sizeof(*lp->rx_bd_v) * ((i + 1) % RX_BD_NUM);
+		lp->rx_bd_v[i].next = cpu_to_be32(lp->rx_bd_p
+				+ sizeof(*lp->rx_bd_v) * ((i + 1) % RX_BD_NUM));
 
 		skb = netdev_alloc_skb_ip_align(ndev,
 						XTE_MAX_JUMBO_FRAME_SIZE);
@@ -295,12 +296,12 @@ static int temac_dma_bd_init(struct net_device *ndev)
 
 		lp->rx_skb[i] = skb;
 		/* returns physical address of skb->data */
-		lp->rx_bd_v[i].phys = dma_map_single(ndev->dev.parent,
-						     skb->data,
-						     XTE_MAX_JUMBO_FRAME_SIZE,
-						     DMA_FROM_DEVICE);
-		lp->rx_bd_v[i].len = XTE_MAX_JUMBO_FRAME_SIZE;
-		lp->rx_bd_v[i].app0 = STS_CTRL_APP0_IRQONEND;
+		skb_dma_addr = dma_map_single(ndev->dev.parent, skb->data,
+					      XTE_MAX_JUMBO_FRAME_SIZE,
+					      DMA_FROM_DEVICE);
+		lp->rx_bd_v[i].phys = cpu_to_be32(skb_dma_addr);
+		lp->rx_bd_v[i].len = cpu_to_be32(XTE_MAX_JUMBO_FRAME_SIZE);
+		lp->rx_bd_v[i].app0 = cpu_to_be32(STS_CTRL_APP0_IRQONEND);
 	}
 
 	lp->dma_out(lp, TX_CHNL_CTRL, 0x10220400 |
@@ -676,11 +677,11 @@ static void temac_start_xmit_done(struct net_device *ndev)
 	struct sk_buff *skb;
 
 	cur_p = &lp->tx_bd_v[lp->tx_bd_ci];
-	stat = cur_p->app0;
+	stat = be32_to_cpu(cur_p->app0);
 
 	while (stat & STS_CTRL_APP0_CMPLT) {
-		dma_unmap_single(ndev->dev.parent, cur_p->phys, cur_p->len,
-				 DMA_TO_DEVICE);
+		dma_unmap_single(ndev->dev.parent, be32_to_cpu(cur_p->phys),
+				 be32_to_cpu(cur_p->len), DMA_TO_DEVICE);
 		skb = (struct sk_buff *)ptr_from_txbd(cur_p);
 		if (skb)
 			dev_consume_skb_irq(skb);
@@ -691,14 +692,14 @@ static void temac_start_xmit_done(struct net_device *ndev)
 		cur_p->app4 = 0;
 
 		ndev->stats.tx_packets++;
-		ndev->stats.tx_bytes += cur_p->len;
+		ndev->stats.tx_bytes += be32_to_cpu(cur_p->len);
 
 		lp->tx_bd_ci++;
 		if (lp->tx_bd_ci >= TX_BD_NUM)
 			lp->tx_bd_ci = 0;
 
 		cur_p = &lp->tx_bd_v[lp->tx_bd_ci];
-		stat = cur_p->app0;
+		stat = be32_to_cpu(cur_p->app0);
 	}
 
 	netif_wake_queue(ndev);
@@ -732,7 +733,7 @@ temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 {
 	struct temac_local *lp = netdev_priv(ndev);
 	struct cdmac_bd *cur_p;
-	dma_addr_t start_p, tail_p;
+	dma_addr_t start_p, tail_p, skb_dma_addr;
 	int ii;
 	unsigned long num_frag;
 	skb_frag_t *frag;
@@ -753,15 +754,17 @@ temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 		unsigned int csum_start_off = skb_checksum_start_offset(skb);
 		unsigned int csum_index_off = csum_start_off + skb->csum_offset;
 
-		cur_p->app0 |= 1; /* TX Checksum Enabled */
-		cur_p->app1 = (csum_start_off << 16) | csum_index_off;
+		cur_p->app0 |= cpu_to_be32(0x000001); /* TX Checksum Enabled */
+		cur_p->app1 = cpu_to_be32((csum_start_off << 16)
+					  | csum_index_off);
 		cur_p->app2 = 0;  /* initial checksum seed */
 	}
 
-	cur_p->app0 |= STS_CTRL_APP0_SOP;
-	cur_p->len = skb_headlen(skb);
-	cur_p->phys = dma_map_single(ndev->dev.parent, skb->data,
-				     skb_headlen(skb), DMA_TO_DEVICE);
+	cur_p->app0 |= cpu_to_be32(STS_CTRL_APP0_SOP);
+	skb_dma_addr = dma_map_single(ndev->dev.parent, skb->data,
+				      skb_headlen(skb), DMA_TO_DEVICE);
+	cur_p->len = cpu_to_be32(skb_headlen(skb));
+	cur_p->phys = cpu_to_be32(skb_dma_addr);
 	ptr_to_txbd((void *)skb, cur_p);
 
 	for (ii = 0; ii < num_frag; ii++) {
@@ -770,14 +773,16 @@ temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 			lp->tx_bd_tail = 0;
 
 		cur_p = &lp->tx_bd_v[lp->tx_bd_tail];
-		cur_p->phys = dma_map_single(ndev->dev.parent,
-					     skb_frag_address(frag),
-					     skb_frag_size(frag), DMA_TO_DEVICE);
-		cur_p->len = skb_frag_size(frag);
+		skb_dma_addr = dma_map_single(ndev->dev.parent,
+					      skb_frag_address(frag),
+					      skb_frag_size(frag),
+					      DMA_TO_DEVICE);
+		cur_p->phys = cpu_to_be32(skb_dma_addr);
+		cur_p->len = cpu_to_be32(skb_frag_size(frag));
 		cur_p->app0 = 0;
 		frag++;
 	}
-	cur_p->app0 |= STS_CTRL_APP0_EOP;
+	cur_p->app0 |= cpu_to_be32(STS_CTRL_APP0_EOP);
 
 	tail_p = lp->tx_bd_p + sizeof(*lp->tx_bd_v) * lp->tx_bd_tail;
 	lp->tx_bd_tail++;
@@ -799,7 +804,7 @@ static void ll_temac_recv(struct net_device *ndev)
 	struct sk_buff *skb, *new_skb;
 	unsigned int bdstat;
 	struct cdmac_bd *cur_p;
-	dma_addr_t tail_p;
+	dma_addr_t tail_p, skb_dma_addr;
 	int length;
 	unsigned long flags;
 
@@ -808,14 +813,14 @@ static void ll_temac_recv(struct net_device *ndev)
 	tail_p = lp->rx_bd_p + sizeof(*lp->rx_bd_v) * lp->rx_bd_ci;
 	cur_p = &lp->rx_bd_v[lp->rx_bd_ci];
 
-	bdstat = cur_p->app0;
+	bdstat = be32_to_cpu(cur_p->app0);
 	while ((bdstat & STS_CTRL_APP0_CMPLT)) {
 
 		skb = lp->rx_skb[lp->rx_bd_ci];
-		length = cur_p->app4 & 0x3FFF;
+		length = be32_to_cpu(cur_p->app4) & 0x3FFF;
 
-		dma_unmap_single(ndev->dev.parent, cur_p->phys, length,
-				 DMA_FROM_DEVICE);
+		dma_unmap_single(ndev->dev.parent, be32_to_cpu(cur_p->phys),
+				 length, DMA_FROM_DEVICE);
 
 		skb_put(skb, length);
 		skb->protocol = eth_type_trans(skb, ndev);
@@ -826,7 +831,12 @@ static void ll_temac_recv(struct net_device *ndev)
 		    (skb->protocol == htons(ETH_P_IP)) &&
 		    (skb->len > 64)) {
 
-			skb->csum = cur_p->app3 & 0xFFFF;
+			/* Convert from device endianness (be32) to cpu
+			 * endiannes, and if necessary swap the bytes
+			 * (back) for proper IP checksum byte order
+			 * (be16).
+			 */
+			skb->csum = htons(be32_to_cpu(cur_p->app3) & 0xFFFF);
 			skb->ip_summed = CHECKSUM_COMPLETE;
 		}
 
@@ -843,11 +853,12 @@ static void ll_temac_recv(struct net_device *ndev)
 			return;
 		}
 
-		cur_p->app0 = STS_CTRL_APP0_IRQONEND;
-		cur_p->phys = dma_map_single(ndev->dev.parent, new_skb->data,
-					     XTE_MAX_JUMBO_FRAME_SIZE,
-					     DMA_FROM_DEVICE);
-		cur_p->len = XTE_MAX_JUMBO_FRAME_SIZE;
+		cur_p->app0 = cpu_to_be32(STS_CTRL_APP0_IRQONEND);
+		skb_dma_addr = dma_map_single(ndev->dev.parent, new_skb->data,
+					      XTE_MAX_JUMBO_FRAME_SIZE,
+					      DMA_FROM_DEVICE);
+		cur_p->phys = cpu_to_be32(skb_dma_addr);
+		cur_p->len = cpu_to_be32(XTE_MAX_JUMBO_FRAME_SIZE);
 		lp->rx_skb[lp->rx_bd_ci] = new_skb;
 
 		lp->rx_bd_ci++;
@@ -855,7 +866,7 @@ static void ll_temac_recv(struct net_device *ndev)
 			lp->rx_bd_ci = 0;
 
 		cur_p = &lp->rx_bd_v[lp->rx_bd_ci];
-		bdstat = cur_p->app0;
+		bdstat = be32_to_cpu(cur_p->app0);
 	}
 	lp->dma_out(lp, RX_TAILDESC_PTR, tail_p);
 
-- 
2.4.11


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

* [PATCH v3 06/12] net: ll_temac: Allow use on x86 platforms
  2019-04-30  7:17   ` [PATCH v3 00/12] net: ll_temac: x86_64 support Esben Haabendal
                       ` (4 preceding siblings ...)
  2019-04-30  7:17     ` [PATCH v3 05/12] net: ll_temac: Fix support for little-endian platforms Esben Haabendal
@ 2019-04-30  7:17     ` Esben Haabendal
  2019-04-30  7:17     ` [PATCH v3 07/12] net: ll_temac: Support indirect_mutex share within TEMAC IP Esben Haabendal
                       ` (6 subsequent siblings)
  12 siblings, 0 replies; 59+ messages in thread
From: Esben Haabendal @ 2019-04-30  7:17 UTC (permalink / raw)
  To: netdev
  Cc: Andrew Lunn, David S. Miller, Michal Simek, linux-arm-kernel,
	linux-kernel

With little-endian and 64-bit support in place, the ll_temac driver can
now be used on x86 and x86_64 platforms.

And while at it, enable COMPILE_TEST also.

Signed-off-by: Esben Haabendal <esben@geanix.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
---
 drivers/net/ethernet/xilinx/Kconfig | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/xilinx/Kconfig b/drivers/net/ethernet/xilinx/Kconfig
index 6d68c8a..db448fa 100644
--- a/drivers/net/ethernet/xilinx/Kconfig
+++ b/drivers/net/ethernet/xilinx/Kconfig
@@ -5,7 +5,7 @@
 config NET_VENDOR_XILINX
 	bool "Xilinx devices"
 	default y
-	depends on PPC || PPC32 || MICROBLAZE || ARCH_ZYNQ || MIPS
+	depends on PPC || PPC32 || MICROBLAZE || ARCH_ZYNQ || MIPS || X86 || COMPILE_TEST
 	---help---
 	  If you have a network (Ethernet) card belonging to this class, say Y.
 
@@ -33,7 +33,7 @@ config XILINX_AXI_EMAC
 
 config XILINX_LL_TEMAC
 	tristate "Xilinx LL TEMAC (LocalLink Tri-mode Ethernet MAC) driver"
-	depends on (PPC || MICROBLAZE)
+	depends on PPC || MICROBLAZE || X86 || COMPILE_TEST
 	select PHYLIB
 	---help---
 	  This driver supports the Xilinx 10/100/1000 LocalLink TEMAC
-- 
2.4.11


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

* [PATCH v3 07/12] net: ll_temac: Support indirect_mutex share within TEMAC IP
  2019-04-30  7:17   ` [PATCH v3 00/12] net: ll_temac: x86_64 support Esben Haabendal
                       ` (5 preceding siblings ...)
  2019-04-30  7:17     ` [PATCH v3 06/12] net: ll_temac: Allow use on x86 platforms Esben Haabendal
@ 2019-04-30  7:17     ` Esben Haabendal
  2019-04-30 16:59       ` Andrew Lunn
  2019-04-30  7:17     ` [PATCH v3 08/12] net: ll_temac: Fix iommu/swiotlb leak Esben Haabendal
                       ` (5 subsequent siblings)
  12 siblings, 1 reply; 59+ messages in thread
From: Esben Haabendal @ 2019-04-30  7:17 UTC (permalink / raw)
  To: netdev
  Cc: David S. Miller, Michal Simek, YueHaibing, Luis Chamberlain,
	Yang Wei, linux-arm-kernel, linux-kernel

Indirect register access goes through a DCR bus bridge, which
allows only one outstanding transaction.  And to make matters
worse, each TEMAC IP block contains two Ethernet interfaces, and
although they seem to have separate registers for indirect access,
they actually share the registers.  Or to be more specific, MSW, LSW
and CTL registers are physically shared between Ethernet interfaces
in same TEMAC IP, with RDY register being (almost) specificic to
the Ethernet interface.  The 0x10000 bit in RDY reflects combined
bus ready state though.

So we need to take care to synchronize not only within a single
device, but also between devices in same TEMAC IP.

This commit allows to do that with legacy platform devices.

For OF devices, the xlnx,compound parent of the temac node should be
used to find siblings, and setup a shared indirect_mutex between them.
I will leave this work to somebody else, as I don't have hardware to
test that.  No regression is introduced by that, as before this commit
using two Ethernet interfaces in same TEMAC block is simply broken.

Signed-off-by: Esben Haabendal <esben@geanix.com>
---
 drivers/net/ethernet/xilinx/ll_temac.h        |  5 +++-
 drivers/net/ethernet/xilinx/ll_temac_main.c   | 36 +++++++++++++++++++--------
 drivers/net/ethernet/xilinx/ll_temac_mdio.c   | 16 ++++++------
 include/linux/platform_data/xilinx-ll-temac.h |  6 +++++
 4 files changed, 43 insertions(+), 20 deletions(-)

diff --git a/drivers/net/ethernet/xilinx/ll_temac.h b/drivers/net/ethernet/xilinx/ll_temac.h
index 23d8dd5..990f9ed 100644
--- a/drivers/net/ethernet/xilinx/ll_temac.h
+++ b/drivers/net/ethernet/xilinx/ll_temac.h
@@ -358,7 +358,10 @@ struct temac_local {
 
 	struct sk_buff **rx_skb;
 	spinlock_t rx_lock;
-	struct mutex indirect_mutex;
+	/* For synchronization of indirect register access.  Must be
+	 * shared mutex between interfaces in same TEMAC block.
+	 */
+	struct mutex *indirect_mutex;
 	u32 options;			/* Current options word */
 	int last_link;
 	unsigned int temac_features;
diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index 179a998..d3899e7 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -344,7 +344,7 @@ static void temac_do_set_mac_address(struct net_device *ndev)
 	struct temac_local *lp = netdev_priv(ndev);
 
 	/* set up unicast MAC address filter set its mac address */
-	mutex_lock(&lp->indirect_mutex);
+	mutex_lock(lp->indirect_mutex);
 	temac_indirect_out32(lp, XTE_UAW0_OFFSET,
 			     (ndev->dev_addr[0]) |
 			     (ndev->dev_addr[1] << 8) |
@@ -355,7 +355,7 @@ static void temac_do_set_mac_address(struct net_device *ndev)
 	temac_indirect_out32(lp, XTE_UAW1_OFFSET,
 			     (ndev->dev_addr[4] & 0x000000ff) |
 			     (ndev->dev_addr[5] << 8));
-	mutex_unlock(&lp->indirect_mutex);
+	mutex_unlock(lp->indirect_mutex);
 }
 
 static int temac_init_mac_address(struct net_device *ndev, const void *address)
@@ -384,7 +384,7 @@ static void temac_set_multicast_list(struct net_device *ndev)
 	u32 multi_addr_msw, multi_addr_lsw, val;
 	int i;
 
-	mutex_lock(&lp->indirect_mutex);
+	mutex_lock(lp->indirect_mutex);
 	if (ndev->flags & (IFF_ALLMULTI | IFF_PROMISC) ||
 	    netdev_mc_count(ndev) > MULTICAST_CAM_TABLE_NUM) {
 		/*
@@ -423,7 +423,7 @@ static void temac_set_multicast_list(struct net_device *ndev)
 		temac_indirect_out32(lp, XTE_MAW1_OFFSET, 0);
 		dev_info(&ndev->dev, "Promiscuous mode disabled.\n");
 	}
-	mutex_unlock(&lp->indirect_mutex);
+	mutex_unlock(lp->indirect_mutex);
 }
 
 static struct temac_option {
@@ -515,7 +515,7 @@ static u32 temac_setoptions(struct net_device *ndev, u32 options)
 	struct temac_option *tp = &temac_options[0];
 	int reg;
 
-	mutex_lock(&lp->indirect_mutex);
+	mutex_lock(lp->indirect_mutex);
 	while (tp->opt) {
 		reg = temac_indirect_in32(lp, tp->reg) & ~tp->m_or;
 		if (options & tp->opt)
@@ -524,7 +524,7 @@ static u32 temac_setoptions(struct net_device *ndev, u32 options)
 		tp++;
 	}
 	lp->options |= options;
-	mutex_unlock(&lp->indirect_mutex);
+	mutex_unlock(lp->indirect_mutex);
 
 	return 0;
 }
@@ -543,7 +543,7 @@ static void temac_device_reset(struct net_device *ndev)
 
 	dev_dbg(&ndev->dev, "%s()\n", __func__);
 
-	mutex_lock(&lp->indirect_mutex);
+	mutex_lock(lp->indirect_mutex);
 	/* Reset the receiver and wait for it to finish reset */
 	temac_indirect_out32(lp, XTE_RXC1_OFFSET, XTE_RXC1_RXRST_MASK);
 	timeout = 1000;
@@ -595,7 +595,7 @@ static void temac_device_reset(struct net_device *ndev)
 	temac_indirect_out32(lp, XTE_TXC_OFFSET, 0);
 	temac_indirect_out32(lp, XTE_FCC_OFFSET, XTE_FCC_RXFLO_MASK);
 
-	mutex_unlock(&lp->indirect_mutex);
+	mutex_unlock(lp->indirect_mutex);
 
 	/* Sync default options with HW
 	 * but leave receiver and transmitter disabled.  */
@@ -623,7 +623,7 @@ static void temac_adjust_link(struct net_device *ndev)
 	/* hash together the state values to decide if something has changed */
 	link_state = phy->speed | (phy->duplex << 1) | phy->link;
 
-	mutex_lock(&lp->indirect_mutex);
+	mutex_lock(lp->indirect_mutex);
 	if (lp->last_link != link_state) {
 		mii_speed = temac_indirect_in32(lp, XTE_EMCFG_OFFSET);
 		mii_speed &= ~XTE_EMCFG_LINKSPD_MASK;
@@ -639,7 +639,7 @@ static void temac_adjust_link(struct net_device *ndev)
 		lp->last_link = link_state;
 		phy_print_status(phy);
 	}
-	mutex_unlock(&lp->indirect_mutex);
+	mutex_unlock(lp->indirect_mutex);
 }
 
 #ifdef CONFIG_64BIT
@@ -1091,7 +1091,21 @@ static int temac_probe(struct platform_device *pdev)
 	lp->dev = &pdev->dev;
 	lp->options = XTE_OPTION_DEFAULTS;
 	spin_lock_init(&lp->rx_lock);
-	mutex_init(&lp->indirect_mutex);
+
+	/* Setup mutex for synchronization of indirect register access */
+	if (pdata) {
+		if (!pdata->indirect_mutex) {
+			dev_err(&pdev->dev,
+				"indirect_mutex missing in platform_data\n");
+			return -EINVAL;
+		}
+		lp->indirect_mutex = pdata->indirect_mutex;
+	} else {
+		lp->indirect_mutex = devm_kmalloc(&pdev->dev,
+						  sizeof(*lp->indirect_mutex),
+						  GFP_KERNEL);
+		mutex_init(lp->indirect_mutex);
+	}
 
 	/* map device registers */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
diff --git a/drivers/net/ethernet/xilinx/ll_temac_mdio.c b/drivers/net/ethernet/xilinx/ll_temac_mdio.c
index c5307e5..c2a1170 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_mdio.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_mdio.c
@@ -29,10 +29,10 @@ static int temac_mdio_read(struct mii_bus *bus, int phy_id, int reg)
 	/* Write the PHY address to the MIIM Access Initiator register.
 	 * When the transfer completes, the PHY register value will appear
 	 * in the LSW0 register */
-	mutex_lock(&lp->indirect_mutex);
+	mutex_lock(lp->indirect_mutex);
 	temac_iow(lp, XTE_LSW0_OFFSET, (phy_id << 5) | reg);
 	rc = temac_indirect_in32(lp, XTE_MIIMAI_OFFSET);
-	mutex_unlock(&lp->indirect_mutex);
+	mutex_unlock(lp->indirect_mutex);
 
 	dev_dbg(lp->dev, "temac_mdio_read(phy_id=%i, reg=%x) == %x\n",
 		phy_id, reg, rc);
@@ -50,10 +50,10 @@ static int temac_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 val)
 	/* First write the desired value into the write data register
 	 * and then write the address into the access initiator register
 	 */
-	mutex_lock(&lp->indirect_mutex);
+	mutex_lock(lp->indirect_mutex);
 	temac_indirect_out32(lp, XTE_MGTDR_OFFSET, val);
 	temac_indirect_out32(lp, XTE_MIIMAI_OFFSET, (phy_id << 5) | reg);
-	mutex_unlock(&lp->indirect_mutex);
+	mutex_unlock(lp->indirect_mutex);
 
 	return 0;
 }
@@ -87,9 +87,9 @@ int temac_mdio_setup(struct temac_local *lp, struct platform_device *pdev)
 
 	/* Enable the MDIO bus by asserting the enable bit and writing
 	 * in the clock config */
-	mutex_lock(&lp->indirect_mutex);
+	mutex_lock(lp->indirect_mutex);
 	temac_indirect_out32(lp, XTE_MC_OFFSET, 1 << 6 | clk_div);
-	mutex_unlock(&lp->indirect_mutex);
+	mutex_unlock(lp->indirect_mutex);
 
 	bus = devm_mdiobus_alloc(&pdev->dev);
 	if (!bus)
@@ -116,10 +116,10 @@ int temac_mdio_setup(struct temac_local *lp, struct platform_device *pdev)
 	if (rc)
 		return rc;
 
-	mutex_lock(&lp->indirect_mutex);
+	mutex_lock(lp->indirect_mutex);
 	dev_dbg(lp->dev, "MDIO bus registered;  MC:%x\n",
 		temac_indirect_in32(lp, XTE_MC_OFFSET));
-	mutex_unlock(&lp->indirect_mutex);
+	mutex_unlock(lp->indirect_mutex);
 	return 0;
 }
 
diff --git a/include/linux/platform_data/xilinx-ll-temac.h b/include/linux/platform_data/xilinx-ll-temac.h
index af87927..b0b8238 100644
--- a/include/linux/platform_data/xilinx-ll-temac.h
+++ b/include/linux/platform_data/xilinx-ll-temac.h
@@ -16,6 +16,12 @@ struct ll_temac_platform_data {
 	phy_interface_t phy_interface; /* PHY interface mode */
 	bool reg_little_endian;	/* Little endian TEMAC register access  */
 	bool dma_little_endian;	/* Little endian DMA register access  */
+	/* Pre-initialized mutex to use for synchronizing indirect
+	 * register access.  When using both interfaces of a single
+	 * TEMAC IP block, the same mutex should be passed here, as
+	 * they share the same DCR bus bridge.
+	 */
+	struct mutex *indirect_mutex;
 };
 
 #endif /* __LINUX_XILINX_LL_TEMAC_H */
-- 
2.4.11


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

* [PATCH v3 08/12] net: ll_temac: Fix iommu/swiotlb leak
  2019-04-30  7:17   ` [PATCH v3 00/12] net: ll_temac: x86_64 support Esben Haabendal
                       ` (6 preceding siblings ...)
  2019-04-30  7:17     ` [PATCH v3 07/12] net: ll_temac: Support indirect_mutex share within TEMAC IP Esben Haabendal
@ 2019-04-30  7:17     ` Esben Haabendal
  2019-04-30 17:00       ` Andrew Lunn
  2019-04-30  7:17     ` [PATCH v3 09/12] net: ll_temac: Fix bug causing buffer descriptor overrun Esben Haabendal
                       ` (4 subsequent siblings)
  12 siblings, 1 reply; 59+ messages in thread
From: Esben Haabendal @ 2019-04-30  7:17 UTC (permalink / raw)
  To: netdev
  Cc: David S. Miller, Michal Simek, Yang Wei, Luis Chamberlain,
	YueHaibing, linux-arm-kernel, linux-kernel

Unmap the actual buffer length, not the amount of data received, avoiding
resource exhaustion of swiotlb (seen on x86_64 platform).

Signed-off-by: Esben Haabendal <esben@geanix.com>
---
 drivers/net/ethernet/xilinx/ll_temac_main.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index d3899e7..7e42746 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -820,7 +820,7 @@ static void ll_temac_recv(struct net_device *ndev)
 		length = be32_to_cpu(cur_p->app4) & 0x3FFF;
 
 		dma_unmap_single(ndev->dev.parent, be32_to_cpu(cur_p->phys),
-				 length, DMA_FROM_DEVICE);
+				 XTE_MAX_JUMBO_FRAME_SIZE, DMA_FROM_DEVICE);
 
 		skb_put(skb, length);
 		skb->protocol = eth_type_trans(skb, ndev);
-- 
2.4.11


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

* [PATCH v3 09/12] net: ll_temac: Fix bug causing buffer descriptor overrun
  2019-04-30  7:17   ` [PATCH v3 00/12] net: ll_temac: x86_64 support Esben Haabendal
                       ` (7 preceding siblings ...)
  2019-04-30  7:17     ` [PATCH v3 08/12] net: ll_temac: Fix iommu/swiotlb leak Esben Haabendal
@ 2019-04-30  7:17     ` Esben Haabendal
  2019-04-30  7:17     ` [PATCH v3 10/12] net: ll_temac: Replace bad usage of msleep() with usleep_range() Esben Haabendal
                       ` (3 subsequent siblings)
  12 siblings, 0 replies; 59+ messages in thread
From: Esben Haabendal @ 2019-04-30  7:17 UTC (permalink / raw)
  To: netdev
  Cc: David S. Miller, Michal Simek, Luis Chamberlain, YueHaibing,
	Yang Wei, linux-arm-kernel, linux-kernel

As we are actually using a BD for both the skb and each frag contained in
it, the oldest TX BD would be overwritten when there was exactly one BD
less than needed.

Signed-off-by: Esben Haabendal <esben@geanix.com>
---
 drivers/net/ethernet/xilinx/ll_temac_main.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index 7e42746..6837565 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -743,7 +743,7 @@ temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 	start_p = lp->tx_bd_p + sizeof(*lp->tx_bd_v) * lp->tx_bd_tail;
 	cur_p = &lp->tx_bd_v[lp->tx_bd_tail];
 
-	if (temac_check_tx_bd_space(lp, num_frag)) {
+	if (temac_check_tx_bd_space(lp, num_frag + 1)) {
 		if (!netif_queue_stopped(ndev))
 			netif_stop_queue(ndev);
 		return NETDEV_TX_BUSY;
-- 
2.4.11


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

* [PATCH v3 10/12] net: ll_temac: Replace bad usage of msleep() with usleep_range()
  2019-04-30  7:17   ` [PATCH v3 00/12] net: ll_temac: x86_64 support Esben Haabendal
                       ` (8 preceding siblings ...)
  2019-04-30  7:17     ` [PATCH v3 09/12] net: ll_temac: Fix bug causing buffer descriptor overrun Esben Haabendal
@ 2019-04-30  7:17     ` Esben Haabendal
  2019-04-30  7:17     ` [PATCH v3 11/12] net: ll_temac: Allow configuration of IRQ coalescing Esben Haabendal
                       ` (2 subsequent siblings)
  12 siblings, 0 replies; 59+ messages in thread
From: Esben Haabendal @ 2019-04-30  7:17 UTC (permalink / raw)
  To: netdev
  Cc: Andrew Lunn, David S. Miller, Michal Simek, Luis Chamberlain,
	Yang Wei, YueHaibing, linux-arm-kernel, linux-kernel

Use usleep_range() to avoid problems with msleep() actually sleeping
much longer than expected.

Signed-off-by: Esben Haabendal <esben@geanix.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
---
 drivers/net/ethernet/xilinx/ll_temac_main.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index 6837565..fec8e4c 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -92,7 +92,7 @@ int temac_indirect_busywait(struct temac_local *lp)
 			WARN_ON(1);
 			return -ETIMEDOUT;
 		}
-		msleep(1);
+		usleep_range(500, 1000);
 	}
 	return 0;
 }
-- 
2.4.11


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

* [PATCH v3 11/12] net: ll_temac: Allow configuration of IRQ coalescing
  2019-04-30  7:17   ` [PATCH v3 00/12] net: ll_temac: x86_64 support Esben Haabendal
                       ` (9 preceding siblings ...)
  2019-04-30  7:17     ` [PATCH v3 10/12] net: ll_temac: Replace bad usage of msleep() with usleep_range() Esben Haabendal
@ 2019-04-30  7:17     ` Esben Haabendal
  2019-04-30  7:17     ` [PATCH v3 12/12] net: ll_temac: Enable DMA when ready, not before Esben Haabendal
  2019-05-01 18:33     ` [PATCH v3 00/12] net: ll_temac: x86_64 support David Miller
  12 siblings, 0 replies; 59+ messages in thread
From: Esben Haabendal @ 2019-04-30  7:17 UTC (permalink / raw)
  To: netdev
  Cc: David S. Miller, Michal Simek, Yang Wei, Luis Chamberlain,
	YueHaibing, linux-arm-kernel, linux-kernel

This allows custom setup of IRQ coalescing for platforms using legacy
platform_device. The irq timeout and count parameters can be used for
tuning cpu load vs. latency.

I have maintained the 0x00000400 bit in TX_CHNL_CTRL.  It is specified as
unused in the documentation I have available.  It does not make any
difference in the hardware I have available, so it is left in to not risk
breaking other platforms where it might be used.

Signed-off-by: Esben Haabendal <esben@geanix.com>
---
 drivers/net/ethernet/xilinx/ll_temac.h        |  4 +++
 drivers/net/ethernet/xilinx/ll_temac_main.c   | 40 +++++++++++++++++++--------
 include/linux/platform_data/xilinx-ll-temac.h |  5 ++++
 3 files changed, 37 insertions(+), 12 deletions(-)

diff --git a/drivers/net/ethernet/xilinx/ll_temac.h b/drivers/net/ethernet/xilinx/ll_temac.h
index 990f9ed..1aeda08 100644
--- a/drivers/net/ethernet/xilinx/ll_temac.h
+++ b/drivers/net/ethernet/xilinx/ll_temac.h
@@ -375,6 +375,10 @@ struct temac_local {
 	int tx_bd_next;
 	int tx_bd_tail;
 	int rx_bd_ci;
+
+	/* DMA channel control setup */
+	u32 tx_chnl_ctrl;
+	u32 rx_chnl_ctrl;
 };
 
 /* Wrappers for temac_ior()/temac_iow() function pointers above */
diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index fec8e4c..bccef30 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -304,18 +304,15 @@ static int temac_dma_bd_init(struct net_device *ndev)
 		lp->rx_bd_v[i].app0 = cpu_to_be32(STS_CTRL_APP0_IRQONEND);
 	}
 
-	lp->dma_out(lp, TX_CHNL_CTRL, 0x10220400 |
-					  CHNL_CTRL_IRQ_EN |
-					  CHNL_CTRL_IRQ_DLY_EN |
-					  CHNL_CTRL_IRQ_COAL_EN);
-	/* 0x10220483 */
-	/* 0x00100483 */
-	lp->dma_out(lp, RX_CHNL_CTRL, 0xff070000 |
-					  CHNL_CTRL_IRQ_EN |
-					  CHNL_CTRL_IRQ_DLY_EN |
-					  CHNL_CTRL_IRQ_COAL_EN |
-					  CHNL_CTRL_IRQ_IOE);
-	/* 0xff010283 */
+	/* Configure DMA channel (irq setup) */
+	lp->dma_out(lp, TX_CHNL_CTRL, lp->tx_chnl_ctrl |
+		    0x00000400 | // Use 1 Bit Wide Counters. Currently Not Used!
+		    CHNL_CTRL_IRQ_EN | CHNL_CTRL_IRQ_ERR_EN |
+		    CHNL_CTRL_IRQ_DLY_EN | CHNL_CTRL_IRQ_COAL_EN);
+	lp->dma_out(lp, RX_CHNL_CTRL, lp->rx_chnl_ctrl |
+		    CHNL_CTRL_IRQ_IOE |
+		    CHNL_CTRL_IRQ_EN | CHNL_CTRL_IRQ_ERR_EN |
+		    CHNL_CTRL_IRQ_DLY_EN | CHNL_CTRL_IRQ_COAL_EN);
 
 	lp->dma_out(lp, RX_CURDESC_PTR,  lp->rx_bd_p);
 	lp->dma_out(lp, RX_TAILDESC_PTR,
@@ -1191,6 +1188,13 @@ static int temac_probe(struct platform_device *pdev)
 		lp->rx_irq = irq_of_parse_and_map(dma_np, 0);
 		lp->tx_irq = irq_of_parse_and_map(dma_np, 1);
 
+		/* Use defaults for IRQ delay/coalescing setup.  These
+		 * are configuration values, so does not belong in
+		 * device-tree.
+		 */
+		lp->tx_chnl_ctrl = 0x10220000;
+		lp->rx_chnl_ctrl = 0xff070000;
+
 		/* Finished with the DMA node; drop the reference */
 		of_node_put(dma_np);
 	} else if (pdata) {
@@ -1214,6 +1218,18 @@ static int temac_probe(struct platform_device *pdev)
 		/* Get DMA RX and TX interrupts */
 		lp->rx_irq = platform_get_irq(pdev, 0);
 		lp->tx_irq = platform_get_irq(pdev, 1);
+
+		/* IRQ delay/coalescing setup */
+		if (pdata->tx_irq_timeout || pdata->tx_irq_count)
+			lp->tx_chnl_ctrl = (pdata->tx_irq_timeout << 24) |
+				(pdata->tx_irq_count << 16);
+		else
+			lp->tx_chnl_ctrl = 0x10220000;
+		if (pdata->rx_irq_timeout || pdata->rx_irq_count)
+			lp->rx_chnl_ctrl = (pdata->rx_irq_timeout << 24) |
+				(pdata->rx_irq_count << 16);
+		else
+			lp->rx_chnl_ctrl = 0xff070000;
 	}
 
 	/* Error handle returned DMA RX and TX interrupts */
diff --git a/include/linux/platform_data/xilinx-ll-temac.h b/include/linux/platform_data/xilinx-ll-temac.h
index b0b8238..368530f 100644
--- a/include/linux/platform_data/xilinx-ll-temac.h
+++ b/include/linux/platform_data/xilinx-ll-temac.h
@@ -22,6 +22,11 @@ struct ll_temac_platform_data {
 	 * they share the same DCR bus bridge.
 	 */
 	struct mutex *indirect_mutex;
+	/* DMA channel control setup */
+	u8 tx_irq_timeout;	/* TX Interrupt Delay Time-out */
+	u8 tx_irq_count;	/* TX Interrupt Coalescing Threshold Count */
+	u8 rx_irq_timeout;	/* RX Interrupt Delay Time-out */
+	u8 rx_irq_count;	/* RX Interrupt Coalescing Threshold Count */
 };
 
 #endif /* __LINUX_XILINX_LL_TEMAC_H */
-- 
2.4.11


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

* [PATCH v3 12/12] net: ll_temac: Enable DMA when ready, not before
  2019-04-30  7:17   ` [PATCH v3 00/12] net: ll_temac: x86_64 support Esben Haabendal
                       ` (10 preceding siblings ...)
  2019-04-30  7:17     ` [PATCH v3 11/12] net: ll_temac: Allow configuration of IRQ coalescing Esben Haabendal
@ 2019-04-30  7:17     ` Esben Haabendal
  2019-05-01 18:33     ` [PATCH v3 00/12] net: ll_temac: x86_64 support David Miller
  12 siblings, 0 replies; 59+ messages in thread
From: Esben Haabendal @ 2019-04-30  7:17 UTC (permalink / raw)
  To: netdev
  Cc: David S. Miller, Michal Simek, Luis Chamberlain, YueHaibing,
	Yang Wei, linux-arm-kernel, linux-kernel

As soon as TAILDESCR_PTR is written, DMA transfers might start.
Let's ensure we are ready to receive DMA IRQ's before doing that.

Signed-off-by: Esben Haabendal <esben@geanix.com>
---
 drivers/net/ethernet/xilinx/ll_temac_main.c | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index bccef30..1003ee1 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -314,17 +314,21 @@ static int temac_dma_bd_init(struct net_device *ndev)
 		    CHNL_CTRL_IRQ_EN | CHNL_CTRL_IRQ_ERR_EN |
 		    CHNL_CTRL_IRQ_DLY_EN | CHNL_CTRL_IRQ_COAL_EN);
 
-	lp->dma_out(lp, RX_CURDESC_PTR,  lp->rx_bd_p);
-	lp->dma_out(lp, RX_TAILDESC_PTR,
-		       lp->rx_bd_p + (sizeof(*lp->rx_bd_v) * (RX_BD_NUM - 1)));
-	lp->dma_out(lp, TX_CURDESC_PTR, lp->tx_bd_p);
-
 	/* Init descriptor indexes */
 	lp->tx_bd_ci = 0;
 	lp->tx_bd_next = 0;
 	lp->tx_bd_tail = 0;
 	lp->rx_bd_ci = 0;
 
+	/* Enable RX DMA transfers */
+	wmb();
+	lp->dma_out(lp, RX_CURDESC_PTR,  lp->rx_bd_p);
+	lp->dma_out(lp, RX_TAILDESC_PTR,
+		       lp->rx_bd_p + (sizeof(*lp->rx_bd_v) * (RX_BD_NUM - 1)));
+
+	/* Prepare for TX DMA transfer */
+	lp->dma_out(lp, TX_CURDESC_PTR, lp->tx_bd_p);
+
 	return 0;
 
 out:
@@ -789,6 +793,7 @@ temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 	skb_tx_timestamp(skb);
 
 	/* Kick off the transfer */
+	wmb();
 	lp->dma_out(lp, TX_TAILDESC_PTR, tail_p); /* DMA start */
 
 	return NETDEV_TX_OK;
-- 
2.4.11


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

* Re: [PATCH v3 07/12] net: ll_temac: Support indirect_mutex share within TEMAC IP
  2019-04-30  7:17     ` [PATCH v3 07/12] net: ll_temac: Support indirect_mutex share within TEMAC IP Esben Haabendal
@ 2019-04-30 16:59       ` Andrew Lunn
  0 siblings, 0 replies; 59+ messages in thread
From: Andrew Lunn @ 2019-04-30 16:59 UTC (permalink / raw)
  To: Esben Haabendal
  Cc: netdev, David S. Miller, Michal Simek, YueHaibing,
	Luis Chamberlain, Yang Wei, linux-arm-kernel, linux-kernel

On Tue, Apr 30, 2019 at 09:17:54AM +0200, Esben Haabendal wrote:
> Indirect register access goes through a DCR bus bridge, which
> allows only one outstanding transaction.  And to make matters
> worse, each TEMAC IP block contains two Ethernet interfaces, and
> although they seem to have separate registers for indirect access,
> they actually share the registers.  Or to be more specific, MSW, LSW
> and CTL registers are physically shared between Ethernet interfaces
> in same TEMAC IP, with RDY register being (almost) specificic to
> the Ethernet interface.  The 0x10000 bit in RDY reflects combined
> bus ready state though.
> 
> So we need to take care to synchronize not only within a single
> device, but also between devices in same TEMAC IP.
> 
> This commit allows to do that with legacy platform devices.
> 
> For OF devices, the xlnx,compound parent of the temac node should be
> used to find siblings, and setup a shared indirect_mutex between them.
> I will leave this work to somebody else, as I don't have hardware to
> test that.  No regression is introduced by that, as before this commit
> using two Ethernet interfaces in same TEMAC block is simply broken.
> 
> Signed-off-by: Esben Haabendal <esben@geanix.com>

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

    Andrew

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

* Re: [PATCH v3 08/12] net: ll_temac: Fix iommu/swiotlb leak
  2019-04-30  7:17     ` [PATCH v3 08/12] net: ll_temac: Fix iommu/swiotlb leak Esben Haabendal
@ 2019-04-30 17:00       ` Andrew Lunn
  0 siblings, 0 replies; 59+ messages in thread
From: Andrew Lunn @ 2019-04-30 17:00 UTC (permalink / raw)
  To: Esben Haabendal
  Cc: netdev, David S. Miller, Michal Simek, Yang Wei,
	Luis Chamberlain, YueHaibing, linux-arm-kernel, linux-kernel

On Tue, Apr 30, 2019 at 09:17:55AM +0200, Esben Haabendal wrote:
> Unmap the actual buffer length, not the amount of data received, avoiding
> resource exhaustion of swiotlb (seen on x86_64 platform).
> 
> Signed-off-by: Esben Haabendal <esben@geanix.com>

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

    Andrew

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

* Re: [PATCH v3 00/12] net: ll_temac: x86_64 support
  2019-04-30  7:17   ` [PATCH v3 00/12] net: ll_temac: x86_64 support Esben Haabendal
                       ` (11 preceding siblings ...)
  2019-04-30  7:17     ` [PATCH v3 12/12] net: ll_temac: Enable DMA when ready, not before Esben Haabendal
@ 2019-05-01 18:33     ` David Miller
  12 siblings, 0 replies; 59+ messages in thread
From: David Miller @ 2019-05-01 18:33 UTC (permalink / raw)
  To: esben
  Cc: netdev, linux-arm-kernel, michal.simek, mcgrof, yang.wei9,
	yuehaibing, linux-kernel

From: Esben Haabendal <esben@geanix.com>
Date: Tue, 30 Apr 2019 09:17:47 +0200

> This patch series adds support for use of ll_temac driver with
> platform_data configuration and fixes endianess and 64-bit problems so
> that it can be used on x86_64 platform.
> 
> A few bugfixes are also included.

Series applied to net-next.

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

end of thread, other threads:[~2019-05-01 18:33 UTC | newest]

Thread overview: 59+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-04-26  7:32 [PATCH 00/12] net: ll_temac: x86_64 support Esben Haabendal
2019-04-26  7:32 ` [PATCH 01/12] net: ll_temac: Fix and simplify error handling by using devres functions Esben Haabendal
2019-04-26  7:32 ` [PATCH 02/12] net: ll_temac: Extend support to non-device-tree platforms Esben Haabendal
2019-04-26 13:58   ` Andrew Lunn
2019-04-26  7:32 ` [PATCH 03/12] net: ll_temac: Fix support for 64-bit platforms Esben Haabendal
2019-04-26 18:40   ` Jakub Kicinski
2019-04-26 20:59     ` Andrew Lunn
2019-04-26 21:08       ` Jakub Kicinski
2019-04-26 22:02         ` Andrew Lunn
2019-04-26 22:30           ` Jakub Kicinski
2019-04-27  8:49             ` Esben Haabendal
2019-04-26  7:32 ` [PATCH 04/12] net: ll_temac: Add support for non-native register endianness Esben Haabendal
2019-04-26  7:32 ` [PATCH 05/12] net: ll_temac: Fix support for little-endian platforms Esben Haabendal
2019-04-26  7:32 ` [PATCH 06/12] net: ll_temac: Allow use on x86 platforms Esben Haabendal
2019-04-26 14:05   ` Andrew Lunn
2019-04-26  7:32 ` [PATCH 07/12] net: ll_temac: Support indirect_mutex share within TEMAC IP Esben Haabendal
2019-04-26 14:14   ` Andrew Lunn
2019-04-26  7:32 ` [PATCH 08/12] net: ll_temac: Fix iommu/swiotlb leak Esben Haabendal
2019-04-26 14:21   ` Andrew Lunn
2019-04-26 14:43     ` Robin Murphy
2019-04-26 15:37       ` Andrew Lunn
2019-04-26  7:32 ` [PATCH 09/12] net: ll_temac: Fix bug causing buffer descriptor overrun Esben Haabendal
2019-04-26  7:32 ` [PATCH 10/12] net: ll_temac: Replace bad usage of msleep() with usleep_range() Esben Haabendal
2019-04-26 14:01   ` Andrew Lunn
2019-04-26  7:32 ` [PATCH 11/12] net: ll_temac: Allow configuration of IRQ coalescing Esben Haabendal
2019-04-26  7:32 ` [PATCH 12/12] net: ll_temac: Enable DMA when ready, not before Esben Haabendal
2019-04-29  8:34 ` [PATCH 00/12] net: ll_temac: x86_64 support Esben Haabendal
2019-04-29  8:34   ` [PATCH 01/12] net: ll_temac: Fix and simplify error handling by using devres functions Esben Haabendal
2019-04-29  8:34   ` [PATCH 02/12] net: ll_temac: Extend support to non-device-tree platforms Esben Haabendal
2019-04-29  8:34   ` [PATCH 03/12] net: ll_temac: Fix support for 64-bit platforms Esben Haabendal
2019-04-29 22:06     ` Andrew Lunn
2019-04-29  8:34   ` [PATCH 04/12] net: ll_temac: Add support for non-native register endianness Esben Haabendal
2019-04-29  8:34   ` [PATCH 05/12] net: ll_temac: Fix support for little-endian platforms Esben Haabendal
2019-04-29  8:34   ` [PATCH 06/12] net: ll_temac: Allow use on x86 platforms Esben Haabendal
2019-04-29 22:06     ` Andrew Lunn
2019-04-29  8:34   ` [PATCH 07/12] net: ll_temac: Support indirect_mutex share within TEMAC IP Esben Haabendal
2019-04-29 22:12     ` Andrew Lunn
2019-04-30  6:54       ` Esben Haabendal
2019-04-29  8:34   ` [PATCH 08/12] net: ll_temac: Fix iommu/swiotlb leak Esben Haabendal
2019-04-29  8:34   ` [PATCH 09/12] net: ll_temac: Fix bug causing buffer descriptor overrun Esben Haabendal
2019-04-29  8:34   ` [PATCH 10/12] net: ll_temac: Replace bad usage of msleep() with usleep_range() Esben Haabendal
2019-04-29  8:34   ` [PATCH 11/12] net: ll_temac: Allow configuration of IRQ coalescing Esben Haabendal
2019-04-29  8:34   ` [PATCH 12/12] net: ll_temac: Enable DMA when ready, not before Esben Haabendal
2019-04-30  7:17   ` [PATCH v3 00/12] net: ll_temac: x86_64 support Esben Haabendal
2019-04-30  7:17     ` [PATCH v3 01/12] net: ll_temac: Fix and simplify error handling by using devres functions Esben Haabendal
2019-04-30  7:17     ` [PATCH v3 02/12] net: ll_temac: Extend support to non-device-tree platforms Esben Haabendal
2019-04-30  7:17     ` [PATCH v3 03/12] net: ll_temac: Fix support for 64-bit platforms Esben Haabendal
2019-04-30  7:17     ` [PATCH v3 04/12] net: ll_temac: Add support for non-native register endianness Esben Haabendal
2019-04-30  7:17     ` [PATCH v3 05/12] net: ll_temac: Fix support for little-endian platforms Esben Haabendal
2019-04-30  7:17     ` [PATCH v3 06/12] net: ll_temac: Allow use on x86 platforms Esben Haabendal
2019-04-30  7:17     ` [PATCH v3 07/12] net: ll_temac: Support indirect_mutex share within TEMAC IP Esben Haabendal
2019-04-30 16:59       ` Andrew Lunn
2019-04-30  7:17     ` [PATCH v3 08/12] net: ll_temac: Fix iommu/swiotlb leak Esben Haabendal
2019-04-30 17:00       ` Andrew Lunn
2019-04-30  7:17     ` [PATCH v3 09/12] net: ll_temac: Fix bug causing buffer descriptor overrun Esben Haabendal
2019-04-30  7:17     ` [PATCH v3 10/12] net: ll_temac: Replace bad usage of msleep() with usleep_range() Esben Haabendal
2019-04-30  7:17     ` [PATCH v3 11/12] net: ll_temac: Allow configuration of IRQ coalescing Esben Haabendal
2019-04-30  7:17     ` [PATCH v3 12/12] net: ll_temac: Enable DMA when ready, not before Esben Haabendal
2019-05-01 18:33     ` [PATCH v3 00/12] net: ll_temac: x86_64 support David Miller

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).