diff options
Diffstat (limited to 'drivers/net/wireless')
56 files changed, 1119 insertions, 1180 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index 4cc13940c89..f76c3ca07a4 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -1023,6 +1023,7 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,  					  AR_PHY_AGC_CONTROL_FLTR_CAL   |  					  AR_PHY_AGC_CONTROL_PKDET_CAL; +	/* Use chip chainmask only for calibration */  	ar9003_hw_set_chain_masks(ah, ah->caps.rx_chainmask, ah->caps.tx_chainmask);  	if (rtt) { @@ -1150,6 +1151,9 @@ skip_tx_iqcal:  		ar9003_hw_rtt_disable(ah);  	} +	/* Revert chainmask to runtime parameters */ +	ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask); +  	/* Initialize list pointers */  	ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; diff --git a/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h index 28fd99203f6..bdee2ed6721 100644 --- a/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h @@ -519,7 +519,7 @@ static const u32 ar9580_1p0_mac_core[][2] = {  	{0x00008258, 0x00000000},  	{0x0000825c, 0x40000000},  	{0x00008260, 0x00080922}, -	{0x00008264, 0x9bc00010}, +	{0x00008264, 0x9d400010},  	{0x00008268, 0xffffffff},  	{0x0000826c, 0x0000ffff},  	{0x00008270, 0x00000000}, diff --git a/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c b/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c index 467b60014b7..73fe8d6db56 100644 --- a/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c +++ b/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c @@ -143,14 +143,14 @@ channel_detector_create(struct dfs_pattern_detector *dpd, u16 freq)  	u32 sz, i;  	struct channel_detector *cd; -	cd = kmalloc(sizeof(*cd), GFP_KERNEL); +	cd = kmalloc(sizeof(*cd), GFP_ATOMIC);  	if (cd == NULL)  		goto fail;  	INIT_LIST_HEAD(&cd->head);  	cd->freq = freq;  	sz = sizeof(cd->detectors) * dpd->num_radar_types; -	cd->detectors = kzalloc(sz, GFP_KERNEL); +	cd->detectors = kzalloc(sz, GFP_ATOMIC);  	if (cd->detectors == NULL)  		goto fail; diff --git a/drivers/net/wireless/ath/ath9k/dfs_pri_detector.c b/drivers/net/wireless/ath/ath9k/dfs_pri_detector.c index 91b8dceeadb..5e48c5515b8 100644 --- a/drivers/net/wireless/ath/ath9k/dfs_pri_detector.c +++ b/drivers/net/wireless/ath/ath9k/dfs_pri_detector.c @@ -218,7 +218,7 @@ static bool pulse_queue_enqueue(struct pri_detector *pde, u64 ts)  {  	struct pulse_elem *p = pool_get_pulse_elem();  	if (p == NULL) { -		p = kmalloc(sizeof(*p), GFP_KERNEL); +		p = kmalloc(sizeof(*p), GFP_ATOMIC);  		if (p == NULL) {  			DFS_POOL_STAT_INC(pulse_alloc_error);  			return false; @@ -299,7 +299,7 @@ static bool pseq_handler_create_sequences(struct pri_detector *pde,  		ps.deadline_ts = ps.first_ts + ps.dur;  		new_ps = pool_get_pseq_elem();  		if (new_ps == NULL) { -			new_ps = kmalloc(sizeof(*new_ps), GFP_KERNEL); +			new_ps = kmalloc(sizeof(*new_ps), GFP_ATOMIC);  			if (new_ps == NULL) {  				DFS_POOL_STAT_INC(pseq_alloc_error);  				return false; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 716058b6755..a47f5e05fc0 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -796,7 +796,7 @@ static int ath9k_init_firmware_version(struct ath9k_htc_priv *priv)  	 * required version.  	 */  	if (priv->fw_version_major != MAJOR_VERSION_REQ || -	    priv->fw_version_minor != MINOR_VERSION_REQ) { +	    priv->fw_version_minor < MINOR_VERSION_REQ) {  		dev_err(priv->dev, "ath9k_htc: Please upgrade to FW version %d.%d\n",  			MAJOR_VERSION_REQ, MINOR_VERSION_REQ);  		return -EINVAL; diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c index ade3afb21f9..7fdac6c7b3e 100644 --- a/drivers/net/wireless/ath/ath9k/link.c +++ b/drivers/net/wireless/ath/ath9k/link.c @@ -28,21 +28,21 @@ void ath_tx_complete_poll_work(struct work_struct *work)  	int i;  	bool needreset = false; -	for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) -		if (ATH_TXQ_SETUP(sc, i)) { -			txq = &sc->tx.txq[i]; -			ath_txq_lock(sc, txq); -			if (txq->axq_depth) { -				if (txq->axq_tx_inprogress) { -					needreset = true; -					ath_txq_unlock(sc, txq); -					break; -				} else { -					txq->axq_tx_inprogress = true; -				} +	for (i = 0; i < IEEE80211_NUM_ACS; i++) { +		txq = sc->tx.txq_map[i]; + +		ath_txq_lock(sc, txq); +		if (txq->axq_depth) { +			if (txq->axq_tx_inprogress) { +				needreset = true; +				ath_txq_unlock(sc, txq); +				break; +			} else { +				txq->axq_tx_inprogress = true;  			} -			ath_txq_unlock_complete(sc, txq);  		} +		ath_txq_unlock_complete(sc, txq); +	}  	if (needreset) {  		ath_dbg(ath9k_hw_common(sc->sc_ah), RESET, @@ -170,7 +170,8 @@ void ath_rx_poll(unsigned long data)  {  	struct ath_softc *sc = (struct ath_softc *)data; -	ieee80211_queue_work(sc->hw, &sc->hw_check_work); +	if (!test_bit(SC_OP_INVALID, &sc->sc_flags)) +		ieee80211_queue_work(sc->hw, &sc->hw_check_work);  }  /* diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 6e66f9c6782..988372d218a 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -280,6 +280,10 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan)  	if (r) {  		ath_err(common,  			"Unable to reset channel, reset status %d\n", r); + +		ath9k_hw_enable_interrupts(ah); +		ath9k_queue_reset(sc, RESET_TYPE_BB_HANG); +  		goto out;  	} diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index 38bc5a7997f..122146943bf 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -1487,8 +1487,12 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,  	const struct b43_dma_ops *ops;  	struct b43_dmaring *ring;  	struct b43_dmadesc_meta *meta; +	static const struct b43_txstatus fake; /* filled with 0 */ +	const struct b43_txstatus *txstat;  	int slot, firstused;  	bool frame_succeed; +	int skip; +	static u8 err_out1, err_out2;  	ring = parse_cookie(dev, status->cookie, &slot);  	if (unlikely(!ring)) @@ -1501,13 +1505,36 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,  	firstused = ring->current_slot - ring->used_slots + 1;  	if (firstused < 0)  		firstused = ring->nr_slots + firstused; + +	skip = 0;  	if (unlikely(slot != firstused)) {  		/* This possibly is a firmware bug and will result in -		 * malfunction, memory leaks and/or stall of DMA functionality. */ -		b43dbg(dev->wl, "Out of order TX status report on DMA ring %d. " -		       "Expected %d, but got %d\n", -		       ring->index, firstused, slot); -		return; +		 * malfunction, memory leaks and/or stall of DMA functionality. +		 */ +		if (slot == next_slot(ring, next_slot(ring, firstused))) { +			/* If a single header/data pair was missed, skip over +			 * the first two slots in an attempt to recover. +			 */ +			slot = firstused; +			skip = 2; +			if (!err_out1) { +				/* Report the error once. */ +				b43dbg(dev->wl, +				       "Skip on DMA ring %d slot %d.\n", +				       ring->index, slot); +				err_out1 = 1; +			} +		} else { +			/* More than a single header/data pair were missed. +			 * Report this error once. +			 */ +			if (!err_out2) +				b43dbg(dev->wl, +				       "Out of order TX status report on DMA ring %d. Expected %d, but got %d\n", +				       ring->index, firstused, slot); +			err_out2 = 1; +			return; +		}  	}  	ops = ring->ops; @@ -1522,11 +1549,13 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,  			       slot, firstused, ring->index);  			break;  		} +  		if (meta->skb) {  			struct b43_private_tx_info *priv_info = -				b43_get_priv_tx_info(IEEE80211_SKB_CB(meta->skb)); +			     b43_get_priv_tx_info(IEEE80211_SKB_CB(meta->skb)); -			unmap_descbuffer(ring, meta->dmaaddr, meta->skb->len, 1); +			unmap_descbuffer(ring, meta->dmaaddr, +					 meta->skb->len, 1);  			kfree(priv_info->bouncebuffer);  			priv_info->bouncebuffer = NULL;  		} else { @@ -1538,8 +1567,9 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,  			struct ieee80211_tx_info *info;  			if (unlikely(!meta->skb)) { -				/* This is a scatter-gather fragment of a frame, so -				 * the skb pointer must not be NULL. */ +				/* This is a scatter-gather fragment of a frame, +				 * so the skb pointer must not be NULL. +				 */  				b43dbg(dev->wl, "TX status unexpected NULL skb "  				       "at slot %d (first=%d) on ring %d\n",  				       slot, firstused, ring->index); @@ -1550,9 +1580,18 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,  			/*  			 * Call back to inform the ieee80211 subsystem about -			 * the status of the transmission. +			 * the status of the transmission. When skipping over +			 * a missed TX status report, use a status structure +			 * filled with zeros to indicate that the frame was not +			 * sent (frame_count 0) and not acknowledged  			 */ -			frame_succeed = b43_fill_txstatus_report(dev, info, status); +			if (unlikely(skip)) +				txstat = &fake; +			else +				txstat = status; + +			frame_succeed = b43_fill_txstatus_report(dev, info, +								 txstat);  #ifdef CONFIG_B43_DEBUG  			if (frame_succeed)  				ring->nr_succeed_tx_packets++; @@ -1580,12 +1619,14 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,  		/* Everything unmapped and free'd. So it's not used anymore. */  		ring->used_slots--; -		if (meta->is_last_fragment) { +		if (meta->is_last_fragment && !skip) {  			/* This is the last scatter-gather  			 * fragment of the frame. We are done. */  			break;  		}  		slot = next_slot(ring, slot); +		if (skip > 0) +			--skip;  	}  	if (ring->stopped) {  		B43_WARN_ON(free_slots(ring) < TX_SLOTS_PER_FRAME); diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 3c35382ee6c..b70f220bc4b 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -1564,7 +1564,7 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev)  	u16 clip_off[2] = { 0xFFFF, 0xFFFF };  	u8 vcm_final = 0; -	s8 offset[4]; +	s32 offset[4];  	s32 results[8][4] = { };  	s32 results_min[4] = { };  	s32 poll_results[4] = { }; @@ -1615,7 +1615,7 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev)  		}  		for (i = 0; i < 4; i += 2) {  			s32 curr; -			s32 mind = 40; +			s32 mind = 0x100000;  			s32 minpoll = 249;  			u8 minvcm = 0;  			if (2 * core != i) @@ -1732,7 +1732,7 @@ static void b43_nphy_rev2_rssi_cal(struct b43_wldev *dev, u8 type)  	u8 regs_save_radio[2];  	u16 regs_save_phy[2]; -	s8 offset[4]; +	s32 offset[4];  	u8 core;  	u8 rail; @@ -1799,7 +1799,7 @@ static void b43_nphy_rev2_rssi_cal(struct b43_wldev *dev, u8 type)  	}  	for (i = 0; i < 4; i++) { -		s32 mind = 40; +		s32 mind = 0x100000;  		u8 minvcm = 0;  		s32 minpoll = 249;  		s32 curr; @@ -5165,7 +5165,8 @@ static void b43_nphy_pmu_spur_avoid(struct b43_wldev *dev, bool avoid)  #endif  #ifdef CONFIG_B43_SSB  	case B43_BUS_SSB: -		/* FIXME */ +		ssb_pmu_spuravoid_pllupdate(&dev->dev->sdev->bus->chipco, +					    avoid);  		break;  #endif  	} diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index 4469321c0eb..35fc68be158 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -3317,15 +3317,15 @@ static int _brcmf_sdbrcm_download_firmware(struct brcmf_sdio *bus)  		goto err;  	} -	/* External image takes precedence if specified */  	if (brcmf_sdbrcm_download_code_file(bus)) {  		brcmf_err("dongle image file download failed\n");  		goto err;  	} -	/* External nvram takes precedence if specified */ -	if (brcmf_sdbrcm_download_nvram(bus)) +	if (brcmf_sdbrcm_download_nvram(bus)) {  		brcmf_err("dongle nvram file download failed\n"); +		goto err; +	}  	/* Take arm out of reset */  	if (brcmf_sdbrcm_download_state(bus, false)) { diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 2af9c0f0798..78da3eff75e 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -1891,8 +1891,10 @@ static s32  brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,  	      u8 key_idx, const u8 *mac_addr, struct key_params *params)  { +	struct brcmf_if *ifp = netdev_priv(ndev);  	struct brcmf_wsec_key key;  	s32 err = 0; +	u8 keybuf[8];  	memset(&key, 0, sizeof(key));  	key.index = (u32) key_idx; @@ -1916,8 +1918,9 @@ brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,  		brcmf_dbg(CONN, "Setting the key index %d\n", key.index);  		memcpy(key.data, params->key, key.len); -		if (params->cipher == WLAN_CIPHER_SUITE_TKIP) { -			u8 keybuf[8]; +		if ((ifp->vif->mode != WL_MODE_AP) && +		    (params->cipher == WLAN_CIPHER_SUITE_TKIP)) { +			brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");  			memcpy(keybuf, &key.data[24], sizeof(keybuf));  			memcpy(&key.data[24], &key.data[16], sizeof(keybuf));  			memcpy(&key.data[16], keybuf, sizeof(keybuf)); @@ -2013,7 +2016,7 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,  		break;  	case WLAN_CIPHER_SUITE_TKIP:  		if (ifp->vif->mode != WL_MODE_AP) { -			brcmf_dbg(CONN, "Swapping key\n"); +			brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");  			memcpy(keybuf, &key.data[24], sizeof(keybuf));  			memcpy(&key.data[24], &key.data[16], sizeof(keybuf));  			memcpy(&key.data[16], keybuf, sizeof(keybuf)); @@ -2118,8 +2121,7 @@ brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,  		err = -EAGAIN;  		goto done;  	} -	switch (wsec & ~SES_OW_ENABLED) { -	case WEP_ENABLED: +	if (wsec & WEP_ENABLED) {  		sec = &profile->sec;  		if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {  			params.cipher = WLAN_CIPHER_SUITE_WEP40; @@ -2128,16 +2130,13 @@ brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,  			params.cipher = WLAN_CIPHER_SUITE_WEP104;  			brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");  		} -		break; -	case TKIP_ENABLED: +	} else if (wsec & TKIP_ENABLED) {  		params.cipher = WLAN_CIPHER_SUITE_TKIP;  		brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n"); -		break; -	case AES_ENABLED: +	} else if (wsec & AES_ENABLED) {  		params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;  		brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n"); -		break; -	default: +	} else  {  		brcmf_err("Invalid algo (0x%x)\n", wsec);  		err = -EINVAL;  		goto done; @@ -3824,8 +3823,9 @@ exit:  static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)  {  	struct brcmf_if *ifp = netdev_priv(ndev); -	s32 err = -EPERM; +	s32 err;  	struct brcmf_fil_bss_enable_le bss_enable; +	struct brcmf_join_params join_params;  	brcmf_dbg(TRACE, "Enter\n"); @@ -3833,16 +3833,21 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)  		/* Due to most likely deauths outstanding we sleep */  		/* first to make sure they get processed by fw. */  		msleep(400); -		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0); -		if (err < 0) { -			brcmf_err("setting AP mode failed %d\n", err); -			goto exit; -		} + +		memset(&join_params, 0, sizeof(join_params)); +		err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID, +					     &join_params, sizeof(join_params)); +		if (err < 0) +			brcmf_err("SET SSID error (%d)\n", err);  		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0); -		if (err < 0) { +		if (err < 0)  			brcmf_err("BRCMF_C_UP error %d\n", err); -			goto exit; -		} +		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0); +		if (err < 0) +			brcmf_err("setting AP mode failed %d\n", err); +		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 0); +		if (err < 0) +			brcmf_err("setting INFRA mode failed %d\n", err);  	} else {  		bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx);  		bss_enable.enable = cpu_to_le32(0); @@ -3855,7 +3860,6 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)  	set_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);  	clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state); -exit:  	return err;  } @@ -4124,10 +4128,6 @@ static const struct ieee80211_iface_limit brcmf_iface_limits[] = {  	},  	{  		.max = 1, -		.types = BIT(NL80211_IFTYPE_P2P_DEVICE) -	}, -	{ -		.max = 1,  		.types = BIT(NL80211_IFTYPE_P2P_CLIENT) |  			 BIT(NL80211_IFTYPE_P2P_GO)  	}, @@ -4183,8 +4183,7 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev)  				 BIT(NL80211_IFTYPE_ADHOC) |  				 BIT(NL80211_IFTYPE_AP) |  				 BIT(NL80211_IFTYPE_P2P_CLIENT) | -				 BIT(NL80211_IFTYPE_P2P_GO) | -				 BIT(NL80211_IFTYPE_P2P_DEVICE); +				 BIT(NL80211_IFTYPE_P2P_GO);  	wiphy->iface_combinations = brcmf_iface_combos;  	wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos);  	wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index c6451c61407..e2340b231aa 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c @@ -274,6 +274,130 @@ static void brcms_set_basic_rate(struct brcm_rateset *rs, u16 rate, bool is_br)  	}  } +/** + * This function frees the WL per-device resources. + * + * This function frees resources owned by the WL device pointed to + * by the wl parameter. + * + * precondition: can both be called locked and unlocked + * + */ +static void brcms_free(struct brcms_info *wl) +{ +	struct brcms_timer *t, *next; + +	/* free ucode data */ +	if (wl->fw.fw_cnt) +		brcms_ucode_data_free(&wl->ucode); +	if (wl->irq) +		free_irq(wl->irq, wl); + +	/* kill dpc */ +	tasklet_kill(&wl->tasklet); + +	if (wl->pub) { +		brcms_debugfs_detach(wl->pub); +		brcms_c_module_unregister(wl->pub, "linux", wl); +	} + +	/* free common resources */ +	if (wl->wlc) { +		brcms_c_detach(wl->wlc); +		wl->wlc = NULL; +		wl->pub = NULL; +	} + +	/* virtual interface deletion is deferred so we cannot spinwait */ + +	/* wait for all pending callbacks to complete */ +	while (atomic_read(&wl->callbacks) > 0) +		schedule(); + +	/* free timers */ +	for (t = wl->timers; t; t = next) { +		next = t->next; +#ifdef DEBUG +		kfree(t->name); +#endif +		kfree(t); +	} +} + +/* +* called from both kernel as from this kernel module (error flow on attach) +* precondition: perimeter lock is not acquired. +*/ +static void brcms_remove(struct bcma_device *pdev) +{ +	struct ieee80211_hw *hw = bcma_get_drvdata(pdev); +	struct brcms_info *wl = hw->priv; + +	if (wl->wlc) { +		wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, false); +		wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy); +		ieee80211_unregister_hw(hw); +	} + +	brcms_free(wl); + +	bcma_set_drvdata(pdev, NULL); +	ieee80211_free_hw(hw); +} + +/* + * Precondition: Since this function is called in brcms_pci_probe() context, + * no locking is required. + */ +static void brcms_release_fw(struct brcms_info *wl) +{ +	int i; +	for (i = 0; i < MAX_FW_IMAGES; i++) { +		release_firmware(wl->fw.fw_bin[i]); +		release_firmware(wl->fw.fw_hdr[i]); +	} +} + +/* + * Precondition: Since this function is called in brcms_pci_probe() context, + * no locking is required. + */ +static int brcms_request_fw(struct brcms_info *wl, struct bcma_device *pdev) +{ +	int status; +	struct device *device = &pdev->dev; +	char fw_name[100]; +	int i; + +	memset(&wl->fw, 0, sizeof(struct brcms_firmware)); +	for (i = 0; i < MAX_FW_IMAGES; i++) { +		if (brcms_firmwares[i] == NULL) +			break; +		sprintf(fw_name, "%s-%d.fw", brcms_firmwares[i], +			UCODE_LOADER_API_VER); +		status = request_firmware(&wl->fw.fw_bin[i], fw_name, device); +		if (status) { +			wiphy_err(wl->wiphy, "%s: fail to load firmware %s\n", +				  KBUILD_MODNAME, fw_name); +			return status; +		} +		sprintf(fw_name, "%s_hdr-%d.fw", brcms_firmwares[i], +			UCODE_LOADER_API_VER); +		status = request_firmware(&wl->fw.fw_hdr[i], fw_name, device); +		if (status) { +			wiphy_err(wl->wiphy, "%s: fail to load firmware %s\n", +				  KBUILD_MODNAME, fw_name); +			return status; +		} +		wl->fw.hdr_num_entries[i] = +		    wl->fw.fw_hdr[i]->size / (sizeof(struct firmware_hdr)); +	} +	wl->fw.fw_cnt = i; +	status = brcms_ucode_data_init(wl, &wl->ucode); +	brcms_release_fw(wl); +	return status; +} +  static void brcms_ops_tx(struct ieee80211_hw *hw,  			 struct ieee80211_tx_control *control,  			 struct sk_buff *skb) @@ -306,6 +430,14 @@ static int brcms_ops_start(struct ieee80211_hw *hw)  	if (!blocked)  		wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy); +	if (!wl->ucode.bcm43xx_bomminor) { +		err = brcms_request_fw(wl, wl->wlc->hw->d11core); +		if (err) { +			brcms_remove(wl->wlc->hw->d11core); +			return -ENOENT; +		} +	} +  	spin_lock_bh(&wl->lock);  	/* avoid acknowledging frames before a non-monitor device is added */  	wl->mute_tx = true; @@ -793,128 +925,6 @@ void brcms_dpc(unsigned long data)  	wake_up(&wl->tx_flush_wq);  } -/* - * Precondition: Since this function is called in brcms_pci_probe() context, - * no locking is required. - */ -static int brcms_request_fw(struct brcms_info *wl, struct bcma_device *pdev) -{ -	int status; -	struct device *device = &pdev->dev; -	char fw_name[100]; -	int i; - -	memset(&wl->fw, 0, sizeof(struct brcms_firmware)); -	for (i = 0; i < MAX_FW_IMAGES; i++) { -		if (brcms_firmwares[i] == NULL) -			break; -		sprintf(fw_name, "%s-%d.fw", brcms_firmwares[i], -			UCODE_LOADER_API_VER); -		status = request_firmware(&wl->fw.fw_bin[i], fw_name, device); -		if (status) { -			wiphy_err(wl->wiphy, "%s: fail to load firmware %s\n", -				  KBUILD_MODNAME, fw_name); -			return status; -		} -		sprintf(fw_name, "%s_hdr-%d.fw", brcms_firmwares[i], -			UCODE_LOADER_API_VER); -		status = request_firmware(&wl->fw.fw_hdr[i], fw_name, device); -		if (status) { -			wiphy_err(wl->wiphy, "%s: fail to load firmware %s\n", -				  KBUILD_MODNAME, fw_name); -			return status; -		} -		wl->fw.hdr_num_entries[i] = -		    wl->fw.fw_hdr[i]->size / (sizeof(struct firmware_hdr)); -	} -	wl->fw.fw_cnt = i; -	return brcms_ucode_data_init(wl, &wl->ucode); -} - -/* - * Precondition: Since this function is called in brcms_pci_probe() context, - * no locking is required. - */ -static void brcms_release_fw(struct brcms_info *wl) -{ -	int i; -	for (i = 0; i < MAX_FW_IMAGES; i++) { -		release_firmware(wl->fw.fw_bin[i]); -		release_firmware(wl->fw.fw_hdr[i]); -	} -} - -/** - * This function frees the WL per-device resources. - * - * This function frees resources owned by the WL device pointed to - * by the wl parameter. - * - * precondition: can both be called locked and unlocked - * - */ -static void brcms_free(struct brcms_info *wl) -{ -	struct brcms_timer *t, *next; - -	/* free ucode data */ -	if (wl->fw.fw_cnt) -		brcms_ucode_data_free(&wl->ucode); -	if (wl->irq) -		free_irq(wl->irq, wl); - -	/* kill dpc */ -	tasklet_kill(&wl->tasklet); - -	if (wl->pub) { -		brcms_debugfs_detach(wl->pub); -		brcms_c_module_unregister(wl->pub, "linux", wl); -	} - -	/* free common resources */ -	if (wl->wlc) { -		brcms_c_detach(wl->wlc); -		wl->wlc = NULL; -		wl->pub = NULL; -	} - -	/* virtual interface deletion is deferred so we cannot spinwait */ - -	/* wait for all pending callbacks to complete */ -	while (atomic_read(&wl->callbacks) > 0) -		schedule(); - -	/* free timers */ -	for (t = wl->timers; t; t = next) { -		next = t->next; -#ifdef DEBUG -		kfree(t->name); -#endif -		kfree(t); -	} -} - -/* -* called from both kernel as from this kernel module (error flow on attach) -* precondition: perimeter lock is not acquired. -*/ -static void brcms_remove(struct bcma_device *pdev) -{ -	struct ieee80211_hw *hw = bcma_get_drvdata(pdev); -	struct brcms_info *wl = hw->priv; - -	if (wl->wlc) { -		wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, false); -		wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy); -		ieee80211_unregister_hw(hw); -	} - -	brcms_free(wl); - -	bcma_set_drvdata(pdev, NULL); -	ieee80211_free_hw(hw); -} -  static irqreturn_t brcms_isr(int irq, void *dev_id)  {  	struct brcms_info *wl; @@ -1047,18 +1057,8 @@ static struct brcms_info *brcms_attach(struct bcma_device *pdev)  	spin_lock_init(&wl->lock);  	spin_lock_init(&wl->isr_lock); -	/* prepare ucode */ -	if (brcms_request_fw(wl, pdev) < 0) { -		wiphy_err(wl->wiphy, "%s: Failed to find firmware usually in " -			  "%s\n", KBUILD_MODNAME, "/lib/firmware/brcm"); -		brcms_release_fw(wl); -		brcms_remove(pdev); -		return NULL; -	} -  	/* common load-time initialization */  	wl->wlc = brcms_c_attach((void *)wl, pdev, unit, false, &err); -	brcms_release_fw(wl);  	if (!wl->wlc) {  		wiphy_err(wl->wiphy, "%s: attach() failed with code %d\n",  			  KBUILD_MODNAME, err); diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c index 21a82423247..18d37645e2c 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c @@ -1137,9 +1137,8 @@ wlc_lcnphy_set_rx_gain_by_distribution(struct brcms_phy *pi,  	gain0_15 = ((biq1 & 0xf) << 12) |  		   ((tia & 0xf) << 8) |  		   ((lna2 & 0x3) << 6) | -		   ((lna2 & 0x3) << 4) | -		   ((lna1 & 0x3) << 2) | -		   ((lna1 & 0x3) << 0); +		   ((lna2 & +		     0x3) << 4) | ((lna1 & 0x3) << 2) | ((lna1 & 0x3) << 0);  	mod_phy_reg(pi, 0x4b6, (0xffff << 0), gain0_15 << 0);  	mod_phy_reg(pi, 0x4b7, (0xf << 0), gain16_19 << 0); @@ -1157,8 +1156,6 @@ wlc_lcnphy_set_rx_gain_by_distribution(struct brcms_phy *pi,  	}  	mod_phy_reg(pi, 0x44d, (0x1 << 0), (!trsw) << 0); -	mod_phy_reg(pi, 0x4b1, (0x3 << 11), lna1 << 11); -	mod_phy_reg(pi, 0x4e6, (0x3 << 3), lna1 << 3);  } @@ -1331,43 +1328,6 @@ static u32 wlc_lcnphy_measure_digital_power(struct brcms_phy *pi, u16 nsamples)  	return (iq_est.i_pwr + iq_est.q_pwr) / nsamples;  } -static bool wlc_lcnphy_rx_iq_cal_gain(struct brcms_phy *pi, u16 biq1_gain, -				      u16 tia_gain, u16 lna2_gain) -{ -	u32 i_thresh_l, q_thresh_l; -	u32 i_thresh_h, q_thresh_h; -	struct lcnphy_iq_est iq_est_h, iq_est_l; - -	wlc_lcnphy_set_rx_gain_by_distribution(pi, 0, 0, 0, biq1_gain, tia_gain, -					       lna2_gain, 0); - -	wlc_lcnphy_rx_gain_override_enable(pi, true); -	wlc_lcnphy_start_tx_tone(pi, 2000, (40 >> 1), 0); -	udelay(500); -	write_radio_reg(pi, RADIO_2064_REG112, 0); -	if (!wlc_lcnphy_rx_iq_est(pi, 1024, 32, &iq_est_l)) -		return false; - -	wlc_lcnphy_start_tx_tone(pi, 2000, 40, 0); -	udelay(500); -	write_radio_reg(pi, RADIO_2064_REG112, 0); -	if (!wlc_lcnphy_rx_iq_est(pi, 1024, 32, &iq_est_h)) -		return false; - -	i_thresh_l = (iq_est_l.i_pwr << 1); -	i_thresh_h = (iq_est_l.i_pwr << 2) + iq_est_l.i_pwr; - -	q_thresh_l = (iq_est_l.q_pwr << 1); -	q_thresh_h = (iq_est_l.q_pwr << 2) + iq_est_l.q_pwr; -	if ((iq_est_h.i_pwr > i_thresh_l) && -	    (iq_est_h.i_pwr < i_thresh_h) && -	    (iq_est_h.q_pwr > q_thresh_l) && -	    (iq_est_h.q_pwr < q_thresh_h)) -		return true; - -	return false; -} -  static bool  wlc_lcnphy_rx_iq_cal(struct brcms_phy *pi,  		     const struct lcnphy_rx_iqcomp *iqcomp, @@ -1382,8 +1342,8 @@ wlc_lcnphy_rx_iq_cal(struct brcms_phy *pi,  	    RFOverrideVal0_old, rfoverride2_old, rfoverride2val_old,  	    rfoverride3_old, rfoverride3val_old, rfoverride4_old,  	    rfoverride4val_old, afectrlovr_old, afectrlovrval_old; -	int tia_gain, lna2_gain, biq1_gain; -	bool set_gain; +	int tia_gain; +	u32 received_power, rx_pwr_threshold;  	u16 old_sslpnCalibClkEnCtrl, old_sslpnRxFeClkEnCtrl;  	u16 values_to_save[11];  	s16 *ptr; @@ -1408,134 +1368,126 @@ wlc_lcnphy_rx_iq_cal(struct brcms_phy *pi,  		goto cal_done;  	} -	WARN_ON(module != 1); -	tx_pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi); -	wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF); - -	for (i = 0; i < 11; i++) -		values_to_save[i] = -			read_radio_reg(pi, rxiq_cal_rf_reg[i]); -	Core1TxControl_old = read_phy_reg(pi, 0x631); +	if (module == 1) { -	or_phy_reg(pi, 0x631, 0x0015); - -	RFOverride0_old = read_phy_reg(pi, 0x44c); -	RFOverrideVal0_old = read_phy_reg(pi, 0x44d); -	rfoverride2_old = read_phy_reg(pi, 0x4b0); -	rfoverride2val_old = read_phy_reg(pi, 0x4b1); -	rfoverride3_old = read_phy_reg(pi, 0x4f9); -	rfoverride3val_old = read_phy_reg(pi, 0x4fa); -	rfoverride4_old = read_phy_reg(pi, 0x938); -	rfoverride4val_old = read_phy_reg(pi, 0x939); -	afectrlovr_old = read_phy_reg(pi, 0x43b); -	afectrlovrval_old = read_phy_reg(pi, 0x43c); -	old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da); -	old_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db); +		tx_pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi); +		wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF); -	tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi); -	if (tx_gain_override_old) { -		wlc_lcnphy_get_tx_gain(pi, &old_gains); -		tx_gain_index_old = pi_lcn->lcnphy_current_index; -	} +		for (i = 0; i < 11; i++) +			values_to_save[i] = +				read_radio_reg(pi, rxiq_cal_rf_reg[i]); +		Core1TxControl_old = read_phy_reg(pi, 0x631); -	wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_idx); +		or_phy_reg(pi, 0x631, 0x0015); -	mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0); -	mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0); +		RFOverride0_old = read_phy_reg(pi, 0x44c); +		RFOverrideVal0_old = read_phy_reg(pi, 0x44d); +		rfoverride2_old = read_phy_reg(pi, 0x4b0); +		rfoverride2val_old = read_phy_reg(pi, 0x4b1); +		rfoverride3_old = read_phy_reg(pi, 0x4f9); +		rfoverride3val_old = read_phy_reg(pi, 0x4fa); +		rfoverride4_old = read_phy_reg(pi, 0x938); +		rfoverride4val_old = read_phy_reg(pi, 0x939); +		afectrlovr_old = read_phy_reg(pi, 0x43b); +		afectrlovrval_old = read_phy_reg(pi, 0x43c); +		old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da); +		old_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db); -	mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1); -	mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1); +		tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi); +		if (tx_gain_override_old) { +			wlc_lcnphy_get_tx_gain(pi, &old_gains); +			tx_gain_index_old = pi_lcn->lcnphy_current_index; +		} -	write_radio_reg(pi, RADIO_2064_REG116, 0x06); -	write_radio_reg(pi, RADIO_2064_REG12C, 0x07); -	write_radio_reg(pi, RADIO_2064_REG06A, 0xd3); -	write_radio_reg(pi, RADIO_2064_REG098, 0x03); -	write_radio_reg(pi, RADIO_2064_REG00B, 0x7); -	mod_radio_reg(pi, RADIO_2064_REG113, 1 << 4, 1 << 4); -	write_radio_reg(pi, RADIO_2064_REG01D, 0x01); -	write_radio_reg(pi, RADIO_2064_REG114, 0x01); -	write_radio_reg(pi, RADIO_2064_REG02E, 0x10); -	write_radio_reg(pi, RADIO_2064_REG12A, 0x08); +		wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_idx); -	mod_phy_reg(pi, 0x938, (0x1 << 0), 1 << 0); -	mod_phy_reg(pi, 0x939, (0x1 << 0), 0 << 0); -	mod_phy_reg(pi, 0x938, (0x1 << 1), 1 << 1); -	mod_phy_reg(pi, 0x939, (0x1 << 1), 1 << 1); -	mod_phy_reg(pi, 0x938, (0x1 << 2), 1 << 2); -	mod_phy_reg(pi, 0x939, (0x1 << 2), 1 << 2); -	mod_phy_reg(pi, 0x938, (0x1 << 3), 1 << 3); -	mod_phy_reg(pi, 0x939, (0x1 << 3), 1 << 3); -	mod_phy_reg(pi, 0x938, (0x1 << 5), 1 << 5); -	mod_phy_reg(pi, 0x939, (0x1 << 5), 0 << 5); +		mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0); +		mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0); -	mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0); -	mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0); +		mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1); +		mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1); -	write_phy_reg(pi, 0x6da, 0xffff); -	or_phy_reg(pi, 0x6db, 0x3); +		write_radio_reg(pi, RADIO_2064_REG116, 0x06); +		write_radio_reg(pi, RADIO_2064_REG12C, 0x07); +		write_radio_reg(pi, RADIO_2064_REG06A, 0xd3); +		write_radio_reg(pi, RADIO_2064_REG098, 0x03); +		write_radio_reg(pi, RADIO_2064_REG00B, 0x7); +		mod_radio_reg(pi, RADIO_2064_REG113, 1 << 4, 1 << 4); +		write_radio_reg(pi, RADIO_2064_REG01D, 0x01); +		write_radio_reg(pi, RADIO_2064_REG114, 0x01); +		write_radio_reg(pi, RADIO_2064_REG02E, 0x10); +		write_radio_reg(pi, RADIO_2064_REG12A, 0x08); -	wlc_lcnphy_set_trsw_override(pi, tx_switch, rx_switch); -	set_gain = false; +		mod_phy_reg(pi, 0x938, (0x1 << 0), 1 << 0); +		mod_phy_reg(pi, 0x939, (0x1 << 0), 0 << 0); +		mod_phy_reg(pi, 0x938, (0x1 << 1), 1 << 1); +		mod_phy_reg(pi, 0x939, (0x1 << 1), 1 << 1); +		mod_phy_reg(pi, 0x938, (0x1 << 2), 1 << 2); +		mod_phy_reg(pi, 0x939, (0x1 << 2), 1 << 2); +		mod_phy_reg(pi, 0x938, (0x1 << 3), 1 << 3); +		mod_phy_reg(pi, 0x939, (0x1 << 3), 1 << 3); +		mod_phy_reg(pi, 0x938, (0x1 << 5), 1 << 5); +		mod_phy_reg(pi, 0x939, (0x1 << 5), 0 << 5); -	lna2_gain = 3; -	while ((lna2_gain >= 0) && !set_gain) { -		tia_gain = 4; +		mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0); +		mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0); -		while ((tia_gain >= 0) && !set_gain) { -			biq1_gain = 6; +		wlc_lcnphy_start_tx_tone(pi, 2000, 120, 0); +		write_phy_reg(pi, 0x6da, 0xffff); +		or_phy_reg(pi, 0x6db, 0x3); +		wlc_lcnphy_set_trsw_override(pi, tx_switch, rx_switch); +		wlc_lcnphy_rx_gain_override_enable(pi, true); -			while ((biq1_gain >= 0) && !set_gain) { -				set_gain = wlc_lcnphy_rx_iq_cal_gain(pi, -								     (u16) -								     biq1_gain, -								     (u16) -								     tia_gain, -								     (u16) -								     lna2_gain); -				biq1_gain -= 1; -			} +		tia_gain = 8; +		rx_pwr_threshold = 950; +		while (tia_gain > 0) {  			tia_gain -= 1; -		} -		lna2_gain -= 1; -	} +			wlc_lcnphy_set_rx_gain_by_distribution(pi, +							       0, 0, 2, 2, +							       (u16) +							       tia_gain, 1, 0); +			udelay(500); -	if (set_gain) -		result = wlc_lcnphy_calc_rx_iq_comp(pi, 1024); -	else -		result = false; +			received_power = +				wlc_lcnphy_measure_digital_power(pi, 2000); +			if (received_power < rx_pwr_threshold) +				break; +		} +		result = wlc_lcnphy_calc_rx_iq_comp(pi, 0xffff); -	wlc_lcnphy_stop_tx_tone(pi); +		wlc_lcnphy_stop_tx_tone(pi); -	write_phy_reg(pi, 0x631, Core1TxControl_old); +		write_phy_reg(pi, 0x631, Core1TxControl_old); -	write_phy_reg(pi, 0x44c, RFOverrideVal0_old); -	write_phy_reg(pi, 0x44d, RFOverrideVal0_old); -	write_phy_reg(pi, 0x4b0, rfoverride2_old); -	write_phy_reg(pi, 0x4b1, rfoverride2val_old); -	write_phy_reg(pi, 0x4f9, rfoverride3_old); -	write_phy_reg(pi, 0x4fa, rfoverride3val_old); -	write_phy_reg(pi, 0x938, rfoverride4_old); -	write_phy_reg(pi, 0x939, rfoverride4val_old); -	write_phy_reg(pi, 0x43b, afectrlovr_old); -	write_phy_reg(pi, 0x43c, afectrlovrval_old); -	write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl); -	write_phy_reg(pi, 0x6db, old_sslpnRxFeClkEnCtrl); +		write_phy_reg(pi, 0x44c, RFOverrideVal0_old); +		write_phy_reg(pi, 0x44d, RFOverrideVal0_old); +		write_phy_reg(pi, 0x4b0, rfoverride2_old); +		write_phy_reg(pi, 0x4b1, rfoverride2val_old); +		write_phy_reg(pi, 0x4f9, rfoverride3_old); +		write_phy_reg(pi, 0x4fa, rfoverride3val_old); +		write_phy_reg(pi, 0x938, rfoverride4_old); +		write_phy_reg(pi, 0x939, rfoverride4val_old); +		write_phy_reg(pi, 0x43b, afectrlovr_old); +		write_phy_reg(pi, 0x43c, afectrlovrval_old); +		write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl); +		write_phy_reg(pi, 0x6db, old_sslpnRxFeClkEnCtrl); -	wlc_lcnphy_clear_trsw_override(pi); +		wlc_lcnphy_clear_trsw_override(pi); -	mod_phy_reg(pi, 0x44c, (0x1 << 2), 0 << 2); +		mod_phy_reg(pi, 0x44c, (0x1 << 2), 0 << 2); -	for (i = 0; i < 11; i++) -		write_radio_reg(pi, rxiq_cal_rf_reg[i], -				values_to_save[i]); +		for (i = 0; i < 11; i++) +			write_radio_reg(pi, rxiq_cal_rf_reg[i], +					values_to_save[i]); -	if (tx_gain_override_old) -		wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_index_old); -	else -		wlc_lcnphy_disable_tx_gain_override(pi); +		if (tx_gain_override_old) +			wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_index_old); +		else +			wlc_lcnphy_disable_tx_gain_override(pi); -	wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl); -	wlc_lcnphy_rx_gain_override_enable(pi, false); +		wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl); +		wlc_lcnphy_rx_gain_override_enable(pi, false); +	}  cal_done:  	kfree(ptr); @@ -1829,17 +1781,6 @@ wlc_lcnphy_radio_2064_channel_tune_4313(struct brcms_phy *pi, u8 channel)  		write_radio_reg(pi, RADIO_2064_REG038, 3);  		write_radio_reg(pi, RADIO_2064_REG091, 7);  	} - -	if (!(pi->sh->boardflags & BFL_FEM)) { -		u8 reg038[14] = {0xd, 0xe, 0xd, 0xd, 0xd, 0xc, -			0xa, 0xb, 0xb, 0x3, 0x3, 0x2, 0x0, 0x0}; - -		write_radio_reg(pi, RADIO_2064_REG02A, 0xf); -		write_radio_reg(pi, RADIO_2064_REG091, 0x3); -		write_radio_reg(pi, RADIO_2064_REG038, 0x3); - -		write_radio_reg(pi, RADIO_2064_REG038, reg038[channel - 1]); -	}  }  static int @@ -2034,16 +1975,6 @@ wlc_lcnphy_set_tssi_mux(struct brcms_phy *pi, enum lcnphy_tssi_mode pos)  		} else {  			mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0x1);  			mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8); -			mod_radio_reg(pi, RADIO_2064_REG028, 0x1, 0x0); -			mod_radio_reg(pi, RADIO_2064_REG11A, 0x4, 1<<2); -			mod_radio_reg(pi, RADIO_2064_REG036, 0x10, 0x0); -			mod_radio_reg(pi, RADIO_2064_REG11A, 0x10, 1<<4); -			mod_radio_reg(pi, RADIO_2064_REG036, 0x3, 0x0); -			mod_radio_reg(pi, RADIO_2064_REG035, 0xff, 0x77); -			mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0xe<<1); -			mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 1<<7); -			mod_radio_reg(pi, RADIO_2064_REG005, 0x7, 1<<1); -			mod_radio_reg(pi, RADIO_2064_REG029, 0xf0, 0<<4);  		}  	} else {  		mod_phy_reg(pi, 0x4d9, (0x1 << 2), (0x1) << 2); @@ -2130,14 +2061,12 @@ static void wlc_lcnphy_pwrctrl_rssiparams(struct brcms_phy *pi)  		    (auxpga_vmid_temp << 0) | (auxpga_gain_temp << 12));  	mod_radio_reg(pi, RADIO_2064_REG082, (1 << 5), (1 << 5)); -	mod_radio_reg(pi, RADIO_2064_REG07C, (1 << 0), (1 << 0));  }  static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi)  {  	struct phytbl_info tab;  	u32 rfseq, ind; -	u8 tssi_sel;  	tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;  	tab.tbl_width = 32; @@ -2159,13 +2088,7 @@ static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi)  	mod_phy_reg(pi, 0x503, (0x1 << 4), (1) << 4); -	if (pi->sh->boardflags & BFL_FEM) { -		tssi_sel = 0x1; -		wlc_lcnphy_set_tssi_mux(pi, LCNPHY_TSSI_EXT); -	} else { -		tssi_sel = 0xe; -		wlc_lcnphy_set_tssi_mux(pi, LCNPHY_TSSI_POST_PA); -	} +	wlc_lcnphy_set_tssi_mux(pi, LCNPHY_TSSI_EXT);  	mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0) << 14);  	mod_phy_reg(pi, 0x4a4, (0x1 << 15), (1) << 15); @@ -2201,10 +2124,9 @@ static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi)  	mod_phy_reg(pi, 0x49a, (0x1ff << 0), (0xff) << 0);  	if (LCNREV_IS(pi->pubpi.phy_rev, 2)) { -		mod_radio_reg(pi, RADIO_2064_REG028, 0xf, tssi_sel); +		mod_radio_reg(pi, RADIO_2064_REG028, 0xf, 0xe);  		mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4);  	} else { -		mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, tssi_sel << 1);  		mod_radio_reg(pi, RADIO_2064_REG03A, 0x1, 1);  		mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 1 << 3);  	} @@ -2251,10 +2173,6 @@ static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi)  	mod_phy_reg(pi, 0x4d7, (0xf << 8), (0) << 8); -	mod_radio_reg(pi, RADIO_2064_REG035, 0xff, 0x0); -	mod_radio_reg(pi, RADIO_2064_REG036, 0x3, 0x0); -	mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8); -  	wlc_lcnphy_pwrctrl_rssiparams(pi);  } @@ -2873,8 +2791,6 @@ static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi)  		read_radio_reg(pi, RADIO_2064_REG007) & 1;  	u16 SAVE_jtag_auxpga = read_radio_reg(pi, RADIO_2064_REG0FF) & 0x10;  	u16 SAVE_iqadc_aux_en = read_radio_reg(pi, RADIO_2064_REG11F) & 4; -	u8 SAVE_bbmult = wlc_lcnphy_get_bbmult(pi); -  	idleTssi = read_phy_reg(pi, 0x4ab);  	suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &  			 MCTL_EN_MAC)); @@ -2892,12 +2808,6 @@ static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi)  	mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, 1 << 4);  	mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 1 << 2);  	wlc_lcnphy_tssi_setup(pi); - -	mod_phy_reg(pi, 0x4d7, (0x1 << 0), (1 << 0)); -	mod_phy_reg(pi, 0x4d7, (0x1 << 6), (1 << 6)); - -	wlc_lcnphy_set_bbmult(pi, 0x0); -  	wlc_phy_do_dummy_tx(pi, true, OFF);  	idleTssi = ((read_phy_reg(pi, 0x4ab) & (0x1ff << 0))  		    >> 0); @@ -2919,7 +2829,6 @@ static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi)  	mod_phy_reg(pi, 0x44c, (0x1 << 12), (0) << 12); -	wlc_lcnphy_set_bbmult(pi, SAVE_bbmult);  	wlc_lcnphy_set_tx_gain_override(pi, tx_gain_override_old);  	wlc_lcnphy_set_tx_gain(pi, &old_gains);  	wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl); @@ -3133,11 +3042,6 @@ static void wlc_lcnphy_tx_pwr_ctrl_init(struct brcms_phy_pub *ppi)  			wlc_lcnphy_write_table(pi, &tab);  			tab.tbl_offset++;  		} -		mod_phy_reg(pi, 0x4d0, (0x1 << 0), (0) << 0); -		mod_phy_reg(pi, 0x4d3, (0xff << 0), (0) << 0); -		mod_phy_reg(pi, 0x4d3, (0xff << 8), (0) << 8); -		mod_phy_reg(pi, 0x4d0, (0x1 << 4), (0) << 4); -		mod_phy_reg(pi, 0x4d0, (0x1 << 2), (0) << 2);  		mod_phy_reg(pi, 0x410, (0x1 << 7), (0) << 7); @@ -3939,6 +3843,7 @@ static void wlc_lcnphy_txpwrtbl_iqlo_cal(struct brcms_phy *pi)  	target_gains.pad_gain = 21;  	target_gains.dac_gain = 0;  	wlc_lcnphy_set_tx_gain(pi, &target_gains); +	wlc_lcnphy_set_tx_pwr_by_index(pi, 16);  	if (LCNREV_IS(pi->pubpi.phy_rev, 1) || pi_lcn->lcnphy_hw_iqcal_en) { @@ -3949,7 +3854,6 @@ static void wlc_lcnphy_txpwrtbl_iqlo_cal(struct brcms_phy *pi)  					lcnphy_recal ? LCNPHY_CAL_RECAL :  					LCNPHY_CAL_FULL), false);  	} else { -		wlc_lcnphy_set_tx_pwr_by_index(pi, 16);  		wlc_lcnphy_tx_iqlo_soft_cal_full(pi);  	} @@ -4374,22 +4278,17 @@ wlc_lcnphy_load_tx_gain_table(struct brcms_phy *pi,  	if (CHSPEC_IS5G(pi->radio_chanspec))  		pa_gain = 0x70;  	else -		pa_gain = 0x60; +		pa_gain = 0x70;  	if (pi->sh->boardflags & BFL_FEM)  		pa_gain = 0x10; -  	tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;  	tab.tbl_width = 32;  	tab.tbl_len = 1;  	tab.tbl_ptr = &val;  	for (j = 0; j < 128; j++) { -		if (pi->sh->boardflags & BFL_FEM) -			gm_gain = gain_table[j].gm; -		else -			gm_gain = 15; - +		gm_gain = gain_table[j].gm;  		val = (((u32) pa_gain << 24) |  		       (gain_table[j].pad << 16) |  		       (gain_table[j].pga << 8) | gm_gain); @@ -4600,10 +4499,7 @@ static void wlc_radio_2064_init(struct brcms_phy *pi)  	write_phy_reg(pi, 0x4ea, 0x4688); -	if (pi->sh->boardflags & BFL_FEM) -		mod_phy_reg(pi, 0x4eb, (0x7 << 0), 2 << 0); -	else -		mod_phy_reg(pi, 0x4eb, (0x7 << 0), 3 << 0); +	mod_phy_reg(pi, 0x4eb, (0x7 << 0), 2 << 0);  	mod_phy_reg(pi, 0x4eb, (0x7 << 6), 0 << 6); @@ -4614,13 +4510,6 @@ static void wlc_radio_2064_init(struct brcms_phy *pi)  	wlc_lcnphy_rcal(pi);  	wlc_lcnphy_rc_cal(pi); - -	if (!(pi->sh->boardflags & BFL_FEM)) { -		write_radio_reg(pi, RADIO_2064_REG032, 0x6f); -		write_radio_reg(pi, RADIO_2064_REG033, 0x19); -		write_radio_reg(pi, RADIO_2064_REG039, 0xe); -	} -  }  static void wlc_lcnphy_radio_init(struct brcms_phy *pi) @@ -4650,20 +4539,22 @@ static void wlc_lcnphy_tbl_init(struct brcms_phy *pi)  		wlc_lcnphy_write_table(pi, &tab);  	} -	if (!(pi->sh->boardflags & BFL_FEM)) { -		tab.tbl_id = LCNPHY_TBL_ID_RFSEQ; -		tab.tbl_width = 16; -		tab.tbl_ptr = &val; -		tab.tbl_len = 1; +	tab.tbl_id = LCNPHY_TBL_ID_RFSEQ; +	tab.tbl_width = 16; +	tab.tbl_ptr = &val; +	tab.tbl_len = 1; -		val = 150; -		tab.tbl_offset = 0; -		wlc_lcnphy_write_table(pi, &tab); +	val = 114; +	tab.tbl_offset = 0; +	wlc_lcnphy_write_table(pi, &tab); -		val = 220; -		tab.tbl_offset = 1; -		wlc_lcnphy_write_table(pi, &tab); -	} +	val = 130; +	tab.tbl_offset = 1; +	wlc_lcnphy_write_table(pi, &tab); + +	val = 6; +	tab.tbl_offset = 8; +	wlc_lcnphy_write_table(pi, &tab);  	if (CHSPEC_IS2G(pi->radio_chanspec)) {  		if (pi->sh->boardflags & BFL_FEM) @@ -5055,7 +4946,6 @@ void wlc_phy_chanspec_set_lcnphy(struct brcms_phy *pi, u16 chanspec)  		wlc_lcnphy_load_tx_iir_filter(pi, true, 3);  	mod_phy_reg(pi, 0x4eb, (0x7 << 3), (1) << 3); -	wlc_lcnphy_tssi_setup(pi);  }  void wlc_phy_detach_lcnphy(struct brcms_phy *pi) @@ -5094,7 +4984,8 @@ bool wlc_phy_attach_lcnphy(struct brcms_phy *pi)  	if (!wlc_phy_txpwr_srom_read_lcnphy(pi))  		return false; -	if (LCNREV_IS(pi->pubpi.phy_rev, 1)) { +	if ((pi->sh->boardflags & BFL_FEM) && +	    (LCNREV_IS(pi->pubpi.phy_rev, 1))) {  		if (pi_lcn->lcnphy_tempsense_option == 3) {  			pi->hwpwrctrl = true;  			pi->hwpwrctrl_capable = true; diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c index b7e95acc208..622c01ca72c 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c @@ -1992,70 +1992,70 @@ static const u16 dot11lcn_sw_ctrl_tbl_4313_epa_rev0[] = {  };  static const u16 dot11lcn_sw_ctrl_tbl_4313_rev0[] = { -	0x0009,  	0x000a, -	0x0005, -	0x0006,  	0x0009, -	0x000a, -	0x0005,  	0x0006, -	0x0009, -	0x000a,  	0x0005, -	0x0006, -	0x0009,  	0x000a, -	0x0005, -	0x0006,  	0x0009, -	0x000a, -	0x0005,  	0x0006, -	0x0009, -	0x000a,  	0x0005, -	0x0006, -	0x0009,  	0x000a, -	0x0005, -	0x0006,  	0x0009, -	0x000a, -	0x0005,  	0x0006, -	0x0009, -	0x000a,  	0x0005, -	0x0006, -	0x0009,  	0x000a, -	0x0005, -	0x0006,  	0x0009, -	0x000a, -	0x0005,  	0x0006, -	0x0009, -	0x000a,  	0x0005, -	0x0006, +	0x000a,  	0x0009, +	0x0006, +	0x0005,  	0x000a, +	0x0009, +	0x0006,  	0x0005, +	0x000a, +	0x0009,  	0x0006, +	0x0005, +	0x000a,  	0x0009, +	0x0006, +	0x0005,  	0x000a, +	0x0009, +	0x0006,  	0x0005, +	0x000a, +	0x0009,  	0x0006, +	0x0005, +	0x000a,  	0x0009, +	0x0006, +	0x0005,  	0x000a, +	0x0009, +	0x0006,  	0x0005, +	0x000a, +	0x0009,  	0x0006, +	0x0005, +	0x000a,  	0x0009, +	0x0006, +	0x0005,  	0x000a, +	0x0009, +	0x0006,  	0x0005, +	0x000a, +	0x0009,  	0x0006, +	0x0005,  };  static const u16 dot11lcn_sw_ctrl_tbl_rev0[] = { diff --git a/drivers/net/wireless/iwlegacy/3945-mac.c b/drivers/net/wireless/iwlegacy/3945-mac.c index 3630a41df50..c353b5f19c8 100644 --- a/drivers/net/wireless/iwlegacy/3945-mac.c +++ b/drivers/net/wireless/iwlegacy/3945-mac.c @@ -475,6 +475,7 @@ il3945_tx_skb(struct il_priv *il,  	dma_addr_t txcmd_phys;  	int txq_id = skb_get_queue_mapping(skb);  	u16 len, idx, hdr_len; +	u16 firstlen, secondlen;  	u8 id;  	u8 unicast;  	u8 sta_id; @@ -589,21 +590,22 @@ il3945_tx_skb(struct il_priv *il,  	len =  	    sizeof(struct il3945_tx_cmd) + sizeof(struct il_cmd_header) +  	    hdr_len; -	len = (len + 3) & ~3; +	firstlen = (len + 3) & ~3;  	/* Physical address of this Tx command's header (not MAC header!),  	 * within command buffer array. */  	txcmd_phys = -	    pci_map_single(il->pci_dev, &out_cmd->hdr, len, PCI_DMA_TODEVICE); +	    pci_map_single(il->pci_dev, &out_cmd->hdr, firstlen, +			   PCI_DMA_TODEVICE);  	if (unlikely(pci_dma_mapping_error(il->pci_dev, txcmd_phys)))  		goto drop_unlock;  	/* Set up TFD's 2nd entry to point directly to remainder of skb,  	 * if any (802.11 null frames have no payload). */ -	len = skb->len - hdr_len; -	if (len) { +	secondlen = skb->len - hdr_len; +	if (secondlen > 0) {  		phys_addr = -		    pci_map_single(il->pci_dev, skb->data + hdr_len, len, +		    pci_map_single(il->pci_dev, skb->data + hdr_len, secondlen,  				   PCI_DMA_TODEVICE);  		if (unlikely(pci_dma_mapping_error(il->pci_dev, phys_addr)))  			goto drop_unlock; @@ -611,12 +613,12 @@ il3945_tx_skb(struct il_priv *il,  	/* Add buffer containing Tx command and MAC(!) header to TFD's  	 * first entry */ -	il->ops->txq_attach_buf_to_tfd(il, txq, txcmd_phys, len, 1, 0); +	il->ops->txq_attach_buf_to_tfd(il, txq, txcmd_phys, firstlen, 1, 0);  	dma_unmap_addr_set(out_meta, mapping, txcmd_phys); -	dma_unmap_len_set(out_meta, len, len); -	if (len) -		il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, len, 0, -					       U32_PAD(len)); +	dma_unmap_len_set(out_meta, len, firstlen); +	if (secondlen > 0) +		il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, secondlen, 0, +					       U32_PAD(secondlen));  	if (!ieee80211_has_morefrags(hdr->frame_control)) {  		txq->need_update = 1; diff --git a/drivers/net/wireless/iwlegacy/4965-rs.c b/drivers/net/wireless/iwlegacy/4965-rs.c index e8324b5e5bf..6c7493c2d69 100644 --- a/drivers/net/wireless/iwlegacy/4965-rs.c +++ b/drivers/net/wireless/iwlegacy/4965-rs.c @@ -2152,7 +2152,7 @@ il4965_rs_initialize_lq(struct il_priv *il, struct ieee80211_conf *conf,  	int rate_idx;  	int i;  	u32 rate; -	u8 use_green = il4965_rs_use_green(il, sta); +	u8 use_green;  	u8 active_tbl = 0;  	u8 valid_tx_ant;  	struct il_station_priv *sta_priv; @@ -2160,6 +2160,7 @@ il4965_rs_initialize_lq(struct il_priv *il, struct ieee80211_conf *conf,  	if (!sta || !lq_sta)  		return; +	use_green = il4965_rs_use_green(il, sta);  	sta_priv = (void *)sta->drv_priv;  	i = lq_sta->last_txrate_idx; diff --git a/drivers/net/wireless/iwlwifi/dvm/lib.c b/drivers/net/wireless/iwlwifi/dvm/lib.c index 86ea5f4c393..44ca0e57f9f 100644 --- a/drivers/net/wireless/iwlwifi/dvm/lib.c +++ b/drivers/net/wireless/iwlwifi/dvm/lib.c @@ -1262,6 +1262,15 @@ int iwl_dvm_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)  	}  	/* +	 * This can happen upon FW ASSERT: we clear the STATUS_FW_ERROR flag +	 * in iwl_down but cancel the workers only later. +	 */ +	if (!priv->ucode_loaded) { +		IWL_ERR(priv, "Fw not loaded - dropping CMD: %x\n", cmd->id); +		return -EIO; +	} + +	/*  	 * Synchronous commands from this op-mode must hold  	 * the mutex, this ensures we don't try to send two  	 * (or more) synchronous commands at a time. diff --git a/drivers/net/wireless/iwlwifi/dvm/rxon.c b/drivers/net/wireless/iwlwifi/dvm/rxon.c index 23be948cf16..a82b6b39d4f 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rxon.c +++ b/drivers/net/wireless/iwlwifi/dvm/rxon.c @@ -1419,6 +1419,14 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,  	mutex_lock(&priv->mutex); +	if (changes & BSS_CHANGED_IDLE && bss_conf->idle) { +		/* +		 * If we go idle, then clearly no "passive-no-rx" +		 * workaround is needed any more, this is a reset. +		 */ +		iwlagn_lift_passive_no_rx(priv); +	} +  	if (unlikely(!iwl_is_ready(priv))) {  		IWL_DEBUG_MAC80211(priv, "leave - not ready\n");  		mutex_unlock(&priv->mutex); @@ -1450,16 +1458,6 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,  			priv->timestamp = bss_conf->sync_tsf;  			ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;  		} else { -			/* -			 * If we disassociate while there are pending -			 * frames, just wake up the queues and let the -			 * frames "escape" ... This shouldn't really -			 * be happening to start with, but we should -			 * not get stuck in this case either since it -			 * can happen if userspace gets confused. -			 */ -			iwlagn_lift_passive_no_rx(priv); -  			ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;  			if (ctx->ctxid == IWL_RXON_CTX_BSS) diff --git a/drivers/net/wireless/iwlwifi/dvm/sta.c b/drivers/net/wireless/iwlwifi/dvm/sta.c index 94ef33838bc..b775769f832 100644 --- a/drivers/net/wireless/iwlwifi/dvm/sta.c +++ b/drivers/net/wireless/iwlwifi/dvm/sta.c @@ -151,7 +151,7 @@ int iwl_send_add_sta(struct iwl_priv *priv,  		       sta_id, sta->sta.addr, flags & CMD_ASYNC ?  "a" : "");  	if (!(flags & CMD_ASYNC)) { -		cmd.flags |= CMD_WANT_SKB | CMD_WANT_HCMD; +		cmd.flags |= CMD_WANT_SKB;  		might_sleep();  	} diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c index 6aec2df3bb2..d1a670d7b10 100644 --- a/drivers/net/wireless/iwlwifi/dvm/tx.c +++ b/drivers/net/wireless/iwlwifi/dvm/tx.c @@ -1192,7 +1192,7 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,  			memset(&info->status, 0, sizeof(info->status));  			if (status == TX_STATUS_FAIL_PASSIVE_NO_RX && -			    iwl_is_associated_ctx(ctx) && ctx->vif && +			    ctx->vif &&  			    ctx->vif->type == NL80211_IFTYPE_STATION) {  				/* block and stop all queues */  				priv->passive_no_rx = true; diff --git a/drivers/net/wireless/iwlwifi/dvm/ucode.c b/drivers/net/wireless/iwlwifi/dvm/ucode.c index 736fe9bb140..1a4ac9236a4 100644 --- a/drivers/net/wireless/iwlwifi/dvm/ucode.c +++ b/drivers/net/wireless/iwlwifi/dvm/ucode.c @@ -367,6 +367,8 @@ int iwl_load_ucode_wait_alive(struct iwl_priv *priv,  		return -EIO;  	} +	priv->ucode_loaded = true; +  	if (ucode_type != IWL_UCODE_WOWLAN) {  		/* delay a bit to give rfkill time to run */  		msleep(5); @@ -380,8 +382,6 @@ int iwl_load_ucode_wait_alive(struct iwl_priv *priv,  		return ret;  	} -	priv->ucode_loaded = true; -  	return 0;  } diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h index 10f01793d7a..81aa91fab5a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h @@ -363,7 +363,7 @@ TRACE_EVENT(iwlwifi_dev_hcmd,  		__entry->flags = cmd->flags;  		memcpy(__get_dynamic_array(hcmd), hdr, sizeof(*hdr)); -		for (i = 0; i < IWL_MAX_CMD_TFDS; i++) { +		for (i = 0; i < IWL_MAX_CMD_TBS_PER_TFD; i++) {  			if (!cmd->len[i])  				continue;  			memcpy((u8 *)__get_dynamic_array(hcmd) + offset, diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index 6f228bb2b84..fbfd2d13711 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -1102,7 +1102,6 @@ void iwl_drv_stop(struct iwl_drv *drv)  /* shared module parameters */  struct iwl_mod_params iwlwifi_mod_params = { -	.amsdu_size_8K = 1,  	.restart_fw = 1,  	.plcp_check = true,  	.bt_coex_active = true, @@ -1207,7 +1206,7 @@ MODULE_PARM_DESC(11n_disable,  	"disable 11n functionality, bitmap: 1: full, 2: agg TX, 4: agg RX");  module_param_named(amsdu_size_8K, iwlwifi_mod_params.amsdu_size_8K,  		   int, S_IRUGO); -MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size"); +MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size (default 0)");  module_param_named(fw_restart, iwlwifi_mod_params.restart_fw, int, S_IRUGO);  MODULE_PARM_DESC(fw_restart, "restart firmware in case of error"); diff --git a/drivers/net/wireless/iwlwifi/iwl-modparams.h b/drivers/net/wireless/iwlwifi/iwl-modparams.h index e5e3a79eae2..2c2a729092f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-modparams.h +++ b/drivers/net/wireless/iwlwifi/iwl-modparams.h @@ -91,7 +91,7 @@ enum iwl_power_level {   * @sw_crypto: using hardware encryption, default = 0   * @disable_11n: disable 11n capabilities, default = 0,   *	use IWL_DISABLE_HT_* constants - * @amsdu_size_8K: enable 8K amsdu size, default = 1 + * @amsdu_size_8K: enable 8K amsdu size, default = 0   * @restart_fw: restart firmware, default = 1   * @plcp_check: enable plcp health check, default = true   * @wd_disable: enable stuck queue check, default = 0 diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 8c7bec6b9a0..0cac2b7af78 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -186,19 +186,13 @@ struct iwl_rx_packet {   * @CMD_ASYNC: Return right away and don't want for the response   * @CMD_WANT_SKB: valid only with CMD_SYNC. The caller needs the buffer of the   *	response. The caller needs to call iwl_free_resp when done. - * @CMD_WANT_HCMD: The caller needs to get the HCMD that was sent in the - *	response handler. Chunks flagged by %IWL_HCMD_DFL_NOCOPY won't be - *	copied. The pointer passed to the response handler is in the transport - *	ownership and don't need to be freed by the op_mode. This also means - *	that the pointer is invalidated after the op_mode's handler returns.   * @CMD_ON_DEMAND: This command is sent by the test mode pipe.   */  enum CMD_MODE {  	CMD_SYNC		= 0,  	CMD_ASYNC		= BIT(0),  	CMD_WANT_SKB		= BIT(1), -	CMD_WANT_HCMD		= BIT(2), -	CMD_ON_DEMAND		= BIT(3), +	CMD_ON_DEMAND		= BIT(2),  };  #define DEF_CMD_PAYLOAD_SIZE 320 @@ -217,7 +211,11 @@ struct iwl_device_cmd {  #define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_device_cmd)) -#define IWL_MAX_CMD_TFDS	2 +/* + * number of transfer buffers (fragments) per transmit frame descriptor; + * this is just the driver's idea, the hardware supports 20 + */ +#define IWL_MAX_CMD_TBS_PER_TFD	2  /**   * struct iwl_hcmd_dataflag - flag for each one of the chunks of the command @@ -254,15 +252,15 @@ enum iwl_hcmd_dataflag {   * @id: id of the host command   */  struct iwl_host_cmd { -	const void *data[IWL_MAX_CMD_TFDS]; +	const void *data[IWL_MAX_CMD_TBS_PER_TFD];  	struct iwl_rx_packet *resp_pkt;  	unsigned long _rx_page_addr;  	u32 _rx_page_order;  	int handler_status;  	u32 flags; -	u16 len[IWL_MAX_CMD_TFDS]; -	u8 dataflags[IWL_MAX_CMD_TFDS]; +	u16 len[IWL_MAX_CMD_TBS_PER_TFD]; +	u8 dataflags[IWL_MAX_CMD_TBS_PER_TFD];  	u8 id;  }; diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 23eebda848b..2adb61f103f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -762,18 +762,20 @@ struct iwl_phy_context_cmd {  #define IWL_RX_INFO_PHY_CNT 8  #define IWL_RX_INFO_AGC_IDX 1  #define IWL_RX_INFO_RSSI_AB_IDX 2 -#define IWL_RX_INFO_RSSI_C_IDX 3 -#define IWL_OFDM_AGC_DB_MSK 0xfe00 -#define IWL_OFDM_AGC_DB_POS 9 +#define IWL_OFDM_AGC_A_MSK 0x0000007f +#define IWL_OFDM_AGC_A_POS 0 +#define IWL_OFDM_AGC_B_MSK 0x00003f80 +#define IWL_OFDM_AGC_B_POS 7 +#define IWL_OFDM_AGC_CODE_MSK 0x3fe00000 +#define IWL_OFDM_AGC_CODE_POS 20  #define IWL_OFDM_RSSI_INBAND_A_MSK 0x00ff -#define IWL_OFDM_RSSI_ALLBAND_A_MSK 0xff00  #define IWL_OFDM_RSSI_A_POS 0 +#define IWL_OFDM_RSSI_ALLBAND_A_MSK 0xff00 +#define IWL_OFDM_RSSI_ALLBAND_A_POS 8  #define IWL_OFDM_RSSI_INBAND_B_MSK 0xff0000 -#define IWL_OFDM_RSSI_ALLBAND_B_MSK 0xff000000  #define IWL_OFDM_RSSI_B_POS 16 -#define IWL_OFDM_RSSI_INBAND_C_MSK 0x00ff -#define IWL_OFDM_RSSI_ALLBAND_C_MSK 0xff00 -#define IWL_OFDM_RSSI_C_POS 0 +#define IWL_OFDM_RSSI_ALLBAND_B_MSK 0xff000000 +#define IWL_OFDM_RSSI_ALLBAND_B_POS 24  /**   * struct iwl_rx_phy_info - phy info diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index d3d959db03a..500f818dba0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -79,17 +79,8 @@  #define UCODE_VALID_OK	cpu_to_le32(0x1)  /* Default calibration values for WkP - set to INIT image w/o running */ -static const u8 wkp_calib_values_bb_filter[] = { 0xbf, 0x00, 0x5f, 0x00, 0x2f, -						 0x00, 0x18, 0x00 }; -static const u8 wkp_calib_values_rx_dc[] = { 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, -					     0x7f, 0x7f, 0x7f }; -static const u8 wkp_calib_values_tx_lo[] = { 0x00, 0x00, 0x00, 0x00 }; -static const u8 wkp_calib_values_tx_iq[] = { 0xff, 0x00, 0xff, 0x00, 0x00, -					     0x00 }; -static const u8 wkp_calib_values_rx_iq[] = { 0xff, 0x00, 0x00, 0x00 };  static const u8 wkp_calib_values_rx_iq_skew[] = { 0x00, 0x00, 0x01, 0x00 };  static const u8 wkp_calib_values_tx_iq_skew[] = { 0x01, 0x00, 0x00, 0x00 }; -static const u8 wkp_calib_values_xtal[] = { 0xd2, 0xd2 };  struct iwl_calib_default_data {  	u16 size; @@ -99,12 +90,7 @@ struct iwl_calib_default_data {  #define CALIB_SIZE_N_DATA(_buf) {.size = sizeof(_buf), .data = &_buf}  static const struct iwl_calib_default_data wkp_calib_default_data[12] = { -	[5] = CALIB_SIZE_N_DATA(wkp_calib_values_rx_dc), -	[6] = CALIB_SIZE_N_DATA(wkp_calib_values_bb_filter), -	[7] = CALIB_SIZE_N_DATA(wkp_calib_values_tx_lo), -	[8] = CALIB_SIZE_N_DATA(wkp_calib_values_tx_iq),  	[9] = CALIB_SIZE_N_DATA(wkp_calib_values_tx_iq_skew), -	[10] = CALIB_SIZE_N_DATA(wkp_calib_values_rx_iq),  	[11] = CALIB_SIZE_N_DATA(wkp_calib_values_rx_iq_skew),  }; @@ -241,20 +227,6 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,  	return 0;  } -#define IWL_HW_REV_ID_RAINBOW	0x2 -#define IWL_PROJ_TYPE_LHP	0x5 - -static u32 iwl_mvm_build_phy_cfg(struct iwl_mvm *mvm) -{ -	struct iwl_nvm_data *data = mvm->nvm_data; -	/* Temp calls to static definitions, will be changed to CSR calls */ -	u8 hw_rev_id = IWL_HW_REV_ID_RAINBOW; -	u8 project_type = IWL_PROJ_TYPE_LHP; - -	return data->radio_cfg_dash | (data->radio_cfg_step << 2) | -		(hw_rev_id << 4) | ((project_type & 0x7f) << 6) | -		(data->valid_tx_ant << 16) | (data->valid_rx_ant << 20); -}  static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm)  { @@ -262,7 +234,7 @@ static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm)  	enum iwl_ucode_type ucode_type = mvm->cur_ucode;  	/* Set parameters */ -	phy_cfg_cmd.phy_cfg = cpu_to_le32(iwl_mvm_build_phy_cfg(mvm)); +	phy_cfg_cmd.phy_cfg = cpu_to_le32(mvm->fw->phy_config);  	phy_cfg_cmd.calib_control.event_trigger =  		mvm->fw->default_calib[ucode_type].event_trigger;  	phy_cfg_cmd.calib_control.flow_trigger = @@ -275,103 +247,6 @@ static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm)  				    sizeof(phy_cfg_cmd), &phy_cfg_cmd);  } -/* Starting with the new PHY DB implementation - New calibs are enabled */ -/* Value - 0x405e7 */ -#define IWL_CALIB_DEFAULT_FLOW_INIT	(IWL_CALIB_CFG_XTAL_IDX		|\ -					 IWL_CALIB_CFG_TEMPERATURE_IDX	|\ -					 IWL_CALIB_CFG_VOLTAGE_READ_IDX	|\ -					 IWL_CALIB_CFG_DC_IDX		|\ -					 IWL_CALIB_CFG_BB_FILTER_IDX	|\ -					 IWL_CALIB_CFG_LO_LEAKAGE_IDX	|\ -					 IWL_CALIB_CFG_TX_IQ_IDX	|\ -					 IWL_CALIB_CFG_RX_IQ_IDX	|\ -					 IWL_CALIB_CFG_AGC_IDX) - -#define IWL_CALIB_DEFAULT_EVENT_INIT	0x0 - -/* Value 0x41567 */ -#define IWL_CALIB_DEFAULT_FLOW_RUN	(IWL_CALIB_CFG_XTAL_IDX		|\ -					 IWL_CALIB_CFG_TEMPERATURE_IDX	|\ -					 IWL_CALIB_CFG_VOLTAGE_READ_IDX	|\ -					 IWL_CALIB_CFG_BB_FILTER_IDX	|\ -					 IWL_CALIB_CFG_DC_IDX		|\ -					 IWL_CALIB_CFG_TX_IQ_IDX	|\ -					 IWL_CALIB_CFG_RX_IQ_IDX	|\ -					 IWL_CALIB_CFG_SENSITIVITY_IDX	|\ -					 IWL_CALIB_CFG_AGC_IDX) - -#define IWL_CALIB_DEFAULT_EVENT_RUN	(IWL_CALIB_CFG_XTAL_IDX		|\ -					 IWL_CALIB_CFG_TEMPERATURE_IDX	|\ -					 IWL_CALIB_CFG_VOLTAGE_READ_IDX	|\ -					 IWL_CALIB_CFG_TX_PWR_IDX	|\ -					 IWL_CALIB_CFG_DC_IDX		|\ -					 IWL_CALIB_CFG_TX_IQ_IDX	|\ -					 IWL_CALIB_CFG_SENSITIVITY_IDX) - -/* - * Sets the calibrations trigger values that will be sent to the FW for runtime - * and init calibrations. - * The ones given in the FW TLV are not correct. - */ -static void iwl_set_default_calib_trigger(struct iwl_mvm *mvm) -{ -	struct iwl_tlv_calib_ctrl default_calib; - -	/* -	 * WkP FW TLV calib bits are wrong, overwrite them. -	 * This defines the dynamic calibrations which are implemented in the -	 * uCode both for init(flow) calculation and event driven calibs. -	 */ - -	/* Init Image */ -	default_calib.event_trigger = cpu_to_le32(IWL_CALIB_DEFAULT_EVENT_INIT); -	default_calib.flow_trigger = cpu_to_le32(IWL_CALIB_DEFAULT_FLOW_INIT); - -	if (default_calib.event_trigger != -	    mvm->fw->default_calib[IWL_UCODE_INIT].event_trigger) -		IWL_ERR(mvm, -			"Updating the event calib for INIT image: 0x%x -> 0x%x\n", -			mvm->fw->default_calib[IWL_UCODE_INIT].event_trigger, -			default_calib.event_trigger); -	if (default_calib.flow_trigger != -	    mvm->fw->default_calib[IWL_UCODE_INIT].flow_trigger) -		IWL_ERR(mvm, -			"Updating the flow calib for INIT image: 0x%x -> 0x%x\n", -			mvm->fw->default_calib[IWL_UCODE_INIT].flow_trigger, -			default_calib.flow_trigger); - -	memcpy((void *)&mvm->fw->default_calib[IWL_UCODE_INIT], -	       &default_calib, sizeof(struct iwl_tlv_calib_ctrl)); -	IWL_ERR(mvm, -		"Setting uCode init calibrations event 0x%x, trigger 0x%x\n", -		default_calib.event_trigger, -		default_calib.flow_trigger); - -	/* Run time image */ -	default_calib.event_trigger = cpu_to_le32(IWL_CALIB_DEFAULT_EVENT_RUN); -	default_calib.flow_trigger = cpu_to_le32(IWL_CALIB_DEFAULT_FLOW_RUN); - -	if (default_calib.event_trigger != -	    mvm->fw->default_calib[IWL_UCODE_REGULAR].event_trigger) -		IWL_ERR(mvm, -			"Updating the event calib for RT image: 0x%x -> 0x%x\n", -			mvm->fw->default_calib[IWL_UCODE_REGULAR].event_trigger, -			default_calib.event_trigger); -	if (default_calib.flow_trigger != -	    mvm->fw->default_calib[IWL_UCODE_REGULAR].flow_trigger) -		IWL_ERR(mvm, -			"Updating the flow calib for RT image: 0x%x -> 0x%x\n", -			mvm->fw->default_calib[IWL_UCODE_REGULAR].flow_trigger, -			default_calib.flow_trigger); - -	memcpy((void *)&mvm->fw->default_calib[IWL_UCODE_REGULAR], -	       &default_calib, sizeof(struct iwl_tlv_calib_ctrl)); -	IWL_ERR(mvm, -		"Setting uCode runtime calibs event 0x%x, trigger 0x%x\n", -		default_calib.event_trigger, -		default_calib.flow_trigger); -} -  static int iwl_set_default_calibrations(struct iwl_mvm *mvm)  {  	u8 cmd_raw[16]; /* holds the variable size commands */ @@ -446,8 +321,10 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)  	ret = iwl_nvm_check_version(mvm->nvm_data, mvm->trans);  	WARN_ON(ret); -	/* Override the calibrations from TLV and the const of fw */ -	iwl_set_default_calib_trigger(mvm); +	/* Send TX valid antennas before triggering calibrations */ +	ret = iwl_send_tx_ant_cfg(mvm, mvm->nvm_data->valid_tx_ant); +	if (ret) +		goto error;  	/* WkP doesn't have all calibrations, need to set default values */  	if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) { diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 537711b1047..bdae700c769 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -80,7 +80,8 @@  #define IWL_INVALID_MAC80211_QUEUE	0xff  #define IWL_MVM_MAX_ADDRESSES		2 -#define IWL_RSSI_OFFSET 44 +/* RSSI offset for WkP */ +#define IWL_RSSI_OFFSET 50  enum iwl_mvm_tx_fifo {  	IWL_MVM_TX_FIFO_BK = 0, diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index aa59adf87db..d0f9c1e0475 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -624,12 +624,8 @@ static void iwl_mvm_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb)  	ieee80211_free_txskb(mvm->hw, skb);  } -static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode) +static void iwl_mvm_nic_restart(struct iwl_mvm *mvm)  { -	struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); - -	iwl_mvm_dump_nic_error_log(mvm); -  	iwl_abort_notification_waits(&mvm->notif_wait);  	/* @@ -663,9 +659,21 @@ static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode)  	}  } +static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode) +{ +	struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); + +	iwl_mvm_dump_nic_error_log(mvm); + +	iwl_mvm_nic_restart(mvm); +} +  static void iwl_mvm_cmd_queue_full(struct iwl_op_mode *op_mode)  { +	struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); +  	WARN_ON(1); +	iwl_mvm_nic_restart(mvm);  }  static const struct iwl_op_mode_ops iwl_mvm_ops = { diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index 3f40ab05bbd..b0b190d0ec2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c @@ -131,33 +131,42 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm,  static int iwl_mvm_calc_rssi(struct iwl_mvm *mvm,  			     struct iwl_rx_phy_info *phy_info)  { -	u32 rssi_a, rssi_b, rssi_c, max_rssi, agc_db; +	int rssi_a, rssi_b, rssi_a_dbm, rssi_b_dbm, max_rssi_dbm; +	int rssi_all_band_a, rssi_all_band_b; +	u32 agc_a, agc_b, max_agc;  	u32 val; -	/* Find max rssi among 3 possible receivers. +	/* Find max rssi among 2 possible receivers.  	 * These values are measured by the Digital Signal Processor (DSP).  	 * They should stay fairly constant even as the signal strength varies,  	 * if the radio's Automatic Gain Control (AGC) is working right.  	 * AGC value (see below) will provide the "interesting" info.  	 */ +	val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_AGC_IDX]); +	agc_a = (val & IWL_OFDM_AGC_A_MSK) >> IWL_OFDM_AGC_A_POS; +	agc_b = (val & IWL_OFDM_AGC_B_MSK) >> IWL_OFDM_AGC_B_POS; +	max_agc = max_t(u32, agc_a, agc_b); +  	val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_RSSI_AB_IDX]);  	rssi_a = (val & IWL_OFDM_RSSI_INBAND_A_MSK) >> IWL_OFDM_RSSI_A_POS;  	rssi_b = (val & IWL_OFDM_RSSI_INBAND_B_MSK) >> IWL_OFDM_RSSI_B_POS; -	val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_RSSI_C_IDX]); -	rssi_c = (val & IWL_OFDM_RSSI_INBAND_C_MSK) >> IWL_OFDM_RSSI_C_POS; - -	val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_AGC_IDX]); -	agc_db = (val & IWL_OFDM_AGC_DB_MSK) >> IWL_OFDM_AGC_DB_POS; +	rssi_all_band_a = (val & IWL_OFDM_RSSI_ALLBAND_A_MSK) >> +				IWL_OFDM_RSSI_ALLBAND_A_POS; +	rssi_all_band_b = (val & IWL_OFDM_RSSI_ALLBAND_B_MSK) >> +				IWL_OFDM_RSSI_ALLBAND_B_POS; -	max_rssi = max_t(u32, rssi_a, rssi_b); -	max_rssi = max_t(u32, max_rssi, rssi_c); +	/* +	 * dBm = rssi dB - agc dB - constant. +	 * Higher AGC (higher radio gain) means lower signal. +	 */ +	rssi_a_dbm = rssi_a - IWL_RSSI_OFFSET - agc_a; +	rssi_b_dbm = rssi_b - IWL_RSSI_OFFSET - agc_b; +	max_rssi_dbm = max_t(int, rssi_a_dbm, rssi_b_dbm); -	IWL_DEBUG_STATS(mvm, "Rssi In A %d B %d C %d Max %d AGC dB %d\n", -			rssi_a, rssi_b, rssi_c, max_rssi, agc_db); +	IWL_DEBUG_STATS(mvm, "Rssi In A %d B %d Max %d AGCA %d AGCB %d\n", +			rssi_a_dbm, rssi_b_dbm, max_rssi_dbm, agc_a, agc_b); -	/* dBm = max_rssi dB - agc dB - constant. -	 * Higher AGC (higher radio gain) means lower signal. */ -	return max_rssi - agc_db - IWL_RSSI_OFFSET; +	return max_rssi_dbm;  }  /* diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 861a7f9f8e7..274f44e2ef6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -770,6 +770,16 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  	u16 txq_id;  	int err; + +	/* +	 * If mac80211 is cleaning its state, then say that we finished since +	 * our state has been cleared anyway. +	 */ +	if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { +		ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); +		return 0; +	} +  	spin_lock_bh(&mvmsta->lock);  	txq_id = tid_data->txq_id; diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index 6b67ce3f679..6645efe5c03 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -607,12 +607,8 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,  		/* Single frame failure in an AMPDU queue => send BAR */  		if (txq_id >= IWL_FIRST_AMPDU_QUEUE && -		    !(info->flags & IEEE80211_TX_STAT_ACK)) { -			/* there must be only one skb in the skb_list */ -			WARN_ON_ONCE(skb_freed > 1 || -				     !skb_queue_empty(&skbs)); +		    !(info->flags & IEEE80211_TX_STAT_ACK))  			info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; -		}  		/* W/A FW bug: seq_ctl is wrong when the queue is flushed */  		if (status == TX_STATUS_FAIL_FIFO_FLUSHED) { diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index 3d62e805535..148843e7f34 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h @@ -137,10 +137,6 @@ static inline int iwl_queue_dec_wrap(int index, int n_bd)  struct iwl_cmd_meta {  	/* only for SYNC commands, iff the reply skb is wanted */  	struct iwl_host_cmd *source; - -	DEFINE_DMA_UNMAP_ADDR(mapping); -	DEFINE_DMA_UNMAP_LEN(len); -  	u32 flags;  }; @@ -185,25 +181,36 @@ struct iwl_queue {  /*   * The FH will write back to the first TB only, so we need   * to copy some data into the buffer regardless of whether - * it should be mapped or not. This indicates how much to - * copy, even for HCMDs it must be big enough to fit the - * DRAM scratch from the TX cmd, at least 16 bytes. + * it should be mapped or not. This indicates how big the + * first TB must be to include the scratch buffer. Since + * the scratch is 4 bytes at offset 12, it's 16 now. If we + * make it bigger then allocations will be bigger and copy + * slower, so that's probably not useful.   */ -#define IWL_HCMD_MIN_COPY_SIZE	16 +#define IWL_HCMD_SCRATCHBUF_SIZE	16  struct iwl_pcie_txq_entry {  	struct iwl_device_cmd *cmd; -	struct iwl_device_cmd *copy_cmd;  	struct sk_buff *skb;  	/* buffer to free after command completes */  	const void *free_buf;  	struct iwl_cmd_meta meta;  }; +struct iwl_pcie_txq_scratch_buf { +	struct iwl_cmd_header hdr; +	u8 buf[8]; +	__le32 scratch; +}; +  /**   * struct iwl_txq - Tx Queue for DMA   * @q: generic Rx/Tx queue descriptor   * @tfds: transmit frame descriptors (DMA memory) + * @scratchbufs: start of command headers, including scratch buffers, for + *	the writeback -- this is DMA memory and an array holding one buffer + *	for each command on the queue + * @scratchbufs_dma: DMA address for the scratchbufs start   * @entries: transmit entries (driver state)   * @lock: queue lock   * @stuck_timer: timer that fires if queue gets stuck @@ -217,6 +224,8 @@ struct iwl_pcie_txq_entry {  struct iwl_txq {  	struct iwl_queue q;  	struct iwl_tfd *tfds; +	struct iwl_pcie_txq_scratch_buf *scratchbufs; +	dma_addr_t scratchbufs_dma;  	struct iwl_pcie_txq_entry *entries;  	spinlock_t lock;  	struct timer_list stuck_timer; @@ -225,6 +234,13 @@ struct iwl_txq {  	u8 active;  }; +static inline dma_addr_t +iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx) +{ +	return txq->scratchbufs_dma + +	       sizeof(struct iwl_pcie_txq_scratch_buf) * idx; +} +  /**   * struct iwl_trans_pcie - PCIe transport specific data   * @rxq: all the RX queue data diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index b0ae06d2456..567e67ad1f6 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c @@ -637,22 +637,14 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,  		index = SEQ_TO_INDEX(sequence);  		cmd_index = get_cmd_index(&txq->q, index); -		if (reclaim) { -			struct iwl_pcie_txq_entry *ent; -			ent = &txq->entries[cmd_index]; -			cmd = ent->copy_cmd; -			WARN_ON_ONCE(!cmd && ent->meta.flags & CMD_WANT_HCMD); -		} else { +		if (reclaim) +			cmd = txq->entries[cmd_index].cmd; +		else  			cmd = NULL; -		}  		err = iwl_op_mode_rx(trans->op_mode, &rxcb, cmd);  		if (reclaim) { -			/* The original command isn't needed any more */ -			kfree(txq->entries[cmd_index].copy_cmd); -			txq->entries[cmd_index].copy_cmd = NULL; -			/* nor is the duplicated part of the command */  			kfree(txq->entries[cmd_index].free_buf);  			txq->entries[cmd_index].free_buf = NULL;  		} diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 17bedc50e75..12c4f31ca8f 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -475,6 +475,10 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,  	/* If platform's RF_KILL switch is NOT set to KILL */  	hw_rfkill = iwl_is_rfkill_set(trans); +	if (hw_rfkill) +		set_bit(STATUS_RFKILL, &trans_pcie->status); +	else +		clear_bit(STATUS_RFKILL, &trans_pcie->status);  	iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);  	if (hw_rfkill && !run_in_rfkill)  		return -ERFKILL; @@ -641,6 +645,7 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,  static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)  { +	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);  	bool hw_rfkill;  	int err; @@ -656,6 +661,10 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)  	iwl_enable_rfkill_int(trans);  	hw_rfkill = iwl_is_rfkill_set(trans); +	if (hw_rfkill) +		set_bit(STATUS_RFKILL, &trans_pcie->status); +	else +		clear_bit(STATUS_RFKILL, &trans_pcie->status);  	iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);  	return 0; @@ -694,6 +703,10 @@ static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans,  		 * op_mode.  		 */  		hw_rfkill = iwl_is_rfkill_set(trans); +		if (hw_rfkill) +			set_bit(STATUS_RFKILL, &trans_pcie->status); +		else +			clear_bit(STATUS_RFKILL, &trans_pcie->status);  		iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);  	}  } diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 8b625a7f568..cb5c6792e3a 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -191,12 +191,9 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data)  	}  	for (i = q->read_ptr; i != q->write_ptr; -	     i = iwl_queue_inc_wrap(i, q->n_bd)) { -		struct iwl_tx_cmd *tx_cmd = -			(struct iwl_tx_cmd *)txq->entries[i].cmd->payload; +	     i = iwl_queue_inc_wrap(i, q->n_bd))  		IWL_ERR(trans, "scratch %d = 0x%08x\n", i, -			get_unaligned_le32(&tx_cmd->scratch)); -	} +			le32_to_cpu(txq->scratchbufs[i].scratch));  	iwl_op_mode_nic_error(trans->op_mode);  } @@ -367,8 +364,8 @@ static inline u8 iwl_pcie_tfd_get_num_tbs(struct iwl_tfd *tfd)  }  static void iwl_pcie_tfd_unmap(struct iwl_trans *trans, -			       struct iwl_cmd_meta *meta, struct iwl_tfd *tfd, -			       enum dma_data_direction dma_dir) +			       struct iwl_cmd_meta *meta, +			       struct iwl_tfd *tfd)  {  	int i;  	int num_tbs; @@ -382,17 +379,12 @@ static void iwl_pcie_tfd_unmap(struct iwl_trans *trans,  		return;  	} -	/* Unmap tx_cmd */ -	if (num_tbs) -		dma_unmap_single(trans->dev, -				dma_unmap_addr(meta, mapping), -				dma_unmap_len(meta, len), -				DMA_BIDIRECTIONAL); +	/* first TB is never freed - it's the scratchbuf data */ -	/* Unmap chunks, if any. */  	for (i = 1; i < num_tbs; i++)  		dma_unmap_single(trans->dev, iwl_pcie_tfd_tb_get_addr(tfd, i), -				 iwl_pcie_tfd_tb_get_len(tfd, i), dma_dir); +				 iwl_pcie_tfd_tb_get_len(tfd, i), +				 DMA_TO_DEVICE);  	tfd->num_tbs = 0;  } @@ -406,8 +398,7 @@ static void iwl_pcie_tfd_unmap(struct iwl_trans *trans,   * Does NOT advance any TFD circular buffer read/write indexes   * Does NOT free the TFD itself (which is within circular buffer)   */ -static void iwl_pcie_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq, -				  enum dma_data_direction dma_dir) +static void iwl_pcie_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq)  {  	struct iwl_tfd *tfd_tmp = txq->tfds; @@ -418,8 +409,7 @@ static void iwl_pcie_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq,  	lockdep_assert_held(&txq->lock);  	/* We have only q->n_window txq->entries, but we use q->n_bd tfds */ -	iwl_pcie_tfd_unmap(trans, &txq->entries[idx].meta, &tfd_tmp[rd_ptr], -			   dma_dir); +	iwl_pcie_tfd_unmap(trans, &txq->entries[idx].meta, &tfd_tmp[rd_ptr]);  	/* free SKB */  	if (txq->entries) { @@ -479,6 +469,7 @@ static int iwl_pcie_txq_alloc(struct iwl_trans *trans,  {  	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);  	size_t tfd_sz = sizeof(struct iwl_tfd) * TFD_QUEUE_SIZE_MAX; +	size_t scratchbuf_sz;  	int i;  	if (WARN_ON(txq->entries || txq->tfds)) @@ -514,9 +505,25 @@ static int iwl_pcie_txq_alloc(struct iwl_trans *trans,  		IWL_ERR(trans, "dma_alloc_coherent(%zd) failed\n", tfd_sz);  		goto error;  	} + +	BUILD_BUG_ON(IWL_HCMD_SCRATCHBUF_SIZE != sizeof(*txq->scratchbufs)); +	BUILD_BUG_ON(offsetof(struct iwl_pcie_txq_scratch_buf, scratch) != +			sizeof(struct iwl_cmd_header) + +			offsetof(struct iwl_tx_cmd, scratch)); + +	scratchbuf_sz = sizeof(*txq->scratchbufs) * slots_num; + +	txq->scratchbufs = dma_alloc_coherent(trans->dev, scratchbuf_sz, +					      &txq->scratchbufs_dma, +					      GFP_KERNEL); +	if (!txq->scratchbufs) +		goto err_free_tfds; +  	txq->q.id = txq_id;  	return 0; +err_free_tfds: +	dma_free_coherent(trans->dev, tfd_sz, txq->tfds, txq->q.dma_addr);  error:  	if (txq->entries && txq_id == trans_pcie->cmd_queue)  		for (i = 0; i < slots_num; i++) @@ -565,22 +572,13 @@ static void iwl_pcie_txq_unmap(struct iwl_trans *trans, int txq_id)  	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);  	struct iwl_txq *txq = &trans_pcie->txq[txq_id];  	struct iwl_queue *q = &txq->q; -	enum dma_data_direction dma_dir;  	if (!q->n_bd)  		return; -	/* In the command queue, all the TBs are mapped as BIDI -	 * so unmap them as such. -	 */ -	if (txq_id == trans_pcie->cmd_queue) -		dma_dir = DMA_BIDIRECTIONAL; -	else -		dma_dir = DMA_TO_DEVICE; -  	spin_lock_bh(&txq->lock);  	while (q->write_ptr != q->read_ptr) { -		iwl_pcie_txq_free_tfd(trans, txq, dma_dir); +		iwl_pcie_txq_free_tfd(trans, txq);  		q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd);  	}  	spin_unlock_bh(&txq->lock); @@ -610,7 +608,6 @@ static void iwl_pcie_txq_free(struct iwl_trans *trans, int txq_id)  	if (txq_id == trans_pcie->cmd_queue)  		for (i = 0; i < txq->q.n_window; i++) {  			kfree(txq->entries[i].cmd); -			kfree(txq->entries[i].copy_cmd);  			kfree(txq->entries[i].free_buf);  		} @@ -619,6 +616,10 @@ static void iwl_pcie_txq_free(struct iwl_trans *trans, int txq_id)  		dma_free_coherent(dev, sizeof(struct iwl_tfd) *  				  txq->q.n_bd, txq->tfds, txq->q.dma_addr);  		txq->q.dma_addr = 0; + +		dma_free_coherent(dev, +				  sizeof(*txq->scratchbufs) * txq->q.n_window, +				  txq->scratchbufs, txq->scratchbufs_dma);  	}  	kfree(txq->entries); @@ -962,7 +963,7 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,  		iwl_pcie_txq_inval_byte_cnt_tbl(trans, txq); -		iwl_pcie_txq_free_tfd(trans, txq, DMA_TO_DEVICE); +		iwl_pcie_txq_free_tfd(trans, txq);  	}  	iwl_pcie_txq_progress(trans_pcie, txq); @@ -1152,29 +1153,29 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,  	void *dup_buf = NULL;  	dma_addr_t phys_addr;  	int idx; -	u16 copy_size, cmd_size, dma_size; +	u16 copy_size, cmd_size, scratch_size;  	bool had_nocopy = false;  	int i;  	u32 cmd_pos; -	const u8 *cmddata[IWL_MAX_CMD_TFDS]; -	u16 cmdlen[IWL_MAX_CMD_TFDS]; +	const u8 *cmddata[IWL_MAX_CMD_TBS_PER_TFD]; +	u16 cmdlen[IWL_MAX_CMD_TBS_PER_TFD];  	copy_size = sizeof(out_cmd->hdr);  	cmd_size = sizeof(out_cmd->hdr);  	/* need one for the header if the first is NOCOPY */ -	BUILD_BUG_ON(IWL_MAX_CMD_TFDS > IWL_NUM_OF_TBS - 1); +	BUILD_BUG_ON(IWL_MAX_CMD_TBS_PER_TFD > IWL_NUM_OF_TBS - 1); -	for (i = 0; i < IWL_MAX_CMD_TFDS; i++) { +	for (i = 0; i < IWL_MAX_CMD_TBS_PER_TFD; i++) {  		cmddata[i] = cmd->data[i];  		cmdlen[i] = cmd->len[i];  		if (!cmd->len[i])  			continue; -		/* need at least IWL_HCMD_MIN_COPY_SIZE copied */ -		if (copy_size < IWL_HCMD_MIN_COPY_SIZE) { -			int copy = IWL_HCMD_MIN_COPY_SIZE - copy_size; +		/* need at least IWL_HCMD_SCRATCHBUF_SIZE copied */ +		if (copy_size < IWL_HCMD_SCRATCHBUF_SIZE) { +			int copy = IWL_HCMD_SCRATCHBUF_SIZE - copy_size;  			if (copy > cmdlen[i])  				copy = cmdlen[i]; @@ -1260,15 +1261,15 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,  	/* and copy the data that needs to be copied */  	cmd_pos = offsetof(struct iwl_device_cmd, payload);  	copy_size = sizeof(out_cmd->hdr); -	for (i = 0; i < IWL_MAX_CMD_TFDS; i++) { +	for (i = 0; i < IWL_MAX_CMD_TBS_PER_TFD; i++) {  		int copy = 0; -		if (!cmd->len) +		if (!cmd->len[i])  			continue; -		/* need at least IWL_HCMD_MIN_COPY_SIZE copied */ -		if (copy_size < IWL_HCMD_MIN_COPY_SIZE) { -			copy = IWL_HCMD_MIN_COPY_SIZE - copy_size; +		/* need at least IWL_HCMD_SCRATCHBUF_SIZE copied */ +		if (copy_size < IWL_HCMD_SCRATCHBUF_SIZE) { +			copy = IWL_HCMD_SCRATCHBUF_SIZE - copy_size;  			if (copy > cmd->len[i])  				copy = cmd->len[i]; @@ -1286,50 +1287,38 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,  		}  	} -	WARN_ON_ONCE(txq->entries[idx].copy_cmd); - -	/* -	 * since out_cmd will be the source address of the FH, it will write -	 * the retry count there. So when the user needs to receivce the HCMD -	 * that corresponds to the response in the response handler, it needs -	 * to set CMD_WANT_HCMD. -	 */ -	if (cmd->flags & CMD_WANT_HCMD) { -		txq->entries[idx].copy_cmd = -			kmemdup(out_cmd, cmd_pos, GFP_ATOMIC); -		if (unlikely(!txq->entries[idx].copy_cmd)) { -			idx = -ENOMEM; -			goto out; -		} -	} -  	IWL_DEBUG_HC(trans,  		     "Sending command %s (#%x), seq: 0x%04X, %d bytes at %d[%d]:%d\n",  		     get_cmd_string(trans_pcie, out_cmd->hdr.cmd),  		     out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence),  		     cmd_size, q->write_ptr, idx, trans_pcie->cmd_queue); -	/* -	 * If the entire command is smaller than IWL_HCMD_MIN_COPY_SIZE, we must -	 * still map at least that many bytes for the hardware to write back to. -	 * We have enough space, so that's not a problem. -	 */ -	dma_size = max_t(u16, copy_size, IWL_HCMD_MIN_COPY_SIZE); +	/* start the TFD with the scratchbuf */ +	scratch_size = min_t(int, copy_size, IWL_HCMD_SCRATCHBUF_SIZE); +	memcpy(&txq->scratchbufs[q->write_ptr], &out_cmd->hdr, scratch_size); +	iwl_pcie_txq_build_tfd(trans, txq, +			       iwl_pcie_get_scratchbuf_dma(txq, q->write_ptr), +			       scratch_size, 1); -	phys_addr = dma_map_single(trans->dev, &out_cmd->hdr, dma_size, -				   DMA_BIDIRECTIONAL); -	if (unlikely(dma_mapping_error(trans->dev, phys_addr))) { -		idx = -ENOMEM; -		goto out; -	} - -	dma_unmap_addr_set(out_meta, mapping, phys_addr); -	dma_unmap_len_set(out_meta, len, dma_size); +	/* map first command fragment, if any remains */ +	if (copy_size > scratch_size) { +		phys_addr = dma_map_single(trans->dev, +					   ((u8 *)&out_cmd->hdr) + scratch_size, +					   copy_size - scratch_size, +					   DMA_TO_DEVICE); +		if (dma_mapping_error(trans->dev, phys_addr)) { +			iwl_pcie_tfd_unmap(trans, out_meta, +					   &txq->tfds[q->write_ptr]); +			idx = -ENOMEM; +			goto out; +		} -	iwl_pcie_txq_build_tfd(trans, txq, phys_addr, copy_size, 1); +		iwl_pcie_txq_build_tfd(trans, txq, phys_addr, +				       copy_size - scratch_size, 0); +	}  	/* map the remaining (adjusted) nocopy/dup fragments */ -	for (i = 0; i < IWL_MAX_CMD_TFDS; i++) { +	for (i = 0; i < IWL_MAX_CMD_TBS_PER_TFD; i++) {  		const void *data = cmddata[i];  		if (!cmdlen[i]) @@ -1340,11 +1329,10 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,  		if (cmd->dataflags[i] & IWL_HCMD_DFL_DUP)  			data = dup_buf;  		phys_addr = dma_map_single(trans->dev, (void *)data, -					   cmdlen[i], DMA_BIDIRECTIONAL); +					   cmdlen[i], DMA_TO_DEVICE);  		if (dma_mapping_error(trans->dev, phys_addr)) {  			iwl_pcie_tfd_unmap(trans, out_meta, -					   &txq->tfds[q->write_ptr], -					   DMA_BIDIRECTIONAL); +					   &txq->tfds[q->write_ptr]);  			idx = -ENOMEM;  			goto out;  		} @@ -1418,7 +1406,7 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans,  	cmd = txq->entries[cmd_index].cmd;  	meta = &txq->entries[cmd_index].meta; -	iwl_pcie_tfd_unmap(trans, meta, &txq->tfds[index], DMA_BIDIRECTIONAL); +	iwl_pcie_tfd_unmap(trans, meta, &txq->tfds[index]);  	/* Input error checking is done when commands are added to queue. */  	if (meta->flags & CMD_WANT_SKB) { @@ -1597,10 +1585,9 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,  	struct iwl_cmd_meta *out_meta;  	struct iwl_txq *txq;  	struct iwl_queue *q; -	dma_addr_t phys_addr = 0; -	dma_addr_t txcmd_phys; -	dma_addr_t scratch_phys; -	u16 len, firstlen, secondlen; +	dma_addr_t tb0_phys, tb1_phys, scratch_phys; +	void *tb1_addr; +	u16 len, tb1_len, tb2_len;  	u8 wait_write_ptr = 0;  	__le16 fc = hdr->frame_control;  	u8 hdr_len = ieee80211_hdrlen(fc); @@ -1638,85 +1625,80 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,  		cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) |  			    INDEX_TO_SEQ(q->write_ptr))); +	tb0_phys = iwl_pcie_get_scratchbuf_dma(txq, q->write_ptr); +	scratch_phys = tb0_phys + sizeof(struct iwl_cmd_header) + +		       offsetof(struct iwl_tx_cmd, scratch); + +	tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys); +	tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys); +  	/* Set up first empty entry in queue's array of Tx/cmd buffers */  	out_meta = &txq->entries[q->write_ptr].meta;  	/* -	 * Use the first empty entry in this queue's command buffer array -	 * to contain the Tx command and MAC header concatenated together -	 * (payload data will be in another buffer). -	 * Size of this varies, due to varying MAC header length. -	 * If end is not dword aligned, we'll have 2 extra bytes at the end -	 * of the MAC header (device reads on dword boundaries). -	 * We'll tell device about this padding later. +	 * The second TB (tb1) points to the remainder of the TX command +	 * and the 802.11 header - dword aligned size +	 * (This calculation modifies the TX command, so do it before the +	 * setup of the first TB)  	 */ -	len = sizeof(struct iwl_tx_cmd) + -		sizeof(struct iwl_cmd_header) + hdr_len; -	firstlen = (len + 3) & ~3; +	len = sizeof(struct iwl_tx_cmd) + sizeof(struct iwl_cmd_header) + +	      hdr_len - IWL_HCMD_SCRATCHBUF_SIZE; +	tb1_len = (len + 3) & ~3;  	/* Tell NIC about any 2-byte padding after MAC header */ -	if (firstlen != len) +	if (tb1_len != len)  		tx_cmd->tx_flags |= TX_CMD_FLG_MH_PAD_MSK; -	/* Physical address of this Tx command's header (not MAC header!), -	 * within command buffer array. */ -	txcmd_phys = dma_map_single(trans->dev, -				    &dev_cmd->hdr, firstlen, -				    DMA_BIDIRECTIONAL); -	if (unlikely(dma_mapping_error(trans->dev, txcmd_phys))) -		goto out_err; -	dma_unmap_addr_set(out_meta, mapping, txcmd_phys); -	dma_unmap_len_set(out_meta, len, firstlen); +	/* The first TB points to the scratchbuf data - min_copy bytes */ +	memcpy(&txq->scratchbufs[q->write_ptr], &dev_cmd->hdr, +	       IWL_HCMD_SCRATCHBUF_SIZE); +	iwl_pcie_txq_build_tfd(trans, txq, tb0_phys, +			       IWL_HCMD_SCRATCHBUF_SIZE, 1); -	if (!ieee80211_has_morefrags(fc)) { -		txq->need_update = 1; -	} else { -		wait_write_ptr = 1; -		txq->need_update = 0; -	} +	/* there must be data left over for TB1 or this code must be changed */ +	BUILD_BUG_ON(sizeof(struct iwl_tx_cmd) < IWL_HCMD_SCRATCHBUF_SIZE); -	/* Set up TFD's 2nd entry to point directly to remainder of skb, -	 * if any (802.11 null frames have no payload). */ -	secondlen = skb->len - hdr_len; -	if (secondlen > 0) { -		phys_addr = dma_map_single(trans->dev, skb->data + hdr_len, -					   secondlen, DMA_TO_DEVICE); -		if (unlikely(dma_mapping_error(trans->dev, phys_addr))) { -			dma_unmap_single(trans->dev, -					 dma_unmap_addr(out_meta, mapping), -					 dma_unmap_len(out_meta, len), -					 DMA_BIDIRECTIONAL); +	/* map the data for TB1 */ +	tb1_addr = ((u8 *)&dev_cmd->hdr) + IWL_HCMD_SCRATCHBUF_SIZE; +	tb1_phys = dma_map_single(trans->dev, tb1_addr, tb1_len, DMA_TO_DEVICE); +	if (unlikely(dma_mapping_error(trans->dev, tb1_phys))) +		goto out_err; +	iwl_pcie_txq_build_tfd(trans, txq, tb1_phys, tb1_len, 0); + +	/* +	 * Set up TFD's third entry to point directly to remainder +	 * of skb, if any (802.11 null frames have no payload). +	 */ +	tb2_len = skb->len - hdr_len; +	if (tb2_len > 0) { +		dma_addr_t tb2_phys = dma_map_single(trans->dev, +						     skb->data + hdr_len, +						     tb2_len, DMA_TO_DEVICE); +		if (unlikely(dma_mapping_error(trans->dev, tb2_phys))) { +			iwl_pcie_tfd_unmap(trans, out_meta, +					   &txq->tfds[q->write_ptr]);  			goto out_err;  		} +		iwl_pcie_txq_build_tfd(trans, txq, tb2_phys, tb2_len, 0);  	} -	/* Attach buffers to TFD */ -	iwl_pcie_txq_build_tfd(trans, txq, txcmd_phys, firstlen, 1); -	if (secondlen > 0) -		iwl_pcie_txq_build_tfd(trans, txq, phys_addr, secondlen, 0); - -	scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) + -				offsetof(struct iwl_tx_cmd, scratch); - -	/* take back ownership of DMA buffer to enable update */ -	dma_sync_single_for_cpu(trans->dev, txcmd_phys, firstlen, -				DMA_BIDIRECTIONAL); -	tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys); -	tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys); -  	/* Set up entry for this TFD in Tx byte-count array */  	iwl_pcie_txq_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len)); -	dma_sync_single_for_device(trans->dev, txcmd_phys, firstlen, -				   DMA_BIDIRECTIONAL); -  	trace_iwlwifi_dev_tx(trans->dev, skb,  			     &txq->tfds[txq->q.write_ptr],  			     sizeof(struct iwl_tfd), -			     &dev_cmd->hdr, firstlen, -			     skb->data + hdr_len, secondlen); +			     &dev_cmd->hdr, IWL_HCMD_SCRATCHBUF_SIZE + tb1_len, +			     skb->data + hdr_len, tb2_len);  	trace_iwlwifi_dev_tx_data(trans->dev, skb, -				  skb->data + hdr_len, secondlen); +				  skb->data + hdr_len, tb2_len); + +	if (!ieee80211_has_morefrags(fc)) { +		txq->need_update = 1; +	} else { +		wait_write_ptr = 1; +		txq->need_update = 0; +	}  	/* start timer if queue currently empty */  	if (txq->need_update && q->read_ptr == q->write_ptr && diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index a44023a7bd5..8aaf56ade4d 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1892,7 +1892,8 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,  		}  	} -	for (i = 0; i < request->n_channels; i++) { +	for (i = 0; i < min_t(u32, request->n_channels, +			      MWIFIEX_USER_SCAN_CHAN_MAX); i++) {  		chan = request->channels[i];  		priv->user_scan_cfg->chan_list[i].chan_number = chan->hw_value;  		priv->user_scan_cfg->chan_list[i].radio_type = chan->band; diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 20a6c555587..b5c8b962ce1 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -157,6 +157,20 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,  		return -1;  	} +	cmd_code = le16_to_cpu(host_cmd->command); +	cmd_size = le16_to_cpu(host_cmd->size); + +	if (adapter->hw_status == MWIFIEX_HW_STATUS_RESET && +	    cmd_code != HostCmd_CMD_FUNC_SHUTDOWN && +	    cmd_code != HostCmd_CMD_FUNC_INIT) { +		dev_err(adapter->dev, +			"DNLD_CMD: FW in reset state, ignore cmd %#x\n", +			cmd_code); +		mwifiex_complete_cmd(adapter, cmd_node); +		mwifiex_insert_cmd_to_free_q(adapter, cmd_node); +		return -1; +	} +  	/* Set command sequence number */  	adapter->seq_num++;  	host_cmd->seq_num = cpu_to_le16(HostCmd_SET_SEQ_NO_BSS_INFO @@ -168,9 +182,6 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,  	adapter->curr_cmd = cmd_node;  	spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); -	cmd_code = le16_to_cpu(host_cmd->command); -	cmd_size = le16_to_cpu(host_cmd->size); -  	/* Adjust skb length */  	if (cmd_node->cmd_skb->len > cmd_size)  		/* @@ -484,8 +495,6 @@ int mwifiex_send_cmd_sync(struct mwifiex_private *priv, uint16_t cmd_no,  	ret = mwifiex_send_cmd_async(priv, cmd_no, cmd_action, cmd_oid,  				     data_buf); -	if (!ret) -		ret = mwifiex_wait_queue_complete(adapter);  	return ret;  } @@ -588,9 +597,10 @@ int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no,  	if (cmd_no == HostCmd_CMD_802_11_SCAN) {  		mwifiex_queue_scan_cmd(priv, cmd_node);  	} else { -		adapter->cmd_queued = cmd_node;  		mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true);  		queue_work(adapter->workqueue, &adapter->main_work); +		if (cmd_node->wait_q_enabled) +			ret = mwifiex_wait_queue_complete(adapter, cmd_node);  	}  	return ret; diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index e38aa9b3663..0ff4c37ab42 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -709,6 +709,14 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter)  		return ret;  	} +	/* cancel current command */ +	if (adapter->curr_cmd) { +		dev_warn(adapter->dev, "curr_cmd is still in processing\n"); +		del_timer(&adapter->cmd_timer); +		mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd); +		adapter->curr_cmd = NULL; +	} +  	/* shut down mwifiex */  	dev_dbg(adapter->dev, "info: shutdown mwifiex...\n"); diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c index 246aa62a481..2fe0ceba440 100644 --- a/drivers/net/wireless/mwifiex/join.c +++ b/drivers/net/wireless/mwifiex/join.c @@ -1117,10 +1117,9 @@ mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv,  		adhoc_join->bss_descriptor.bssid,  		adhoc_join->bss_descriptor.ssid); -	for (i = 0; bss_desc->supported_rates[i] && -			i < MWIFIEX_SUPPORTED_RATES; -			i++) -			; +	for (i = 0; i < MWIFIEX_SUPPORTED_RATES && +		    bss_desc->supported_rates[i]; i++) +		;  	rates_size = i;  	/* Copy Data Rates from the Rates recorded in scan response */ diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 553adfb0aa8..7035ade9af7 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -723,7 +723,6 @@ struct mwifiex_adapter {  	u16 cmd_wait_q_required;  	struct mwifiex_wait_queue cmd_wait_q;  	u8 scan_wait_q_woken; -	struct cmd_ctrl_node *cmd_queued;  	spinlock_t queue_lock;		/* lock for tx queues */  	struct completion fw_load;  	u8 country_code[IEEE80211_COUNTRY_STRING_LEN]; @@ -1018,7 +1017,8 @@ int mwifiex_request_set_multicast_list(struct mwifiex_private *priv,  			struct mwifiex_multicast_list *mcast_list);  int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist,  			    struct net_device *dev); -int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter); +int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter, +				struct cmd_ctrl_node *cmd_queued);  int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,  		      struct cfg80211_ssid *req_ssid);  int mwifiex_cancel_hs(struct mwifiex_private *priv, int cmd_type); diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index 5c395e2e6a2..feb20461339 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c @@ -1508,6 +1508,7 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter)  		}  		memcpy(adapter->upld_buf, skb->data,  		       min_t(u32, MWIFIEX_SIZE_OF_CMD_BUFFER, skb->len)); +		skb_push(skb, INTF_HEADER_LEN);  		if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE,  					   PCI_DMA_FROMDEVICE))  			return -1; diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index bb60c2754a9..e7f6deaf715 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -1388,10 +1388,15 @@ int mwifiex_scan_networks(struct mwifiex_private *priv,  			list_del(&cmd_node->list);  			spin_unlock_irqrestore(&adapter->scan_pending_q_lock,  					       flags); -			adapter->cmd_queued = cmd_node;  			mwifiex_insert_cmd_to_pending_q(adapter, cmd_node,  							true);  			queue_work(adapter->workqueue, &adapter->main_work); + +			/* Perform internal scan synchronously */ +			if (!priv->scan_request) { +				dev_dbg(adapter->dev, "wait internal scan\n"); +				mwifiex_wait_queue_complete(adapter, cmd_node); +			}  		} else {  			spin_unlock_irqrestore(&adapter->scan_pending_q_lock,  					       flags); @@ -1790,7 +1795,12 @@ check_next_scan:  		/* Need to indicate IOCTL complete */  		if (adapter->curr_cmd->wait_q_enabled) {  			adapter->cmd_wait_q.status = 0; -			mwifiex_complete_cmd(adapter, adapter->curr_cmd); +			if (!priv->scan_request) { +				dev_dbg(adapter->dev, +					"complete internal scan\n"); +				mwifiex_complete_cmd(adapter, +						     adapter->curr_cmd); +			}  		}  		if (priv->report_scan_result)  			priv->report_scan_result = false; @@ -1946,9 +1956,6 @@ int mwifiex_request_scan(struct mwifiex_private *priv,  		/* Normal scan */  		ret = mwifiex_scan_networks(priv, NULL); -	if (!ret) -		ret = mwifiex_wait_queue_complete(priv->adapter); -  	up(&priv->async_sem);  	return ret; diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index 9f33c92c90f..13100f8de3d 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -54,16 +54,10 @@ int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist,   * This function waits on a cmd wait queue. It also cancels the pending   * request after waking up, in case of errors.   */ -int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter) +int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter, +				struct cmd_ctrl_node *cmd_queued)  {  	int status; -	struct cmd_ctrl_node *cmd_queued; - -	if (!adapter->cmd_queued) -		return 0; - -	cmd_queued = adapter->cmd_queued; -	adapter->cmd_queued = NULL;  	dev_dbg(adapter->dev, "cmd pending\n");  	atomic_inc(&adapter->cmd_pending); diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index 44d6ead4334..76cd47eb901 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -20,6 +20,7 @@ if RT2X00  config RT2400PCI  	tristate "Ralink rt2400 (PCI/PCMCIA) support"  	depends on PCI +	select RT2X00_LIB_MMIO  	select RT2X00_LIB_PCI  	select EEPROM_93CX6  	---help--- @@ -31,6 +32,7 @@ config RT2400PCI  config RT2500PCI  	tristate "Ralink rt2500 (PCI/PCMCIA) support"  	depends on PCI +	select RT2X00_LIB_MMIO  	select RT2X00_LIB_PCI  	select EEPROM_93CX6  	---help--- @@ -43,6 +45,7 @@ config RT61PCI  	tristate "Ralink rt2501/rt61 (PCI/PCMCIA) support"  	depends on PCI  	select RT2X00_LIB_PCI +	select RT2X00_LIB_MMIO  	select RT2X00_LIB_FIRMWARE  	select RT2X00_LIB_CRYPTO  	select CRC_ITU_T @@ -55,10 +58,11 @@ config RT61PCI  config RT2800PCI  	tristate "Ralink rt27xx/rt28xx/rt30xx (PCI/PCIe/PCMCIA) support" -	depends on PCI || RALINK_RT288X || RALINK_RT305X +	depends on PCI || SOC_RT288X || SOC_RT305X  	select RT2800_LIB +	select RT2X00_LIB_MMIO  	select RT2X00_LIB_PCI if PCI -	select RT2X00_LIB_SOC if RALINK_RT288X || RALINK_RT305X +	select RT2X00_LIB_SOC if SOC_RT288X || SOC_RT305X  	select RT2X00_LIB_FIRMWARE  	select RT2X00_LIB_CRYPTO  	select CRC_CCITT @@ -185,6 +189,9 @@ endif  config RT2800_LIB  	tristate +config RT2X00_LIB_MMIO +	tristate +  config RT2X00_LIB_PCI  	tristate  	select RT2X00_LIB diff --git a/drivers/net/wireless/rt2x00/Makefile b/drivers/net/wireless/rt2x00/Makefile index 349d5b8284a..f069d8bc5b6 100644 --- a/drivers/net/wireless/rt2x00/Makefile +++ b/drivers/net/wireless/rt2x00/Makefile @@ -9,6 +9,7 @@ rt2x00lib-$(CONFIG_RT2X00_LIB_FIRMWARE)	+= rt2x00firmware.o  rt2x00lib-$(CONFIG_RT2X00_LIB_LEDS)	+= rt2x00leds.o  obj-$(CONFIG_RT2X00_LIB)		+= rt2x00lib.o +obj-$(CONFIG_RT2X00_LIB_MMIO)		+= rt2x00mmio.o  obj-$(CONFIG_RT2X00_LIB_PCI)		+= rt2x00pci.o  obj-$(CONFIG_RT2X00_LIB_SOC)		+= rt2x00soc.o  obj-$(CONFIG_RT2X00_LIB_USB)		+= rt2x00usb.o diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 221beaaa83f..dcfb54e0c51 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -34,6 +34,7 @@  #include <linux/slab.h>  #include "rt2x00.h" +#include "rt2x00mmio.h"  #include "rt2x00pci.h"  #include "rt2400pci.h" diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 39edc59e8d0..e1d2dc9ed28 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -34,6 +34,7 @@  #include <linux/slab.h>  #include "rt2x00.h" +#include "rt2x00mmio.h"  #include "rt2x00pci.h"  #include "rt2500pci.h" diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 48a01aa21f1..ba5a05625aa 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -41,6 +41,7 @@  #include <linux/eeprom_93cx6.h>  #include "rt2x00.h" +#include "rt2x00mmio.h"  #include "rt2x00pci.h"  #include "rt2x00soc.h"  #include "rt2800lib.h" @@ -89,7 +90,7 @@ static void rt2800pci_mcu_status(struct rt2x00_dev *rt2x00dev, const u8 token)  	rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);  } -#if defined(CONFIG_RALINK_RT288X) || defined(CONFIG_RALINK_RT305X) +#if defined(CONFIG_SOC_RT288X) || defined(CONFIG_SOC_RT305X)  static int rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)  {  	void __iomem *base_addr = ioremap(0x1F040000, EEPROM_SIZE); @@ -107,7 +108,7 @@ static inline int rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)  {  	return -ENOMEM;  } -#endif /* CONFIG_RALINK_RT288X || CONFIG_RALINK_RT305X */ +#endif /* CONFIG_SOC_RT288X || CONFIG_SOC_RT305X */  #ifdef CONFIG_PCI  static void rt2800pci_eepromregister_read(struct eeprom_93cx6 *eeprom) @@ -1177,7 +1178,7 @@ MODULE_DEVICE_TABLE(pci, rt2800pci_device_table);  #endif /* CONFIG_PCI */  MODULE_LICENSE("GPL"); -#if defined(CONFIG_RALINK_RT288X) || defined(CONFIG_RALINK_RT305X) +#if defined(CONFIG_SOC_RT288X) || defined(CONFIG_SOC_RT305X)  static int rt2800soc_probe(struct platform_device *pdev)  {  	return rt2x00soc_probe(pdev, &rt2800pci_ops); @@ -1194,7 +1195,7 @@ static struct platform_driver rt2800soc_driver = {  	.suspend	= rt2x00soc_suspend,  	.resume		= rt2x00soc_resume,  }; -#endif /* CONFIG_RALINK_RT288X || CONFIG_RALINK_RT305X */ +#endif /* CONFIG_SOC_RT288X || CONFIG_SOC_RT305X */  #ifdef CONFIG_PCI  static int rt2800pci_probe(struct pci_dev *pci_dev, @@ -1217,7 +1218,7 @@ static int __init rt2800pci_init(void)  {  	int ret = 0; -#if defined(CONFIG_RALINK_RT288X) || defined(CONFIG_RALINK_RT305X) +#if defined(CONFIG_SOC_RT288X) || defined(CONFIG_SOC_RT305X)  	ret = platform_driver_register(&rt2800soc_driver);  	if (ret)  		return ret; @@ -1225,7 +1226,7 @@ static int __init rt2800pci_init(void)  #ifdef CONFIG_PCI  	ret = pci_register_driver(&rt2800pci_driver);  	if (ret) { -#if defined(CONFIG_RALINK_RT288X) || defined(CONFIG_RALINK_RT305X) +#if defined(CONFIG_SOC_RT288X) || defined(CONFIG_SOC_RT305X)  		platform_driver_unregister(&rt2800soc_driver);  #endif  		return ret; @@ -1240,7 +1241,7 @@ static void __exit rt2800pci_exit(void)  #ifdef CONFIG_PCI  	pci_unregister_driver(&rt2800pci_driver);  #endif -#if defined(CONFIG_RALINK_RT288X) || defined(CONFIG_RALINK_RT305X) +#if defined(CONFIG_SOC_RT288X) || defined(CONFIG_SOC_RT305X)  	platform_driver_unregister(&rt2800soc_driver);  #endif  } diff --git a/drivers/net/wireless/rt2x00/rt2x00mmio.c b/drivers/net/wireless/rt2x00/rt2x00mmio.c new file mode 100644 index 00000000000..d84a680ba0c --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00mmio.c @@ -0,0 +1,216 @@ +/* +	Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> +	<http://rt2x00.serialmonkey.com> + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the +	Free Software Foundation, Inc., +	59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* +	Module: rt2x00mmio +	Abstract: rt2x00 generic mmio device routines. + */ + +#include <linux/dma-mapping.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> + +#include "rt2x00.h" +#include "rt2x00mmio.h" + +/* + * Register access. + */ +int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev, +			   const unsigned int offset, +			   const struct rt2x00_field32 field, +			   u32 *reg) +{ +	unsigned int i; + +	if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) +		return 0; + +	for (i = 0; i < REGISTER_BUSY_COUNT; i++) { +		rt2x00pci_register_read(rt2x00dev, offset, reg); +		if (!rt2x00_get_field32(*reg, field)) +			return 1; +		udelay(REGISTER_BUSY_DELAY); +	} + +	printk_once(KERN_ERR "%s() Indirect register access failed: " +	      "offset=0x%.08x, value=0x%.08x\n", __func__, offset, *reg); +	*reg = ~0; + +	return 0; +} +EXPORT_SYMBOL_GPL(rt2x00pci_regbusy_read); + +bool rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) +{ +	struct data_queue *queue = rt2x00dev->rx; +	struct queue_entry *entry; +	struct queue_entry_priv_pci *entry_priv; +	struct skb_frame_desc *skbdesc; +	int max_rx = 16; + +	while (--max_rx) { +		entry = rt2x00queue_get_entry(queue, Q_INDEX); +		entry_priv = entry->priv_data; + +		if (rt2x00dev->ops->lib->get_entry_state(entry)) +			break; + +		/* +		 * Fill in desc fields of the skb descriptor +		 */ +		skbdesc = get_skb_frame_desc(entry->skb); +		skbdesc->desc = entry_priv->desc; +		skbdesc->desc_len = entry->queue->desc_size; + +		/* +		 * DMA is already done, notify rt2x00lib that +		 * it finished successfully. +		 */ +		rt2x00lib_dmastart(entry); +		rt2x00lib_dmadone(entry); + +		/* +		 * Send the frame to rt2x00lib for further processing. +		 */ +		rt2x00lib_rxdone(entry, GFP_ATOMIC); +	} + +	return !max_rx; +} +EXPORT_SYMBOL_GPL(rt2x00pci_rxdone); + +void rt2x00pci_flush_queue(struct data_queue *queue, bool drop) +{ +	unsigned int i; + +	for (i = 0; !rt2x00queue_empty(queue) && i < 10; i++) +		msleep(10); +} +EXPORT_SYMBOL_GPL(rt2x00pci_flush_queue); + +/* + * Device initialization handlers. + */ +static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev, +				     struct data_queue *queue) +{ +	struct queue_entry_priv_pci *entry_priv; +	void *addr; +	dma_addr_t dma; +	unsigned int i; + +	/* +	 * Allocate DMA memory for descriptor and buffer. +	 */ +	addr = dma_alloc_coherent(rt2x00dev->dev, +				  queue->limit * queue->desc_size, +				  &dma, GFP_KERNEL); +	if (!addr) +		return -ENOMEM; + +	memset(addr, 0, queue->limit * queue->desc_size); + +	/* +	 * Initialize all queue entries to contain valid addresses. +	 */ +	for (i = 0; i < queue->limit; i++) { +		entry_priv = queue->entries[i].priv_data; +		entry_priv->desc = addr + i * queue->desc_size; +		entry_priv->desc_dma = dma + i * queue->desc_size; +	} + +	return 0; +} + +static void rt2x00pci_free_queue_dma(struct rt2x00_dev *rt2x00dev, +				     struct data_queue *queue) +{ +	struct queue_entry_priv_pci *entry_priv = +	    queue->entries[0].priv_data; + +	if (entry_priv->desc) +		dma_free_coherent(rt2x00dev->dev, +				  queue->limit * queue->desc_size, +				  entry_priv->desc, entry_priv->desc_dma); +	entry_priv->desc = NULL; +} + +int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev) +{ +	struct data_queue *queue; +	int status; + +	/* +	 * Allocate DMA +	 */ +	queue_for_each(rt2x00dev, queue) { +		status = rt2x00pci_alloc_queue_dma(rt2x00dev, queue); +		if (status) +			goto exit; +	} + +	/* +	 * Register interrupt handler. +	 */ +	status = request_irq(rt2x00dev->irq, +			     rt2x00dev->ops->lib->irq_handler, +			     IRQF_SHARED, rt2x00dev->name, rt2x00dev); +	if (status) { +		ERROR(rt2x00dev, "IRQ %d allocation failed (error %d).\n", +		      rt2x00dev->irq, status); +		goto exit; +	} + +	return 0; + +exit: +	queue_for_each(rt2x00dev, queue) +		rt2x00pci_free_queue_dma(rt2x00dev, queue); + +	return status; +} +EXPORT_SYMBOL_GPL(rt2x00pci_initialize); + +void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev) +{ +	struct data_queue *queue; + +	/* +	 * Free irq line. +	 */ +	free_irq(rt2x00dev->irq, rt2x00dev); + +	/* +	 * Free DMA +	 */ +	queue_for_each(rt2x00dev, queue) +		rt2x00pci_free_queue_dma(rt2x00dev, queue); +} +EXPORT_SYMBOL_GPL(rt2x00pci_uninitialize); + +/* + * rt2x00mmio module information. + */ +MODULE_AUTHOR(DRV_PROJECT); +MODULE_VERSION(DRV_VERSION); +MODULE_DESCRIPTION("rt2x00 mmio library"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/rt2x00/rt2x00mmio.h b/drivers/net/wireless/rt2x00/rt2x00mmio.h new file mode 100644 index 00000000000..4ecaf60175b --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00mmio.h @@ -0,0 +1,119 @@ +/* +	Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> +	<http://rt2x00.serialmonkey.com> + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License as published by +	the Free Software Foundation; either version 2 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +	GNU General Public License for more details. + +	You should have received a copy of the GNU General Public License +	along with this program; if not, write to the +	Free Software Foundation, Inc., +	59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* +	Module: rt2x00mmio +	Abstract: Data structures for the rt2x00mmio module. + */ + +#ifndef RT2X00MMIO_H +#define RT2X00MMIO_H + +#include <linux/io.h> + +/* + * Register access. + */ +static inline void rt2x00pci_register_read(struct rt2x00_dev *rt2x00dev, +					   const unsigned int offset, +					   u32 *value) +{ +	*value = readl(rt2x00dev->csr.base + offset); +} + +static inline void rt2x00pci_register_multiread(struct rt2x00_dev *rt2x00dev, +						const unsigned int offset, +						void *value, const u32 length) +{ +	memcpy_fromio(value, rt2x00dev->csr.base + offset, length); +} + +static inline void rt2x00pci_register_write(struct rt2x00_dev *rt2x00dev, +					    const unsigned int offset, +					    u32 value) +{ +	writel(value, rt2x00dev->csr.base + offset); +} + +static inline void rt2x00pci_register_multiwrite(struct rt2x00_dev *rt2x00dev, +						 const unsigned int offset, +						 const void *value, +						 const u32 length) +{ +	__iowrite32_copy(rt2x00dev->csr.base + offset, value, length >> 2); +} + +/** + * rt2x00pci_regbusy_read - Read from register with busy check + * @rt2x00dev: Device pointer, see &struct rt2x00_dev. + * @offset: Register offset + * @field: Field to check if register is busy + * @reg: Pointer to where register contents should be stored + * + * This function will read the given register, and checks if the + * register is busy. If it is, it will sleep for a couple of + * microseconds before reading the register again. If the register + * is not read after a certain timeout, this function will return + * FALSE. + */ +int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev, +			   const unsigned int offset, +			   const struct rt2x00_field32 field, +			   u32 *reg); + +/** + * struct queue_entry_priv_pci: Per entry PCI specific information + * + * @desc: Pointer to device descriptor + * @desc_dma: DMA pointer to &desc. + * @data: Pointer to device's entry memory. + * @data_dma: DMA pointer to &data. + */ +struct queue_entry_priv_pci { +	__le32 *desc; +	dma_addr_t desc_dma; +}; + +/** + * rt2x00pci_rxdone - Handle RX done events + * @rt2x00dev: Device pointer, see &struct rt2x00_dev. + * + * Returns true if there are still rx frames pending and false if all + * pending rx frames were processed. + */ +bool rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev); + +/** + * rt2x00pci_flush_queue - Flush data queue + * @queue: Data queue to stop + * @drop: True to drop all pending frames. + * + * This will wait for a maximum of 100ms, waiting for the queues + * to become empty. + */ +void rt2x00pci_flush_queue(struct data_queue *queue, bool drop); + +/* + * Device initialization handlers. + */ +int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev); +void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev); + +#endif /* RT2X00MMIO_H */ diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index a0c8caef3b0..e87865e3311 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -33,182 +33,6 @@  #include "rt2x00pci.h"  /* - * Register access. - */ -int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev, -			   const unsigned int offset, -			   const struct rt2x00_field32 field, -			   u32 *reg) -{ -	unsigned int i; - -	if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) -		return 0; - -	for (i = 0; i < REGISTER_BUSY_COUNT; i++) { -		rt2x00pci_register_read(rt2x00dev, offset, reg); -		if (!rt2x00_get_field32(*reg, field)) -			return 1; -		udelay(REGISTER_BUSY_DELAY); -	} - -	ERROR(rt2x00dev, "Indirect register access failed: " -	      "offset=0x%.08x, value=0x%.08x\n", offset, *reg); -	*reg = ~0; - -	return 0; -} -EXPORT_SYMBOL_GPL(rt2x00pci_regbusy_read); - -bool rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) -{ -	struct data_queue *queue = rt2x00dev->rx; -	struct queue_entry *entry; -	struct queue_entry_priv_pci *entry_priv; -	struct skb_frame_desc *skbdesc; -	int max_rx = 16; - -	while (--max_rx) { -		entry = rt2x00queue_get_entry(queue, Q_INDEX); -		entry_priv = entry->priv_data; - -		if (rt2x00dev->ops->lib->get_entry_state(entry)) -			break; - -		/* -		 * Fill in desc fields of the skb descriptor -		 */ -		skbdesc = get_skb_frame_desc(entry->skb); -		skbdesc->desc = entry_priv->desc; -		skbdesc->desc_len = entry->queue->desc_size; - -		/* -		 * DMA is already done, notify rt2x00lib that -		 * it finished successfully. -		 */ -		rt2x00lib_dmastart(entry); -		rt2x00lib_dmadone(entry); - -		/* -		 * Send the frame to rt2x00lib for further processing. -		 */ -		rt2x00lib_rxdone(entry, GFP_ATOMIC); -	} - -	return !max_rx; -} -EXPORT_SYMBOL_GPL(rt2x00pci_rxdone); - -void rt2x00pci_flush_queue(struct data_queue *queue, bool drop) -{ -	unsigned int i; - -	for (i = 0; !rt2x00queue_empty(queue) && i < 10; i++) -		msleep(10); -} -EXPORT_SYMBOL_GPL(rt2x00pci_flush_queue); - -/* - * Device initialization handlers. - */ -static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev, -				     struct data_queue *queue) -{ -	struct queue_entry_priv_pci *entry_priv; -	void *addr; -	dma_addr_t dma; -	unsigned int i; - -	/* -	 * Allocate DMA memory for descriptor and buffer. -	 */ -	addr = dma_alloc_coherent(rt2x00dev->dev, -				  queue->limit * queue->desc_size, -				  &dma, GFP_KERNEL); -	if (!addr) -		return -ENOMEM; - -	memset(addr, 0, queue->limit * queue->desc_size); - -	/* -	 * Initialize all queue entries to contain valid addresses. -	 */ -	for (i = 0; i < queue->limit; i++) { -		entry_priv = queue->entries[i].priv_data; -		entry_priv->desc = addr + i * queue->desc_size; -		entry_priv->desc_dma = dma + i * queue->desc_size; -	} - -	return 0; -} - -static void rt2x00pci_free_queue_dma(struct rt2x00_dev *rt2x00dev, -				     struct data_queue *queue) -{ -	struct queue_entry_priv_pci *entry_priv = -	    queue->entries[0].priv_data; - -	if (entry_priv->desc) -		dma_free_coherent(rt2x00dev->dev, -				  queue->limit * queue->desc_size, -				  entry_priv->desc, entry_priv->desc_dma); -	entry_priv->desc = NULL; -} - -int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev) -{ -	struct data_queue *queue; -	int status; - -	/* -	 * Allocate DMA -	 */ -	queue_for_each(rt2x00dev, queue) { -		status = rt2x00pci_alloc_queue_dma(rt2x00dev, queue); -		if (status) -			goto exit; -	} - -	/* -	 * Register interrupt handler. -	 */ -	status = request_irq(rt2x00dev->irq, -			     rt2x00dev->ops->lib->irq_handler, -			     IRQF_SHARED, rt2x00dev->name, rt2x00dev); -	if (status) { -		ERROR(rt2x00dev, "IRQ %d allocation failed (error %d).\n", -		      rt2x00dev->irq, status); -		goto exit; -	} - -	return 0; - -exit: -	queue_for_each(rt2x00dev, queue) -		rt2x00pci_free_queue_dma(rt2x00dev, queue); - -	return status; -} -EXPORT_SYMBOL_GPL(rt2x00pci_initialize); - -void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev) -{ -	struct data_queue *queue; - -	/* -	 * Free irq line. -	 */ -	free_irq(rt2x00dev->irq, rt2x00dev); - -	/* -	 * Free DMA -	 */ -	queue_for_each(rt2x00dev, queue) -		rt2x00pci_free_queue_dma(rt2x00dev, queue); -} -EXPORT_SYMBOL_GPL(rt2x00pci_uninitialize); - -/*   * PCI driver handlers.   */  static void rt2x00pci_free_reg(struct rt2x00_dev *rt2x00dev) diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h index e2c99f2b9a1..60d90b20f8b 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.h +++ b/drivers/net/wireless/rt2x00/rt2x00pci.h @@ -36,94 +36,6 @@  #define PCI_DEVICE_DATA(__ops)	.driver_data = (kernel_ulong_t)(__ops)  /* - * Register access. - */ -static inline void rt2x00pci_register_read(struct rt2x00_dev *rt2x00dev, -					   const unsigned int offset, -					   u32 *value) -{ -	*value = readl(rt2x00dev->csr.base + offset); -} - -static inline void rt2x00pci_register_multiread(struct rt2x00_dev *rt2x00dev, -						const unsigned int offset, -						void *value, const u32 length) -{ -	memcpy_fromio(value, rt2x00dev->csr.base + offset, length); -} - -static inline void rt2x00pci_register_write(struct rt2x00_dev *rt2x00dev, -					    const unsigned int offset, -					    u32 value) -{ -	writel(value, rt2x00dev->csr.base + offset); -} - -static inline void rt2x00pci_register_multiwrite(struct rt2x00_dev *rt2x00dev, -						 const unsigned int offset, -						 const void *value, -						 const u32 length) -{ -	__iowrite32_copy(rt2x00dev->csr.base + offset, value, length >> 2); -} - -/** - * rt2x00pci_regbusy_read - Read from register with busy check - * @rt2x00dev: Device pointer, see &struct rt2x00_dev. - * @offset: Register offset - * @field: Field to check if register is busy - * @reg: Pointer to where register contents should be stored - * - * This function will read the given register, and checks if the - * register is busy. If it is, it will sleep for a couple of - * microseconds before reading the register again. If the register - * is not read after a certain timeout, this function will return - * FALSE. - */ -int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev, -			   const unsigned int offset, -			   const struct rt2x00_field32 field, -			   u32 *reg); - -/** - * struct queue_entry_priv_pci: Per entry PCI specific information - * - * @desc: Pointer to device descriptor - * @desc_dma: DMA pointer to &desc. - * @data: Pointer to device's entry memory. - * @data_dma: DMA pointer to &data. - */ -struct queue_entry_priv_pci { -	__le32 *desc; -	dma_addr_t desc_dma; -}; - -/** - * rt2x00pci_rxdone - Handle RX done events - * @rt2x00dev: Device pointer, see &struct rt2x00_dev. - * - * Returns true if there are still rx frames pending and false if all - * pending rx frames were processed. - */ -bool rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev); - -/** - * rt2x00pci_flush_queue - Flush data queue - * @queue: Data queue to stop - * @drop: True to drop all pending frames. - * - * This will wait for a maximum of 100ms, waiting for the queues - * to become empty. - */ -void rt2x00pci_flush_queue(struct data_queue *queue, bool drop); - -/* - * Device initialization handlers. - */ -int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev); -void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev); - -/*   * PCI driver handlers.   */  int rt2x00pci_probe(struct pci_dev *pci_dev, const struct rt2x00_ops *ops); diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index f95792cfcf8..9e3c8ff53e3 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -35,6 +35,7 @@  #include <linux/eeprom_93cx6.h>  #include "rt2x00.h" +#include "rt2x00mmio.h"  #include "rt2x00pci.h"  #include "rt61pci.h" diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c index b1ccff474c7..c08d0f4c5f3 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c @@ -1377,74 +1377,57 @@ void rtl92cu_card_disable(struct ieee80211_hw *hw)  void rtl92cu_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid)  { -	/* dummy routine needed for callback from rtl_op_configure_filter() */ -} - -/*========================================================================== */ - -static void _rtl92cu_set_check_bssid(struct ieee80211_hw *hw, -			      enum nl80211_iftype type) -{  	struct rtl_priv *rtlpriv = rtl_priv(hw); -	u32 reg_rcr = rtl_read_dword(rtlpriv, REG_RCR);  	struct rtl_hal *rtlhal = rtl_hal(rtlpriv); -	struct rtl_phy *rtlphy = &(rtlpriv->phy); -	u8 filterout_non_associated_bssid = false; +	u32 reg_rcr = rtl_read_dword(rtlpriv, REG_RCR); -	switch (type) { -	case NL80211_IFTYPE_ADHOC: -	case NL80211_IFTYPE_STATION: -		filterout_non_associated_bssid = true; -		break; -	case NL80211_IFTYPE_UNSPECIFIED: -	case NL80211_IFTYPE_AP: -	default: -		break; -	} -	if (filterout_non_associated_bssid) { +	if (rtlpriv->psc.rfpwr_state != ERFON) +		return; + +	if (check_bssid) { +		u8 tmp;  		if (IS_NORMAL_CHIP(rtlhal->version)) { -			switch (rtlphy->current_io_type) { -			case IO_CMD_RESUME_DM_BY_SCAN: -				reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN); -				rtlpriv->cfg->ops->set_hw_reg(hw, -						 HW_VAR_RCR, (u8 *)(®_rcr)); -				/* enable update TSF */ -				_rtl92cu_set_bcn_ctrl_reg(hw, 0, BIT(4)); -				break; -			case IO_CMD_PAUSE_DM_BY_SCAN: -				reg_rcr &= ~(RCR_CBSSID_DATA | RCR_CBSSID_BCN); -				rtlpriv->cfg->ops->set_hw_reg(hw, -						 HW_VAR_RCR, (u8 *)(®_rcr)); -				/* disable update TSF */ -				_rtl92cu_set_bcn_ctrl_reg(hw, BIT(4), 0); -				break; -			} +			reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN); +			tmp = BIT(4);  		} else { -			reg_rcr |= (RCR_CBSSID); -			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, -						      (u8 *)(®_rcr)); -			_rtl92cu_set_bcn_ctrl_reg(hw, 0, (BIT(4)|BIT(5))); +			reg_rcr |= RCR_CBSSID; +			tmp = BIT(4) | BIT(5);  		} -	} else if (filterout_non_associated_bssid == false) { +		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, +					      (u8 *) (®_rcr)); +		_rtl92cu_set_bcn_ctrl_reg(hw, 0, tmp); +	} else { +		u8 tmp;  		if (IS_NORMAL_CHIP(rtlhal->version)) { -			reg_rcr &= (~(RCR_CBSSID_DATA | RCR_CBSSID_BCN)); -			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, -						      (u8 *)(®_rcr)); -			_rtl92cu_set_bcn_ctrl_reg(hw, BIT(4), 0); +			reg_rcr &= ~(RCR_CBSSID_DATA | RCR_CBSSID_BCN); +			tmp = BIT(4);  		} else { -			reg_rcr &= (~RCR_CBSSID); -			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, -						      (u8 *)(®_rcr)); -			_rtl92cu_set_bcn_ctrl_reg(hw, (BIT(4)|BIT(5)), 0); +			reg_rcr &= ~RCR_CBSSID; +			tmp = BIT(4) | BIT(5);  		} +		reg_rcr &= (~(RCR_CBSSID_DATA | RCR_CBSSID_BCN)); +		rtlpriv->cfg->ops->set_hw_reg(hw, +					      HW_VAR_RCR, (u8 *) (®_rcr)); +		_rtl92cu_set_bcn_ctrl_reg(hw, tmp, 0);  	}  } +/*========================================================================== */ +  int rtl92cu_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type)  { +	struct rtl_priv *rtlpriv = rtl_priv(hw); +  	if (_rtl92cu_set_media_status(hw, type))  		return -EOPNOTSUPP; -	_rtl92cu_set_check_bssid(hw, type); + +	if (rtlpriv->mac80211.link_state == MAC80211_LINKED) { +		if (type != NL80211_IFTYPE_AP) +			rtl92cu_set_check_bssid(hw, true); +	} else { +		rtl92cu_set_check_bssid(hw, false); +	} +  	return 0;  } @@ -2058,8 +2041,6 @@ void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw,  			       (shortgi_rate << 4) | (shortgi_rate);  	}  	rtl_write_dword(rtlpriv, REG_ARFR0 + ratr_index * 4, ratr_value); -	RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, "%x\n", -		 rtl_read_dword(rtlpriv, REG_ARFR0));  }  void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level) diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index 156b52732f3..5847d6d0881 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -851,6 +851,7 @@ static void _rtl_usb_transmit(struct ieee80211_hw *hw, struct sk_buff *skb,  	if (unlikely(!_urb)) {  		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,  			 "Can't allocate urb. Drop skb!\n"); +		kfree_skb(skb);  		return;  	}  	_rtl_submit_tx_urb(hw, _urb);  |