pata_efar: fix PIO2 underclocking
[safe/jmp/linux-2.6] / drivers / net / r8169.c
index 0771eb6..8247a94 100644 (file)
@@ -1148,7 +1148,7 @@ static void rtl8169_update_counters(struct net_device *dev)
                return;
 
        RTL_W32(CounterAddrHigh, (u64)paddr >> 32);
-       cmd = (u64)paddr & DMA_32BIT_MASK;
+       cmd = (u64)paddr & DMA_BIT_MASK(32);
        RTL_W32(CounterAddrLow, cmd);
        RTL_W32(CounterAddrLow, cmd | CounterDump);
 
@@ -2046,11 +2046,11 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        tp->cp_cmd = PCIMulRW | RxChkSum;
 
        if ((sizeof(dma_addr_t) > 4) &&
-           !pci_set_dma_mask(pdev, DMA_64BIT_MASK) && use_dac) {
+           !pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) && use_dac) {
                tp->cp_cmd |= PCIDAC;
                dev->features |= NETIF_F_HIGHDMA;
        } else {
-               rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+               rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
                if (rc < 0) {
                        if (netif_msg_probe(tp)) {
                                dev_err(&pdev->dev,
@@ -2075,8 +2075,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (!tp->pcie_cap && netif_msg_probe(tp))
                dev_info(&pdev->dev, "no PCI Express capability\n");
 
-       /* Unneeded ? Don't mess with Mrs. Murphy. */
-       rtl8169_irq_mask_and_ack(ioaddr);
+       RTL_W16(IntrMask, 0x0000);
 
        /* Soft reset the chip. */
        RTL_W8(ChipCmd, CmdReset);
@@ -2088,6 +2087,8 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                msleep_interruptible(1);
        }
 
+       RTL_W16(IntrStatus, 0xffff);
+
        /* Identify chip attached to board */
        rtl8169_get_mac_version(tp, ioaddr);
 
@@ -2342,9 +2343,9 @@ static void rtl_set_rx_tx_desc_registers(struct rtl8169_private *tp,
         * Switching from MMIO to I/O access fixes the issue as well.
         */
        RTL_W32(TxDescStartAddrHigh, ((u64) tp->TxPhyAddr) >> 32);
-       RTL_W32(TxDescStartAddrLow, ((u64) tp->TxPhyAddr) & DMA_32BIT_MASK);
+       RTL_W32(TxDescStartAddrLow, ((u64) tp->TxPhyAddr) & DMA_BIT_MASK(32));
        RTL_W32(RxDescAddrHigh, ((u64) tp->RxPhyAddr) >> 32);
-       RTL_W32(RxDescAddrLow, ((u64) tp->RxPhyAddr) & DMA_32BIT_MASK);
+       RTL_W32(RxDescAddrLow, ((u64) tp->RxPhyAddr) & DMA_BIT_MASK(32));
 }
 
 static u16 rtl_rw_cpluscmd(void __iomem *ioaddr)
@@ -3253,13 +3254,6 @@ static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev)
                opts1 |= FirstFrag;
        } else {
                len = skb->len;
-
-               if (unlikely(len < ETH_ZLEN)) {
-                       if (skb_padto(skb, ETH_ZLEN))
-                               goto err_update_stats;
-                       len = ETH_ZLEN;
-               }
-
                opts1 |= FirstFrag | LastFrag;
                tp->tx_skb[entry].skb = skb;
        }
@@ -3297,7 +3291,6 @@ out:
 err_stop:
        netif_stop_queue(dev);
        ret = NETDEV_TX_BUSY;
-err_update_stats:
        dev->stats.tx_dropped++;
        goto out;
 }
@@ -3561,54 +3554,64 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
        int handled = 0;
        int status;
 
+       /* loop handling interrupts until we have no new ones or
+        * we hit a invalid/hotplug case.
+        */
        status = RTL_R16(IntrStatus);
