X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fnet%2Fsungem.c;h=5cd50fd53c1251fd8ba9a68a700ca28d96fcc897;hb=f7f1b0f1e2fbadeab12d24236000e778aa9b1ead;hp=38e94961e1a48aa4b23082c78ddd236e54f13c40;hpb=e3f6fb6212a7102bdb56ba38fa1e98fe72950475;p=linux-2.6.git diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index 38e94961e..5cd50fd53 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -3,16 +3,32 @@ * * Copyright (C) 2000, 2001, 2002, 2003 David S. Miller (davem@redhat.com) * - * Support for Apple GMAC and assorted PHYs by - * Benjamin Herrenscmidt (benh@kernel.crashing.org) + * Support for Apple GMAC and assorted PHYs, WOL, Power Management + * (C) 2001,2002,2003 Benjamin Herrenscmidt (benh@kernel.crashing.org) + * (C) 2004,2005 Benjamin Herrenscmidt, IBM Corp. * * NAPI and NETPOLL support * (C) 2004 by Eric Lemoine (eric.lemoine@gmail.com) * * TODO: - * - Get rid of all those nasty mdelay's and replace them - * with schedule_timeout. - * - Implement WOL + * - Now that the driver was significantly simplified, I need to rework + * the locking. I'm sure we don't need _2_ spinlocks, and we probably + * can avoid taking most of them for so long period of time (and schedule + * instead). The main issues at this point are caused by the netdev layer + * though: + * + * gem_change_mtu() and gem_set_multicast() are called with a read_lock() + * help by net/core/dev.c, thus they can't schedule. That means they can't + * call netif_poll_disable() neither, thus force gem_poll() to keep a spinlock + * where it could have been dropped. change_mtu especially would love also to + * be able to msleep instead of horrid locked delays when resetting the HW, + * but that read_lock() makes it impossible, unless I defer it's action to + * the reset task, which means it'll be asynchronous (won't take effect until + * the system schedules a bit). + * + * Also, it would probably be possible to also remove most of the long-life + * locking in open/resume code path (gem_reinit_chip) by beeing more careful + * about when we can start taking interrupts or get xmit() called... */ #include @@ -109,6 +125,8 @@ static struct pci_device_id gem_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_K2_GMAC, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_SH_SUNGEM, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, {0, } }; @@ -196,6 +214,33 @@ static inline void gem_disable_ints(struct gem *gp) writel(GREG_STAT_NAPI | GREG_STAT_TXDONE, gp->regs + GREG_IMASK); } +static void gem_get_cell(struct gem *gp) +{ + BUG_ON(gp->cell_enabled < 0); + gp->cell_enabled++; +#ifdef CONFIG_PPC_PMAC + if (gp->cell_enabled == 1) { + mb(); + pmac_call_feature(PMAC_FTR_GMAC_ENABLE, gp->of_node, 0, 1); + udelay(10); + } +#endif /* CONFIG_PPC_PMAC */ +} + +/* Turn off the chip's clock */ +static void gem_put_cell(struct gem *gp) +{ + BUG_ON(gp->cell_enabled <= 0); + gp->cell_enabled--; +#ifdef CONFIG_PPC_PMAC + if (gp->cell_enabled == 0) { + mb(); + pmac_call_feature(PMAC_FTR_GMAC_ENABLE, gp->of_node, 0, 0); + udelay(10); + } +#endif /* CONFIG_PPC_PMAC */ +} + static void gem_handle_mif_event(struct gem *gp, u32 reg_val, u32 changed_bits) { if (netif_msg_intr(gp)) @@ -319,7 +364,19 @@ static int gem_rxmac_reset(struct gem *gp) u64 desc_dma; u32 val; - /* First, reset MAC RX. */ + /* First, reset & disable MAC RX. */ + writel(MAC_RXRST_CMD, gp->regs + MAC_RXRST); + for (limit = 0; limit < 5000; limit++) { + if (!(readl(gp->regs + MAC_RXRST) & MAC_RXRST_CMD)) + break; + udelay(10); + } + if (limit == 5000) { + printk(KERN_ERR "%s: RX MAC will not reset, resetting whole " + "chip.\n", dev->name); + return 1; + } + writel(gp->mac_rx_cfg & ~MAC_RXCFG_ENAB, gp->regs + MAC_RXCFG); for (limit = 0; limit < 5000; limit++) { @@ -597,7 +654,7 @@ static int gem_abnormal_irq(struct net_device *dev, struct gem *gp, u32 gem_stat return 0; do_reset: - gp->reset_task_pending = 2; + gp->reset_task_pending = 1; schedule_work(&gp->reset_task); return 1; @@ -823,6 +880,9 @@ static int gem_poll(struct net_device *dev, int *budget) struct gem *gp = dev->priv; unsigned long flags; + /* + * NAPI locking nightmare: See comment at head of driver + */ spin_lock_irqsave(&gp->lock, flags); do { @@ -874,8 +934,11 @@ static irqreturn_t gem_interrupt(int irq, void *dev_id, struct pt_regs *regs) struct gem *gp = dev->priv; unsigned long flags; - /* Swallow interrupts when shutting the chip down */ - if (!gp->hw_running) + /* Swallow interrupts when shutting the chip down, though + * that shouldn't happen, we should have done free_irq() at + * this point... + */ + if (!gp->running) return IRQ_HANDLED; spin_lock_irqsave(&gp->lock, flags); @@ -916,7 +979,7 @@ static void gem_tx_timeout(struct net_device *dev) struct gem *gp = dev->priv; printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name); - if (!gp->hw_running) { + if (!gp->running) { printk("%s: hrm.. hw not running !\n", dev->name); return; } @@ -934,7 +997,7 @@ static void gem_tx_timeout(struct net_device *dev) spin_lock_irq(&gp->lock); spin_lock(&gp->tx_lock); - gp->reset_task_pending = 2; + gp->reset_task_pending = 1; schedule_work(&gp->reset_task); spin_unlock(&gp->tx_lock); @@ -975,6 +1038,11 @@ static int gem_start_xmit(struct sk_buff *skb, struct net_device *dev) local_irq_restore(flags); return NETDEV_TX_LOCKED; } + /* We raced with gem_do_stop() */ + if (!gp->running) { + spin_unlock_irqrestore(&gp->tx_lock, flags); + return NETDEV_TX_BUSY; + } /* This is a hard error, log it. */ if (TX_BUFFS_AVAIL(gp) <= (skb_shinfo(skb)->nr_frags + 1)) { @@ -1073,46 +1141,10 @@ static int gem_start_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } -/* Jumbo-grams don't seem to work :-( */ -#define GEM_MIN_MTU 68 -#if 1 -#define GEM_MAX_MTU 1500 -#else -#define GEM_MAX_MTU 9000 -#endif - -static int gem_change_mtu(struct net_device *dev, int new_mtu) -{ - struct gem *gp = dev->priv; - - if (new_mtu < GEM_MIN_MTU || new_mtu > GEM_MAX_MTU) - return -EINVAL; - - if (!netif_running(dev) || !netif_device_present(dev)) { - /* We'll just catch it later when the - * device is up'd or resumed. - */ - dev->mtu = new_mtu; - return 0; - } - - spin_lock_irq(&gp->lock); - spin_lock(&gp->tx_lock); - dev->mtu = new_mtu; - gp->reset_task_pending = 1; - schedule_work(&gp->reset_task); - spin_unlock(&gp->tx_lock); - spin_unlock_irq(&gp->lock); - - flush_scheduled_work(); - - return 0; -} - #define STOP_TRIES 32 /* Must be invoked under gp->lock and gp->tx_lock. */ -static void gem_stop(struct gem *gp) +static void gem_reset(struct gem *gp) { int limit; u32 val; @@ -1140,7 +1172,7 @@ static void gem_stop(struct gem *gp) /* Must be invoked under gp->lock and gp->tx_lock. */ static void gem_start_dma(struct gem *gp) { - unsigned long val; + u32 val; /* We are ready to rock, turn everything on. */ val = readl(gp->regs + TXDMA_CFG); @@ -1155,10 +1187,31 @@ static void gem_start_dma(struct gem *gp) (void) readl(gp->regs + MAC_RXCFG); udelay(100); - writel(GREG_STAT_TXDONE, gp->regs + GREG_IMASK); + gem_enable_ints(gp); writel(RX_RING_SIZE - 4, gp->regs + RXDMA_KICK); +} + +/* Must be invoked under gp->lock and gp->tx_lock. DMA won't be + * actually stopped before about 4ms tho ... + */ +static void gem_stop_dma(struct gem *gp) +{ + u32 val; + + /* We are done rocking, turn everything off. */ + val = readl(gp->regs + TXDMA_CFG); + writel(val & ~TXDMA_CFG_ENABLE, gp->regs + TXDMA_CFG); + val = readl(gp->regs + RXDMA_CFG); + writel(val & ~RXDMA_CFG_ENABLE, gp->regs + RXDMA_CFG); + val = readl(gp->regs + MAC_TXCFG); + writel(val & ~MAC_TXCFG_ENAB, gp->regs + MAC_TXCFG); + val = readl(gp->regs + MAC_RXCFG); + writel(val & ~MAC_RXCFG_ENAB, gp->regs + MAC_RXCFG); + + (void) readl(gp->regs + MAC_RXCFG); + /* Need to wait a bit ... done by the caller */ } @@ -1219,10 +1272,10 @@ start_aneg: if (speed == 0) speed = SPEED_10; - /* If HW is down, we don't try to actually setup the PHY, we + /* If we are asleep, we don't try to actually setup the PHY, we * just store the settings */ - if (!gp->hw_running) { + if (gp->asleep) { gp->phy_mii.autoneg = gp->want_autoneg = autoneg; gp->phy_mii.speed = speed; gp->phy_mii.duplex = duplex; @@ -1279,6 +1332,9 @@ static int gem_set_link_modes(struct gem *gp) printk(KERN_INFO "%s: Link is up at %d Mbps, %s-duplex.\n", gp->dev->name, speed, (full_duplex ? "full" : "half")); + if (!gp->running) + return 0; + val = (MAC_TXCFG_EIPG0 | MAC_TXCFG_NGU); if (full_duplex) { val |= (MAC_TXCFG_ICS | MAC_TXCFG_ICOLL); @@ -1405,48 +1461,19 @@ static int gem_mdio_link_not_up(struct gem *gp) } } -static void gem_init_rings(struct gem *); -static void gem_init_hw(struct gem *, int); - -static void gem_reset_task(void *data) -{ - struct gem *gp = (struct gem *) data; - - netif_poll_disable(gp->dev); - spin_lock_irq(&gp->lock); - spin_lock(&gp->tx_lock); - - if (gp->hw_running && gp->opened) { - netif_stop_queue(gp->dev); - - /* Reset the chip & rings */ - gem_stop(gp); - gem_init_rings(gp); - - gem_init_hw(gp, - (gp->reset_task_pending == 2)); - - netif_wake_queue(gp->dev); - } - gp->reset_task_pending = 0; - - spin_unlock(&gp->tx_lock); - spin_unlock_irq(&gp->lock); - netif_poll_enable(gp->dev); -} - static void gem_link_timer(unsigned long data) { struct gem *gp = (struct gem *) data; int restart_aneg = 0; - if (!gp->hw_running) + if (gp->asleep) return; spin_lock_irq(&gp->lock); spin_lock(&gp->tx_lock); + gem_get_cell(gp); - /* If the link of task is still pending, we just + /* If the reset task is still pending, we just * reschedule the link timer */ if (gp->reset_task_pending) @@ -1462,8 +1489,7 @@ static void gem_link_timer(unsigned long data) if ((val & PCS_MIISTAT_LS) != 0) { gp->lstate = link_up; netif_carrier_on(gp->dev); - if (gp->opened) - (void)gem_set_link_modes(gp); + (void)gem_set_link_modes(gp); } goto restart; } @@ -1484,7 +1510,7 @@ static void gem_link_timer(unsigned long data) } else if (gp->lstate != link_up) { gp->lstate = link_up; netif_carrier_on(gp->dev); - if (gp->opened && gem_set_link_modes(gp)) + if (gem_set_link_modes(gp)) restart_aneg = 1; } } else { @@ -1497,7 +1523,7 @@ static void gem_link_timer(unsigned long data) printk(KERN_INFO "%s: Link down\n", gp->dev->name); netif_carrier_off(gp->dev); - gp->reset_task_pending = 2; + gp->reset_task_pending = 1; schedule_work(&gp->reset_task); restart_aneg = 1; } else if (++gp->timer_ticks > 10) { @@ -1514,6 +1540,7 @@ static void gem_link_timer(unsigned long data) restart: mod_timer(&gp->link_timer, jiffies + ((12 * HZ) / 10)); out_unlock: + gem_put_cell(gp); spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); } @@ -1619,59 +1646,40 @@ static void gem_init_rings(struct gem *gp) wmb(); } -/* Must be invoked under gp->lock and gp->tx_lock. */ +/* Init PHY interface and start link poll state machine */ static void gem_init_phy(struct gem *gp) { u32 mifcfg; - + /* Revert MIF CFG setting done on stop_phy */ mifcfg = readl(gp->regs + MIF_CFG); mifcfg &= ~MIF_CFG_BBMODE; writel(mifcfg, gp->regs + MIF_CFG); -#ifdef CONFIG_PPC_PMAC if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) { - int i, j; + int i; /* Those delay sucks, the HW seem to love them though, I'll * serisouly consider breaking some locks here to be able * to schedule instead */ - pmac_call_feature(PMAC_FTR_GMAC_PHY_RESET, gp->of_node, 0, 0); - for (j = 0; j < 3; j++) { + for (i = 0; i < 3; i++) { +#ifdef CONFIG_PPC_PMAC + pmac_call_feature(PMAC_FTR_GMAC_PHY_RESET, gp->of_node, 0, 0); + msleep(20); +#endif /* Some PHYs used by apple have problem getting back to us, - * we _know_ it's actually at addr 0 or 1, that's a hack, but - * it helps to do that reset now. I suspect some motherboards - * don't wire the PHY reset line properly, thus the PHY doesn't - * come back with the above pmac_call_feature. + * we do an additional reset here */ - gp->mii_phy_addr = 0; - phy_write(gp, MII_BMCR, BMCR_RESET); - gp->mii_phy_addr = 1; phy_write(gp, MII_BMCR, BMCR_RESET); - /* We should probably break some locks here and schedule... */ - mdelay(10); - - /* On K2, we only probe the internal PHY at address 1, other - * addresses tend to return garbage. - */ - if (gp->pdev->device == PCI_DEVICE_ID_APPLE_K2_GMAC) + msleep(20); + if (phy_read(gp, MII_BMCR) != 0xffff) break; - - for (i = 0; i < 32; i++) { - gp->mii_phy_addr = i; - if (phy_read(gp, MII_BMCR) != 0xffff) - break; - } - if (i == 32) { + if (i == 2) printk(KERN_WARNING "%s: GMAC PHY not responding !\n", gp->dev->name); - gp->mii_phy_addr = 0; - } else - break; } } -#endif /* CONFIG_PPC_PMAC */ if (gp->pdev->vendor == PCI_VENDOR_ID_SUN && gp->pdev->device == PCI_DEVICE_ID_SUN_GEM) { @@ -1755,6 +1763,16 @@ static void gem_init_phy(struct gem *gp) val |= PCS_SCTRL_LOOP; writel(val, gp->regs + PCS_SCTRL); } + + /* Default aneg parameters */ + gp->timer_ticks = 0; + gp->lstate = link_down; + netif_carrier_off(gp->dev); + + /* Can I advertise gigabit here ? I'd need BCM PHY docs... */ + spin_lock_irq(&gp->lock); + gem_begin_auto_negotiation(gp, NULL); + spin_unlock_irq(&gp->lock); } /* Must be invoked under gp->lock and gp->tx_lock. */ @@ -1796,8 +1814,7 @@ static void gem_init_dma(struct gem *gp) } /* Must be invoked under gp->lock and gp->tx_lock. */ -static u32 -gem_setup_multicast(struct gem *gp) +static u32 gem_setup_multicast(struct gem *gp) { u32 rxcfg = 0; int i; @@ -1914,6 +1931,11 @@ static void gem_init_mac(struct gem *gp) * make no use of those events other than to record them. */ writel(0xffffffff, gp->regs + MAC_MCMASK); + + /* Don't enable GEM's WOL in normal operations + */ + if (gp->has_wol) + writel(0, gp->regs + WOL_WAKECSR); } /* Must be invoked under gp->lock and gp->tx_lock. */ @@ -1975,6 +1997,23 @@ static int gem_check_invariants(struct gem *gp) gp->tx_fifo_sz = readl(gp->regs + TXDMA_FSZ) * 64; gp->rx_fifo_sz = readl(gp->regs + RXDMA_FSZ) * 64; gp->swrst_base = 0; + + mif_cfg = readl(gp->regs + MIF_CFG); + mif_cfg &= ~(MIF_CFG_PSELECT|MIF_CFG_POLL|MIF_CFG_BBMODE|MIF_CFG_MDI1); + mif_cfg |= MIF_CFG_MDI0; + writel(mif_cfg, gp->regs + MIF_CFG); + writel(PCS_DMODE_MGM, gp->regs + PCS_DMODE); + writel(MAC_XIFCFG_OE, gp->regs + MAC_XIFCFG); + + /* We hard-code the PHY address so we can properly bring it out of + * reset later on, we can't really probe it at this point, though + * that isn't an issue. + */ + if (gp->pdev->device == PCI_DEVICE_ID_APPLE_K2_GMAC) + gp->mii_phy_addr = 1; + else + gp->mii_phy_addr = 0; + return 0; } @@ -2053,68 +2092,28 @@ static int gem_check_invariants(struct gem *gp) } /* Must be invoked under gp->lock and gp->tx_lock. */ -static void gem_init_hw(struct gem *gp, int restart_link) +static void gem_reinit_chip(struct gem *gp) { - /* On Apple's gmac, I initialize the PHY only after - * setting up the chip. It appears the gigabit PHYs - * don't quite like beeing talked to on the GII when - * the chip is not running, I suspect it might not - * be clocked at that point. --BenH - */ - if (restart_link) - gem_init_phy(gp); - gem_init_pause_thresholds(gp); - gem_init_dma(gp); - gem_init_mac(gp); - - if (restart_link) { - /* Default aneg parameters */ - gp->timer_ticks = 0; - gp->lstate = link_down; - netif_carrier_off(gp->dev); - - /* Can I advertise gigabit here ? I'd need BCM PHY docs... */ - gem_begin_auto_negotiation(gp, NULL); - } else { - if (gp->lstate == link_up) { - netif_carrier_on(gp->dev); - gem_set_link_modes(gp); - } - } -} + /* Reset the chip */ + gem_reset(gp); -#ifdef CONFIG_PPC_PMAC -/* Enable the chip's clock and make sure it's config space is - * setup properly. There appear to be no need to restore the - * base addresses. - */ -static void gem_apple_powerup(struct gem *gp) -{ - u32 mif_cfg; + /* Make sure ints are disabled */ + gem_disable_ints(gp); - mb(); - pmac_call_feature(PMAC_FTR_GMAC_ENABLE, gp->of_node, 0, 1); + /* Allocate & setup ring buffers */ + gem_init_rings(gp); - udelay(3); - - mif_cfg = readl(gp->regs + MIF_CFG); - mif_cfg &= ~(MIF_CFG_PSELECT|MIF_CFG_POLL|MIF_CFG_BBMODE|MIF_CFG_MDI1); - mif_cfg |= MIF_CFG_MDI0; - writel(mif_cfg, gp->regs + MIF_CFG); - writel(PCS_DMODE_MGM, gp->regs + PCS_DMODE); - writel(MAC_XIFCFG_OE, gp->regs + MAC_XIFCFG); -} + /* Configure pause thresholds */ + gem_init_pause_thresholds(gp); -/* Turn off the chip's clock */ -static void gem_apple_powerdown(struct gem *gp) -{ - pmac_call_feature(PMAC_FTR_GMAC_ENABLE, gp->of_node, 0, 0); + /* Init DMA & MAC engines */ + gem_init_dma(gp); + gem_init_mac(gp); } -#endif /* CONFIG_PPC_PMAC */ /* Must be invoked with no lock held. */ -static void gem_stop_phy(struct gem *gp) +static void gem_stop_phy(struct gem *gp, int wol) { u32 mifcfg; unsigned long flags; @@ -2131,8 +2130,22 @@ static void gem_stop_phy(struct gem *gp) mifcfg &= ~MIF_CFG_POLL; writel(mifcfg, gp->regs + MIF_CFG); - if (gp->wake_on_lan) { - /* Setup wake-on-lan */ + if (wol && gp->has_wol) { + unsigned char *e = &gp->dev->dev_addr[0]; + u32 csr; + + /* Setup wake-on-lan for MAGIC packet */ + writel(MAC_RXCFG_HFE | MAC_RXCFG_SFCS | MAC_RXCFG_ENAB, + gp->regs + MAC_RXCFG); + writel((e[4] << 8) | e[5], gp->regs + WOL_MATCH0); + writel((e[2] << 8) | e[3], gp->regs + WOL_MATCH1); + writel((e[0] << 8) | e[1], gp->regs + WOL_MATCH2); + + writel(WOL_MCOUNT_N | WOL_MCOUNT_M, gp->regs + WOL_MCOUNT); + csr = WOL_WAKECSR_ENABLE; + if ((readl(gp->regs + MAC_XIFCFG) & MAC_XIFCFG_GMII) == 0) + csr |= WOL_WAKECSR_MII; + writel(csr, gp->regs + WOL_WAKECSR); } else { writel(0, gp->regs + MAC_RXCFG); (void)readl(gp->regs + MAC_RXCFG); @@ -2148,20 +2161,20 @@ static void gem_stop_phy(struct gem *gp) writel(0, gp->regs + TXDMA_CFG); writel(0, gp->regs + RXDMA_CFG); - if (!gp->wake_on_lan) { + if (!wol) { spin_lock_irqsave(&gp->lock, flags); spin_lock(&gp->tx_lock); - gem_stop(gp); + gem_reset(gp); writel(MAC_TXRST_CMD, gp->regs + MAC_TXRST); writel(MAC_RXRST_CMD, gp->regs + MAC_RXRST); spin_unlock(&gp->tx_lock); spin_unlock_irqrestore(&gp->lock, flags); - } - if (found_mii_phy(gp) && gp->phy_mii.def->ops->suspend) - gp->phy_mii.def->ops->suspend(&gp->phy_mii, 0 /* wake on lan options */); + /* No need to take the lock here */ + + if (found_mii_phy(gp) && gp->phy_mii.def->ops->suspend) + gp->phy_mii.def->ops->suspend(&gp->phy_mii); - if (!gp->wake_on_lan) { /* According to Apple, we must set the MDIO pins to this begnign * state or we may 1) eat more current, 2) damage some PHYs */ @@ -2174,181 +2187,160 @@ static void gem_stop_phy(struct gem *gp) } } -/* Shut down the chip, must be called with pm_sem held. */ -static void gem_shutdown(struct gem *gp) + +static int gem_do_start(struct net_device *dev) { - /* Make us not-running to avoid timers respawning - * and swallow irqs - */ - gp->hw_running = 0; - wmb(); + struct gem *gp = dev->priv; + unsigned long flags; - /* Stop the link timer */ - del_timer_sync(&gp->link_timer); + spin_lock_irqsave(&gp->lock, flags); + spin_lock(&gp->tx_lock); - /* Stop the reset task */ - while (gp->reset_task_pending) - yield(); - - /* Actually stop the chip */ - if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) { - gem_stop_phy(gp); + /* Enable the cell */ + gem_get_cell(gp); -#ifdef CONFIG_PPC_PMAC - /* Power down the chip */ - gem_apple_powerdown(gp); -#endif /* CONFIG_PPC_PMAC */ - } else{ - unsigned long flags; + /* Init & setup chip hardware */ + gem_reinit_chip(gp); + + gp->running = 1; + + if (gp->lstate == link_up) { + netif_carrier_on(gp->dev); + gem_set_link_modes(gp); + } + + netif_wake_queue(gp->dev); + + spin_unlock(&gp->tx_lock); + spin_unlock_irqrestore(&gp->lock, flags); + + if (request_irq(gp->pdev->irq, gem_interrupt, + SA_SHIRQ, dev->name, (void *)dev)) { + printk(KERN_ERR "%s: failed to request irq !\n", gp->dev->name); spin_lock_irqsave(&gp->lock, flags); spin_lock(&gp->tx_lock); - gem_stop(gp); + + gp->running = 0; + gem_reset(gp); + gem_clean_rings(gp); + gem_put_cell(gp); + spin_unlock(&gp->tx_lock); spin_unlock_irqrestore(&gp->lock, flags); + + return -EAGAIN; } + + return 0; } -static void gem_pm_task(void *data) +static void gem_do_stop(struct net_device *dev, int wol) { - struct gem *gp = (struct gem *) data; + struct gem *gp = dev->priv; + unsigned long flags; - /* We assume if we can't lock the pm_sem, then open() was - * called again (or suspend()), and we can safely ignore - * the PM request - */ - if (down_trylock(&gp->pm_sem)) - return; + spin_lock_irqsave(&gp->lock, flags); + spin_lock(&gp->tx_lock); - /* Driver was re-opened or already shut down */ - if (gp->opened || !gp->hw_running) { - up(&gp->pm_sem); - return; - } + gp->running = 0; + + /* Stop netif queue */ + netif_stop_queue(dev); - gem_shutdown(gp); + /* Make sure ints are disabled */ + gem_disable_ints(gp); - up(&gp->pm_sem); -} + /* We can drop the lock now */ + spin_unlock(&gp->tx_lock); + spin_unlock_irqrestore(&gp->lock, flags); -static void gem_pm_timer(unsigned long data) -{ - struct gem *gp = (struct gem *) data; + /* If we are going to sleep with WOL */ + gem_stop_dma(gp); + msleep(10); + if (!wol) + gem_reset(gp); + msleep(10); + + /* Get rid of rings */ + gem_clean_rings(gp); - schedule_work(&gp->pm_task); + /* No irq needed anymore */ + free_irq(gp->pdev->irq, (void *) dev); + + /* Cell not needed neither if no WOL */ + if (!wol) { + spin_lock_irqsave(&gp->lock, flags); + gem_put_cell(gp); + spin_unlock_irqrestore(&gp->lock, flags); + } } -static int gem_open(struct net_device *dev) +static void gem_reset_task(void *data) { - struct gem *gp = dev->priv; - int hw_was_up; + struct gem *gp = (struct gem *) data; down(&gp->pm_sem); - hw_was_up = gp->hw_running; + netif_poll_disable(gp->dev); - /* Stop the PM timer/task */ - del_timer(&gp->pm_timer); - flush_scheduled_work(); + spin_lock_irq(&gp->lock); + spin_lock(&gp->tx_lock); - /* The power-management semaphore protects the hw_running - * etc. state so it is safe to do this bit without gp->lock - */ - if (!gp->hw_running) { -#ifdef CONFIG_PPC_PMAC - /* First, we need to bring up the chip */ - if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) { - gem_apple_powerup(gp); - gem_check_invariants(gp); - } -#endif /* CONFIG_PPC_PMAC */ + if (gp->running == 0) + goto not_running; - /* Reset the chip */ - spin_lock_irq(&gp->lock); - spin_lock(&gp->tx_lock); - gem_stop(gp); - spin_unlock(&gp->tx_lock); - spin_unlock_irq(&gp->lock); + if (gp->running) { + netif_stop_queue(gp->dev); - gp->hw_running = 1; + /* Reset the chip & rings */ + gem_reinit_chip(gp); + if (gp->lstate == link_up) + gem_set_link_modes(gp); + netif_wake_queue(gp->dev); } + not_running: + gp->reset_task_pending = 0; - /* We can now request the interrupt as we know it's masked - * on the controller - */ - if (request_irq(gp->pdev->irq, gem_interrupt, - SA_SHIRQ, dev->name, (void *)dev)) { - printk(KERN_ERR "%s: failed to request irq !\n", gp->dev->name); - - spin_lock_irq(&gp->lock); - spin_lock(&gp->tx_lock); -#ifdef CONFIG_PPC_PMAC - if (!hw_was_up && gp->pdev->vendor == PCI_VENDOR_ID_APPLE) - gem_apple_powerdown(gp); -#endif /* CONFIG_PPC_PMAC */ - /* Fire the PM timer that will shut us down in about 10 seconds */ - gp->pm_timer.expires = jiffies + 10*HZ; - add_timer(&gp->pm_timer); - up(&gp->pm_sem); - spin_unlock(&gp->tx_lock); - spin_unlock_irq(&gp->lock); + spin_unlock(&gp->tx_lock); + spin_unlock_irq(&gp->lock); - return -EAGAIN; - } + netif_poll_enable(gp->dev); - spin_lock_irq(&gp->lock); - spin_lock(&gp->tx_lock); + up(&gp->pm_sem); +} - /* Allocate & setup ring buffers */ - gem_init_rings(gp); - /* Init & setup chip hardware */ - gem_init_hw(gp, !hw_was_up); +static int gem_open(struct net_device *dev) +{ + struct gem *gp = dev->priv; + int rc = 0; - gp->opened = 1; + down(&gp->pm_sem); - spin_unlock(&gp->tx_lock); - spin_unlock_irq(&gp->lock); + /* We need the cell enabled */ + if (!gp->asleep) + rc = gem_do_start(dev); + gp->opened = (rc == 0); up(&gp->pm_sem); - return 0; + return rc; } static int gem_close(struct net_device *dev) { struct gem *gp = dev->priv; - /* Make sure we don't get distracted by suspend/resume */ - down(&gp->pm_sem); - /* Note: we don't need to call netif_poll_disable() here because * our caller (dev_close) already did it for us */ - /* Stop traffic, mark us closed */ - spin_lock_irq(&gp->lock); - spin_lock(&gp->tx_lock); + down(&gp->pm_sem); gp->opened = 0; - - netif_stop_queue(dev); - - /* Stop chip */ - gem_stop(gp); - - /* Get rid of rings */ - gem_clean_rings(gp); - - /* Bye, the pm timer will finish the job */ - free_irq(gp->pdev->irq, (void *) dev); - - spin_unlock(&gp->tx_lock); - spin_unlock_irq(&gp->lock); - - /* Fire the PM timer that will shut us down in about 10 seconds */ - gp->pm_timer.expires = jiffies + 10*HZ; - add_timer(&gp->pm_timer); + if (!gp->asleep) + gem_do_stop(dev, 0); up(&gp->pm_sem); @@ -2356,49 +2348,66 @@ static int gem_close(struct net_device *dev) } #ifdef CONFIG_PM -static int gem_suspend(struct pci_dev *pdev, u32 state) +static int gem_suspend(struct pci_dev *pdev, pm_message_t state) { struct net_device *dev = pci_get_drvdata(pdev); struct gem *gp = dev->priv; + unsigned long flags; - netif_poll_disable(dev); - - /* We hold the PM semaphore during entire driver - * sleep time - */ down(&gp->pm_sem); + netif_poll_disable(dev); + printk(KERN_INFO "%s: suspending, WakeOnLan %s\n", - dev->name, gp->wake_on_lan ? "enabled" : "disabled"); + dev->name, + (gp->wake_on_lan && gp->opened) ? "enabled" : "disabled"); - /* If the driver is opened, we stop the DMA */ - if (gp->opened) { - spin_lock_irq(&gp->lock); - spin_lock(&gp->tx_lock); + /* Keep the cell enabled during the entire operation */ + spin_lock_irqsave(&gp->lock, flags); + spin_lock(&gp->tx_lock); + gem_get_cell(gp); + spin_unlock(&gp->tx_lock); + spin_unlock_irqrestore(&gp->lock, flags); + /* If the driver is opened, we stop the MAC */ + if (gp->opened) { /* Stop traffic, mark us closed */ netif_device_detach(dev); - /* Stop chip */ - gem_stop(gp); + /* Switch off MAC, remember WOL setting */ + gp->asleep_wol = gp->wake_on_lan; + gem_do_stop(dev, gp->asleep_wol); + } else + gp->asleep_wol = 0; - /* Get rid of ring buffers */ - gem_clean_rings(gp); + /* Mark us asleep */ + gp->asleep = 1; + wmb(); - spin_unlock(&gp->tx_lock); - spin_unlock_irq(&gp->lock); + /* Stop the link timer */ + del_timer_sync(&gp->link_timer); - if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) - disable_irq(gp->pdev->irq); - } + /* Now we release the semaphore to not block the reset task who + * can take it too. We are marked asleep, so there will be no + * conflict here + */ + up(&gp->pm_sem); - if (gp->hw_running) { - /* Kill PM timer if any */ - del_timer_sync(&gp->pm_timer); - flush_scheduled_work(); + /* Wait for a pending reset task to complete */ + while (gp->reset_task_pending) + yield(); + flush_scheduled_work(); - gem_shutdown(gp); - } + /* Shut the PHY down eventually and setup WOL */ + gem_stop_phy(gp, gp->asleep_wol); + + /* Make sure bus master is disabled */ + pci_disable_device(gp->pdev); + + /* Release the cell, no need to take a lock at this point since + * nothing else can happen now + */ + gem_put_cell(gp); return 0; } @@ -2407,36 +2416,74 @@ static int gem_resume(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); struct gem *gp = dev->priv; + unsigned long flags; printk(KERN_INFO "%s: resuming\n", dev->name); - if (gp->opened) { -#ifdef CONFIG_PPC_PMAC - /* First, we need to bring up the chip */ - if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) { - gem_apple_powerup(gp); - gem_check_invariants(gp); - } -#endif /* CONFIG_PPC_PMAC */ - spin_lock_irq(&gp->lock); - spin_lock(&gp->tx_lock); + down(&gp->pm_sem); - gem_stop(gp); - gp->hw_running = 1; - gem_init_rings(gp); - gem_init_hw(gp, 1); + /* Keep the cell enabled during the entire operation, no need to + * take a lock here tho since nothing else can happen while we are + * marked asleep + */ + gem_get_cell(gp); - spin_unlock(&gp->tx_lock); - spin_unlock_irq(&gp->lock); + /* Make sure PCI access and bus master are enabled */ + if (pci_enable_device(gp->pdev)) { + printk(KERN_ERR "%s: Can't re-enable chip !\n", + dev->name); + /* Put cell and forget it for now, it will be considered as + * still asleep, a new sleep cycle may bring it back + */ + gem_put_cell(gp); + up(&gp->pm_sem); + return 0; + } + pci_set_master(gp->pdev); + + /* Reset everything */ + gem_reset(gp); + + /* Mark us woken up */ + gp->asleep = 0; + wmb(); + + /* Bring the PHY back. Again, lock is useless at this point as + * nothing can be happening until we restart the whole thing + */ + gem_init_phy(gp); + + /* If we were opened, bring everything back */ + if (gp->opened) { + /* Restart MAC */ + gem_do_start(dev); + /* Re-attach net device */ netif_device_attach(dev); - if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) - enable_irq(gp->pdev->irq); + } - up(&gp->pm_sem); + + spin_lock_irqsave(&gp->lock, flags); + spin_lock(&gp->tx_lock); + + /* If we had WOL enabled, the cell clock was never turned off during + * sleep, so we end up beeing unbalanced. Fix that here + */ + if (gp->asleep_wol) + gem_put_cell(gp); + + /* This function doesn't need to hold the cell, it will be held if the + * driver is open by gem_do_start(). + */ + gem_put_cell(gp); + + spin_unlock(&gp->tx_lock); + spin_unlock_irqrestore(&gp->lock, flags); netif_poll_enable(dev); + up(&gp->pm_sem); + return 0; } #endif /* CONFIG_PM */ @@ -2449,7 +2496,10 @@ static struct net_device_stats *gem_get_stats(struct net_device *dev) spin_lock_irq(&gp->lock); spin_lock(&gp->tx_lock); - if (gp->hw_running) { + /* I have seen this being called while the PM was in progress, + * so we shield against this + */ + if (gp->running) { stats->rx_crc_errors += readl(gp->regs + MAC_FCSERR); writel(0, gp->regs + MAC_FCSERR); @@ -2479,12 +2529,13 @@ static void gem_set_multicast(struct net_device *dev) u32 rxcfg, rxcfg_new; int limit = 10000; - if (!gp->hw_running) - return; - + spin_lock_irq(&gp->lock); spin_lock(&gp->tx_lock); + if (!gp->running) + goto bail; + netif_stop_queue(dev); rxcfg = readl(gp->regs + MAC_RXCFG); @@ -2508,10 +2559,50 @@ static void gem_set_multicast(struct net_device *dev) netif_wake_queue(dev); + bail: spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); } +/* Jumbo-grams don't seem to work :-( */ +#define GEM_MIN_MTU 68 +#if 1 +#define GEM_MAX_MTU 1500 +#else +#define GEM_MAX_MTU 9000 +#endif + +static int gem_change_mtu(struct net_device *dev, int new_mtu) +{ + struct gem *gp = dev->priv; + + if (new_mtu < GEM_MIN_MTU || new_mtu > GEM_MAX_MTU) + return -EINVAL; + + if (!netif_running(dev) || !netif_device_present(dev)) { + /* We'll just catch it later when the + * device is up'd or resumed. + */ + dev->mtu = new_mtu; + return 0; + } + + down(&gp->pm_sem); + spin_lock_irq(&gp->lock); + spin_lock(&gp->tx_lock); + dev->mtu = new_mtu; + if (gp->running) { + gem_reinit_chip(gp); + if (gp->lstate == link_up) + gem_set_link_modes(gp); + } + spin_unlock(&gp->tx_lock); + spin_unlock_irq(&gp->lock); + up(&gp->pm_sem); + + return 0; +} + static void gem_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { struct gem *gp = dev->priv; @@ -2540,7 +2631,6 @@ static int gem_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) /* Return current PHY settings */ spin_lock_irq(&gp->lock); - spin_lock(&gp->tx_lock); cmd->autoneg = gp->want_autoneg; cmd->speed = gp->phy_mii.speed; cmd->duplex = gp->phy_mii.duplex; @@ -2552,7 +2642,6 @@ static int gem_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) */ if (cmd->advertising == 0) cmd->advertising = cmd->supported; - spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); } else { // XXX PCS ? cmd->supported = @@ -2592,9 +2681,9 @@ static int gem_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) /* Apply settings and restart link process. */ spin_lock_irq(&gp->lock); - spin_lock(&gp->tx_lock); + gem_get_cell(gp); gem_begin_auto_negotiation(gp, cmd); - spin_unlock(&gp->tx_lock); + gem_put_cell(gp); spin_unlock_irq(&gp->lock); return 0; @@ -2609,9 +2698,9 @@ static int gem_nway_reset(struct net_device *dev) /* Restart link process. */ spin_lock_irq(&gp->lock); - spin_lock(&gp->tx_lock); + gem_get_cell(gp); gem_begin_auto_negotiation(gp, NULL); - spin_unlock(&gp->tx_lock); + gem_put_cell(gp); spin_unlock_irq(&gp->lock); return 0; @@ -2628,7 +2717,37 @@ static void gem_set_msglevel(struct net_device *dev, u32 value) struct gem *gp = dev->priv; gp->msg_enable = value; } - + + +/* Add more when I understand how to program the chip */ +/* like WAKE_UCAST | WAKE_MCAST | WAKE_BCAST */ + +#define WOL_SUPPORTED_MASK (WAKE_MAGIC) + +static void gem_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct gem *gp = dev->priv; + + /* Add more when I understand how to program the chip */ + if (gp->has_wol) { + wol->supported = WOL_SUPPORTED_MASK; + wol->wolopts = gp->wake_on_lan; + } else { + wol->supported = 0; + wol->wolopts = 0; + } +} + +static int gem_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct gem *gp = dev->priv; + + if (!gp->has_wol) + return -EOPNOTSUPP; + gp->wake_on_lan = wol->wolopts & WOL_SUPPORTED_MASK; + return 0; +} + static struct ethtool_ops gem_ethtool_ops = { .get_drvinfo = gem_get_drvinfo, .get_link = ethtool_op_get_link, @@ -2637,6 +2756,8 @@ static struct ethtool_ops gem_ethtool_ops = { .nway_reset = gem_nway_reset, .get_msglevel = gem_get_msglevel, .set_msglevel = gem_set_msglevel, + .get_wol = gem_get_wol, + .set_wol = gem_set_wol, }; static int gem_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) @@ -2644,22 +2765,28 @@ static int gem_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) struct gem *gp = dev->priv; struct mii_ioctl_data *data = if_mii(ifr); int rc = -EOPNOTSUPP; - + unsigned long flags; + /* Hold the PM semaphore while doing ioctl's or we may collide - * with open/close and power management and oops. + * with power management. */ down(&gp->pm_sem); - + + spin_lock_irqsave(&gp->lock, flags); + gem_get_cell(gp); + spin_unlock_irqrestore(&gp->lock, flags); + switch (cmd) { case SIOCGMIIPHY: /* Get address of MII PHY in use. */ data->phy_id = gp->mii_phy_addr; /* Fallthrough... */ case SIOCGMIIREG: /* Read MII PHY register. */ - if (!gp->hw_running) - rc = -EIO; + if (!gp->running) + rc = -EAGAIN; else { - data->val_out = __phy_read(gp, data->phy_id & 0x1f, data->reg_num & 0x1f); + data->val_out = __phy_read(gp, data->phy_id & 0x1f, + data->reg_num & 0x1f); rc = 0; } break; @@ -2667,14 +2794,19 @@ static int gem_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) case SIOCSMIIREG: /* Write MII PHY register. */ if (!capable(CAP_NET_ADMIN)) rc = -EPERM; - else if (!gp->hw_running) - rc = -EIO; + else if (!gp->running) + rc = -EAGAIN; else { - __phy_write(gp, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in); + __phy_write(gp, data->phy_id & 0x1f, data->reg_num & 0x1f, + data->val_in); rc = 0; } break; }; + + spin_lock_irqsave(&gp->lock, flags); + gem_put_cell(gp); + spin_unlock_irqrestore(&gp->lock, flags); up(&gp->pm_sem); @@ -2779,6 +2911,47 @@ static int __devinit gem_get_device_address(struct gem *gp) return 0; } +static void __devexit gem_remove_one(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + + if (dev) { + struct gem *gp = dev->priv; + + unregister_netdev(dev); + + /* Stop the link timer */ + del_timer_sync(&gp->link_timer); + + /* We shouldn't need any locking here */ + gem_get_cell(gp); + + /* Wait for a pending reset task to complete */ + while (gp->reset_task_pending) + yield(); + flush_scheduled_work(); + + /* Shut the PHY down */ + gem_stop_phy(gp, 0); + + gem_put_cell(gp); + + /* Make sure bus master is disabled */ + pci_disable_device(gp->pdev); + + /* Free resources */ + pci_free_consistent(pdev, + sizeof(struct gem_init_block), + gp->init_block, + gp->gblock_dvma); + iounmap(gp->regs); + pci_release_regions(pdev); + free_netdev(dev); + + pci_set_drvdata(pdev, NULL); + } +} + static int __devinit gem_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -2827,7 +3000,7 @@ static int __devinit gem_init_one(struct pci_dev *pdev, } pci_using_dac = 0; } - + gemreg_base = pci_resource_start(pdev, 0); gemreg_len = pci_resource_len(pdev, 0); @@ -2870,11 +3043,6 @@ static int __devinit gem_init_one(struct pci_dev *pdev, gp->link_timer.function = gem_link_timer; gp->link_timer.data = (unsigned long) gp; - init_timer(&gp->pm_timer); - gp->pm_timer.function = gem_pm_timer; - gp->pm_timer.data = (unsigned long) gp; - - INIT_WORK(&gp->pm_task, gem_pm_task, gp); INIT_WORK(&gp->reset_task, gem_reset_task, gp); gp->lstate = link_down; @@ -2889,20 +3057,22 @@ static int __devinit gem_init_one(struct pci_dev *pdev, goto err_out_free_res; } - /* On Apple, we power the chip up now in order for check - * invariants to work, but also because the firmware might - * not have properly shut down the PHY. + /* On Apple, we want a reference to the Open Firmware device-tree + * node. We use it for clock control. */ #ifdef CONFIG_PPC_PMAC gp->of_node = pci_device_to_OF_node(pdev); - if (pdev->vendor == PCI_VENDOR_ID_APPLE) - gem_apple_powerup(gp); #endif - spin_lock_irq(&gp->lock); - spin_lock(&gp->tx_lock); - gem_stop(gp); - spin_unlock(&gp->tx_lock); - spin_unlock_irq(&gp->lock); + + /* Only Apple version supports WOL afaik */ + if (pdev->vendor == PCI_VENDOR_ID_APPLE) + gp->has_wol = 1; + + /* Make sure cell is enabled */ + gem_get_cell(gp); + + /* Make sure everything is stopped and in init state */ + gem_reset(gp); /* Fill up the mii_phy structure (even if we won't use it) */ gp->phy_mii.dev = dev; @@ -2911,7 +3081,8 @@ static int __devinit gem_init_one(struct pci_dev *pdev, /* By default, we start with autoneg */ gp->want_autoneg = 1; - + + /* Check fifo sizes, PHY type, etc... */ if (gem_check_invariants(gp)) { err = -ENODEV; goto err_out_iounmap; @@ -2951,6 +3122,19 @@ static int __devinit gem_init_one(struct pci_dev *pdev, dev->poll_controller = gem_poll_controller; #endif + /* Set that now, in case PM kicks in now */ + pci_set_drvdata(pdev, dev); + + /* Detect & init PHY, start autoneg, we release the cell now + * too, it will be managed by whoever needs it + */ + gem_init_phy(gp); + + spin_lock_irq(&gp->lock); + gem_put_cell(gp); + spin_unlock_irq(&gp->lock); + + /* Register with kernel */ if (register_netdev(dev)) { printk(KERN_ERR PFX "Cannot register net device, " "aborting.\n"); @@ -2965,48 +3149,22 @@ static int __devinit gem_init_one(struct pci_dev *pdev, i == 5 ? ' ' : ':'); printk("\n"); - /* Detect & init PHY, start autoneg */ - spin_lock_irq(&gp->lock); - spin_lock(&gp->tx_lock); - gp->hw_running = 1; - gem_init_phy(gp); - gem_begin_auto_negotiation(gp, NULL); - spin_unlock(&gp->tx_lock); - spin_unlock_irq(&gp->lock); - if (gp->phy_type == phy_mii_mdio0 || gp->phy_type == phy_mii_mdio1) printk(KERN_INFO "%s: Found %s PHY\n", dev->name, gp->phy_mii.def ? gp->phy_mii.def->name : "no"); - pci_set_drvdata(pdev, dev); - /* GEM can do it all... */ dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_LLTX; if (pci_using_dac) dev->features |= NETIF_F_HIGHDMA; - /* Fire the PM timer that will shut us down in about 10 seconds */ - gp->pm_timer.expires = jiffies + 10*HZ; - add_timer(&gp->pm_timer); - return 0; err_out_free_consistent: - pci_free_consistent(pdev, - sizeof(struct gem_init_block), - gp->init_block, - gp->gblock_dvma); - + gem_remove_one(pdev); err_out_iounmap: - down(&gp->pm_sem); - /* Stop the PM timer & task */ - del_timer_sync(&gp->pm_timer); - flush_scheduled_work(); - if (gp->hw_running) - gem_shutdown(gp); - up(&gp->pm_sem); - + gem_put_cell(gp); iounmap(gp->regs); err_out_free_res: @@ -3020,34 +3178,6 @@ err_disable_device: } -static void __devexit gem_remove_one(struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - - if (dev) { - struct gem *gp = dev->priv; - - unregister_netdev(dev); - - down(&gp->pm_sem); - /* Stop the PM timer & task */ - del_timer_sync(&gp->pm_timer); - flush_scheduled_work(); - if (gp->hw_running) - gem_shutdown(gp); - up(&gp->pm_sem); - - pci_free_consistent(pdev, - sizeof(struct gem_init_block), - gp->init_block, - gp->gblock_dvma); - iounmap(gp->regs); - pci_release_regions(pdev); - free_netdev(dev); - - pci_set_drvdata(pdev, NULL); - } -} static struct pci_driver gem_driver = { .name = GEM_MODULE_NAME,