summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNimrod Andy <B38611@freescale.com>2014-12-24 04:30:39 -0500
committerDavid S. Miller <davem@davemloft.net>2014-12-31 13:06:50 -0500
commitde40ed31b3c577cefd7b54972365a272ecbe9dd6 (patch)
tree2d74ddd3e075563f713332dfe0449bd5567a557c
parent03366a33db91abd298457b0f707187247f1a6b7d (diff)
net: fec: add Wake-on-LAN support
Support for Wake-on-LAN using Magic Packet. ENET IP supports sleep mode in low power status, when system enter suspend status, Magic packet can wake up system even if all SOC clocks are gate. The patch doing below things: - flagging the device as a wakeup source for the system, as well as its Wake-on-LAN interrupt - prepare the hardware for entering WoL mode - add standard ethtool WOL interface - enable the ENET interrupt to wake us Tested on i.MX6q/dl sabresd, sabreauto boards, i.MX6SX arm2 boards. Signed-off-by: Fugang Duan <B38611@freescale.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--Documentation/devicetree/bindings/net/fsl-fec.txt2
-rw-r--r--drivers/net/ethernet/freescale/fec.h2
-rw-r--r--drivers/net/ethernet/freescale/fec_main.c104
-rw-r--r--include/linux/fec.h1
4 files changed, 99 insertions, 10 deletions
diff --git a/Documentation/devicetree/bindings/net/fsl-fec.txt b/Documentation/devicetree/bindings/net/fsl-fec.txt
index 0c8775c45798..a9eb611bee68 100644
--- a/Documentation/devicetree/bindings/net/fsl-fec.txt
+++ b/Documentation/devicetree/bindings/net/fsl-fec.txt
@@ -22,6 +22,8 @@ Optional properties:
22- fsl,num-rx-queues : The property is valid for enet-avb IP, which supports 22- fsl,num-rx-queues : The property is valid for enet-avb IP, which supports
23 hw multi queues. Should specify the rx queue number, otherwise set rx queue 23 hw multi queues. Should specify the rx queue number, otherwise set rx queue
24 number to 1. 24 number to 1.
25- fsl,magic-packet : If present, indicates that the hardware supports waking
26 up via magic packet.
25 27
26Optional subnodes: 28Optional subnodes:
27- mdio : specifies the mdio bus in the FEC, used as a container for phy nodes 29- mdio : specifies the mdio bus in the FEC, used as a container for phy nodes
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index df8bbddaeb37..d77a96fdf1dd 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -357,6 +357,7 @@ struct bufdesc_ex {
357#define FEC_ENET_RXB ((uint)0x01000000) /* A buffer was received */ 357#define FEC_ENET_RXB ((uint)0x01000000) /* A buffer was received */
358#define FEC_ENET_MII ((uint)0x00800000) /* MII interrupt */ 358#define FEC_ENET_MII ((uint)0x00800000) /* MII interrupt */
359#define FEC_ENET_EBERR ((uint)0x00400000) /* SDMA bus error */ 359#define FEC_ENET_EBERR ((uint)0x00400000) /* SDMA bus error */
360#define FEC_ENET_WAKEUP ((uint)0x00020000) /* Wakeup request */
360#define FEC_ENET_TXF (FEC_ENET_TXF_0 | FEC_ENET_TXF_1 | FEC_ENET_TXF_2) 361#define FEC_ENET_TXF (FEC_ENET_TXF_0 | FEC_ENET_TXF_1 | FEC_ENET_TXF_2)
361#define FEC_ENET_RXF (FEC_ENET_RXF_0 | FEC_ENET_RXF_1 | FEC_ENET_RXF_2) 362#define FEC_ENET_RXF (FEC_ENET_RXF_0 | FEC_ENET_RXF_1 | FEC_ENET_RXF_2)
362#define FEC_ENET_TS_AVAIL ((uint)0x00010000) 363#define FEC_ENET_TS_AVAIL ((uint)0x00010000)
@@ -512,6 +513,7 @@ struct fec_enet_private {
512 int irq[FEC_IRQ_NUM]; 513 int irq[FEC_IRQ_NUM];
513 bool bufdesc_ex; 514 bool bufdesc_ex;
514 int pause_flag; 515 int pause_flag;
516 int wol_flag;
515 u32 quirks; 517 u32 quirks;
516 518
517 struct napi_struct napi; 519 struct napi_struct napi;
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 5ebdf8dc8a31..49cd358c30fa 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -187,6 +187,9 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
187#define FEC_MMFR_RA(v) ((v & 0x1f) << 18) 187#define FEC_MMFR_RA(v) ((v & 0x1f) << 18)
188#define FEC_MMFR_TA (2 << 16) 188#define FEC_MMFR_TA (2 << 16)
189#define FEC_MMFR_DATA(v) (v & 0xffff) 189#define FEC_MMFR_DATA(v) (v & 0xffff)
190/* FEC ECR bits definition */
191#define FEC_ECR_MAGICEN (1 << 2)
192#define FEC_ECR_SLEEP (1 << 3)
190 193
191#define FEC_MII_TIMEOUT 30000 /* us */ 194#define FEC_MII_TIMEOUT 30000 /* us */
192 195
@@ -195,6 +198,9 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
195 198
196#define FEC_PAUSE_FLAG_AUTONEG 0x1 199#define FEC_PAUSE_FLAG_AUTONEG 0x1
197#define FEC_PAUSE_FLAG_ENABLE 0x2 200#define FEC_PAUSE_FLAG_ENABLE 0x2
201#define FEC_WOL_HAS_MAGIC_PACKET (0x1 << 0)
202#define FEC_WOL_FLAG_ENABLE (0x1 << 1)
203#define FEC_WOL_FLAG_SLEEP_ON (0x1 << 2)
198 204
199#define COPYBREAK_DEFAULT 256 205#define COPYBREAK_DEFAULT 256
200 206
@@ -1089,7 +1095,9 @@ static void
1089fec_stop(struct net_device *ndev) 1095fec_stop(struct net_device *ndev)
1090{ 1096{
1091 struct fec_enet_private *fep = netdev_priv(ndev); 1097 struct fec_enet_private *fep = netdev_priv(ndev);
1098 struct fec_platform_data *pdata = fep->pdev->dev.platform_data;
1092 u32 rmii_mode = readl(fep->hwp + FEC_R_CNTRL) & (1 << 8); 1099 u32 rmii_mode = readl(fep->hwp + FEC_R_CNTRL) & (1 << 8);
1100 u32 val;
1093 1101
1094 /* We cannot expect a graceful transmit stop without link !!! */ 1102 /* We cannot expect a graceful transmit stop without link !!! */
1095 if (fep->link) { 1103 if (fep->link) {
@@ -1103,17 +1111,28 @@ fec_stop(struct net_device *ndev)
1103 * For i.MX6SX SOC, enet use AXI bus, we use disable MAC 1111 * For i.MX6SX SOC, enet use AXI bus, we use disable MAC
1104 * instead of reset MAC itself. 1112 * instead of reset MAC itself.
1105 */ 1113 */
1106 if (fep->quirks & FEC_QUIRK_HAS_AVB) { 1114 if (!(fep->wol_flag & FEC_WOL_FLAG_SLEEP_ON)) {
1107 writel(0, fep->hwp + FEC_ECNTRL); 1115 if (fep->quirks & FEC_QUIRK_HAS_AVB) {
1116 writel(0, fep->hwp + FEC_ECNTRL);
1117 } else {
1118 writel(1, fep->hwp + FEC_ECNTRL);
1119 udelay(10);
1120 }
1121 writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
1108 } else { 1122 } else {
1109 writel(1, fep->hwp + FEC_ECNTRL); 1123 writel(FEC_DEFAULT_IMASK | FEC_ENET_WAKEUP, fep->hwp + FEC_IMASK);
1110 udelay(10); 1124 val = readl(fep->hwp + FEC_ECNTRL);
1125 val |= (FEC_ECR_MAGICEN | FEC_ECR_SLEEP);
1126 writel(val, fep->hwp + FEC_ECNTRL);
1127
1128 if (pdata && pdata->sleep_mode_enable)
1129 pdata->sleep_mode_enable(true);
1111 } 1130 }
1112 writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); 1131 writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
1113 writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
1114 1132
1115 /* We have to keep ENET enabled to have MII interrupt stay working */ 1133 /* We have to keep ENET enabled to have MII interrupt stay working */
1116 if (fep->quirks & FEC_QUIRK_ENET_MAC) { 1134 if (fep->quirks & FEC_QUIRK_ENET_MAC &&
1135 !(fep->wol_flag & FEC_WOL_FLAG_SLEEP_ON)) {
1117 writel(2, fep->hwp + FEC_ECNTRL); 1136 writel(2, fep->hwp + FEC_ECNTRL);
1118 writel(rmii_mode, fep->hwp + FEC_R_CNTRL); 1137 writel(rmii_mode, fep->hwp + FEC_R_CNTRL);
1119 } 1138 }
@@ -2427,6 +2446,44 @@ static int fec_enet_set_tunable(struct net_device *netdev,
2427 return ret; 2446 return ret;
2428} 2447}
2429 2448
2449static void
2450fec_enet_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
2451{
2452 struct fec_enet_private *fep = netdev_priv(ndev);
2453
2454 if (fep->wol_flag & FEC_WOL_HAS_MAGIC_PACKET) {
2455 wol->supported = WAKE_MAGIC;
2456 wol->wolopts = fep->wol_flag & FEC_WOL_FLAG_ENABLE ? WAKE_MAGIC : 0;
2457 } else {
2458 wol->supported = wol->wolopts = 0;
2459 }
2460}
2461
2462static int
2463fec_enet_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
2464{
2465 struct fec_enet_private *fep = netdev_priv(ndev);
2466
2467 if (!(fep->wol_flag & FEC_WOL_HAS_MAGIC_PACKET))
2468 return -EINVAL;
2469
2470 if (wol->wolopts & ~WAKE_MAGIC)
2471 return -EINVAL;
2472
2473 device_set_wakeup_enable(&ndev->dev, wol->wolopts & WAKE_MAGIC);
2474 if (device_may_wakeup(&ndev->dev)) {
2475 fep->wol_flag |= FEC_WOL_FLAG_ENABLE;
2476 if (fep->irq[0] > 0)
2477 enable_irq_wake(fep->irq[0]);
2478 } else {
2479 fep->wol_flag &= (~FEC_WOL_FLAG_ENABLE);
2480 if (fep->irq[0] > 0)
2481 disable_irq_wake(fep->irq[0]);
2482 }
2483
2484 return 0;
2485}
2486
2430static const struct ethtool_ops fec_enet_ethtool_ops = { 2487static const struct ethtool_ops fec_enet_ethtool_ops = {
2431 .get_settings = fec_enet_get_settings, 2488 .get_settings = fec_enet_get_settings,
2432 .set_settings = fec_enet_set_settings, 2489 .set_settings = fec_enet_set_settings,
@@ -2445,6 +2502,8 @@ static const struct ethtool_ops fec_enet_ethtool_ops = {
2445 .get_ts_info = fec_enet_get_ts_info, 2502 .get_ts_info = fec_enet_get_ts_info,
2446 .get_tunable = fec_enet_get_tunable, 2503 .get_tunable = fec_enet_get_tunable,
2447 .set_tunable = fec_enet_set_tunable, 2504 .set_tunable = fec_enet_set_tunable,
2505 .get_wol = fec_enet_get_wol,
2506 .set_wol = fec_enet_set_wol,
2448}; 2507};
2449 2508
2450static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) 2509static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
@@ -2705,6 +2764,9 @@ fec_enet_open(struct net_device *ndev)
2705 phy_start(fep->phy_dev); 2764 phy_start(fep->phy_dev);
2706 netif_tx_start_all_queues(ndev); 2765 netif_tx_start_all_queues(ndev);
2707 2766
2767 device_set_wakeup_enable(&ndev->dev, fep->wol_flag &
2768 FEC_WOL_FLAG_ENABLE);
2769
2708 return 0; 2770 return 0;
2709 2771
2710err_enet_mii_probe: 2772err_enet_mii_probe:
@@ -3153,6 +3215,9 @@ fec_probe(struct platform_device *pdev)
3153 3215
3154 platform_set_drvdata(pdev, ndev); 3216 platform_set_drvdata(pdev, ndev);
3155 3217
3218 if (of_get_property(np, "fsl,magic-packet", NULL))
3219 fep->wol_flag |= FEC_WOL_HAS_MAGIC_PACKET;
3220
3156 phy_node = of_parse_phandle(np, "phy-handle", 0); 3221 phy_node = of_parse_phandle(np, "phy-handle", 0);
3157 if (!phy_node && of_phy_is_fixed_link(np)) { 3222 if (!phy_node && of_phy_is_fixed_link(np)) {
3158 ret = of_phy_register_fixed_link(np); 3223 ret = of_phy_register_fixed_link(np);
@@ -3247,6 +3312,8 @@ fec_probe(struct platform_device *pdev)
3247 0, pdev->name, ndev); 3312 0, pdev->name, ndev);
3248 if (ret) 3313 if (ret)
3249 goto failed_irq; 3314 goto failed_irq;
3315
3316 fep->irq[i] = irq;
3250 } 3317 }
3251 3318
3252 init_completion(&fep->mdio_done); 3319 init_completion(&fep->mdio_done);
@@ -3263,6 +3330,9 @@ fec_probe(struct platform_device *pdev)
3263 if (ret) 3330 if (ret)
3264 goto failed_register; 3331 goto failed_register;
3265 3332
3333 device_init_wakeup(&ndev->dev, fep->wol_flag &
3334 FEC_WOL_HAS_MAGIC_PACKET);
3335
3266 if (fep->bufdesc_ex && fep->ptp_clock) 3336 if (fep->bufdesc_ex && fep->ptp_clock)
3267 netdev_info(ndev, "registered PHC device %d\n", fep->dev_id); 3337 netdev_info(ndev, "registered PHC device %d\n", fep->dev_id);
3268 3338
@@ -3316,6 +3386,8 @@ static int __maybe_unused fec_suspend(struct device *dev)
3316 3386
3317 rtnl_lock(); 3387 rtnl_lock();
3318 if (netif_running(ndev)) { 3388 if (netif_running(ndev)) {
3389 if (fep->wol_flag & FEC_WOL_FLAG_ENABLE)
3390 fep->wol_flag |= FEC_WOL_FLAG_SLEEP_ON;
3319 phy_stop(fep->phy_dev); 3391 phy_stop(fep->phy_dev);
3320 napi_disable(&fep->napi); 3392 napi_disable(&fep->napi);
3321 netif_tx_lock_bh(ndev); 3393 netif_tx_lock_bh(ndev);
@@ -3323,11 +3395,12 @@ static int __maybe_unused fec_suspend(struct device *dev)
3323 netif_tx_unlock_bh(ndev); 3395 netif_tx_unlock_bh(ndev);
3324 fec_stop(ndev); 3396 fec_stop(ndev);
3325 fec_enet_clk_enable(ndev, false); 3397 fec_enet_clk_enable(ndev, false);
3326 pinctrl_pm_select_sleep_state(&fep->pdev->dev); 3398 if (!(fep->wol_flag & FEC_WOL_FLAG_ENABLE))
3399 pinctrl_pm_select_sleep_state(&fep->pdev->dev);
3327 } 3400 }
3328 rtnl_unlock(); 3401 rtnl_unlock();
3329 3402
3330 if (fep->reg_phy) 3403 if (fep->reg_phy && !(fep->wol_flag & FEC_WOL_FLAG_ENABLE))
3331 regulator_disable(fep->reg_phy); 3404 regulator_disable(fep->reg_phy);
3332 3405
3333 /* SOC supply clock to phy, when clock is disabled, phy link down 3406 /* SOC supply clock to phy, when clock is disabled, phy link down
@@ -3343,9 +3416,11 @@ static int __maybe_unused fec_resume(struct device *dev)
3343{ 3416{
3344 struct net_device *ndev = dev_get_drvdata(dev); 3417 struct net_device *ndev = dev_get_drvdata(dev);
3345 struct fec_enet_private *fep = netdev_priv(ndev); 3418 struct fec_enet_private *fep = netdev_priv(ndev);
3419 struct fec_platform_data *pdata = fep->pdev->dev.platform_data;
3346 int ret; 3420 int ret;
3421 int val;
3347 3422
3348 if (fep->reg_phy) { 3423 if (fep->reg_phy && !(fep->wol_flag & FEC_WOL_FLAG_ENABLE)) {
3349 ret = regulator_enable(fep->reg_phy); 3424 ret = regulator_enable(fep->reg_phy);
3350 if (ret) 3425 if (ret)
3351 return ret; 3426 return ret;
@@ -3353,12 +3428,21 @@ static int __maybe_unused fec_resume(struct device *dev)
3353 3428
3354 rtnl_lock(); 3429 rtnl_lock();
3355 if (netif_running(ndev)) { 3430 if (netif_running(ndev)) {
3356 pinctrl_pm_select_default_state(&fep->pdev->dev);
3357 ret = fec_enet_clk_enable(ndev, true); 3431 ret = fec_enet_clk_enable(ndev, true);
3358 if (ret) { 3432 if (ret) {
3359 rtnl_unlock(); 3433 rtnl_unlock();
3360 goto failed_clk; 3434 goto failed_clk;
3361 } 3435 }
3436 if (fep->wol_flag & FEC_WOL_FLAG_ENABLE) {
3437 if (pdata && pdata->sleep_mode_enable)
3438 pdata->sleep_mode_enable(false);
3439 val = readl(fep->hwp + FEC_ECNTRL);
3440 val &= ~(FEC_ECR_MAGICEN | FEC_ECR_SLEEP);
3441 writel(val, fep->hwp + FEC_ECNTRL);
3442 fep->wol_flag &= ~FEC_WOL_FLAG_SLEEP_ON;
3443 } else {
3444 pinctrl_pm_select_default_state(&fep->pdev->dev);
3445 }
3362 fec_restart(ndev); 3446 fec_restart(ndev);
3363 netif_tx_lock_bh(ndev); 3447 netif_tx_lock_bh(ndev);
3364 netif_device_attach(ndev); 3448 netif_device_attach(ndev);
diff --git a/include/linux/fec.h b/include/linux/fec.h
index bcff455d1d53..1454a503622d 100644
--- a/include/linux/fec.h
+++ b/include/linux/fec.h
@@ -19,6 +19,7 @@
19struct fec_platform_data { 19struct fec_platform_data {
20 phy_interface_t phy; 20 phy_interface_t phy;
21 unsigned char mac[ETH_ALEN]; 21 unsigned char mac[ETH_ALEN];
22 void (*sleep_mode_enable)(int enabled);
22}; 23};
23 24
24#endif 25#endif