浏览代码

Merge branch 'upstream-fixes' into upstream

Jeff Garzik 19 年之前
父节点
当前提交
9f1da23b63
共有 4 个文件被更改,包括 120 次插入31 次删除
  1. 67 12
      drivers/net/forcedeth.c
  2. 41 11
      drivers/net/sky2.c
  3. 2 0
      drivers/net/sky2.h
  4. 10 8
      include/linux/netdevice.h

+ 67 - 12
drivers/net/forcedeth.c

@@ -105,6 +105,7 @@
  *	0.50: 20 Jan 2006: Add 8021pq tagging support.
  *	0.50: 20 Jan 2006: Add 8021pq tagging support.
  *	0.51: 20 Jan 2006: Add 64bit consistent memory allocation for rings.
  *	0.51: 20 Jan 2006: Add 64bit consistent memory allocation for rings.
  *	0.52: 20 Jan 2006: Add MSI/MSIX support.
  *	0.52: 20 Jan 2006: Add MSI/MSIX support.
+ *	0.53: 19 Mar 2006: Fix init from low power mode and add hw reset.
  *
  *
  * Known bugs:
  * Known bugs:
  * We suspect that on some hardware no TX done interrupts are generated.
  * We suspect that on some hardware no TX done interrupts are generated.
@@ -116,7 +117,7 @@
  * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few
  * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few
  * superfluous timer interrupts from the nic.
  * superfluous timer interrupts from the nic.
  */
  */
-#define FORCEDETH_VERSION		"0.52"
+#define FORCEDETH_VERSION		"0.53"
 #define DRV_NAME			"forcedeth"
 #define DRV_NAME			"forcedeth"
 
 
 #include <linux/module.h>
 #include <linux/module.h>
@@ -160,6 +161,7 @@
 #define DEV_HAS_VLAN            0x0020  /* device supports vlan tagging and striping */
 #define DEV_HAS_VLAN            0x0020  /* device supports vlan tagging and striping */
 #define DEV_HAS_MSI             0x0040  /* device supports MSI */
 #define DEV_HAS_MSI             0x0040  /* device supports MSI */
 #define DEV_HAS_MSI_X           0x0080  /* device supports MSI-X */
 #define DEV_HAS_MSI_X           0x0080  /* device supports MSI-X */
