Commit d87eb12785c14de1586e3bad86ca2c0991300339

Authored by Scott Wood
Committed by Kumar Gala
1 parent 7e1cc9c55a

gianfar: Add magic packet and suspend/resume support.

Signed-off-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Kumar Gala <galak@kernel.crashing.org>

Showing 5 changed files with 173 additions and 6 deletions Side-by-side Diff

arch/powerpc/sysdev/fsl_soc.c
... ... @@ -352,6 +352,9 @@
352 352 else
353 353 gfar_data.interface = PHY_INTERFACE_MODE_MII;
354 354  
  355 + if (of_get_property(np, "fsl,magic-packet", NULL))
  356 + gfar_data.device_flags |= FSL_GIANFAR_DEV_HAS_MAGIC_PACKET;
  357 +
355 358 ph = of_get_property(np, "phy-handle", NULL);
356 359 if (ph == NULL) {
357 360 u32 *fixed_link;
drivers/net/gianfar.c
... ... @@ -143,6 +143,9 @@
143 143 static void gfar_vlan_rx_register(struct net_device *netdev,
144 144 struct vlan_group *grp);
145 145 void gfar_halt(struct net_device *dev);
  146 +#ifdef CONFIG_PM
  147 +static void gfar_halt_nodisable(struct net_device *dev);
  148 +#endif
146 149 void gfar_start(struct net_device *dev);
147 150 static void gfar_clear_exact_match(struct net_device *dev);
148 151 static void gfar_set_mac_for_addr(struct net_device *dev, int num, u8 *addr);
... ... @@ -216,6 +219,7 @@
216 219  
217 220 spin_lock_init(&priv->txlock);
218 221 spin_lock_init(&priv->rxlock);
  222 + spin_lock_init(&priv->bflock);
219 223  
220 224 platform_set_drvdata(pdev, dev);
221 225  
222 226  
... ... @@ -393,7 +397,104 @@
393 397 return 0;
394 398 }
395 399  
  400 +#ifdef CONFIG_PM
  401 +static int gfar_suspend(struct platform_device *pdev, pm_message_t state)
  402 +{
  403 + struct net_device *dev = platform_get_drvdata(pdev);
  404 + struct gfar_private *priv = netdev_priv(dev);
  405 + unsigned long flags;
  406 + u32 tempval;
396 407  
  408 + int magic_packet = priv->wol_en &&
  409 + (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);
  410 +
  411 + netif_device_detach(dev);
  412 +
  413 + if (netif_running(dev)) {
  414 + spin_lock_irqsave(&priv->txlock, flags);
  415 + spin_lock(&priv->rxlock);
  416 +
  417 + gfar_halt_nodisable(dev);
  418 +
  419 + /* Disable Tx, and Rx if wake-on-LAN is disabled. */
  420 + tempval = gfar_read(&priv->regs->maccfg1);
  421 +
  422 + tempval &= ~MACCFG1_TX_EN;
  423 +
  424 + if (!magic_packet)
  425 + tempval &= ~MACCFG1_RX_EN;
  426 +
  427 + gfar_write(&priv->regs->maccfg1, tempval);
  428 +
  429 + spin_unlock(&priv->rxlock);
  430 + spin_unlock_irqrestore(&priv->txlock, flags);
  431 +
  432 +#ifdef CONFIG_GFAR_NAPI
  433 + napi_disable(&priv->napi);
  434 +#endif
  435 +
  436 + if (magic_packet) {
  437 + /* Enable interrupt on Magic Packet */
  438 + gfar_write(&priv->regs->imask, IMASK_MAG);
  439 +
  440 + /* Enable Magic Packet mode */
  441 + tempval = gfar_read(&priv->regs->maccfg2);
  442 + tempval |= MACCFG2_MPEN;
  443 + gfar_write(&priv->regs->maccfg2, tempval);
  444 + } else {
  445 + phy_stop(priv->phydev);
  446 + }
  447 + }
  448 +
  449 + return 0;
  450 +}
  451 +
  452 +static int gfar_resume(struct platform_device *pdev)
  453 +{
  454 + struct net_device *dev = platform_get_drvdata(pdev);
  455 + struct gfar_private *priv = netdev_priv(dev);
  456 + unsigned long flags;
  457 + u32 tempval;
  458 + int magic_packet = priv->wol_en &&
  459 + (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);
  460 +
  461 + if (!netif_running(dev)) {
  462 + netif_device_attach(dev);
  463 + return 0;
  464 + }
  465 +
  466 + if (!magic_packet && priv->phydev)
  467 + phy_start(priv->phydev);
  468 +
  469 + /* Disable Magic Packet mode, in case something
  470 + * else woke us up.
  471 + */
  472 +
  473 + spin_lock_irqsave(&priv->txlock, flags);
  474 + spin_lock(&priv->rxlock);
  475 +
  476 + tempval = gfar_read(&priv->regs->maccfg2);
  477 + tempval &= ~MACCFG2_MPEN;
  478 + gfar_write(&priv->regs->maccfg2, tempval);
  479 +
  480 + gfar_start(dev);
  481 +
  482 + spin_unlock(&priv->rxlock);
  483 + spin_unlock_irqrestore(&priv->txlock, flags);
  484 +
  485 + netif_device_attach(dev);
  486 +
  487 +#ifdef CONFIG_GFAR_NAPI
  488 + napi_enable(&priv->napi);
  489 +#endif
  490 +
  491 + return 0;
  492 +}
  493 +#else
  494 +#define gfar_suspend NULL
  495 +#define gfar_resume NULL
  496 +#endif
  497 +
