X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fnet%2Fsungem.c;h=38e94961e1a48aa4b23082c78ddd236e54f13c40;hb=f1227cd3e0e73c48b93368800aa89f4341103a00;hp=5cd50fd53c1251fd8ba9a68a700ca28d96fcc897;hpb=340e2b1a4c74f653454348914c408420d5d3c28a;p=linux-2.6.git diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index 5cd50fd53..38e94961e 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -3,32 +3,16 @@ * * Copyright (C) 2000, 2001, 2002, 2003 David S. Miller (davem@redhat.com) * - * 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. + * Support for Apple GMAC and assorted PHYs by + * Benjamin Herrenscmidt (benh@kernel.crashing.org) * * NAPI and NETPOLL support * (C) 2004 by Eric Lemoine (eric.lemoine@gmail.com) * * TODO: - * - 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... + * - Get rid of all those nasty mdelay's and replace them + * with schedule_timeout. + * - Implement WOL */ #include @@ -125,8 +109,6 @@ 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, } }; @@ -214,33 +196,6 @@ 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)) @@ -364,19 +319,7 @@ static int gem_rxmac_reset(struct gem *gp) u64 desc_dma; u32 val; - /* 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; - } - + /* First, reset MAC RX. */ writel(gp->mac_rx_cfg & ~MAC_RXCFG_ENAB, gp->regs + MAC_RXCFG); for (limit = 0; limit < 5000; limit++) { @@ -654,7 +597,7 @@ static int gem_abnormal_irq(struct net_device *dev, struct gem *gp, u32 gem_stat return 0; do_reset: - gp->reset_task_pending = 1; + gp->reset_task_pending = 2; schedule_work(&gp->reset_task); return 1; @@ -880,9 +823,6 @@ 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 { @@ -934,11 +874,8 @@ 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, though - * that shouldn't happen, we should have done free_irq() at - * this point... - */ - if (!gp->running) + /* Swallow interrupts when shutting the chip down */ + if (!gp->hw_running) return IRQ_HANDLED; spin_lock_irqsave(&gp->lock, flags); @@ -979,7 +916,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->running) { + if (!gp->hw_running) { printk("%s: hrm.. hw not running !\n", dev->name); return; } @@ -997,7 +934,7 @@ static void gem_tx_timeout(struct net_device *dev) spin_lock_irq(&gp->lock); spin_lock(&gp->tx_lock); - gp->reset_task_pending = 1; + gp->reset_task_pending = 2; schedule_work(&gp->reset_task); spin_unlock(&gp->tx_lock); @@ -1038,11 +975,6 @@ 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)) { @@ -1141,10 +1073,46 @@ 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_reset(struct gem *gp) +static void gem_stop(struct gem *gp) { int limit; u32 val; @@ -1172,7 +1140,7 @@ static void gem_reset(struct gem *gp) /* Must be invoked under gp->lock and gp->tx_lock. */ static void gem_start_dma(struct gem *gp) { - u32 val; + unsigned long val; /* We are ready to rock, turn everything on. */ val = readl(gp->regs + TXDMA_CFG); @@ -1187,31 +1155,10 @@ static void gem_start_dma(struct gem *gp) (void) readl(gp->regs + MAC_RXCFG); udelay(100); - gem_enable_ints(gp); + writel(GREG_STAT_TXDONE, gp->regs + GREG_IMASK); 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 */ } @@ -1272,10 +1219,10 @@ start_aneg: if (speed == 0) speed = SPEED_10; - /* If we are asleep, we don't try to actually setup the PHY, we + /* If HW is down, we don't try to actually setup the PHY, we * just store the settings */ - if (gp->asleep) { + if (!gp->hw_running) { gp->phy_mii.autoneg = gp->want_autoneg = autoneg; gp->phy_mii.speed = speed; gp->phy_mii.duplex = duplex; @@ -1332,9 +1279,6 @@ 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); @@ -1461,19 +1405,48 @@ 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->asleep) + if (!gp->hw_running) return; spin_lock_irq(&gp->lock); spin_lock(&gp->tx_lock); - gem_get_cell(gp); - /* If the reset task is still pending, we just + /* If the link of task is still pending, we just * reschedule the link timer */ if (gp->reset_task_pending) @@ -1489,7 +1462,8 @@ static void gem_link_timer(unsigned long data) if ((val & PCS_MIISTAT_LS) != 0) { gp->lstate = link_up; netif_carrier_on(gp->dev); - (void)gem_set_link_modes(gp); + if (gp->opened) + (void)gem_set_link_modes(gp); } goto restart; } @@ -1510,7 +1484,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 (gem_set_link_modes(gp)) + if (gp->opened && gem_set_link_modes(gp)) restart_aneg = 1; } } else { @@ -1523,7 +1497,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 = 1; + gp->reset_task_pending = 2; schedule_work(&gp->reset_task); restart_aneg = 1; } else if (++gp->timer_ticks > 10) { @@ -1540,7 +1514,6 @@ 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); } @@ -1646,40 +1619,59 @@ static void gem_init_rings(struct gem *gp) wmb(); } -/* Init PHY interface and start link poll state machine */ +/* Must be invoked under gp->lock and gp->tx_lock. */ 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; + int i, j; /* Those delay sucks, the HW seem to love them though, I'll * serisouly consider breaking some locks here to be able * to schedule instead */ - 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 + pmac_call_feature(PMAC_FTR_GMAC_PHY_RESET, gp->of_node, 0, 0); + for (j = 0; j < 3; j++) { /* Some PHYs used by apple have problem getting back to us, - * we do an additional reset here + * 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. */ + gp->mii_phy_addr = 0; phy_write(gp, MII_BMCR, BMCR_RESET); - msleep(20); - if (phy_read(gp, MII_BMCR) != 0xffff) + 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) break; - if (i == 2) + + for (i = 0; i < 32; i++) { + gp->mii_phy_addr = i; + if (phy_read(gp, MII_BMCR) != 0xffff) + break; + } + if (i == 32) { 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) { @@ -1763,16 +1755,6 @@ 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. */ @@ -1814,7 +1796,8 @@ 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; @@ -1931,11 +1914,6 @@ 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. */ @@ -1997,23 +1975,6 @@ 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; } @@ -2092,28 +2053,68 @@ static int gem_check_invariants(struct gem *gp) } /* Must be invoked under gp->lock and gp->tx_lock. */ -static void gem_reinit_chip(struct gem *gp) +static void gem_init_hw(struct gem *gp, int restart_link) { - /* Reset the chip */ - gem_reset(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); - /* Make sure ints are disabled */ - gem_disable_ints(gp); + if (restart_link) { + /* Default aneg parameters */ + gp->timer_ticks = 0; + gp->lstate = link_down; + netif_carrier_off(gp->dev); - /* Allocate & setup ring buffers */ - gem_init_rings(gp); + /* 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); + } + } +} - /* Configure pause thresholds */ - gem_init_pause_thresholds(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; - /* Init DMA & MAC engines */ - gem_init_dma(gp); - gem_init_mac(gp); + mb(); + pmac_call_feature(PMAC_FTR_GMAC_ENABLE, gp->of_node, 0, 1); + + 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); +} + +/* 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); } +#endif /* CONFIG_PPC_PMAC */ /* Must be invoked with no lock held. */ -static void gem_stop_phy(struct gem *gp, int wol) +static void gem_stop_phy(struct gem *gp) { u32 mifcfg; unsigned long flags; @@ -2130,22 +2131,8 @@ static void gem_stop_phy(struct gem *gp, int wol) mifcfg &= ~MIF_CFG_POLL; writel(mifcfg, gp->regs + MIF_CFG); - 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); + if (gp->wake_on_lan) { + /* Setup wake-on-lan */ } else { writel(0, gp->regs + MAC_RXCFG); (void)readl(gp->regs + MAC_RXCFG); @@ -2161,20 +2148,20 @@ static void gem_stop_phy(struct gem *gp, int wol) writel(0, gp->regs + TXDMA_CFG); writel(0, gp->regs + RXDMA_CFG); - if (!wol) { + if (!gp->wake_on_lan) { spin_lock_irqsave(&gp->lock, flags); spin_lock(&gp->tx_lock); - gem_reset(gp); + gem_stop(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); + } - /* 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 (found_mii_phy(gp) && gp->phy_mii.def->ops->suspend) + gp->phy_mii.def->ops->suspend(&gp->phy_mii, 0 /* wake on lan options */); + 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 */ @@ -2187,160 +2174,181 @@ static void gem_stop_phy(struct gem *gp, int wol) } } - -static int gem_do_start(struct net_device *dev) +/* Shut down the chip, must be called with pm_sem held. */ +static void gem_shutdown(struct gem *gp) { - struct gem *gp = dev->priv; - unsigned long flags; - - spin_lock_irqsave(&gp->lock, flags); - spin_lock(&gp->tx_lock); - - /* Enable the cell */ - gem_get_cell(gp); - - /* 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); - } + /* Make us not-running to avoid timers respawning + * and swallow irqs + */ + gp->hw_running = 0; + wmb(); - netif_wake_queue(gp->dev); + /* Stop the link timer */ + del_timer_sync(&gp->link_timer); - spin_unlock(&gp->tx_lock); - spin_unlock_irqrestore(&gp->lock, flags); + /* 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); - 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); +#ifdef CONFIG_PPC_PMAC + /* Power down the chip */ + gem_apple_powerdown(gp); +#endif /* CONFIG_PPC_PMAC */ + } else{ + unsigned long flags; spin_lock_irqsave(&gp->lock, flags); spin_lock(&gp->tx_lock); - - gp->running = 0; - gem_reset(gp); - gem_clean_rings(gp); - gem_put_cell(gp); - + gem_stop(gp); spin_unlock(&gp->tx_lock); spin_unlock_irqrestore(&gp->lock, flags); - - return -EAGAIN; } - - return 0; } -static void gem_do_stop(struct net_device *dev, int wol) +static void gem_pm_task(void *data) { - struct gem *gp = dev->priv; - unsigned long flags; - - spin_lock_irqsave(&gp->lock, flags); - spin_lock(&gp->tx_lock); - - gp->running = 0; - - /* Stop netif queue */ - netif_stop_queue(dev); + struct gem *gp = (struct gem *) data; - /* Make sure ints are disabled */ - gem_disable_ints(gp); + /* 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; - /* We can drop the lock now */ - spin_unlock(&gp->tx_lock); - spin_unlock_irqrestore(&gp->lock, flags); + /* Driver was re-opened or already shut down */ + if (gp->opened || !gp->hw_running) { + up(&gp->pm_sem); + return; + } - /* If we are going to sleep with WOL */ - gem_stop_dma(gp); - msleep(10); - if (!wol) - gem_reset(gp); - msleep(10); + gem_shutdown(gp); - /* Get rid of rings */ - gem_clean_rings(gp); + up(&gp->pm_sem); +} - /* No irq needed anymore */ - free_irq(gp->pdev->irq, (void *) dev); +static void gem_pm_timer(unsigned long data) +{ + struct gem *gp = (struct gem *) data; - /* 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); - } + schedule_work(&gp->pm_task); } -static void gem_reset_task(void *data) +static int gem_open(struct net_device *dev) { - struct gem *gp = (struct gem *) data; + struct gem *gp = dev->priv; + int hw_was_up; down(&gp->pm_sem); - netif_poll_disable(gp->dev); - - spin_lock_irq(&gp->lock); - spin_lock(&gp->tx_lock); + hw_was_up = gp->hw_running; - if (gp->running == 0) - goto not_running; + /* Stop the PM timer/task */ + del_timer(&gp->pm_timer); + flush_scheduled_work(); - if (gp->running) { - netif_stop_queue(gp->dev); + /* 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 */ - /* Reset the chip & rings */ - gem_reinit_chip(gp); - if (gp->lstate == link_up) - gem_set_link_modes(gp); - netif_wake_queue(gp->dev); + /* 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); + + gp->hw_running = 1; } - not_running: - gp->reset_task_pending = 0; - spin_unlock(&gp->tx_lock); - spin_unlock_irq(&gp->lock); + /* 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); - netif_poll_enable(gp->dev); + 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); - up(&gp->pm_sem); -} + return -EAGAIN; + } + spin_lock_irq(&gp->lock); + spin_lock(&gp->tx_lock); -static int gem_open(struct net_device *dev) -{ - struct gem *gp = dev->priv; - int rc = 0; + /* Allocate & setup ring buffers */ + gem_init_rings(gp); - down(&gp->pm_sem); + /* Init & setup chip hardware */ + gem_init_hw(gp, !hw_was_up); - /* We need the cell enabled */ - if (!gp->asleep) - rc = gem_do_start(dev); - gp->opened = (rc == 0); + gp->opened = 1; + + spin_unlock(&gp->tx_lock); + spin_unlock_irq(&gp->lock); up(&gp->pm_sem); - return rc; + return 0; } 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 */ - down(&gp->pm_sem); + /* Stop traffic, mark us closed */ + spin_lock_irq(&gp->lock); + spin_lock(&gp->tx_lock); gp->opened = 0; - if (!gp->asleep) - gem_do_stop(dev, 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); up(&gp->pm_sem); @@ -2348,66 +2356,49 @@ static int gem_close(struct net_device *dev) } #ifdef CONFIG_PM -static int gem_suspend(struct pci_dev *pdev, pm_message_t state) +static int gem_suspend(struct pci_dev *pdev, u32 state) { struct net_device *dev = pci_get_drvdata(pdev); struct gem *gp = dev->priv; - unsigned long flags; - - down(&gp->pm_sem); netif_poll_disable(dev); + /* We hold the PM semaphore during entire driver + * sleep time + */ + down(&gp->pm_sem); + printk(KERN_INFO "%s: suspending, WakeOnLan %s\n", - dev->name, - (gp->wake_on_lan && gp->opened) ? "enabled" : "disabled"); + dev->name, gp->wake_on_lan ? "enabled" : "disabled"); - /* 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 the driver is opened, we stop the DMA */ if (gp->opened) { + spin_lock_irq(&gp->lock); + spin_lock(&gp->tx_lock); + /* Stop traffic, mark us closed */ netif_device_detach(dev); - /* 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; - - /* Mark us asleep */ - gp->asleep = 1; - wmb(); + /* Stop chip */ + gem_stop(gp); - /* Stop the link timer */ - del_timer_sync(&gp->link_timer); - - /* 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); + /* Get rid of ring buffers */ + gem_clean_rings(gp); - /* Wait for a pending reset task to complete */ - while (gp->reset_task_pending) - yield(); - flush_scheduled_work(); + spin_unlock(&gp->tx_lock); + spin_unlock_irq(&gp->lock); - /* Shut the PHY down eventually and setup WOL */ - gem_stop_phy(gp, gp->asleep_wol); + if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) + disable_irq(gp->pdev->irq); + } - /* Make sure bus master is disabled */ - pci_disable_device(gp->pdev); + if (gp->hw_running) { + /* Kill PM timer if any */ + del_timer_sync(&gp->pm_timer); + flush_scheduled_work(); - /* Release the cell, no need to take a lock at this point since - * nothing else can happen now - */ - gem_put_cell(gp); + gem_shutdown(gp); + } return 0; } @@ -2416,74 +2407,36 @@ 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); - down(&gp->pm_sem); - - /* 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); - - /* 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(); + 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); - /* 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); + gem_stop(gp); + gp->hw_running = 1; + gem_init_rings(gp); + gem_init_hw(gp, 1); - /* If we were opened, bring everything back */ - if (gp->opened) { - /* Restart MAC */ - gem_do_start(dev); + spin_unlock(&gp->tx_lock); + spin_unlock_irq(&gp->lock); - /* Re-attach net device */ netif_device_attach(dev); - + if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) + enable_irq(gp->pdev->irq); } - - 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); + up(&gp->pm_sem); netif_poll_enable(dev); - up(&gp->pm_sem); - return 0; } #endif /* CONFIG_PM */ @@ -2496,10 +2449,7 @@ static struct net_device_stats *gem_get_stats(struct net_device *dev) spin_lock_irq(&gp->lock); spin_lock(&gp->tx_lock); - /* I have seen this being called while the PM was in progress, - * so we shield against this - */ - if (gp->running) { + if (gp->hw_running) { stats->rx_crc_errors += readl(gp->regs + MAC_FCSERR); writel(0, gp->regs + MAC_FCSERR); @@ -2529,13 +2479,12 @@ 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); @@ -2559,50 +2508,10 @@ 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; @@ -2631,6 +2540,7 @@ 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; @@ -2642,6 +2552,7 @@ 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 = @@ -2681,9 +2592,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); - gem_get_cell(gp); + spin_lock(&gp->tx_lock); gem_begin_auto_negotiation(gp, cmd); - gem_put_cell(gp); + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); return 0; @@ -2698,9 +2609,9 @@ static int gem_nway_reset(struct net_device *dev) /* Restart link process. */ spin_lock_irq(&gp->lock); - gem_get_cell(gp); + spin_lock(&gp->tx_lock); gem_begin_auto_negotiation(gp, NULL); - gem_put_cell(gp); + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); return 0; @@ -2717,37 +2628,7 @@ 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, @@ -2756,8 +2637,6 @@ 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) @@ -2765,28 +2644,22 @@ 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 power management. + * with open/close and power management and oops. */ 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->running) - rc = -EAGAIN; + if (!gp->hw_running) + rc = -EIO; 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; @@ -2794,19 +2667,14 @@ 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->running) - rc = -EAGAIN; + else if (!gp->hw_running) + rc = -EIO; 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); @@ -2911,47 +2779,6 @@ 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) { @@ -3000,7 +2827,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); @@ -3043,6 +2870,11 @@ 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; @@ -3057,22 +2889,20 @@ static int __devinit gem_init_one(struct pci_dev *pdev, goto err_out_free_res; } - /* On Apple, we want a reference to the Open Firmware device-tree - * node. We use it for clock control. + /* 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. */ #ifdef CONFIG_PPC_PMAC gp->of_node = pci_device_to_OF_node(pdev); -#endif - - /* 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); + 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); /* Fill up the mii_phy structure (even if we won't use it) */ gp->phy_mii.dev = dev; @@ -3081,8 +2911,7 @@ 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; @@ -3122,19 +2951,6 @@ 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"); @@ -3149,22 +2965,48 @@ 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: - gem_remove_one(pdev); + pci_free_consistent(pdev, + sizeof(struct gem_init_block), + gp->init_block, + gp->gblock_dvma); + err_out_iounmap: - gem_put_cell(gp); + 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); + iounmap(gp->regs); err_out_free_res: @@ -3178,6 +3020,34 @@ 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,