+#define DEV_HAS_POWER_CNTRL     0x0100  /* device supports power savings */
 
 
 enum {
 enum {
 	NvRegIrqStatus = 0x000,
 	NvRegIrqStatus = 0x000,
@@ -203,6 +205,8 @@ enum {
 #define NVREG_MISC1_HD		0x02
 #define NVREG_MISC1_HD		0x02
 #define NVREG_MISC1_FORCE	0x3b0f3c
 #define NVREG_MISC1_FORCE	0x3b0f3c
 
 
+	NvRegMacReset = 0x3c,
+#define NVREG_MAC_RESET_ASSERT	0x0F3
 	NvRegTransmitterControl = 0x084,
 	NvRegTransmitterControl = 0x084,
 #define NVREG_XMITCTL_START	0x01
 #define NVREG_XMITCTL_START	0x01
 	NvRegTransmitterStatus = 0x088,
 	NvRegTransmitterStatus = 0x088,
@@ -326,6 +330,10 @@ enum {
 	NvRegMSIXMap0 = 0x3e0,
 	NvRegMSIXMap0 = 0x3e0,
 	NvRegMSIXMap1 = 0x3e4,
 	NvRegMSIXMap1 = 0x3e4,
 	NvRegMSIXIrqStatus = 0x3f0,
 	NvRegMSIXIrqStatus = 0x3f0,
+
+	NvRegPowerState2 = 0x600,
+#define NVREG_POWERSTATE2_POWERUP_MASK		0x0F11
+#define NVREG_POWERSTATE2_POWERUP_REV_A3	0x0001
 };
 };
 
 
 /* Big endian: should work, but is untested */
 /* Big endian: should work, but is untested */
@@ -414,7 +422,8 @@ typedef union _ring_type {
 #define NV_RX3_VLAN_TAG_MASK	(0x0000FFFF)
 #define NV_RX3_VLAN_TAG_MASK	(0x0000FFFF)
 
 
 /* Miscelaneous hardware related defines: */
 /* Miscelaneous hardware related defines: */
-#define NV_PCI_REGSZ		0x270
+#define NV_PCI_REGSZ_VER1      	0x270
+#define NV_PCI_REGSZ_VER2      	0x604
 
 
 /* various timeout delays: all in usec */
 /* various timeout delays: all in usec */
 #define NV_TXRX_RESET_DELAY	4
 #define NV_TXRX_RESET_DELAY	4
@@ -431,6 +440,7 @@ typedef union _ring_type {
 #define NV_MIIBUSY_DELAY	50
 #define NV_MIIBUSY_DELAY	50
 #define NV_MIIPHY_DELAY	10
 #define NV_MIIPHY_DELAY	10
 #define NV_MIIPHY_DELAYMAX	10000
 #define NV_MIIPHY_DELAYMAX	10000
+#define NV_MAC_RESET_DELAY	64
 
 
 #define NV_WAKEUPPATTERNS	5
 #define NV_WAKEUPPATTERNS	5
 #define NV_WAKEUPMASKENTRIES	4
 #define NV_WAKEUPMASKENTRIES	4
@@ -552,6 +562,8 @@ struct fe_priv {
 	u32 desc_ver;
 	u32 desc_ver;
 	u32 txrxctl_bits;
 	u32 txrxctl_bits;
 	u32 vlanctl_bits;
 	u32 vlanctl_bits;
+	u32 driver_data;
+	u32 register_size;
 
 
 	void __iomem *base;
 	void __iomem *base;
 
 
@@ -919,6 +931,24 @@ static void nv_txrx_reset(struct net_device *dev)
 	pci_push(base);
 	pci_push(base);
 }
 }
 
 
+static void nv_mac_reset(struct net_device *dev)
+{
+	struct fe_priv *np = netdev_priv(dev);
+	u8 __iomem *base = get_hwbase(dev);
+
+	dprintk(KERN_DEBUG "%s: nv_mac_reset\n", dev->name);
+	writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET | np->txrxctl_bits, base + NvRegTxRxControl);
+	pci_push(base);
+	writel(NVREG_MAC_RESET_ASSERT, base + NvRegMacReset);
+	pci_push(base);
+	udelay(NV_MAC_RESET_DELAY);
+	writel(0, base + NvRegMacReset);
+	pci_push(base);
+	udelay(NV_MAC_RESET_DELAY);
+	writel(NVREG_TXRXCTL_BIT2 | np->txrxctl_bits, base + NvRegTxRxControl);
+	pci_push(base);
+}
+
 /*
 /*
  * nv_get_stats: dev->get_stats function
  * nv_get_stats: dev->get_stats function
  * Get latest stats value from the nic.
  * Get latest stats value from the nic.
@@ -1331,7 +1361,7 @@ static void nv_tx_timeout(struct net_device *dev)
 				dev->name, (unsigned long)np->ring_addr,
 				dev->name, (unsigned long)np->ring_addr,
 				np->next_tx, np->nic_tx);
 				np->next_tx, np->nic_tx);
 		printk(KERN_INFO "%s: Dumping tx registers\n", dev->name);
 		printk(KERN_INFO "%s: Dumping tx registers\n", dev->name);
-		for (i=0;i<0x400;i+= 32) {
+		for (i=0;i<=np->register_size;i+= 32) {
 			printk(KERN_INFO "%3x: %08x %08x %08x %08x %08x %08x %08x %08x\n",
 			printk(KERN_INFO "%3x: %08x %08x %08x %08x %08x %08x %08x %08x\n",
 					i,
 					i,
 					readl(base + i + 0), readl(base + i + 4),
 					readl(base + i + 0), readl(base + i + 4),
@@ -2488,11 +2518,11 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
 }
 }
 
 
 #define FORCEDETH_REGS_VER	1
 #define FORCEDETH_REGS_VER	1
-#define FORCEDETH_REGS_SIZE	0x400 /* 256 32-bit registers */
 
 
 static int nv_get_regs_len(struct net_device *dev)
 static int nv_get_regs_len(struct net_device *dev)
 {
 {
-	return FORCEDETH_REGS_SIZE;
+	struct fe_priv *np = netdev_priv(dev);
+	return np->register_size;
 }
 }
 
 
 static void nv_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *buf)
 static void nv_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *buf)
