diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-rx.c')
| -rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-rx.c | 824 | 
1 files changed, 75 insertions, 749 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index df257bc15f4..267eb893590 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -28,6 +28,7 @@   *****************************************************************************/  #include <linux/etherdevice.h> +#include <linux/slab.h>  #include <net/mac80211.h>  #include <asm/unaligned.h>  #include "iwl-eeprom.h" @@ -162,197 +163,6 @@ void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q  	spin_unlock_irqrestore(&q->lock, flags);  }  EXPORT_SYMBOL(iwl_rx_queue_update_write_ptr); -/** - * iwl_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr - */ -static inline __le32 iwl_dma_addr2rbd_ptr(struct iwl_priv *priv, -					  dma_addr_t dma_addr) -{ -	return cpu_to_le32((u32)(dma_addr >> 8)); -} - -/** - * iwl_rx_queue_restock - refill RX queue from pre-allocated pool - * - * If there are slots in the RX queue that need to be restocked, - * and we have free pre-allocated buffers, fill the ranks as much - * as we can, pulling from rx_free. - * - * This moves the 'write' index forward to catch up with 'processed', and - * also updates the memory address in the firmware to reference the new - * target buffer. - */ -void iwl_rx_queue_restock(struct iwl_priv *priv) -{ -	struct iwl_rx_queue *rxq = &priv->rxq; -	struct list_head *element; -	struct iwl_rx_mem_buffer *rxb; -	unsigned long flags; -	int write; - -	spin_lock_irqsave(&rxq->lock, flags); -	write = rxq->write & ~0x7; -	while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) { -		/* Get next free Rx buffer, remove from free list */ -		element = rxq->rx_free.next; -		rxb = list_entry(element, struct iwl_rx_mem_buffer, list); -		list_del(element); - -		/* Point to Rx buffer via next RBD in circular buffer */ -		rxq->bd[rxq->write] = iwl_dma_addr2rbd_ptr(priv, rxb->page_dma); -		rxq->queue[rxq->write] = rxb; -		rxq->write = (rxq->write + 1) & RX_QUEUE_MASK; -		rxq->free_count--; -	} -	spin_unlock_irqrestore(&rxq->lock, flags); -	/* If the pre-allocated buffer pool is dropping low, schedule to -	 * refill it */ -	if (rxq->free_count <= RX_LOW_WATERMARK) -		queue_work(priv->workqueue, &priv->rx_replenish); - - -	/* If we've added more space for the firmware to place data, tell it. -	 * Increment device's write pointer in multiples of 8. */ -	if (rxq->write_actual != (rxq->write & ~0x7)) { -		spin_lock_irqsave(&rxq->lock, flags); -		rxq->need_update = 1; -		spin_unlock_irqrestore(&rxq->lock, flags); -		iwl_rx_queue_update_write_ptr(priv, rxq); -	} -} -EXPORT_SYMBOL(iwl_rx_queue_restock); - - -/** - * iwl_rx_replenish - Move all used packet from rx_used to rx_free - * - * When moving to rx_free an SKB is allocated for the slot. - * - * Also restock the Rx queue via iwl_rx_queue_restock. - * This is called as a scheduled work item (except for during initialization) - */ -void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority) -{ -	struct iwl_rx_queue *rxq = &priv->rxq; -	struct list_head *element; -	struct iwl_rx_mem_buffer *rxb; -	struct page *page; -	unsigned long flags; -	gfp_t gfp_mask = priority; - -	while (1) { -		spin_lock_irqsave(&rxq->lock, flags); -		if (list_empty(&rxq->rx_used)) { -			spin_unlock_irqrestore(&rxq->lock, flags); -			return; -		} -		spin_unlock_irqrestore(&rxq->lock, flags); - -		if (rxq->free_count > RX_LOW_WATERMARK) -			gfp_mask |= __GFP_NOWARN; - -		if (priv->hw_params.rx_page_order > 0) -			gfp_mask |= __GFP_COMP; - -		/* Alloc a new receive buffer */ -		page = alloc_pages(gfp_mask, priv->hw_params.rx_page_order); -		if (!page) { -			if (net_ratelimit()) -				IWL_DEBUG_INFO(priv, "alloc_pages failed, " -					       "order: %d\n", -					       priv->hw_params.rx_page_order); - -			if ((rxq->free_count <= RX_LOW_WATERMARK) && -			    net_ratelimit()) -				IWL_CRIT(priv, "Failed to alloc_pages with %s. Only %u free buffers remaining.\n", -					 priority == GFP_ATOMIC ?  "GFP_ATOMIC" : "GFP_KERNEL", -					 rxq->free_count); -			/* We don't reschedule replenish work here -- we will -			 * call the restock method and if it still needs -			 * more buffers it will schedule replenish */ -			return; -		} - -		spin_lock_irqsave(&rxq->lock, flags); - -		if (list_empty(&rxq->rx_used)) { -			spin_unlock_irqrestore(&rxq->lock, flags); -			__free_pages(page, priv->hw_params.rx_page_order); -			return; -		} -		element = rxq->rx_used.next; -		rxb = list_entry(element, struct iwl_rx_mem_buffer, list); -		list_del(element); - -		spin_unlock_irqrestore(&rxq->lock, flags); - -		rxb->page = page; -		/* Get physical address of the RB */ -		rxb->page_dma = pci_map_page(priv->pci_dev, page, 0, -				PAGE_SIZE << priv->hw_params.rx_page_order, -				PCI_DMA_FROMDEVICE); -		/* dma address must be no more than 36 bits */ -		BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36)); -		/* and also 256 byte aligned! */ -		BUG_ON(rxb->page_dma & DMA_BIT_MASK(8)); - -		spin_lock_irqsave(&rxq->lock, flags); - -		list_add_tail(&rxb->list, &rxq->rx_free); -		rxq->free_count++; -		priv->alloc_rxb_page++; - -		spin_unlock_irqrestore(&rxq->lock, flags); -	} -} - -void iwl_rx_replenish(struct iwl_priv *priv) -{ -	unsigned long flags; - -	iwl_rx_allocate(priv, GFP_KERNEL); - -	spin_lock_irqsave(&priv->lock, flags); -	iwl_rx_queue_restock(priv); -	spin_unlock_irqrestore(&priv->lock, flags); -} -EXPORT_SYMBOL(iwl_rx_replenish); - -void iwl_rx_replenish_now(struct iwl_priv *priv) -{ -	iwl_rx_allocate(priv, GFP_ATOMIC); - -	iwl_rx_queue_restock(priv); -} -EXPORT_SYMBOL(iwl_rx_replenish_now); - - -/* Assumes that the skb field of the buffers in 'pool' is kept accurate. - * If an SKB has been detached, the POOL needs to have its SKB set to NULL - * This free routine walks the list of POOL entries and if SKB is set to - * non NULL it is unmapped and freed - */ -void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq) -{ -	int i; -	for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) { -		if (rxq->pool[i].page != NULL) { -			pci_unmap_page(priv->pci_dev, rxq->pool[i].page_dma, -				PAGE_SIZE << priv->hw_params.rx_page_order, -				PCI_DMA_FROMDEVICE); -			__iwl_free_pages(priv, rxq->pool[i].page); -			rxq->pool[i].page = NULL; -		} -	} - -	dma_free_coherent(&priv->pci_dev->dev, 4 * RX_QUEUE_SIZE, rxq->bd, -			  rxq->dma_addr); -	dma_free_coherent(&priv->pci_dev->dev, sizeof(struct iwl_rb_status), -			  rxq->rb_stts, rxq->rb_stts_dma); -	rxq->bd = NULL; -	rxq->rb_stts  = NULL; -} -EXPORT_SYMBOL(iwl_rx_queue_free);  int iwl_rx_queue_alloc(struct iwl_priv *priv)  { @@ -395,98 +205,6 @@ err_bd:  }  EXPORT_SYMBOL(iwl_rx_queue_alloc); -void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq) -{ -	unsigned long flags; -	int i; -	spin_lock_irqsave(&rxq->lock, flags); -	INIT_LIST_HEAD(&rxq->rx_free); -	INIT_LIST_HEAD(&rxq->rx_used); -	/* Fill the rx_used queue with _all_ of the Rx buffers */ -	for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) { -		/* In the reset function, these buffers may have been allocated -		 * to an SKB, so we need to unmap and free potential storage */ -		if (rxq->pool[i].page != NULL) { -			pci_unmap_page(priv->pci_dev, rxq->pool[i].page_dma, -				PAGE_SIZE << priv->hw_params.rx_page_order, -				PCI_DMA_FROMDEVICE); -			__iwl_free_pages(priv, rxq->pool[i].page); -			rxq->pool[i].page = NULL; -		} -		list_add_tail(&rxq->pool[i].list, &rxq->rx_used); -	} - -	/* Set us so that we have processed and used all buffers, but have -	 * not restocked the Rx queue with fresh buffers */ -	rxq->read = rxq->write = 0; -	rxq->write_actual = 0; -	rxq->free_count = 0; -	spin_unlock_irqrestore(&rxq->lock, flags); -} - -int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) -{ -	u32 rb_size; -	const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */ -	u32 rb_timeout = 0; /* FIXME: RX_RB_TIMEOUT for all devices? */ - -	if (!priv->cfg->use_isr_legacy) -		rb_timeout = RX_RB_TIMEOUT; - -	if (priv->cfg->mod_params->amsdu_size_8K) -		rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K; -	else -		rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K; - -	/* Stop Rx DMA */ -	iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); - -	/* Reset driver's Rx queue write index */ -	iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0); - -	/* Tell device where to find RBD circular buffer in DRAM */ -	iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_BASE_REG, -			   (u32)(rxq->dma_addr >> 8)); - -	/* Tell device where in DRAM to update its Rx status */ -	iwl_write_direct32(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG, -			   rxq->rb_stts_dma >> 4); - -	/* Enable Rx DMA -	 * FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY is set because of HW bug in -	 *      the credit mechanism in 5000 HW RX FIFO -	 * Direct rx interrupts to hosts -	 * Rx buffer size 4 or 8k -	 * RB timeout 0x10 -	 * 256 RBDs -	 */ -	iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, -			   FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL | -			   FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY | -			   FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL | -			   FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MSK | -			   rb_size| -			   (rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)| -			   (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS)); - -	/* Set interrupt coalescing timer to default (2048 usecs) */ -	iwl_write8(priv, CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF); - -	return 0; -} - -int iwl_rxq_stop(struct iwl_priv *priv) -{ - -	/* stop Rx DMA */ -	iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); -	iwl_poll_direct_bit(priv, FH_MEM_RSSR_RX_STATUS_REG, -			    FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000); - -	return 0; -} -EXPORT_SYMBOL(iwl_rxq_stop); -  void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,  				struct iwl_rx_mem_buffer *rxb) @@ -542,6 +260,7 @@ static void iwl_rx_calc_noise(struct iwl_priv *priv)  		le32_to_cpu(rx_info->beacon_silence_rssi_b) & IN_BAND_FILTER;  	int bcn_silence_c =  		le32_to_cpu(rx_info->beacon_silence_rssi_c) & IN_BAND_FILTER; +	int last_rx_noise;  	if (bcn_silence_a) {  		total_silence += bcn_silence_a; @@ -558,13 +277,13 @@ static void iwl_rx_calc_noise(struct iwl_priv *priv)  	/* Average among active antennas */  	if (num_active_rx) -		priv->last_rx_noise = (total_silence / num_active_rx) - 107; +		last_rx_noise = (total_silence / num_active_rx) - 107;  	else -		priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; +		last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;  	IWL_DEBUG_CALIB(priv, "inband silence a %u, b %u, c %u, dBm %d\n",  			bcn_silence_a, bcn_silence_b, bcn_silence_c, -			priv->last_rx_noise); +			last_rx_noise);  }  #ifdef CONFIG_IWLWIFI_DEBUG @@ -616,29 +335,20 @@ static void iwl_accumulative_statistics(struct iwl_priv *priv,  #define REG_RECALIB_PERIOD (60) -#define PLCP_MSG "plcp_err exceeded %u, %u, %u, %u, %u, %d, %u mSecs\n" -void iwl_rx_statistics(struct iwl_priv *priv, -			      struct iwl_rx_mem_buffer *rxb) +/** + * iwl_good_plcp_health - checks for plcp error. + * + * When the plcp error is exceeding the thresholds, reset the radio + * to improve the throughput. + */ +bool iwl_good_plcp_health(struct iwl_priv *priv, +				struct iwl_rx_packet *pkt)  { -	int change; -	struct iwl_rx_packet *pkt = rxb_addr(rxb); +	bool rc = true;  	int combined_plcp_delta;  	unsigned int plcp_msec;  	unsigned long plcp_received_jiffies; -	IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n", -		     (int)sizeof(priv->statistics), -		     le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK); - -	change = ((priv->statistics.general.temperature != -		   pkt->u.stats.general.temperature) || -		  ((priv->statistics.flag & -		    STATISTICS_REPLY_FLG_HT40_MODE_MSK) != -		   (pkt->u.stats.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK))); - -#ifdef CONFIG_IWLWIFI_DEBUG -	iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats); -#endif  	/*  	 * check for plcp_err and trigger radio reset if it exceeds  	 * the plcp error threshold plcp_delta. @@ -659,11 +369,11 @@ void iwl_rx_statistics(struct iwl_priv *priv,  			le32_to_cpu(priv->statistics.rx.ofdm_ht.plcp_err));  		if ((combined_plcp_delta > 0) && -			((combined_plcp_delta * 100) / plcp_msec) > +		    ((combined_plcp_delta * 100) / plcp_msec) >  			priv->cfg->plcp_delta_threshold) {  			/* -			 * if plcp_err exceed the threshold, the following -			 * data is printed in csv format: +			 * if plcp_err exceed the threshold, +			 * the following data is printed in csv format:  			 *    Text: plcp_err exceeded %d,  			 *    Received ofdm.plcp_err,  			 *    Current ofdm.plcp_err, @@ -672,22 +382,73 @@ void iwl_rx_statistics(struct iwl_priv *priv,  			 *    combined_plcp_delta,  			 *    plcp_msec  			 */ -			IWL_DEBUG_RADIO(priv, PLCP_MSG, +			IWL_DEBUG_RADIO(priv, "plcp_err exceeded %u, " +				"%u, %u, %u, %u, %d, %u mSecs\n",  				priv->cfg->plcp_delta_threshold,  				le32_to_cpu(pkt->u.stats.rx.ofdm.plcp_err),  				le32_to_cpu(priv->statistics.rx.ofdm.plcp_err),  				le32_to_cpu(pkt->u.stats.rx.ofdm_ht.plcp_err),  				le32_to_cpu( -					priv->statistics.rx.ofdm_ht.plcp_err), +				  priv->statistics.rx.ofdm_ht.plcp_err),  				combined_plcp_delta, plcp_msec); +			rc = false; +		} +	} +	return rc; +} +EXPORT_SYMBOL(iwl_good_plcp_health); -			/* -			 * Reset the RF radio due to the high plcp -			 * error rate -			 */ -			iwl_force_reset(priv, IWL_RF_RESET); +static void iwl_recover_from_statistics(struct iwl_priv *priv, +				struct iwl_rx_packet *pkt) +{ +	if (test_bit(STATUS_EXIT_PENDING, &priv->status)) +		return; +	if (iwl_is_associated(priv)) { +		if (priv->cfg->ops->lib->check_ack_health) { +			if (!priv->cfg->ops->lib->check_ack_health( +			    priv, pkt)) { +				/* +				 * low ack count detected +				 * restart Firmware +				 */ +				IWL_ERR(priv, "low ack count detected, " +					"restart firmware\n"); +				iwl_force_reset(priv, IWL_FW_RESET); +			} +		} else if (priv->cfg->ops->lib->check_plcp_health) { +			if (!priv->cfg->ops->lib->check_plcp_health( +			    priv, pkt)) { +				/* +				 * high plcp error detected +				 * reset Radio +				 */ +				iwl_force_reset(priv, IWL_RF_RESET); +			}  		}  	} +} + +void iwl_rx_statistics(struct iwl_priv *priv, +			      struct iwl_rx_mem_buffer *rxb) +{ +	int change; +	struct iwl_rx_packet *pkt = rxb_addr(rxb); + + +	IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n", +		     (int)sizeof(priv->statistics), +		     le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK); + +	change = ((priv->statistics.general.temperature != +		   pkt->u.stats.general.temperature) || +		  ((priv->statistics.flag & +		    STATISTICS_REPLY_FLG_HT40_MODE_MSK) != +		   (pkt->u.stats.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK))); + +#ifdef CONFIG_IWLWIFI_DEBUG +	iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats); +#endif +	iwl_recover_from_statistics(priv, pkt);  	memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics)); @@ -730,139 +491,6 @@ void iwl_reply_statistics(struct iwl_priv *priv,  }  EXPORT_SYMBOL(iwl_reply_statistics); -/* Calc max signal level (dBm) among 3 possible receivers */ -static inline int iwl_calc_rssi(struct iwl_priv *priv, -				struct iwl_rx_phy_res *rx_resp) -{ -	return priv->cfg->ops->utils->calc_rssi(priv, rx_resp); -} - -#ifdef CONFIG_IWLWIFI_DEBUG -/** - * iwl_dbg_report_frame - dump frame to syslog during debug sessions - * - * You may hack this function to show different aspects of received frames, - * including selective frame dumps. - * group100 parameter selects whether to show 1 out of 100 good data frames. - *    All beacon and probe response frames are printed. - */ -static void iwl_dbg_report_frame(struct iwl_priv *priv, -		      struct iwl_rx_phy_res *phy_res, u16 length, -		      struct ieee80211_hdr *header, int group100) -{ -	u32 to_us; -	u32 print_summary = 0; -	u32 print_dump = 0;	/* set to 1 to dump all frames' contents */ -	u32 hundred = 0; -	u32 dataframe = 0; -	__le16 fc; -	u16 seq_ctl; -	u16 channel; -	u16 phy_flags; -	u32 rate_n_flags; -	u32 tsf_low; -	int rssi; - -	if (likely(!(iwl_get_debug_level(priv) & IWL_DL_RX))) -		return; - -	/* MAC header */ -	fc = header->frame_control; -	seq_ctl = le16_to_cpu(header->seq_ctrl); - -	/* metadata */ -	channel = le16_to_cpu(phy_res->channel); -	phy_flags = le16_to_cpu(phy_res->phy_flags); -	rate_n_flags = le32_to_cpu(phy_res->rate_n_flags); - -	/* signal statistics */ -	rssi = iwl_calc_rssi(priv, phy_res); -	tsf_low = le64_to_cpu(phy_res->timestamp) & 0x0ffffffff; - -	to_us = !compare_ether_addr(header->addr1, priv->mac_addr); - -	/* if data frame is to us and all is good, -	 *   (optionally) print summary for only 1 out of every 100 */ -	if (to_us && (fc & ~cpu_to_le16(IEEE80211_FCTL_PROTECTED)) == -	    cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) { -		dataframe = 1; -		if (!group100) -			print_summary = 1;	/* print each frame */ -		else if (priv->framecnt_to_us < 100) { -			priv->framecnt_to_us++; -			print_summary = 0; -		} else { -			priv->framecnt_to_us = 0; -			print_summary = 1; -			hundred = 1; -		} -	} else { -		/* print summary for all other frames */ -		print_summary = 1; -	} - -	if (print_summary) { -		char *title; -		int rate_idx; -		u32 bitrate; - -		if (hundred) -			title = "100Frames"; -		else if (ieee80211_has_retry(fc)) -			title = "Retry"; -		else if (ieee80211_is_assoc_resp(fc)) -			title = "AscRsp"; -		else if (ieee80211_is_reassoc_resp(fc)) -			title = "RasRsp"; -		else if (ieee80211_is_probe_resp(fc)) { -			title = "PrbRsp"; -			print_dump = 1;	/* dump frame contents */ -		} else if (ieee80211_is_beacon(fc)) { -			title = "Beacon"; -			print_dump = 1;	/* dump frame contents */ -		} else if (ieee80211_is_atim(fc)) -			title = "ATIM"; -		else if (ieee80211_is_auth(fc)) -			title = "Auth"; -		else if (ieee80211_is_deauth(fc)) -			title = "DeAuth"; -		else if (ieee80211_is_disassoc(fc)) -			title = "DisAssoc"; -		else -			title = "Frame"; - -		rate_idx = iwl_hwrate_to_plcp_idx(rate_n_flags); -		if (unlikely((rate_idx < 0) || (rate_idx >= IWL_RATE_COUNT))) { -			bitrate = 0; -			WARN_ON_ONCE(1); -		} else { -			bitrate = iwl_rates[rate_idx].ieee / 2; -		} - -		/* print frame summary. -		 * MAC addresses show just the last byte (for brevity), -		 *    but you can hack it to show more, if you'd like to. */ -		if (dataframe) -			IWL_DEBUG_RX(priv, "%s: mhd=0x%04x, dst=0x%02x, " -				     "len=%u, rssi=%d, chnl=%d, rate=%u, \n", -				     title, le16_to_cpu(fc), header->addr1[5], -				     length, rssi, channel, bitrate); -		else { -			/* src/dst addresses assume managed mode */ -			IWL_DEBUG_RX(priv, "%s: 0x%04x, dst=0x%02x, src=0x%02x, " -				     "len=%u, rssi=%d, tim=%lu usec, " -				     "phy=0x%02x, chnl=%d\n", -				     title, le16_to_cpu(fc), header->addr1[5], -				     header->addr3[5], length, rssi, -				     tsf_low - priv->scan_start_tsf, -				     phy_flags, channel); -		} -	} -	if (print_dump) -		iwl_print_hex_dump(priv, IWL_DL_RX, header, length); -} -#endif -  /*   * returns non-zero if packet should be dropped   */ @@ -910,305 +538,3 @@ int iwl_set_decrypted_flag(struct iwl_priv *priv,  	return 0;  }  EXPORT_SYMBOL(iwl_set_decrypted_flag); - -static u32 iwl_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in) -{ -	u32 decrypt_out = 0; - -	if ((decrypt_in & RX_RES_STATUS_STATION_FOUND) == -					RX_RES_STATUS_STATION_FOUND) -		decrypt_out |= (RX_RES_STATUS_STATION_FOUND | -				RX_RES_STATUS_NO_STATION_INFO_MISMATCH); - -	decrypt_out |= (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK); - -	/* packet was not encrypted */ -	if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) == -					RX_RES_STATUS_SEC_TYPE_NONE) -		return decrypt_out; - -	/* packet was encrypted with unknown alg */ -	if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) == -					RX_RES_STATUS_SEC_TYPE_ERR) -		return decrypt_out; - -	/* decryption was not done in HW */ -	if ((decrypt_in & RX_MPDU_RES_STATUS_DEC_DONE_MSK) != -					RX_MPDU_RES_STATUS_DEC_DONE_MSK) -		return decrypt_out; - -	switch (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) { - -	case RX_RES_STATUS_SEC_TYPE_CCMP: -		/* alg is CCM: check MIC only */ -		if (!(decrypt_in & RX_MPDU_RES_STATUS_MIC_OK)) -			/* Bad MIC */ -			decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC; -		else -			decrypt_out |= RX_RES_STATUS_DECRYPT_OK; - -		break; - -	case RX_RES_STATUS_SEC_TYPE_TKIP: -		if (!(decrypt_in & RX_MPDU_RES_STATUS_TTAK_OK)) { -			/* Bad TTAK */ -			decrypt_out |= RX_RES_STATUS_BAD_KEY_TTAK; -			break; -		} -		/* fall through if TTAK OK */ -	default: -		if (!(decrypt_in & RX_MPDU_RES_STATUS_ICV_OK)) -			decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC; -		else -			decrypt_out |= RX_RES_STATUS_DECRYPT_OK; -		break; -	}; - -	IWL_DEBUG_RX(priv, "decrypt_in:0x%x  decrypt_out = 0x%x\n", -					decrypt_in, decrypt_out); - -	return decrypt_out; -} - -static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, -					struct ieee80211_hdr *hdr, -					u16 len, -					u32 ampdu_status, -					struct iwl_rx_mem_buffer *rxb, -					struct ieee80211_rx_status *stats) -{ -	struct sk_buff *skb; -	int ret = 0; -	__le16 fc = hdr->frame_control; - -	/* We only process data packets if the interface is open */ -	if (unlikely(!priv->is_open)) { -		IWL_DEBUG_DROP_LIMIT(priv, -		    "Dropping packet while interface is not open.\n"); -		return; -	} - -	/* In case of HW accelerated crypto and bad decryption, drop */ -	if (!priv->cfg->mod_params->sw_crypto && -	    iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats)) -		return; - -	skb = alloc_skb(IWL_LINK_HDR_MAX * 2, GFP_ATOMIC); -	if (!skb) { -		IWL_ERR(priv, "alloc_skb failed\n"); -		return; -	} - -	skb_reserve(skb, IWL_LINK_HDR_MAX); -	skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len); - -	/* mac80211 currently doesn't support paged SKB. Convert it to -	 * linear SKB for management frame and data frame requires -	 * software decryption or software defragementation. */ -	if (ieee80211_is_mgmt(fc) || -	    ieee80211_has_protected(fc) || -	    ieee80211_has_morefrags(fc) || -	    le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG || -	    (ieee80211_is_data_qos(fc) && -	     *ieee80211_get_qos_ctl(hdr) & -	     IEEE80211_QOS_CONTROL_A_MSDU_PRESENT)) -		ret = skb_linearize(skb); -	else -		ret = __pskb_pull_tail(skb, min_t(u16, IWL_LINK_HDR_MAX, len)) ? -			 0 : -ENOMEM; - -	if (ret) { -		kfree_skb(skb); -		goto out; -	} - -	/* -	 * XXX: We cannot touch the page and its virtual memory (hdr) after -	 * here. It might have already been freed by the above skb change. -	 */ - -	iwl_update_stats(priv, false, fc, len); -	memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); - -	ieee80211_rx(priv->hw, skb); - out: -	priv->alloc_rxb_page--; -	rxb->page = NULL; -} - -/* This is necessary only for a number of statistics, see the caller. */ -static int iwl_is_network_packet(struct iwl_priv *priv, -		struct ieee80211_hdr *header) -{ -	/* Filter incoming packets to determine if they are targeted toward -	 * this network, discarding packets coming from ourselves */ -	switch (priv->iw_mode) { -	case NL80211_IFTYPE_ADHOC: /* Header: Dest. | Source    | BSSID */ -		/* packets to our IBSS update information */ -		return !compare_ether_addr(header->addr3, priv->bssid); -	case NL80211_IFTYPE_STATION: /* Header: Dest. | AP{BSSID} | Source */ -		/* packets to our IBSS update information */ -		return !compare_ether_addr(header->addr2, priv->bssid); -	default: -		return 1; -	} -} - -/* Called for REPLY_RX (legacy ABG frames), or - * REPLY_RX_MPDU_CMD (HT high-throughput N frames). */ -void iwl_rx_reply_rx(struct iwl_priv *priv, -				struct iwl_rx_mem_buffer *rxb) -{ -	struct ieee80211_hdr *header; -	struct ieee80211_rx_status rx_status; -	struct iwl_rx_packet *pkt = rxb_addr(rxb); -	struct iwl_rx_phy_res *phy_res; -	__le32 rx_pkt_status; -	struct iwl4965_rx_mpdu_res_start *amsdu; -	u32 len; -	u32 ampdu_status; -	u32 rate_n_flags; - -	/** -	 * REPLY_RX and REPLY_RX_MPDU_CMD are handled differently. -	 *	REPLY_RX: physical layer info is in this buffer -	 *	REPLY_RX_MPDU_CMD: physical layer info was sent in separate -	 *		command and cached in priv->last_phy_res -	 * -	 * Here we set up local variables depending on which command is -	 * received. -	 */ -	if (pkt->hdr.cmd == REPLY_RX) { -		phy_res = (struct iwl_rx_phy_res *)pkt->u.raw; -		header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*phy_res) -				+ phy_res->cfg_phy_cnt); - -		len = le16_to_cpu(phy_res->byte_count); -		rx_pkt_status = *(__le32 *)(pkt->u.raw + sizeof(*phy_res) + -				phy_res->cfg_phy_cnt + len); -		ampdu_status = le32_to_cpu(rx_pkt_status); -	} else { -		if (!priv->last_phy_res[0]) { -			IWL_ERR(priv, "MPDU frame without cached PHY data\n"); -			return; -		} -		phy_res = (struct iwl_rx_phy_res *)&priv->last_phy_res[1]; -		amsdu = (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw; -		header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*amsdu)); -		len = le16_to_cpu(amsdu->byte_count); -		rx_pkt_status = *(__le32 *)(pkt->u.raw + sizeof(*amsdu) + len); -		ampdu_status = iwl_translate_rx_status(priv, -				le32_to_cpu(rx_pkt_status)); -	} - -	if ((unlikely(phy_res->cfg_phy_cnt > 20))) { -		IWL_DEBUG_DROP(priv, "dsp size out of range [0,20]: %d/n", -				phy_res->cfg_phy_cnt); -		return; -	} - -	if (!(rx_pkt_status & RX_RES_STATUS_NO_CRC32_ERROR) || -	    !(rx_pkt_status & RX_RES_STATUS_NO_RXE_OVERFLOW)) { -		IWL_DEBUG_RX(priv, "Bad CRC or FIFO: 0x%08X.\n", -				le32_to_cpu(rx_pkt_status)); -		return; -	} - -	/* This will be used in several places later */ -	rate_n_flags = le32_to_cpu(phy_res->rate_n_flags); - -	/* rx_status carries information about the packet to mac80211 */ -	rx_status.mactime = le64_to_cpu(phy_res->timestamp); -	rx_status.freq = -		ieee80211_channel_to_frequency(le16_to_cpu(phy_res->channel)); -	rx_status.band = (phy_res->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? -				IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; -	rx_status.rate_idx = -		iwl_hwrate_to_mac80211_idx(rate_n_flags, rx_status.band); -	rx_status.flag = 0; - -	/* TSF isn't reliable. In order to allow smooth user experience, -	 * this W/A doesn't propagate it to the mac80211 */ -	/*rx_status.flag |= RX_FLAG_TSFT;*/ - -	priv->ucode_beacon_time = le32_to_cpu(phy_res->beacon_time_stamp); - -	/* Find max signal strength (dBm) among 3 antenna/receiver chains */ -	rx_status.signal = iwl_calc_rssi(priv, phy_res); - -	/* Meaningful noise values are available only from beacon statistics, -	 *   which are gathered only when associated, and indicate noise -	 *   only for the associated network channel ... -	 * Ignore these noise values while scanning (other channels) */ -	if (iwl_is_associated(priv) && -	    !test_bit(STATUS_SCANNING, &priv->status)) { -		rx_status.noise = priv->last_rx_noise; -	} else { -		rx_status.noise = IWL_NOISE_MEAS_NOT_AVAILABLE; -	} - -	/* Reset beacon noise level if not associated. */ -	if (!iwl_is_associated(priv)) -		priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; - -#ifdef CONFIG_IWLWIFI_DEBUG -	/* Set "1" to report good data frames in groups of 100 */ -	if (unlikely(iwl_get_debug_level(priv) & IWL_DL_RX)) -		iwl_dbg_report_frame(priv, phy_res, len, header, 1); -#endif -	iwl_dbg_log_rx_data_frame(priv, len, header); -	IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, noise %d, TSF %llu\n", -		rx_status.signal, rx_status.noise, -		(unsigned long long)rx_status.mactime); - -	/* -	 * "antenna number" -	 * -	 * It seems that the antenna field in the phy flags value -	 * is actually a bit field. This is undefined by radiotap, -	 * it wants an actual antenna number but I always get "7" -	 * for most legacy frames I receive indicating that the -	 * same frame was received on all three RX chains. -	 * -	 * I think this field should be removed in favor of a -	 * new 802.11n radiotap field "RX chains" that is defined -	 * as a bitmask. -	 */ -	rx_status.antenna = -		(le16_to_cpu(phy_res->phy_flags) & RX_RES_PHY_FLAGS_ANTENNA_MSK) -		>> RX_RES_PHY_FLAGS_ANTENNA_POS; - -	/* set the preamble flag if appropriate */ -	if (phy_res->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) -		rx_status.flag |= RX_FLAG_SHORTPRE; - -	/* Set up the HT phy flags */ -	if (rate_n_flags & RATE_MCS_HT_MSK) -		rx_status.flag |= RX_FLAG_HT; -	if (rate_n_flags & RATE_MCS_HT40_MSK) -		rx_status.flag |= RX_FLAG_40MHZ; -	if (rate_n_flags & RATE_MCS_SGI_MSK) -		rx_status.flag |= RX_FLAG_SHORT_GI; - -	if (iwl_is_network_packet(priv, header)) { -		priv->last_rx_rssi = rx_status.signal; -		priv->last_beacon_time =  priv->ucode_beacon_time; -		priv->last_tsf = le64_to_cpu(phy_res->timestamp); -	} - -	iwl_pass_packet_to_mac80211(priv, header, len, ampdu_status, -				    rxb, &rx_status); -} -EXPORT_SYMBOL(iwl_rx_reply_rx); - -/* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD). - * This will be used later in iwl_rx_reply_rx() for REPLY_RX_MPDU_CMD. */ -void iwl_rx_reply_rx_phy(struct iwl_priv *priv, -				    struct iwl_rx_mem_buffer *rxb) -{ -	struct iwl_rx_packet *pkt = rxb_addr(rxb); -	priv->last_phy_res[0] = 1; -	memcpy(&priv->last_phy_res[1], &(pkt->u.raw[0]), -	       sizeof(struct iwl_rx_phy_res)); -} -EXPORT_SYMBOL(iwl_rx_reply_rx_phy);  |