ath79: Make upstream ag71xx driver work
authorHauke Mehrtens <hauke@hauke-m.de>
Mon, 17 Feb 2020 23:36:28 +0000 (00:36 +0100)
committerKoen Vandeputte <koen.vandeputte@ncentric.com>
Fri, 28 Feb 2020 16:50:46 +0000 (17:50 +0100)
* Fix some bugs in the driver
* Add missing clock and reset references in dts
* Rename mdio-bus to mdio so the driver find it

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
target/linux/ath79/dts/ar934x.dtsi
target/linux/ath79/dts/ath79.dtsi
target/linux/ath79/patches-5.4/200-ag71xx-Handle-allocation-errors-in-ag71xx_rings_init.patch [new file with mode: 0644]
target/linux/ath79/patches-5.4/201-ag71xx-Call-ag71xx_hw_disable-in-case-phy_conenct-fa.patch [new file with mode: 0644]
target/linux/ath79/patches-5.4/202-ag71xx-Run-ag71xx_link_adjust-only-when-needed.patch [new file with mode: 0644]

index e8c21fb71061522aca98e8df0e063dd2892badfd..0451960a60a4e69ab384f4a256c1c02445607f9d 100644 (file)
        pll-handle = <&pll>;
        resets = <&rst 9>, <&rst 22>;
        reset-names = "mac", "mdio";
