X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fnet%2Fnatsemi.c;h=c9bfe4eea189d9d113feac1a99174b73eb0f4eeb;hb=f001a70cdc61c01452d42e8b32fd7c7842ef62d5;hp=5f88200724e6c12474f3a1a8fe5cdbdd1f349419;hpb=069f8256362b7a17da532f0631cee73b4cfee65b;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index 5f88200..c9bfe4e 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -81,6 +81,8 @@ static const int multicast_filter_limit = 100; Setting to > 1518 effectively disables this feature. */ static int rx_copybreak; +static int dspcfg_workaround = 1; + /* Used to pass the media type, etc. Both 'options[]' and 'full_duplex[]' should exist for driver interoperability. @@ -106,7 +108,7 @@ static int full_duplex[MAX_UNITS]; #define TX_TIMEOUT (2*HZ) #define NATSEMI_HW_TIMEOUT 400 -#define NATSEMI_TIMER_FREQ 3*HZ +#define NATSEMI_TIMER_FREQ 5*HZ #define NATSEMI_PG0_NREGS 64 #define NATSEMI_RFDR_NREGS 8 #define NATSEMI_PG1_NREGS 4 @@ -125,11 +127,10 @@ static int full_duplex[MAX_UNITS]; #define NATSEMI_RX_LIMIT 2046 /* maximum supported by hardware */ /* These identify the driver base version and may not be removed. */ -static const char version[] __devinitdata = +static const char version[] __devinitconst = KERN_INFO DRV_NAME " dp8381x driver, version " DRV_VERSION ", " DRV_RELDATE "\n" KERN_INFO " originally by Donald Becker \n" - KERN_INFO " http://www.scyld.com/network/natsemi.html\n" KERN_INFO " 2.4.x kernel port by Jeff Garzik, Tjeerd Mulder\n"; MODULE_AUTHOR("Donald Becker "); @@ -139,12 +140,14 @@ MODULE_LICENSE("GPL"); module_param(mtu, int, 0); module_param(debug, int, 0); module_param(rx_copybreak, int, 0); +module_param(dspcfg_workaround, int, 1); module_param_array(options, int, NULL, 0); module_param_array(full_duplex, int, NULL, 0); MODULE_PARM_DESC(mtu, "DP8381x MTU (all boards)"); MODULE_PARM_DESC(debug, "DP8381x default debug level"); MODULE_PARM_DESC(rx_copybreak, "DP8381x copy breakpoint for copy-only-tiny-frames"); +MODULE_PARM_DESC(dspcfg_workaround, "DP8381x: control DspCfg workaround"); MODULE_PARM_DESC(options, "DP8381x: Bits 0-3: media type, bit 17: full duplex"); MODULE_PARM_DESC(full_duplex, "DP8381x full duplex setting(s) (1)"); @@ -200,22 +203,8 @@ skbuff at an offset of "+2", 16-byte aligning the IP header. IIId. Synchronization Most operations are synchronized on the np->lock irq spinlock, except the -performance critical codepaths: - -The rx process only runs in the interrupt handler. Access from outside -the interrupt handler is only permitted after disable_irq(). - -The rx process usually runs under the netif_tx_lock. If np->intr_tx_reap -is set, then access is permitted under spin_lock_irq(&np->lock). - -Thus configuration functions that want to access everything must call - disable_irq(dev->irq); - netif_tx_lock_bh(dev); - spin_lock_irq(&np->lock); - -IV. Notes - -NatSemi PCI network controllers are very uncommon. +recieve and transmit paths which are synchronised using a combination of +hardware descriptor ownership, disabling interrupts and NAPI poll scheduling. IVb. References @@ -249,7 +238,7 @@ enum { }; /* array of board data directly indexed by pci_tbl[x].driver_data */ -static const struct { +static struct { const char *name; unsigned long flags; unsigned int eeprom_size; @@ -258,7 +247,7 @@ static const struct { { "NatSemi DP8381[56]", 0, 24 }, }; -static const struct pci_device_id natsemi_pci_tbl[] __devinitdata = { +static struct pci_device_id natsemi_pci_tbl[] __devinitdata = { { PCI_VENDOR_ID_NS, 0x0020, 0x12d9, 0x000c, 0, 0, 0 }, { PCI_VENDOR_ID_NS, 0x0020, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, { } /* terminate list */ @@ -522,10 +511,10 @@ enum PhyCtrl_bits { /* Note that using only 32 bit fields simplifies conversion to big-endian architectures. */ struct netdev_desc { - u32 next_desc; - s32 cmd_status; - u32 addr; - u32 software_use; + __le32 next_desc; + __le32 cmd_status; + __le32 addr; + __le32 software_use; }; /* Bits in network_desc.status */ @@ -557,6 +546,8 @@ struct netdev_private { /* address of a sent-in-place packet/buffer, for later free() */ struct sk_buff *tx_skbuff[TX_RING_SIZE]; dma_addr_t tx_dma[TX_RING_SIZE]; + struct net_device *dev; + struct napi_struct napi; struct net_device_stats stats; /* Media monitoring timer */ struct timer_list timer; @@ -590,6 +581,7 @@ struct netdev_private { u32 srr; /* expected DSPCFG value */ u16 dspcfg; + int dspcfg_workaround; /* parms saved in ethtool format */ u16 speed; /* The forced speed, 10Mb, 100Mb, gigabit */ u8 duplex; /* Duplex, half or full */ @@ -620,7 +612,7 @@ static void undo_cable_magic(struct net_device *dev); static void check_link(struct net_device *dev); static void netdev_timer(unsigned long data); static void dump_ring(struct net_device *dev); -static void tx_timeout(struct net_device *dev); +static void ns_tx_timeout(struct net_device *dev); static int alloc_ring(struct net_device *dev); static void refill_rx(struct net_device *dev); static void init_ring(struct net_device *dev); @@ -632,7 +624,7 @@ static void init_registers(struct net_device *dev); static int start_tx(struct sk_buff *skb, struct net_device *dev); static irqreturn_t intr_handler(int irq, void *dev_instance); static void netdev_error(struct net_device *dev, int intr_status); -static int natsemi_poll(struct net_device *dev, int *budget); +static int natsemi_poll(struct napi_struct *napi, int budget); static void netdev_rx(struct net_device *dev, int *work_done, int work_to_do); static void netdev_tx_done(struct net_device *dev); static int natsemi_change_mtu(struct net_device *dev, int new_mtu); @@ -656,6 +648,56 @@ static int netdev_get_regs(struct net_device *dev, u8 *buf); static int netdev_get_eeprom(struct net_device *dev, u8 *buf); static const struct ethtool_ops ethtool_ops; +#define NATSEMI_ATTR(_name) \ +static ssize_t natsemi_show_##_name(struct device *dev, \ + struct device_attribute *attr, char *buf); \ + static ssize_t natsemi_set_##_name(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count); \ + static DEVICE_ATTR(_name, 0644, natsemi_show_##_name, natsemi_set_##_name) + +#define NATSEMI_CREATE_FILE(_dev, _name) \ + device_create_file(&_dev->dev, &dev_attr_##_name) +#define NATSEMI_REMOVE_FILE(_dev, _name) \ + device_remove_file(&_dev->dev, &dev_attr_##_name) + +NATSEMI_ATTR(dspcfg_workaround); + +static ssize_t natsemi_show_dspcfg_workaround(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct netdev_private *np = netdev_priv(to_net_dev(dev)); + + return sprintf(buf, "%s\n", np->dspcfg_workaround ? "on" : "off"); +} + +static ssize_t natsemi_set_dspcfg_workaround(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct netdev_private *np = netdev_priv(to_net_dev(dev)); + int new_setting; + unsigned long flags; + + /* Find out the new setting */ + if (!strncmp("on", buf, count - 1) || !strncmp("1", buf, count - 1)) + new_setting = 1; + else if (!strncmp("off", buf, count - 1) + || !strncmp("0", buf, count - 1)) + new_setting = 0; + else + return count; + + spin_lock_irqsave(&np->lock, flags); + + np->dspcfg_workaround = new_setting; + + spin_unlock_irqrestore(&np->lock, flags); + + return count; +} + static inline void __iomem *ns_ioaddr(struct net_device *dev) { return (void __iomem *) dev->base_addr; @@ -737,6 +779,22 @@ static void __devinit natsemi_init_media (struct net_device *dev) } +static const struct net_device_ops natsemi_netdev_ops = { + .ndo_open = netdev_open, + .ndo_stop = netdev_close, + .ndo_start_xmit = start_tx, + .ndo_get_stats = get_stats, + .ndo_set_multicast_list = set_rx_mode, + .ndo_change_mtu = natsemi_change_mtu, + .ndo_do_ioctl = netdev_ioctl, + .ndo_tx_timeout = ns_tx_timeout, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = natsemi_poll_controller, +#endif +}; + static int __devinit natsemi_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -744,7 +802,8 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, struct netdev_private *np; int i, option, irq, chip_idx = ent->driver_data; static int find_cnt = -1; - unsigned long iostart, iosize; + resource_size_t iostart; + unsigned long iosize; void __iomem *ioaddr; const int pcibar = 1; /* PCI base address register */ int prev_eedata; @@ -781,7 +840,6 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, dev = alloc_etherdev(sizeof (struct netdev_private)); if (!dev) return -ENOMEM; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); i = pci_request_regions(pdev, DRV_NAME); @@ -807,6 +865,8 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, dev->irq = irq; np = netdev_priv(dev); + netif_napi_add(dev, &np->napi, natsemi_poll, 64); + np->dev = dev; np->pci_dev = pdev; pci_set_drvdata(pdev, dev); @@ -820,6 +880,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, np->ignore_phy = 1; else np->ignore_phy = 0; + np->dspcfg_workaround = dspcfg_workaround; /* Initial port: * - If configured to ignore the PHY set up for external. @@ -866,22 +927,9 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, if (find_cnt < MAX_UNITS && full_duplex[find_cnt]) np->full_duplex = 1; - /* The chip-specific entries in the device structure. */ - dev->open = &netdev_open; - dev->hard_start_xmit = &start_tx; - dev->stop = &netdev_close; - dev->get_stats = &get_stats; - dev->set_multicast_list = &set_rx_mode; - dev->change_mtu = &natsemi_change_mtu; - dev->do_ioctl = &netdev_ioctl; - dev->tx_timeout = &tx_timeout; + dev->netdev_ops = &natsemi_netdev_ops; dev->watchdog_timeo = TX_TIMEOUT; - dev->poll = natsemi_poll; - dev->weight = 64; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = &natsemi_poll_controller; -#endif SET_ETHTOOL_OPS(dev, ðtool_ops); if (mtu) @@ -899,13 +947,15 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, if (i) goto err_register_netdev; + if (NATSEMI_CREATE_FILE(pdev, dspcfg_workaround)) + goto err_create_file; + if (netif_msg_drv(np)) { - printk(KERN_INFO "natsemi %s: %s at %#08lx (%s), ", - dev->name, natsemi_pci_info[chip_idx].name, iostart, - pci_name(np->pci_dev)); - for (i = 0; i < ETH_ALEN-1; i++) - printk("%02x:", dev->dev_addr[i]); - printk("%02x, IRQ %d", dev->dev_addr[i], irq); + printk(KERN_INFO "natsemi %s: %s at %#08llx " + "(%s), %pM, IRQ %d", + dev->name, natsemi_pci_info[chip_idx].name, + (unsigned long long)iostart, pci_name(np->pci_dev), + dev->dev_addr, irq); if (dev->if_port == PORT_TP) printk(", port TP.\n"); else if (np->ignore_phy) @@ -915,6 +965,9 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, } return 0; + err_create_file: + unregister_netdev(dev); + err_register_netdev: iounmap(ioaddr); @@ -936,7 +989,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, a delay. Note that pre-2.0.34 kernels had a cache-alignment bug that made udelay() unreliable. The old method of using an ISA access as a delay, __SLOW_DOWN_IO__, is - depricated. + deprecated. */ #define eeprom_delay(ee_addr) readl(ee_addr) @@ -1493,6 +1546,8 @@ static int netdev_open(struct net_device *dev) free_irq(dev->irq, dev); return i; } + napi_enable(&np->napi); + init_ring(dev); spin_lock_irq(&np->lock); init_registers(dev); @@ -1514,7 +1569,7 @@ static int netdev_open(struct net_device *dev) /* Set the timer to check for link beat. */ init_timer(&np->timer); - np->timer.expires = jiffies + NATSEMI_TIMER_FREQ; + np->timer.expires = round_jiffies(jiffies + NATSEMI_TIMER_FREQ); np->timer.data = (unsigned long)dev; np->timer.function = &netdev_timer; /* timer handler */ add_timer(&np->timer); @@ -1553,7 +1608,7 @@ static void do_cable_magic(struct net_device *dev) * (these values all come from National) */ if (!(data & 0x80) || ((data >= 0xd8) && (data <= 0xff))) { - struct netdev_private *np = netdev_priv(dev); + np = netdev_priv(dev); /* the bug has been triggered - fix the coefficient */ writew(TSTDAT_FIXED, ioaddr + TSTDAT); @@ -1727,7 +1782,8 @@ static void init_registers(struct net_device *dev) * It seems that a reference set for this chip went out with incorrect info, * and there exist boards that aren't quite right. An unexpected voltage * drop can cause the PHY to get itself in a weird state (basically reset). - * NOTE: this only seems to affect revC chips. + * NOTE: this only seems to affect revC chips. The user can disable + * this check via dspcfg_workaround sysfs option. * 3) check of death of the RX path due to OOM */ static void netdev_timer(unsigned long data) @@ -1735,7 +1791,7 @@ static void netdev_timer(unsigned long data) struct net_device *dev = (struct net_device *)data; struct netdev_private *np = netdev_priv(dev); void __iomem * ioaddr = ns_ioaddr(dev); - int next_tick = 5*HZ; + int next_tick = NATSEMI_TIMER_FREQ; if (netif_msg_timer(np)) { /* DO NOT read the IntrStatus register, @@ -1753,10 +1809,10 @@ static void netdev_timer(unsigned long data) writew(1, ioaddr+PGSEL); dspcfg = readw(ioaddr+DSPCFG); writew(0, ioaddr+PGSEL); - if (dspcfg != np->dspcfg) { + if (np->dspcfg_workaround && dspcfg != np->dspcfg) { if (!netif_queue_stopped(dev)) { spin_unlock_irq(&np->lock); - if (netif_msg_hw(np)) + if (netif_msg_drv(np)) printk(KERN_NOTICE "%s: possible phy reset: " "re-initializing\n", dev->name); disable_irq(dev->irq); @@ -1793,7 +1849,11 @@ static void netdev_timer(unsigned long data) next_tick = 1; } } - mod_timer(&np->timer, jiffies + next_tick); + + if (next_tick > 1) + mod_timer(&np->timer, round_jiffies(jiffies + next_tick)); + else + mod_timer(&np->timer, jiffies + next_tick); } static void dump_ring(struct net_device *dev) @@ -1819,7 +1879,7 @@ static void dump_ring(struct net_device *dev) } } -static void tx_timeout(struct net_device *dev) +static void ns_tx_timeout(struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); void __iomem * ioaddr = ns_ioaddr(dev); @@ -1964,7 +2024,7 @@ static void drain_rx(struct net_device *dev) /* Free all the skbuffs in the Rx queue. */ for (i = 0; i < RX_RING_SIZE; i++) { np->rx_ring[i].cmd_status = 0; - np->rx_ring[i].addr = 0xBADF00D0; /* An invalid address. */ + np->rx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */ if (np->rx_skbuff[i]) { pci_unmap_single(np->pci_dev, np->rx_dma[i], buflen, @@ -2138,10 +2198,10 @@ static irqreturn_t intr_handler(int irq, void *dev_instance) prefetch(&np->rx_skbuff[np->cur_rx % RX_RING_SIZE]); - if (netif_rx_schedule_prep(dev)) { + if (napi_schedule_prep(&np->napi)) { /* Disable interrupts and register for poll */ natsemi_irq_disable(dev); - __netif_rx_schedule(dev); + __napi_schedule(&np->napi); } else printk(KERN_WARNING "%s: Ignoring interrupt, status %#08x, mask %#08x.\n", @@ -2154,12 +2214,11 @@ static irqreturn_t intr_handler(int irq, void *dev_instance) /* This is the NAPI poll routine. As well as the standard RX handling * it also handles all other interrupts that the chip might raise. */ -static int natsemi_poll(struct net_device *dev, int *budget) +static int natsemi_poll(struct napi_struct *napi, int budget) { - struct netdev_private *np = netdev_priv(dev); + struct netdev_private *np = container_of(napi, struct netdev_private, napi); + struct net_device *dev = np->dev; void __iomem * ioaddr = ns_ioaddr(dev); - - int work_to_do = min(*budget, dev->quota); int work_done = 0; do { @@ -2169,6 +2228,14 @@ static int natsemi_poll(struct net_device *dev, int *budget) dev->name, np->intr_status, readl(ioaddr + IntrMask)); + /* netdev_rx() may read IntrStatus again if the RX state + * machine falls over so do it first. */ + if (np->intr_status & + (IntrRxDone | IntrRxIntr | RxStatusFIFOOver | + IntrRxErr | IntrRxOverrun)) { + netdev_rx(dev, &work_done, budget); + } + if (np->intr_status & (IntrTxDone | IntrTxIntr | IntrTxIdle | IntrTxErr)) { spin_lock(&np->lock); @@ -2180,31 +2247,22 @@ static int natsemi_poll(struct net_device *dev, int *budget) if (np->intr_status & IntrAbnormalSummary) netdev_error(dev, np->intr_status); - if (np->intr_status & - (IntrRxDone | IntrRxIntr | RxStatusFIFOOver | - IntrRxErr | IntrRxOverrun)) { - netdev_rx(dev, &work_done, work_to_do); - } - - *budget -= work_done; - dev->quota -= work_done; - - if (work_done >= work_to_do) - return 1; + if (work_done >= budget) + return work_done; np->intr_status = readl(ioaddr + IntrStatus); } while (np->intr_status); - netif_rx_complete(dev); + napi_complete(napi); /* Reenable interrupts providing nothing is trying to shut * the chip down. */ spin_lock(&np->lock); - if (!np->hands_off && netif_running(dev)) + if (!np->hands_off) natsemi_irq_enable(dev); spin_unlock(&np->lock); - return 0; + return work_done; } /* This routine is logically part of the interrupt handler, but separated @@ -2287,15 +2345,14 @@ static void netdev_rx(struct net_device *dev, int *work_done, int work_to_do) * without copying to a minimally-sized skbuff. */ if (pkt_len < rx_copybreak && (skb = dev_alloc_skb(pkt_len + RX_OFFSET)) != NULL) { - skb->dev = dev; /* 16 byte align the IP header */ skb_reserve(skb, RX_OFFSET); pci_dma_sync_single_for_cpu(np->pci_dev, np->rx_dma[entry], buflen, PCI_DMA_FROMDEVICE); - eth_copy_and_sum(skb, - np->rx_skbuff[entry]->data, pkt_len, 0); + skb_copy_to_linear_data(skb, + np->rx_skbuff[entry]->data, pkt_len); skb_put(skb, pkt_len); pci_dma_sync_single_for_device(np->pci_dev, np->rx_dma[entry], @@ -2309,7 +2366,6 @@ static void netdev_rx(struct net_device *dev, int *work_done, int work_to_do) } skb->protocol = eth_type_trans(skb, dev); netif_receive_skb(skb); - dev->last_rx = jiffies; np->stats.rx_packets++; np->stats.rx_bytes += pkt_len; } @@ -2375,13 +2431,16 @@ static void netdev_error(struct net_device *dev, int intr_status) dev->name); } np->stats.rx_fifo_errors++; + np->stats.rx_errors++; } /* Hmmmmm, it's not clear how to recover from PCI faults. */ if (intr_status & IntrPCIErr) { printk(KERN_NOTICE "%s: PCI error %#08x\n", dev->name, intr_status & IntrPCIErr); np->stats.tx_fifo_errors++; + np->stats.tx_errors++; np->stats.rx_fifo_errors++; + np->stats.rx_errors++; } spin_unlock(&np->lock); } @@ -2439,8 +2498,8 @@ static void __set_rx_mode(struct net_device *dev) memset(mc_filter, 0, sizeof(mc_filter)); for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) { - int i = (ether_crc(ETH_ALEN, mclist->dmi_addr) >> 23) & 0x1ff; - mc_filter[i/8] |= (1 << (i & 0x07)); + int b = (ether_crc(ETH_ALEN, mclist->dmi_addr) >> 23) & 0x1ff; + mc_filter[b/8] |= (1 << (b & 0x07)); } rx_mode = RxFilterEnable | AcceptBroadcast | AcceptMulticast | AcceptMyPhys; @@ -3092,6 +3151,8 @@ static int netdev_close(struct net_device *dev) dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx); + napi_disable(&np->napi); + /* * FIXME: what if someone tries to close a device * that is suspended? @@ -3156,6 +3217,7 @@ static void __devexit natsemi_remove1 (struct pci_dev *pdev) struct net_device *dev = pci_get_drvdata(pdev); void __iomem * ioaddr = ns_ioaddr(dev); + NATSEMI_REMOVE_FILE(pdev, dspcfg_workaround); unregister_netdev (dev); pci_release_regions (pdev); iounmap(ioaddr); @@ -3173,7 +3235,7 @@ static void __devexit natsemi_remove1 (struct pci_dev *pdev) * suspend/resume synchronization: * entry points: * netdev_open, netdev_close, netdev_ioctl, set_rx_mode, intr_handler, - * start_tx, tx_timeout + * start_tx, ns_tx_timeout * * No function accesses the hardware without checking np->hands_off. * the check occurs under spin_lock_irq(&np->lock); @@ -3186,7 +3248,7 @@ static void __devexit natsemi_remove1 (struct pci_dev *pdev) * disable_irq() to enforce synchronization. * * natsemi_poll: checks before reenabling interrupts. suspend * sets hands_off, disables interrupts and then waits with - * netif_poll_disable(). + * napi_disable(). * * Interrupts must be disabled, otherwise hands_off can cause irq storms. */ @@ -3212,7 +3274,7 @@ static int natsemi_suspend (struct pci_dev *pdev, pm_message_t state) spin_unlock_irq(&np->lock); enable_irq(dev->irq); - netif_poll_disable(dev); + napi_disable(&np->napi); /* Update the error counts. */ __get_stats(dev); @@ -3244,15 +3306,23 @@ static int natsemi_resume (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata (pdev); struct netdev_private *np = netdev_priv(dev); + int ret = 0; rtnl_lock(); if (netif_device_present(dev)) goto out; if (netif_running(dev)) { BUG_ON(!np->hands_off); - pci_enable_device(pdev); + ret = pci_enable_device(pdev); + if (ret < 0) { + dev_err(&pdev->dev, + "pci_enable_device() failed: %d\n", ret); + goto out; + } /* pci_power_on(pdev); */ + napi_enable(&np->napi); + natsemi_reset(dev); init_ring(dev); disable_irq(dev->irq); @@ -3263,13 +3333,12 @@ static int natsemi_resume (struct pci_dev *pdev) spin_unlock_irq(&np->lock); enable_irq(dev->irq); - mod_timer(&np->timer, jiffies + 1*HZ); + mod_timer(&np->timer, round_jiffies(jiffies + 1*HZ)); } netif_device_attach(dev); - netif_poll_enable(dev); out: rtnl_unlock(); - return 0; + return ret; } #endif /* CONFIG_PM */