Linux 2.6.21-rc5
[powerpc.git] / drivers / net / natsemi.c
index c6172a7..349b96a 100644 (file)
@@ -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);