diff options
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 39b45e901be6..b8394cf134e8 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c | |||
| @@ -134,6 +134,9 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, int l | |||
| 134 | static void gfar_vlan_rx_register(struct net_device *netdev, | 134 | static void gfar_vlan_rx_register(struct net_device *netdev, |
| 135 | struct vlan_group *grp); | 135 | struct vlan_group *grp); |
| 136 | void gfar_halt(struct net_device *dev); | 136 | void gfar_halt(struct net_device *dev); |
| 137 | #ifdef CONFIG_PM | ||
| 138 | static void gfar_halt_nodisable(struct net_device *dev); | ||
| 139 | #endif | ||
| 137 | void gfar_start(struct net_device *dev); | 140 | void gfar_start(struct net_device *dev); |
| 138 | static void gfar_clear_exact_match(struct net_device *dev); | 141 | static void gfar_clear_exact_match(struct net_device *dev); |
| 139 | static void gfar_set_mac_for_addr(struct net_device *dev, int num, u8 *addr); | 142 | static void gfar_set_mac_for_addr(struct net_device *dev, int num, u8 *addr); |
| @@ -207,6 +210,7 @@ static int gfar_probe(struct platform_device *pdev) | |||
| 207 | 210 | ||
| 208 | spin_lock_init(&priv->txlock); | 211 | spin_lock_init(&priv->txlock); |
| 209 | spin_lock_init(&priv->rxlock); | 212 | spin_lock_init(&priv->rxlock); |
| 213 | spin_lock_init(&priv->bflock); | ||
| 210 | 214 | ||
| 211 | platform_set_drvdata(pdev, dev); | 215 | platform_set_drvdata(pdev, dev); |
| 212 | 216 | ||
| @@ -378,6 +382,103 @@ static int gfar_remove(struct platform_device *pdev) | |||
| 378 | return 0; | 382 | return 0; |
| 379 | } | 383 | } |
| 380 | 384 | ||
| 385 | #ifdef CONFIG_PM | ||
| 386 | static int gfar_suspend(struct platform_device *pdev, pm_message_t state) | ||
| 387 | { | ||
| 388 | struct net_device *dev = platform_get_drvdata(pdev); | ||
| 389 | struct gfar_private *priv = netdev_priv(dev); | ||
| 390 | unsigned long flags; | ||
| 391 | u32 tempval; | ||
| 392 | |||
| 393 | int magic_packet = priv->wol_en && | ||
| 394 | (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET); | ||
| 395 | |||
| 396 | netif_device_detach(dev); | ||
| 397 | |||
| 398 | if (netif_running(dev)) { | ||
| 399 | spin_lock_irqsave(&priv->txlock, flags); | ||
| 400 | spin_lock(&priv->rxlock); | ||
| 401 | |||
| 402 | gfar_halt_nodisable(dev); | ||
| 403 | |||
| 404 | /* Disable Tx, and Rx if wake-on-LAN is disabled. */ | ||
| 405 | tempval = gfar_read(&priv->regs->maccfg1); | ||
| 406 | |||
| 407 | tempval &= ~MACCFG1_TX_EN; | ||
| 408 | |||
| 409 | if (!magic_packet) | ||
| 410 | tempval &= ~MACCFG1_RX_EN; | ||
| 411 | |||
| 412 | gfar_write(&priv->regs->maccfg1, tempval); | ||
| 413 | |||
| 414 | spin_unlock(&priv->rxlock); | ||
| 415 | spin_unlock_irqrestore(&priv->txlock, flags); | ||
| 416 | |||
| 417 | #ifdef CONFIG_GFAR_NAPI | ||
| 418 | napi_disable(&priv->napi); | ||
| 419 | #endif | ||
| 420 | |||
| 421 | if (magic_packet) { | ||
| 422 | /* Enable interrupt on Magic Packet */ | ||
| 423 | gfar_write(&priv->regs->imask, IMASK_MAG); | ||
| 424 | |||
| 425 | /* Enable Magic Packet mode */ | ||
| 426 | tempval = gfar_read(&priv->regs->maccfg2); | ||
| 427 | tempval |= MACCFG2_MPEN; | ||
| 428 | gfar_write(&priv->regs->maccfg2, tempval); | ||
| 429 | } else { | ||
| 430 | phy_stop(priv->phydev); | ||
| 431 | } | ||
| 432 | } | ||
| 433 | |||
| 434 | return 0; | ||
| 435 | } | ||
| 436 | |||
| 437 | static int gfar_resume(struct platform_device *pdev) | ||
| 438 | { | ||
| 439 | struct net_device *dev = platform_get_drvdata(pdev); | ||
| 440 | struct gfar_private *priv = netdev_priv(dev); | ||
| 441 | unsigned long flags; | ||
| 442 | u32 tempval; | ||
| 443 | int magic_packet = priv->wol_en && | ||
| 444 | (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET); | ||
| 445 | |||
| 446 | if (!netif_running(dev)) { | ||
| 447 | netif_device_attach(dev); | ||
| 448 | return 0; | ||
| 449 | } | ||
| 450 | |||
| 451 | if (!magic_packet && priv->phydev) | ||
| 452 | phy_start(priv->phydev); | ||
| 453 | |||
| 454 | /* Disable Magic Packet mode, in case something | ||
| 455 | * else woke us up. | ||
| 456 | */ | ||
| 457 | |||
| 458 | spin_lock_irqsave(&priv->txlock, flags); | ||
| 459 | spin_lock(&priv->rxlock); | ||
| 460 | |||
| 461 | tempval = gfar_read(&priv->regs->maccfg2); | ||
| 462 | tempval &= ~MACCFG2_MPEN; | ||
| 463 | gfar_write(&priv->regs->maccfg2, tempval); | ||
| 464 | |||
| 465 | gfar_start(dev); | ||
| 466 | |||
| 467 | spin_unlock(&priv->rxlock); | ||
| 468 | spin_unlock_irqrestore(&priv->txlock, flags); | ||
| 469 | |||
| 470 | netif_device_attach(dev); | ||
| 471 | |||
| 472 | #ifdef CONFIG_GFAR_NAPI | ||
| 473 | napi_enable(&priv->napi); | ||
| 474 | #endif | ||
| 475 | |||
| 476 | return 0; | ||
| 477 | } | ||
| 478 | #else | ||
| 479 | #define gfar_suspend NULL | ||
| 480 | #define gfar_resume NULL | ||
| 481 | #endif | ||
| 381 | 482 | ||
| 382 | /* Reads the controller's registers to determine what interface | 483 | /* Reads the controller's registers to determine what interface |
| 383 | * connects it to the PHY. | 484 | * connects it to the PHY. |
| @@ -534,8 +635,9 @@ static void init_registers(struct net_device *dev) | |||
| 534 | } | 635 | } |
| 535 | 636 | ||
| 536 | 637 | ||
| 638 | #ifdef CONFIG_PM | ||
| 537 | /* Halt the receive and transmit queues */ | 639 | /* Halt the receive and transmit queues */ |
| 538 | void gfar_halt(struct net_device *dev) | 640 | static void gfar_halt_nodisable(struct net_device *dev) |
| 539 | { | 641 | { |
| 540 | struct gfar_private *priv = netdev_priv(dev); | 642 | struct gfar_private *priv = netdev_priv(dev); |
| 541 | struct gfar __iomem *regs = priv->regs; | 643 | struct gfar __iomem *regs = priv->regs; |
| @@ -558,6 +660,15 @@ void gfar_halt(struct net_device *dev) | |||
| 558 | (IEVENT_GRSC | IEVENT_GTSC))) | 660 | (IEVENT_GRSC | IEVENT_GTSC))) |
| 559 | cpu_relax(); | 661 | cpu_relax(); |
| 560 | } | 662 | } |
| 663 | } | ||
| 664 | #endif | ||
| 665 | |||
| 666 | /* Halt the receive and transmit queues */ | ||
| 667 | void gfar_halt(struct net_device *dev) | ||
| 668 | { | ||
| 669 | struct gfar_private *priv = netdev_priv(dev); | ||
| 670 | struct gfar __iomem *regs = priv->regs; | ||
| 671 | u32 tempval; | ||
| 561 | 672 | ||
| 562 | /* Disable Rx and Tx */ | 673 | /* Disable Rx and Tx */ |
| 563 | tempval = gfar_read(®s->maccfg1); | 674 | tempval = gfar_read(®s->maccfg1); |
| @@ -1909,7 +2020,12 @@ static irqreturn_t gfar_error(int irq, void *dev_id) | |||
| 1909 | u32 events = gfar_read(&priv->regs->ievent); | 2020 | u32 events = gfar_read(&priv->regs->ievent); |
| 1910 | 2021 | ||
| 1911 | /* Clear IEVENT */ | 2022 | /* Clear IEVENT */ |
| 1912 | gfar_write(&priv->regs->ievent, IEVENT_ERR_MASK); | 2023 | gfar_write(&priv->regs->ievent, events & IEVENT_ERR_MASK); |
| 2024 | |||
| 2025 | /* Magic Packet is not an error. */ | ||
| 2026 | if ((priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET) && | ||
| 2027 | (events & IEVENT_MAG)) | ||
| 2028 | events &= ~IEVENT_MAG; | ||
| 1913 | 2029 | ||
| 1914 | /* Hmm... */ | 2030 | /* Hmm... */ |
| 1915 | if (netif_msg_rx_err(priv) || netif_msg_tx_err(priv)) | 2031 | if (netif_msg_rx_err(priv) || netif_msg_tx_err(priv)) |
| @@ -1977,6 +2093,8 @@ MODULE_ALIAS("platform:fsl-gianfar"); | |||
| 1977 | static struct platform_driver gfar_driver = { | 2093 | static struct platform_driver gfar_driver = { |
| 1978 | .probe = gfar_probe, | 2094 | .probe = gfar_probe, |
| 1979 | .remove = gfar_remove, | 2095 | .remove = gfar_remove, |
| 2096 | .suspend = gfar_suspend, | ||
| 2097 | .resume = gfar_resume, | ||
| 1980 | .driver = { | 2098 | .driver = { |
| 1981 | .name = "fsl-gianfar", | 2099 | .name = "fsl-gianfar", |
| 1982 | .owner = THIS_MODULE, | 2100 | .owner = THIS_MODULE, |
