Skip to content

Commit 40755a0

Browse files
ffainellidavem330
authored andcommitted
net: systemport: add suspend and resume support
Implement the hardware recommended suspend/resume procedure for SYSTEMPORT. We leverage the previous factoring work such that we can logically break all suspend/resume operations into disctint RX and TX code paths. When the system enters S3, we will loose all register contents, so make sure that we correctly re-program all the hardware and software views of the RX & TX rings as well. Signed-off-by: Florian Fainelli <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent b02e6d9 commit 40755a0

File tree

1 file changed

+160
-4
lines changed

1 file changed

+160
-4
lines changed

drivers/net/ethernet/broadcom/bcmsysport.c

Lines changed: 160 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1311,11 +1311,19 @@ static void bcm_sysport_netif_start(struct net_device *dev)
13111311
netif_tx_start_all_queues(dev);
13121312
}
13131313

1314+
static void rbuf_init(struct bcm_sysport_priv *priv)
1315+
{
1316+
u32 reg;
1317+
1318+
reg = rbuf_readl(priv, RBUF_CONTROL);
1319+
reg |= RBUF_4B_ALGN | RBUF_RSB_EN;
1320+
rbuf_writel(priv, reg, RBUF_CONTROL);
1321+
}
1322+
13141323
static int bcm_sysport_open(struct net_device *dev)
13151324
{
13161325
struct bcm_sysport_priv *priv = netdev_priv(dev);
13171326
unsigned int i;
1318-
u32 reg;
13191327
int ret;
13201328

13211329
/* Reset UniMAC */
@@ -1332,9 +1340,7 @@ static int bcm_sysport_open(struct net_device *dev)
13321340
umac_enable_set(priv, CMD_RX_EN | CMD_TX_EN, 0);
13331341

13341342
/* Enable RBUF 2bytes alignment and Receive Status Block */
1335-
reg = rbuf_readl(priv, RBUF_CONTROL);
1336-
reg |= RBUF_4B_ALGN | RBUF_RSB_EN;
1337-
rbuf_writel(priv, reg, RBUF_CONTROL);
1343+
rbuf_init(priv);
13381344

13391345
/* Set maximum frame length */
13401346
umac_writel(priv, UMAC_MAX_MTU_SIZE, UMAC_MAX_FRAME_LEN);
@@ -1640,6 +1646,155 @@ static int bcm_sysport_remove(struct platform_device *pdev)
16401646
return 0;
16411647
}
16421648