@@ -2504,7 +2534,7 @@ static void nv_get_regs(struct net_device *dev, struct ethtool_regs *regs, void
 
 
 	regs->version = FORCEDETH_REGS_VER;
 	regs->version = FORCEDETH_REGS_VER;
 	spin_lock_irq(&np->lock);
 	spin_lock_irq(&np->lock);
-	for (i=0;i<FORCEDETH_REGS_SIZE/sizeof(u32);i++)
+	for (i = 0;i <= np->register_size/sizeof(u32); i++)
 		rbuf[i] = readl(base + i*sizeof(u32));
 		rbuf[i] = readl(base + i*sizeof(u32));
 	spin_unlock_irq(&np->lock);
 	spin_unlock_irq(&np->lock);
 }
 }
@@ -2608,6 +2638,8 @@ static int nv_open(struct net_device *dev)
 	dprintk(KERN_DEBUG "nv_open: begin\n");
 	dprintk(KERN_DEBUG "nv_open: begin\n");
 
 
 	/* 1) erase previous misconfiguration */
 	/* 1) erase previous misconfiguration */
+	if (np->driver_data & DEV_HAS_POWER_CNTRL)
+		nv_mac_reset(dev);
 	/* 4.1-1: stop adapter: ignored, 4.3 seems to be overkill */
 	/* 4.1-1: stop adapter: ignored, 4.3 seems to be overkill */
 	writel(NVREG_MCASTADDRA_FORCE, base + NvRegMulticastAddrA);
 	writel(NVREG_MCASTADDRA_FORCE, base + NvRegMulticastAddrA);
 	writel(0, base + NvRegMulticastAddrB);
 	writel(0, base + NvRegMulticastAddrB);
@@ -2878,6 +2910,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
 	unsigned long addr;
 	unsigned long addr;
 	u8 __iomem *base;
 	u8 __iomem *base;
 	int err, i;
 	int err, i;
+	u32 powerstate;
 
 
 	dev = alloc_etherdev(sizeof(struct fe_priv));
 	dev = alloc_etherdev(sizeof(struct fe_priv));
 	err = -ENOMEM;
 	err = -ENOMEM;
@@ -2910,6 +2943,11 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
 	if (err < 0)
 	if (err < 0)
 		goto out_disable;
 		goto out_disable;
 
 
+	if (id->driver_data & (DEV_HAS_VLAN|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL))
+		np->register_size = NV_PCI_REGSZ_VER2;
+	else
+		np->register_size = NV_PCI_REGSZ_VER1;
+
 	err = -EINVAL;
 	err = -EINVAL;
 	addr = 0;
 	addr = 0;
 	for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
 	for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
@@ -2918,7 +2956,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
 				pci_resource_len(pci_dev, i),
 				pci_resource_len(pci_dev, i),
 				pci_resource_flags(pci_dev, i));
 				pci_resource_flags(pci_dev, i));
 		if (pci_resource_flags(pci_dev, i) & IORESOURCE_MEM &&
 		if (pci_resource_flags(pci_dev, i) & IORESOURCE_MEM &&
-				pci_resource_len(pci_dev, i) >= NV_PCI_REGSZ) {
+				pci_resource_len(pci_dev, i) >= np->register_size) {
 			addr = pci_resource_start(pci_dev, i);
 			addr = pci_resource_start(pci_dev, i);
 			break;
 			break;
 		}
 		}
@@ -2929,6 +2967,9 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
 		goto out_relreg;
 		goto out_relreg;
 	}
 	}
 
 
+	/* copy of driver data */
+	np->driver_data = id->driver_data;
+
 	/* handle different descriptor versions */
 	/* handle different descriptor versions */
 	if (id->driver_data & DEV_HAS_HIGH_DMA) {
 	if (id->driver_data & DEV_HAS_HIGH_DMA) {
 		/* packet format 3: supports 40-bit addressing */
 		/* packet format 3: supports 40-bit addressing */
@@ -2986,7 +3027,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
 	}
 	}
 
 
 	err = -ENOMEM;
 	err = -ENOMEM;
