diff options
Diffstat (limited to 'drivers/net/wireless/wl12xx/rx.c')
| -rw-r--r-- | drivers/net/wireless/wl12xx/rx.c | 80 | 
1 files changed, 52 insertions, 28 deletions
diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/rx.c index 919b59f0030..70091035e01 100644 --- a/drivers/net/wireless/wl12xx/rx.c +++ b/drivers/net/wireless/wl12xx/rx.c @@ -48,18 +48,14 @@ static void wl1271_rx_status(struct wl1271 *wl,  			     struct ieee80211_rx_status *status,  			     u8 beacon)  { -	enum ieee80211_band desc_band; -  	memset(status, 0, sizeof(struct ieee80211_rx_status)); -	status->band = wl->band; -  	if ((desc->flags & WL1271_RX_DESC_BAND_MASK) == WL1271_RX_DESC_BAND_BG) -		desc_band = IEEE80211_BAND_2GHZ; +		status->band = IEEE80211_BAND_2GHZ;  	else -		desc_band = IEEE80211_BAND_5GHZ; +		status->band = IEEE80211_BAND_5GHZ; -	status->rate_idx = wl1271_rate_to_idx(desc->rate, desc_band); +	status->rate_idx = wl1271_rate_to_idx(desc->rate, status->band);  #ifdef CONFIG_WL12XX_HT  	/* 11n support */ @@ -76,15 +72,19 @@ static void wl1271_rx_status(struct wl1271 *wl,  	 */  	wl->noise = desc->rssi - (desc->snr >> 1); -	status->freq = ieee80211_channel_to_frequency(desc->channel, desc_band); +	status->freq = ieee80211_channel_to_frequency(desc->channel, +						      status->band);  	if (desc->flags & WL1271_RX_DESC_ENCRYPT_MASK) { -		status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED; +		u8 desc_err_code = desc->status & WL1271_RX_DESC_STATUS_MASK; + +		status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED | +				RX_FLAG_DECRYPTED; -		if (likely(!(desc->status & WL1271_RX_DESC_DECRYPT_FAIL))) -			status->flag |= RX_FLAG_DECRYPTED; -		if (unlikely(desc->status & WL1271_RX_DESC_MIC_FAIL)) +		if (unlikely(desc_err_code == WL1271_RX_DESC_MIC_FAIL)) {  			status->flag |= RX_FLAG_MMIC_ERROR; +			wl1271_warning("Michael MIC error"); +		}  	}  } @@ -103,6 +103,25 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length)  	if (unlikely(wl->state == WL1271_STATE_PLT))  		return -EINVAL; +	/* the data read starts with the descriptor */ +	desc = (struct wl1271_rx_descriptor *) data; + +	switch (desc->status & WL1271_RX_DESC_STATUS_MASK) { +	/* discard corrupted packets */ +	case WL1271_RX_DESC_DRIVER_RX_Q_FAIL: +	case WL1271_RX_DESC_DECRYPT_FAIL: +		wl1271_warning("corrupted packet in RX with status: 0x%x", +			       desc->status & WL1271_RX_DESC_STATUS_MASK); +		return -EINVAL; +	case WL1271_RX_DESC_SUCCESS: +	case WL1271_RX_DESC_MIC_FAIL: +		break; +	default: +		wl1271_error("invalid RX descriptor status: 0x%x", +			     desc->status & WL1271_RX_DESC_STATUS_MASK); +		return -EINVAL; +	} +  	skb = __dev_alloc_skb(length, GFP_KERNEL);  	if (!skb) {  		wl1271_error("Couldn't allocate RX frame"); @@ -112,9 +131,6 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length)  	buf = skb_put(skb, length);  	memcpy(buf, data, length); -	/* the data read starts with the descriptor */ -	desc = (struct wl1271_rx_descriptor *) buf; -  	/* now we pull the descriptor out of the buffer */  	skb_pull(skb, sizeof(*desc)); @@ -124,7 +140,8 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length)  	wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon); -	wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len, +	wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, +		     skb->len - desc->pad_len,  		     beacon ? "beacon" : "");  	skb_trim(skb, skb->len - desc->pad_len); @@ -163,18 +180,25 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status)  			break;  		} -		/* -		 * Choose the block we want to read -		 * For aggregated packets, only the first memory block should -		 * be retrieved. The FW takes care of the rest. -		 */ -		mem_block = wl1271_rx_get_mem_block(status, drv_rx_counter); -		wl->rx_mem_pool_addr.addr = (mem_block << 8) + -			le32_to_cpu(wl_mem_map->packet_memory_pool_start); -		wl->rx_mem_pool_addr.addr_extra = -			wl->rx_mem_pool_addr.addr + 4; -		wl1271_write(wl, WL1271_SLV_REG_DATA, &wl->rx_mem_pool_addr, -				sizeof(wl->rx_mem_pool_addr), false); +		if (wl->chip.id != CHIP_ID_1283_PG20) { +			/* +			 * Choose the block we want to read +			 * For aggregated packets, only the first memory block +			 * should be retrieved. The FW takes care of the rest. +			 */ +			mem_block = wl1271_rx_get_mem_block(status, +							    drv_rx_counter); + +			wl->rx_mem_pool_addr.addr = (mem_block << 8) + +			   le32_to_cpu(wl_mem_map->packet_memory_pool_start); + +			wl->rx_mem_pool_addr.addr_extra = +				wl->rx_mem_pool_addr.addr + 4; + +			wl1271_write(wl, WL1271_SLV_REG_DATA, +				     &wl->rx_mem_pool_addr, +				     sizeof(wl->rx_mem_pool_addr), false); +		}  		/* Read all available packets at once */  		wl1271_read(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf,  |