diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/recv.c')
| -rw-r--r-- | drivers/net/wireless/ath/ath9k/recv.c | 177 | 
1 files changed, 94 insertions, 83 deletions
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index ee156e54314..8be2b5d8c15 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -124,13 +124,13 @@ static bool ath_rx_edma_buf_link(struct ath_softc *sc,  	SKB_CB_ATHBUF(skb) = bf;  	ath9k_hw_addrxbuf_edma(ah, bf->bf_buf_addr, qtype); -	skb_queue_tail(&rx_edma->rx_fifo, skb); +	__skb_queue_tail(&rx_edma->rx_fifo, skb);  	return true;  }  static void ath_rx_addbuffer_edma(struct ath_softc *sc, -				  enum ath9k_rx_qtype qtype, int size) +				  enum ath9k_rx_qtype qtype)  {  	struct ath_common *common = ath9k_hw_common(sc->sc_ah);  	struct ath_buf *bf, *tbf; @@ -155,7 +155,7 @@ static void ath_rx_remove_buffer(struct ath_softc *sc,  	rx_edma = &sc->rx.rx_edma[qtype]; -	while ((skb = skb_dequeue(&rx_edma->rx_fifo)) != NULL) { +	while ((skb = __skb_dequeue(&rx_edma->rx_fifo)) != NULL) {  		bf = SKB_CB_ATHBUF(skb);  		BUG_ON(!bf);  		list_add_tail(&bf->list, &sc->rx.rxbuf); @@ -250,15 +250,9 @@ rx_init_fail:  static void ath_edma_start_recv(struct ath_softc *sc)  {  	ath9k_hw_rxena(sc->sc_ah); - -	ath_rx_addbuffer_edma(sc, ATH9K_RX_QUEUE_HP, -			      sc->rx.rx_edma[ATH9K_RX_QUEUE_HP].rx_fifo_hwsize); - -	ath_rx_addbuffer_edma(sc, ATH9K_RX_QUEUE_LP, -			      sc->rx.rx_edma[ATH9K_RX_QUEUE_LP].rx_fifo_hwsize); - +	ath_rx_addbuffer_edma(sc, ATH9K_RX_QUEUE_HP); +	ath_rx_addbuffer_edma(sc, ATH9K_RX_QUEUE_LP);  	ath_opmode_init(sc); -  	ath9k_hw_startpcureceive(sc->sc_ah, !!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL));  } @@ -280,49 +274,47 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)  	common->rx_bufsize = IEEE80211_MAX_MPDU_LEN / 2 +  			     sc->sc_ah->caps.rx_status_len; -	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { +	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)  		return ath_rx_edma_init(sc, nbufs); -	} else { -		ath_dbg(common, CONFIG, "cachelsz %u rxbufsize %u\n", -			common->cachelsz, common->rx_bufsize); -		/* Initialize rx descriptors */ +	ath_dbg(common, CONFIG, "cachelsz %u rxbufsize %u\n", +		common->cachelsz, common->rx_bufsize); -		error = ath_descdma_setup(sc, &sc->rx.rxdma, &sc->rx.rxbuf, -				"rx", nbufs, 1, 0); -		if (error != 0) { -			ath_err(common, -				"failed to allocate rx descriptors: %d\n", -				error); +	/* Initialize rx descriptors */ + +	error = ath_descdma_setup(sc, &sc->rx.rxdma, &sc->rx.rxbuf, +				  "rx", nbufs, 1, 0); +	if (error != 0) { +		ath_err(common, +			"failed to allocate rx descriptors: %d\n", +			error); +		goto err; +	} + +	list_for_each_entry(bf, &sc->rx.rxbuf, list) { +		skb = ath_rxbuf_alloc(common, common->rx_bufsize, +				      GFP_KERNEL); +		if (skb == NULL) { +			error = -ENOMEM;  			goto err;  		} -		list_for_each_entry(bf, &sc->rx.rxbuf, list) { -			skb = ath_rxbuf_alloc(common, common->rx_bufsize, -					      GFP_KERNEL); -			if (skb == NULL) { -				error = -ENOMEM; -				goto err; -			} - -			bf->bf_mpdu = skb; -			bf->bf_buf_addr = dma_map_single(sc->dev, skb->data, -					common->rx_bufsize, -					DMA_FROM_DEVICE); -			if (unlikely(dma_mapping_error(sc->dev, -							bf->bf_buf_addr))) { -				dev_kfree_skb_any(skb); -				bf->bf_mpdu = NULL; -				bf->bf_buf_addr = 0; -				ath_err(common, -					"dma_mapping_error() on RX init\n"); -				error = -ENOMEM; -				goto err; -			} +		bf->bf_mpdu = skb; +		bf->bf_buf_addr = dma_map_single(sc->dev, skb->data, +						 common->rx_bufsize, +						 DMA_FROM_DEVICE); +		if (unlikely(dma_mapping_error(sc->dev, +					       bf->bf_buf_addr))) { +			dev_kfree_skb_any(skb); +			bf->bf_mpdu = NULL; +			bf->bf_buf_addr = 0; +			ath_err(common, +				"dma_mapping_error() on RX init\n"); +			error = -ENOMEM; +			goto err;  		} -		sc->rx.rxlink = NULL;  	} - +	sc->rx.rxlink = NULL;  err:  	if (error)  		ath_rx_cleanup(sc); @@ -340,17 +332,17 @@ void ath_rx_cleanup(struct ath_softc *sc)  	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {  		ath_rx_edma_cleanup(sc);  		return; -	} else { -		list_for_each_entry(bf, &sc->rx.rxbuf, list) { -			skb = bf->bf_mpdu; -			if (skb) { -				dma_unmap_single(sc->dev, bf->bf_buf_addr, -						common->rx_bufsize, -						DMA_FROM_DEVICE); -				dev_kfree_skb(skb); -				bf->bf_buf_addr = 0; -				bf->bf_mpdu = NULL; -			} +	} + +	list_for_each_entry(bf, &sc->rx.rxbuf, list) { +		skb = bf->bf_mpdu; +		if (skb) { +			dma_unmap_single(sc->dev, bf->bf_buf_addr, +					 common->rx_bufsize, +					 DMA_FROM_DEVICE); +			dev_kfree_skb(skb); +			bf->bf_buf_addr = 0; +			bf->bf_mpdu = NULL;  		}  	}  } @@ -381,6 +373,10 @@ u32 ath_calcrxfilter(struct ath_softc *sc)  	rfilt = ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST  		| ATH9K_RX_FILTER_MCAST; +	/* if operating on a DFS channel, enable radar pulse detection */ +	if (sc->hw->conf.radar_enabled) +		rfilt |= ATH9K_RX_FILTER_PHYRADAR | ATH9K_RX_FILTER_PHYERR; +  	if (sc->rx.rxfilter & FIF_PROBE_REQ)  		rfilt |= ATH9K_RX_FILTER_PROBEREQ; @@ -723,6 +719,13 @@ static struct ath_buf *ath_get_next_rx_buf(struct ath_softc *sc,  		ret = ath9k_hw_rxprocdesc(ah, tds, &trs);  		if (ret == -EINPROGRESS)  			return NULL; + +		/* +		 * mark descriptor as zero-length and set the 'more' +		 * flag to ensure that both buffers get discarded +		 */ +		rs->rs_datalen = 0; +		rs->rs_more = true;  	}  	list_del(&bf->list); @@ -859,7 +862,7 @@ static int ath9k_process_rate(struct ath_common *common,  	unsigned int i = 0;  	struct ath_softc __maybe_unused *sc = common->priv; -	band = hw->conf.channel->band; +	band = hw->conf.chandef.chan->band;  	sband = hw->wiphy->bands[band];  	if (rx_stats->rs_rate & 0x80) { @@ -929,14 +932,20 @@ static void ath9k_process_rssi(struct ath_common *common,   * up the frame up to let mac80211 handle the actual error case, be it no   * decryption key or real decryption error. This let us keep statistics there.   */ -static int ath9k_rx_skb_preprocess(struct ath_common *common, -				   struct ieee80211_hw *hw, +static int ath9k_rx_skb_preprocess(struct ath_softc *sc,  				   struct ieee80211_hdr *hdr,  				   struct ath_rx_status *rx_stats,  				   struct ieee80211_rx_status *rx_status,  				   bool *decrypt_error)  { -	struct ath_hw *ah = common->ah; +	struct ieee80211_hw *hw = sc->hw; +	struct ath_hw *ah = sc->sc_ah; +	struct ath_common *common = ath9k_hw_common(ah); +	bool discard_current = sc->rx.discard_next; + +	sc->rx.discard_next = rx_stats->rs_more; +	if (discard_current) +		return -EINVAL;  	/*  	 * everything but the rate is checked here, the rate check is done @@ -954,14 +963,15 @@ static int ath9k_rx_skb_preprocess(struct ath_common *common,  	if (ath9k_process_rate(common, hw, rx_stats, rx_status))  		return -EINVAL; -	rx_status->band = hw->conf.channel->band; -	rx_status->freq = hw->conf.channel->center_freq; +	rx_status->band = hw->conf.chandef.chan->band; +	rx_status->freq = hw->conf.chandef.chan->center_freq;  	rx_status->signal = ah->noise + rx_stats->rs_rssi;  	rx_status->antenna = rx_stats->rs_antenna;  	rx_status->flag |= RX_FLAG_MACTIME_END;  	if (rx_stats->rs_moreaggr)  		rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL; +	sc->rx.discard_next = false;  	return 0;  } @@ -981,7 +991,7 @@ static void ath9k_rx_skb_postprocess(struct ath_common *common,  	hdr = (struct ieee80211_hdr *) skb->data;  	hdrlen = ieee80211_get_hdrlen_from_skb(skb);  	fc = hdr->frame_control; -	padpos = ath9k_cmn_padpos(hdr->frame_control); +	padpos = ieee80211_hdrlen(fc);  	/* The MAC header is padded to have 32-bit boundary if the  	 * packet payload is non-zero. The general calculation for @@ -1162,6 +1172,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)  	u64 tsf = 0;  	u32 tsf_lower = 0;  	unsigned long flags; +	dma_addr_t new_buf_addr;  	if (edma)  		dma_type = DMA_BIDIRECTIONAL; @@ -1228,6 +1239,9 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)  		    unlikely(tsf_lower - rs.rs_tstamp > 0x10000000))  			rxs->mactime += 0x100000000ULL; +		if (rs.rs_phyerr == ATH9K_PHYERR_RADAR) +			ath9k_dfs_process_phyerr(sc, hdr, &rs, rxs->mactime); +  		if (rs.rs_status & ATH9K_RXERR_PHY) {  			if (ath_process_fft(sc, hdr, &rs, rxs->mactime)) {  				RX_STAT_INC(rx_spectral); @@ -1235,8 +1249,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)  			}  		} -		retval = ath9k_rx_skb_preprocess(common, hw, hdr, &rs, -						 rxs, &decrypt_error); +		retval = ath9k_rx_skb_preprocess(sc, hdr, &rs, rxs, +						 &decrypt_error);  		if (retval)  			goto requeue_drop_frag; @@ -1257,10 +1271,20 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)  			goto requeue_drop_frag;  		} +		/* We will now give hardware our shiny new allocated skb */ +		new_buf_addr = dma_map_single(sc->dev, requeue_skb->data, +					      common->rx_bufsize, dma_type); +		if (unlikely(dma_mapping_error(sc->dev, new_buf_addr))) { +			dev_kfree_skb_any(requeue_skb); +			goto requeue_drop_frag; +		} +  		/* Unmap the frame */  		dma_unmap_single(sc->dev, bf->bf_buf_addr, -				 common->rx_bufsize, -				 dma_type); +				 common->rx_bufsize, dma_type); + +		bf->bf_mpdu = requeue_skb; +		bf->bf_buf_addr = new_buf_addr;  		skb_put(skb, rs.rs_datalen + ah->caps.rx_status_len);  		if (ah->caps.rx_status_len) @@ -1270,21 +1294,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)  			ath9k_rx_skb_postprocess(common, hdr_skb, &rs,  						 rxs, decrypt_error); -		/* We will now give hardware our shiny new allocated skb */ -		bf->bf_mpdu = requeue_skb; -		bf->bf_buf_addr = dma_map_single(sc->dev, requeue_skb->data, -						 common->rx_bufsize, -						 dma_type); -		if (unlikely(dma_mapping_error(sc->dev, -			  bf->bf_buf_addr))) { -			dev_kfree_skb_any(requeue_skb); -			bf->bf_mpdu = NULL; -			bf->bf_buf_addr = 0; -			ath_err(common, "dma_mapping_error() on RX\n"); -			ieee80211_rx(hw, skb); -			break; -		} -  		if (rs.rs_more) {  			RX_STAT_INC(rx_frags);  			/* @@ -1302,6 +1311,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)  			sc->rx.frag = skb;  			goto requeue;  		} +		if (rs.rs_status & ATH9K_RXERR_CORRUPT_DESC) +			goto requeue_drop_frag;  		if (sc->rx.frag) {  			int space = skb->len - skb_tailroom(hdr_skb);  |