Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bc61167a authored by Iyappan Subramanian's avatar Iyappan Subramanian Committed by David S. Miller
Browse files

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: 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>
parent cb0366b7
Loading
Loading
Loading
Loading
+23 −11
Original line number Diff line number Diff line
@@ -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,9 +749,11 @@ static void xgene_gport_shutdown(struct xgene_enet_pdata *pdata)
	}
	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 int xgene_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
{
+39 −6
Original line number Diff line number Diff line
@@ -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 (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
	}

	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)
+1 −0
Original line number Diff line number Diff line
@@ -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,
+23 −1
Original line number Diff line number Diff line
@@ -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,