This is a first attempt to add PM support to the PPC 440 emac driver. Still needed are code to take care of the PHY chip, and to support wake-on-lan. Any comments on how to do those would be most welcome.
The 'PM support for Ebony' patch I posted can be used to test on that platform. -Geoff * emac-pm.patch Signed-off-by: Geoff Levand <geoffrey.levand at am.sony.com> for CELF -- Index: linux-2.6.12-bhpm/drivers/net/ibm_emac/ibm_emac_core.c =================================================================== --- linux-2.6.12-bhpm.orig/drivers/net/ibm_emac/ibm_emac_core.c 2005-06-02 15:09:23.000000000 -0700 +++ linux-2.6.12-bhpm/drivers/net/ibm_emac/ibm_emac_core.c 2005-06-02 17:11:02.000000000 -0700 @@ -1306,7 +1306,7 @@ ep->ack_slot = 0; } -static void emac_reset_configure(struct ocp_enet_private *fep) +static void emac_reset(struct ocp_enet_private *fep) { emac_t *emacp = fep->emacp; int i; @@ -1338,6 +1338,14 @@ /* Switch IRQs off for now */ out_be32(&emacp->em0iser, 0); +} + +static void emac_reset_configure(struct ocp_enet_private *fep) +{ + emac_t *emacp = fep->emacp; + + /* Reset EMAC */ + emac_reset(fep); /* Configure MAL rx channel */ mal_set_rcbs(fep->mal, fep->mal_rx_chan, DESC_BUF_SIZE_REG); @@ -1615,20 +1623,10 @@ } } -static int emac_open(struct net_device *dev) +static int emac_up(struct net_device *dev) { - struct ocp_enet_private *fep = dev->priv; int rc; - - spin_lock_irq(&fep->lock); - - fep->opened = 1; - netif_carrier_off(dev); - - /* Reset & configure the chip */ - emac_reset_configure(fep); - - spin_unlock_irq(&fep->lock); + struct ocp_enet_private *fep = dev->priv; /* Request our interrupt lines */ rc = request_irq(dev->irq, emac_mac_irq, 0, "IBM EMAC MAC", dev); @@ -1646,6 +1644,24 @@ return rc; } +static int emac_open(struct net_device *dev) +{ + struct ocp_enet_private *fep = dev->priv; + + spin_lock_irq(&fep->lock); + + fep->opened = 1; + netif_carrier_off(dev); + + /* Reset & configure the chip */ + emac_reset_configure(fep); + + spin_unlock_irq(&fep->lock); + + return emac_up(dev); + +} + static int emac_close(struct net_device *dev) { struct ocp_enet_private *fep = dev->priv; @@ -1975,6 +1991,71 @@ return 0; } +#ifdef CONFIG_PM +static int emac_suspend(struct ocp_device *pdev, u32 state) +{ + struct net_device *netdev = ocp_get_drvdata(pdev); + struct ocp_enet_private *fep = netdev->priv; + + pr_debug("PM:emac_suspend:%d\n", state); + + if(netif_running(netdev)) + emac_close(netdev); + + /* Stop timer and Reset the chip */ + spin_lock_irq(&fep->lock); + del_timer(&fep->link_timer); + fep->opened = 0; + emac_reset(fep); + spin_unlock_irq(&fep->lock); + + /* detach */ + netif_device_detach(netdev); + + /* + * Save current states then turn off EMAC and PHY + * according to specified state. + * make WOL(WakeupOnLan) enable, if needed + */ + // XXX:TBD + pdev->current_state = state; + + return 0; +} + +static int emac_resume(struct ocp_device *pdev) +{ + struct net_device *netdev = ocp_get_drvdata(pdev); + struct ocp_enet_private *fep = netdev->priv; + + pr_debug("emac_resume:\n"); + + /* Turn on EMAC and PHY and restore state */ + // XXX:TBD + pdev->current_state = 0; + + /* Reset & configure the chip then Restart Timer */ + spin_lock_irq(&fep->lock); + + fep->opened = 1; + netif_carrier_off(netdev); + emac_reset_configure(fep); + + (fep->link_timer).expires = jiffies+1; + add_timer(&fep->link_timer); + + spin_unlock_irq(&fep->lock); + + /* attach */ + netif_device_attach(netdev); + + if(netif_running(netdev)) + emac_up(netdev); + + return 0; +} +#endif + /* Structure for a device driver */ static struct ocp_device_id emac_ids[] = { {.vendor = OCP_ANY_ID,.function = OCP_FUNC_EMAC}, @@ -1987,6 +2068,10 @@ .probe = emac_probe, .remove = emac_remove, +#ifdef CONFIG_PM + .suspend = emac_suspend, + .resume = emac_resume, +#endif }; static int __init emac_init(void) -EOF