]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/commitdiff
drivers: net: xgene: Fix module unload crash - clkrst sequence
authorIyappan Subramanian <isubramanian@apm.com>
Tue, 26 Jul 2016 00:12:39 +0000 (17:12 -0700)
committerLuis Henriques <luis.henriques@canonical.com>
Tue, 8 Nov 2016 16:44:10 +0000 (16:44 +0000)
BugLink: https://launchpad.net/bugs/1632739
This patch fixes clock reset sequence.

- Added clock reset sequence for ACPI
- Added delay in clock reset sequence to make sure pulse is generated
- Added clk_unprepare_disable() in port shutdown to make sure
  clock increment/decrement counts are matching
- Removed MII_MGMT_CONFIG programming, since it is not required
- Fixed programming XGENET_CONFIG_REG to enable SGMII mode

Signed-off-by: Iyappan Subramanian <isubramanian@apm.com>
Tested-by: Fushen Chen <fchen@apm.com>
Tested-by: Toan Le <toanle@apm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
(cherry picked from commit bc61167ac816621c94f722177d2ae718c103005f yakkety)
Signed-off-by: Craig Magina <craig.magina@canonical.com>
Acked-by: Tim Gardner <tim.gardner@canonical.com>
Acked-by: Seth Forshee <seth.forshee@canonical.com>
Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
drivers/net/ethernet/apm/xgene/xgene_enet_hw.c
drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c
drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.h
drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c

index 312f3a32c3d24e1437c29d96247b12e984c5f5a9..92fa9c74a59355b22d2224a75928481b49c9998b 100644 (file)
@@ -675,24 +675,33 @@ bool xgene_ring_mgr_init(struct xgene_enet_pdata *p)
 
 static int xgene_enet_reset(struct xgene_enet_pdata *pdata)
 {
-       u32 val;
+       struct device *dev = &pdata->pdev->dev;
 
        if (!xgene_ring_mgr_init(pdata))
                return -ENODEV;
 
-       if (!IS_ERR(pdata->clk)) {
+       if (dev->of_node) {
                clk_prepare_enable(pdata->clk);
+               udelay(5);
                clk_disable_unprepare(pdata->clk);
+               udelay(5);
                clk_prepare_enable(pdata->clk);
-               xgene_enet_ecc_init(pdata);
+               udelay(5);
+       } else {
+#ifdef CONFIG_ACPI
+               if (acpi_has_method(ACPI_HANDLE(&pdata->pdev->dev), "_RST")) {
+                       acpi_evaluate_object(ACPI_HANDLE(&pdata->pdev->dev),
+                                            "_RST", NULL, NULL);
+               } else if (acpi_has_method(ACPI_HANDLE(&pdata->pdev->dev),
+                                        "_INI")) {
+                       acpi_evaluate_object(ACPI_HANDLE(&pdata->pdev->dev),
+                                            "_INI", NULL, NULL);
+               }
+#endif
        }
-       xgene_enet_config_ring_if_assoc(pdata);
 
-       /* Enable auto-incr for scanning */
-       xgene_enet_rd_mcx_mac(pdata, MII_MGMT_CONFIG_ADDR, &val);
-       val |= SCAN_AUTO_INCR;
-       MGMT_CLOCK_SEL_SET(&val, 1);
-       xgene_enet_wr_mcx_mac(pdata, MII_MGMT_CONFIG_ADDR, val);
+       xgene_enet_ecc_init(pdata);
+       xgene_enet_config_ring_if_assoc(pdata);
 
        return 0;
 }
@@ -717,6 +726,7 @@ static void xgene_enet_clear(struct xgene_enet_pdata *pdata,
 
 static void xgene_gport_shutdown(struct xgene_enet_pdata *pdata)
 {
+       struct device *dev = &pdata->pdev->dev;
        struct xgene_enet_desc_ring *ring;
        u32 pb, val;
        int i;
@@ -739,8 +749,10 @@ static void xgene_gport_shutdown(struct xgene_enet_pdata *pdata)
        }
        xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIWQRESET_ADDR, pb);
 
-       if (!IS_ERR(pdata->clk))
-               clk_disable_unprepare(pdata->clk);
+       if (dev->of_node) {
+               if (!IS_ERR(pdata->clk))
+                       clk_disable_unprepare(pdata->clk);
+       }
 }
 
 static int xgene_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
index 5a13047d001795c37c25d0ff9ae13b9d18f039af..6c4911097000d95d70c97f48cacbae39be9706c2 100644 (file)
@@ -28,6 +28,12 @@ static void xgene_enet_wr_csr(struct xgene_enet_pdata *p, u32 offset, u32 val)
        iowrite32(val, p->eth_csr_addr + offset);
 }
 
