forked from Minki/linux
drivers: net: xgene: Fix module unload crash - clkrst sequence
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>
This commit is contained in:
parent
cb0366b7c1
commit
bc61167ac8
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
||||
enum xgene_phy_speed {
|
||||
PHY_SPEED_10,
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user