| 1 | --- a/drivers/net/wireless/ath/ath9k/main.c |
| 2 | +++ b/drivers/net/wireless/ath/ath9k/main.c |
| 3 | @@ -1291,6 +1291,11 @@ static void ath9k_stop(struct ieee80211_ |
| 4 | } else |
| 5 | sc->rx.rxlink = NULL; |
| 6 | |
| 7 | + if (sc->rx.frag) { |
| 8 | + dev_kfree_skb_any(sc->rx.frag); |
| 9 | + sc->rx.frag = NULL; |
| 10 | + } |
| 11 | + |
| 12 | /* disable HAL and put h/w to sleep */ |
| 13 | ath9k_hw_disable(ah); |
| 14 | ath9k_hw_configpcipowersave(ah, 1, 1); |
| 15 | --- a/drivers/net/wireless/ath/ath9k/recv.c |
| 16 | +++ b/drivers/net/wireless/ath/ath9k/recv.c |
| 17 | @@ -209,11 +209,6 @@ static int ath_rx_edma_init(struct ath_s |
| 18 | int error = 0, i; |
| 19 | u32 size; |
| 20 | |
| 21 | - |
| 22 | - common->rx_bufsize = roundup(IEEE80211_MAX_MPDU_LEN + |
| 23 | - ah->caps.rx_status_len, |
| 24 | - min(common->cachelsz, (u16)64)); |
| 25 | - |
| 26 | ath9k_hw_set_rx_bufsize(ah, common->rx_bufsize - |
| 27 | ah->caps.rx_status_len); |
| 28 | |
| 29 | @@ -300,12 +295,12 @@ int ath_rx_init(struct ath_softc *sc, in |
| 30 | sc->sc_flags &= ~SC_OP_RXFLUSH; |
| 31 | spin_lock_init(&sc->rx.rxbuflock); |
| 32 | |
| 33 | + common->rx_bufsize = IEEE80211_MAX_MPDU_LEN / 2 + |
| 34 | + sc->sc_ah->caps.rx_status_len; |
| 35 | + |
| 36 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { |
| 37 | return ath_rx_edma_init(sc, nbufs); |
| 38 | } else { |
| 39 | - common->rx_bufsize = roundup(IEEE80211_MAX_MPDU_LEN, |
| 40 | - min(common->cachelsz, (u16)64)); |
| 41 | - |
| 42 | ath_dbg(common, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n", |
| 43 | common->cachelsz, common->rx_bufsize); |
| 44 | |
| 45 | @@ -815,15 +810,9 @@ static bool ath9k_rx_accept(struct ath_c |
| 46 | if (rx_stats->rs_datalen > (common->rx_bufsize - rx_status_len)) |
| 47 | return false; |
| 48 | |
| 49 | - /* |
| 50 | - * rs_more indicates chained descriptors which can be used |
| 51 | - * to link buffers together for a sort of scatter-gather |
| 52 | - * operation. |
| 53 | - * reject the frame, we don't support scatter-gather yet and |
| 54 | - * the frame is probably corrupt anyway |
| 55 | - */ |
| 56 | + /* Only use error bits from the last fragment */ |
| 57 | if (rx_stats->rs_more) |
| 58 | - return false; |
| 59 | + return true; |
| 60 | |
| 61 | /* |
| 62 | * The rx_stats->rs_status will not be set until the end of the |
| 63 | @@ -981,6 +970,10 @@ static int ath9k_rx_skb_preprocess(struc |
| 64 | if (!ath9k_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error)) |
| 65 | return -EINVAL; |
| 66 | |
| 67 | + /* Only use status info from the last fragment */ |
| 68 | + if (rx_stats->rs_more) |
| 69 | + return 0; |
| 70 | + |
| 71 | ath9k_process_rssi(common, hw, hdr, rx_stats); |
| 72 | |
| 73 | if (ath9k_process_rate(common, hw, rx_stats, rx_status)) |
| 74 | @@ -1582,7 +1575,7 @@ div_comb_done: |
| 75 | int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) |
| 76 | { |
| 77 | struct ath_buf *bf; |
| 78 | - struct sk_buff *skb = NULL, *requeue_skb; |
| 79 | + struct sk_buff *skb = NULL, *requeue_skb, *hdr_skb; |
| 80 | struct ieee80211_rx_status *rxs; |
| 81 | struct ath_hw *ah = sc->sc_ah; |
| 82 | struct ath_common *common = ath9k_hw_common(ah); |
| 83 | @@ -1633,8 +1626,17 @@ int ath_rx_tasklet(struct ath_softc *sc, |
| 84 | if (!skb) |
| 85 | continue; |
| 86 | |
| 87 | - hdr = (struct ieee80211_hdr *) (skb->data + rx_status_len); |
| 88 | - rxs = IEEE80211_SKB_RXCB(skb); |
| 89 | + /* |
| 90 | + * Take frame header from the first fragment and RX status from |
| 91 | + * the last one. |
| 92 | + */ |
| 93 | + if (sc->rx.frag) |
| 94 | + hdr_skb = sc->rx.frag; |
| 95 | + else |
| 96 | + hdr_skb = skb; |
| 97 | + |
| 98 | + hdr = (struct ieee80211_hdr *) (hdr_skb->data + rx_status_len); |
| 99 | + rxs = IEEE80211_SKB_RXCB(hdr_skb); |
| 100 | |
| 101 | ath_debug_stat_rx(sc, &rs); |
| 102 | |
| 103 | @@ -1643,12 +1645,12 @@ int ath_rx_tasklet(struct ath_softc *sc, |
| 104 | * chain it back at the queue without processing it. |
| 105 | */ |
| 106 | if (flush) |
| 107 | - goto requeue; |
| 108 | + goto requeue_drop_frag; |
| 109 | |
| 110 | retval = ath9k_rx_skb_preprocess(common, hw, hdr, &rs, |
| 111 | rxs, &decrypt_error); |
| 112 | if (retval) |
| 113 | - goto requeue; |
| 114 | + goto requeue_drop_frag; |
| 115 | |
| 116 | rxs->mactime = (tsf & ~0xffffffffULL) | rs.rs_tstamp; |
| 117 | if (rs.rs_tstamp > tsf_lower && |
| 118 | @@ -1668,7 +1670,7 @@ int ath_rx_tasklet(struct ath_softc *sc, |
| 119 | * skb and put it at the tail of the sc->rx.rxbuf list for |
| 120 | * processing. */ |
| 121 | if (!requeue_skb) |
| 122 | - goto requeue; |
| 123 | + goto requeue_drop_frag; |
| 124 | |
| 125 | /* Unmap the frame */ |
| 126 | dma_unmap_single(sc->dev, bf->bf_buf_addr, |
| 127 | @@ -1679,8 +1681,9 @@ int ath_rx_tasklet(struct ath_softc *sc, |
| 128 | if (ah->caps.rx_status_len) |
| 129 | skb_pull(skb, ah->caps.rx_status_len); |
| 130 | |
| 131 | - ath9k_rx_skb_postprocess(common, skb, &rs, |
| 132 | - rxs, decrypt_error); |
| 133 | + if (!rs.rs_more) |
| 134 | + ath9k_rx_skb_postprocess(common, hdr_skb, &rs, |
| 135 | + rxs, decrypt_error); |
| 136 | |
| 137 | /* We will now give hardware our shiny new allocated skb */ |
| 138 | bf->bf_mpdu = requeue_skb; |
| 139 | @@ -1697,6 +1700,38 @@ int ath_rx_tasklet(struct ath_softc *sc, |
| 140 | break; |
| 141 | } |
| 142 | |
| 143 | + if (rs.rs_more) { |
| 144 | + /* |
| 145 | + * rs_more indicates chained descriptors which can be |
| 146 | + * used to link buffers together for a sort of |
| 147 | + * scatter-gather operation. |
| 148 | + */ |
| 149 | + if (sc->rx.frag) { |
| 150 | + /* too many fragments - cannot handle frame */ |
| 151 | + dev_kfree_skb_any(sc->rx.frag); |
| 152 | + dev_kfree_skb_any(skb); |
| 153 | + skb = NULL; |
| 154 | + } |
| 155 | + sc->rx.frag = skb; |
| 156 | + goto requeue; |
| 157 | + } |
| 158 | + |
| 159 | + if (sc->rx.frag) { |
| 160 | + int space = skb->len - skb_tailroom(hdr_skb); |
| 161 | + |
| 162 | + sc->rx.frag = NULL; |
| 163 | + |
| 164 | + if (pskb_expand_head(hdr_skb, 0, space, GFP_ATOMIC) < 0) { |
| 165 | + dev_kfree_skb(skb); |
| 166 | + goto requeue_drop_frag; |
| 167 | + } |
| 168 | + |
| 169 | + skb_copy_from_linear_data(skb, skb_put(hdr_skb, skb->len), |
| 170 | + skb->len); |
| 171 | + dev_kfree_skb_any(skb); |
| 172 | + skb = hdr_skb; |
| 173 | + } |
| 174 | + |
| 175 | /* |
| 176 | * change the default rx antenna if rx diversity chooses the |
| 177 | * other antenna 3 times in a row. |
| 178 | @@ -1722,6 +1757,11 @@ int ath_rx_tasklet(struct ath_softc *sc, |
| 179 | |
| 180 | ieee80211_rx(hw, skb); |
| 181 | |
| 182 | +requeue_drop_frag: |
| 183 | + if (sc->rx.frag) { |
| 184 | + dev_kfree_skb_any(sc->rx.frag); |
| 185 | + sc->rx.frag = NULL; |
| 186 | + } |
| 187 | requeue: |
| 188 | if (edma) { |
| 189 | list_add_tail(&bf->list, &sc->rx.rxbuf); |
| 190 | --- a/drivers/net/wireless/ath/ath9k/ath9k.h |
| 191 | +++ b/drivers/net/wireless/ath/ath9k/ath9k.h |
| 192 | @@ -311,6 +311,8 @@ struct ath_rx { |
| 193 | struct ath_descdma rxdma; |
| 194 | struct ath_buf *rx_bufptr; |
| 195 | struct ath_rx_edma rx_edma[ATH9K_RX_QUEUE_MAX]; |
| 196 | + |
| 197 | + struct sk_buff *frag; |
| 198 | }; |
| 199 | |
| 200 | int ath_startrecv(struct ath_softc *sc); |
| 201 | |