+static void xgene_enet_wr_clkrst_csr(struct xgene_enet_pdata *p, u32 offset,
+                                    u32 val)
+{
+       iowrite32(val, p->base_addr + offset);
+}
+
 static void xgene_enet_wr_ring_if(struct xgene_enet_pdata *p,
                                  u32 offset, u32 val)
 {
@@ -434,17 +440,38 @@ static void xgene_sgmac_tx_disable(struct xgene_enet_pdata *p)
 
 static int xgene_enet_reset(struct xgene_enet_pdata *p)
 {
+       struct device *dev = &p->pdev->dev;
+
        if (!xgene_ring_mgr_init(p))
                return -ENODEV;
 
-       if (!IS_ERR(p->clk)) {
-               clk_prepare_enable(p->clk);
-               clk_disable_unprepare(p->clk);
-               clk_prepare_enable(p->clk);
+       if (p->enet_id == XGENE_ENET2)
+               xgene_enet_wr_clkrst_csr(p, XGENET_CONFIG_REG_ADDR, SGMII_EN);
+
+       if (dev->of_node) {
+               if (!IS_ERR(p->clk)) {
+                       clk_prepare_enable(p->clk);
+                       udelay(5);
+                       clk_disable_unprepare(p->clk);
+                       udelay(5);
+                       clk_prepare_enable(p->clk);
+                       udelay(5);
+               }
+       } else {
+#ifdef CONFIG_ACPI
+               if (acpi_has_method(ACPI_HANDLE(&p->pdev->dev), "_RST"))
+                       acpi_evaluate_object(ACPI_HANDLE(&p->pdev->dev),
+                                            "_RST", NULL, NULL);
+               else if (acpi_has_method(ACPI_HANDLE(&p->pdev->dev), "_INI"))
+                       acpi_evaluate_object(ACPI_HANDLE(&p->pdev->dev),
+                                            "_INI", NULL, NULL);
+#endif
        }
 
-       xgene_enet_ecc_init(p);
-       xgene_enet_config_ring_if_assoc(p);
+       if (!p->port_id) {
+               xgene_enet_ecc_init(p);
+               xgene_enet_config_ring_if_assoc(p);
+       }
 
        return 0;
 }
@@ -492,6 +519,7 @@ static void xgene_enet_clear(struct xgene_enet_pdata *pdata,
 
 static void xgene_enet_shutdown(struct xgene_enet_pdata *p)
 {
+       struct device *dev = &p->pdev->dev;
        struct xgene_enet_desc_ring *ring;
        u32 pb, val;
        int i;
@@ -513,6 +541,11 @@ static void xgene_enet_shutdown(struct xgene_enet_pdata *p)
                pb |= BIT(val);
        }
        xgene_enet_wr_ring_if(p, ENET_CFGSSQMIWQRESET_ADDR, pb);
+
+       if (dev->of_node) {
+               if (!IS_ERR(p->clk))
+                       clk_disable_unprepare(p->clk);
+       }
 }
 
 static void xgene_enet_link_state(struct work_struct *work)
index 718544ed37bee9c0d24f8bbe6b2a4dbd34e7e18d..e78202c906ede05bc54447743bb25536b1e63f0e 100644 (file)
@@ -35,6 +35,7 @@
 #define LINK_UP                                BIT(15)
 #define MPA_IDLE_WITH_QMI_EMPTY                BIT(12)
 #define SG_RX_DV_GATE_REG_0_ADDR       0x05fc
+#define SGMII_EN                       0x1
 
 
 extern struct xgene_mac_ops xgene_sgmac_ops;
index 9a5d56492054341548f12ce35cfe185ba484fd7f..12d869a65d33587835db2d6866bf76f50b133a43 100644 (file)
@@ -258,13 +258,29 @@ static void xgene_xgmac_tx_disable(struct xgene_enet_pdata *pdata)
 
 static int xgene_enet_reset(struct xgene_enet_pdata *pdata)
 {
+       struct device *dev = &pdata->pdev->dev;
+
        if (!xgene_ring_mgr_init(pdata))
                return -ENODEV;
 
-       if (!IS_ERR(pdata->clk)) {
+       if (dev->of_node) {
                clk_prepare_enable(pdata->clk);
+               udelay(5);
                clk_disable_unprepare(pdata->clk);
+               udelay(5);
                clk_prepare_enable(pdata->clk);
+               udelay(5);
+       } else {
+#ifdef CONFIG_ACPI
+               if (acpi_has_method(ACPI_HANDLE(&pdata->pdev->dev), "_RST")) {
+                       acpi_evaluate_object(ACPI_HANDLE(&pdata->pdev->dev),
+                                            "_RST", NULL, NULL);
+               } else if (acpi_has_method(ACPI_HANDLE(&pdata->pdev->dev),
+                                          "_INI")) {
+                       acpi_evaluate_object(ACPI_HANDLE(&pdata->pdev->dev),
+                                            "_INI", NULL, NULL);
+               }
+#endif
        }
 
        xgene_enet_ecc_init(pdata);
@@ -292,6 +308,7 @@ static void xgene_enet_xgcle_bypass(struct xgene_enet_pdata *pdata,
 
 static void xgene_enet_shutdown(struct xgene_enet_pdata *pdata)
 {
+       struct device *dev = &pdata->pdev->dev;
        struct xgene_enet_desc_ring *ring;
        u32 pb, val;
        int i;
@@ -313,6 +330,11 @@ static void xgene_enet_shutdown(struct xgene_enet_pdata *pdata)
                pb |= BIT(val);
        }
        xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIWQRESET_ADDR, pb);
+
+       if (dev->of_node) {
+               if (!IS_ERR(pdata->clk))
+                       clk_disable_unprepare(pdata->clk);
+       }
 }
 
 static void xgene_enet_clear(struct xgene_enet_pdata *pdata,