diff options
author | Michael Hennerich <michael.hennerich@analog.com> | 2010-05-10 01:39:11 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-05-17 20:20:59 -0400 |
commit | 53fd3f2829268703729a2db0e24c0e36360b68a2 (patch) | |
tree | 748ffb62dd85169e42205a36c4b28efadbea2cef /drivers/net/bfin_mac.c | |
parent | 812a9de71512e5da6f3177f7249a2448b6a4322e (diff) |
netdev: bfin_mac: add support for wake-on-lan magic packets
Note that WOL works only in PM Suspend Standby Mode (Sleep Mode).
Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/bfin_mac.c')
-rw-r--r-- | drivers/net/bfin_mac.c | 76 |
1 files changed, 72 insertions, 4 deletions
diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index 5d962b86ee22..28f350711267 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c | |||
@@ -464,6 +464,14 @@ static int mii_probe(struct net_device *dev) | |||
464 | * Ethtool support | 464 | * Ethtool support |
465 | */ | 465 | */ |
466 | 466 | ||
467 | /* | ||
468 | * interrupt routine for magic packet wakeup | ||
469 | */ | ||
470 | static irqreturn_t bfin_mac_wake_interrupt(int irq, void *dev_id) | ||
471 | { | ||
472 | return IRQ_HANDLED; | ||
473 | } | ||
474 | |||
467 | static int | 475 | static int |
468 | bfin_mac_ethtool_getsettings(struct net_device *dev, struct ethtool_cmd *cmd) | 476 | bfin_mac_ethtool_getsettings(struct net_device *dev, struct ethtool_cmd *cmd) |
469 | { | 477 | { |
@@ -498,11 +506,57 @@ static void bfin_mac_ethtool_getdrvinfo(struct net_device *dev, | |||
498 | strcpy(info->bus_info, dev_name(&dev->dev)); | 506 | strcpy(info->bus_info, dev_name(&dev->dev)); |
499 | } | 507 | } |
500 | 508 | ||
509 | static void bfin_mac_ethtool_getwol(struct net_device *dev, | ||
510 | struct ethtool_wolinfo *wolinfo) | ||
511 | { | ||
512 | struct bfin_mac_local *lp = netdev_priv(dev); | ||
513 | |||
514 | wolinfo->supported = WAKE_MAGIC; | ||
515 | wolinfo->wolopts = lp->wol; | ||
516 | } | ||
517 | |||
518 | static int bfin_mac_ethtool_setwol(struct net_device *dev, | ||
519 | struct ethtool_wolinfo *wolinfo) | ||
520 | { | ||
521 | struct bfin_mac_local *lp = netdev_priv(dev); | ||
522 | int rc; | ||
523 | |||
524 | if (wolinfo->wolopts & (WAKE_MAGICSECURE | | ||
525 | WAKE_UCAST | | ||
526 | WAKE_MCAST | | ||
527 | WAKE_BCAST | | ||
528 | WAKE_ARP)) | ||
529 | return -EOPNOTSUPP; | ||
530 | |||
531 | lp->wol = wolinfo->wolopts; | ||
532 | |||
533 | if (lp->wol && !lp->irq_wake_requested) { | ||
534 | /* register wake irq handler */ | ||
535 | rc = request_irq(IRQ_MAC_WAKEDET, bfin_mac_wake_interrupt, | ||
536 | IRQF_DISABLED, "EMAC_WAKE", dev); | ||
537 | if (rc) | ||
538 | return rc; | ||
539 | lp->irq_wake_requested = true; | ||
540 | } | ||
541 | |||
542 | if (!lp->wol && lp->irq_wake_requested) { | ||
543 | free_irq(IRQ_MAC_WAKEDET, dev); | ||
544 | lp->irq_wake_requested = false; | ||
545 | } | ||
546 | |||
547 | /* Make sure the PHY driver doesn't suspend */ | ||
548 | device_init_wakeup(&dev->dev, lp->wol); | ||
549 | |||
550 | return 0; | ||
551 | } | ||
552 | |||
501 | static const struct ethtool_ops bfin_mac_ethtool_ops = { | 553 | static const struct ethtool_ops bfin_mac_ethtool_ops = { |
502 | .get_settings = bfin_mac_ethtool_getsettings, | 554 | .get_settings = bfin_mac_ethtool_getsettings, |
503 | .set_settings = bfin_mac_ethtool_setsettings, | 555 | .set_settings = bfin_mac_ethtool_setsettings, |
504 | .get_link = ethtool_op_get_link, | 556 | .get_link = ethtool_op_get_link, |
505 | .get_drvinfo = bfin_mac_ethtool_getdrvinfo, | 557 | .get_drvinfo = bfin_mac_ethtool_getdrvinfo, |
558 | .get_wol = bfin_mac_ethtool_getwol, | ||
559 | .set_wol = bfin_mac_ethtool_setwol, | ||
506 | }; | 560 | }; |
507 | 561 | ||
508 | /**************************************************************************/ | 562 | /**************************************************************************/ |
@@ -1474,9 +1528,16 @@ static int __devexit bfin_mac_remove(struct platform_device *pdev) | |||
1474 | static int bfin_mac_suspend(struct platform_device *pdev, pm_message_t mesg) | 1528 | static int bfin_mac_suspend(struct platform_device *pdev, pm_message_t mesg) |
1475 | { | 1529 | { |
1476 | struct net_device *net_dev = platform_get_drvdata(pdev); | 1530 | struct net_device *net_dev = platform_get_drvdata(pdev); |
1531 | struct bfin_mac_local *lp = netdev_priv(net_dev); | ||
1477 | 1532 | ||
1478 | if (netif_running(net_dev)) | 1533 | if (lp->wol) { |
1479 | bfin_mac_close(net_dev); | 1534 | bfin_write_EMAC_OPMODE((bfin_read_EMAC_OPMODE() & ~TE) | RE); |
1535 | bfin_write_EMAC_WKUP_CTL(MPKE); | ||
1536 | enable_irq_wake(IRQ_MAC_WAKEDET); | ||
1537 | } else { | ||
1538 | if (netif_running(net_dev)) | ||
1539 | bfin_mac_close(net_dev); | ||
1540 | } | ||
1480 | 1541 | ||
1481 | return 0; | 1542 | return 0; |
1482 | } | 1543 | } |
@@ -1484,9 +1545,16 @@ static int bfin_mac_suspend(struct platform_device *pdev, pm_message_t mesg) | |||
1484 | static int bfin_mac_resume(struct platform_device *pdev) | 1545 | static int bfin_mac_resume(struct platform_device *pdev) |
1485 | { | 1546 | { |
1486 | struct net_device *net_dev = platform_get_drvdata(pdev); | 1547 | struct net_device *net_dev = platform_get_drvdata(pdev); |
1548 | struct bfin_mac_local *lp = netdev_priv(net_dev); | ||
1487 | 1549 | ||
1488 | if (netif_running(net_dev)) | 1550 | if (lp->wol) { |
1489 | bfin_mac_open(net_dev); | 1551 | bfin_write_EMAC_OPMODE(bfin_read_EMAC_OPMODE() | TE); |
1552 | bfin_write_EMAC_WKUP_CTL(0); | ||
1553 | disable_irq_wake(IRQ_MAC_WAKEDET); | ||
1554 | } else { | ||
1555 | if (netif_running(net_dev)) | ||
1556 | bfin_mac_open(net_dev); | ||
1557 | } | ||
1490 | 1558 | ||
1491 | return 0; | 1559 | return 0; |
1492 | } | 1560 | } |