aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/ath5k/base.c32
-rw-r--r--drivers/net/wireless/ath5k/base.h2
2 files changed, 26 insertions, 8 deletions
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c
index d9769c527346..ed51c4a69d43 100644
--- a/drivers/net/wireless/ath5k/base.c
+++ b/drivers/net/wireless/ath5k/base.c
@@ -1682,20 +1682,21 @@ ath5k_tasklet_rx(unsigned long data)
1682 struct ath5k_rx_status rs = {}; 1682 struct ath5k_rx_status rs = {};
1683 struct sk_buff *skb; 1683 struct sk_buff *skb;
1684 struct ath5k_softc *sc = (void *)data; 1684 struct ath5k_softc *sc = (void *)data;
1685 struct ath5k_buf *bf; 1685 struct ath5k_buf *bf, *bf_last;
1686 struct ath5k_desc *ds; 1686 struct ath5k_desc *ds;
1687 int ret; 1687 int ret;
1688 int hdrlen; 1688 int hdrlen;
1689 int pad; 1689 int pad;
1690 1690
1691 spin_lock(&sc->rxbuflock); 1691 spin_lock(&sc->rxbuflock);
1692 if (list_empty(&sc->rxbuf)) {
1693 ATH5K_WARN(sc, "empty rx buf pool\n");
1694 goto unlock;
1695 }
1696 bf_last = list_entry(sc->rxbuf.prev, struct ath5k_buf, list);
1692 do { 1697 do {
1693 rxs.flag = 0; 1698 rxs.flag = 0;
1694 1699
1695 if (unlikely(list_empty(&sc->rxbuf))) {
1696 ATH5K_WARN(sc, "empty rx buf pool\n");
1697 break;
1698 }
1699 bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list); 1700 bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list);
1700 BUG_ON(bf->skb == NULL); 1701 BUG_ON(bf->skb == NULL);
1701 skb = bf->skb; 1702 skb = bf->skb;
@@ -1705,8 +1706,24 @@ ath5k_tasklet_rx(unsigned long data)
1705 pci_dma_sync_single_for_cpu(sc->pdev, sc->desc_daddr, 1706 pci_dma_sync_single_for_cpu(sc->pdev, sc->desc_daddr,
1706 sc->desc_len, PCI_DMA_FROMDEVICE); 1707 sc->desc_len, PCI_DMA_FROMDEVICE);
1707 1708
1708 if (unlikely(ds->ds_link == bf->daddr)) /* this is the end */ 1709 /*
1709 break; 1710 * last buffer must not be freed to ensure proper hardware
1711 * function. When the hardware finishes also a packet next to
1712 * it, we are sure, it doesn't use it anymore and we can go on.
1713 */
1714 if (bf_last == bf)
1715 bf->flags |= 1;
1716 if (bf->flags) {
1717 struct ath5k_buf *bf_next = list_entry(bf->list.next,
1718 struct ath5k_buf, list);
1719 ret = sc->ah->ah_proc_rx_desc(sc->ah, bf_next->desc,
1720 &rs);
1721 if (ret)
1722 break;
1723 bf->flags &= ~1;
1724 /* skip the overwritten one (even status is martian) */
1725 goto next;
1726 }
1710 1727
1711 ret = sc->ah->ah_proc_rx_desc(sc->ah, ds, &rs); 1728 ret = sc->ah->ah_proc_rx_desc(sc->ah, ds, &rs);
1712 if (unlikely(ret == -EINPROGRESS)) 1729 if (unlikely(ret == -EINPROGRESS))
@@ -1816,6 +1833,7 @@ accept:
1816next: 1833next:
1817 list_move_tail(&bf->list, &sc->rxbuf); 1834 list_move_tail(&bf->list, &sc->rxbuf);
1818 } while (ath5k_rxbuf_setup(sc, bf) == 0); 1835 } while (ath5k_rxbuf_setup(sc, bf) == 0);
1836unlock:
1819 spin_unlock(&sc->rxbuflock); 1837 spin_unlock(&sc->rxbuflock);
1820} 1838}
1821 1839
diff --git a/drivers/net/wireless/ath5k/base.h b/drivers/net/wireless/ath5k/base.h
index 47f414b09e67..d7e03e6b8271 100644
--- a/drivers/net/wireless/ath5k/base.h
+++ b/drivers/net/wireless/ath5k/base.h
@@ -56,7 +56,7 @@
56 56
57struct ath5k_buf { 57struct ath5k_buf {
58 struct list_head list; 58 struct list_head list;
59 unsigned int flags; /* tx descriptor flags */ 59 unsigned int flags; /* rx descriptor flags */
60 struct ath5k_desc *desc; /* virtual addr of desc */ 60 struct ath5k_desc *desc; /* virtual addr of desc */
61 dma_addr_t daddr; /* physical addr of desc */ 61 dma_addr_t daddr; /* physical addr of desc */
62 struct sk_buff *skb; /* skbuff for buf */ 62 struct sk_buff *skb; /* skbuff for buf */