diff options
| author | Ayaz Abdulla <aabdulla@nvidia.com> | 2006-05-20 14:59:48 -0700 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-05-21 12:59:16 -0700 | 
| commit | 84b3932bf0fd8cdc8c75a5be77e1dded1e6479c6 (patch) | |
| tree | 731b287b0635ef97c1621c49d0be555d6f351bbe | |
| parent | 6566a3f8f3281497a81815dfe2b64eb54dafe05d (diff) | |
[PATCH] forcedeth: fix multi irq issues
With Manfred Spraul <manfred@colorfullife.com> and
     Andrew Morton <akpm@osdl.org>
Bring back this recently-reverted patch, only fixed.
Original changelog:
    From: Ayaz Abdulla <aabdulla@nvidia.com>
    This patch fixes the issues with multiple irqs.
    I am resending based on feedback. I decoupled the dma mask for
    consistent memory and fixed leak with multiple irq in error path.
    Thanks to Manfred for catching the spin lock problem.
Fix it:
    From: Manfred Spraul <manfred@colorfullife.com>
    Fix bug introduced by ebf34c9b6fcd22338ef764b039b3ac55ed0e297b, covered in
    http://bugzilla.kernel.org/show_bug.cgi?id=6568.
    Remove second instance of the request_irq() calls: they were moved
    from nv_open into nv_request_irq.
    Thanks to Alistair Strachan <alistair@devzero.co.uk> for reporting and
    persisting.