-	np->base = ioremap(addr, NV_PCI_REGSZ);
+	np->base = ioremap(addr, np->register_size);
 	if (!np->base)
 	if (!np->base)
 		goto out_relreg;
 		goto out_relreg;
 	dev->base_addr = (unsigned long)np->base;
 	dev->base_addr = (unsigned long)np->base;
@@ -3062,6 +3103,20 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
 	writel(0, base + NvRegWakeUpFlags);
 	writel(0, base + NvRegWakeUpFlags);
 	np->wolenabled = 0;
 	np->wolenabled = 0;
 
 
+	if (id->driver_data & DEV_HAS_POWER_CNTRL) {
+		u8 revision_id;
+		pci_read_config_byte(pci_dev, PCI_REVISION_ID, &revision_id);
+
+		/* take phy and nic out of low power mode */
+		powerstate = readl(base + NvRegPowerState2);
+		powerstate &= ~NVREG_POWERSTATE2_POWERUP_MASK;
+		if ((id->device == PCI_DEVICE_ID_NVIDIA_NVENET_12 ||
+		     id->device == PCI_DEVICE_ID_NVIDIA_NVENET_13) &&
+		    revision_id >= 0xA3)
+			powerstate |= NVREG_POWERSTATE2_POWERUP_REV_A3;
+		writel(powerstate, base + NvRegPowerState2);
+	}
+
 	if (np->desc_ver == DESC_VER_1) {
 	if (np->desc_ver == DESC_VER_1) {
 		np->tx_flags = NV_TX_VALID;
 		np->tx_flags = NV_TX_VALID;
 	} else {
 	} else {
@@ -3223,19 +3278,19 @@ static struct pci_device_id pci_tbl[] = {
 	},
 	},
 	{	/* MCP51 Ethernet Controller */
 	{	/* MCP51 Ethernet Controller */
 		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_12),
 		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_12),
-		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA,
+		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL,
 	},
 	},
 	{	/* MCP51 Ethernet Controller */
 	{	/* MCP51 Ethernet Controller */
 		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_13),
 		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_13),
-		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA,
+		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL,
 	},
 	},
 	{	/* MCP55 Ethernet Controller */
 	{	/* MCP55 Ethernet Controller */
 		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_14),
 		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_14),
-		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X,
+		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL,
 	},
 	},
 	{	/* MCP55 Ethernet Controller */
 	{	/* MCP55 Ethernet Controller */
 		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_15),
 		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_15),
-		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X,
+		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL,
 	},
 	},
 	{0,},
 	{0,},
 };
 };

+ 41 - 11
drivers/net/sky2.c

@@ -51,7 +51,7 @@
 #include "sky2.h"
 #include "sky2.h"
 
 
 #define DRV_NAME		"sky2"
 #define DRV_NAME		"sky2"
-#define DRV_VERSION		"1.1"
+#define DRV_VERSION		"1.2"
 #define PFX			DRV_NAME " "
 #define PFX			DRV_NAME " "
 
 
 /*
 /*
@@ -925,8 +925,7 @@ static inline struct sk_buff *sky2_alloc_skb(unsigned int size, gfp_t gfp_mask)
 	skb = alloc_skb(size + RX_SKB_ALIGN, gfp_mask);
 	skb = alloc_skb(size + RX_SKB_ALIGN, gfp_mask);
 	if (likely(skb)) {
 	if (likely(skb)) {
 		unsigned long p	= (unsigned long) skb->data;
 		unsigned long p	= (unsigned long) skb->data;
-		skb_reserve(skb,
-			((p + RX_SKB_ALIGN - 1) & ~(RX_SKB_ALIGN - 1)) - p);
+		skb_reserve(skb, ALIGN(p, RX_SKB_ALIGN) - p);
 	}
 	}
 
 
 	return skb;
 	return skb;
@@ -1686,13 +1685,12 @@ static void sky2_tx_timeout(struct net_device *dev)
 }
 }
 
 
 
 
-#define roundup(x, y)   ((((x)+((y)-1))/(y))*(y))
 /* Want receive buffer size to be multiple of 64 bits
 /* Want receive buffer size to be multiple of 64 bits
  * and incl room for vlan and truncation
  * and incl room for vlan and truncation
  */
  */
 static inline unsigned sky2_buf_size(int mtu)
 static inline unsigned sky2_buf_size(int mtu)
 {
 {
-	return roundup(mtu + ETH_HLEN + VLAN_HLEN, 8) + 8;
+	return ALIGN(mtu + ETH_HLEN + VLAN_HLEN, 8) + 8;
 }
 }
 
 
 static int sky2_change_mtu(struct net_device *dev, int new_mtu)
 static int sky2_change_mtu(struct net_device *dev, int new_mtu)
