lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1559326545-28825-3-git-send-email-hancock@sedsystems.ca>
Date:   Fri, 31 May 2019 12:15:34 -0600
From:   Robert Hancock <hancock@...systems.ca>
To:     netdev@...r.kernel.org
Cc:     anirudh@...inx.com, John.Linn@...inx.com,
        Robert Hancock <hancock@...systems.ca>
Subject: [PATCH net-next 02/13] net: axienet: clean up MDIO handling

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

-Centralize all MDIO handling in xilinx_axienet_mdio.c

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

-Fixed ordering of MDIO teardown vs. netdev teardown

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

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

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