Signed-off-by: Ayaz Abdulla <aabdulla@nvidia.com>
Signed-off-by: Manfred Spraul <manfred@colorfullife.com>
Cc: Jeff Garzik <jeff@garzik.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
| -rw-r--r-- | drivers/net/forcedeth.c | 380 | 
1 files changed, 226 insertions, 154 deletions
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 7e078b4cca7c..705e1229d89d 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -106,6 +106,7 @@   *	0.51: 20 Jan 2006: Add 64bit consistent memory allocation for rings.   *	0.52: 20 Jan 2006: Add MSI/MSIX support.   *	0.53: 19 Mar 2006: Fix init from low power mode and add hw reset. + *	0.54: 21 Mar 2006: Fix spin locks for multi irqs and cleanup.   *   * Known bugs:   * We suspect that on some hardware no TX done interrupts are generated. @@ -117,7 +118,7 @@   * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few   * superfluous timer interrupts from the nic.   */ -#define FORCEDETH_VERSION		"0.53" +#define FORCEDETH_VERSION		"0.54"  #define DRV_NAME			"forcedeth"  #include <linux/module.h> @@ -710,6 +711,72 @@ static void setup_hw_rings(struct net_device *dev, int rxtx_flags)  	}  } +static int using_multi_irqs(struct net_device *dev) +{ +	struct fe_priv *np = get_nvpriv(dev); + +	if (!(np->msi_flags & NV_MSI_X_ENABLED) || +	    ((np->msi_flags & NV_MSI_X_ENABLED) && +	     ((np->msi_flags & NV_MSI_X_VECTORS_MASK) == 0x1))) +		return 0; +	else +		return 1; +} + +static void nv_enable_irq(struct net_device *dev) +{ +	struct fe_priv *np = get_nvpriv(dev); + +	if (!using_multi_irqs(dev)) { +		if (np->msi_flags & NV_MSI_X_ENABLED) +			enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector); +		else +			enable_irq(dev->irq); +	} else { +		enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector); +		enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector); +		enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector); +	} +} + +static void nv_disable_irq(struct net_device *dev) +{ +	struct fe_priv *np = get_nvpriv(dev); + +	if (!using_multi_irqs(dev)) { +		if (np->msi_flags & NV_MSI_X_ENABLED) +			disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector); +		else +			disable_irq(dev->irq); +	} else { +		disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector); +		disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector); +		disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector); +	} +} + +/* In MSIX mode, a write to irqmask behaves as XOR */ +static void nv_enable_hw_interrupts(struct net_device *dev, u32 mask) +{ +	u8 __iomem *base = get_hwbase(dev); + +	writel(mask, base + NvRegIrqMask); +} + +static void nv_disable_hw_interrupts(struct net_device *dev, u32 mask) +{ +	struct fe_priv *np = get_nvpriv(dev); +	u8 __iomem *base = get_hwbase(dev); + +	if (np->msi_flags & NV_MSI_X_ENABLED) { +		writel(mask, base + NvRegIrqMask); +	} else { +		if (np->msi_flags & NV_MSI_ENABLED) +			writel(0, base + NvRegMSIIrqMask); +		writel(0, base + NvRegIrqMask); +	} +} +  #define MII_READ	(-1)  /* mii_rw: read/write a register on the PHY.   * @@ -1019,24 +1086,25 @@ static void nv_do_rx_refill(unsigned long data)  	struct net_device *dev = (struct net_device *) data;  	struct fe_priv *np = netdev_priv(dev); - -	if (!(np->msi_flags & NV_MSI_X_ENABLED) || -	    ((np->msi_flags & NV_MSI_X_ENABLED) && -	     ((np->msi_flags & NV_MSI_X_VECTORS_MASK) == 0x1))) { -		disable_irq(dev->irq); +	if (!using_multi_irqs(dev)) { +		if (np->msi_flags & NV_MSI_X_ENABLED) +			disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector); +		else +			disable_irq(dev->irq);  	} else {  		disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector);  	}  	if (nv_alloc_rx(dev)) { -		spin_lock(&np->lock); +		spin_lock_irq(&np->lock);  		if (!np->in_shutdown)  			mod_timer(&np->oom_kick, jiffies + OOM_REFILL); -		spin_unlock(&np->lock); +		spin_unlock_irq(&np->lock);  	} -	if (!(np->msi_flags & NV_MSI_X_ENABLED) || -	    ((np->msi_flags & NV_MSI_X_ENABLED) && -	     ((np->msi_flags & NV_MSI_X_VECTORS_MASK) == 0x1))) { -		enable_irq(dev->irq); +	if (!using_multi_irqs(dev)) { +		if (np->msi_flags & NV_MSI_X_ENABLED) +			enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector); +		else +			enable_irq(dev->irq);  	} else {  		enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector);  	} @@ -1668,15 +1736,7 @@ static int nv_change_mtu(struct net_device *dev, int new_mtu)  		 * guessed, there is probably a simpler approach.  		 * Changing the MTU is a rare event, it shouldn't matter.  		 */ -		if (!(np->msi_flags & NV_MSI_X_ENABLED) || -		    ((np->msi_flags & NV_MSI_X_ENABLED) && -		     ((np->msi_flags & NV_MSI_X_VECTORS_MASK) == 0x1))) { -			disable_irq(dev->irq); -		} else { -			disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector); -			disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector); -			disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector); -		} +		nv_disable_irq(dev);  		spin_lock_bh(&dev->xmit_lock);  		spin_lock(&np->lock);  		/* stop engines */ @@ -1709,15 +1769,7 @@ static int nv_change_mtu(struct net_device *dev, int new_mtu)  		nv_start_tx(dev);  		spin_unlock(&np->lock);  		spin_unlock_bh(&dev->xmit_lock); -		if (!(np->msi_flags & NV_MSI_X_ENABLED) || -		    ((np->msi_flags & NV_MSI_X_ENABLED) && -		     ((np->msi_flags & NV_MSI_X_VECTORS_MASK) == 0x1))) { -			enable_irq(dev->irq); -		} else { -			enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector); -			enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector); -			enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector); -		} +		nv_enable_irq(dev);  	}  	return 0;  } @@ -2108,16 +2160,16 @@ static irqreturn_t nv_nic_irq_tx(int foo, void *data, struct pt_regs *regs)  		if (!(events & np->irqmask))  			break; -		spin_lock(&np->lock); +		spin_lock_irq(&np->lock);  		nv_tx_done(dev); -		spin_unlock(&np->lock); +		spin_unlock_irq(&np->lock);  		if (events & (NVREG_IRQ_TX_ERR)) {  			dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n",  						dev->name, events);  		}  		if (i > max_interrupt_work) { -			spin_lock(&np->lock); +			spin_lock_irq(&np->lock);  			/* disable interrupts on the nic */  			writel(NVREG_IRQ_TX_ALL, base + NvRegIrqMask);  			pci_push(base); @@ -2127,7 +2179,7 @@ static irqreturn_t nv_nic_irq_tx(int foo, void *data, struct pt_regs *regs)  				mod_timer(&np->nic_poll, jiffies + POLL_WAIT);  			}  			printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq_tx.\n", dev->name, i); -			spin_unlock(&np->lock); +			spin_unlock_irq(&np->lock);  			break;  		} @@ -2157,14 +2209,14 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data, struct pt_regs *regs)  		nv_rx_process(dev);  		if (nv_alloc_rx(dev)) { -			spin_lock(&np->lock); +			spin_lock_irq(&np->lock);  			if (!np->in_shutdown)  				mod_timer(&np->oom_kick, jiffies + OOM_REFILL); -			spin_unlock(&np->lock); +			spin_unlock_irq(&np->lock);  		}  		if (i > max_interrupt_work) { -			spin_lock(&np->lock); +			spin_lock_irq(&np->lock);  			/* disable interrupts on the nic */  			writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);  			pci_push(base); @@ -2174,7 +2226,7 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data, struct pt_regs *regs)  				mod_timer(&np->nic_poll, jiffies + POLL_WAIT);  			}  			printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq_rx.\n", dev->name, i); -			spin_unlock(&np->lock); +			spin_unlock_irq(&np->lock);  			break;  		} @@ -2203,14 +2255,14 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data, struct pt_regs *regs)  			break;  		if (events & NVREG_IRQ_LINK) { -			spin_lock(&np->lock); +			spin_lock_irq(&np->lock);  			nv_link_irq(dev); -			spin_unlock(&np->lock); +			spin_unlock_irq(&np->lock);  		}  		if (np->need_linktimer && time_after(jiffies, np->link_timeout)) { -			spin_lock(&np->lock); +			spin_lock_irq(&np->lock);  			nv_linkchange(dev); -			spin_unlock(&np->lock); +			spin_unlock_irq(&np->lock);  			np->link_timeout = jiffies + LINK_TIMEOUT;  		}  		if (events & (NVREG_IRQ_UNKNOWN)) { @@ -2218,7 +2270,7 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data, struct pt_regs *regs)  						dev->name, events);  		}  		if (i > max_interrupt_work) { -			spin_lock(&np->lock); +			spin_lock_irq(&np->lock);  			/* disable interrupts on the nic */  			writel(NVREG_IRQ_OTHER, base + NvRegIrqMask);  			pci_push(base); @@ -2228,7 +2280,7 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data, struct pt_regs *regs)  				mod_timer(&np->nic_poll, jiffies + POLL_WAIT);  			}  			printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq_other.\n", dev->name, i); -			spin_unlock(&np->lock); +			spin_unlock_irq(&np->lock);  			break;  		} @@ -2251,10 +2303,11 @@ static void nv_do_nic_poll(unsigned long data)  	 * nv_nic_irq because that may decide to do otherwise  	 */ -	if (!(np->msi_flags & NV_MSI_X_ENABLED) || -	    ((np->msi_flags & NV_MSI_X_ENABLED) && -	     ((np->msi_flags & NV_MSI_X_VECTORS_MASK) == 0x1))) { -		disable_irq(dev->irq); +	if (!using_multi_irqs(dev)) { +		if (np->msi_flags & NV_MSI_X_ENABLED) +			disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector); +		else +			disable_irq(dev->irq);  		mask = np->irqmask;  	} else {  		if (np->nic_poll_irq & NVREG_IRQ_RX_ALL) { @@ -2277,11 +2330,12 @@ static void nv_do_nic_poll(unsigned long data)  	writel(mask, base + NvRegIrqMask);  	pci_push(base); -	if (!(np->msi_flags & NV_MSI_X_ENABLED) || -	    ((np->msi_flags & NV_MSI_X_ENABLED) && -	     ((np->msi_flags & NV_MSI_X_VECTORS_MASK) == 0x1))) { +	if (!using_multi_irqs(dev)) {  		nv_nic_irq((int) 0, (void *) data, (struct pt_regs *) NULL); -		enable_irq(dev->irq); +		if (np->msi_flags & NV_MSI_X_ENABLED) +			enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector); +		else +			enable_irq(dev->irq);  	} else {  		if (np->nic_poll_irq & NVREG_IRQ_RX_ALL) {  			nv_nic_irq_rx((int) 0, (void *) data, (struct pt_regs *) NULL); @@ -2628,6 +2682,113 @@ static void set_msix_vector_map(struct net_device *dev, u32 vector, u32 irqmask)  	writel(readl(base + NvRegMSIXMap1) | msixmap, base + NvRegMSIXMap1);  } +static int nv_request_irq(struct net_device *dev) +{ +	struct fe_priv *np = get_nvpriv(dev); +	u8 __iomem *base = get_hwbase(dev); +	int ret = 1; +	int i; + +	if (np->msi_flags & NV_MSI_X_CAPABLE) { +		for (i = 0; i < (np->msi_flags & NV_MSI_X_VECTORS_MASK); i++) { +			np->msi_x_entry[i].entry = i; +		} +		if ((ret = pci_enable_msix(np->pci_dev, np->msi_x_entry, (np->msi_flags & NV_MSI_X_VECTORS_MASK))) == 0) { +			np->msi_flags |= NV_MSI_X_ENABLED; +			if (optimization_mode == NV_OPTIMIZATION_MODE_THROUGHPUT) { +				/* Request irq for rx handling */ +				if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector, &nv_nic_irq_rx, SA_SHIRQ, dev->name, dev) != 0) { +					printk(KERN_INFO "forcedeth: request_irq failed for rx %d\n", ret); +					pci_disable_msix(np->pci_dev); +					np->msi_flags &= ~NV_MSI_X_ENABLED; +					goto out_err; +				} +				/* Request irq for tx handling */ +				if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector, &nv_nic_irq_tx, SA_SHIRQ, dev->name, dev) != 0) { +					printk(KERN_INFO "forcedeth: request_irq failed for tx %d\n", ret); +					pci_disable_msix(np->pci_dev); +					np->msi_flags &= ~NV_MSI_X_ENABLED; +					goto out_free_rx; +				} +				/* Request irq for link and timer handling */ +				if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector, &nv_nic_irq_other, SA_SHIRQ, dev->name, dev) != 0) { +					printk(KERN_INFO "forcedeth: request_irq failed for link %d\n", ret); +					pci_disable_msix(np->pci_dev); +					np->msi_flags &= ~NV_MSI_X_ENABLED; +					goto out_free_tx; +				} +				/* map interrupts to their respective vector */ +				writel(0, base + NvRegMSIXMap0); +				writel(0, base + NvRegMSIXMap1); +				set_msix_vector_map(dev, NV_MSI_X_VECTOR_RX, NVREG_IRQ_RX_ALL); +				set_msix_vector_map(dev, NV_MSI_X_VECTOR_TX, NVREG_IRQ_TX_ALL); +				set_msix_vector_map(dev, NV_MSI_X_VECTOR_OTHER, NVREG_IRQ_OTHER); +			} else { +				/* Request irq for all interrupts */ +				if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector, &nv_nic_irq, SA_SHIRQ, dev->name, dev) != 0) { +					printk(KERN_INFO "forcedeth: request_irq failed %d\n", ret); +					pci_disable_msix(np->pci_dev); +					np->msi_flags &= ~NV_MSI_X_ENABLED; +					goto out_err; +				} + +				/* map interrupts to vector 0 */ +				writel(0, base + NvRegMSIXMap0); +				writel(0, base + NvRegMSIXMap1); +			} +		} +	} +	if (ret != 0 && np->msi_flags & NV_MSI_CAPABLE) { +		if ((ret = pci_enable_msi(np->pci_dev)) == 0) { +			np->msi_flags |= NV_MSI_ENABLED; +			if (request_irq(np->pci_dev->irq, &nv_nic_irq, SA_SHIRQ, dev->name, dev) != 0) { +				printk(KERN_INFO "forcedeth: request_irq failed %d\n", ret); +				pci_disable_msi(np->pci_dev); +				np->msi_flags &= ~NV_MSI_ENABLED; +				goto out_err; +			} + +			/* map interrupts to vector 0 */ +			writel(0, base + NvRegMSIMap0); +			writel(0, base + NvRegMSIMap1); +			/* enable msi vector 0 */ +			writel(NVREG_MSI_VECTOR_0_ENABLED, base + NvRegMSIIrqMask); +		} +	} +	if (ret != 0) { +		if (request_irq(np->pci_dev->irq, &nv_nic_irq, SA_SHIRQ, dev->name, dev) != 0) +			goto out_err; +	} + +	return 0; +out_free_tx: +	free_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector, dev); +out_free_rx: +	free_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector, dev); +out_err: +	return 1; +} + +static void nv_free_irq(struct net_device *dev) +{ +	struct fe_priv *np = get_nvpriv(dev); +	int i; + +	if (np->msi_flags & NV_MSI_X_ENABLED) { +		for (i = 0; i < (np->msi_flags & NV_MSI_X_VECTORS_MASK); i++) { +			free_irq(np->msi_x_entry[i].vector, dev); +		} +		pci_disable_msix(np->pci_dev); +		np->msi_flags &= ~NV_MSI_X_ENABLED; +	} else { +		free_irq(np->pci_dev->irq, dev); +		if (np->msi_flags & NV_MSI_ENABLED) { +			pci_disable_msi(np->pci_dev); +			np->msi_flags &= ~NV_MSI_ENABLED; +		} +	} +} +  static int nv_open(struct net_device *dev)  {  	struct fe_priv *np = netdev_priv(dev); @@ -2720,86 +2881,18 @@ static int nv_open(struct net_device *dev)  	udelay(10);  	writel(readl(base + NvRegPowerState) | NVREG_POWERSTATE_VALID, base + NvRegPowerState); -	writel(0, base + NvRegIrqMask); +	nv_disable_hw_interrupts(dev, np->irqmask);  	pci_push(base);  	writel(NVREG_MIISTAT_MASK2, base + NvRegMIIStatus);  	writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);  	pci_push(base); -	if (np->msi_flags & NV_MSI_X_CAPABLE) { -		for (i = 0; i < (np->msi_flags & NV_MSI_X_VECTORS_MASK); i++) { -			np->msi_x_entry[i].entry = i; -		} -		if ((ret = pci_enable_msix(np->pci_dev, np->msi_x_entry, (np->msi_flags & NV_MSI_X_VECTORS_MASK))) == 0) { -			np->msi_flags |= NV_MSI_X_ENABLED; -			if (optimization_mode == NV_OPTIMIZATION_MODE_THROUGHPUT) { -				/* Request irq for rx handling */ -				if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector, &nv_nic_irq_rx, SA_SHIRQ, dev->name, dev) != 0) { -					printk(KERN_INFO "forcedeth: request_irq failed for rx %d\n", ret); -					pci_disable_msix(np->pci_dev); -					np->msi_flags &= ~NV_MSI_X_ENABLED; -					goto out_drain; -				} -				/* Request irq for tx handling */ -				if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector, &nv_nic_irq_tx, SA_SHIRQ, dev->name, dev) != 0) { -					printk(KERN_INFO "forcedeth: request_irq failed for tx %d\n", ret); -					pci_disable_msix(np->pci_dev); -					np->msi_flags &= ~NV_MSI_X_ENABLED; -					goto out_drain; -				} -				/* Request irq for link and timer handling */ -				if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector, &nv_nic_irq_other, SA_SHIRQ, dev->name, dev) != 0) { -					printk(KERN_INFO "forcedeth: request_irq failed for link %d\n", ret); -					pci_disable_msix(np->pci_dev); -					np->msi_flags &= ~NV_MSI_X_ENABLED; -					goto out_drain; -				} - -				/* map interrupts to their respective vector */ -				writel(0, base + NvRegMSIXMap0); -				writel(0, base + NvRegMSIXMap1); -				set_msix_vector_map(dev, NV_MSI_X_VECTOR_RX, NVREG_IRQ_RX_ALL); -				set_msix_vector_map(dev, NV_MSI_X_VECTOR_TX, NVREG_IRQ_TX_ALL); -				set_msix_vector_map(dev, NV_MSI_X_VECTOR_OTHER, NVREG_IRQ_OTHER); -			} else { -				/* Request irq for all interrupts */ -				if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector, &nv_nic_irq, SA_SHIRQ, dev->name, dev) != 0) { -					printk(KERN_INFO "forcedeth: request_irq failed %d\n", ret); -					pci_disable_msix(np->pci_dev); -					np->msi_flags &= ~NV_MSI_X_ENABLED; -					goto out_drain; -				} - -				/* map interrupts to vector 0 */ -				writel(0, base + NvRegMSIXMap0); -				writel(0, base + NvRegMSIXMap1); -			} -		} -	} -	if (ret != 0 && np->msi_flags & NV_MSI_CAPABLE) { -		if ((ret = pci_enable_msi(np->pci_dev)) == 0) { -			np->msi_flags |= NV_MSI_ENABLED; -			if (request_irq(np->pci_dev->irq, &nv_nic_irq, SA_SHIRQ, dev->name, dev) != 0) { -				printk(KERN_INFO "forcedeth: request_irq failed %d\n", ret); -				pci_disable_msi(np->pci_dev); -				np->msi_flags &= ~NV_MSI_ENABLED; -				goto out_drain; -			} - -			/* map interrupts to vector 0 */ -			writel(0, base + NvRegMSIMap0); -			writel(0, base + NvRegMSIMap1); -			/* enable msi vector 0 */ -			writel(NVREG_MSI_VECTOR_0_ENABLED, base + NvRegMSIIrqMask); -		} -	} -	if (ret != 0) { -		if (request_irq(np->pci_dev->irq, &nv_nic_irq, SA_SHIRQ, dev->name, dev) != 0) -			goto out_drain; +	if (nv_request_irq(dev)) { +		goto out_drain;  	}  	/* ask for interrupts */ -	writel(np->irqmask, base + NvRegIrqMask); +	nv_enable_hw_interrupts(dev, np->irqmask);  	spin_lock_irq(&np->lock);  	writel(NVREG_MCASTADDRA_FORCE, base + NvRegMulticastAddrA); @@ -2843,7 +2936,6 @@ static int nv_close(struct net_device *dev)  {  	struct fe_priv *np = netdev_priv(dev);  	u8 __iomem *base; -	int i;  	spin_lock_irq(&np->lock);  	np->in_shutdown = 1; @@ -2861,31 +2953,13 @@ static int nv_close(struct net_device *dev)  	/* disable interrupts on the nic or we will lock up */  	base = get_hwbase(dev); -	if (np->msi_flags & NV_MSI_X_ENABLED) { -		writel(np->irqmask, base + NvRegIrqMask); -	} else { -		if (np->msi_flags & NV_MSI_ENABLED) -			writel(0, base + NvRegMSIIrqMask); -		writel(0, base + NvRegIrqMask); -	} +	nv_disable_hw_interrupts(dev, np->irqmask);  	pci_push(base);  	dprintk(KERN_INFO "%s: Irqmask is zero again\n", dev->name);  	spin_unlock_irq(&np->lock); -	if (np->msi_flags & NV_MSI_X_ENABLED) { -		for (i = 0; i < (np->msi_flags & NV_MSI_X_VECTORS_MASK); i++) { -			free_irq(np->msi_x_entry[i].vector, dev); -		} -		pci_disable_msix(np->pci_dev); -		np->msi_flags &= ~NV_MSI_X_ENABLED; -	} else { -		free_irq(np->pci_dev->irq, dev); -		if (np->msi_flags & NV_MSI_ENABLED) { -			pci_disable_msi(np->pci_dev); -			np->msi_flags &= ~NV_MSI_ENABLED; -		} -	} +	nv_free_irq(dev);  	drain_ring(dev); @@ -2974,20 +3048,18 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i  	if (id->driver_data & DEV_HAS_HIGH_DMA) {  		/* packet format 3: supports 40-bit addressing */  		np->desc_ver = DESC_VER_3; +		np->txrxctl_bits = NVREG_TXRXCTL_DESC_3;  		if (pci_set_dma_mask(pci_dev, DMA_39BIT_MASK)) {  			printk(KERN_INFO "forcedeth: 64-bit DMA failed, using 32-bit addressing for device %s.\n",  					pci_name(pci_dev));  		} else { -			if (pci_set_consistent_dma_mask(pci_dev, 0x0000007fffffffffULL)) { -				printk(KERN_INFO "forcedeth: 64-bit DMA (consistent) failed for device %s.\n", -					pci_name(pci_dev)); -				goto out_relreg; -			} else { -				dev->features |= NETIF_F_HIGHDMA; -				printk(KERN_INFO "forcedeth: using HIGHDMA\n"); -			} +			dev->features |= NETIF_F_HIGHDMA; +			printk(KERN_INFO "forcedeth: using HIGHDMA\n"); +		} +		if (pci_set_consistent_dma_mask(pci_dev, 0x0000007fffffffffULL)) { +			printk(KERN_INFO "forcedeth: 64-bit DMA (consistent) failed for device %s.\n", +			       pci_name(pci_dev));  		} -		np->txrxctl_bits = NVREG_TXRXCTL_DESC_3;  	} else if (id->driver_data & DEV_HAS_LARGEDESC) {  		/* packet format 2: supports jumbo frames */  		np->desc_ver = DESC_VER_2;  | 
