ath9k: Add open loop power control support for AR9287.
[pandora-kernel.git] / drivers / net / vxge / vxge-main.c
index 7b5402b..094d155 100644 (file)
@@ -87,22 +87,25 @@ static inline int is_vxge_card_up(struct vxgedev *vdev)
 static inline void VXGE_COMPLETE_VPATH_TX(struct vxge_fifo *fifo)
 {
        unsigned long flags = 0;
-       struct sk_buff *skb_ptr = NULL;
-       struct sk_buff **temp, *head, *skb;
-
-       if (spin_trylock_irqsave(&fifo->tx_lock, flags)) {
-               vxge_hw_vpath_poll_tx(fifo->handle, (void **)&skb_ptr);
-               spin_unlock_irqrestore(&fifo->tx_lock, flags);
-       }
-       /* free SKBs */
-       head = skb_ptr;
-       while (head) {
-               skb = head;
-               temp = (struct sk_buff **)&skb->cb;
-               head = *temp;
-               *temp = NULL;
-               dev_kfree_skb_irq(skb);
-       }
+       struct sk_buff **skb_ptr = NULL;
+       struct sk_buff **temp;
+#define NR_SKB_COMPLETED 128
+       struct sk_buff *completed[NR_SKB_COMPLETED];
+       int more;
+
+       do {
+               more = 0;
+               skb_ptr = completed;
+
+               if (spin_trylock_irqsave(&fifo->tx_lock, flags)) {
+                       vxge_hw_vpath_poll_tx(fifo->handle, &skb_ptr,
+                                               NR_SKB_COMPLETED, &more);
+                       spin_unlock_irqrestore(&fifo->tx_lock, flags);
+               }
+               /* free SKBs */
+               for (temp = completed; temp != skb_ptr; temp++)
+                       dev_kfree_skb_irq(*temp);
+       } while (more) ;
 }
 
 static inline void VXGE_COMPLETE_ALL_TX(struct vxgedev *vdev)
@@ -283,6 +286,7 @@ vxge_rx_alloc(void *dtrh, struct vxge_ring *ring, const int skb_size)
        skb_reserve(skb, VXGE_HW_HEADER_ETHERNET_II_802_3_ALIGN);
 
        rx_priv->skb = skb;
+       rx_priv->skb_data = NULL;
        rx_priv->data_size = skb_size;
        vxge_debug_entryexit(VXGE_TRACE,
                "%s: %s:%d Exiting...", ring->ndev->name, __func__, __LINE__);
@@ -302,7 +306,8 @@ static int vxge_rx_map(void *dtrh, struct vxge_ring *ring)
                ring->ndev->name, __func__, __LINE__);
        rx_priv = vxge_hw_ring_rxd_private_get(dtrh);
 
-       dma_addr = pci_map_single(ring->pdev, rx_priv->skb->data,
+       rx_priv->skb_data = rx_priv->skb->data;
+       dma_addr = pci_map_single(ring->pdev, rx_priv->skb_data,
                                rx_priv->data_size, PCI_DMA_FROMDEVICE);
 
        if (dma_addr == 0) {
@@ -442,10 +447,12 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr,
        vxge_hw_ring_replenish(ringh, 0);
 
        do {
+               prefetch((char *)dtr + L1_CACHE_BYTES);
                rx_priv = vxge_hw_ring_rxd_private_get(dtr);
                skb = rx_priv->skb;
                data_size = rx_priv->data_size;
                data_dma = rx_priv->data_dma;
+               prefetch(rx_priv->skb_data);
 
                vxge_debug_rx(VXGE_TRACE,
                        "%s: %s:%d  skb = 0x%p",
@@ -600,11 +607,10 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr,
 enum vxge_hw_status
 vxge_xmit_compl(struct __vxge_hw_fifo *fifo_hw, void *dtr,
                enum vxge_hw_fifo_tcode t_code, void *userdata,
-               void **skb_ptr)
+               struct sk_buff ***skb_ptr, int nr_skb, int *more)
 {
        struct vxge_fifo *fifo = (struct vxge_fifo *)userdata;
-       struct sk_buff *skb, *head = NULL;
-       struct sk_buff **temp;
+       struct sk_buff *skb, **done_skb = *skb_ptr;
        int pkt_cnt = 0;
 
        vxge_debug_entryexit(VXGE_TRACE,
@@ -657,9 +663,12 @@ vxge_xmit_compl(struct __vxge_hw_fifo *fifo_hw, void *dtr,
                fifo->stats.tx_frms++;
                fifo->stats.tx_bytes += skb->len;
 
-               temp = (struct sk_buff **)&skb->cb;
-               *temp = head;
-               head = skb;
+               *done_skb++ = skb;
+
+               if (--nr_skb <= 0) {
+                       *more = 1;
+                       break;
+               }
 
                pkt_cnt++;
                if (pkt_cnt > fifo->indicate_max_pkts)
@@ -668,11 +677,9 @@ vxge_xmit_compl(struct __vxge_hw_fifo *fifo_hw, void *dtr,
        } while (vxge_hw_fifo_txdl_next_completed(fifo_hw,
                                &dtr, &t_code) == VXGE_HW_OK);
 
+       *skb_ptr = done_skb;
        vxge_wake_tx_queue(fifo, skb);
 
-       if (skb_ptr)
-               *skb_ptr = (void *) head;
-
        vxge_debug_entryexit(VXGE_TRACE,
                                "%s: %s:%d  Exiting...",
                                fifo->ndev->name, __func__, __LINE__);
@@ -895,6 +902,12 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev)
                goto _exit2;
        }
 
+       /* Last TXD?  Stop tx queue to avoid dropping packets.  TX
+        * completion will resume the queue.
+        */
+       if (avail == 1)
+               vxge_stop_tx_queue(fifo);
+
        status = vxge_hw_fifo_txdl_reserve(fifo_hw, &dtr, &dtr_priv);
        if (unlikely(status != VXGE_HW_OK)) {
                vxge_debug_tx(VXGE_ERR,
@@ -1046,6 +1059,7 @@ vxge_rx_term(void *dtrh, enum vxge_hw_rxd_state state, void *userdata)
                rx_priv->data_size, PCI_DMA_FROMDEVICE);
 
        dev_kfree_skb(rx_priv->skb);
+       rx_priv->skb_data = NULL;
 
        vxge_debug_entryexit(VXGE_TRACE,
                "%s: %s:%d  Exiting...",
@@ -3956,6 +3970,9 @@ static pci_ers_result_t vxge_io_error_detected(struct pci_dev *pdev,
 
        netif_device_detach(netdev);
 
+       if (state == pci_channel_io_perm_failure)
+               return PCI_ERS_RESULT_DISCONNECT;
+
        if (netif_running(netdev)) {
                /* Bring down the card, while avoiding PCI I/O */
                do_vxge_close(netdev, 0);