397 498 /* Reads the controller's registers to determine what interface
398 499 * connects it to the PHY.
399 500 */
400 501  
... ... @@ -549,8 +650,9 @@
549 650 }
550 651  
551 652  
  653 +#ifdef CONFIG_PM
552 654 /* Halt the receive and transmit queues */
553   -void gfar_halt(struct net_device *dev)
  655 +static void gfar_halt_nodisable(struct net_device *dev)
554 656 {
555 657 struct gfar_private *priv = netdev_priv(dev);
556 658 struct gfar __iomem *regs = priv->regs;
557 659  
... ... @@ -573,7 +675,16 @@
573 675 (IEVENT_GRSC | IEVENT_GTSC)))
574 676 cpu_relax();
575 677 }
  678 +}
  679 +#endif
576 680  
  681 +/* Halt the receive and transmit queues */
  682 +void gfar_halt(struct net_device *dev)
  683 +{
  684 + struct gfar_private *priv = netdev_priv(dev);
  685 + struct gfar __iomem *regs = priv->regs;
  686 + u32 tempval;
  687 +
577 688 /* Disable Rx and Tx */
578 689 tempval = gfar_read(&regs->maccfg1);
579 690 tempval &= ~(MACCFG1_RX_EN | MACCFG1_TX_EN);
580 691  
... ... @@ -1969,8 +2080,13 @@
1969 2080 u32 events = gfar_read(&priv->regs->ievent);
1970 2081  
1971 2082 /* Clear IEVENT */
1972   - gfar_write(&priv->regs->ievent, IEVENT_ERR_MASK);
  2083 + gfar_write(&priv->regs->ievent, events & IEVENT_ERR_MASK);
1973 2084  
  2085 + /* Magic Packet is not an error. */
  2086 + if ((priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET) &&
  2087 + (events & IEVENT_MAG))
  2088 + events &= ~IEVENT_MAG;
  2089 +
1974 2090 /* Hmm... */
1975 2091 if (netif_msg_rx_err(priv) || netif_msg_tx_err(priv))
1976 2092 printk(KERN_DEBUG "%s: error interrupt (ievent=0x%08x imask=0x%08x)\n",
... ... @@ -2042,6 +2158,8 @@
2042 2158 static struct platform_driver gfar_driver = {
2043 2159 .probe = gfar_probe,
2044 2160 .remove = gfar_remove,
  2161 + .suspend = gfar_suspend,
  2162 + .resume = gfar_resume,
2045 2163 .driver = {
2046 2164 .name = "fsl-gianfar",
2047 2165 .owner = THIS_MODULE,
drivers/net/gianfar.h
... ... @@ -168,6 +168,7 @@
168 168 #define MACCFG2_GMII 0x00000200
169 169 #define MACCFG2_HUGEFRAME 0x00000020
170 170 #define MACCFG2_LENGTHCHECK 0x00000010
  171 +#define MACCFG2_MPEN 0x00000008
171 172  
172 173 #define ECNTRL_INIT_SETTINGS 0x00001000
173 174 #define ECNTRL_TBI_MODE 0x00000020
... ... @@ -240,6 +241,7 @@
240 241 #define IEVENT_CRL 0x00020000
241 242 #define IEVENT_XFUN 0x00010000
242 243 #define IEVENT_RXB0 0x00008000
  244 +#define IEVENT_MAG 0x00000800
243 245 #define IEVENT_GRSC 0x00000100
244 246 #define IEVENT_RXF0 0x00000080
245 247 #define IEVENT_FIR 0x00000008
... ... @@ -252,7 +254,8 @@
252 254 #define IEVENT_ERR_MASK \
253 255 (IEVENT_RXC | IEVENT_BSY | IEVENT_EBERR | IEVENT_MSRO | \
254 256 IEVENT_BABT | IEVENT_TXC | IEVENT_TXE | IEVENT_LC \
255   - | IEVENT_CRL | IEVENT_XFUN | IEVENT_DPE | IEVENT_PERR)
  257 + | IEVENT_CRL | IEVENT_XFUN | IEVENT_DPE | IEVENT_PERR \
  258 + | IEVENT_MAG)
256 259  
257 260 #define IMASK_INIT_CLEAR 0x00000000
258 261 #define IMASK_BABR 0x80000000
... ... @@ -270,6 +273,7 @@
270 273 #define IMASK_CRL 0x00020000
271 274 #define IMASK_XFUN 0x00010000
272 275 #define IMASK_RXB0 0x00008000
  276 +#define IMASK_MAG 0x00000800
273 277 #define IMASK_GTSC 0x00000100
274 278 #define IMASK_RXFEN0 0x00000080
275 279 #define IMASK_FIR 0x00000008
276 280  
... ... @@ -737,10 +741,14 @@
737 741 unsigned int fifo_starve;
738 742 unsigned int fifo_starve_off;
739 743  
  744 + /* Bitfield update lock */
  745 + spinlock_t bflock;
  746 +
740 747 unsigned char vlan_enable:1,
741 748 rx_csum_enable:1,
742 749 extended_hash:1,
743   - bd_stash_en:1;
  750 + bd_stash_en:1,
  751 + wol_en:1; /* Wake-on-LAN enabled */
744 752 unsigned short padding;
745 753  
746 754 unsigned int interruptTransmit;
drivers/net/gianfar_ethtool.c
... ... @@ -479,14 +479,13 @@
479 479 static int gfar_set_rx_csum(struct net_device *dev, uint32_t data)
480 480 {
481 481 struct gfar_private *priv = netdev_priv(dev);
  482 + unsigned long flags;
482 483 int err = 0;
483 484  
484 485 if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
485 486 return -EOPNOTSUPP;
486 487  
487 488 if (dev->flags & IFF_UP) {
488   - unsigned long flags;
489   -
490 489 /* Halt TX and RX, and process the frames which
491 490 * have already been received */
492 491 spin_lock_irqsave(&priv->txlock, flags);
493 492  
... ... @@ -502,7 +501,9 @@
502 501 stop_gfar(dev);
503 502 }
504 503  
  504 + spin_lock_irqsave(&priv->bflock, flags);
505 505 priv->rx_csum_enable = data;
  506 + spin_unlock_irqrestore(&priv->bflock, flags);
506 507  
507 508 if (dev->flags & IFF_UP)
508 509 err = startup_gfar(dev);
509 510  
... ... @@ -564,7 +565,39 @@
564 565 priv->msg_enable = data;
565 566 }
566 567  
  568 +#ifdef CONFIG_PM
  569 +static void gfar_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
  570 +{
  571 + struct gfar_private *priv = netdev_priv(dev);
567 572  
  573 + if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET) {
  574 + wol->supported = WAKE_MAGIC;
  575 + wol->wolopts = priv->wol_en ? WAKE_MAGIC : 0;
  576 + } else {
  577 + wol->supported = wol->wolopts = 0;
  578 + }
  579 +}
  580 +
  581 +static int gfar_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
  582 +{
  583 + struct gfar_private *priv = netdev_priv(dev);
  584 + unsigned long flags;
  585 +
  586 + if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET) &&
  587 + wol->wolopts != 0)
  588 + return -EINVAL;
  589 +
  590 + if (wol->wolopts & ~WAKE_MAGIC)
  591 + return -EINVAL;
  592 +
  593 + spin_lock_irqsave(&priv->bflock, flags);
  594 + priv->wol_en = wol->wolopts & WAKE_MAGIC ? 1 : 0;
  595 + spin_unlock_irqrestore(&priv->bflock, flags);
  596 +
  597 + return 0;
  598 +}
  599 +#endif
  600 +
568 601 const struct ethtool_ops gfar_ethtool_ops = {
569 602 .get_settings = gfar_gsettings,
570 603 .set_settings = gfar_ssettings,
... ... @@ -585,5 +618,9 @@
585 618 .set_tx_csum = gfar_set_tx_csum,
586 619 .get_msglevel = gfar_get_msglevel,
587 620 .set_msglevel = gfar_set_msglevel,
  621 +#ifdef CONFIG_PM
  622 + .get_wol = gfar_get_wol,
  623 + .set_wol = gfar_set_wol,
  624 +#endif
588 625 };
include/linux/fsl_devices.h
... ... @@ -69,6 +69,7 @@
69 69 #define FSL_GIANFAR_DEV_HAS_VLAN 0x00000020
70 70 #define FSL_GIANFAR_DEV_HAS_EXTENDED_HASH 0x00000040
71 71 #define FSL_GIANFAR_DEV_HAS_PADDING 0x00000080
  72 +#define FSL_GIANFAR_DEV_HAS_MAGIC_PACKET 0x00000100
72 73  
73 74 /* Flags in gianfar_platform_data */
74 75 #define FSL_GIANFAR_BRD_HAS_PHY_INTR 0x00000001 /* set or use a timer */