|
@@ -1712,7 +1712,7 @@ static void init_registers(struct net_device *dev)
|
|
|
|
|
|
/* Enable interrupts by setting the interrupt mask. */
|
|
|
writel(DEFAULT_INTR, ioaddr + IntrMask);
|
|
|
- writel(1, ioaddr + IntrEnable);
|
|
|
+ natsemi_irq_enable(dev);
|
|
|
|
|
|
writel(RxOn | TxOn, ioaddr + ChipCmd);
|
|
|
writel(StatsClear, ioaddr + StatsCtrl); /* Clear Stats */
|
|
@@ -2119,28 +2119,35 @@ static irqreturn_t intr_handler(int irq, void *dev_instance)
|
|
|
struct netdev_private *np = netdev_priv(dev);
|
|
|
void __iomem * ioaddr = ns_ioaddr(dev);
|
|
|
|
|
|
- if (np->hands_off)
|
|
|
+ /* Reading IntrStatus automatically acknowledges so don't do
|
|
|
+ * that while interrupts are disabled, (for example, while a
|
|
|
+ * poll is scheduled). */
|
|
|
+ if (np->hands_off || !readl(ioaddr + IntrEnable))
|
|
|
return IRQ_NONE;
|
|
|
|
|
|
- /* Reading automatically acknowledges. */
|
|
|
np->intr_status = readl(ioaddr + IntrStatus);
|
|
|
|
|
|
+ if (!np->intr_status)
|
|
|
+ return IRQ_NONE;
|
|
|
+
|
|
|
if (netif_msg_intr(np))
|
|
|
printk(KERN_DEBUG
|
|
|
"%s: Interrupt, status %#08x, mask %#08x.\n",
|
|
|
dev->name, np->intr_status,
|
|
|
readl(ioaddr + IntrMask));
|
|
|
|
|
|
- if (!np->intr_status)
|
|
|
- return IRQ_NONE;
|
|
|
-
|
|
|
prefetch(&np->rx_skbuff[np->cur_rx % RX_RING_SIZE]);
|
|
|
|
|
|
if (netif_rx_schedule_prep(dev)) {
|
|
|
/* Disable interrupts and register for poll */
|
|
|
natsemi_irq_disable(dev);
|
|
|
__netif_rx_schedule(dev);
|
|
|
- }
|
|
|
+ } else
|
|
|
+ printk(KERN_WARNING
|
|
|
+ "%s: Ignoring interrupt, status %#08x, mask %#08x.\n",
|
|
|
+ dev->name, np->intr_status,
|
|
|
+ readl(ioaddr + IntrMask));
|
|
|
+
|
|
|
return IRQ_HANDLED;
|
|
|
}
|
|
|
|
|
@@ -2156,6 +2163,20 @@ static int natsemi_poll(struct net_device *dev, int *budget)
|
|
|
int work_done = 0;
|
|
|
|
|
|
do {
|
|
|
+ if (netif_msg_intr(np))
|
|
|
+ printk(KERN_DEBUG
|
|
|
+ "%s: Poll, status %#08x, mask %#08x.\n",
|
|
|
+ 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, work_to_do);
|
|
|
+ }
|
|
|
+
|
|
|
if (np->intr_status &
|
|
|
(IntrTxDone | IntrTxIntr | IntrTxIdle | IntrTxErr)) {
|
|
|
spin_lock(&np->lock);
|
|
@@ -2167,12 +2188,6 @@ 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;
|
|
|
|
|
@@ -2399,19 +2414,8 @@ static struct net_device_stats *get_stats(struct net_device *dev)
|
|
|
#ifdef CONFIG_NET_POLL_CONTROLLER
|
|
|
static void natsemi_poll_controller(struct net_device *dev)
|
|
|
{
|
|
|
- struct netdev_private *np = netdev_priv(dev);
|
|
|
-
|
|
|
disable_irq(dev->irq);
|
|
|
-
|
|
|
- /*
|
|
|
- * A real interrupt might have already reached us at this point
|
|
|
- * but NAPI might still haven't called us back. As the interrupt
|
|
|
- * status register is cleared by reading, we should prevent an
|
|
|
- * interrupt loss in this case...
|
|
|
- */
|
|
|
- if (!np->intr_status)
|
|
|
- intr_handler(dev->irq, dev);
|
|
|
-
|
|
|
+ intr_handler(dev->irq, dev);
|
|
|
enable_irq(dev->irq);
|
|
|
}
|
|
|
#endif
|
|
@@ -3071,7 +3075,7 @@ static void enable_wol_mode(struct net_device *dev, int enable_intr)
|
|
|
* Could be used to send a netlink message.
|
|
|
*/
|
|
|
writel(WOLPkt | LinkChange, ioaddr + IntrMask);
|
|
|
- writel(1, ioaddr + IntrEnable);
|
|
|
+ natsemi_irq_enable(dev);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -3202,7 +3206,7 @@ static int natsemi_suspend (struct pci_dev *pdev, pm_message_t state)
|
|
|
disable_irq(dev->irq);
|
|
|
spin_lock_irq(&np->lock);
|
|
|
|
|
|
- writel(0, ioaddr + IntrEnable);
|
|
|
+ natsemi_irq_disable(dev);
|
|
|
np->hands_off = 1;
|
|
|
natsemi_stop_rxtx(dev);
|
|
|
netif_stop_queue(dev);
|