+       clocks = <&pll ATH79_CLK_AHB>, <&pll ATH79_CLK_AHB>;
+       clock-names = "eth", "mdio";
 };
 
 &mdio1 {
 &eth1 {
        compatible = "qca,ar9340-eth", "syscon";
 
-       resets = <&rst 13>;
-       reset-names = "mac";
+       resets = <&rst 13>, <&rst 23>;
+       reset-names = "mac", "mdio";
+       clocks = <&pll ATH79_CLK_AHB>, <&pll ATH79_CLK_AHB>;
+       clock-names = "eth", "mdio";
        phy-mode = "gmii";
 
        fixed-link {
index c3512720259aea5536925d9756f05a3ece393054..1d1424590c3bd3fd1495298fac723fe87c7b672a 100644 (file)
@@ -49,7 +49,7 @@
                        interrupts = <4>;
                        phy-mode = "mii";
 
-                       mdio0: mdio-bus {
+                       mdio0: mdio {
                                status = "disabled";
 
                                compatible = "qca,ath79-mdio";
@@ -72,7 +72,7 @@
                        interrupts = <5>;
                        phy-mode = "mii";
 
-                       mdio1: mdio-bus {
+                       mdio1: mdio {
                                status = "disabled";
 
                                compatible = "qca,ath79-mdio";
diff --git a/target/linux/ath79/patches-5.4/200-ag71xx-Handle-allocation-errors-in-ag71xx_rings_init.patch b/target/linux/ath79/patches-5.4/200-ag71xx-Handle-allocation-errors-in-ag71xx_rings_init.patch
new file mode 100644 (file)
index 0000000..6631cb8
--- /dev/null
@@ -0,0 +1,61 @@
+From 2cee757eaf5cc6175bc0ac7b0b808794124ec40a Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Mon, 17 Feb 2020 23:40:14 +0100
+Subject: [PATCH 1/3] ag71xx: Handle allocation errors in ag71xx_rings_init()
+
+Free the allocated resources in ag71xx_rings_init() in case
+ag71xx_ring_rx_init() returns an error.
+
+This is only a potential problem, I did not ran into this one.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+Fixes: d51b6ce441d3 ("net: ethernet: add ag71xx driver")
+---
+ drivers/net/ethernet/atheros/ag71xx.c | 22 ++++++++++++++++++----
+ 1 file changed, 18 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/ethernet/atheros/ag71xx.c
++++ b/drivers/net/ethernet/atheros/ag71xx.c
+@@ -1133,6 +1133,7 @@ static int ag71xx_rings_init(struct ag71
+       struct ag71xx_ring *tx = &ag->tx_ring;
+       struct ag71xx_ring *rx = &ag->rx_ring;
+       int ring_size, tx_size;
++      int ret;
+       ring_size = BIT(tx->order) + BIT(rx->order);
+       tx_size = BIT(tx->order);
+@@ -1145,9 +1146,8 @@ static int ag71xx_rings_init(struct ag71
+                                          ring_size * AG71XX_DESC_SIZE,
+                                          &tx->descs_dma, GFP_KERNEL);
+       if (!tx->descs_cpu) {
+-              kfree(tx->buf);
+-              tx->buf = NULL;
+-              return -ENOMEM;
++              ret = -ENOMEM;
++              goto err_free_buf;
+       }
+       rx->buf = &tx->buf[tx_size];
+@@ -1155,7 +1155,21 @@ static int ag71xx_rings_init(struct ag71
+       rx->descs_dma = tx->descs_dma + tx_size * AG71XX_DESC_SIZE;
+       ag71xx_ring_tx_init(ag);
+-      return ag71xx_ring_rx_init(ag);
++      ret = ag71xx_ring_rx_init(ag);
++      if (ret)
++              goto err_free_dma;
++
++      return 0;
++
++err_free_dma:
++      dma_free_coherent(&ag->pdev->dev, ring_size * AG71XX_DESC_SIZE,
++                        tx->descs_cpu, tx->descs_dma);
++      rx->buf = NULL;
++err_free_buf:
++      kfree(tx->buf);
++      tx->buf = NULL;
++
++      return ret;
+ }
+ static void ag71xx_rings_free(struct ag71xx *ag)
diff --git a/target/linux/ath79/patches-5.4/201-ag71xx-Call-ag71xx_hw_disable-in-case-phy_conenct-fa.patch b/target/linux/ath79/patches-5.4/201-ag71xx-Call-ag71xx_hw_disable-in-case-phy_conenct-fa.patch
new file mode 100644 (file)
index 0000000..16d60a4
--- /dev/null
@@ -0,0 +1,45 @@
+From 2f8c5a68d0030ae5e65fca1bf5ca44929d5b3b06 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Mon, 17 Feb 2020 23:50:23 +0100
+Subject: [PATCH 2/3] ag71xx: Call ag71xx_hw_disable() in case phy_conenct
+ fails
+
+When the ag71xx_phy_connect() failed only parts of the actions done
+previously in this function wrere reverted, because only
+ag71xx_rings_cleanup() was called. My system crashed the next time
+open() was called because napi_disable() was not called again and this
+resulted in two calls to napi_enable(), which is not allowed.
+
+Fix this by disabling the device again.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+Fixes: d51b6ce441d3 ("net: ethernet: add ag71xx driver")
+---
+ drivers/net/ethernet/atheros/ag71xx.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/ethernet/atheros/ag71xx.c
++++ b/drivers/net/ethernet/atheros/ag71xx.c
+@@ -1263,18 +1263,18 @@ static int ag71xx_open(struct net_device
+       ret = ag71xx_hw_enable(ag);
+       if (ret)
+-              goto err;
++              return ret;
+       ret = ag71xx_phy_connect(ag);
+       if (ret)
+-              goto err;
++              goto err_hw_disable;
+       phy_start(ndev->phydev);
+       return 0;
+-err:
+-      ag71xx_rings_cleanup(ag);
++err_hw_disable:
++      ag71xx_hw_disable(ag);
+       return ret;
+ }
diff --git a/target/linux/ath79/patches-5.4/202-ag71xx-Run-ag71xx_link_adjust-only-when-needed.patch b/target/linux/ath79/patches-5.4/202-ag71xx-Run-ag71xx_link_adjust-only-when-needed.patch
new file mode 100644 (file)
index 0000000..00f34df
--- /dev/null
@@ -0,0 +1,69 @@
+From d42c6bf2752a46bdf3931bd6e56db419742fbb20 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Mon, 17 Feb 2020 23:55:22 +0100
+Subject: [PATCH 3/3] ag71xx: Run ag71xx_link_adjust() only when needed
+
+My system printed this line every second:
+  ag71xx 19000000.eth eth0: Link is Up - 1Gbps/Full - flow control off
+The function ag71xx_phy_link_adjust() was called by the PHY layer every
+second even when nothing changed.
+
+With this patch the old status is stored and the real
+ag71xx_link_adjust() function is only called when when something really
+changed. This way the update and also this print is only done once any
+more.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+Fixes: d51b6ce441d3 ("net: ethernet: add ag71xx driver")
+---
+ drivers/net/ethernet/atheros/ag71xx.c | 24 +++++++++++++++++++++++-
+ 1 file changed, 23 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/atheros/ag71xx.c
++++ b/drivers/net/ethernet/atheros/ag71xx.c
+@@ -307,6 +307,10 @@ struct ag71xx {
+       u32 msg_enable;
+       const struct ag71xx_dcfg *dcfg;
++      unsigned int            link;
++      unsigned int            speed;
++      int                     duplex;
++
+       /* From this point onwards we're not looking at per-packet fields. */
+       void __iomem *mac_base;
+@@ -854,6 +858,7 @@ static void ag71xx_link_adjust(struct ag
+       if (!phydev->link && update) {
+               ag71xx_hw_stop(ag);
++              phy_print_status(phydev);
+               return;
+       }
+@@ -907,8 +912,25 @@ static void ag71xx_link_adjust(struct ag
+ static void ag71xx_phy_link_adjust(struct net_device *ndev)
+ {
+       struct ag71xx *ag = netdev_priv(ndev);
++      struct phy_device *phydev = ndev->phydev;
++      int status_change = 0;
++
++      if (phydev->link) {
++              if (ag->duplex != phydev->duplex
++                  || ag->speed != phydev->speed) {
++                      status_change = 1;
++              }
++      }
++
++      if (phydev->link != ag->link)
++              status_change = 1;
++
++      ag->link = phydev->link;
++      ag->duplex = phydev->duplex;
++      ag->speed = phydev->speed;
+-      ag71xx_link_adjust(ag, true);
++      if (status_change)
++              ag71xx_link_adjust(ag, true);
+ }
+ static int ag71xx_phy_connect(struct ag71xx *ag)