diff options
author | Scott Wood <scottwood@freescale.com> | 2008-07-11 19:04:45 -0400 |
---|---|---|
committer | Kumar Gala <galak@kernel.crashing.org> | 2008-07-16 18:57:47 -0400 |
commit | d87eb12785c14de1586e3bad86ca2c0991300339 (patch) | |
tree | 9caa5a958d88910049a03bbfbd1a8a3367b6332b /drivers/net/gianfar.c | |
parent | 7e1cc9c55a2a4af62f30fade62fb612a243def39 (diff) |
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>
Diffstat (limited to 'drivers/net/gianfar.c')
-rw-r--r-- | drivers/net/gianfar.c | 122 |
1 files changed, 120 insertions, 2 deletions
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 25bdd0832df5..36f229ff52f2 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c | |||
@@ -143,6 +143,9 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, int l | |||
143 | static void gfar_vlan_rx_register(struct net_device *netdev, | 143 | static void gfar_vlan_rx_register(struct net_device *netdev, |
144 | struct vlan_group *grp); | 144 | struct vlan_group *grp); |
145 | void gfar_halt(struct net_device *dev); | 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 | void gfar_start(struct net_device *dev); | 149 | void gfar_start(struct net_device *dev); |
147 | static void gfar_clear_exact_match(struct net_device *dev); | 150 | static void gfar_clear_exact_match(struct net_device *dev); |
148 | static void gfar_set_mac_for_addr(struct net_device *dev, int num, u8 *addr); | 151 | static void gfar_set_mac_for_addr(struct net_device *dev, int num, u8 *addr); |
@@ -216,6 +219,7 @@ static int gfar_probe(struct platform_device *pdev) | |||
216 | 219 | ||
217 | spin_lock_init(&priv->txlock); | 220 | spin_lock_init(&priv->txlock); |
218 | spin_lock_init(&priv->rxlock); | 221 | spin_lock_init(&priv->rxlock); |
222 | spin_lock_init(&priv->bflock); | ||
219 | 223 | ||
220 | platform_set_drvdata(pdev, dev); | 224 | platform_set_drvdata(pdev, dev); |
221 | 225 | ||
@@ -393,6 +397,103 @@ static int gfar_remove(struct platform_device *pdev) | |||
393 | return 0; | 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; | ||
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 | ||
396 | 497 | ||
397 | /* Reads the controller's registers to determine what interface | 498 | /* Reads the controller's registers to determine what interface |
398 | * connects it to the PHY. | 499 | * connects it to the PHY. |
@@ -549,8 +650,9 @@ static void init_registers(struct net_device *dev) | |||
549 | } | 650 | } |
550 | 651 | ||
551 | 652 | ||
653 | #ifdef CONFIG_PM | ||
552 | /* Halt the receive and transmit queues */ | 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 | struct gfar_private *priv = netdev_priv(dev); | 657 | struct gfar_private *priv = netdev_priv(dev); |
556 | struct gfar __iomem *regs = priv->regs; | 658 | struct gfar __iomem *regs = priv->regs; |
@@ -573,6 +675,15 @@ void gfar_halt(struct net_device *dev) | |||
573 | (IEVENT_GRSC | IEVENT_GTSC))) | 675 | (IEVENT_GRSC | IEVENT_GTSC))) |
574 | cpu_relax(); | 676 | cpu_relax(); |
575 | } | 677 | } |
678 | } | ||
679 | #endif | ||
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; | ||
576 | 687 | ||
577 | /* Disable Rx and Tx */ | 688 | /* Disable Rx and Tx */ |
578 | tempval = gfar_read(®s->maccfg1); | 689 | tempval = gfar_read(®s->maccfg1); |
@@ -1969,7 +2080,12 @@ static irqreturn_t gfar_error(int irq, void *dev_id) | |||
1969 | u32 events = gfar_read(&priv->regs->ievent); | 2080 | u32 events = gfar_read(&priv->regs->ievent); |
1970 | 2081 | ||
1971 | /* Clear IEVENT */ | 2082 | /* Clear IEVENT */ |
1972 | gfar_write(&priv->regs->ievent, IEVENT_ERR_MASK); | 2083 | gfar_write(&priv->regs->ievent, events & IEVENT_ERR_MASK); |
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; | ||
1973 | 2089 | ||
1974 | /* Hmm... */ | 2090 | /* Hmm... */ |
1975 | if (netif_msg_rx_err(priv) || netif_msg_tx_err(priv)) | 2091 | if (netif_msg_rx_err(priv) || netif_msg_tx_err(priv)) |
@@ -2042,6 +2158,8 @@ MODULE_ALIAS("platform:fsl-gianfar"); | |||
2042 | static struct platform_driver gfar_driver = { | 2158 | static struct platform_driver gfar_driver = { |
2043 | .probe = gfar_probe, | 2159 | .probe = gfar_probe, |
2044 | .remove = gfar_remove, | 2160 | .remove = gfar_remove, |
2161 | .suspend = gfar_suspend, | ||
2162 | .resume = gfar_resume, | ||
2045 | .driver = { | 2163 | .driver = { |
2046 | .name = "fsl-gianfar", | 2164 | .name = "fsl-gianfar", |
2047 | .owner = THIS_MODULE, | 2165 | .owner = THIS_MODULE, |