@@ -2086,6 +2084,20 @@ static void sky2_descriptor_error(struct sky2_hw *hw, unsigned port,
 	}
 	}
 }
 }
 
 
+/* If idle then force a fake soft NAPI poll once a second
+ * to work around cases where sharing an edge triggered interrupt.
+ */
+static void sky2_idle(unsigned long arg)
+{
+	struct net_device *dev = (struct net_device *) arg;
+
+	local_irq_disable();
+	if (__netif_rx_schedule_prep(dev))
+		__netif_rx_schedule(dev);
+	local_irq_enable();
+}
+
+
 static int sky2_poll(struct net_device *dev0, int *budget)
 static int sky2_poll(struct net_device *dev0, int *budget)
 {
 {
 	struct sky2_hw *hw = ((struct sky2_port *) netdev_priv(dev0))->hw;
 	struct sky2_hw *hw = ((struct sky2_port *) netdev_priv(dev0))->hw;
@@ -2093,6 +2105,7 @@ static int sky2_poll(struct net_device *dev0, int *budget)
 	int work_done = 0;
 	int work_done = 0;
 	u32 status = sky2_read32(hw, B0_Y2_SP_EISR);
 	u32 status = sky2_read32(hw, B0_Y2_SP_EISR);
 
 
+ restart_poll:
 	if (unlikely(status & ~Y2_IS_STAT_BMU)) {
 	if (unlikely(status & ~Y2_IS_STAT_BMU)) {
 		if (status & Y2_IS_HW_ERR)
 		if (status & Y2_IS_HW_ERR)
 			sky2_hw_intr(hw);
 			sky2_hw_intr(hw);
@@ -2123,7 +2136,7 @@ static int sky2_poll(struct net_device *dev0, int *budget)
 	}
 	}
 
 
 	if (status & Y2_IS_STAT_BMU) {
 	if (status & Y2_IS_STAT_BMU) {
-		work_done = sky2_status_intr(hw, work_limit);
+		work_done += sky2_status_intr(hw, work_limit - work_done);
 		*budget -= work_done;
 		*budget -= work_done;
 		dev0->quota -= work_done;
 		dev0->quota -= work_done;
 
 
@@ -2133,9 +2146,24 @@ static int sky2_poll(struct net_device *dev0, int *budget)
 		sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ);
 		sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ);
 	}
 	}
 
 
-	netif_rx_complete(dev0);
+	mod_timer(&hw->idle_timer, jiffies + HZ);
+
+	local_irq_disable();
+	__netif_rx_complete(dev0);
 
 
 	status = sky2_read32(hw, B0_Y2_SP_LISR);
 	status = sky2_read32(hw, B0_Y2_SP_LISR);
+
+	if (unlikely(status)) {
+		/* More work pending, try and keep going */
+		if (__netif_rx_schedule_prep(dev0)) {
+			__netif_rx_reschedule(dev0, work_done);
+			status = sky2_read32(hw, B0_Y2_SP_EISR);
+			local_irq_enable();
+			goto restart_poll;
+		}
+	}
+
+	local_irq_enable();
 	return 0;
 	return 0;
 }
 }
 
 
@@ -2153,8 +2181,6 @@ static irqreturn_t sky2_intr(int irq, void *dev_id, struct pt_regs *regs)
 	prefetch(&hw->st_le[hw->st_idx]);
 	prefetch(&hw->st_le[hw->st_idx]);
 	if (likely(__netif_rx_schedule_prep(dev0)))
 	if (likely(__netif_rx_schedule_prep(dev0)))
 		__netif_rx_schedule(dev0);
 		__netif_rx_schedule(dev0);
-	else
-		printk(KERN_DEBUG PFX "irq race detected\n");
 
 
 	return IRQ_HANDLED;
 	return IRQ_HANDLED;
 }
 }