+       while (status && status != 0xffff) {
+               handled = 1;
 
-       /* hotplug/major error/no more work/shared irq */
-       if ((status == 0xffff) || !status)
-               goto out;
+               /* Handle all of the error cases first. These will reset
+                * the chip, so just exit the loop.
+                */
+               if (unlikely(!netif_running(dev))) {
+                       rtl8169_asic_down(ioaddr);
+                       break;
+               }
 
-       handled = 1;
+               /* Work around for rx fifo overflow */
+               if (unlikely(status & RxFIFOOver) &&
+               (tp->mac_version == RTL_GIGA_MAC_VER_11)) {
+                       netif_stop_queue(dev);
+                       rtl8169_tx_timeout(dev);
+                       break;
+               }
 
-       if (unlikely(!netif_running(dev))) {
-               rtl8169_asic_down(ioaddr);
-               goto out;
-       }
+               if (unlikely(status & SYSErr)) {
+                       rtl8169_pcierr_interrupt(dev);
+                       break;
+               }
 
-       status &= tp->intr_mask;
-       RTL_W16(IntrStatus,
-               (status & RxFIFOOver) ? (status | RxOverflow) : status);
+               if (status & LinkChg)
+                       rtl8169_check_link_status(dev, tp, ioaddr);
 
-       if (!(status & tp->intr_event))
-               goto out;
-
-       /* Work around for rx fifo overflow */
-       if (unlikely(status & RxFIFOOver) &&
-           (tp->mac_version == RTL_GIGA_MAC_VER_11)) {
-               netif_stop_queue(dev);
-               rtl8169_tx_timeout(dev);
-               goto out;
-       }
+               /* We need to see the lastest version of tp->intr_mask to
+                * avoid ignoring an MSI interrupt and having to wait for
+                * another event which may never come.
+                */
+               smp_rmb();
+               if (status & tp->intr_mask & tp->napi_event) {
+                       RTL_W16(IntrMask, tp->intr_event & ~tp->napi_event);
+                       tp->intr_mask = ~tp->napi_event;
+
+                       if (likely(napi_schedule_prep(&tp->napi)))
+                               __napi_schedule(&tp->napi);
+                       else if (netif_msg_intr(tp)) {
+                               printk(KERN_INFO "%s: interrupt %04x in poll\n",
+                               dev->name, status);
+                       }
+               }
 
-       if (unlikely(status & SYSErr)) {
-               rtl8169_pcierr_interrupt(dev);
-               goto out;
+               /* We only get a new MSI interrupt when all active irq
+                * sources on the chip have been acknowledged. So, ack
+                * everything we've seen and check if new sources have become
+                * active to avoid blocking all interrupts from the chip.
+                */
+               RTL_W16(IntrStatus,
+                       (status & RxFIFOOver) ? (status | RxOverflow) : status);
+               status = RTL_R16(IntrStatus);
        }
 
-       if (status & LinkChg)
-               rtl8169_check_link_status(dev, tp, ioaddr);
-
-       if (status & tp->napi_event) {
-               RTL_W16(IntrMask, tp->intr_event & ~tp->napi_event);
-               tp->intr_mask = ~tp->napi_event;
-
-               if (likely(netif_rx_schedule_prep(&tp->napi)))
-                       __netif_rx_schedule(&tp->napi);
-               else if (netif_msg_intr(tp)) {
-                       printk(KERN_INFO "%s: interrupt %04x in poll\n",
-                              dev->name, status);
-               }
-       }
-out:
        return IRQ_RETVAL(handled);
 }
 
@@ -3623,14 +3626,16 @@ static int rtl8169_poll(struct napi_struct *napi, int budget)
        rtl8169_tx_interrupt(dev, tp, ioaddr);
 
        if (work_done < budget) {
-               netif_rx_complete(napi);
-               tp->intr_mask = 0xffff;
-               /*
-                * 20040426: the barrier is not strictly required but the
-                * behavior of the irq handler could be less predictable
-                * without it. Btw, the lack of flush for the posted pci
-                * write is safe - FR
+               napi_complete(napi);
+
+               /* We need for force the visibility of tp->intr_mask
+                * for other CPUs, as we can loose an MSI interrupt
+                * and potentially wait for a retransmit timeout if we don't.
+                * The posted write to IntrMask is safe, as it will
+                * eventually make it to the chip and we won't loose anything
+                * until it does.
                 */
+               tp->intr_mask = 0xffff;
                smp_wmb();
                RTL_W16(IntrMask, tp->intr_event);
        }