diff options
author | David S. Miller <davem@davemloft.net> | 2014-07-21 19:04:37 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-07-21 19:04:37 -0400 |
commit | bb1fed7110c287024dce6bee8152aad903104d96 (patch) | |
tree | 8062476c2325870473869bb27217f7f22093bc51 | |
parent | 575a19354c80fde236382755592256d30d2a27fb (diff) | |
parent | 06ba8375ec42daae19124eaa106295dbe159731f (diff) |
Merge branch 'bcmgenet-next'
Florian Fainelli says:
====================
net: bcmgenet: PM and Wake-on-LAN
This patchset brings S2/S3 Power Management support to the GENET driver
as well as Wake-on-LAN using Magic Packets with or without SecureOn
passwords.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ethernet/broadcom/genet/Makefile | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/genet/bcmgenet.c | 270 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/genet/bcmgenet.h | 12 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c | 206 |
4 files changed, 430 insertions, 60 deletions
diff --git a/drivers/net/ethernet/broadcom/genet/Makefile b/drivers/net/ethernet/broadcom/genet/Makefile index 31f55a90a197..9b6885efa9e7 100644 --- a/drivers/net/ethernet/broadcom/genet/Makefile +++ b/drivers/net/ethernet/broadcom/genet/Makefile | |||
@@ -1,2 +1,2 @@ | |||
1 | obj-$(CONFIG_BCMGENET) += genet.o | 1 | obj-$(CONFIG_BCMGENET) += genet.o |
2 | genet-objs := bcmgenet.o bcmmii.o | 2 | genet-objs := bcmgenet.o bcmmii.o bcmgenet_wol.o |
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 16281ad2da12..0173a6d355aa 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c | |||
@@ -730,6 +730,8 @@ static struct ethtool_ops bcmgenet_ethtool_ops = { | |||
730 | .get_link = ethtool_op_get_link, | 730 | .get_link = ethtool_op_get_link, |
731 | .get_msglevel = bcmgenet_get_msglevel, | 731 | .get_msglevel = bcmgenet_get_msglevel, |
732 | .set_msglevel = bcmgenet_set_msglevel, | 732 | .set_msglevel = bcmgenet_set_msglevel, |
733 | .get_wol = bcmgenet_get_wol, | ||
734 | .set_wol = bcmgenet_set_wol, | ||
733 | }; | 735 | }; |
734 | 736 | ||
735 | /* Power down the unimac, based on mode. */ | 737 | /* Power down the unimac, based on mode. */ |
@@ -743,6 +745,10 @@ static void bcmgenet_power_down(struct bcmgenet_priv *priv, | |||
743 | phy_detach(priv->phydev); | 745 | phy_detach(priv->phydev); |
744 | break; | 746 | break; |
745 | 747 | ||
748 | case GENET_POWER_WOL_MAGIC: | ||
749 | bcmgenet_wol_power_down_cfg(priv, mode); | ||
750 | break; | ||
751 | |||
746 | case GENET_POWER_PASSIVE: | 752 | case GENET_POWER_PASSIVE: |
747 | /* Power down LED */ | 753 | /* Power down LED */ |
748 | bcmgenet_mii_reset(priv->dev); | 754 | bcmgenet_mii_reset(priv->dev); |
@@ -777,6 +783,9 @@ static void bcmgenet_power_up(struct bcmgenet_priv *priv, | |||
777 | /* enable APD */ | 783 | /* enable APD */ |
778 | reg |= EXT_PWR_DN_EN_LD; | 784 | reg |= EXT_PWR_DN_EN_LD; |
779 | break; | 785 | break; |
786 | case GENET_POWER_WOL_MAGIC: | ||
787 | bcmgenet_wol_power_up_cfg(priv, mode); | ||
788 | return; | ||
780 | default: | 789 | default: |
781 | break; | 790 | break; |
782 | } | 791 | } |
@@ -1437,6 +1446,25 @@ static void bcmgenet_free_rx_buffers(struct bcmgenet_priv *priv) | |||
1437 | } | 1446 | } |
1438 | } | 1447 | } |
1439 | 1448 | ||
1449 | static void umac_enable_set(struct bcmgenet_priv *priv, u32 mask, | ||
1450 | bool enable) | ||
1451 | { | ||
1452 | u32 reg; | ||
1453 | |||
1454 | reg = bcmgenet_umac_readl(priv, UMAC_CMD); | ||
1455 | if (enable) | ||
1456 | reg |= mask; | ||
1457 | else | ||
1458 | reg &= ~mask; | ||
1459 | bcmgenet_umac_writel(priv, reg, UMAC_CMD); | ||
1460 | |||
1461 | /* UniMAC stops on a packet boundary, wait for a full-size packet | ||
1462 | * to be processed | ||
1463 | */ | ||
1464 | if (enable == 0) | ||
1465 | usleep_range(1000, 2000); | ||
1466 | } | ||
1467 | |||
1440 | static int reset_umac(struct bcmgenet_priv *priv) | 1468 | static int reset_umac(struct bcmgenet_priv *priv) |
1441 | { | 1469 | { |
1442 | struct device *kdev = &priv->pdev->dev; | 1470 | struct device *kdev = &priv->pdev->dev; |
@@ -1469,6 +1497,17 @@ static int reset_umac(struct bcmgenet_priv *priv) | |||
1469 | return 0; | 1497 | return 0; |
1470 | } | 1498 | } |
1471 | 1499 | ||
1500 | static void bcmgenet_intr_disable(struct bcmgenet_priv *priv) | ||
1501 | { | ||
1502 | /* Mask all interrupts.*/ | ||
1503 | bcmgenet_intrl2_0_writel(priv, 0xFFFFFFFF, INTRL2_CPU_MASK_SET); | ||
1504 | bcmgenet_intrl2_0_writel(priv, 0xFFFFFFFF, INTRL2_CPU_CLEAR); | ||
1505 | bcmgenet_intrl2_0_writel(priv, 0, INTRL2_CPU_MASK_CLEAR); | ||
1506 | bcmgenet_intrl2_1_writel(priv, 0xFFFFFFFF, INTRL2_CPU_MASK_SET); | ||
1507 | bcmgenet_intrl2_1_writel(priv, 0xFFFFFFFF, INTRL2_CPU_CLEAR); | ||
1508 | bcmgenet_intrl2_1_writel(priv, 0, INTRL2_CPU_MASK_CLEAR); | ||
1509 | } | ||
1510 | |||
1472 | static int init_umac(struct bcmgenet_priv *priv) | 1511 | static int init_umac(struct bcmgenet_priv *priv) |
1473 | { | 1512 | { |
1474 | struct device *kdev = &priv->pdev->dev; | 1513 | struct device *kdev = &priv->pdev->dev; |
@@ -1497,10 +1536,7 @@ static int init_umac(struct bcmgenet_priv *priv) | |||
1497 | if (!GENET_IS_V1(priv) && !GENET_IS_V2(priv)) | 1536 | if (!GENET_IS_V1(priv) && !GENET_IS_V2(priv)) |
1498 | bcmgenet_rbuf_writel(priv, 1, RBUF_TBUF_SIZE_CTRL); | 1537 | bcmgenet_rbuf_writel(priv, 1, RBUF_TBUF_SIZE_CTRL); |
1499 | 1538 | ||
1500 | /* Mask all interrupts.*/ | 1539 | bcmgenet_intr_disable(priv); |
1501 | bcmgenet_intrl2_0_writel(priv, 0xFFFFFFFF, INTRL2_CPU_MASK_SET); | ||
1502 | bcmgenet_intrl2_0_writel(priv, 0xFFFFFFFF, INTRL2_CPU_CLEAR); | ||
1503 | bcmgenet_intrl2_0_writel(priv, 0, INTRL2_CPU_MASK_CLEAR); | ||
1504 | 1540 | ||
1505 | cpu_mask_clear = UMAC_IRQ_RXDMA_BDONE; | 1541 | cpu_mask_clear = UMAC_IRQ_RXDMA_BDONE; |
1506 | 1542 | ||
@@ -1802,6 +1838,13 @@ static void bcmgenet_irq_task(struct work_struct *work) | |||
1802 | 1838 | ||
1803 | netif_dbg(priv, intr, priv->dev, "%s\n", __func__); | 1839 | netif_dbg(priv, intr, priv->dev, "%s\n", __func__); |
1804 | 1840 | ||
1841 | if (priv->irq0_stat & UMAC_IRQ_MPD_R) { | ||
1842 | priv->irq0_stat &= ~UMAC_IRQ_MPD_R; | ||
1843 | netif_dbg(priv, wol, priv->dev, | ||
1844 | "magic packet detected, waking up\n"); | ||
1845 | bcmgenet_power_up(priv, GENET_POWER_WOL_MAGIC); | ||
1846 | } | ||
1847 | |||
1805 | /* Link UP/DOWN event */ | 1848 | /* Link UP/DOWN event */ |
1806 | if ((priv->hw_params->flags & GENET_HAS_MDIO_INTR) && | 1849 | if ((priv->hw_params->flags & GENET_HAS_MDIO_INTR) && |
1807 | (priv->irq0_stat & (UMAC_IRQ_LINK_UP|UMAC_IRQ_LINK_DOWN))) { | 1850 | (priv->irq0_stat & (UMAC_IRQ_LINK_UP|UMAC_IRQ_LINK_DOWN))) { |
@@ -1891,6 +1934,15 @@ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id) | |||
1891 | return IRQ_HANDLED; | 1934 | return IRQ_HANDLED; |
1892 | } | 1935 | } |
1893 | 1936 | ||
1937 | static irqreturn_t bcmgenet_wol_isr(int irq, void *dev_id) | ||
1938 | { | ||
1939 | struct bcmgenet_priv *priv = dev_id; | ||
1940 | |||
1941 | pm_wakeup_event(&priv->pdev->dev, 0); | ||
1942 | |||
1943 | return IRQ_HANDLED; | ||
1944 | } | ||
1945 | |||
1894 | static void bcmgenet_umac_reset(struct bcmgenet_priv *priv) | 1946 | static void bcmgenet_umac_reset(struct bcmgenet_priv *priv) |
1895 | { | 1947 | { |
1896 | u32 reg; | 1948 | u32 reg; |
@@ -1915,14 +1967,8 @@ static void bcmgenet_set_hw_addr(struct bcmgenet_priv *priv, | |||
1915 | 1967 | ||
1916 | static int bcmgenet_wol_resume(struct bcmgenet_priv *priv) | 1968 | static int bcmgenet_wol_resume(struct bcmgenet_priv *priv) |
1917 | { | 1969 | { |
1918 | int ret; | ||
1919 | |||
1920 | /* From WOL-enabled suspend, switch to regular clock */ | 1970 | /* From WOL-enabled suspend, switch to regular clock */ |
1921 | clk_disable(priv->clk_wol); | 1971 | clk_disable_unprepare(priv->clk_wol); |
1922 | /* init umac registers to synchronize s/w with h/w */ | ||
1923 | ret = init_umac(priv); | ||
1924 | if (ret) | ||
1925 | return ret; | ||
1926 | 1972 | ||
1927 | phy_init_hw(priv->phydev); | 1973 | phy_init_hw(priv->phydev); |
1928 | /* Speed settings must be restored */ | 1974 | /* Speed settings must be restored */ |
@@ -1967,6 +2013,23 @@ static void bcmgenet_enable_dma(struct bcmgenet_priv *priv, u32 dma_ctrl) | |||
1967 | bcmgenet_tdma_writel(priv, reg, DMA_CTRL); | 2013 | bcmgenet_tdma_writel(priv, reg, DMA_CTRL); |
1968 | } | 2014 | } |
1969 | 2015 | ||
2016 | static void bcmgenet_netif_start(struct net_device *dev) | ||
2017 | { | ||
2018 | struct bcmgenet_priv *priv = netdev_priv(dev); | ||
2019 | |||
2020 | /* Start the network engine */ | ||
2021 | napi_enable(&priv->napi); | ||
2022 | |||
2023 | umac_enable_set(priv, CMD_TX_EN | CMD_RX_EN, true); | ||
2024 | |||
2025 | if (phy_is_internal(priv->phydev)) | ||
2026 | bcmgenet_power_up(priv, GENET_POWER_PASSIVE); | ||
2027 | |||
2028 | netif_tx_start_all_queues(dev); | ||
2029 | |||
2030 | phy_start(priv->phydev); | ||
2031 | } | ||
2032 | |||
1970 | static int bcmgenet_open(struct net_device *dev) | 2033 | static int bcmgenet_open(struct net_device *dev) |
1971 | { | 2034 | { |
1972 | struct bcmgenet_priv *priv = netdev_priv(dev); | 2035 | struct bcmgenet_priv *priv = netdev_priv(dev); |
@@ -1988,18 +2051,14 @@ static int bcmgenet_open(struct net_device *dev) | |||
1988 | goto err_clk_disable; | 2051 | goto err_clk_disable; |
1989 | 2052 | ||
1990 | /* disable ethernet MAC while updating its registers */ | 2053 | /* disable ethernet MAC while updating its registers */ |
2054 | umac_enable_set(priv, CMD_TX_EN | CMD_RX_EN, false); | ||
2055 | |||
2056 | /* Make sure we reflect the value of CRC_CMD_FWD */ | ||
1991 | reg = bcmgenet_umac_readl(priv, UMAC_CMD); | 2057 | reg = bcmgenet_umac_readl(priv, UMAC_CMD); |
1992 | reg &= ~(CMD_TX_EN | CMD_RX_EN); | 2058 | priv->crc_fwd_en = !!(reg & CMD_CRC_FWD); |
1993 | bcmgenet_umac_writel(priv, reg, UMAC_CMD); | ||
1994 | 2059 | ||
1995 | bcmgenet_set_hw_addr(priv, dev->dev_addr); | 2060 | bcmgenet_set_hw_addr(priv, dev->dev_addr); |
1996 | 2061 | ||
1997 | if (priv->wol_enabled) { | ||
1998 | ret = bcmgenet_wol_resume(priv); | ||
1999 | if (ret) | ||
2000 | return ret; | ||
2001 | } | ||
2002 | |||
2003 | if (phy_is_internal(priv->phydev)) { | 2062 | if (phy_is_internal(priv->phydev)) { |
2004 | reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT); | 2063 | reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT); |
2005 | reg |= EXT_ENERGY_DET_MASK; | 2064 | reg |= EXT_ENERGY_DET_MASK; |
@@ -2033,24 +2092,7 @@ static int bcmgenet_open(struct net_device *dev) | |||
2033 | goto err_irq0; | 2092 | goto err_irq0; |
2034 | } | 2093 | } |
2035 | 2094 | ||
2036 | /* Start the network engine */ | 2095 | bcmgenet_netif_start(dev); |
2037 | napi_enable(&priv->napi); | ||
2038 | |||
2039 | reg = bcmgenet_umac_readl(priv, UMAC_CMD); | ||
2040 | reg |= (CMD_TX_EN | CMD_RX_EN); | ||
2041 | bcmgenet_umac_writel(priv, reg, UMAC_CMD); | ||
2042 | |||
2043 | /* Make sure we reflect the value of CRC_CMD_FWD */ | ||
2044 | priv->crc_fwd_en = !!(reg & CMD_CRC_FWD); | ||
2045 | |||
2046 | device_set_wakeup_capable(&dev->dev, 1); | ||
2047 | |||
2048 | if (phy_is_internal(priv->phydev)) | ||
2049 | bcmgenet_power_up(priv, GENET_POWER_PASSIVE); | ||
2050 | |||
2051 | netif_tx_start_all_queues(dev); | ||
2052 | |||
2053 | phy_start(priv->phydev); | ||
2054 | 2096 | ||
2055 | return 0; | 2097 | return 0; |
2056 | 2098 | ||
@@ -2117,33 +2159,40 @@ static int bcmgenet_dma_teardown(struct bcmgenet_priv *priv) | |||
2117 | return ret; | 2159 | return ret; |
2118 | } | 2160 | } |
2119 | 2161 | ||
2162 | static void bcmgenet_netif_stop(struct net_device *dev) | ||
2163 | { | ||
2164 | struct bcmgenet_priv *priv = netdev_priv(dev); | ||
2165 | |||
2166 | netif_tx_stop_all_queues(dev); | ||
2167 | napi_disable(&priv->napi); | ||
2168 | phy_stop(priv->phydev); | ||
2169 | |||
2170 | bcmgenet_intr_disable(priv); | ||
2171 | |||
2172 | /* Wait for pending work items to complete. Since interrupts are | ||
2173 | * disabled no new work will be scheduled. | ||
2174 | */ | ||
2175 | cancel_work_sync(&priv->bcmgenet_irq_work); | ||
2176 | } | ||
2177 | |||
2120 | static int bcmgenet_close(struct net_device *dev) | 2178 | static int bcmgenet_close(struct net_device *dev) |
2121 | { | 2179 | { |
2122 | struct bcmgenet_priv *priv = netdev_priv(dev); | 2180 | struct bcmgenet_priv *priv = netdev_priv(dev); |
2123 | int ret; | 2181 | int ret; |
2124 | u32 reg; | ||
2125 | 2182 | ||
2126 | netif_dbg(priv, ifdown, dev, "bcmgenet_close\n"); | 2183 | netif_dbg(priv, ifdown, dev, "bcmgenet_close\n"); |
2127 | 2184 | ||
2128 | phy_stop(priv->phydev); | 2185 | bcmgenet_netif_stop(dev); |
2129 | 2186 | ||
2130 | /* Disable MAC receive */ | 2187 | /* Disable MAC receive */ |
2131 | reg = bcmgenet_umac_readl(priv, UMAC_CMD); | 2188 | umac_enable_set(priv, CMD_RX_EN, false); |
2132 | reg &= ~CMD_RX_EN; | ||
2133 | bcmgenet_umac_writel(priv, reg, UMAC_CMD); | ||
2134 | |||
2135 | netif_tx_stop_all_queues(dev); | ||
2136 | 2189 | ||
2137 | ret = bcmgenet_dma_teardown(priv); | 2190 | ret = bcmgenet_dma_teardown(priv); |
2138 | if (ret) | 2191 | if (ret) |
2139 | return ret; | 2192 | return ret; |
2140 | 2193 | ||
2141 | /* Disable MAC transmit. TX DMA disabled have to done before this */ | 2194 | /* Disable MAC transmit. TX DMA disabled have to done before this */ |
2142 | reg = bcmgenet_umac_readl(priv, UMAC_CMD); | 2195 | umac_enable_set(priv, CMD_TX_EN, false); |
2143 | reg &= ~CMD_TX_EN; | ||
2144 | bcmgenet_umac_writel(priv, reg, UMAC_CMD); | ||
2145 | |||
2146 | napi_disable(&priv->napi); | ||
2147 | 2196 | ||
2148 | /* tx reclaim */ | 2197 | /* tx reclaim */ |
2149 | bcmgenet_tx_reclaim_all(dev); | 2198 | bcmgenet_tx_reclaim_all(dev); |
@@ -2152,18 +2201,9 @@ static int bcmgenet_close(struct net_device *dev) | |||
2152 | free_irq(priv->irq0, priv); | 2201 | free_irq(priv->irq0, priv); |
2153 | free_irq(priv->irq1, priv); | 2202 | free_irq(priv->irq1, priv); |
2154 | 2203 | ||
2155 | /* Wait for pending work items to complete - we are stopping | ||
2156 | * the clock now. Since interrupts are disabled, no new work | ||
2157 | * will be scheduled. | ||
2158 | */ | ||
2159 | cancel_work_sync(&priv->bcmgenet_irq_work); | ||
2160 | |||
2161 | if (phy_is_internal(priv->phydev)) | 2204 | if (phy_is_internal(priv->phydev)) |
2162 | bcmgenet_power_down(priv, GENET_POWER_PASSIVE); | 2205 | bcmgenet_power_down(priv, GENET_POWER_PASSIVE); |
2163 | 2206 | ||
2164 | if (priv->wol_enabled) | ||
2165 | clk_enable(priv->clk_wol); | ||
2166 | |||
2167 | if (!IS_ERR(priv->clk)) | 2207 | if (!IS_ERR(priv->clk)) |
2168 | clk_disable_unprepare(priv->clk); | 2208 | clk_disable_unprepare(priv->clk); |
2169 | 2209 | ||
@@ -2450,6 +2490,7 @@ static int bcmgenet_probe(struct platform_device *pdev) | |||
2450 | priv = netdev_priv(dev); | 2490 | priv = netdev_priv(dev); |
2451 | priv->irq0 = platform_get_irq(pdev, 0); | 2491 | priv->irq0 = platform_get_irq(pdev, 0); |
2452 | priv->irq1 = platform_get_irq(pdev, 1); | 2492 | priv->irq1 = platform_get_irq(pdev, 1); |
2493 | priv->wol_irq = platform_get_irq(pdev, 2); | ||
2453 | if (!priv->irq0 || !priv->irq1) { | 2494 | if (!priv->irq0 || !priv->irq1) { |
2454 | dev_err(&pdev->dev, "can't find IRQs\n"); | 2495 | dev_err(&pdev->dev, "can't find IRQs\n"); |
2455 | err = -EINVAL; | 2496 | err = -EINVAL; |
@@ -2484,6 +2525,13 @@ static int bcmgenet_probe(struct platform_device *pdev) | |||
2484 | dev->hw_features |= NETIF_F_SG | NETIF_F_IP_CSUM | | 2525 | dev->hw_features |= NETIF_F_SG | NETIF_F_IP_CSUM | |
2485 | NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM; | 2526 | NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM; |
2486 | 2527 | ||
2528 | /* Request the WOL interrupt and advertise suspend if available */ | ||
2529 | priv->wol_irq_disabled = true; | ||
2530 | err = devm_request_irq(&pdev->dev, priv->wol_irq, bcmgenet_wol_isr, 0, | ||
2531 | dev->name, priv); | ||
2532 | if (!err) | ||
2533 | device_set_wakeup_capable(&pdev->dev, 1); | ||
2534 | |||
2487 | /* Set the needed headroom to account for any possible | 2535 | /* Set the needed headroom to account for any possible |
2488 | * features enabling/disabling at runtime | 2536 | * features enabling/disabling at runtime |
2489 | */ | 2537 | */ |
@@ -2561,6 +2609,111 @@ static int bcmgenet_remove(struct platform_device *pdev) | |||
2561 | return 0; | 2609 | return 0; |
2562 | } | 2610 | } |
2563 | 2611 | ||
2612 | #ifdef CONFIG_PM_SLEEP | ||
2613 | static int bcmgenet_suspend(struct device *d) | ||
2614 | { | ||
2615 | struct net_device *dev = dev_get_drvdata(d); | ||
2616 | struct bcmgenet_priv *priv = netdev_priv(dev); | ||
2617 | int ret; | ||
2618 | |||
2619 | if (!netif_running(dev)) | ||
2620 | return 0; | ||
2621 | |||
2622 | bcmgenet_netif_stop(dev); | ||
2623 | |||
2624 | netif_device_detach(dev); | ||
2625 | |||
2626 | /* Disable MAC receive */ | ||
2627 | umac_enable_set(priv, CMD_RX_EN, false); | ||
2628 | |||
2629 | ret = bcmgenet_dma_teardown(priv); | ||
2630 | if (ret) | ||
2631 | return ret; | ||
2632 | |||
2633 | /* Disable MAC transmit. TX DMA disabled have to done before this */ | ||
2634 | umac_enable_set(priv, CMD_TX_EN, false); | ||
2635 | |||
2636 | /* tx reclaim */ | ||
2637 | bcmgenet_tx_reclaim_all(dev); | ||
2638 | bcmgenet_fini_dma(priv); | ||
2639 | |||
2640 | /* Prepare the device for Wake-on-LAN and switch to the slow clock */ | ||
2641 | if (device_may_wakeup(d) && priv->wolopts) { | ||
2642 | bcmgenet_power_down(priv, GENET_POWER_WOL_MAGIC); | ||
2643 | clk_prepare_enable(priv->clk_wol); | ||
2644 | } | ||
2645 | |||
2646 | /* Turn off the clocks */ | ||
2647 | clk_disable_unprepare(priv->clk); | ||
2648 | |||
2649 | return 0; | ||
2650 | } | ||
2651 | |||
2652 | static int bcmgenet_resume(struct device *d) | ||
2653 | { | ||
2654 | struct net_device *dev = dev_get_drvdata(d); | ||
2655 | struct bcmgenet_priv *priv = netdev_priv(dev); | ||
2656 | unsigned long dma_ctrl; | ||
2657 | int ret; | ||
2658 | u32 reg; | ||
2659 | |||
2660 | if (!netif_running(dev)) | ||
2661 | return 0; | ||
2662 | |||
2663 | /* Turn on the clock */ | ||
2664 | ret = clk_prepare_enable(priv->clk); | ||
2665 | if (ret) | ||
2666 | return ret; | ||
2667 | |||
2668 | bcmgenet_umac_reset(priv); | ||
2669 | |||
2670 | ret = init_umac(priv); | ||
2671 | if (ret) | ||
2672 | goto out_clk_disable; | ||
2673 | |||
2674 | if (priv->wolopts) | ||
2675 | ret = bcmgenet_wol_resume(priv); | ||
2676 | |||
2677 | if (ret) | ||
2678 | goto out_clk_disable; | ||
2679 | |||
2680 | /* disable ethernet MAC while updating its registers */ | ||
2681 | umac_enable_set(priv, CMD_TX_EN | CMD_RX_EN, false); | ||
2682 | |||
2683 | bcmgenet_set_hw_addr(priv, dev->dev_addr); | ||
2684 | |||
2685 | if (phy_is_internal(priv->phydev)) { | ||
2686 | reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT); | ||
2687 | reg |= EXT_ENERGY_DET_MASK; | ||
2688 | bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT); | ||
2689 | } | ||
2690 | |||
2691 | /* Disable RX/TX DMA and flush TX queues */ | ||
2692 | dma_ctrl = bcmgenet_dma_disable(priv); | ||
2693 | |||
2694 | /* Reinitialize TDMA and RDMA and SW housekeeping */ | ||
2695 | ret = bcmgenet_init_dma(priv); | ||
2696 | if (ret) { | ||
2697 | netdev_err(dev, "failed to initialize DMA\n"); | ||
2698 | goto out_clk_disable; | ||
2699 | } | ||
2700 | |||
2701 | /* Always enable ring 16 - descriptor ring */ | ||
2702 | bcmgenet_enable_dma(priv, dma_ctrl); | ||
2703 | |||
2704 | netif_device_attach(dev); | ||
2705 | |||
2706 | bcmgenet_netif_start(dev); | ||
2707 | |||
2708 | return 0; | ||
2709 | |||
2710 | out_clk_disable: | ||
2711 | clk_disable_unprepare(priv->clk); | ||
2712 | return ret; | ||
2713 | } | ||
2714 | #endif /* CONFIG_PM_SLEEP */ | ||
2715 | |||
2716 | static SIMPLE_DEV_PM_OPS(bcmgenet_pm_ops, bcmgenet_suspend, bcmgenet_resume); | ||
2564 | 2717 | ||
2565 | static struct platform_driver bcmgenet_driver = { | 2718 | static struct platform_driver bcmgenet_driver = { |
2566 | .probe = bcmgenet_probe, | 2719 | .probe = bcmgenet_probe, |
@@ -2569,6 +2722,7 @@ static struct platform_driver bcmgenet_driver = { | |||
2569 | .name = "bcmgenet", | 2722 | .name = "bcmgenet", |
2570 | .owner = THIS_MODULE, | 2723 | .owner = THIS_MODULE, |
2571 | .of_match_table = bcmgenet_match, | 2724 | .of_match_table = bcmgenet_match, |
2725 | .pm = &bcmgenet_pm_ops, | ||
2572 | }, | 2726 | }, |
2573 | }; | 2727 | }; |
2574 | module_platform_driver(bcmgenet_driver); | 2728 | module_platform_driver(bcmgenet_driver); |
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h index e23c993b1362..c61cd98b662e 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h | |||
@@ -456,6 +456,7 @@ struct enet_cb { | |||
456 | enum bcmgenet_power_mode { | 456 | enum bcmgenet_power_mode { |
457 | GENET_POWER_CABLE_SENSE = 0, | 457 | GENET_POWER_CABLE_SENSE = 0, |
458 | GENET_POWER_PASSIVE, | 458 | GENET_POWER_PASSIVE, |
459 | GENET_POWER_WOL_MAGIC, | ||
459 | }; | 460 | }; |
460 | 461 | ||
461 | struct bcmgenet_priv; | 462 | struct bcmgenet_priv; |
@@ -569,6 +570,8 @@ struct bcmgenet_priv { | |||
569 | int irq1; | 570 | int irq1; |
570 | unsigned int irq0_stat; | 571 | unsigned int irq0_stat; |
571 | unsigned int irq1_stat; | 572 | unsigned int irq1_stat; |
573 | int wol_irq; | ||
574 | bool wol_irq_disabled; | ||
572 | 575 | ||
573 | /* HW descriptors/checksum variables */ | 576 | /* HW descriptors/checksum variables */ |
574 | bool desc_64b_en; | 577 | bool desc_64b_en; |
@@ -583,7 +586,6 @@ struct bcmgenet_priv { | |||
583 | struct platform_device *pdev; | 586 | struct platform_device *pdev; |
584 | 587 | ||
585 | /* WOL */ | 588 | /* WOL */ |
586 | unsigned long wol_enabled; | ||
587 | struct clk *clk_wol; | 589 | struct clk *clk_wol; |
588 | u32 wolopts; | 590 | u32 wolopts; |
589 | 591 | ||
@@ -625,4 +627,12 @@ int bcmgenet_mii_config(struct net_device *dev); | |||
625 | void bcmgenet_mii_exit(struct net_device *dev); | 627 | void bcmgenet_mii_exit(struct net_device *dev); |
626 | void bcmgenet_mii_reset(struct net_device *dev); | 628 | void bcmgenet_mii_reset(struct net_device *dev); |
627 | 629 | ||
630 | /* Wake-on-LAN routines */ | ||
631 | void bcmgenet_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol); | ||
632 | int bcmgenet_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol); | ||
633 | int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv, | ||
634 | enum bcmgenet_power_mode mode); | ||
635 | void bcmgenet_wol_power_up_cfg(struct bcmgenet_priv *priv, | ||
636 | enum bcmgenet_power_mode mode); | ||
637 | |||
628 | #endif /* __BCMGENET_H__ */ | 638 | #endif /* __BCMGENET_H__ */ |
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c new file mode 100644 index 000000000000..b82b7e4e06b2 --- /dev/null +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c | |||
@@ -0,0 +1,206 @@ | |||
1 | /* | ||
2 | * Broadcom GENET (Gigabit Ethernet) Wake-on-LAN support | ||
3 | * | ||
4 | * Copyright (c) 2014 Broadcom Corporation | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #define pr_fmt(fmt) "bcmgenet_wol: " fmt | ||
12 | |||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/sched.h> | ||
16 | #include <linux/types.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/string.h> | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/errno.h> | ||
21 | #include <linux/delay.h> | ||
22 | #include <linux/pm.h> | ||
23 | #include <linux/clk.h> | ||
24 | #include <linux/version.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | #include <net/arp.h> | ||
27 | |||
28 | #include <linux/mii.h> | ||
29 | #include <linux/ethtool.h> | ||
30 | #include <linux/netdevice.h> | ||
31 | #include <linux/inetdevice.h> | ||
32 | #include <linux/etherdevice.h> | ||
33 | #include <linux/skbuff.h> | ||
34 | #include <linux/in.h> | ||
35 | #include <linux/ip.h> | ||
36 | #include <linux/ipv6.h> | ||
37 | #include <linux/phy.h> | ||
38 | |||
39 | #include "bcmgenet.h" | ||
40 | |||
41 | /* ethtool function - get WOL (Wake on LAN) settings, Only Magic Packet | ||
42 | * Detection is supported through ethtool | ||
43 | */ | ||
44 | void bcmgenet_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) | ||
45 | { | ||
46 | struct bcmgenet_priv *priv = netdev_priv(dev); | ||
47 | u32 reg; | ||
48 | |||
49 | wol->supported = WAKE_MAGIC | WAKE_MAGICSECURE; | ||
50 | wol->wolopts = priv->wolopts; | ||
51 | memset(wol->sopass, 0, sizeof(wol->sopass)); | ||
52 | |||
53 | if (wol->wolopts & WAKE_MAGICSECURE) { | ||
54 | reg = bcmgenet_umac_readl(priv, UMAC_MPD_PW_MS); | ||
55 | put_unaligned_be16(reg, &wol->sopass[0]); | ||
56 | reg = bcmgenet_umac_readl(priv, UMAC_MPD_PW_LS); | ||
57 | put_unaligned_be32(reg, &wol->sopass[2]); | ||
58 | } | ||
59 | } | ||
60 | |||
61 | /* ethtool function - set WOL (Wake on LAN) settings. | ||
62 | * Only for magic packet detection mode. | ||
63 | */ | ||
64 | int bcmgenet_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) | ||
65 | { | ||
66 | struct bcmgenet_priv *priv = netdev_priv(dev); | ||
67 | struct device *kdev = &priv->pdev->dev; | ||
68 | u32 reg; | ||
69 | |||
70 | if (!device_can_wakeup(kdev)) | ||
71 | return -ENOTSUPP; | ||
72 | |||
73 | if (wol->wolopts & ~(WAKE_MAGIC | WAKE_MAGICSECURE)) | ||
74 | return -EINVAL; | ||
75 | |||
76 | if (wol->wolopts & WAKE_MAGICSECURE) { | ||
77 | bcmgenet_umac_writel(priv, get_unaligned_be16(&wol->sopass[0]), | ||
78 | UMAC_MPD_PW_MS); | ||
79 | bcmgenet_umac_writel(priv, get_unaligned_be32(&wol->sopass[2]), | ||
80 | UMAC_MPD_PW_LS); | ||
81 | reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL); | ||
82 | reg |= MPD_PW_EN; | ||
83 | bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL); | ||
84 | } | ||
85 | |||
86 | /* Flag the device and relevant IRQ as wakeup capable */ | ||
87 | if (wol->wolopts) { | ||
88 | device_set_wakeup_enable(kdev, 1); | ||
89 | enable_irq_wake(priv->wol_irq); | ||
90 | priv->wol_irq_disabled = false; | ||
91 | } else { | ||
92 | device_set_wakeup_enable(kdev, 0); | ||
93 | /* Avoid unbalanced disable_irq_wake calls */ | ||
94 | if (!priv->wol_irq_disabled) | ||
95 | disable_irq_wake(priv->wol_irq); | ||
96 | priv->wol_irq_disabled = true; | ||
97 | } | ||
98 | |||
99 | priv->wolopts = wol->wolopts; | ||
100 | |||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | static int bcmgenet_poll_wol_status(struct bcmgenet_priv *priv) | ||
105 | { | ||
106 | struct net_device *dev = priv->dev; | ||
107 | int retries = 0; | ||
108 | |||
109 | while (!(bcmgenet_rbuf_readl(priv, RBUF_STATUS) | ||
110 | & RBUF_STATUS_WOL)) { | ||
111 | retries++; | ||
112 | if (retries > 5) { | ||
113 | netdev_crit(dev, "polling wol mode timeout\n"); | ||
114 | return -ETIMEDOUT; | ||
115 | } | ||
116 | mdelay(1); | ||
117 | } | ||
118 | |||
119 | return retries; | ||
120 | } | ||
121 | |||
122 | int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv, | ||
123 | enum bcmgenet_power_mode mode) | ||
124 | { | ||
125 | struct net_device *dev = priv->dev; | ||
126 | u32 cpu_mask_clear; | ||
127 | int retries = 0; | ||
128 | u32 reg; | ||
129 | |||
130 | if (mode != GENET_POWER_WOL_MAGIC) { | ||
131 | netif_err(priv, wol, dev, "unsupported mode: %d\n", mode); | ||
132 | return -EINVAL; | ||
133 | } | ||
134 | |||
135 | /* disable RX */ | ||
136 | reg = bcmgenet_umac_readl(priv, UMAC_CMD); | ||
137 | reg &= ~CMD_RX_EN; | ||
138 | bcmgenet_umac_writel(priv, reg, UMAC_CMD); | ||
139 | mdelay(10); | ||
140 | |||
141 | reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL); | ||
142 | reg |= MPD_EN; | ||
143 | bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL); | ||
144 | |||
145 | /* Do not leave UniMAC in MPD mode only */ | ||
146 | retries = bcmgenet_poll_wol_status(priv); | ||
147 | if (retries < 0) { | ||
148 | reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL); | ||
149 | reg &= ~MPD_EN; | ||
150 | bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL); | ||
151 | return retries; | ||
152 | } | ||
153 | |||
154 | netif_dbg(priv, wol, dev, "MPD WOL-ready status set after %d msec\n", | ||
155 | retries); | ||
156 | |||
157 | /* Enable CRC forward */ | ||
158 | reg = bcmgenet_umac_readl(priv, UMAC_CMD); | ||
159 | priv->crc_fwd_en = 1; | ||
160 | reg |= CMD_CRC_FWD; | ||
161 | |||
162 | /* Receiver must be enabled for WOL MP detection */ | ||
163 | reg |= CMD_RX_EN; | ||
164 | bcmgenet_umac_writel(priv, reg, UMAC_CMD); | ||
165 | |||
166 | if (priv->hw_params->flags & GENET_HAS_EXT) { | ||
167 | reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT); | ||
168 | reg &= ~EXT_ENERGY_DET_MASK; | ||
169 | bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT); | ||
170 | } | ||
171 | |||
172 | /* Enable the MPD interrupt */ | ||
173 | cpu_mask_clear = UMAC_IRQ_MPD_R; | ||
174 | |||
175 | bcmgenet_intrl2_0_writel(priv, cpu_mask_clear, INTRL2_CPU_MASK_CLEAR); | ||
176 | |||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | void bcmgenet_wol_power_up_cfg(struct bcmgenet_priv *priv, | ||
181 | enum bcmgenet_power_mode mode) | ||
182 | { | ||
183 | u32 cpu_mask_set; | ||
184 | u32 reg; | ||
185 | |||
186 | if (mode != GENET_POWER_WOL_MAGIC) { | ||
187 | netif_err(priv, wol, priv->dev, "invalid mode: %d\n", mode); | ||
188 | return; | ||
189 | } | ||
190 | |||
191 | reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL); | ||
192 | reg &= ~MPD_EN; | ||
193 | bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL); | ||
194 | |||
195 | /* Disable CRC Forward */ | ||
196 | reg = bcmgenet_umac_readl(priv, UMAC_CMD); | ||
197 | reg &= ~CMD_CRC_FWD; | ||
198 | bcmgenet_umac_writel(priv, reg, UMAC_CMD); | ||
199 | priv->crc_fwd_en = 0; | ||
200 | |||
201 | /* Stop monitoring magic packet IRQ */ | ||
202 | cpu_mask_set = UMAC_IRQ_MPD_R; | ||
203 | |||
204 | /* Stop monitoring magic packet IRQ */ | ||
205 | bcmgenet_intrl2_0_writel(priv, cpu_mask_set, INTRL2_CPU_MASK_SET); | ||
206 | } | ||