diff options
| author | John W. Linville <linville@tuxdriver.com> | 2013-03-29 16:41:36 -0400 | 
|---|---|---|
| committer | John W. Linville <linville@tuxdriver.com> | 2013-03-29 16:41:36 -0400 | 
| commit | 9a574cd67a447059f9c14bbef47873315d7f7b35 (patch) | |
| tree | 0ebb71d213d868d8884b1fa0e05b7393c66c665b | |
| parent | 689b66cb53fbb5d567aa4e095eaa828aff73aef0 (diff) | |
| parent | 2e1253d640eb7f8707d2591c93097c1e9f9c71d5 (diff) | |
| download | olio-linux-3.10-9a574cd67a447059f9c14bbef47873315d7f7b35.tar.xz olio-linux-3.10-9a574cd67a447059f9c14bbef47873315d7f7b35.zip  | |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless
Conflicts:
	net/mac80211/sta_info.c
	net/wireless/core.h
34 files changed, 456 insertions, 404 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 143507e7f6d..685949bb883 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5043,9 +5043,8 @@ S:	Maintained  F:	drivers/net/ethernet/marvell/sk*  MARVELL LIBERTAS WIRELESS DRIVER -M:	Dan Williams <dcbw@redhat.com>  L:	libertas-dev@lists.infradead.org -S:	Maintained +S:	Orphan  F:	drivers/net/wireless/libertas/  MARVELL MV643XX ETHERNET DRIVER diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index b282af181b4..6aab00ef437 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -73,9 +73,11 @@ static struct usb_device_id ath3k_table[] = {  	{ USB_DEVICE(0x03F0, 0x311D) },  	/* Atheros AR3012 with sflash firmware*/ +	{ USB_DEVICE(0x0CF3, 0x0036) },  	{ USB_DEVICE(0x0CF3, 0x3004) },  	{ USB_DEVICE(0x0CF3, 0x3008) },  	{ USB_DEVICE(0x0CF3, 0x311D) }, +	{ USB_DEVICE(0x0CF3, 0x817a) },  	{ USB_DEVICE(0x13d3, 0x3375) },  	{ USB_DEVICE(0x04CA, 0x3004) },  	{ USB_DEVICE(0x04CA, 0x3005) }, @@ -107,9 +109,11 @@ MODULE_DEVICE_TABLE(usb, ath3k_table);  static struct usb_device_id ath3k_blist_tbl[] = {  	/* Atheros AR3012 with sflash firmware*/ +	{ USB_DEVICE(0x0CF3, 0x0036), .driver_info = BTUSB_ATH3012 },  	{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },  	{ USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 },  	{ USB_DEVICE(0x0cf3, 0x311D), .driver_info = BTUSB_ATH3012 }, +	{ USB_DEVICE(0x0CF3, 0x817a), .driver_info = BTUSB_ATH3012 },  	{ USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },  	{ USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 },  	{ USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 }, diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index e547851870e..2cc5f774a29 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -131,9 +131,11 @@ static struct usb_device_id blacklist_table[] = {  	{ USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE },  	/* Atheros 3012 with sflash firmware */ +	{ USB_DEVICE(0x0cf3, 0x0036), .driver_info = BTUSB_ATH3012 },  	{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },  	{ USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 },  	{ USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 }, +	{ USB_DEVICE(0x0cf3, 0x817a), .driver_info = BTUSB_ATH3012 },  	{ USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },  	{ USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 },  	{ USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 }, diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index e1770e60be2..639ba7d18ea 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) { @@ -1151,6 +1152,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/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/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..e8486c1e091 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; diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c index 427b0f613b9..3d6b16ce468 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); @@ -1837,17 +1789,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 @@ -2042,16 +1983,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); @@ -2138,14 +2069,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; @@ -2167,13 +2096,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); @@ -2209,10 +2132,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);  	} @@ -2259,10 +2181,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);  } @@ -2881,8 +2799,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)); @@ -2900,12 +2816,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); @@ -2927,7 +2837,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); @@ -3141,11 +3050,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); @@ -3947,6 +3851,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) { @@ -3957,7 +3862,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);  	} @@ -4382,22 +4286,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); @@ -4608,10 +4507,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); @@ -4622,13 +4518,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) @@ -4658,20 +4547,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) @@ -5064,7 +4955,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) @@ -5103,7 +4993,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 df5a57c7480..b37a582ccbe 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 cddf77c36b3..87c006c9c57 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/ucode.c b/drivers/net/wireless/iwlwifi/dvm/ucode.c index 166019afc2d..0a1cdc5e856 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/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 6649e377e9c..50ba0a468f9 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 a4508c2fa92..c3f15df67b9 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -1264,7 +1264,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,  	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_SCRATCHBUF_SIZE copied */ diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index d19a88c47a4..9a1302bd4c0 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 cab3434d0d5..daf8801cecd 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/main.h b/drivers/net/wireless/mwifiex/main.h index 975bc186a64..535595eeb5c 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -728,7 +728,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]; @@ -1029,7 +1028,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 b5ff9f1f69c..856959b64bc 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c @@ -1519,6 +1519,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..d215b4d3c51 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -1388,10 +1388,13 @@ 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) +				mwifiex_wait_queue_complete(adapter, cmd_node);  		} else {  			spin_unlock_irqrestore(&adapter->scan_pending_q_lock,  					       flags); @@ -1946,9 +1949,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 76d31deb7b1..8c943b6ebf4 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/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index 72c2614213c..83915dcd0e5 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -932,6 +932,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); diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 0a3aeb7e0aa..d919d1161ab 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -359,6 +359,7 @@ static void __sco_sock_close(struct sock *sk)  			sco_chan_del(sk, ECONNRESET);  		break; +	case BT_CONNECT2:  	case BT_CONNECT:  	case BT_DISCONN:  		sco_chan_del(sk, ECONNRESET); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index d646e12e55a..2a3c1e9bdf2 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -349,21 +349,19 @@ static void ieee80211_set_default_queues(struct ieee80211_sub_if_data *sdata)  static int ieee80211_add_virtual_monitor(struct ieee80211_local *local)  {  	struct ieee80211_sub_if_data *sdata; -	int ret = 0; +	int ret;  	if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF))  		return 0; -	mutex_lock(&local->iflist_mtx); +	ASSERT_RTNL();  	if (local->monitor_sdata) -		goto out_unlock; +		return 0;  	sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size, GFP_KERNEL); -	if (!sdata) { -		ret = -ENOMEM; -		goto out_unlock; -	} +	if (!sdata) +		return -ENOMEM;  	/* set up data */  	sdata->local = local; @@ -377,13 +375,13 @@ static int ieee80211_add_virtual_monitor(struct ieee80211_local *local)  	if (WARN_ON(ret)) {  		/* ok .. stupid driver, it asked for this! */  		kfree(sdata); -		goto out_unlock; +		return ret;  	}  	ret = ieee80211_check_queues(sdata);  	if (ret) {  		kfree(sdata); -		goto out_unlock; +		return ret;  	}  	ret = ieee80211_vif_use_channel(sdata, &local->monitor_chandef, @@ -391,13 +389,14 @@ static int ieee80211_add_virtual_monitor(struct ieee80211_local *local)  	if (ret) {  		drv_remove_interface(local, sdata);  		kfree(sdata); -		goto out_unlock; +		return ret;  	} +	mutex_lock(&local->iflist_mtx);  	rcu_assign_pointer(local->monitor_sdata, sdata); - out_unlock:  	mutex_unlock(&local->iflist_mtx); -	return ret; + +	return 0;  }  static void ieee80211_del_virtual_monitor(struct ieee80211_local *local) @@ -407,14 +406,20 @@ static void ieee80211_del_virtual_monitor(struct ieee80211_local *local)  	if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF))  		return; +	ASSERT_RTNL(); +  	mutex_lock(&local->iflist_mtx);  	sdata = rcu_dereference_protected(local->monitor_sdata,  					  lockdep_is_held(&local->iflist_mtx)); -	if (!sdata) -		goto out_unlock; +	if (!sdata) { +		mutex_unlock(&local->iflist_mtx); +		return; +	}  	rcu_assign_pointer(local->monitor_sdata, NULL); +	mutex_unlock(&local->iflist_mtx); +  	synchronize_net();  	ieee80211_vif_release_channel(sdata); @@ -422,8 +427,6 @@ static void ieee80211_del_virtual_monitor(struct ieee80211_local *local)  	drv_remove_interface(local, sdata);  	kfree(sdata); - out_unlock: -	mutex_unlock(&local->iflist_mtx);  }  /* diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index aead5410c62..123a300cef5 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -1004,7 +1004,8 @@ void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local)  	rcu_read_lock();  	list_for_each_entry_rcu(sdata, &local->interfaces, list) -		if (ieee80211_vif_is_mesh(&sdata->vif)) +		if (ieee80211_vif_is_mesh(&sdata->vif) && +		    ieee80211_sdata_running(sdata))  			ieee80211_queue_work(&local->hw, &sdata->work);  	rcu_read_unlock();  } diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 4d383a93ea7..e06dbbf8cb4 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3531,8 +3531,10 @@ void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local)  	/* Restart STA timers */  	rcu_read_lock(); -	list_for_each_entry_rcu(sdata, &local->interfaces, list) -		ieee80211_restart_sta_timer(sdata); +	list_for_each_entry_rcu(sdata, &local->interfaces, list) { +		if (ieee80211_sdata_running(sdata)) +			ieee80211_restart_sta_timer(sdata); +	}  	rcu_read_unlock();  } diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 5b4492af4e8..2528b5a4d6d 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2666,7 +2666,19 @@ ieee80211_rx_h_action_return(struct ieee80211_rx_data *rx)  		memset(nskb->cb, 0, sizeof(nskb->cb)); -		ieee80211_tx_skb(rx->sdata, nskb); +		if (rx->sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) { +			struct ieee80211_tx_info *info = IEEE80211_SKB_CB(nskb); + +			info->flags = IEEE80211_TX_CTL_TX_OFFCHAN | +				      IEEE80211_TX_INTFL_OFFCHAN_TX_OK | +				      IEEE80211_TX_CTL_NO_CCK_RATE; +			if (local->hw.flags & IEEE80211_HW_QUEUE_CONTROL) +				info->hw_queue = +					local->hw.offchannel_tx_hw_queue; +		} + +		__ieee80211_tx_skb_tid_band(rx->sdata, nskb, 7, +					    status->band);  	}  	dev_kfree_skb(rx->skb);  	return RX_QUEUED; diff --git a/net/wireless/core.c b/net/wireless/core.c index 92e3fd44e3b..84c9ad7e1dc 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -212,6 +212,39 @@ static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data)  	rdev_rfkill_poll(rdev);  } +void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev, +			      struct wireless_dev *wdev) +{ +	lockdep_assert_held(&rdev->devlist_mtx); +	lockdep_assert_held(&rdev->sched_scan_mtx); + +	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_P2P_DEVICE)) +		return; + +	if (!wdev->p2p_started) +		return; + +	rdev_stop_p2p_device(rdev, wdev); +	wdev->p2p_started = false; + +	rdev->opencount--; + +	if (rdev->scan_req && rdev->scan_req->wdev == wdev) { +		bool busy = work_busy(&rdev->scan_done_wk); + +		/* +		 * If the work isn't pending or running (in which case it would +		 * be waiting for the lock we hold) the driver didn't properly +		 * cancel the scan when the interface was removed. In this case +		 * warn and leak the scan request object to not crash later. +		 */ +		WARN_ON(!busy); + +		rdev->scan_req->aborted = true; +		___cfg80211_scan_done(rdev, !busy); +	} +} +  static int cfg80211_rfkill_set_block(void *data, bool blocked)  {  	struct cfg80211_registered_device *rdev = data; @@ -221,7 +254,8 @@ static int cfg80211_rfkill_set_block(void *data, bool blocked)  		return 0;  	rtnl_lock(); -	mutex_lock(&rdev->devlist_mtx); + +	/* read-only iteration need not hold the devlist_mtx */  	list_for_each_entry(wdev, &rdev->wdev_list, list) {  		if (wdev->netdev) { @@ -231,18 +265,18 @@ static int cfg80211_rfkill_set_block(void *data, bool blocked)  		/* otherwise, check iftype */  		switch (wdev->iftype) {  		case NL80211_IFTYPE_P2P_DEVICE: -			if (!wdev->p2p_started) -				break; -			rdev_stop_p2p_device(rdev, wdev); -			wdev->p2p_started = false; -			rdev->opencount--; +			/* but this requires it */ +			mutex_lock(&rdev->devlist_mtx); +			mutex_lock(&rdev->sched_scan_mtx); +			cfg80211_stop_p2p_device(rdev, wdev); +			mutex_unlock(&rdev->sched_scan_mtx); +			mutex_unlock(&rdev->devlist_mtx);  			break;  		default:  			break;  		}  	} -	mutex_unlock(&rdev->devlist_mtx);  	rtnl_unlock();  	return 0; @@ -745,17 +779,13 @@ static void wdev_cleanup_work(struct work_struct *work)  	wdev = container_of(work, struct wireless_dev, cleanup_work);  	rdev = wiphy_to_dev(wdev->wiphy); -	cfg80211_lock_rdev(rdev); +	mutex_lock(&rdev->sched_scan_mtx);  	if (WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev)) {  		rdev->scan_req->aborted = true;  		___cfg80211_scan_done(rdev, true);  	} -	cfg80211_unlock_rdev(rdev); - -	mutex_lock(&rdev->sched_scan_mtx); -  	if (WARN_ON(rdev->sched_scan_req &&  		    rdev->sched_scan_req->dev == wdev->netdev)) {  		__cfg80211_stop_sched_scan(rdev, false); @@ -781,21 +811,19 @@ void cfg80211_unregister_wdev(struct wireless_dev *wdev)  		return;  	mutex_lock(&rdev->devlist_mtx); +	mutex_lock(&rdev->sched_scan_mtx);  	list_del_rcu(&wdev->list);  	rdev->devlist_generation++;  	switch (wdev->iftype) {  	case NL80211_IFTYPE_P2P_DEVICE: -		if (!wdev->p2p_started) -			break; -		rdev_stop_p2p_device(rdev, wdev); -		wdev->p2p_started = false; -		rdev->opencount--; +		cfg80211_stop_p2p_device(rdev, wdev);  		break;  	default:  		WARN_ON_ONCE(1);  		break;  	} +	mutex_unlock(&rdev->sched_scan_mtx);  	mutex_unlock(&rdev->devlist_mtx);  }  EXPORT_SYMBOL(cfg80211_unregister_wdev); @@ -945,6 +973,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,  		cfg80211_update_iface_num(rdev, wdev->iftype, 1);  		cfg80211_lock_rdev(rdev);  		mutex_lock(&rdev->devlist_mtx); +		mutex_lock(&rdev->sched_scan_mtx);  		wdev_lock(wdev);  		switch (wdev->iftype) {  #ifdef CONFIG_CFG80211_WEXT @@ -976,6 +1005,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,  			break;  		}  		wdev_unlock(wdev); +		mutex_unlock(&rdev->sched_scan_mtx);  		rdev->opencount++;  		mutex_unlock(&rdev->devlist_mtx);  		cfg80211_unlock_rdev(rdev); diff --git a/net/wireless/core.h b/net/wireless/core.h index d5d06fdea96..124e5e773fb 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -503,6 +503,9 @@ void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,  void cfg80211_leave(struct cfg80211_registered_device *rdev,  		    struct wireless_dev *wdev); +void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev, +			      struct wireless_dev *wdev); +  #define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10  #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index f924d45af1b..671b69a3c13 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -5048,14 +5048,19 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)  	if (!rdev->ops->scan)  		return -EOPNOTSUPP; -	if (rdev->scan_req) -		return -EBUSY; +	mutex_lock(&rdev->sched_scan_mtx); +	if (rdev->scan_req) { +		err = -EBUSY; +		goto unlock; +	}  	if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {  		n_channels = validate_scan_freqs(  				info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]); -		if (!n_channels) -			return -EINVAL; +		if (!n_channels) { +			err = -EINVAL; +			goto unlock; +		}  	} else {  		enum ieee80211_band band;  		n_channels = 0; @@ -5069,23 +5074,29 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)  		nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp)  			n_ssids++; -	if (n_ssids > wiphy->max_scan_ssids) -		return -EINVAL; +	if (n_ssids > wiphy->max_scan_ssids) { +		err = -EINVAL; +		goto unlock; +	}  	if (info->attrs[NL80211_ATTR_IE])  		ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);  	else  		ie_len = 0; -	if (ie_len > wiphy->max_scan_ie_len) -		return -EINVAL; +	if (ie_len > wiphy->max_scan_ie_len) { +		err = -EINVAL; +		goto unlock; +	}  	request = kzalloc(sizeof(*request)  			+ sizeof(*request->ssids) * n_ssids  			+ sizeof(*request->channels) * n_channels  			+ ie_len, GFP_KERNEL); -	if (!request) -		return -ENOMEM; +	if (!request) { +		err = -ENOMEM; +		goto unlock; +	}  	if (n_ssids)  		request->ssids = (void *)&request->channels[n_channels]; @@ -5222,6 +5233,8 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)  		kfree(request);  	} + unlock: +	mutex_unlock(&rdev->sched_scan_mtx);  	return err;  } @@ -8130,20 +8143,9 @@ static int nl80211_stop_p2p_device(struct sk_buff *skb, struct genl_info *info)  	if (!rdev->ops->stop_p2p_device)  		return -EOPNOTSUPP; -	if (!wdev->p2p_started) -		return 0; - -	rdev_stop_p2p_device(rdev, wdev); -	wdev->p2p_started = false; - -	mutex_lock(&rdev->devlist_mtx); -	rdev->opencount--; -	mutex_unlock(&rdev->devlist_mtx); - -	if (WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev)) { -		rdev->scan_req->aborted = true; -		___cfg80211_scan_done(rdev, true); -	} +	mutex_lock(&rdev->sched_scan_mtx); +	cfg80211_stop_p2p_device(rdev, wdev); +	mutex_unlock(&rdev->sched_scan_mtx);  	return 0;  } @@ -8929,7 +8931,7 @@ static int nl80211_add_scan_req(struct sk_buff *msg,  	struct nlattr *nest;  	int i; -	ASSERT_RDEV_LOCK(rdev); +	lockdep_assert_held(&rdev->sched_scan_mtx);  	if (WARN_ON(!req))  		return 0; diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 674aadca007..fd99ea495b7 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -169,7 +169,7 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)  	union iwreq_data wrqu;  #endif -	ASSERT_RDEV_LOCK(rdev); +	lockdep_assert_held(&rdev->sched_scan_mtx);  	request = rdev->scan_req; @@ -230,9 +230,9 @@ void __cfg80211_scan_done(struct work_struct *wk)  	rdev = container_of(wk, struct cfg80211_registered_device,  			    scan_done_wk); -	cfg80211_lock_rdev(rdev); +	mutex_lock(&rdev->sched_scan_mtx);  	___cfg80211_scan_done(rdev, false); -	cfg80211_unlock_rdev(rdev); +	mutex_unlock(&rdev->sched_scan_mtx);  }  void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) @@ -698,11 +698,6 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,  	found = rb_find_bss(dev, tmp, BSS_CMP_REGULAR);  	if (found) { -		found->pub.beacon_interval = tmp->pub.beacon_interval; -		found->pub.signal = tmp->pub.signal; -		found->pub.capability = tmp->pub.capability; -		found->ts = tmp->ts; -  		/* Update IEs */  		if (rcu_access_pointer(tmp->pub.proberesp_ies)) {  			const struct cfg80211_bss_ies *old; @@ -723,6 +718,8 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,  			if (found->pub.hidden_beacon_bss &&  			    !list_empty(&found->hidden_list)) { +				const struct cfg80211_bss_ies *f; +  				/*  				 * The found BSS struct is one of the probe  				 * response members of a group, but we're @@ -732,6 +729,10 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,  				 * SSID to showing it, which is confusing so  				 * drop this information.  				 */ + +				f = rcu_access_pointer(tmp->pub.beacon_ies); +				kfree_rcu((struct cfg80211_bss_ies *)f, +					  rcu_head);  				goto drop;  			} @@ -761,6 +762,11 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,  				kfree_rcu((struct cfg80211_bss_ies *)old,  					  rcu_head);  		} + +		found->pub.beacon_interval = tmp->pub.beacon_interval; +		found->pub.signal = tmp->pub.signal; +		found->pub.capability = tmp->pub.capability; +		found->ts = tmp->ts;  	} else {  		struct cfg80211_internal_bss *new;  		struct cfg80211_internal_bss *hidden; @@ -1056,6 +1062,7 @@ int cfg80211_wext_siwscan(struct net_device *dev,  	if (IS_ERR(rdev))  		return PTR_ERR(rdev); +	mutex_lock(&rdev->sched_scan_mtx);  	if (rdev->scan_req) {  		err = -EBUSY;  		goto out; @@ -1162,6 +1169,7 @@ int cfg80211_wext_siwscan(struct net_device *dev,  		dev_hold(dev);  	}   out: +	mutex_unlock(&rdev->sched_scan_mtx);  	kfree(creq);  	cfg80211_unlock_rdev(rdev);  	return err; diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 88fc9aa54fe..818ad637819 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -85,6 +85,7 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev)  	ASSERT_RTNL();  	ASSERT_RDEV_LOCK(rdev);  	ASSERT_WDEV_LOCK(wdev); +	lockdep_assert_held(&rdev->sched_scan_mtx);  	if (rdev->scan_req)  		return -EBUSY; @@ -324,11 +325,9 @@ void cfg80211_sme_scan_done(struct net_device *dev)  {  	struct wireless_dev *wdev = dev->ieee80211_ptr; -	mutex_lock(&wiphy_to_dev(wdev->wiphy)->devlist_mtx);  	wdev_lock(wdev);  	__cfg80211_sme_scan_done(dev);  	wdev_unlock(wdev); -	mutex_unlock(&wiphy_to_dev(wdev->wiphy)->devlist_mtx);  }  void cfg80211_sme_rx_auth(struct net_device *dev, @@ -928,9 +927,12 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev,  	int err;  	mutex_lock(&rdev->devlist_mtx); +	/* might request scan - scan_mtx -> wdev_mtx dependency */ +	mutex_lock(&rdev->sched_scan_mtx);  	wdev_lock(dev->ieee80211_ptr);  	err = __cfg80211_connect(rdev, dev, connect, connkeys, NULL);  	wdev_unlock(dev->ieee80211_ptr); +	mutex_unlock(&rdev->sched_scan_mtx);  	mutex_unlock(&rdev->devlist_mtx);  	return err; diff --git a/net/wireless/trace.h b/net/wireless/trace.h index ccadef2106a..3c2033b8f59 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -27,7 +27,8 @@  #define WIPHY_PR_ARG	__entry->wiphy_name  #define WDEV_ENTRY	__field(u32, id) -#define WDEV_ASSIGN	(__entry->id) = (wdev ? wdev->identifier : 0) +#define WDEV_ASSIGN	(__entry->id) = (!IS_ERR_OR_NULL(wdev)	\ +					 ? wdev->identifier : 0)  #define WDEV_PR_FMT	"wdev(%u)"  #define WDEV_PR_ARG	(__entry->id) @@ -1778,7 +1779,7 @@ TRACE_EVENT(rdev_set_mac_acl,  	),  	TP_fast_assign(  		WIPHY_ASSIGN; -		WIPHY_ASSIGN; +		NETDEV_ASSIGN;  		__entry->acl_policy = params->acl_policy;  	),  	TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", acl policy: %d", diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index fb9622f6d99..e79cb5c0655 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c @@ -89,6 +89,7 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev,  	cfg80211_lock_rdev(rdev);  	mutex_lock(&rdev->devlist_mtx); +	mutex_lock(&rdev->sched_scan_mtx);  	wdev_lock(wdev);  	if (wdev->sme_state != CFG80211_SME_IDLE) { @@ -135,6 +136,7 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev,  	err = cfg80211_mgd_wext_connect(rdev, wdev);   out:  	wdev_unlock(wdev); +	mutex_unlock(&rdev->sched_scan_mtx);  	mutex_unlock(&rdev->devlist_mtx);  	cfg80211_unlock_rdev(rdev);  	return err; @@ -190,6 +192,7 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev,  	cfg80211_lock_rdev(rdev);  	mutex_lock(&rdev->devlist_mtx); +	mutex_lock(&rdev->sched_scan_mtx);  	wdev_lock(wdev);  	err = 0; @@ -223,6 +226,7 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev,  	err = cfg80211_mgd_wext_connect(rdev, wdev);   out:  	wdev_unlock(wdev); +	mutex_unlock(&rdev->sched_scan_mtx);  	mutex_unlock(&rdev->devlist_mtx);  	cfg80211_unlock_rdev(rdev);  	return err; @@ -285,6 +289,7 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev,  	cfg80211_lock_rdev(rdev);  	mutex_lock(&rdev->devlist_mtx); +	mutex_lock(&rdev->sched_scan_mtx);  	wdev_lock(wdev);  	if (wdev->sme_state != CFG80211_SME_IDLE) { @@ -313,6 +318,7 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev,  	err = cfg80211_mgd_wext_connect(rdev, wdev);   out:  	wdev_unlock(wdev); +	mutex_unlock(&rdev->sched_scan_mtx);  	mutex_unlock(&rdev->devlist_mtx);  	cfg80211_unlock_rdev(rdev);  	return err;  |