@@ -2193,7 +2219,7 @@ static inline u32 sky2_clk2us(const struct sky2_hw *hw, u32 clk)
 }
 }
 
 
 
 
-static int sky2_reset(struct sky2_hw *hw)
+static int __devinit sky2_reset(struct sky2_hw *hw)
 {
 {
 	u16 status;
 	u16 status;
 	u8 t8, pmd_type;
 	u8 t8, pmd_type;
@@ -3276,6 +3302,8 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
 
 
 	sky2_write32(hw, B0_IMSK, Y2_IS_BASE);
 	sky2_write32(hw, B0_IMSK, Y2_IS_BASE);
 
 
+	setup_timer(&hw->idle_timer, sky2_idle, (unsigned long) dev);
+
 	pci_set_drvdata(pdev, hw);
 	pci_set_drvdata(pdev, hw);
 
 
 	return 0;
 	return 0;
@@ -3311,13 +3339,15 @@ static void __devexit sky2_remove(struct pci_dev *pdev)
 	if (!hw)
 	if (!hw)
 		return;
 		return;
 
 
+	del_timer_sync(&hw->idle_timer);
+
+	sky2_write32(hw, B0_IMSK, 0);
 	dev0 = hw->dev[0];
 	dev0 = hw->dev[0];
 	dev1 = hw->dev[1];
 	dev1 = hw->dev[1];
 	if (dev1)
 	if (dev1)
 		unregister_netdev(dev1);
 		unregister_netdev(dev1);
 	unregister_netdev(dev0);
 	unregister_netdev(dev0);
 
 
-	sky2_write32(hw, B0_IMSK, 0);
 	sky2_set_power_state(hw, PCI_D3hot);
 	sky2_set_power_state(hw, PCI_D3hot);
 	sky2_write16(hw, B0_Y2LED, LED_STAT_OFF);
 	sky2_write16(hw, B0_Y2LED, LED_STAT_OFF);
 	sky2_write8(hw, B0_CTST, CS_RST_SET);
 	sky2_write8(hw, B0_CTST, CS_RST_SET);

+ 2 - 0
drivers/net/sky2.h

@@ -1880,6 +1880,8 @@ struct sky2_hw {
 	struct sky2_status_le *st_le;
 	struct sky2_status_le *st_le;
 	u32		     st_idx;
 	u32		     st_idx;
 	dma_addr_t   	     st_dma;
 	dma_addr_t   	     st_dma;
+
+	struct timer_list    idle_timer;
 	int		     msi_detected;
 	int		     msi_detected;
 	wait_queue_head_t    msi_wait;
 	wait_queue_head_t    msi_wait;
 };
 };

+ 10 - 8
include/linux/netdevice.h

@@ -829,19 +829,21 @@ static inline void netif_rx_schedule(struct net_device *dev)
 		__netif_rx_schedule(dev);
 		__netif_rx_schedule(dev);
 }
 }
 
 
-/* Try to reschedule poll. Called by dev->poll() after netif_rx_complete().
- * Do not inline this?
- */
+
+static inline void  __netif_rx_reschedule(struct net_device *dev, int undo)
+{
+	dev->quota += undo;
+	list_add_tail(&dev->poll_list, &__get_cpu_var(softnet_data).poll_list);
+	__raise_softirq_irqoff(NET_RX_SOFTIRQ);
+}
+
+/* Try to reschedule poll. Called by dev->poll() after netif_rx_complete(). */
 static inline int netif_rx_reschedule(struct net_device *dev, int undo)
 static inline int netif_rx_reschedule(struct net_device *dev, int undo)
 {
 {
 	if (netif_rx_schedule_prep(dev)) {
 	if (netif_rx_schedule_prep(dev)) {
 		unsigned long flags;
 		unsigned long flags;
-
-		dev->quota += undo;
-
 		local_irq_save(flags);
 		local_irq_save(flags);
-		list_add_tail(&dev->poll_list, &__get_cpu_var(softnet_data).poll_list);
-		__raise_softirq_irqoff(NET_RX_SOFTIRQ);
+		__netif_rx_reschedule(dev, undo);
 		local_irq_restore(flags);
 		local_irq_restore(flags);
 		return 1;
 		return 1;
 	}
 	}