1649+
#ifdef CONFIG_PM_SLEEP
1650+
static int bcm_sysport_suspend(struct device *d)
1651+
{
1652+
struct net_device *dev = dev_get_drvdata(d);
1653+
struct bcm_sysport_priv *priv = netdev_priv(dev);
1654+
unsigned int i;
1655+
int ret;
1656+
u32 reg;
1657+
1658+
if (!netif_running(dev))
1659+
return 0;
1660+
1661+
bcm_sysport_netif_stop(dev);
1662+
1663+
phy_suspend(priv->phydev);
1664+
1665+
netif_device_detach(dev);
1666+
1667+
/* Disable UniMAC RX */
1668+
umac_enable_set(priv, CMD_RX_EN, 0);
1669+
1670+
ret = rdma_enable_set(priv, 0);
1671+
if (ret) {
1672+
netdev_err(dev, "RDMA timeout!\n");
1673+
return ret;
1674+
}
1675+
1676+
/* Disable RXCHK if enabled */
1677+
if (priv->rx_csum_en) {
1678+
reg = rxchk_readl(priv, RXCHK_CONTROL);
1679+
reg &= ~RXCHK_EN;
1680+
rxchk_writel(priv, reg, RXCHK_CONTROL);
1681+
}
1682+
1683+
/* Flush RX pipe */
1684+
topctrl_writel(priv, RX_FLUSH, RX_FLUSH_CNTL);
1685+
1686+
ret = tdma_enable_set(priv, 0);
1687+
if (ret) {
1688+
netdev_err(dev, "TDMA timeout!\n");
1689+
return ret;
1690+
}
1691+
1692+
/* Wait for a packet boundary */
1693+
usleep_range(2000, 3000);
1694+
1695+
umac_enable_set(priv, CMD_TX_EN, 0);
1696+
1697+
topctrl_writel(priv, TX_FLUSH, TX_FLUSH_CNTL);
1698+
1699+
/* Free RX/TX rings SW structures */
1700+
for (i = 0; i < dev->num_tx_queues; i++)
1701+
bcm_sysport_fini_tx_ring(priv, i);
1702+
bcm_sysport_fini_rx_ring(priv);
1703+
1704+
return 0;
1705+
}
1706+
1707+
static int bcm_sysport_resume(struct device *d)
1708+
{
1709+
struct net_device *dev = dev_get_drvdata(d);
1710+
struct bcm_sysport_priv *priv = netdev_priv(dev);
1711+
unsigned int i;
1712+
u32 reg;
1713+
int ret;
1714+
1715+
if (!netif_running(dev))
1716+
return 0;
1717+
1718+
/* Initialize both hardware and software ring */
1719+
for (i = 0; i < dev->num_tx_queues; i++) {
1720+
ret = bcm_sysport_init_tx_ring(priv, i);
1721+
if (ret) {
1722+
netdev_err(dev, "failed to initialize TX ring %d\n",
1723+
i);
1724+
goto out_free_tx_rings;
1725+
}
1726+
}
1727+
1728+
/* Initialize linked-list */
1729+
tdma_writel(priv, TDMA_LL_RAM_INIT_BUSY, TDMA_STATUS);
1730+
1731+
/* Initialize RX ring */
1732+
ret = bcm_sysport_init_rx_ring(priv);
1733+
if (ret) {
1734+
netdev_err(dev, "failed to initialize RX ring\n");
1735+
goto out_free_rx_ring;
1736+
}
1737+
1738+
netif_device_attach(dev);
1739+
1740+
/* Enable RX interrupt and TX ring full interrupt */
1741+
intrl2_0_mask_clear(priv, INTRL2_0_RDMA_MBDONE | INTRL2_0_TX_RING_FULL);
1742+
1743+
/* RX pipe enable */
1744+
topctrl_writel(priv, 0, RX_FLUSH_CNTL);
1745+
1746+
ret = rdma_enable_set(priv, 1);
1747+
if (ret) {
1748+
netdev_err(dev, "failed to enable RDMA\n");
1749+
goto out_free_rx_ring;
1750+
}
1751+
1752+
/* Enable rxhck */
1753+
if (priv->rx_csum_en) {
1754+
reg = rxchk_readl(priv, RXCHK_CONTROL);
1755+
reg |= RXCHK_EN;
1756+
rxchk_writel(priv, reg, RXCHK_CONTROL);
1757+
}
1758+
1759+
rbuf_init(priv);
1760+
1761+
/* Set maximum frame length */
1762+
umac_writel(priv, UMAC_MAX_MTU_SIZE, UMAC_MAX_FRAME_LEN);
1763+
1764+
/* Set MAC address */
1765+
umac_set_hw_addr(priv, dev->dev_addr);
1766+
1767+
umac_enable_set(priv, CMD_RX_EN, 1);
1768+
1769+
/* TX pipe enable */
1770+
topctrl_writel(priv, 0, TX_FLUSH_CNTL);
1771+
1772+
umac_enable_set(priv, CMD_TX_EN, 1);
1773+
1774+
ret = tdma_enable_set(priv, 1);
1775+
if (ret) {
1776+
netdev_err(dev, "TDMA timeout!\n");
1777+
goto out_free_rx_ring;
1778+
}
1779+
1780+
phy_resume(priv->phydev);
1781+
1782+
bcm_sysport_netif_start(dev);
1783+
1784+
return 0;
1785+
1786+
out_free_rx_ring:
1787+
bcm_sysport_fini_rx_ring(priv);
1788+
out_free_tx_rings:
1789+
for (i = 0; i < dev->num_tx_queues; i++)
1790+
bcm_sysport_fini_tx_ring(priv, i);
1791+
return ret;
1792+
}
1793+
#endif
1794+
1795+
static SIMPLE_DEV_PM_OPS(bcm_sysport_pm_ops,
1796+
bcm_sysport_suspend, bcm_sysport_resume);
1797+
16431798
static const struct of_device_id bcm_sysport_of_match[] = {
16441799
{ .compatible = "brcm,systemport-v1.00" },
16451800
{ .compatible = "brcm,systemport" },
@@ -1653,6 +1808,7 @@ static struct platform_driver bcm_sysport_driver = {
16531808
.name = "brcm-systemport",
16541809
.owner = THIS_MODULE,
16551810
.of_match_table = bcm_sysport_of_match,
1811+
.pm = &bcm_sysport_pm_ops,
16561812
},
16571813
};
16581814
module_platform_driver(bcm_sysport_driver);

0 commit comments

Comments
 (0)