diff options
Diffstat (limited to 'drivers/net/wireless/ath5k/base.c')
-rw-r--r-- | drivers/net/wireless/ath5k/base.c | 95 |
1 files changed, 62 insertions, 33 deletions
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 8ef87356e083..1d77ee9d6e99 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c | |||
@@ -1028,6 +1028,8 @@ ath5k_setup_bands(struct ieee80211_hw *hw) | |||
1028 | * it's done by reseting the chip. To accomplish this we must | 1028 | * it's done by reseting the chip. To accomplish this we must |
1029 | * first cleanup any pending DMA, then restart stuff after a la | 1029 | * first cleanup any pending DMA, then restart stuff after a la |
1030 | * ath5k_init. | 1030 | * ath5k_init. |
1031 | * | ||
1032 | * Called with sc->lock. | ||
1031 | */ | 1033 | */ |
1032 | static int | 1034 | static int |
1033 | ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan) | 1035 | ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan) |
@@ -1096,6 +1098,42 @@ ath5k_hw_to_driver_rix(struct ath5k_softc *sc, int hw_rix) | |||
1096 | * Buffers setup * | 1098 | * Buffers setup * |
1097 | \***************/ | 1099 | \***************/ |
1098 | 1100 | ||
1101 | static | ||
1102 | struct sk_buff *ath5k_rx_skb_alloc(struct ath5k_softc *sc, dma_addr_t *skb_addr) | ||
1103 | { | ||
1104 | struct sk_buff *skb; | ||
1105 | unsigned int off; | ||
1106 | |||
1107 | /* | ||
1108 | * Allocate buffer with headroom_needed space for the | ||
1109 | * fake physical layer header at the start. | ||
1110 | */ | ||
1111 | skb = dev_alloc_skb(sc->rxbufsize + sc->cachelsz - 1); | ||
1112 | |||
1113 | if (!skb) { | ||
1114 | ATH5K_ERR(sc, "can't alloc skbuff of size %u\n", | ||
1115 | sc->rxbufsize + sc->cachelsz - 1); | ||
1116 | return NULL; | ||
1117 | } | ||
1118 | /* | ||
1119 | * Cache-line-align. This is important (for the | ||
1120 | * 5210 at least) as not doing so causes bogus data | ||
1121 | * in rx'd frames. | ||
1122 | */ | ||
1123 | off = ((unsigned long)skb->data) % sc->cachelsz; | ||
1124 | if (off != 0) | ||
1125 | skb_reserve(skb, sc->cachelsz - off); | ||
1126 | |||
1127 | *skb_addr = pci_map_single(sc->pdev, | ||
1128 | skb->data, sc->rxbufsize, PCI_DMA_FROMDEVICE); | ||
1129 | if (unlikely(pci_dma_mapping_error(sc->pdev, *skb_addr))) { | ||
1130 | ATH5K_ERR(sc, "%s: DMA mapping failed\n", __func__); | ||
1131 | dev_kfree_skb(skb); | ||
1132 | return NULL; | ||
1133 | } | ||
1134 | return skb; | ||
1135 | } | ||
1136 | |||
1099 | static int | 1137 | static int |
1100 | ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) | 1138 | ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) |
1101 | { | 1139 | { |
@@ -1103,37 +1141,11 @@ ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) | |||
1103 | struct sk_buff *skb = bf->skb; | 1141 | struct sk_buff *skb = bf->skb; |
1104 | struct ath5k_desc *ds; | 1142 | struct ath5k_desc *ds; |
1105 | 1143 | ||
1106 | if (likely(skb == NULL)) { | 1144 | if (!skb) { |
1107 | unsigned int off; | 1145 | skb = ath5k_rx_skb_alloc(sc, &bf->skbaddr); |
1108 | 1146 | if (!skb) | |
1109 | /* | ||
1110 | * Allocate buffer with headroom_needed space for the | ||
1111 | * fake physical layer header at the start. | ||
1112 | */ | ||
1113 | skb = dev_alloc_skb(sc->rxbufsize + sc->cachelsz - 1); | ||
1114 | if (unlikely(skb == NULL)) { | ||
1115 | ATH5K_ERR(sc, "can't alloc skbuff of size %u\n", | ||
1116 | sc->rxbufsize + sc->cachelsz - 1); | ||
1117 | return -ENOMEM; | 1147 | return -ENOMEM; |
1118 | } | ||
1119 | /* | ||
1120 | * Cache-line-align. This is important (for the | ||
1121 | * 5210 at least) as not doing so causes bogus data | ||
1122 | * in rx'd frames. | ||
1123 | */ | ||
1124 | off = ((unsigned long)skb->data) % sc->cachelsz; | ||
1125 | if (off != 0) | ||
1126 | skb_reserve(skb, sc->cachelsz - off); | ||
1127 | |||
1128 | bf->skb = skb; | 1148 | bf->skb = skb; |
1129 | bf->skbaddr = pci_map_single(sc->pdev, | ||
1130 | skb->data, sc->rxbufsize, PCI_DMA_FROMDEVICE); | ||
1131 | if (unlikely(pci_dma_mapping_error(sc->pdev, bf->skbaddr))) { | ||
1132 | ATH5K_ERR(sc, "%s: DMA mapping failed\n", __func__); | ||
1133 | dev_kfree_skb(skb); | ||
1134 | bf->skb = NULL; | ||
1135 | return -ENOMEM; | ||
1136 | } | ||
1137 | } | 1149 | } |
1138 | 1150 | ||
1139 | /* | 1151 | /* |
@@ -1662,7 +1674,8 @@ ath5k_tasklet_rx(unsigned long data) | |||
1662 | { | 1674 | { |
1663 | struct ieee80211_rx_status rxs = {}; | 1675 | struct ieee80211_rx_status rxs = {}; |
1664 | struct ath5k_rx_status rs = {}; | 1676 | struct ath5k_rx_status rs = {}; |
1665 | struct sk_buff *skb; | 1677 | struct sk_buff *skb, *next_skb; |
1678 | dma_addr_t next_skb_addr; | ||
1666 | struct ath5k_softc *sc = (void *)data; | 1679 | struct ath5k_softc *sc = (void *)data; |
1667 | struct ath5k_buf *bf, *bf_last; | 1680 | struct ath5k_buf *bf, *bf_last; |
1668 | struct ath5k_desc *ds; | 1681 | struct ath5k_desc *ds; |
@@ -1747,10 +1760,17 @@ ath5k_tasklet_rx(unsigned long data) | |||
1747 | goto next; | 1760 | goto next; |
1748 | } | 1761 | } |
1749 | accept: | 1762 | accept: |
1763 | next_skb = ath5k_rx_skb_alloc(sc, &next_skb_addr); | ||
1764 | |||
1765 | /* | ||
1766 | * If we can't replace bf->skb with a new skb under memory | ||
1767 | * pressure, just skip this packet | ||
1768 | */ | ||
1769 | if (!next_skb) | ||
1770 | goto next; | ||
1771 | |||
1750 | pci_unmap_single(sc->pdev, bf->skbaddr, sc->rxbufsize, | 1772 | pci_unmap_single(sc->pdev, bf->skbaddr, sc->rxbufsize, |
1751 | PCI_DMA_FROMDEVICE); | 1773 | PCI_DMA_FROMDEVICE); |
1752 | bf->skb = NULL; | ||
1753 | |||
1754 | skb_put(skb, rs.rs_datalen); | 1774 | skb_put(skb, rs.rs_datalen); |
1755 | 1775 | ||
1756 | /* The MAC header is padded to have 32-bit boundary if the | 1776 | /* The MAC header is padded to have 32-bit boundary if the |
@@ -1823,6 +1843,9 @@ accept: | |||
1823 | ath5k_check_ibss_tsf(sc, skb, &rxs); | 1843 | ath5k_check_ibss_tsf(sc, skb, &rxs); |
1824 | 1844 | ||
1825 | __ieee80211_rx(sc->hw, skb, &rxs); | 1845 | __ieee80211_rx(sc->hw, skb, &rxs); |
1846 | |||
1847 | bf->skb = next_skb; | ||
1848 | bf->skbaddr = next_skb_addr; | ||
1826 | next: | 1849 | next: |
1827 | list_move_tail(&bf->list, &sc->rxbuf); | 1850 | list_move_tail(&bf->list, &sc->rxbuf); |
1828 | } while (ath5k_rxbuf_setup(sc, bf) == 0); | 1851 | } while (ath5k_rxbuf_setup(sc, bf) == 0); |
@@ -2814,11 +2837,17 @@ ath5k_config(struct ieee80211_hw *hw, u32 changed) | |||
2814 | { | 2837 | { |
2815 | struct ath5k_softc *sc = hw->priv; | 2838 | struct ath5k_softc *sc = hw->priv; |
2816 | struct ieee80211_conf *conf = &hw->conf; | 2839 | struct ieee80211_conf *conf = &hw->conf; |
2840 | int ret; | ||
2841 | |||
2842 | mutex_lock(&sc->lock); | ||
2817 | 2843 | ||
2818 | sc->bintval = conf->beacon_int; | 2844 | sc->bintval = conf->beacon_int; |
2819 | sc->power_level = conf->power_level; | 2845 | sc->power_level = conf->power_level; |
2820 | 2846 | ||
2821 | return ath5k_chan_set(sc, conf->channel); | 2847 | ret = ath5k_chan_set(sc, conf->channel); |
2848 | |||
2849 | mutex_unlock(&sc->lock); | ||
2850 | return ret; | ||
2822 | } | 2851 | } |
2823 | 2852 | ||
2824 | static int | 2853 | static int |