Commit bcdba833 authored by Iyappan Subramanian's avatar Iyappan Subramanian Committed by Luis Henriques

drivers: net: xgene: Fix module unload crash - clkrst sequence

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: default avatarIyappan Subramanian <isubramanian@apm.com>
Tested-by: default avatarFushen Chen <fchen@apm.com>
Tested-by: default avatarToan Le <toanle@apm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
(cherry picked from commit bc61167a yakkety)
Signed-off-by: default avatarCraig Magina <craig.magina@canonical.com>
Acked-by: default avatarTim Gardner <tim.gardner@canonical.com>
Acked-by: default avatarSeth Forshee <seth.forshee@canonical.com>
Signed-off-by: default avatarSeth Forshee <seth.forshee@canonical.com>
parent 2142a741
...@@ -675,24 +675,33 @@ bool xgene_ring_mgr_init(struct xgene_enet_pdata *p) ...@@ -675,24 +675,33 @@ bool xgene_ring_mgr_init(struct xgene_enet_pdata *p)
static int xgene_enet_reset(struct xgene_enet_pdata *pdata) static int xgene_enet_reset(struct xgene_enet_pdata *pdata)
{ {
u32 val; struct device *dev = &pdata->pdev->dev;
if (!xgene_ring_mgr_init(pdata)) if (!xgene_ring_mgr_init(pdata))
return -ENODEV; return -ENODEV;
if (!IS_ERR(pdata->clk)) { if (dev->of_node) {
clk_prepare_enable(pdata->clk); clk_prepare_enable(pdata->clk);
udelay(5);
clk_disable_unprepare(pdata->clk); clk_disable_unprepare(pdata->clk);
udelay(5);
clk_prepare_enable(pdata->clk); 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_ecc_init(pdata);
xgene_enet_rd_mcx_mac(pdata, MII_MGMT_CONFIG_ADDR, &val); xgene_enet_config_ring_if_assoc(pdata);
val |= SCAN_AUTO_INCR;
MGMT_CLOCK_SEL_SET(&val, 1);
xgene_enet_wr_mcx_mac(pdata, MII_MGMT_CONFIG_ADDR, val);
return 0; return 0;
} }
...@@ -717,6 +726,7 @@ static void xgene_enet_clear(struct xgene_enet_pdata *pdata, ...@@ -717,6 +726,7 @@ static void xgene_enet_clear(struct xgene_enet_pdata *pdata,
static void xgene_gport_shutdown(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; struct xgene_enet_desc_ring *ring;
u32 pb, val; u32 pb, val;
int i; int i;
...@@ -739,8 +749,10 @@ static void xgene_gport_shutdown(struct xgene_enet_pdata *pdata) ...@@ -739,8 +749,10 @@ static void xgene_gport_shutdown(struct xgene_enet_pdata *pdata)
} }
xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIWQRESET_ADDR, pb); xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIWQRESET_ADDR, pb);
if (dev->of_node) {
if (!IS_ERR(pdata->clk)) if (!IS_ERR(pdata->clk))
clk_disable_unprepare(pdata->clk); clk_disable_unprepare(pdata->clk);
}
} }
static int xgene_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum) static int xgene_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
......
...@@ -28,6 +28,12 @@ static void xgene_enet_wr_csr(struct xgene_enet_pdata *p, u32 offset, u32 val) ...@@ -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); 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, static void xgene_enet_wr_ring_if(struct xgene_enet_pdata *p,
u32 offset, u32 val) u32 offset, u32 val)
{ {
...@@ -434,17 +440,38 @@ static void xgene_sgmac_tx_disable(struct xgene_enet_pdata *p) ...@@ -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) static int xgene_enet_reset(struct xgene_enet_pdata *p)
{ {
struct device *dev = &p->pdev->dev;
if (!xgene_ring_mgr_init(p)) if (!xgene_ring_mgr_init(p))
return -ENODEV; return -ENODEV;
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)) { if (!IS_ERR(p->clk)) {
clk_prepare_enable(p->clk); clk_prepare_enable(p->clk);
udelay(5);
clk_disable_unprepare(p->clk); clk_disable_unprepare(p->clk);
udelay(5);
clk_prepare_enable(p->clk); 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
} }
if (!p->port_id) {
xgene_enet_ecc_init(p); xgene_enet_ecc_init(p);
xgene_enet_config_ring_if_assoc(p); xgene_enet_config_ring_if_assoc(p);
}
return 0; return 0;
} }
...@@ -492,6 +519,7 @@ static void xgene_enet_clear(struct xgene_enet_pdata *pdata, ...@@ -492,6 +519,7 @@ static void xgene_enet_clear(struct xgene_enet_pdata *pdata,
static void xgene_enet_shutdown(struct xgene_enet_pdata *p) static void xgene_enet_shutdown(struct xgene_enet_pdata *p)
{ {
struct device *dev = &p->pdev->dev;
struct xgene_enet_desc_ring *ring; struct xgene_enet_desc_ring *ring;
u32 pb, val; u32 pb, val;
int i; int i;
...@@ -513,6 +541,11 @@ static void xgene_enet_shutdown(struct xgene_enet_pdata *p) ...@@ -513,6 +541,11 @@ static void xgene_enet_shutdown(struct xgene_enet_pdata *p)
pb |= BIT(val); pb |= BIT(val);
} }
xgene_enet_wr_ring_if(p, ENET_CFGSSQMIWQRESET_ADDR, pb); 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) static void xgene_enet_link_state(struct work_struct *work)
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#define LINK_UP BIT(15) #define LINK_UP BIT(15)
#define MPA_IDLE_WITH_QMI_EMPTY BIT(12) #define MPA_IDLE_WITH_QMI_EMPTY BIT(12)
#define SG_RX_DV_GATE_REG_0_ADDR 0x05fc #define SG_RX_DV_GATE_REG_0_ADDR 0x05fc
#define SGMII_EN 0x1
extern struct xgene_mac_ops xgene_sgmac_ops; extern struct xgene_mac_ops xgene_sgmac_ops;
......
...@@ -258,13 +258,29 @@ static void xgene_xgmac_tx_disable(struct xgene_enet_pdata *pdata) ...@@ -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) static int xgene_enet_reset(struct xgene_enet_pdata *pdata)
{ {
struct device *dev = &pdata->pdev->dev;
if (!xgene_ring_mgr_init(pdata)) if (!xgene_ring_mgr_init(pdata))
return -ENODEV; return -ENODEV;
if (!IS_ERR(pdata->clk)) { if (dev->of_node) {
clk_prepare_enable(pdata->clk); clk_prepare_enable(pdata->clk);
udelay(5);
clk_disable_unprepare(pdata->clk); clk_disable_unprepare(pdata->clk);
udelay(5);
clk_prepare_enable(pdata->clk); 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); xgene_enet_ecc_init(pdata);
...@@ -292,6 +308,7 @@ static void xgene_enet_xgcle_bypass(struct xgene_enet_pdata *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) static void xgene_enet_shutdown(struct xgene_enet_pdata *pdata)
{ {
struct device *dev = &pdata->pdev->dev;
struct xgene_enet_desc_ring *ring; struct xgene_enet_desc_ring *ring;
u32 pb, val; u32 pb, val;
int i; int i;
...@@ -313,6 +330,11 @@ static void xgene_enet_shutdown(struct xgene_enet_pdata *pdata) ...@@ -313,6 +330,11 @@ static void xgene_enet_shutdown(struct xgene_enet_pdata *pdata)
pb |= BIT(val); pb |= BIT(val);
} }
xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIWQRESET_ADDR, pb); 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, static void xgene_enet_clear(struct xgene_enet_pdata *pdata,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment