diff options
| author | David S. Miller <davem@davemloft.net> | 2009-12-25 16:34:56 -0800 | 
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2009-12-25 16:34:56 -0800 | 
| commit | d346f49d0badd80aa9fc699fa9c6d5b23e778eb6 (patch) | |
| tree | 9e9698ffe7966fbe7ce924a30843f87cdfa2646e /drivers/net | |
| parent | d87fd25d5ac4cd044e21b749a8f6cac90f093c71 (diff) | |
| parent | b6ce5c33001b1dc83e6a1a6f30c5dccccea651b6 (diff) | |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Diffstat (limited to 'drivers/net')
69 files changed, 1437 insertions, 507 deletions
| diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h index 9f9459860d82..b99a8c2053d8 100644 --- a/drivers/net/wireless/ath/ar9170/ar9170.h +++ b/drivers/net/wireless/ath/ar9170/ar9170.h @@ -109,7 +109,6 @@ struct ar9170_rxstream_mpdu_merge {  	bool has_plcp;  }; -#define AR9170_NUM_MAX_BA_RETRY	5  #define AR9170_NUM_TID	16  #define WME_BA_BMP_SIZE         64  #define AR9170_NUM_MAX_AGG_LEN	(2 * WME_BA_BMP_SIZE) @@ -143,7 +142,6 @@ struct ar9170_sta_tid {  	u16 tid;  	enum ar9170_tid_state state;  	bool active; -	u8 retry;  };  #define AR9170_QUEUE_TIMEOUT		64 @@ -154,6 +152,8 @@ struct ar9170_sta_tid {  #define AR9170_NUM_TX_STATUS		128  #define AR9170_NUM_TX_AGG_MAX		30 +#define AR9170_NUM_TX_LIMIT_HARD       AR9170_TXQ_DEPTH +#define AR9170_NUM_TX_LIMIT_SOFT       (AR9170_TXQ_DEPTH - 10)  struct ar9170 {  	struct ieee80211_hw *hw; @@ -248,13 +248,8 @@ struct ar9170_sta_info {  	unsigned int ampdu_max_len;  }; -#define AR9170_TX_FLAG_WAIT_FOR_ACK	BIT(0) -#define AR9170_TX_FLAG_NO_ACK		BIT(1) -#define AR9170_TX_FLAG_BLOCK_ACK	BIT(2) -  struct ar9170_tx_info {  	unsigned long timeout; -	unsigned int flags;  };  #define IS_STARTED(a)		(((struct ar9170 *)a)->state >= AR9170_STARTED) diff --git a/drivers/net/wireless/ath/ar9170/hw.h b/drivers/net/wireless/ath/ar9170/hw.h index 701ddb7d8400..0a1d4c28e68a 100644 --- a/drivers/net/wireless/ath/ar9170/hw.h +++ b/drivers/net/wireless/ath/ar9170/hw.h @@ -276,6 +276,7 @@ struct ar9170_tx_control {  #define AR9170_TX_MAC_RATE_PROBE		0x8000  /* either-or */ +#define AR9170_TX_PHY_MOD_MASK			0x00000003  #define AR9170_TX_PHY_MOD_CCK			0x00000000  #define AR9170_TX_PHY_MOD_OFDM			0x00000001  #define AR9170_TX_PHY_MOD_HT			0x00000002 diff --git a/drivers/net/wireless/ath/ar9170/mac.c b/drivers/net/wireless/ath/ar9170/mac.c index ddc8c09dc79e..857e86104295 100644 --- a/drivers/net/wireless/ath/ar9170/mac.c +++ b/drivers/net/wireless/ath/ar9170/mac.c @@ -117,7 +117,7 @@ int ar9170_set_qos(struct ar9170 *ar)  	ar9170_regwrite(AR9170_MAC_REG_AC1_AC0_TXOP,  			ar->edcf[0].txop | ar->edcf[1].txop << 16);  	ar9170_regwrite(AR9170_MAC_REG_AC3_AC2_TXOP, -			ar->edcf[1].txop | ar->edcf[3].txop << 16); +			ar->edcf[2].txop | ar->edcf[3].txop << 16);  	ar9170_regwrite_finish(); diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index f9d6db8d013e..20f04ab2b13e 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -194,12 +194,15 @@ static inline u16 ar9170_get_seq(struct sk_buff *skb)  	return ar9170_get_seq_h((void *) txc->frame_data);  } +static inline u16 ar9170_get_tid_h(struct ieee80211_hdr *hdr) +{ +	return (ieee80211_get_qos_ctl(hdr))[0] & IEEE80211_QOS_CTL_TID_MASK; +} +  static inline u16 ar9170_get_tid(struct sk_buff *skb)  {  	struct ar9170_tx_control *txc = (void *) skb->data; -	struct ieee80211_hdr *hdr = (void *) txc->frame_data; - -	return (ieee80211_get_qos_ctl(hdr))[0] & IEEE80211_QOS_CTL_TID_MASK; +	return ar9170_get_tid_h((struct ieee80211_hdr *) txc->frame_data);  }  #define GET_NEXT_SEQ(seq)	((seq + 1) & 0x0fff) @@ -213,10 +216,10 @@ static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb)  	struct ar9170_tx_info *arinfo = (void *) txinfo->rate_driver_data;  	struct ieee80211_hdr *hdr = (void *) txc->frame_data; -	printk(KERN_DEBUG "%s: => FRAME [skb:%p, q:%d, DA:[%pM] flags:%x s:%d " +	printk(KERN_DEBUG "%s: => FRAME [skb:%p, q:%d, DA:[%pM] s:%d "  			  "mac_ctrl:%04x, phy_ctrl:%08x, timeout:[%d ms]]\n",  	       wiphy_name(ar->hw->wiphy), skb, skb_get_queue_mapping(skb), -	       ieee80211_get_DA(hdr), arinfo->flags, ar9170_get_seq_h(hdr), +	       ieee80211_get_DA(hdr), ar9170_get_seq_h(hdr),  	       le16_to_cpu(txc->mac_control), le32_to_cpu(txc->phy_control),  	       jiffies_to_msecs(arinfo->timeout - jiffies));  } @@ -430,7 +433,7 @@ void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb)  	spin_lock_irqsave(&ar->tx_stats_lock, flags);  	ar->tx_stats[queue].len--; -	if (skb_queue_empty(&ar->tx_pending[queue])) { +	if (ar->tx_stats[queue].len < AR9170_NUM_TX_LIMIT_SOFT) {  #ifdef AR9170_QUEUE_STOP_DEBUG  		printk(KERN_DEBUG "%s: wake queue %d\n",  		       wiphy_name(ar->hw->wiphy), queue); @@ -440,22 +443,17 @@ void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb)  	}  	spin_unlock_irqrestore(&ar->tx_stats_lock, flags); -	if (arinfo->flags & AR9170_TX_FLAG_BLOCK_ACK) { -		ar9170_tx_ampdu_callback(ar, skb); -	} else if (arinfo->flags & AR9170_TX_FLAG_WAIT_FOR_ACK) { -		arinfo->timeout = jiffies + -				  msecs_to_jiffies(AR9170_TX_TIMEOUT); - -		skb_queue_tail(&ar->tx_status[queue], skb); -	} else if (arinfo->flags & AR9170_TX_FLAG_NO_ACK) { +	if (info->flags & IEEE80211_TX_CTL_NO_ACK) {  		ar9170_tx_status(ar, skb, AR9170_TX_STATUS_FAILED);  	} else { -#ifdef AR9170_QUEUE_DEBUG -		printk(KERN_DEBUG "%s: unsupported frame flags!\n", -		       wiphy_name(ar->hw->wiphy)); -		ar9170_print_txheader(ar, skb); -#endif /* AR9170_QUEUE_DEBUG */ -		dev_kfree_skb_any(skb); +		if (info->flags & IEEE80211_TX_CTL_AMPDU) { +			ar9170_tx_ampdu_callback(ar, skb); +		} else { +			arinfo->timeout = jiffies + +				  msecs_to_jiffies(AR9170_TX_TIMEOUT); + +			skb_queue_tail(&ar->tx_status[queue], skb); +		}  	}  	if (!ar->tx_stats[queue].len && @@ -1407,17 +1405,6 @@ static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb)  	if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&  	     (is_valid_ether_addr(ieee80211_get_DA(hdr)))) { -		if (info->flags & IEEE80211_TX_CTL_AMPDU) { -			if (unlikely(!info->control.sta)) -				goto err_out; - -			txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_AGGR); -			arinfo->flags = AR9170_TX_FLAG_BLOCK_ACK; - -			goto out; -		} - -		txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_RATE_PROBE);  		/*  		 * WARNING:  		 * Putting the QoS queue bits into an unexplored territory is @@ -1431,12 +1418,17 @@ static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb)  		txc->phy_control |=  			cpu_to_le32(queue << AR9170_TX_PHY_QOS_SHIFT); -		arinfo->flags = AR9170_TX_FLAG_WAIT_FOR_ACK; -	} else { -		arinfo->flags = AR9170_TX_FLAG_NO_ACK; + +		if (info->flags & IEEE80211_TX_CTL_AMPDU) { +			if (unlikely(!info->control.sta)) +				goto err_out; + +			txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_AGGR); +		} else { +			txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_RATE_PROBE); +		}  	} -out:  	return 0;  err_out: @@ -1671,8 +1663,7 @@ static bool ar9170_tx_ampdu(struct ar9170 *ar)  		 * tell the FW/HW that this is the last frame,  		 * that way it will wait for the immediate block ack.  		 */ -		if (likely(skb_peek_tail(&agg))) -			ar9170_tx_indicate_immba(ar, skb_peek_tail(&agg)); +		ar9170_tx_indicate_immba(ar, skb_peek_tail(&agg));  #ifdef AR9170_TXAGG_DEBUG  		printk(KERN_DEBUG "%s: generated A-MPDU looks like this:\n", @@ -1716,6 +1707,21 @@ static void ar9170_tx(struct ar9170 *ar)  	for (i = 0; i < __AR9170_NUM_TXQ; i++) {  		spin_lock_irqsave(&ar->tx_stats_lock, flags); +		frames = min(ar->tx_stats[i].limit - ar->tx_stats[i].len, +			     skb_queue_len(&ar->tx_pending[i])); + +		if (remaining_space < frames) { +#ifdef AR9170_QUEUE_DEBUG +			printk(KERN_DEBUG "%s: tx quota reached queue:%d, " +			       "remaining slots:%d, needed:%d\n", +			       wiphy_name(ar->hw->wiphy), i, remaining_space, +			       frames); +#endif /* AR9170_QUEUE_DEBUG */ +			frames = remaining_space; +		} + +		ar->tx_stats[i].len += frames; +		ar->tx_stats[i].count += frames;  		if (ar->tx_stats[i].len >= ar->tx_stats[i].limit) {  #ifdef AR9170_QUEUE_DEBUG  			printk(KERN_DEBUG "%s: queue %d full\n", @@ -1733,25 +1739,8 @@ static void ar9170_tx(struct ar9170 *ar)  			__ar9170_dump_txstats(ar);  #endif /* AR9170_QUEUE_STOP_DEBUG */  			ieee80211_stop_queue(ar->hw, i); -			spin_unlock_irqrestore(&ar->tx_stats_lock, flags); -			continue;  		} -		frames = min(ar->tx_stats[i].limit - ar->tx_stats[i].len, -			     skb_queue_len(&ar->tx_pending[i])); - -		if (remaining_space < frames) { -#ifdef AR9170_QUEUE_DEBUG -			printk(KERN_DEBUG "%s: tx quota reached queue:%d, " -			       "remaining slots:%d, needed:%d\n", -			       wiphy_name(ar->hw->wiphy), i, remaining_space, -			       frames); -#endif /* AR9170_QUEUE_DEBUG */ -			frames = remaining_space; -		} - -		ar->tx_stats[i].len += frames; -		ar->tx_stats[i].count += frames;  		spin_unlock_irqrestore(&ar->tx_stats_lock, flags);  		if (!frames) @@ -1773,7 +1762,7 @@ static void ar9170_tx(struct ar9170 *ar)  			arinfo->timeout = jiffies +  					  msecs_to_jiffies(AR9170_TX_TIMEOUT); -			if (arinfo->flags == AR9170_TX_FLAG_BLOCK_ACK) +			if (info->flags & IEEE80211_TX_CTL_AMPDU)  				atomic_inc(&ar->tx_ampdu_pending);  #ifdef AR9170_QUEUE_DEBUG @@ -1784,7 +1773,7 @@ static void ar9170_tx(struct ar9170 *ar)  			err = ar->tx(ar, skb);  			if (unlikely(err)) { -				if (arinfo->flags == AR9170_TX_FLAG_BLOCK_ACK) +				if (info->flags & IEEE80211_TX_CTL_AMPDU)  					atomic_dec(&ar->tx_ampdu_pending);  				frames_failed++; @@ -2366,7 +2355,6 @@ static void ar9170_sta_notify(struct ieee80211_hw *hw,  			sta_info->agg[i].state = AR9170_TID_STATE_SHUTDOWN;  			sta_info->agg[i].active = false;  			sta_info->agg[i].ssn = 0; -			sta_info->agg[i].retry = 0;  			sta_info->agg[i].tid = i;  			INIT_LIST_HEAD(&sta_info->agg[i].list);  			skb_queue_head_init(&sta_info->agg[i].queue); diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c index e0799d924057..0f361186b78f 100644 --- a/drivers/net/wireless/ath/ar9170/usb.c +++ b/drivers/net/wireless/ath/ar9170/usb.c @@ -84,6 +84,8 @@ static struct usb_device_id ar9170_usb_ids[] = {  	{ USB_DEVICE(0x0cde, 0x0023) },  	/* Z-Com UB82 ABG */  	{ USB_DEVICE(0x0cde, 0x0026) }, +	/* Sphairon Homelink 1202 */ +	{ USB_DEVICE(0x0cde, 0x0027) },  	/* Arcadyan WN7512 */  	{ USB_DEVICE(0x083a, 0xf522) },  	/* Planex GWUS300 */ diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index e2cef2ff5d8f..9f1f523e02eb 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -453,7 +453,6 @@ struct ath_softc {  	int irq;  	spinlock_t sc_resetlock;  	spinlock_t sc_serial_rw; -	spinlock_t ani_lock;  	spinlock_t sc_pm_lock;  	struct mutex mutex; diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index b66f72dbf7b9..592f1b70f55a 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -289,23 +289,49 @@ static ssize_t read_file_rcstat(struct file *file, char __user *user_buf,  	if (sc->cur_rate_table == NULL)  		return 0; -	max = 80 + sc->cur_rate_table->rate_cnt * 64; +	max = 80 + sc->cur_rate_table->rate_cnt * 1024;  	buf = kmalloc(max + 1, GFP_KERNEL);  	if (buf == NULL)  		return 0;  	buf[max] = 0; -	len += sprintf(buf, "%5s %15s %8s %9s %3s\n\n", "Rate", "Success", -		       "Retries", "XRetries", "PER"); +	len += sprintf(buf, "%6s %6s %6s " +		       "%10s %10s %10s %10s\n", +		       "HT", "MCS", "Rate", +		       "Success", "Retries", "XRetries", "PER");  	for (i = 0; i < sc->cur_rate_table->rate_cnt; i++) {  		u32 ratekbps = sc->cur_rate_table->info[i].ratekbps;  		struct ath_rc_stats *stats = &sc->debug.stats.rcstats[i]; +		char mcs[5]; +		char htmode[5]; +		int used_mcs = 0, used_htmode = 0; + +		if (WLAN_RC_PHY_HT(sc->cur_rate_table->info[i].phy)) { +			used_mcs = snprintf(mcs, 5, "%d", +				sc->cur_rate_table->info[i].ratecode); + +			if (WLAN_RC_PHY_40(sc->cur_rate_table->info[i].phy)) +				used_htmode = snprintf(htmode, 5, "HT40"); +			else if (WLAN_RC_PHY_20(sc->cur_rate_table->info[i].phy)) +				used_htmode = snprintf(htmode, 5, "HT20"); +			else +				used_htmode = snprintf(htmode, 5, "????"); +		} + +		mcs[used_mcs] = '\0'; +		htmode[used_htmode] = '\0';  		len += snprintf(buf + len, max - len, -			"%3u.%d: %8u %8u %8u %8u\n", ratekbps / 1000, -			(ratekbps % 1000) / 100, stats->success, -			stats->retries, stats->xretries, +			"%6s %6s %3u.%d: " +			"%10u %10u %10u %10u\n", +			htmode, +			mcs, +			ratekbps / 1000, +			(ratekbps % 1000) / 100, +			stats->success, +			stats->retries, +			stats->xretries,  			stats->per);  	} diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 2ec61f08cfdb..9474f9f6d400 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -343,30 +343,6 @@ static bool ath9k_hw_chip_test(struct ath_hw *ah)  	return true;  } -static const char *ath9k_hw_devname(u16 devid) -{ -	switch (devid) { -	case AR5416_DEVID_PCI: -		return "Atheros 5416"; -	case AR5416_DEVID_PCIE: -		return "Atheros 5418"; -	case AR9160_DEVID_PCI: -		return "Atheros 9160"; -	case AR5416_AR9100_DEVID: -		return "Atheros 9100"; -	case AR9280_DEVID_PCI: -	case AR9280_DEVID_PCIE: -		return "Atheros 9280"; -	case AR9285_DEVID_PCIE: -		return "Atheros 9285"; -	case AR5416_DEVID_AR9287_PCI: -	case AR5416_DEVID_AR9287_PCIE: -		return "Atheros 9287"; -	} - -	return NULL; -} -  static void ath9k_hw_init_config(struct ath_hw *ah)  {  	int i; @@ -392,7 +368,7 @@ static void ath9k_hw_init_config(struct ath_hw *ah)  		ah->config.spurchans[i][1] = AR_NO_SPUR;  	} -	ah->config.intr_mitigation = true; +	ah->config.rx_intr_mitigation = true;  	/*  	 * We need this for PCI devices only (Cardbus, PCI, miniPCI) @@ -1184,7 +1160,7 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah,  		AR_IMR_RXORN |  		AR_IMR_BCNMISC; -	if (ah->config.intr_mitigation) +	if (ah->config.rx_intr_mitigation)  		ah->mask_reg |= AR_IMR_RXINTM | AR_IMR_RXMINTR;  	else  		ah->mask_reg |= AR_IMR_RXOK; @@ -1266,12 +1242,6 @@ static void ath9k_hw_init_user_settings(struct ath_hw *ah)  		ath9k_hw_set_global_txtimeout(ah, ah->globaltxtimeout);  } -const char *ath9k_hw_probe(u16 vendorid, u16 devid) -{ -	return vendorid == ATHEROS_VENDOR_ID ? -		ath9k_hw_devname(devid) : NULL; -} -  void ath9k_hw_detach(struct ath_hw *ah)  {  	struct ath_common *common = ath9k_hw_common(ah); @@ -2121,7 +2091,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,  	REG_WRITE(ah, AR_OBS, 8); -	if (ah->config.intr_mitigation) { +	if (ah->config.rx_intr_mitigation) {  		REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, 500);  		REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, 2000);  	} @@ -2781,7 +2751,7 @@ bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked)  		*masked = isr & ATH9K_INT_COMMON; -		if (ah->config.intr_mitigation) { +		if (ah->config.rx_intr_mitigation) {  			if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM))  				*masked |= ATH9K_INT_RX;  		} @@ -2914,7 +2884,7 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints)  	}  	if (ints & ATH9K_INT_RX) {  		mask |= AR_IMR_RXERR; -		if (ah->config.intr_mitigation) +		if (ah->config.rx_intr_mitigation)  			mask |= AR_IMR_RXMINTR | AR_IMR_RXINTM;  		else  			mask |= AR_IMR_RXOK | AR_IMR_RXDESC; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index e2b0c73a616f..8849450dc591 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -212,7 +212,7 @@ struct ath9k_ops_config {  	u32 cck_trig_low;  	u32 enable_ani;  	int serialize_regmode; -	bool intr_mitigation; +	bool rx_intr_mitigation;  #define SPUR_DISABLE        	0  #define SPUR_ENABLE_IOCTL   	1  #define SPUR_ENABLE_EEPROM  	2 diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 9e68c1a8aef0..3f5b887d0fcd 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -363,14 +363,6 @@ static void ath_ani_calibrate(unsigned long data)  	short_cal_interval = (ah->opmode == NL80211_IFTYPE_AP) ?  		ATH_AP_SHORT_CALINTERVAL : ATH_STA_SHORT_CALINTERVAL; -	/* -	* don't calibrate when we're scanning. -	* we are most likely not on our home channel. -	*/ -	spin_lock(&sc->ani_lock); -	if (sc->sc_flags & SC_OP_SCANNING) -		goto set_timer; -  	/* Only calibrate if awake */  	if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE)  		goto set_timer; @@ -437,7 +429,6 @@ static void ath_ani_calibrate(unsigned long data)  	ath9k_ps_restore(sc);  set_timer: -	spin_unlock(&sc->ani_lock);  	/*  	* Set timer interval based on previous results.  	* The interval must be the shortest necessary to satisfy ANI, @@ -1610,7 +1601,6 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,  	spin_lock_init(&sc->wiphy_lock);  	spin_lock_init(&sc->sc_resetlock);  	spin_lock_init(&sc->sc_serial_rw); -	spin_lock_init(&sc->ani_lock);  	spin_lock_init(&sc->sc_pm_lock);  	mutex_init(&sc->mutex);  	tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); @@ -3119,6 +3109,7 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw)  {  	struct ath_wiphy *aphy = hw->priv;  	struct ath_softc *sc = aphy->sc; +	struct ath_common *common = ath9k_hw_common(sc->sc_ah);  	mutex_lock(&sc->mutex);  	if (ath9k_wiphy_scanning(sc)) { @@ -3134,10 +3125,9 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw)  	aphy->state = ATH_WIPHY_SCAN;  	ath9k_wiphy_pause_all_forced(sc, aphy); - -	spin_lock_bh(&sc->ani_lock);  	sc->sc_flags |= SC_OP_SCANNING; -	spin_unlock_bh(&sc->ani_lock); +	del_timer_sync(&common->ani.timer); +	cancel_delayed_work_sync(&sc->tx_complete_work);  	mutex_unlock(&sc->mutex);  } @@ -3145,13 +3135,14 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)  {  	struct ath_wiphy *aphy = hw->priv;  	struct ath_softc *sc = aphy->sc; +	struct ath_common *common = ath9k_hw_common(sc->sc_ah);  	mutex_lock(&sc->mutex); -	spin_lock_bh(&sc->ani_lock);  	aphy->state = ATH_WIPHY_ACTIVE;  	sc->sc_flags &= ~SC_OP_SCANNING;  	sc->sc_flags |= SC_OP_FULL_RESET; -	spin_unlock_bh(&sc->ani_lock); +	ath_start_ani(common); +	ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);  	ath_beacon_config(sc, NULL);  	mutex_unlock(&sc->mutex);  } diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h index 9eb96f506998..4f6d6fd442f4 100644 --- a/drivers/net/wireless/ath/ath9k/rc.h +++ b/drivers/net/wireless/ath/ath9k/rc.h @@ -57,6 +57,10 @@ enum {  				|| (_phy == WLAN_RC_PHY_HT_40_DS)	\  				|| (_phy == WLAN_RC_PHY_HT_20_DS_HGI)	\  				|| (_phy == WLAN_RC_PHY_HT_40_DS_HGI)) +#define WLAN_RC_PHY_20(_phy)   ((_phy == WLAN_RC_PHY_HT_20_SS)		\ +				|| (_phy == WLAN_RC_PHY_HT_20_DS)	\ +				|| (_phy == WLAN_RC_PHY_HT_20_SS_HGI)	\ +				|| (_phy == WLAN_RC_PHY_HT_20_DS_HGI))  #define WLAN_RC_PHY_40(_phy)   ((_phy == WLAN_RC_PHY_HT_40_SS)		\  				|| (_phy == WLAN_RC_PHY_HT_40_DS)	\  				|| (_phy == WLAN_RC_PHY_HT_40_SS_HGI)	\ diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c index ff9b5c882184..d70732819423 100644 --- a/drivers/net/wireless/hostap/hostap_hw.c +++ b/drivers/net/wireless/hostap/hostap_hw.c @@ -2618,6 +2618,15 @@ static irqreturn_t prism2_interrupt(int irq, void *dev_id)  	int events = 0;  	u16 ev; +	/* Detect early interrupt before driver is fully configued */ +	if (!dev->base_addr) { +		if (net_ratelimit()) { +			printk(KERN_DEBUG "%s: Interrupt, but dev not configured\n", +			       dev->name); +		} +		return IRQ_HANDLED; +	} +  	iface = netdev_priv(dev);  	local = iface->local; diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 8414178bcff4..0db1fda94a65 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -105,6 +105,7 @@ static struct iwl_lib_ops iwl1000_lib = {  	.load_ucode = iwl5000_load_ucode,  	.dump_nic_event_log = iwl_dump_nic_event_log,  	.dump_nic_error_log = iwl_dump_nic_error_log, +	.dump_csr = iwl_dump_csr,  	.init_alive_start = iwl5000_init_alive_start,  	.alive_notify = iwl5000_alive_notify,  	.send_tx_power = iwl5000_send_tx_power, @@ -140,7 +141,7 @@ static struct iwl_lib_ops iwl1000_lib = {  	 },  }; -static struct iwl_ops iwl1000_ops = { +static const struct iwl_ops iwl1000_ops = {  	.ucode = &iwl5000_ucode,  	.lib = &iwl1000_lib,  	.hcmd = &iwl5000_hcmd, @@ -173,7 +174,6 @@ struct iwl_cfg iwl1000_bgn_cfg = {  	.use_rts_for_ht = true, /* use rts/cts protection */  	.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,  	.support_ct_kill_exit = true, -	.sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,  };  struct iwl_cfg iwl1000_bg_cfg = { diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index e413bd35bc41..d1bab141508a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -2810,7 +2810,7 @@ static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = {  	.rts_tx_cmd_flag = iwlcore_rts_tx_cmd_flag,  }; -static struct iwl_ops iwl3945_ops = { +static const struct iwl_ops iwl3945_ops = {  	.ucode = &iwl3945_ucode,  	.lib = &iwl3945_lib,  	.hcmd = &iwl3945_hcmd, diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index ecc23ec1f6a4..28f6eb5f2cba 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -227,7 +227,8 @@ extern void iwl3945_rx_replenish(void *data);  extern void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq);  extern unsigned int iwl3945_fill_beacon_frame(struct iwl_priv *priv,  					struct ieee80211_hdr *hdr,int left); -extern void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log); +extern int iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log, +				       char **buf, bool display);  extern void iwl3945_dump_nic_error_log(struct iwl_priv *priv);  /* diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 484c5fdf7c2a..78706ce8b7ae 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2208,7 +2208,7 @@ static struct iwl_lib_ops iwl4965_lib = {  	},  }; -static struct iwl_ops iwl4965_ops = { +static const struct iwl_ops iwl4965_ops = {  	.ucode = &iwl4965_ucode,  	.lib = &iwl4965_lib,  	.hcmd = &iwl4965_hcmd, @@ -2239,7 +2239,6 @@ struct iwl_cfg iwl4965_agn_cfg = {  	.broken_powersave = true,  	.led_compensation = 61,  	.chain_noise_num_beacons = IWL4965_CAL_NUM_BEACONS, -	.sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,  };  /* Module firmware */ diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 33a5866538e7..ec6b27689fa8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1466,6 +1466,7 @@ struct iwl_lib_ops iwl5000_lib = {  	.is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr,  	.dump_nic_event_log = iwl_dump_nic_event_log,  	.dump_nic_error_log = iwl_dump_nic_error_log, +	.dump_csr = iwl_dump_csr,  	.load_ucode = iwl5000_load_ucode,  	.init_alive_start = iwl5000_init_alive_start,  	.alive_notify = iwl5000_alive_notify, @@ -1518,6 +1519,7 @@ static struct iwl_lib_ops iwl5150_lib = {  	.is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr,  	.dump_nic_event_log = iwl_dump_nic_event_log,  	.dump_nic_error_log = iwl_dump_nic_error_log, +	.dump_csr = iwl_dump_csr,  	.load_ucode = iwl5000_load_ucode,  	.init_alive_start = iwl5000_init_alive_start,  	.alive_notify = iwl5000_alive_notify, @@ -1555,7 +1557,7 @@ static struct iwl_lib_ops iwl5150_lib = {  	 },  }; -static struct iwl_ops iwl5000_ops = { +static const struct iwl_ops iwl5000_ops = {  	.ucode = &iwl5000_ucode,  	.lib = &iwl5000_lib,  	.hcmd = &iwl5000_hcmd, @@ -1563,7 +1565,7 @@ static struct iwl_ops iwl5000_ops = {  	.led = &iwlagn_led_ops,  }; -static struct iwl_ops iwl5150_ops = { +static const struct iwl_ops iwl5150_ops = {  	.ucode = &iwl5000_ucode,  	.lib = &iwl5150_lib,  	.hcmd = &iwl5000_hcmd, @@ -1599,7 +1601,6 @@ struct iwl_cfg iwl5300_agn_cfg = {  	.ht_greenfield_support = true,  	.led_compensation = 51,  	.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, -	.sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,  };  struct iwl_cfg iwl5100_bgn_cfg = { @@ -1668,7 +1669,6 @@ struct iwl_cfg iwl5100_agn_cfg = {  	.ht_greenfield_support = true,  	.led_compensation = 51,  	.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, -	.sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,  };  struct iwl_cfg iwl5350_agn_cfg = { @@ -1692,7 +1692,6 @@ struct iwl_cfg iwl5350_agn_cfg = {  	.ht_greenfield_support = true,  	.led_compensation = 51,  	.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, -	.sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,  };  struct iwl_cfg iwl5150_agn_cfg = { @@ -1716,7 +1715,6 @@ struct iwl_cfg iwl5150_agn_cfg = {  	.ht_greenfield_support = true,  	.led_compensation = 51,  	.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, -	.sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,  };  struct iwl_cfg iwl5150_abg_cfg = { diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 74e571049273..a5a0ed4817a4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -215,6 +215,7 @@ static struct iwl_lib_ops iwl6000_lib = {  	.load_ucode = iwl5000_load_ucode,  	.dump_nic_event_log = iwl_dump_nic_event_log,  	.dump_nic_error_log = iwl_dump_nic_error_log, +	.dump_csr = iwl_dump_csr,  	.init_alive_start = iwl5000_init_alive_start,  	.alive_notify = iwl5000_alive_notify,  	.send_tx_power = iwl5000_send_tx_power, @@ -252,7 +253,7 @@ static struct iwl_lib_ops iwl6000_lib = {  	 },  }; -static struct iwl_ops iwl6000_ops = { +static const struct iwl_ops iwl6000_ops = {  	.ucode = &iwl5000_ucode,  	.lib = &iwl6000_lib,  	.hcmd = &iwl5000_hcmd, @@ -267,7 +268,7 @@ static struct iwl_hcmd_utils_ops iwl6050_hcmd_utils = {  	.calc_rssi = iwl5000_calc_rssi,  }; -static struct iwl_ops iwl6050_ops = { +static const struct iwl_ops iwl6050_ops = {  	.ucode = &iwl5000_ucode,  	.lib = &iwl6000_lib,  	.hcmd = &iwl5000_hcmd, @@ -306,7 +307,6 @@ struct iwl_cfg iwl6000i_2agn_cfg = {  	.supports_idle = true,  	.adv_thermal_throttle = true,  	.support_ct_kill_exit = true, -	.sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,  };  struct iwl_cfg iwl6000i_2abg_cfg = { @@ -395,7 +395,6 @@ struct iwl_cfg iwl6050_2agn_cfg = {  	.supports_idle = true,  	.adv_thermal_throttle = true,  	.support_ct_kill_exit = true, -	.sm_ps_mode = WLAN_HT_CAP_SM_PS_DYNAMIC,  };  struct iwl_cfg iwl6050_2abg_cfg = { @@ -455,7 +454,6 @@ struct iwl_cfg iwl6000_3agn_cfg = {  	.supports_idle = true,  	.adv_thermal_throttle = true,  	.support_ct_kill_exit = true, -	.sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,  };  MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 1c9866daf815..771b03c1c7c5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -657,6 +657,131 @@ static void iwl_bg_statistics_periodic(unsigned long data)  	iwl_send_statistics_request(priv, CMD_ASYNC, false);  } + +static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base, +					u32 start_idx, u32 num_events, +					u32 mode) +{ +	u32 i; +	u32 ptr;        /* SRAM byte address of log data */ +	u32 ev, time, data; /* event log data */ +	unsigned long reg_flags; + +	if (mode == 0) +		ptr = base + (4 * sizeof(u32)) + (start_idx * 2 * sizeof(u32)); +	else +		ptr = base + (4 * sizeof(u32)) + (start_idx * 3 * sizeof(u32)); + +	/* Make sure device is powered up for SRAM reads */ +	spin_lock_irqsave(&priv->reg_lock, reg_flags); +	if (iwl_grab_nic_access(priv)) { +		spin_unlock_irqrestore(&priv->reg_lock, reg_flags); +		return; +	} + +	/* Set starting address; reads will auto-increment */ +	_iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, ptr); +	rmb(); + +	/* +	 * "time" is actually "data" for mode 0 (no timestamp). +	 * place event id # at far right for easier visual parsing. +	 */ +	for (i = 0; i < num_events; i++) { +		ev = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); +		time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); +		if (mode == 0) { +			trace_iwlwifi_dev_ucode_cont_event(priv, +							0, time, ev); +		} else { +			data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); +			trace_iwlwifi_dev_ucode_cont_event(priv, +						time, data, ev); +		} +	} +	/* Allow device to power down */ +	iwl_release_nic_access(priv); +	spin_unlock_irqrestore(&priv->reg_lock, reg_flags); +} + +void iwl_continuous_event_trace(struct iwl_priv *priv) +{ +	u32 capacity;   /* event log capacity in # entries */ +	u32 base;       /* SRAM byte address of event log header */ +	u32 mode;       /* 0 - no timestamp, 1 - timestamp recorded */ +	u32 num_wraps;  /* # times uCode wrapped to top of log */ +	u32 next_entry; /* index of next entry to be written by uCode */ + +	if (priv->ucode_type == UCODE_INIT) +		base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr); +	else +		base = le32_to_cpu(priv->card_alive.log_event_table_ptr); +	if (priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { +		capacity = iwl_read_targ_mem(priv, base); +		num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32))); +		mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32))); +		next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32))); +	} else +		return; + +	if (num_wraps == priv->event_log.num_wraps) { +		iwl_print_cont_event_trace(priv, +				       base, priv->event_log.next_entry, +				       next_entry - priv->event_log.next_entry, +				       mode); +		priv->event_log.non_wraps_count++; +	} else { +		if ((num_wraps - priv->event_log.num_wraps) > 1) +			priv->event_log.wraps_more_count++; +		else +			priv->event_log.wraps_once_count++; +		trace_iwlwifi_dev_ucode_wrap_event(priv, +				num_wraps - priv->event_log.num_wraps, +				next_entry, priv->event_log.next_entry); +		if (next_entry < priv->event_log.next_entry) { +			iwl_print_cont_event_trace(priv, base, +			       priv->event_log.next_entry, +			       capacity - priv->event_log.next_entry, +			       mode); + +			iwl_print_cont_event_trace(priv, base, 0, +				next_entry, mode); +		} else { +			iwl_print_cont_event_trace(priv, base, +			       next_entry, capacity - next_entry, +			       mode); + +			iwl_print_cont_event_trace(priv, base, 0, +				next_entry, mode); +		} +	} +	priv->event_log.num_wraps = num_wraps; +	priv->event_log.next_entry = next_entry; +} + +/** + * iwl_bg_ucode_trace - Timer callback to log ucode event + * + * The timer is continually set to execute every + * UCODE_TRACE_PERIOD milliseconds after the last timer expired + * this function is to perform continuous uCode event logging operation + * if enabled + */ +static void iwl_bg_ucode_trace(unsigned long data) +{ +	struct iwl_priv *priv = (struct iwl_priv *)data; + +	if (test_bit(STATUS_EXIT_PENDING, &priv->status)) +		return; + +	if (priv->event_log.ucode_trace) { +		iwl_continuous_event_trace(priv); +		/* Reschedule the timer to occur in UCODE_TRACE_PERIOD */ +		mod_timer(&priv->ucode_trace, +			 jiffies + msecs_to_jiffies(UCODE_TRACE_PERIOD)); +	} +} +  static void iwl_rx_beacon_notif(struct iwl_priv *priv,  				struct iwl_rx_mem_buffer *rxb)  { @@ -689,12 +814,14 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,  	u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags);  	unsigned long status = priv->status; -	IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s\n", +	IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s CT:%s\n",  			  (flags & HW_CARD_DISABLED) ? "Kill" : "On", -			  (flags & SW_CARD_DISABLED) ? "Kill" : "On"); +			  (flags & SW_CARD_DISABLED) ? "Kill" : "On", +			  (flags & CT_CARD_DISABLED) ? +			  "Reached" : "Not reached");  	if (flags & (SW_CARD_DISABLED | HW_CARD_DISABLED | -		     RF_CARD_DISABLED)) { +		     CT_CARD_DISABLED)) {  		iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,  			    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); @@ -708,10 +835,10 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,  			iwl_write_direct32(priv, HBUS_TARG_MBX_C,  					HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED);  		} -		if (flags & RF_CARD_DISABLED) +		if (flags & CT_CARD_DISABLED)  			iwl_tt_enter_ct_kill(priv);  	} -	if (!(flags & RF_CARD_DISABLED)) +	if (!(flags & CT_CARD_DISABLED))  		iwl_tt_exit_ct_kill(priv);  	if (flags & HW_CARD_DISABLED) @@ -1705,8 +1832,9 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv)   * iwl_print_event_log - Dump error event log to syslog   *   */ -static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, -				u32 num_events, u32 mode) +static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, +			       u32 num_events, u32 mode, +			       int pos, char **buf, size_t bufsz)  {  	u32 i;  	u32 base;       /* SRAM byte address of event log header */ @@ -1716,7 +1844,7 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,  	unsigned long reg_flags;  	if (num_events == 0) -		return; +		return pos;  	if (priv->ucode_type == UCODE_INIT)  		base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);  	else @@ -1744,27 +1872,44 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,  		time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);  		if (mode == 0) {  			/* data, ev */ -			trace_iwlwifi_dev_ucode_event(priv, 0, time, ev); -			IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n", time, ev); +			if (bufsz) { +				pos += scnprintf(*buf + pos, bufsz - pos, +						"EVT_LOG:0x%08x:%04u\n", +						time, ev); +			} else { +				trace_iwlwifi_dev_ucode_event(priv, 0, +					time, ev); +				IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n", +					time, ev); +			}  		} else {  			data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); -			IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n", +			if (bufsz) { +				pos += scnprintf(*buf + pos, bufsz - pos, +						"EVT_LOGT:%010u:0x%08x:%04u\n", +						 time, data, ev); +			} else { +				IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n",  					time, data, ev); -			trace_iwlwifi_dev_ucode_event(priv, time, data, ev); +				trace_iwlwifi_dev_ucode_event(priv, time, +					data, ev); +			}  		}  	}  	/* Allow device to power down */  	iwl_release_nic_access(priv);  	spin_unlock_irqrestore(&priv->reg_lock, reg_flags); +	return pos;  }  /**   * iwl_print_last_event_logs - Dump the newest # of event log to syslog   */ -static void iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity, -				      u32 num_wraps, u32 next_entry, -				      u32 size, u32 mode) +static int iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity, +				    u32 num_wraps, u32 next_entry, +				    u32 size, u32 mode, +				    int pos, char **buf, size_t bufsz)  {  	/*  	 * display the newest DEFAULT_LOG_ENTRIES entries @@ -1772,21 +1917,26 @@ static void iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity,  	 */  	if (num_wraps) {  		if (next_entry < size) { -			iwl_print_event_log(priv, -					capacity - (size - next_entry), -					size - next_entry, mode); -			iwl_print_event_log(priv, 0, -				    next_entry, mode); +			pos = iwl_print_event_log(priv, +						capacity - (size - next_entry), +						size - next_entry, mode, +						pos, buf, bufsz); +			pos = iwl_print_event_log(priv, 0, +						  next_entry, mode, +						  pos, buf, bufsz);  		} else -			iwl_print_event_log(priv, next_entry - size, -				    size, mode); +			pos = iwl_print_event_log(priv, next_entry - size, +						  size, mode, pos, buf, bufsz);  	} else { -		if (next_entry < size) -			iwl_print_event_log(priv, 0, next_entry, mode); -		else -			iwl_print_event_log(priv, next_entry - size, -					    size, mode); +		if (next_entry < size) { +			pos = iwl_print_event_log(priv, 0, next_entry, +						  mode, pos, buf, bufsz); +		} else { +			pos = iwl_print_event_log(priv, next_entry - size, +						  size, mode, pos, buf, bufsz); +		}  	} +	return pos;  }  /* For sanity check only.  Actual size is determined by uCode, typ. 512 */ @@ -1794,7 +1944,8 @@ static void iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity,  #define DEFAULT_DUMP_EVENT_LOG_ENTRIES (20) -void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log) +int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log, +			    char **buf, bool display)  {  	u32 base;       /* SRAM byte address of event log header */  	u32 capacity;   /* event log capacity in # entries */ @@ -1802,6 +1953,8 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log)  	u32 num_wraps;  /* # times uCode wrapped to top of log */  	u32 next_entry; /* index of next entry to be written by uCode */  	u32 size;       /* # entries that we'll print */ +	int pos = 0; +	size_t bufsz = 0;  	if (priv->ucode_type == UCODE_INIT)  		base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); @@ -1812,7 +1965,7 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log)  		IWL_ERR(priv,  			"Invalid event log pointer 0x%08X for %s uCode\n",  			base, (priv->ucode_type == UCODE_INIT) ? "Init" : "RT"); -		return; +		return pos;  	}  	/* event log header */ @@ -1838,7 +1991,7 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log)  	/* bail out if nothing in log */  	if (size == 0) {  		IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n"); -		return; +		return pos;  	}  #ifdef CONFIG_IWLWIFI_DEBUG @@ -1853,6 +2006,15 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log)  		size);  #ifdef CONFIG_IWLWIFI_DEBUG +	if (display) { +		if (full_log) +			bufsz = capacity * 48; +		else +			bufsz = size * 48; +		*buf = kmalloc(bufsz, GFP_KERNEL); +		if (!*buf) +			return pos; +	}  	if ((iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) || full_log) {  		/*  		 * if uCode has wrapped back to top of log, @@ -1860,17 +2022,22 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log)  		 * i.e the next one that uCode would fill.  		 */  		if (num_wraps) -			iwl_print_event_log(priv, next_entry, -					    capacity - next_entry, mode); +			pos = iwl_print_event_log(priv, next_entry, +						capacity - next_entry, mode, +						pos, buf, bufsz);  		/* (then/else) start at top of log */ -		iwl_print_event_log(priv, 0, next_entry, mode); +		pos = iwl_print_event_log(priv, 0, +					  next_entry, mode, pos, buf, bufsz);  	} else -		iwl_print_last_event_logs(priv, capacity, num_wraps, -					next_entry, size, mode); +		pos = iwl_print_last_event_logs(priv, capacity, num_wraps, +						next_entry, size, mode, +						pos, buf, bufsz);  #else -	iwl_print_last_event_logs(priv, capacity, num_wraps, -				next_entry, size, mode); +	pos = iwl_print_last_event_logs(priv, capacity, num_wraps, +					next_entry, size, mode, +					pos, buf, bufsz);  #endif +	return pos;  }  /** @@ -2456,6 +2623,10 @@ static int iwl_setup_mac(struct iwl_priv *priv)  		hw->flags |= IEEE80211_HW_SUPPORTS_PS |  			     IEEE80211_HW_SUPPORTS_DYNAMIC_PS; +	if (priv->cfg->sku & IWL_SKU_N) +		hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | +			     IEEE80211_HW_SUPPORTS_STATIC_SMPS; +  	hw->sta_data_size = sizeof(struct iwl_station_priv);  	hw->wiphy->interface_modes =  		BIT(NL80211_IFTYPE_STATION) | @@ -3126,6 +3297,10 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)  	priv->statistics_periodic.data = (unsigned long)priv;  	priv->statistics_periodic.function = iwl_bg_statistics_periodic; +	init_timer(&priv->ucode_trace); +	priv->ucode_trace.data = (unsigned long)priv; +	priv->ucode_trace.function = iwl_bg_ucode_trace; +  	if (!priv->cfg->use_isr_legacy)  		tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))  			iwl_irq_tasklet, (unsigned long)priv); @@ -3144,6 +3319,7 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv)  	cancel_delayed_work(&priv->alive_start);  	cancel_work_sync(&priv->beacon_update);  	del_timer_sync(&priv->statistics_periodic); +	del_timer_sync(&priv->ucode_trace);  }  static void iwl_init_hw_rates(struct iwl_priv *priv, @@ -3188,6 +3364,7 @@ static int iwl_init_drv(struct iwl_priv *priv)  	priv->band = IEEE80211_BAND_2GHZ;  	priv->iw_mode = NL80211_IFTYPE_STATION; +	priv->current_ht_config.smps = IEEE80211_SMPS_STATIC;  	/* Choose which receivers/antennas to use */  	if (priv->cfg->ops->hcmd->set_rxon_chain) diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c index 95a57b36a7ea..dc61906290e8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-calib.c @@ -414,7 +414,6 @@ static int iwl_sens_auto_corr_ofdm(struct iwl_priv *priv,  /* Prepare a SENSITIVITY_CMD, send to uCode if values have changed */  static int iwl_sensitivity_write(struct iwl_priv *priv)  { -	int ret = 0;  	struct iwl_sensitivity_cmd cmd ;  	struct iwl_sensitivity_data *data = NULL;  	struct iwl_host_cmd cmd_out = { @@ -477,11 +476,7 @@ static int iwl_sensitivity_write(struct iwl_priv *priv)  	memcpy(&(priv->sensitivity_tbl[0]), &(cmd.table[0]),  	       sizeof(u16)*HD_TABLE_SIZE); -	ret = iwl_send_cmd(priv, &cmd_out); -	if (ret) -		IWL_ERR(priv, "SENSITIVITY_CMD failed\n"); - -	return ret; +	return iwl_send_cmd(priv, &cmd_out);  }  void iwl_init_sensitivity(struct iwl_priv *priv) diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index e91507531923..28f3800c560e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -2510,7 +2510,7 @@ struct iwl_card_state_notif {  #define HW_CARD_DISABLED   0x01  #define SW_CARD_DISABLED   0x02 -#define RF_CARD_DISABLED   0x04 +#define CT_CARD_DISABLED   0x04  #define RXON_CARD_DISABLED 0x10  struct iwl_ct_kill_config { diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 574d36658702..e3b96b48b7fe 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -450,8 +450,6 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv,  	if (priv->cfg->ht_greenfield_support)  		ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD;  	ht_info->cap |= IEEE80211_HT_CAP_SGI_20; -	ht_info->cap |= (IEEE80211_HT_CAP_SM_PS & -			     (priv->cfg->sm_ps_mode << 2));  	max_bit_rate = MAX_BIT_RATE_20_MHZ;  	if (priv->hw_params.ht40_channel & BIT(band)) {  		ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; @@ -636,7 +634,7 @@ EXPORT_SYMBOL(iwlcore_rts_tx_cmd_flag);  static bool is_single_rx_stream(struct iwl_priv *priv)  { -	return !priv->current_ht_config.is_ht || +	return priv->current_ht_config.smps == IEEE80211_SMPS_STATIC ||  	       priv->current_ht_config.single_chain_sufficient;  } @@ -1003,28 +1001,18 @@ static int iwl_get_active_rx_chain_count(struct iwl_priv *priv)   */  static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt)  { -	int idle_cnt = active_cnt; -	bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status); - -	/* # Rx chains when idling and maybe trying to save power */ -	switch (priv->cfg->sm_ps_mode) { -	case WLAN_HT_CAP_SM_PS_STATIC: -		idle_cnt = (is_cam) ? active_cnt : IWL_NUM_IDLE_CHAINS_SINGLE; -		break; -	case WLAN_HT_CAP_SM_PS_DYNAMIC: -		idle_cnt = (is_cam) ? IWL_NUM_IDLE_CHAINS_DUAL : -			IWL_NUM_IDLE_CHAINS_SINGLE; -		break; -	case WLAN_HT_CAP_SM_PS_DISABLED: -		break; -	case WLAN_HT_CAP_SM_PS_INVALID: +	/* # Rx chains when idling, depending on SMPS mode */ +	switch (priv->current_ht_config.smps) { +	case IEEE80211_SMPS_STATIC: +	case IEEE80211_SMPS_DYNAMIC: +		return IWL_NUM_IDLE_CHAINS_SINGLE; +	case IEEE80211_SMPS_OFF: +		return active_cnt;  	default: -		IWL_ERR(priv, "invalid sm_ps mode %u\n", -			priv->cfg->sm_ps_mode); -		WARN_ON(1); -		break; +		WARN(1, "invalid SMPS mode %d", +		     priv->current_ht_config.smps); +		return active_cnt;  	} -	return idle_cnt;  }  /* up to 4 chains */ @@ -1363,7 +1351,9 @@ void iwl_irq_handle_error(struct iwl_priv *priv)  	clear_bit(STATUS_HCMD_ACTIVE, &priv->status);  	priv->cfg->ops->lib->dump_nic_error_log(priv); -	priv->cfg->ops->lib->dump_nic_event_log(priv, false); +	if (priv->cfg->ops->lib->dump_csr) +		priv->cfg->ops->lib->dump_csr(priv); +	priv->cfg->ops->lib->dump_nic_event_log(priv, false, NULL, false);  #ifdef CONFIG_IWLWIFI_DEBUG  	if (iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS)  		iwl_print_rx_config_cmd(priv); @@ -2684,6 +2674,21 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)  		IWL_DEBUG_MAC80211(priv, "leave - scanning\n");  	} +	if (changed & (IEEE80211_CONF_CHANGE_SMPS | +		       IEEE80211_CONF_CHANGE_CHANNEL)) { +		/* mac80211 uses static for non-HT which is what we want */ +		priv->current_ht_config.smps = conf->smps_mode; + +		/* +		 * Recalculate chain counts. +		 * +		 * If monitor mode is enabled then mac80211 will +		 * set up the SM PS mode to OFF if an HT channel is +		 * configured. +		 */ +		if (priv->cfg->ops->hcmd->set_rxon_chain) +			priv->cfg->ops->hcmd->set_rxon_chain(priv); +	}  	/* during scanning mac80211 will delay channel setting until  	 * scan finish with changed = 0 @@ -2780,10 +2785,6 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)  		iwl_set_tx_power(priv, conf->power_level, false);  	} -	/* call to ensure that 4965 rx_chain is set properly in monitor mode */ -	if (priv->cfg->ops->hcmd->set_rxon_chain) -		priv->cfg->ops->hcmd->set_rxon_chain(priv); -  	if (!iwl_is_ready(priv)) {  		IWL_DEBUG_MAC80211(priv, "leave - not ready\n");  		goto out; @@ -3191,6 +3192,77 @@ void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len)  EXPORT_SYMBOL(iwl_update_stats);  #endif +const static char *get_csr_string(int cmd) +{ +	switch (cmd) { +		IWL_CMD(CSR_HW_IF_CONFIG_REG); +		IWL_CMD(CSR_INT_COALESCING); +		IWL_CMD(CSR_INT); +		IWL_CMD(CSR_INT_MASK); +		IWL_CMD(CSR_FH_INT_STATUS); +		IWL_CMD(CSR_GPIO_IN); +		IWL_CMD(CSR_RESET); +		IWL_CMD(CSR_GP_CNTRL); +		IWL_CMD(CSR_HW_REV); +		IWL_CMD(CSR_EEPROM_REG); +		IWL_CMD(CSR_EEPROM_GP); +		IWL_CMD(CSR_OTP_GP_REG); +		IWL_CMD(CSR_GIO_REG); +		IWL_CMD(CSR_GP_UCODE_REG); +		IWL_CMD(CSR_GP_DRIVER_REG); +		IWL_CMD(CSR_UCODE_DRV_GP1); +		IWL_CMD(CSR_UCODE_DRV_GP2); +		IWL_CMD(CSR_LED_REG); +		IWL_CMD(CSR_DRAM_INT_TBL_REG); +		IWL_CMD(CSR_GIO_CHICKEN_BITS); +		IWL_CMD(CSR_ANA_PLL_CFG); +		IWL_CMD(CSR_HW_REV_WA_REG); +		IWL_CMD(CSR_DBG_HPET_MEM_REG); +	default: +		return "UNKNOWN"; + +	} +} + +void iwl_dump_csr(struct iwl_priv *priv) +{ +	int i; +	u32 csr_tbl[] = { +		CSR_HW_IF_CONFIG_REG, +		CSR_INT_COALESCING, +		CSR_INT, +		CSR_INT_MASK, +		CSR_FH_INT_STATUS, +		CSR_GPIO_IN, +		CSR_RESET, +		CSR_GP_CNTRL, +		CSR_HW_REV, +		CSR_EEPROM_REG, +		CSR_EEPROM_GP, +		CSR_OTP_GP_REG, +		CSR_GIO_REG, +		CSR_GP_UCODE_REG, +		CSR_GP_DRIVER_REG, +		CSR_UCODE_DRV_GP1, +		CSR_UCODE_DRV_GP2, +		CSR_LED_REG, +		CSR_DRAM_INT_TBL_REG, +		CSR_GIO_CHICKEN_BITS, +		CSR_ANA_PLL_CFG, +		CSR_HW_REV_WA_REG, +		CSR_DBG_HPET_MEM_REG +	}; +	IWL_ERR(priv, "CSR values:\n"); +	IWL_ERR(priv, "(2nd byte of CSR_INT_COALESCING is " +		"CSR_INT_PERIODIC_REG)\n"); +	for (i = 0; i <  ARRAY_SIZE(csr_tbl); i++) { +		IWL_ERR(priv, "  %25s: 0X%08x\n", +			get_csr_string(csr_tbl[i]), +			iwl_read32(priv, csr_tbl[i])); +	} +} +EXPORT_SYMBOL(iwl_dump_csr); +  #ifdef CONFIG_PM  int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 27ca859e7453..308f679ef81c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -169,8 +169,10 @@ struct iwl_lib_ops {  	int (*is_valid_rtc_data_addr)(u32 addr);  	/* 1st ucode load */  	int (*load_ucode)(struct iwl_priv *priv); -	void (*dump_nic_event_log)(struct iwl_priv *priv, bool full_log); +	int (*dump_nic_event_log)(struct iwl_priv *priv, +				  bool full_log, char **buf, bool display);  	void (*dump_nic_error_log)(struct iwl_priv *priv); +	void (*dump_csr)(struct iwl_priv *priv);  	int (*set_channel_switch)(struct iwl_priv *priv, u16 channel);  	/* power management */  	struct iwl_apm_ops apm_ops; @@ -230,7 +232,6 @@ struct iwl_mod_params {   * @chain_noise_num_beacons: number of beacons used to compute chain noise   * @adv_thermal_throttle: support advance thermal throttle   * @support_ct_kill_exit: support ct kill exit condition - * @sm_ps_mode: spatial multiplexing power save mode   * @support_wimax_coexist: support wimax/wifi co-exist   *   * We enable the driver to be backward compatible wrt API version. The @@ -287,7 +288,6 @@ struct iwl_cfg {  	const bool supports_idle;  	bool adv_thermal_throttle;  	bool support_ct_kill_exit; -	u8 sm_ps_mode;  	const bool support_wimax_coexist;  }; @@ -581,7 +581,9 @@ int iwl_pci_resume(struct pci_dev *pdev);  *  Error Handling Debugging  ******************************************************/  void iwl_dump_nic_error_log(struct iwl_priv *priv); -void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log); +int iwl_dump_nic_event_log(struct iwl_priv *priv, +			   bool full_log, char **buf, bool display); +void iwl_dump_csr(struct iwl_priv *priv);  #ifdef CONFIG_IWLWIFI_DEBUG  void iwl_print_rx_config_cmd(struct iwl_priv *priv);  #else diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index d61293ab67c9..58e0462cafa3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -109,6 +109,8 @@ struct iwl_debugfs {  		struct dentry *file_power_save_status;  		struct dentry *file_clear_ucode_statistics;  		struct dentry *file_clear_traffic_statistics; +		struct dentry *file_csr; +		struct dentry *file_ucode_tracing;  	} dbgfs_debug_files;  	u32 sram_offset;  	u32 sram_len; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 21e0f6699daf..ee5aed12a4b1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -420,6 +420,23 @@ static ssize_t iwl_dbgfs_nvm_read(struct file *file,  	return ret;  } +static ssize_t iwl_dbgfs_log_event_read(struct file *file, +					 char __user *user_buf, +					 size_t count, loff_t *ppos) +{ +	struct iwl_priv *priv = file->private_data; +	char *buf; +	int pos = 0; +	ssize_t ret = -ENOMEM; + +	pos = priv->cfg->ops->lib->dump_nic_event_log(priv, true, &buf, true); +	if (pos && buf) { +		ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); +		kfree(buf); +	} +	return ret; +} +  static ssize_t iwl_dbgfs_log_event_write(struct file *file,  					const char __user *user_buf,  					size_t count, loff_t *ppos) @@ -436,7 +453,8 @@ static ssize_t iwl_dbgfs_log_event_write(struct file *file,  	if (sscanf(buf, "%d", &event_log_flag) != 1)  		return -EFAULT;  	if (event_log_flag == 1) -		priv->cfg->ops->lib->dump_nic_event_log(priv, true); +		priv->cfg->ops->lib->dump_nic_event_log(priv, true, +							NULL, false);  	return count;  } @@ -859,7 +877,7 @@ static ssize_t iwl_dbgfs_current_sleep_command_read(struct file *file,  }  DEBUGFS_READ_WRITE_FILE_OPS(sram); -DEBUGFS_WRITE_FILE_OPS(log_event); +DEBUGFS_READ_WRITE_FILE_OPS(log_event);  DEBUGFS_READ_FILE_OPS(nvm);  DEBUGFS_READ_FILE_OPS(stations);  DEBUGFS_READ_FILE_OPS(channels); @@ -1845,6 +1863,80 @@ static ssize_t iwl_dbgfs_clear_ucode_statistics_write(struct file *file,  	return count;  } +static ssize_t iwl_dbgfs_csr_write(struct file *file, +					 const char __user *user_buf, +					 size_t count, loff_t *ppos) +{ +	struct iwl_priv *priv = file->private_data; +	char buf[8]; +	int buf_size; +	int csr; + +	memset(buf, 0, sizeof(buf)); +	buf_size = min(count, sizeof(buf) -  1); +	if (copy_from_user(buf, user_buf, buf_size)) +		return -EFAULT; +	if (sscanf(buf, "%d", &csr) != 1) +		return -EFAULT; + +	if (priv->cfg->ops->lib->dump_csr) +		priv->cfg->ops->lib->dump_csr(priv); + +	return count; +} + +static ssize_t iwl_dbgfs_ucode_tracing_read(struct file *file, +					char __user *user_buf, +					size_t count, loff_t *ppos) { + +	struct iwl_priv *priv = (struct iwl_priv *)file->private_data; +	int pos = 0; +	char buf[128]; +	const size_t bufsz = sizeof(buf); +	ssize_t ret; + +	pos += scnprintf(buf + pos, bufsz - pos, "ucode trace timer is %s\n", +			priv->event_log.ucode_trace ? "On" : "Off"); +	pos += scnprintf(buf + pos, bufsz - pos, "non_wraps_count:\t\t %u\n", +			priv->event_log.non_wraps_count); +	pos += scnprintf(buf + pos, bufsz - pos, "wraps_once_count:\t\t %u\n", +			priv->event_log.wraps_once_count); +	pos += scnprintf(buf + pos, bufsz - pos, "wraps_more_count:\t\t %u\n", +			priv->event_log.wraps_more_count); + +	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); +	return ret; +} + +static ssize_t iwl_dbgfs_ucode_tracing_write(struct file *file, +					 const char __user *user_buf, +					 size_t count, loff_t *ppos) +{ +	struct iwl_priv *priv = file->private_data; +	char buf[8]; +	int buf_size; +	int trace; + +	memset(buf, 0, sizeof(buf)); +	buf_size = min(count, sizeof(buf) -  1); +	if (copy_from_user(buf, user_buf, buf_size)) +		return -EFAULT; +	if (sscanf(buf, "%d", &trace) != 1) +		return -EFAULT; + +	if (trace) { +		priv->event_log.ucode_trace = true; +		/* schedule the ucode timer to occur in UCODE_TRACE_PERIOD */ +		mod_timer(&priv->ucode_trace, +			jiffies + msecs_to_jiffies(UCODE_TRACE_PERIOD)); +	} else { +		priv->event_log.ucode_trace = false; +		del_timer_sync(&priv->ucode_trace); +	} + +	return count; +} +  DEBUGFS_READ_FILE_OPS(rx_statistics);  DEBUGFS_READ_FILE_OPS(tx_statistics);  DEBUGFS_READ_WRITE_FILE_OPS(traffic_log); @@ -1859,6 +1951,8 @@ DEBUGFS_READ_FILE_OPS(tx_power);  DEBUGFS_READ_FILE_OPS(power_save_status);  DEBUGFS_WRITE_FILE_OPS(clear_ucode_statistics);  DEBUGFS_WRITE_FILE_OPS(clear_traffic_statistics); +DEBUGFS_WRITE_FILE_OPS(csr); +DEBUGFS_READ_WRITE_FILE_OPS(ucode_tracing);  /*   * Create the debugfs files and directories @@ -1889,7 +1983,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)  	DEBUGFS_ADD_DIR(debug, dbgfs->dir_drv);  	DEBUGFS_ADD_FILE(nvm, data, S_IRUSR);  	DEBUGFS_ADD_FILE(sram, data, S_IWUSR | S_IRUSR); -	DEBUGFS_ADD_FILE(log_event, data, S_IWUSR); +	DEBUGFS_ADD_FILE(log_event, data, S_IWUSR | S_IRUSR);  	DEBUGFS_ADD_FILE(stations, data, S_IRUSR);  	DEBUGFS_ADD_FILE(channels, data, S_IRUSR);  	DEBUGFS_ADD_FILE(status, data, S_IRUSR); @@ -1909,12 +2003,14 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)  	DEBUGFS_ADD_FILE(power_save_status, debug, S_IRUSR);  	DEBUGFS_ADD_FILE(clear_ucode_statistics, debug, S_IWUSR);  	DEBUGFS_ADD_FILE(clear_traffic_statistics, debug, S_IWUSR); +	DEBUGFS_ADD_FILE(csr, debug, S_IWUSR);  	if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) {  		DEBUGFS_ADD_FILE(ucode_rx_stats, debug, S_IRUSR);  		DEBUGFS_ADD_FILE(ucode_tx_stats, debug, S_IRUSR);  		DEBUGFS_ADD_FILE(ucode_general_stats, debug, S_IRUSR);  		DEBUGFS_ADD_FILE(sensitivity, debug, S_IRUSR);  		DEBUGFS_ADD_FILE(chain_noise, debug, S_IRUSR); +		DEBUGFS_ADD_FILE(ucode_tracing, debug, S_IWUSR | S_IRUSR);  	}  	DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal);  	DEBUGFS_ADD_BOOL(disable_chain_noise, rf, @@ -1966,6 +2062,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)  			file_clear_ucode_statistics);  	DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.  			file_clear_traffic_statistics); +	DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_csr);  	if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) {  		DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.  			file_ucode_rx_stats); @@ -1977,6 +2074,8 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)  			file_sensitivity);  		DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.  			file_chain_noise); +		DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. +			file_ucode_tracing);  	}  	DEBUGFS_REMOVE(priv->dbgfs->dir_debug);  	DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 165d1f6e2dd9..42f9b17327c3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -512,6 +512,7 @@ struct iwl_ht_config {  	bool is_ht;  	bool is_40mhz;  	bool single_chain_sufficient; +	enum ieee80211_smps_mode smps; /* current smps mode */  	/* BSS related data */  	u8 extension_chan_offset;  	u8 ht_protection; @@ -984,6 +985,32 @@ struct iwl_switch_rxon {  	__le16 channel;  }; +/* + * schedule the timer to wake up every UCODE_TRACE_PERIOD milliseconds + * to perform continuous uCode event logging operation if enabled + */ +#define UCODE_TRACE_PERIOD (100) + +/* + * iwl_event_log: current uCode event log position + * + * @ucode_trace: enable/disable ucode continuous trace timer + * @num_wraps: how many times the event buffer wraps + * @next_entry:  the entry just before the next one that uCode would fill + * @non_wraps_count: counter for no wrap detected when dump ucode events + * @wraps_once_count: counter for wrap once detected when dump ucode events + * @wraps_more_count: counter for wrap more than once detected + *		      when dump ucode events + */ +struct iwl_event_log { +	bool ucode_trace; +	u32 num_wraps; +	u32 next_entry; +	int non_wraps_count; +	int wraps_once_count; +	int wraps_more_count; +}; +  struct iwl_priv {  	/* ieee device used by generic ieee processing code */ @@ -1261,6 +1288,7 @@ struct iwl_priv {  	u32 disable_tx_power_cal;  	struct work_struct run_time_calib_work;  	struct timer_list statistics_periodic; +	struct timer_list ucode_trace;  	bool hw_ready;  	/*For 3945*/  #define IWL_DEFAULT_TX_POWER 0x0F @@ -1268,6 +1296,8 @@ struct iwl_priv {  	struct iwl3945_notif_statistics statistics_39;  	u32 sta_supp_rates; + +	struct iwl_event_log event_log;  }; /*iwl_priv */  static inline void iwl_txq_ctx_activate(struct iwl_priv *priv, int txq_id) diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.c b/drivers/net/wireless/iwlwifi/iwl-devtrace.c index e7d88d1da15d..bf46308b17fa 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.c +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.c @@ -11,4 +11,6 @@ EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_iowrite32);  EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_rx);  EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_event);  EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_error); +EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_cont_event); +EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_wrap_event);  #endif diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h index 21361968ab7e..0819f990be6c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h @@ -65,6 +65,50 @@ TRACE_EVENT(iwlwifi_dev_iowrite32,  );  #undef TRACE_SYSTEM +#define TRACE_SYSTEM iwlwifi_ucode + +TRACE_EVENT(iwlwifi_dev_ucode_cont_event, +	TP_PROTO(struct iwl_priv *priv, u32 time, u32 data, u32 ev), +	TP_ARGS(priv, time, data, ev), +	TP_STRUCT__entry( +		PRIV_ENTRY + +		__field(u32, time) +		__field(u32, data) +		__field(u32, ev) +	), +	TP_fast_assign( +		PRIV_ASSIGN; +		__entry->time = time; +		__entry->data = data; +		__entry->ev = ev; +	), +	TP_printk("[%p] EVT_LOGT:%010u:0x%08x:%04u", +		  __entry->priv, __entry->time, __entry->data, __entry->ev) +); + +TRACE_EVENT(iwlwifi_dev_ucode_wrap_event, +	TP_PROTO(struct iwl_priv *priv, u32 wraps, u32 n_entry, u32 p_entry), +	TP_ARGS(priv, wraps, n_entry, p_entry), +	TP_STRUCT__entry( +		PRIV_ENTRY + +		__field(u32, wraps) +		__field(u32, n_entry) +		__field(u32, p_entry) +	), +	TP_fast_assign( +		PRIV_ASSIGN; +		__entry->wraps = wraps; +		__entry->n_entry = n_entry; +		__entry->p_entry = p_entry; +	), +	TP_printk("[%p] wraps=#%02d n=0x%X p=0x%X", +		  __entry->priv, __entry->wraps, __entry->n_entry, +		  __entry->p_entry) +); + +#undef TRACE_SYSTEM  #define TRACE_SYSTEM iwlwifi  TRACE_EVENT(iwlwifi_dev_hcmd, diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index e5d8fa38432e..6533122ed87a 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1559,8 +1559,9 @@ void iwl3945_dump_nic_error_log(struct iwl_priv *priv)   * iwl3945_print_event_log - Dump error event log to syslog   *   */ -static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx, -				u32 num_events, u32 mode) +static int iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx, +				  u32 num_events, u32 mode, +				  int pos, char **buf, size_t bufsz)  {  	u32 i;  	u32 base;       /* SRAM byte address of event log header */ @@ -1570,7 +1571,7 @@ static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx,  	unsigned long reg_flags;  	if (num_events == 0) -		return; +		return pos;  	base = le32_to_cpu(priv->card_alive.log_event_table_ptr); @@ -1596,26 +1597,43 @@ static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx,  		time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);  		if (mode == 0) {  			/* data, ev */ -			IWL_ERR(priv, "0x%08x\t%04u\n", time, ev); -			trace_iwlwifi_dev_ucode_event(priv, 0, time, ev); +			if (bufsz) { +				pos += scnprintf(*buf + pos, bufsz - pos, +						"0x%08x:%04u\n", +						time, ev); +			} else { +				IWL_ERR(priv, "0x%08x\t%04u\n", time, ev); +				trace_iwlwifi_dev_ucode_event(priv, 0, +							      time, ev); +			}  		} else {  			data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); -			IWL_ERR(priv, "%010u\t0x%08x\t%04u\n", time, data, ev); -			trace_iwlwifi_dev_ucode_event(priv, time, data, ev); +			if (bufsz) { +				pos += scnprintf(*buf + pos, bufsz - pos, +						"%010u:0x%08x:%04u\n", +						 time, data, ev); +			} else { +				IWL_ERR(priv, "%010u\t0x%08x\t%04u\n", +					time, data, ev); +				trace_iwlwifi_dev_ucode_event(priv, time, +							      data, ev); +			}  		}  	}  	/* Allow device to power down */  	iwl_release_nic_access(priv);  	spin_unlock_irqrestore(&priv->reg_lock, reg_flags); +	return pos;  }  /**   * iwl3945_print_last_event_logs - Dump the newest # of event log to syslog   */ -static void iwl3945_print_last_event_logs(struct iwl_priv *priv, u32 capacity, +static int iwl3945_print_last_event_logs(struct iwl_priv *priv, u32 capacity,  				      u32 num_wraps, u32 next_entry, -				      u32 size, u32 mode) +				      u32 size, u32 mode, +				      int pos, char **buf, size_t bufsz)  {  	/*  	 * display the newest DEFAULT_LOG_ENTRIES entries @@ -1623,21 +1641,28 @@ static void iwl3945_print_last_event_logs(struct iwl_priv *priv, u32 capacity,  	 */  	if (num_wraps) {  		if (next_entry < size) { -			iwl3945_print_event_log(priv, -					capacity - (size - next_entry), -					size - next_entry, mode); -			iwl3945_print_event_log(priv, 0, -				    next_entry, mode); +			pos = iwl3945_print_event_log(priv, +					     capacity - (size - next_entry), +					     size - next_entry, mode, +					     pos, buf, bufsz); +			pos = iwl3945_print_event_log(priv, 0, +						      next_entry, mode, +						      pos, buf, bufsz);  		} else -			iwl3945_print_event_log(priv, next_entry - size, -				    size, mode); +			pos = iwl3945_print_event_log(priv, next_entry - size, +						      size, mode, +						      pos, buf, bufsz);  	} else {  		if (next_entry < size) -			iwl3945_print_event_log(priv, 0, next_entry, mode); +			pos = iwl3945_print_event_log(priv, 0, +						      next_entry, mode, +						      pos, buf, bufsz);  		else -			iwl3945_print_event_log(priv, next_entry - size, -					    size, mode); +			pos = iwl3945_print_event_log(priv, next_entry - size, +						      size, mode, +						      pos, buf, bufsz);  	} +	return pos;  }  /* For sanity check only.  Actual size is determined by uCode, typ. 512 */ @@ -1645,7 +1670,8 @@ static void iwl3945_print_last_event_logs(struct iwl_priv *priv, u32 capacity,  #define DEFAULT_IWL3945_DUMP_EVENT_LOG_ENTRIES (20) -void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log) +int iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log, +			    char **buf, bool display)  {  	u32 base;       /* SRAM byte address of event log header */  	u32 capacity;   /* event log capacity in # entries */ @@ -1653,11 +1679,13 @@ void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log)  	u32 num_wraps;  /* # times uCode wrapped to top of log */  	u32 next_entry; /* index of next entry to be written by uCode */  	u32 size;       /* # entries that we'll print */ +	int pos = 0; +	size_t bufsz = 0;  	base = le32_to_cpu(priv->card_alive.log_event_table_ptr);  	if (!iwl3945_hw_valid_rtc_data_addr(base)) {  		IWL_ERR(priv, "Invalid event log pointer 0x%08X\n", base); -		return; +		return pos;  	}  	/* event log header */ @@ -1683,7 +1711,7 @@ void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log)  	/* bail out if nothing in log */  	if (size == 0) {  		IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n"); -		return; +		return pos;  	}  #ifdef CONFIG_IWLWIFI_DEBUG @@ -1699,25 +1727,38 @@ void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log)  		  size);  #ifdef CONFIG_IWLWIFI_DEBUG +	if (display) { +		if (full_log) +			bufsz = capacity * 48; +		else +			bufsz = size * 48; +		*buf = kmalloc(bufsz, GFP_KERNEL); +		if (!*buf) +			return pos; +	}  	if ((iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) || full_log) {  		/* if uCode has wrapped back to top of log,  		 * start at the oldest entry,  		 * i.e the next one that uCode would fill.  		 */  		if (num_wraps) -			iwl3945_print_event_log(priv, next_entry, -				    capacity - next_entry, mode); +			pos = iwl3945_print_event_log(priv, next_entry, +						capacity - next_entry, mode, +						pos, buf, bufsz);  		/* (then/else) start at top of log */ -		iwl3945_print_event_log(priv, 0, next_entry, mode); +		pos = iwl3945_print_event_log(priv, 0, next_entry, mode, +					      pos, buf, bufsz);  	} else -		iwl3945_print_last_event_logs(priv, capacity, num_wraps, -					next_entry, size, mode); +		pos = iwl3945_print_last_event_logs(priv, capacity, num_wraps, +						    next_entry, size, mode, +						    pos, buf, bufsz);  #else -	iwl3945_print_last_event_logs(priv, capacity, num_wraps, -				next_entry, size, mode); +	pos = iwl3945_print_last_event_logs(priv, capacity, num_wraps, +					    next_entry, size, mode, +					    pos, buf, bufsz);  #endif - +	return pos;  }  static void iwl3945_irq_tasklet(struct iwl_priv *priv) diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index 6d6ed7485175..d32adeab68a3 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -868,36 +868,35 @@ static int iwm_mlme_mgt_frame(struct iwm_priv *iwm, u8 *buf,  	struct iwm_umac_notif_mgt_frame *mgt_frame =  			(struct iwm_umac_notif_mgt_frame *)buf;  	struct ieee80211_mgmt *mgt = (struct ieee80211_mgmt *)mgt_frame->frame; -	u8 *ie;  	IWM_HEXDUMP(iwm, DBG, MLME, "MGT: ", mgt_frame->frame,  		    le16_to_cpu(mgt_frame->len));  	if (ieee80211_is_assoc_req(mgt->frame_control)) { -		ie = mgt->u.assoc_req.variable;; -		iwm->req_ie_len = -				le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt); +		iwm->req_ie_len = le16_to_cpu(mgt_frame->len) +				  - offsetof(struct ieee80211_mgmt, +					     u.assoc_req.variable);  		kfree(iwm->req_ie);  		iwm->req_ie = kmemdup(mgt->u.assoc_req.variable,  				      iwm->req_ie_len, GFP_KERNEL);  	} else if (ieee80211_is_reassoc_req(mgt->frame_control)) { -		ie = mgt->u.reassoc_req.variable;; -		iwm->req_ie_len = -				le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt); +		iwm->req_ie_len = le16_to_cpu(mgt_frame->len) +				  - offsetof(struct ieee80211_mgmt, +					     u.reassoc_req.variable);  		kfree(iwm->req_ie);  		iwm->req_ie = kmemdup(mgt->u.reassoc_req.variable,  				      iwm->req_ie_len, GFP_KERNEL);  	} else if (ieee80211_is_assoc_resp(mgt->frame_control)) { -		ie = mgt->u.assoc_resp.variable;; -		iwm->resp_ie_len = -				le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt); +		iwm->resp_ie_len = le16_to_cpu(mgt_frame->len) +				   - offsetof(struct ieee80211_mgmt, +					      u.assoc_resp.variable);  		kfree(iwm->resp_ie);  		iwm->resp_ie = kmemdup(mgt->u.assoc_resp.variable,  				       iwm->resp_ie_len, GFP_KERNEL);  	} else if (ieee80211_is_reassoc_resp(mgt->frame_control)) { -		ie = mgt->u.reassoc_resp.variable;; -		iwm->resp_ie_len = -				le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt); +		iwm->resp_ie_len = le16_to_cpu(mgt_frame->len) +				   - offsetof(struct ieee80211_mgmt, +					      u.reassoc_resp.variable);  		kfree(iwm->resp_ie);  		iwm->resp_ie = kmemdup(mgt->u.reassoc_resp.variable,  				       iwm->resp_ie_len, GFP_KERNEL); @@ -1534,6 +1533,33 @@ static void classify8023(struct sk_buff *skb)  	}  } +static void iwm_rx_process_amsdu(struct iwm_priv *iwm, struct sk_buff *skb) +{ +	struct wireless_dev *wdev = iwm_to_wdev(iwm); +	struct net_device *ndev = iwm_to_ndev(iwm); +	struct sk_buff_head list; +	struct sk_buff *frame; + +	IWM_HEXDUMP(iwm, DBG, RX, "A-MSDU: ", skb->data, skb->len); + +	__skb_queue_head_init(&list); +	ieee80211_amsdu_to_8023s(skb, &list, ndev->dev_addr, wdev->iftype, 0); + +	while ((frame = __skb_dequeue(&list))) { +		ndev->stats.rx_packets++; +		ndev->stats.rx_bytes += frame->len; + +		frame->protocol = eth_type_trans(frame, ndev); +		frame->ip_summed = CHECKSUM_NONE; +		memset(frame->cb, 0, sizeof(frame->cb)); + +		if (netif_rx_ni(frame) == NET_RX_DROP) { +			IWM_ERR(iwm, "Packet dropped\n"); +			ndev->stats.rx_dropped++; +		} +	} +} +  static void iwm_rx_process_packet(struct iwm_priv *iwm,  				  struct iwm_rx_packet *packet,  				  struct iwm_rx_ticket_node *ticket_node) @@ -1548,25 +1574,34 @@ static void iwm_rx_process_packet(struct iwm_priv *iwm,  	switch (le16_to_cpu(ticket_node->ticket->action)) {  	case IWM_RX_TICKET_RELEASE:  		IWM_DBG_RX(iwm, DBG, "RELEASE packet\n"); -		classify8023(skb); +  		iwm_rx_adjust_packet(iwm, packet, ticket_node); +		skb->dev = iwm_to_ndev(iwm); +		classify8023(skb); + +		if (le16_to_cpu(ticket_node->ticket->flags) & +		    IWM_RX_TICKET_AMSDU_MSK) { +			iwm_rx_process_amsdu(iwm, skb); +			break; +		} +  		ret = ieee80211_data_to_8023(skb, ndev->dev_addr, wdev->iftype);  		if (ret < 0) {  			IWM_DBG_RX(iwm, DBG, "Couldn't convert 802.11 header - "  				   "%d\n", ret); +			kfree_skb(packet->skb);  			break;  		}  		IWM_HEXDUMP(iwm, DBG, RX, "802.3: ", skb->data, skb->len); -		skb->dev = iwm_to_ndev(iwm); +		ndev->stats.rx_packets++; +		ndev->stats.rx_bytes += skb->len; +  		skb->protocol = eth_type_trans(skb, ndev);  		skb->ip_summed = CHECKSUM_NONE;  		memset(skb->cb, 0, sizeof(skb->cb)); -		ndev->stats.rx_packets++; -		ndev->stats.rx_bytes += skb->len; -  		if (netif_rx_ni(skb) == NET_RX_DROP) {  			IWM_ERR(iwm, "Packet dropped\n");  			ndev->stats.rx_dropped++; diff --git a/drivers/net/wireless/libertas/Kconfig b/drivers/net/wireless/libertas/Kconfig index 30aa9d48d67e..0485c9957575 100644 --- a/drivers/net/wireless/libertas/Kconfig +++ b/drivers/net/wireless/libertas/Kconfig @@ -37,3 +37,9 @@ config LIBERTAS_DEBUG  	depends on LIBERTAS  	---help---  	  Debugging support. + +config LIBERTAS_MESH +	bool "Enable mesh support" +	depends on LIBERTAS +	help +	  This enables Libertas' MESH support, used by e.g. the OLPC people. diff --git a/drivers/net/wireless/libertas/Makefile b/drivers/net/wireless/libertas/Makefile index b188cd97a053..45e870e33117 100644 --- a/drivers/net/wireless/libertas/Makefile +++ b/drivers/net/wireless/libertas/Makefile @@ -5,11 +5,11 @@ libertas-y += cmdresp.o  libertas-y += debugfs.o  libertas-y += ethtool.o  libertas-y += main.o -libertas-y += mesh.o  libertas-y += rx.o  libertas-y += scan.o  libertas-y += tx.o  libertas-y += wext.o +libertas-$(CONFIG_LIBERTAS_MESH) += mesh.o  usb8xxx-objs += if_usb.o  libertas_cs-objs += if_cs.o diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index 751067369ba8..5e650f358415 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -390,10 +390,8 @@ int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,  	cmd.enablehwauto = cpu_to_le16(priv->enablehwauto);  	cmd.bitmap = lbs_rate_to_fw_bitmap(priv->cur_rate, priv->enablehwauto);  	ret = lbs_cmd_with_response(priv, CMD_802_11_RATE_ADAPT_RATESET, &cmd); -	if (!ret && cmd_action == CMD_ACT_GET) { -		priv->ratebitmap = le16_to_cpu(cmd.bitmap); +	if (!ret && cmd_action == CMD_ACT_GET)  		priv->enablehwauto = le16_to_cpu(cmd.enablehwauto); -	}  	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);  	return ret; @@ -807,8 +805,7 @@ static int lbs_try_associate(struct lbs_private *priv,  	}  	/* Use short preamble only when both the BSS and firmware support it */ -	if ((priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) && -	    (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) +	if (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE)  		preamble = RADIO_PREAMBLE_SHORT;  	ret = lbs_set_radio(priv, preamble, 1); @@ -939,8 +936,7 @@ static int lbs_adhoc_join(struct lbs_private *priv,  	}  	/* Use short preamble only when both the BSS and firmware support it */ -	if ((priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) && -	    (bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) { +	if (bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) {  		lbs_deb_join("AdhocJoin: Short preamble\n");  		preamble = RADIO_PREAMBLE_SHORT;  	} @@ -1049,7 +1045,7 @@ static int lbs_adhoc_start(struct lbs_private *priv,  	struct assoc_request *assoc_req)  {  	struct cmd_ds_802_11_ad_hoc_start cmd; -	u8 preamble = RADIO_PREAMBLE_LONG; +	u8 preamble = RADIO_PREAMBLE_SHORT;  	size_t ratesize = 0;  	u16 tmpcap = 0;  	int ret = 0; @@ -1057,11 +1053,6 @@ static int lbs_adhoc_start(struct lbs_private *priv,  	lbs_deb_enter(LBS_DEB_ASSOC); -	if (priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) { -		lbs_deb_join("ADHOC_START: Will use short preamble\n"); -		preamble = RADIO_PREAMBLE_SHORT; -	} -  	ret = lbs_set_radio(priv, preamble, 1);  	if (ret)  		goto out; diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 42611bea76a3..82371ef39524 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -143,19 +143,6 @@ int lbs_update_hw_spec(struct lbs_private *priv)  	lbs_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n",  		    cmd.hwifversion, cmd.version); -	/* Determine mesh_fw_ver from fwrelease and fwcapinfo */ -	/* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */ -	/* 5.110.22 have mesh command with 0xa3 command id */ -	/* 10.0.0.p0 FW brings in mesh config command with different id */ -	/* Check FW version MSB and initialize mesh_fw_ver */ -	if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5) -		priv->mesh_fw_ver = MESH_FW_OLD; -	else if ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) && -		(priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK)) -		priv->mesh_fw_ver = MESH_FW_NEW; -	else -		priv->mesh_fw_ver = MESH_NONE; -  	/* Clamp region code to 8-bit since FW spec indicates that it should  	 * only ever be 8-bit, even though the field size is 16-bit.  Some firmware  	 * returns non-zero high 8 bits here. @@ -855,9 +842,6 @@ int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on)  	if (priv->fwrelease < 0x09000000) {  		switch (preamble) {  		case RADIO_PREAMBLE_SHORT: -			if (!(priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) -				goto out; -			/* Fall through */  		case RADIO_PREAMBLE_AUTO:  		case RADIO_PREAMBLE_LONG:  			cmd.control = cpu_to_le16(preamble); @@ -1011,6 +995,8 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,  		ret = 0;  		break; +#ifdef CONFIG_LIBERTAS_MESH +  	case CMD_BT_ACCESS:  		ret = lbs_cmd_bt_access(cmdptr, cmd_action, pdata_buf);  		break; @@ -1019,6 +1005,8 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,  		ret = lbs_cmd_fwt_access(cmdptr, cmd_action, pdata_buf);  		break; +#endif +  	case CMD_802_11_BEACON_CTRL:  		ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action);  		break; @@ -1317,7 +1305,7 @@ int lbs_execute_next_command(struct lbs_private *priv)  		if ((priv->psmode != LBS802_11POWERMODECAM) &&  		    (priv->psstate == PS_STATE_FULL_POWER) &&  		    ((priv->connect_status == LBS_CONNECTED) || -		    (priv->mesh_connect_status == LBS_CONNECTED))) { +		    lbs_mesh_connected(priv))) {  			if (priv->secinfo.WPAenabled ||  			    priv->secinfo.WPA2enabled) {  				/* check for valid WPA group keys */ diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h index 2862748aef70..cb4138a55fdf 100644 --- a/drivers/net/wireless/libertas/cmd.h +++ b/drivers/net/wireless/libertas/cmd.h @@ -110,18 +110,6 @@ int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val);  int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val); -/* Mesh related */ - -int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action, -		    struct cmd_ds_mesh_access *cmd); - -int lbs_mesh_config_send(struct lbs_private *priv, -			 struct cmd_ds_mesh_config *cmd, -			 uint16_t action, uint16_t type); - -int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan); - -  /* Commands only used in wext.c, assoc. and scan.c */  int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0, diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 21d57690c20a..0334a58820ee 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -485,20 +485,8 @@ int lbs_process_event(struct lbs_private *priv, u32 event)  		break;  	case MACREG_INT_CODE_MESH_AUTO_STARTED: -		/* Ignore spurious autostart events if autostart is disabled */ -		if (!priv->mesh_autostart_enabled) { -			lbs_pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n"); -			break; -		} -		lbs_pr_info("EVENT: MESH_AUTO_STARTED\n"); -		priv->mesh_connect_status = LBS_CONNECTED; -		if (priv->mesh_open) { -			netif_carrier_on(priv->mesh_dev); -			if (!priv->tx_pending_len) -				netif_wake_queue(priv->mesh_dev); -		} -		priv->mode = IW_MODE_ADHOC; -		schedule_work(&priv->sync_channel); +		/* Ignore spurious autostart events */ +		lbs_pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n");  		break;  	default: diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index 6b6ea9f7bf5b..ea3f10ef4e00 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h @@ -397,13 +397,6 @@ enum KEY_INFO_WPA {  	KEY_INFO_WPA_ENABLED = 0x04  }; -/** mesh_fw_ver */ -enum _mesh_fw_ver { -	MESH_NONE = 0, /* MESH is not supported */ -	MESH_FW_OLD,   /* MESH is supported in FW V5 */ -	MESH_FW_NEW,   /* MESH is supported in FW V10 and newer */ -}; -  /* Default values for fwt commands. */  #define FWT_DEFAULT_METRIC 0  #define FWT_DEFAULT_DIR 1 diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 05bb298dfae9..c348aff8f309 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -39,15 +39,14 @@ struct lbs_private {  	/* Mesh */  	struct net_device *mesh_dev; /* Virtual device */ +#ifdef CONFIG_LIBERTAS_MESH  	u32 mesh_connect_status;  	struct lbs_mesh_stats mstats;  	int mesh_open; -	int mesh_fw_ver; -	int mesh_autostart_enabled;  	uint16_t mesh_tlv;  	u8 mesh_ssid[IEEE80211_MAX_SSID_LEN + 1];  	u8 mesh_ssid_len; -	struct work_struct sync_channel; +#endif  	/* Monitor mode */  	struct net_device *rtap_net_dev; @@ -176,9 +175,7 @@ struct lbs_private {  	struct bss_descriptor *networks;  	struct assoc_request * pending_assoc_req;  	struct assoc_request * in_progress_assoc_req; -	u16 capability;  	uint16_t enablehwauto; -	uint16_t ratebitmap;  	/* ADHOC */  	u16 beacon_period; diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c index 63d020374c2b..3804a58d7f4e 100644 --- a/drivers/net/wireless/libertas/ethtool.c +++ b/drivers/net/wireless/libertas/ethtool.c @@ -114,9 +114,11 @@ const struct ethtool_ops lbs_ethtool_ops = {  	.get_drvinfo = lbs_ethtool_get_drvinfo,  	.get_eeprom =  lbs_ethtool_get_eeprom,  	.get_eeprom_len = lbs_ethtool_get_eeprom_len, +#ifdef CONFIG_LIBERTAS_MESH  	.get_sset_count = lbs_mesh_ethtool_get_sset_count,  	.get_ethtool_stats = lbs_mesh_ethtool_get_stats,  	.get_strings = lbs_mesh_ethtool_get_strings, +#endif  	.get_wol = lbs_ethtool_get_wol,  	.set_wol = lbs_ethtool_set_wol,  }; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index c2975c8e2f21..60bde1233a30 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -123,7 +123,7 @@ static ssize_t lbs_rtap_set(struct device *dev,  		if (priv->monitormode == monitor_mode)  			return strlen(buf);  		if (!priv->monitormode) { -			if (priv->infra_open || priv->mesh_open) +			if (priv->infra_open || lbs_mesh_open(priv))  				return -EBUSY;  			if (priv->mode == IW_MODE_INFRA)  				lbs_cmd_80211_deauthenticate(priv, @@ -622,7 +622,7 @@ static int lbs_thread(void *data)  				if (priv->connect_status == LBS_CONNECTED)  					netif_wake_queue(priv->dev);  				if (priv->mesh_dev && -				    priv->mesh_connect_status == LBS_CONNECTED) +				    lbs_mesh_connected(priv))  					netif_wake_queue(priv->mesh_dev);  			}  		} @@ -809,18 +809,6 @@ int lbs_exit_auto_deep_sleep(struct lbs_private *priv)  	return 0;  } -static void lbs_sync_channel_worker(struct work_struct *work) -{ -	struct lbs_private *priv = container_of(work, struct lbs_private, -		sync_channel); - -	lbs_deb_enter(LBS_DEB_MAIN); -	if (lbs_update_channel(priv)) -		lbs_pr_info("Channel synchronization failed."); -	lbs_deb_leave(LBS_DEB_MAIN); -} - -  static int lbs_init_adapter(struct lbs_private *priv)  {  	size_t bufsize; @@ -848,14 +836,12 @@ static int lbs_init_adapter(struct lbs_private *priv)  	memset(priv->current_addr, 0xff, ETH_ALEN);  	priv->connect_status = LBS_DISCONNECTED; -	priv->mesh_connect_status = LBS_DISCONNECTED;  	priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;  	priv->mode = IW_MODE_INFRA;  	priv->channel = DEFAULT_AD_HOC_CHANNEL;  	priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON;  	priv->radio_on = 1;  	priv->enablehwauto = 1; -	priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE;  	priv->psmode = LBS802_11POWERMODECAM;  	priv->psstate = PS_STATE_FULL_POWER;  	priv->is_deep_sleep = 0; @@ -998,11 +984,6 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)  	INIT_DELAYED_WORK(&priv->assoc_work, lbs_association_worker);  	INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker);  	INIT_WORK(&priv->mcast_work, lbs_set_mcast_worker); -	INIT_WORK(&priv->sync_channel, lbs_sync_channel_worker); - -	priv->mesh_open = 0; -	sprintf(priv->mesh_ssid, "mesh"); -	priv->mesh_ssid_len = 4;  	priv->wol_criteria = 0xffffffff;  	priv->wol_gpio = 0xff; @@ -1076,6 +1057,17 @@ void lbs_remove_card(struct lbs_private *priv)  EXPORT_SYMBOL_GPL(lbs_remove_card); +static int lbs_rtap_supported(struct lbs_private *priv) +{ +	if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5) +		return 1; + +	/* newer firmware use a capability mask */ +	return ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) && +		(priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK)); +} + +  int lbs_start_card(struct lbs_private *priv)  {  	struct net_device *dev = priv->dev; @@ -1095,12 +1087,14 @@ int lbs_start_card(struct lbs_private *priv)  	lbs_update_channel(priv); +	lbs_init_mesh(priv); +  	/*  	 * While rtap isn't related to mesh, only mesh-enabled  	 * firmware implements the rtap functionality via  	 * CMD_802_11_MONITOR_MODE.  	 */ -	if (lbs_init_mesh(priv)) { +	if (lbs_rtap_supported(priv)) {  		if (device_create_file(&dev->dev, &dev_attr_lbs_rtap))  			lbs_pr_err("cannot register lbs_rtap attribute\n");  	} @@ -1134,7 +1128,9 @@ void lbs_stop_card(struct lbs_private *priv)  	netif_carrier_off(dev);  	lbs_debugfs_remove_one(priv); -	if (lbs_deinit_mesh(priv)) +	lbs_deinit_mesh(priv); + +	if (lbs_rtap_supported(priv))  		device_remove_file(&dev->dev, &dev_attr_lbs_rtap);  	/* Delete the timeout of the currently processing command */ diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c index 2f91c9b808af..954cd00f7452 100644 --- a/drivers/net/wireless/libertas/mesh.c +++ b/drivers/net/wireless/libertas/mesh.c @@ -1,4 +1,3 @@ -#include <linux/moduleparam.h>  #include <linux/delay.h>  #include <linux/etherdevice.h>  #include <linux/netdevice.h> @@ -196,7 +195,14 @@ int lbs_init_mesh(struct lbs_private *priv)  	lbs_deb_enter(LBS_DEB_MESH); -	if (priv->mesh_fw_ver == MESH_FW_OLD) { +	priv->mesh_connect_status = LBS_DISCONNECTED; + +	/* Determine mesh_fw_ver from fwrelease and fwcapinfo */ +	/* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */ +	/* 5.110.22 have mesh command with 0xa3 command id */ +	/* 10.0.0.p0 FW brings in mesh config command with different id */ +	/* Check FW version MSB and initialize mesh_fw_ver */ +	if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5) {  		/* Enable mesh, if supported, and work out which TLV it uses.  		   0x100 + 291 is an unofficial value used in 5.110.20.pXX  		   0x100 + 37 is the official value used in 5.110.21.pXX @@ -218,7 +224,9 @@ int lbs_init_mesh(struct lbs_private *priv)  					    priv->channel))  				priv->mesh_tlv = 0;  		} -	} else if (priv->mesh_fw_ver == MESH_FW_NEW) { +	} else +	if ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) && +		(priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK)) {  		/* 10.0.0.pXX new firmwares should succeed with TLV  		 * 0x100+37; Do not invoke command with old TLV.  		 */ @@ -227,7 +235,12 @@ int lbs_init_mesh(struct lbs_private *priv)  				    priv->channel))  			priv->mesh_tlv = 0;  	} + +  	if (priv->mesh_tlv) { +		sprintf(priv->mesh_ssid, "mesh"); +		priv->mesh_ssid_len = 4; +  		lbs_add_mesh(priv);  		if (device_create_file(&dev->dev, &dev_attr_lbs_mesh)) @@ -416,10 +429,10 @@ struct net_device *lbs_mesh_set_dev(struct lbs_private *priv,  	struct net_device *dev, struct rxpd *rxpd)  {  	if (priv->mesh_dev) { -		if (priv->mesh_fw_ver == MESH_FW_OLD) { +		if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID) {  			if (rxpd->rx_control & RxPD_MESH_FRAME)  				dev = priv->mesh_dev; -		} else if (priv->mesh_fw_ver == MESH_FW_NEW) { +		} else if (priv->mesh_tlv == TLV_TYPE_MESH_ID) {  			if (rxpd->u.bss.bss_num == MESH_IFACE_ID)  				dev = priv->mesh_dev;  		} @@ -432,9 +445,9 @@ void lbs_mesh_set_txpd(struct lbs_private *priv,  	struct net_device *dev, struct txpd *txpd)  {  	if (dev == priv->mesh_dev) { -		if (priv->mesh_fw_ver == MESH_FW_OLD) +		if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID)  			txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME); -		else if (priv->mesh_fw_ver == MESH_FW_NEW) +		else if (priv->mesh_tlv == TLV_TYPE_MESH_ID)  			txpd->u.bss.bss_num = MESH_IFACE_ID;  	}  } @@ -538,7 +551,7 @@ static int __lbs_mesh_config_send(struct lbs_private *priv,  	 * Command id is 0xac for v10 FW along with mesh interface  	 * id in bits 14-13-12.  	 */ -	if (priv->mesh_fw_ver == MESH_FW_NEW) +	if (priv->mesh_tlv == TLV_TYPE_MESH_ID)  		command = CMD_MESH_CONFIG |  			  (MESH_IFACE_ID << MESH_IFACE_BIT_OFFSET); diff --git a/drivers/net/wireless/libertas/mesh.h b/drivers/net/wireless/libertas/mesh.h index fea9b5d005fc..e2573303a328 100644 --- a/drivers/net/wireless/libertas/mesh.h +++ b/drivers/net/wireless/libertas/mesh.h @@ -9,6 +9,8 @@  #include <net/lib80211.h> +#ifdef CONFIG_LIBERTAS_MESH +  /* Mesh statistics */  struct lbs_mesh_stats {  	u32	fwd_bcast_cnt;		/* Fwd: Broadcast counter */ @@ -46,11 +48,20 @@ void lbs_mesh_set_txpd(struct lbs_private *priv,  /* Command handling */  struct cmd_ds_command; +struct cmd_ds_mesh_access; +struct cmd_ds_mesh_config;  int lbs_cmd_bt_access(struct cmd_ds_command *cmd,  	u16 cmd_action, void *pdata_buf);  int lbs_cmd_fwt_access(struct cmd_ds_command *cmd,  	u16 cmd_action, void *pdata_buf); +int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action, +		    struct cmd_ds_mesh_access *cmd); +int lbs_mesh_config_send(struct lbs_private *priv, +			 struct cmd_ds_mesh_config *cmd, +			 uint16_t action, uint16_t type); +int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan); +  /* Persistent configuration */ @@ -75,4 +86,25 @@ void lbs_mesh_ethtool_get_strings(struct net_device *dev,  	uint32_t stringset, uint8_t *s); +/* Accessors */ + +#define lbs_mesh_open(priv) (priv->mesh_open) +#define lbs_mesh_connected(priv) (priv->mesh_connect_status == LBS_CONNECTED) + +#else + +#define lbs_init_mesh(priv) +#define lbs_deinit_mesh(priv) +#define lbs_add_mesh(priv) +#define lbs_remove_mesh(priv) +#define lbs_mesh_set_dev(priv, dev, rxpd) (dev) +#define lbs_mesh_set_txpd(priv, dev, txpd) +#define lbs_mesh_config(priv, enable, chan) +#define lbs_mesh_open(priv) (0) +#define lbs_mesh_connected(priv) (0) + +#endif + + +  #endif diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index c6a6c042b82f..4a0c3e3cd3b1 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -640,7 +640,7 @@ out:  		if (!priv->tx_pending_len)  			netif_wake_queue(priv->dev);  	} -	if (priv->mesh_dev && (priv->mesh_connect_status == LBS_CONNECTED)) { +	if (priv->mesh_dev && lbs_mesh_connected(priv)) {  		netif_carrier_on(priv->mesh_dev);  		if (!priv->tx_pending_len)  			netif_wake_queue(priv->mesh_dev); diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c index 315d1ce286ca..52d244ea3d97 100644 --- a/drivers/net/wireless/libertas/tx.c +++ b/drivers/net/wireless/libertas/tx.c @@ -198,7 +198,7 @@ void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count)  	if (priv->connect_status == LBS_CONNECTED)  		netif_wake_queue(priv->dev); -	if (priv->mesh_dev && (priv->mesh_connect_status == LBS_CONNECTED)) +	if (priv->mesh_dev && lbs_mesh_connected(priv))  		netif_wake_queue(priv->mesh_dev);  }  EXPORT_SYMBOL_GPL(lbs_send_tx_feedback); diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 4b1aab593a84..71f88a08e090 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -192,7 +192,7 @@ static void copy_active_data_rates(struct lbs_private *priv, u8 *rates)  	lbs_deb_enter(LBS_DEB_WEXT);  	if ((priv->connect_status != LBS_CONNECTED) && -		(priv->mesh_connect_status != LBS_CONNECTED)) +		!lbs_mesh_connected(priv))  		memcpy(rates, lbs_bg_rates, MAX_RATES);  	else  		memcpy(rates, priv->curbssparams.rates, MAX_RATES); @@ -298,6 +298,7 @@ static int lbs_get_nick(struct net_device *dev, struct iw_request_info *info,  	return 0;  } +#ifdef CONFIG_LIBERTAS_MESH  static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info,  			 struct iw_point *dwrq, char *extra)  { @@ -307,7 +308,7 @@ static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info,  	/* Use nickname to indicate that mesh is on */ -	if (priv->mesh_connect_status == LBS_CONNECTED) { +	if (lbs_mesh_connected(priv)) {  		strncpy(extra, "Mesh", 12);  		extra[12] = '\0';  		dwrq->length = strlen(extra); @@ -321,6 +322,7 @@ static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info,  	lbs_deb_leave(LBS_DEB_WEXT);  	return 0;  } +#endif  static int lbs_set_rts(struct net_device *dev, struct iw_request_info *info,  			struct iw_param *vwrq, char *extra) @@ -422,6 +424,7 @@ static int lbs_get_mode(struct net_device *dev,  	return 0;  } +#ifdef CONFIG_LIBERTAS_MESH  static int mesh_wlan_get_mode(struct net_device *dev,  		              struct iw_request_info *info, u32 * uwrq,  			      char *extra) @@ -433,6 +436,7 @@ static int mesh_wlan_get_mode(struct net_device *dev,  	lbs_deb_leave(LBS_DEB_WEXT);  	return 0;  } +#endif  static int lbs_get_txpow(struct net_device *dev,  			  struct iw_request_info *info, @@ -863,7 +867,7 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev)  	/* If we're not associated, all quality values are meaningless */  	if ((priv->connect_status != LBS_CONNECTED) && -	    (priv->mesh_connect_status != LBS_CONNECTED)) +	    !lbs_mesh_connected(priv))  		goto out;  	/* Quality by RSSI */ @@ -1010,6 +1014,7 @@ out:  	return ret;  } +#ifdef CONFIG_LIBERTAS_MESH  static int lbs_mesh_set_freq(struct net_device *dev,  			     struct iw_request_info *info,  			     struct iw_freq *fwrq, char *extra) @@ -1061,6 +1066,7 @@ out:  	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);  	return ret;  } +#endif  static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info,  		  struct iw_param *vwrq, char *extra) @@ -2108,6 +2114,7 @@ out:  	return ret;  } +#ifdef CONFIG_LIBERTAS_MESH  static int lbs_mesh_get_essid(struct net_device *dev,  			      struct iw_request_info *info,  			      struct iw_point *dwrq, char *extra) @@ -2161,6 +2168,7 @@ static int lbs_mesh_set_essid(struct net_device *dev,  	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);  	return ret;  } +#endif  /**   *  @brief Connect to the AP or Ad-hoc Network with specific bssid @@ -2267,7 +2275,13 @@ static const iw_handler lbs_handler[] = {  	(iw_handler) lbs_get_encodeext,/* SIOCGIWENCODEEXT */  	(iw_handler) NULL,		/* SIOCSIWPMKSA */  }; +struct iw_handler_def lbs_handler_def = { +	.num_standard	= ARRAY_SIZE(lbs_handler), +	.standard	= (iw_handler *) lbs_handler, +	.get_wireless_stats = lbs_get_wireless_stats, +}; +#ifdef CONFIG_LIBERTAS_MESH  static const iw_handler mesh_wlan_handler[] = {  	(iw_handler) NULL,	/* SIOCSIWCOMMIT */  	(iw_handler) lbs_get_name,	/* SIOCGIWNAME */ @@ -2325,14 +2339,10 @@ static const iw_handler mesh_wlan_handler[] = {  	(iw_handler) lbs_get_encodeext,/* SIOCGIWENCODEEXT */  	(iw_handler) NULL,		/* SIOCSIWPMKSA */  }; -struct iw_handler_def lbs_handler_def = { -	.num_standard	= ARRAY_SIZE(lbs_handler), -	.standard	= (iw_handler *) lbs_handler, -	.get_wireless_stats = lbs_get_wireless_stats, -};  struct iw_handler_def mesh_handler_def = {  	.num_standard	= ARRAY_SIZE(mesh_wlan_handler),  	.standard	= (iw_handler *) mesh_wlan_handler,  	.get_wireless_stats = lbs_get_wireless_stats,  }; +#endif diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 88e41176e7fd..718a5f198c30 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -436,6 +436,38 @@ static bool hwsim_ps_rx_ok(struct mac80211_hwsim_data *data,  } +struct mac80211_hwsim_addr_match_data { +	bool ret; +	const u8 *addr; +}; + +static void mac80211_hwsim_addr_iter(void *data, u8 *mac, +				     struct ieee80211_vif *vif) +{ +	struct mac80211_hwsim_addr_match_data *md = data; +	if (memcmp(mac, md->addr, ETH_ALEN) == 0) +		md->ret = true; +} + + +static bool mac80211_hwsim_addr_match(struct mac80211_hwsim_data *data, +				      const u8 *addr) +{ +	struct mac80211_hwsim_addr_match_data md; + +	if (memcmp(addr, data->hw->wiphy->perm_addr, ETH_ALEN) == 0) +		return true; + +	md.ret = false; +	md.addr = addr; +	ieee80211_iterate_active_interfaces_atomic(data->hw, +						   mac80211_hwsim_addr_iter, +						   &md); + +	return md.ret; +} + +  static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,  				    struct sk_buff *skb)  { @@ -488,8 +520,7 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,  		if (nskb == NULL)  			continue; -		if (memcmp(hdr->addr1, data2->hw->wiphy->perm_addr, -			   ETH_ALEN) == 0) +		if (mac80211_hwsim_addr_match(data2, hdr->addr1))  			ack = true;  		memcpy(IEEE80211_SKB_RXCB(nskb), &rx_status, sizeof(rx_status));  		ieee80211_rx_irqsafe(data2->hw, nskb); @@ -618,12 +649,26 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)  {  	struct mac80211_hwsim_data *data = hw->priv;  	struct ieee80211_conf *conf = &hw->conf; - -	printk(KERN_DEBUG "%s:%s (freq=%d idle=%d ps=%d)\n", +	static const char *chantypes[4] = { +		[NL80211_CHAN_NO_HT] = "noht", +		[NL80211_CHAN_HT20] = "ht20", +		[NL80211_CHAN_HT40MINUS] = "ht40-", +		[NL80211_CHAN_HT40PLUS] = "ht40+", +	}; +	static const char *smps_modes[IEEE80211_SMPS_NUM_MODES] = { +		[IEEE80211_SMPS_AUTOMATIC] = "auto", +		[IEEE80211_SMPS_OFF] = "off", +		[IEEE80211_SMPS_STATIC] = "static", +		[IEEE80211_SMPS_DYNAMIC] = "dynamic", +	}; + +	printk(KERN_DEBUG "%s:%s (freq=%d/%s idle=%d ps=%d smps=%s)\n",  	       wiphy_name(hw->wiphy), __func__,  	       conf->channel->center_freq, +	       chantypes[conf->channel_type],  	       !!(conf->flags & IEEE80211_CONF_IDLE), -	       !!(conf->flags & IEEE80211_CONF_PS)); +	       !!(conf->flags & IEEE80211_CONF_PS), +	       smps_modes[conf->smps_mode]);  	data->idle = !!(conf->flags & IEEE80211_CONF_IDLE); @@ -827,6 +872,31 @@ static int mac80211_hwsim_testmode_cmd(struct ieee80211_hw *hw,  }  #endif +static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw, +				       struct ieee80211_vif *vif, +				       enum ieee80211_ampdu_mlme_action action, +				       struct ieee80211_sta *sta, u16 tid, u16 *ssn) +{ +	switch (action) { +	case IEEE80211_AMPDU_TX_START: +		ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); +		break; +	case IEEE80211_AMPDU_TX_STOP: +		ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); +		break; +	case IEEE80211_AMPDU_TX_OPERATIONAL: +		break; +	case IEEE80211_AMPDU_RX_START: +	case IEEE80211_AMPDU_RX_STOP: +		break; +	default: +		return -EOPNOTSUPP; +	} + +	return 0; +} + +  static const struct ieee80211_ops mac80211_hwsim_ops =  {  	.tx = mac80211_hwsim_tx, @@ -841,6 +911,7 @@ static const struct ieee80211_ops mac80211_hwsim_ops =  	.set_tim = mac80211_hwsim_set_tim,  	.conf_tx = mac80211_hwsim_conf_tx,  	CFG80211_TESTMODE_CMD(mac80211_hwsim_testmode_cmd) +	.ampdu_action = mac80211_hwsim_ampdu_action,  }; @@ -1082,7 +1153,9 @@ static int __init init_mac80211_hwsim(void)  			BIT(NL80211_IFTYPE_MESH_POINT);  		hw->flags = IEEE80211_HW_MFP_CAPABLE | -			    IEEE80211_HW_SIGNAL_DBM; +			    IEEE80211_HW_SIGNAL_DBM | +			    IEEE80211_HW_SUPPORTS_STATIC_SMPS | +			    IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS;  		/* ask mac80211 to reserve space for magic */  		hw->vif_data_size = sizeof(struct hwsim_vif_priv); diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 2ecbedb26e15..305c106fdc1c 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -2594,23 +2594,9 @@ end:  /*   * driver/device initialization   */ -static int bcm4320a_early_init(struct usbnet *usbdev) -{ -	/* bcm4320a doesn't handle configuration parameters well. Try -	 * set any and you get partially zeroed mac and broken device. -	 */ - -	return 0; -} - -static int bcm4320b_early_init(struct usbnet *usbdev) +static void rndis_copy_module_params(struct usbnet *usbdev)  {  	struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); -	char buf[8]; - -	/* Early initialization settings, setting these won't have effect -	 * if called after generic_rndis_bind(). -	 */  	priv->param_country[0] = modparam_country[0];  	priv->param_country[1] = modparam_country[1]; @@ -2652,6 +2638,32 @@ static int bcm4320b_early_init(struct usbnet *usbdev)  		priv->param_workaround_interval = 500;  	else  		priv->param_workaround_interval = modparam_workaround_interval; +} + +static int bcm4320a_early_init(struct usbnet *usbdev) +{ +	/* copy module parameters for bcm4320a so that iwconfig reports txpower +	 * and workaround parameter is copied to private structure correctly. +	 */ +	rndis_copy_module_params(usbdev); + +	/* bcm4320a doesn't handle configuration parameters well. Try +	 * set any and you get partially zeroed mac and broken device. +	 */ + +	return 0; +} + +static int bcm4320b_early_init(struct usbnet *usbdev) +{ +	struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); +	char buf[8]; + +	rndis_copy_module_params(usbdev); + +	/* Early initialization settings, setting these won't have effect +	 * if called after generic_rndis_bind(). +	 */  	rndis_set_config_parameter_str(usbdev, "Country", priv->param_country);  	rndis_set_config_parameter_str(usbdev, "FrameBursting", diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index dfc886fcb44d..458378c4e500 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -835,7 +835,6 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry,  				  struct rxdone_entry_desc *rxdesc)  {  	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; -	struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);  	struct queue_entry_priv_pci *entry_priv = entry->priv_data;  	__le32 *rxd = entry_priv->desc;  	__le32 *rxwi = (__le32 *)entry->skb->data; @@ -883,10 +882,8 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry,  	if (rt2x00_get_field32(rxd3, RXD_W3_MY_BSS))  		rxdesc->dev_flags |= RXDONE_MY_BSS; -	if (rt2x00_get_field32(rxd3, RXD_W3_L2PAD)) { +	if (rt2x00_get_field32(rxd3, RXD_W3_L2PAD))  		rxdesc->dev_flags |= RXDONE_L2PAD; -		skbdesc->flags |= SKBDESC_L2_PADDED; -	}  	if (rt2x00_get_field32(rxwi1, RXWI_W1_SHORT_GI))  		rxdesc->flags |= RX_FLAG_SHORT_GI; @@ -927,7 +924,6 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry,  	 * Remove TXWI descriptor from start of buffer.  	 */  	skb_pull(entry->skb, RXWI_DESC_SIZE); -	skb_trim(entry->skb, rxdesc->size);  }  /* diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index af85d18cdbe7..40295b454ff6 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -295,9 +295,7 @@ static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev)  	rt2800_register_read(rt2x00dev, USB_DMA_CFG, ®);  	rt2x00_set_field32(®, USB_DMA_CFG_PHY_CLEAR, 0); -	/* Don't use bulk in aggregation when working with USB 1.1 */ -	rt2x00_set_field32(®, USB_DMA_CFG_RX_BULK_AGG_EN, -			   (rt2x00dev->rx->usb_maxpacket == 512)); +	rt2x00_set_field32(®, USB_DMA_CFG_RX_BULK_AGG_EN, 0);  	rt2x00_set_field32(®, USB_DMA_CFG_RX_BULK_AGG_TIMEOUT, 128);  	/*  	 * Total room for RX frames in kilobytes, PBF might still exceed @@ -573,41 +571,57 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry,  {  	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;  	struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); -	__le32 *rxd = (__le32 *)entry->skb->data; +	__le32 *rxi = (__le32 *)entry->skb->data;  	__le32 *rxwi; -	u32 rxd0; +	__le32 *rxd; +	u32 rxi0;  	u32 rxwi0;  	u32 rxwi1;  	u32 rxwi2;  	u32 rxwi3; +	u32 rxd0; +	int rx_pkt_len; + +	/* +	 * RX frame format is : +	 * | RXINFO | RXWI | header | L2 pad | payload | pad | RXD | USB pad | +	 *          |<------------ rx_pkt_len -------------->| +	 */ +	rt2x00_desc_read(rxi, 0, &rxi0); +	rx_pkt_len = rt2x00_get_field32(rxi0, RXINFO_W0_USB_DMA_RX_PKT_LEN); + +	rxwi = (__le32 *)(entry->skb->data + RXINFO_DESC_SIZE); + +	/* +	 * FIXME : we need to check for rx_pkt_len validity +	 */ +	rxd = (__le32 *)(entry->skb->data + RXINFO_DESC_SIZE + rx_pkt_len);  	/*  	 * Copy descriptor to the skbdesc->desc buffer, making it safe from  	 * moving of frame data in rt2x00usb.  	 */ -	memcpy(skbdesc->desc, rxd, skbdesc->desc_len); -	rxd = (__le32 *)skbdesc->desc; -	rxwi = &rxd[RXINFO_DESC_SIZE / sizeof(__le32)]; +	memcpy(skbdesc->desc, rxi, skbdesc->desc_len);  	/*  	 * It is now safe to read the descriptor on all architectures.  	 */ -	rt2x00_desc_read(rxd, 0, &rxd0);  	rt2x00_desc_read(rxwi, 0, &rxwi0);  	rt2x00_desc_read(rxwi, 1, &rxwi1);  	rt2x00_desc_read(rxwi, 2, &rxwi2);  	rt2x00_desc_read(rxwi, 3, &rxwi3); +	rt2x00_desc_read(rxd, 0, &rxd0); -	if (rt2x00_get_field32(rxd0, RXINFO_W0_CRC_ERROR)) +	if (rt2x00_get_field32(rxd0, RXD_W0_CRC_ERROR))  		rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;  	if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) {  		rxdesc->cipher = rt2x00_get_field32(rxwi0, RXWI_W0_UDF);  		rxdesc->cipher_status = -		    rt2x00_get_field32(rxd0, RXINFO_W0_CIPHER_ERROR); +		    rt2x00_get_field32(rxd0, RXD_W0_CIPHER_ERROR);  	} -	if (rt2x00_get_field32(rxd0, RXINFO_W0_DECRYPTED)) { +	if (rt2x00_get_field32(rxd0, RXD_W0_DECRYPTED)) {  		/*  		 * Hardware has stripped IV/EIV data from 802.11 frame during  		 * decryption. Unfortunately the descriptor doesn't contain @@ -622,13 +636,11 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry,  			rxdesc->flags |= RX_FLAG_MMIC_ERROR;  	} -	if (rt2x00_get_field32(rxd0, RXINFO_W0_MY_BSS)) +	if (rt2x00_get_field32(rxd0, RXD_W0_MY_BSS))  		rxdesc->dev_flags |= RXDONE_MY_BSS; -	if (rt2x00_get_field32(rxd0, RXINFO_W0_L2PAD)) { +	if (rt2x00_get_field32(rxd0, RXD_W0_L2PAD))  		rxdesc->dev_flags |= RXDONE_L2PAD; -		skbdesc->flags |= SKBDESC_L2_PADDED; -	}  	if (rt2x00_get_field32(rxwi1, RXWI_W1_SHORT_GI))  		rxdesc->flags |= RX_FLAG_SHORT_GI; @@ -663,7 +675,6 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry,  	 * Remove RXWI descriptor from start of buffer.  	 */  	skb_pull(entry->skb, skbdesc->desc_len); -	skb_trim(entry->skb, rxdesc->size);  }  /* diff --git a/drivers/net/wireless/rt2x00/rt2800usb.h b/drivers/net/wireless/rt2x00/rt2800usb.h index 1e4340a182ef..d1d8ae94b4d4 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.h +++ b/drivers/net/wireless/rt2x00/rt2800usb.h @@ -79,6 +79,8 @@   */  #define TXINFO_DESC_SIZE		( 1 * sizeof(__le32) )  #define RXINFO_DESC_SIZE		( 1 * sizeof(__le32) ) +#define RXWI_DESC_SIZE			( 4 * sizeof(__le32) ) +#define RXD_DESC_SIZE			( 1 * sizeof(__le32) )  /*   * TX Info structure @@ -101,6 +103,54 @@  #define TXINFO_W0_USB_DMA_TX_BURST	FIELD32(0x80000000)  /* + * RX Info structure + */ + +/* + * Word 0 + */ + +#define RXINFO_W0_USB_DMA_RX_PKT_LEN	FIELD32(0x0000ffff) + +/* + * RX WI structure + */ + +/* + * Word0 + */ +#define RXWI_W0_WIRELESS_CLI_ID		FIELD32(0x000000ff) +#define RXWI_W0_KEY_INDEX		FIELD32(0x00000300) +#define RXWI_W0_BSSID			FIELD32(0x00001c00) +#define RXWI_W0_UDF			FIELD32(0x0000e000) +#define RXWI_W0_MPDU_TOTAL_BYTE_COUNT	FIELD32(0x0fff0000) +#define RXWI_W0_TID			FIELD32(0xf0000000) + +/* + * Word1 + */ +#define RXWI_W1_FRAG			FIELD32(0x0000000f) +#define RXWI_W1_SEQUENCE		FIELD32(0x0000fff0) +#define RXWI_W1_MCS			FIELD32(0x007f0000) +#define RXWI_W1_BW			FIELD32(0x00800000) +#define RXWI_W1_SHORT_GI		FIELD32(0x01000000) +#define RXWI_W1_STBC			FIELD32(0x06000000) +#define RXWI_W1_PHYMODE			FIELD32(0xc0000000) + +/* + * Word2 + */ +#define RXWI_W2_RSSI0			FIELD32(0x000000ff) +#define RXWI_W2_RSSI1			FIELD32(0x0000ff00) +#define RXWI_W2_RSSI2			FIELD32(0x00ff0000) + +/* + * Word3 + */ +#define RXWI_W3_SNR0			FIELD32(0x000000ff) +#define RXWI_W3_SNR1			FIELD32(0x0000ff00) + +/*   * RX descriptor format for RX Ring.   */ @@ -115,25 +165,25 @@   * AMSDU: rx with 802.3 header, not 802.11 header.   */ -#define RXINFO_W0_BA			FIELD32(0x00000001) -#define RXINFO_W0_DATA			FIELD32(0x00000002) -#define RXINFO_W0_NULLDATA		FIELD32(0x00000004) -#define RXINFO_W0_FRAG			FIELD32(0x00000008) -#define RXINFO_W0_UNICAST_TO_ME		FIELD32(0x00000010) -#define RXINFO_W0_MULTICAST		FIELD32(0x00000020) -#define RXINFO_W0_BROADCAST		FIELD32(0x00000040) -#define RXINFO_W0_MY_BSS		FIELD32(0x00000080) -#define RXINFO_W0_CRC_ERROR		FIELD32(0x00000100) -#define RXINFO_W0_CIPHER_ERROR		FIELD32(0x00000600) -#define RXINFO_W0_AMSDU			FIELD32(0x00000800) -#define RXINFO_W0_HTC			FIELD32(0x00001000) -#define RXINFO_W0_RSSI			FIELD32(0x00002000) -#define RXINFO_W0_L2PAD			FIELD32(0x00004000) -#define RXINFO_W0_AMPDU			FIELD32(0x00008000) -#define RXINFO_W0_DECRYPTED		FIELD32(0x00010000) -#define RXINFO_W0_PLCP_RSSI		FIELD32(0x00020000) -#define RXINFO_W0_CIPHER_ALG		FIELD32(0x00040000) -#define RXINFO_W0_LAST_AMSDU		FIELD32(0x00080000) -#define RXINFO_W0_PLCP_SIGNAL		FIELD32(0xfff00000) +#define RXD_W0_BA			FIELD32(0x00000001) +#define RXD_W0_DATA			FIELD32(0x00000002) +#define RXD_W0_NULLDATA			FIELD32(0x00000004) +#define RXD_W0_FRAG			FIELD32(0x00000008) +#define RXD_W0_UNICAST_TO_ME		FIELD32(0x00000010) +#define RXD_W0_MULTICAST		FIELD32(0x00000020) +#define RXD_W0_BROADCAST		FIELD32(0x00000040) +#define RXD_W0_MY_BSS			FIELD32(0x00000080) +#define RXD_W0_CRC_ERROR		FIELD32(0x00000100) +#define RXD_W0_CIPHER_ERROR		FIELD32(0x00000600) +#define RXD_W0_AMSDU			FIELD32(0x00000800) +#define RXD_W0_HTC			FIELD32(0x00001000) +#define RXD_W0_RSSI			FIELD32(0x00002000) +#define RXD_W0_L2PAD			FIELD32(0x00004000) +#define RXD_W0_AMPDU			FIELD32(0x00008000) +#define RXD_W0_DECRYPTED		FIELD32(0x00010000) +#define RXD_W0_PLCP_RSSI		FIELD32(0x00020000) +#define RXD_W0_CIPHER_ALG		FIELD32(0x00040000) +#define RXD_W0_LAST_AMSDU		FIELD32(0x00080000) +#define RXD_W0_PLCP_SIGNAL		FIELD32(0xfff00000)  #endif /* RT2800USB_H */ diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 4d841c07c970..194dae01d0c3 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -104,6 +104,12 @@  #define GET_DURATION_RES(__size, __rate)(((__size) * 8 * 10) % (__rate))  /* + * Determine the number of L2 padding bytes required between the header and + * the payload. + */ +#define L2PAD_SIZE(__hdrlen)	(-(__hdrlen) & 3) + +/*   * Determine the alignment requirement,   * to make sure the 802.11 payload is padded to a 4-byte boundrary   * we must determine the address of the payload and calculate the diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 06c43ca39bf8..d7711e4d4751 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -385,9 +385,6 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,  	memset(&rxdesc, 0, sizeof(rxdesc));  	rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc); -	/* Trim buffer to correct size */ -	skb_trim(entry->skb, rxdesc.size); -  	/*  	 * The data behind the ieee80211 header must be  	 * aligned on a 4 byte boundary. @@ -404,11 +401,16 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,  	    (rxdesc.flags & RX_FLAG_IV_STRIPPED))  		rt2x00crypto_rx_insert_iv(entry->skb, header_length,  					  &rxdesc); -	else if (rxdesc.dev_flags & RXDONE_L2PAD) +	else if (header_length && +		 (rxdesc.size > header_length) && +		 (rxdesc.dev_flags & RXDONE_L2PAD))  		rt2x00queue_remove_l2pad(entry->skb, header_length);  	else  		rt2x00queue_align_payload(entry->skb, header_length); +	/* Trim buffer to correct size */ +	skb_trim(entry->skb, rxdesc.size); +  	/*  	 * Check if the frame was received using HT. In that case,  	 * the rate is the MCS index and should be passed to mac80211 diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index 0feb4d0e4668..801be436cf1d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -41,6 +41,9 @@ int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev,  {  	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)) diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 239afc7a9c0b..3d8fb684b4eb 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -177,55 +177,45 @@ void rt2x00queue_align_payload(struct sk_buff *skb, unsigned int header_length)  void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length)  { -	struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); -	unsigned int frame_length = skb->len; +	unsigned int payload_length = skb->len - header_length;  	unsigned int header_align = ALIGN_SIZE(skb, 0);  	unsigned int payload_align = ALIGN_SIZE(skb, header_length); -	unsigned int l2pad = 4 - (payload_align - header_align); +	unsigned int l2pad = payload_length ? L2PAD_SIZE(header_length) : 0; -	if (header_align == payload_align) { -		/* -		 * Both header and payload must be moved the same -		 * amount of bytes to align them properly. This means -		 * we don't use the L2 padding but just move the entire -		 * frame. -		 */ -		rt2x00queue_align_frame(skb); -	} else if (!payload_align) { -		/* -		 * Simple L2 padding, only the header needs to be moved, -		 * the payload is already properly aligned. -		 */ -		skb_push(skb, header_align); -		memmove(skb->data, skb->data + header_align, frame_length); -		skbdesc->flags |= SKBDESC_L2_PADDED; -	} else { -		/* -		 * -		 * Complicated L2 padding, both header and payload need -		 * to be moved. By default we only move to the start -		 * of the buffer, so our header alignment needs to be -		 * increased if there is not enough room for the header -		 * to be moved. -		 */ -		if (payload_align > header_align) -			header_align += 4; +	/* +	 * Adjust the header alignment if the payload needs to be moved more +	 * than the header. +	 */ +	if (payload_align > header_align) +		header_align += 4; + +	/* There is nothing to do if no alignment is needed */ +	if (!header_align) +		return; + +	/* Reserve the amount of space needed in front of the frame */ +	skb_push(skb, header_align); + +	/* +	 * Move the header. +	 */ +	memmove(skb->data, skb->data + header_align, header_length); -		skb_push(skb, header_align); -		memmove(skb->data, skb->data + header_align, header_length); +	/* Move the payload, if present and if required */ +	if (payload_length && payload_align)  		memmove(skb->data + header_length + l2pad,  			skb->data + header_length + l2pad + payload_align, -			frame_length - header_length); -		skbdesc->flags |= SKBDESC_L2_PADDED; -	} +			payload_length); + +	/* Trim the skb to the correct size */ +	skb_trim(skb, header_length + l2pad + payload_length);  }  void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int header_length)  { -	struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); -	unsigned int l2pad = 4 - (header_length & 3); +	unsigned int l2pad = L2PAD_SIZE(header_length); -	if (!l2pad || (skbdesc->flags & SKBDESC_L2_PADDED)) +	if (!l2pad)  		return;  	memmove(skb->data + l2pad, skb->data, header_length); @@ -346,7 +336,9 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,  	 * Header and alignment information.  	 */  	txdesc->header_length = ieee80211_get_hdrlen_from_skb(entry->skb); -	txdesc->l2pad = ALIGN_SIZE(entry->skb, txdesc->header_length); +	if (test_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags) && +	    (entry->skb->len > txdesc->header_length)) +		txdesc->l2pad = L2PAD_SIZE(txdesc->header_length);  	/*  	 * Check whether this frame is to be acked. @@ -387,10 +379,13 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,  	/*  	 * Beacons and probe responses require the tsf timestamp -	 * to be inserted into the frame. +	 * to be inserted into the frame, except for a frame that has been injected +	 * through a monitor interface. This latter is needed for testing a +	 * monitor interface.  	 */ -	if (ieee80211_is_beacon(hdr->frame_control) || -	    ieee80211_is_probe_resp(hdr->frame_control)) +	if ((ieee80211_is_beacon(hdr->frame_control) || +	    ieee80211_is_probe_resp(hdr->frame_control)) && +	    (!(tx_info->flags & IEEE80211_TX_CTL_INJECTED)))  		__set_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags);  	/* diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 70775e5ba1ac..c1e482bb37b3 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -92,8 +92,6 @@ enum data_queue_qid {   * @SKBDESC_DMA_MAPPED_TX: &skb_dma field has been mapped for TX   * @SKBDESC_IV_STRIPPED: Frame contained a IV/EIV provided by   *	mac80211 but was stripped for processing by the driver. - * @SKBDESC_L2_PADDED: Payload has been padded for 4-byte alignment, - *	the padded bytes are located between header and payload.   * @SKBDESC_NOT_MAC80211: Frame didn't originate from mac80211,   *	don't try to pass it back.   */ @@ -101,8 +99,7 @@ enum skb_frame_desc_flags {  	SKBDESC_DMA_MAPPED_RX = 1 << 0,  	SKBDESC_DMA_MAPPED_TX = 1 << 1,  	SKBDESC_IV_STRIPPED = 1 << 2, -	SKBDESC_L2_PADDED = 1 << 3, -	SKBDESC_NOT_MAC80211 = 1 << 4, +	SKBDESC_NOT_MAC80211 = 1 << 3,  };  /** diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index ced3b6ab5e16..6ce88d3c3b65 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -2354,6 +2354,7 @@ static struct usb_device_id rt73usb_device_table[] = {  	{ USB_DEVICE(0x08dd, 0x0120), USB_DEVICE_DATA(&rt73usb_ops) },  	/* Buffalo */  	{ USB_DEVICE(0x0411, 0x00d8), USB_DEVICE_DATA(&rt73usb_ops) }, +	{ USB_DEVICE(0x0411, 0x00d9), USB_DEVICE_DATA(&rt73usb_ops) },  	{ USB_DEVICE(0x0411, 0x00f4), USB_DEVICE_DATA(&rt73usb_ops) },  	{ USB_DEVICE(0x0411, 0x0116), USB_DEVICE_DATA(&rt73usb_ops) },  	{ USB_DEVICE(0x0411, 0x0119), USB_DEVICE_DATA(&rt73usb_ops) }, diff --git a/drivers/net/wireless/rtl818x/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c index a1a3dd15c664..8a40a1439984 100644 --- a/drivers/net/wireless/rtl818x/rtl8180_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c @@ -132,7 +132,6 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev)  			rx_status.antenna = (flags2 >> 15) & 1;  			/* TODO: improve signal/rssi reporting */ -			rx_status.qual = flags2 & 0xFF;  			rx_status.signal = (flags2 >> 8) & 0x7F;  			/* XXX: is this correct? */  			rx_status.rate_idx = (flags >> 20) & 0xF; diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h index 054533f7a124..6301578d1565 100644 --- a/drivers/net/wireless/wl12xx/wl1251.h +++ b/drivers/net/wireless/wl12xx/wl1251.h @@ -247,6 +247,7 @@ struct wl1251_debugfs {  	struct dentry *rxpipe_tx_xfr_host_int_trig_rx_data;  	struct dentry *tx_queue_len; +	struct dentry *tx_queue_status;  	struct dentry *retry_count;  	struct dentry *excessive_retries; diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.c b/drivers/net/wireless/wl12xx/wl1251_acx.c index acfa086dbfc5..beff084040b5 100644 --- a/drivers/net/wireless/wl12xx/wl1251_acx.c +++ b/drivers/net/wireless/wl12xx/wl1251_acx.c @@ -976,3 +976,72 @@ out:  	kfree(acx);  	return ret;  } + +int wl1251_acx_ac_cfg(struct wl1251 *wl, u8 ac, u8 cw_min, u16 cw_max, +		      u8 aifs, u16 txop) +{ +	struct wl1251_acx_ac_cfg *acx; +	int ret = 0; + +	wl1251_debug(DEBUG_ACX, "acx ac cfg %d cw_ming %d cw_max %d " +		     "aifs %d txop %d", ac, cw_min, cw_max, aifs, txop); + +	acx = kzalloc(sizeof(*acx), GFP_KERNEL); + +	if (!acx) { +		ret = -ENOMEM; +		goto out; +	} + +	acx->ac = ac; +	acx->cw_min = cw_min; +	acx->cw_max = cw_max; +	acx->aifsn = aifs; +	acx->txop_limit = txop; + +	ret = wl1251_cmd_configure(wl, ACX_AC_CFG, acx, sizeof(*acx)); +	if (ret < 0) { +		wl1251_warning("acx ac cfg failed: %d", ret); +		goto out; +	} + +out: +	kfree(acx); +	return ret; +} + +int wl1251_acx_tid_cfg(struct wl1251 *wl, u8 queue, +		       enum wl1251_acx_channel_type type, +		       u8 tsid, enum wl1251_acx_ps_scheme ps_scheme, +		       enum wl1251_acx_ack_policy ack_policy) +{ +	struct wl1251_acx_tid_cfg *acx; +	int ret = 0; + +	wl1251_debug(DEBUG_ACX, "acx tid cfg %d type %d tsid %d " +		     "ps_scheme %d ack_policy %d", queue, type, tsid, +		     ps_scheme, ack_policy); + +	acx = kzalloc(sizeof(*acx), GFP_KERNEL); + +	if (!acx) { +		ret = -ENOMEM; +		goto out; +	} + +	acx->queue = queue; +	acx->type = type; +	acx->tsid = tsid; +	acx->ps_scheme = ps_scheme; +	acx->ack_policy = ack_policy; + +	ret = wl1251_cmd_configure(wl, ACX_TID_CFG, acx, sizeof(*acx)); +	if (ret < 0) { +		wl1251_warning("acx tid cfg failed: %d", ret); +		goto out; +	} + +out: +	kfree(acx); +	return ret; +} diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.h b/drivers/net/wireless/wl12xx/wl1251_acx.h index 652371432cd8..26160c45784c 100644 --- a/drivers/net/wireless/wl12xx/wl1251_acx.h +++ b/drivers/net/wireless/wl12xx/wl1251_acx.h @@ -1166,6 +1166,87 @@ struct wl1251_acx_wr_tbtt_and_dtim {  	u8  padding;  } __attribute__ ((packed)); +struct wl1251_acx_ac_cfg { +	struct acx_header header; + +	/* +	 * Access Category - The TX queue's access category +	 * (refer to AccessCategory_enum) +	 */ +	u8 ac; + +	/* +	 * The contention window minimum size (in slots) for +	 * the access class. +	 */ +	u8 cw_min; + +	/* +	 * The contention window maximum size (in slots) for +	 * the access class. +	 */ +	u16 cw_max; + +	/* The AIF value (in slots) for the access class. */ +	u8 aifsn; + +	u8 reserved; + +	/* The TX Op Limit (in microseconds) for the access class. */ +	u16 txop_limit; +} __attribute__ ((packed)); + + +enum wl1251_acx_channel_type { +	CHANNEL_TYPE_DCF	= 0, +	CHANNEL_TYPE_EDCF	= 1, +	CHANNEL_TYPE_HCCA	= 2, +}; + +enum wl1251_acx_ps_scheme { +	/* regular ps: simple sending of packets */ +	WL1251_ACX_PS_SCHEME_LEGACY	= 0, + +	/* sending a packet triggers a unscheduled apsd downstream */ +	WL1251_ACX_PS_SCHEME_UPSD_TRIGGER	= 1, + +	/* a pspoll packet will be sent before every data packet */ +	WL1251_ACX_PS_SCHEME_LEGACY_PSPOLL	= 2, + +	/* scheduled apsd mode */ +	WL1251_ACX_PS_SCHEME_SAPSD		= 3, +}; + +enum wl1251_acx_ack_policy { +	WL1251_ACX_ACK_POLICY_LEGACY	= 0, +	WL1251_ACX_ACK_POLICY_NO_ACK	= 1, +	WL1251_ACX_ACK_POLICY_BLOCK	= 2, +}; + +struct wl1251_acx_tid_cfg { +	struct acx_header header; + +	/* tx queue id number (0-7) */ +	u8 queue; + +	/* channel access type for the queue, enum wl1251_acx_channel_type */ +	u8 type; + +	/* EDCA: ac index (0-3), HCCA: traffic stream id (8-15) */ +	u8 tsid; + +	/* ps scheme of the specified queue, enum wl1251_acx_ps_scheme */ +	u8 ps_scheme; + +	/* the tx queue ack policy, enum wl1251_acx_ack_policy */ +	u8 ack_policy; + +	u8 padding[3]; + +	/* not supported */ +	u32 apsdconf[2]; +} __attribute__ ((packed)); +  /*************************************************************************      Host Interrupt Register (WiLink -> Host) @@ -1322,5 +1403,11 @@ int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime);  int wl1251_acx_rate_policies(struct wl1251 *wl);  int wl1251_acx_mem_cfg(struct wl1251 *wl);  int wl1251_acx_wr_tbtt_and_dtim(struct wl1251 *wl, u16 tbtt, u8 dtim); +int wl1251_acx_ac_cfg(struct wl1251 *wl, u8 ac, u8 cw_min, u16 cw_max, +		      u8 aifs, u16 txop); +int wl1251_acx_tid_cfg(struct wl1251 *wl, u8 queue, +		       enum wl1251_acx_channel_type type, +		       u8 tsid, enum wl1251_acx_ps_scheme ps_scheme, +		       enum wl1251_acx_ack_policy ack_policy);  #endif /* __WL1251_ACX_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1251_debugfs.c b/drivers/net/wireless/wl12xx/wl1251_debugfs.c index a00723059f83..0ccba57fb9fb 100644 --- a/drivers/net/wireless/wl12xx/wl1251_debugfs.c +++ b/drivers/net/wireless/wl12xx/wl1251_debugfs.c @@ -237,6 +237,27 @@ static const struct file_operations tx_queue_len_ops = {  	.open = wl1251_open_file_generic,  }; +static ssize_t tx_queue_status_read(struct file *file, char __user *userbuf, +				    size_t count, loff_t *ppos) +{ +	struct wl1251 *wl = file->private_data; +	char buf[3], status; +	int len; + +	if (wl->tx_queue_stopped) +		status = 's'; +	else +		status = 'r'; + +	len = scnprintf(buf, sizeof(buf), "%c\n", status); +	return simple_read_from_buffer(userbuf, count, ppos, buf, len); +} + +static const struct file_operations tx_queue_status_ops = { +	.read = tx_queue_status_read, +	.open = wl1251_open_file_generic, +}; +  static void wl1251_debugfs_delete_files(struct wl1251 *wl)  {  	DEBUGFS_FWSTATS_DEL(tx, internal_desc_overflow); @@ -331,6 +352,7 @@ static void wl1251_debugfs_delete_files(struct wl1251 *wl)  	DEBUGFS_FWSTATS_DEL(rxpipe, tx_xfr_host_int_trig_rx_data);  	DEBUGFS_DEL(tx_queue_len); +	DEBUGFS_DEL(tx_queue_status);  	DEBUGFS_DEL(retry_count);  	DEBUGFS_DEL(excessive_retries);  } @@ -431,6 +453,7 @@ static int wl1251_debugfs_add_files(struct wl1251 *wl)  	DEBUGFS_FWSTATS_ADD(rxpipe, tx_xfr_host_int_trig_rx_data);  	DEBUGFS_ADD(tx_queue_len, wl->debugfs.rootdir); +	DEBUGFS_ADD(tx_queue_status, wl->debugfs.rootdir);  	DEBUGFS_ADD(retry_count, wl->debugfs.rootdir);  	DEBUGFS_ADD(excessive_retries, wl->debugfs.rootdir); diff --git a/drivers/net/wireless/wl12xx/wl1251_init.c b/drivers/net/wireless/wl12xx/wl1251_init.c index 5cb573383eeb..5aad56ea7153 100644 --- a/drivers/net/wireless/wl12xx/wl1251_init.c +++ b/drivers/net/wireless/wl12xx/wl1251_init.c @@ -294,6 +294,11 @@ static int wl1251_hw_init_tx_queue_config(struct wl1251 *wl)  			goto out;  	} +	wl1251_acx_ac_cfg(wl, AC_BE, CWMIN_BE, CWMAX_BE, AIFS_DIFS, TXOP_BE); +	wl1251_acx_ac_cfg(wl, AC_BK, CWMIN_BK, CWMAX_BK, AIFS_DIFS, TXOP_BK); +	wl1251_acx_ac_cfg(wl, AC_VI, CWMIN_VI, CWMAX_VI, AIFS_DIFS, TXOP_VI); +	wl1251_acx_ac_cfg(wl, AC_VO, CWMIN_VO, CWMAX_VO, AIFS_DIFS, TXOP_VO); +  out:  	kfree(config);  	return ret; diff --git a/drivers/net/wireless/wl12xx/wl1251_init.h b/drivers/net/wireless/wl12xx/wl1251_init.h index b3b25ec885ea..269cefb3e7d4 100644 --- a/drivers/net/wireless/wl12xx/wl1251_init.h +++ b/drivers/net/wireless/wl12xx/wl1251_init.h @@ -26,6 +26,53 @@  #include "wl1251.h" +enum { +	/* best effort/legacy */ +	AC_BE = 0, + +	/* background */ +	AC_BK = 1, + +	/* video */ +	AC_VI = 2, + +	/* voice */ +	AC_VO = 3, + +	/* broadcast dummy access category */ +	AC_BCAST = 4, + +	NUM_ACCESS_CATEGORIES = 4 +}; + +/* following are defult values for the IE fields*/ +#define CWMIN_BK  15 +#define CWMIN_BE  15 +#define CWMIN_VI  7 +#define CWMIN_VO  3 +#define CWMAX_BK  1023 +#define CWMAX_BE  63 +#define CWMAX_VI  15 +#define CWMAX_VO  7 + +/* slot number setting to start transmission at PIFS interval */ +#define AIFS_PIFS 1 + +/* + * slot number setting to start transmission at DIFS interval - normal DCF + * access + */ +#define AIFS_DIFS 2 + +#define AIFSN_BK  7 +#define AIFSN_BE  3 +#define AIFSN_VI  AIFS_PIFS +#define AIFSN_VO  AIFS_PIFS +#define TXOP_BK   0 +#define TXOP_BE   0 +#define TXOP_VI   3008 +#define TXOP_VO   1504 +  int wl1251_hw_init_hwenc_config(struct wl1251 *wl);  int wl1251_hw_init_templates_config(struct wl1251 *wl);  int wl1251_hw_init_rx_config(struct wl1251 *wl, u32 config, u32 filter); diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 2f50a256efa5..6aeffbe9e401 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -395,6 +395,7 @@ static int wl1251_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)  	 * the queue here, otherwise the queue will get too long.  	 */  	if (skb_queue_len(&wl->tx_queue) >= WL1251_TX_QUEUE_MAX_LENGTH) { +		wl1251_debug(DEBUG_TX, "op_tx: tx_queue full, stop queues");  		ieee80211_stop_queues(wl->hw);  		/* @@ -640,20 +641,25 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)  		 * through the bss_info_changed() hook.  		 */  		ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE); +		if (ret < 0) +			goto out_sleep;  	} else if (!(conf->flags & IEEE80211_CONF_PS) &&  		   wl->psm_requested) {  		wl1251_debug(DEBUG_PSM, "psm disabled");  		wl->psm_requested = false; -		if (wl->psm) +		if (wl->psm) {  			ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE); +			if (ret < 0) +				goto out_sleep; +		}  	}  	if (conf->power_level != wl->power_level) {  		ret = wl1251_acx_tx_power(wl, conf->power_level);  		if (ret < 0) -			goto out; +			goto out_sleep;  		wl->power_level = conf->power_level;  	} @@ -1273,6 +1279,43 @@ static struct ieee80211_channel wl1251_channels[] = {  	{ .hw_value = 13, .center_freq = 2472},  }; +static int wl1251_op_conf_tx(struct ieee80211_hw *hw, u16 queue, +			     const struct ieee80211_tx_queue_params *params) +{ +	struct wl1251 *wl = hw->priv; +	int ret; + +	mutex_lock(&wl->mutex); + +	wl1251_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue); + +	ret = wl1251_ps_elp_wakeup(wl); +	if (ret < 0) +		goto out; + +	ret = wl1251_acx_ac_cfg(wl, wl1251_tx_get_queue(queue), +				params->cw_min, params->cw_max, +				params->aifs, params->txop); +	if (ret < 0) +		goto out_sleep; + +	ret = wl1251_acx_tid_cfg(wl, wl1251_tx_get_queue(queue), +				 CHANNEL_TYPE_EDCF, +				 wl1251_tx_get_queue(queue), +				 WL1251_ACX_PS_SCHEME_LEGACY, +				 WL1251_ACX_ACK_POLICY_LEGACY); +	if (ret < 0) +		goto out_sleep; + +out_sleep: +	wl1251_ps_elp_sleep(wl); + +out: +	mutex_unlock(&wl->mutex); + +	return ret; +} +  /* can't be const, mac80211 writes to this */  static struct ieee80211_supported_band wl1251_band_2ghz = {  	.channels = wl1251_channels, @@ -1293,6 +1336,7 @@ static const struct ieee80211_ops wl1251_ops = {  	.hw_scan = wl1251_op_hw_scan,  	.bss_info_changed = wl1251_op_bss_info_changed,  	.set_rts_threshold = wl1251_op_set_rts_threshold, +	.conf_tx = wl1251_op_conf_tx,  };  static int wl1251_register_hw(struct wl1251 *wl) @@ -1338,6 +1382,8 @@ int wl1251_init_ieee80211(struct wl1251 *wl)  	wl->hw->wiphy->max_scan_ssids = 1;  	wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1251_band_2ghz; +	wl->hw->queues = 4; +  	ret = wl1251_register_hw(wl);  	if (ret)  		goto out; diff --git a/drivers/net/wireless/wl12xx/wl1251_ps.c b/drivers/net/wireless/wl12xx/wl1251_ps.c index 9931b197ff77..851dfb65e474 100644 --- a/drivers/net/wireless/wl12xx/wl1251_ps.c +++ b/drivers/net/wireless/wl12xx/wl1251_ps.c @@ -26,7 +26,8 @@  #include "wl1251_cmd.h"  #include "wl1251_io.h" -#define WL1251_WAKEUP_TIMEOUT 2000 +/* in ms */ +#define WL1251_WAKEUP_TIMEOUT 100  void wl1251_elp_work(struct work_struct *work)  { @@ -67,7 +68,7 @@ void wl1251_ps_elp_sleep(struct wl1251 *wl)  int wl1251_ps_elp_wakeup(struct wl1251 *wl)  { -	unsigned long timeout; +	unsigned long timeout, start;  	u32 elp_reg;  	if (!wl->elp) @@ -75,6 +76,7 @@ int wl1251_ps_elp_wakeup(struct wl1251 *wl)  	wl1251_debug(DEBUG_PSM, "waking up chip from elp"); +	start = jiffies;  	timeout = jiffies + msecs_to_jiffies(WL1251_WAKEUP_TIMEOUT);  	wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP); @@ -95,8 +97,7 @@ int wl1251_ps_elp_wakeup(struct wl1251 *wl)  	}  	wl1251_debug(DEBUG_PSM, "wakeup time: %u ms", -		     jiffies_to_msecs(jiffies) - -		     (jiffies_to_msecs(timeout) - WL1251_WAKEUP_TIMEOUT)); +		     jiffies_to_msecs(jiffies - start));  	wl->elp = false; diff --git a/drivers/net/wireless/wl12xx/wl1251_rx.c b/drivers/net/wireless/wl12xx/wl1251_rx.c index f84cc89cbffc..b56732226cc0 100644 --- a/drivers/net/wireless/wl12xx/wl1251_rx.c +++ b/drivers/net/wireless/wl12xx/wl1251_rx.c @@ -126,7 +126,7 @@ static void wl1251_rx_body(struct wl1251 *wl,  	if (wl->rx_current_buffer)  		rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size; -	skb = dev_alloc_skb(length); +	skb = __dev_alloc_skb(length, GFP_KERNEL);  	if (!skb) {  		wl1251_error("Couldn't allocate RX frame");  		return; diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.c b/drivers/net/wireless/wl12xx/wl1251_tx.c index f85970615849..c8223185efd2 100644 --- a/drivers/net/wireless/wl12xx/wl1251_tx.c +++ b/drivers/net/wireless/wl12xx/wl1251_tx.c @@ -167,8 +167,7 @@ static int wl1251_tx_fill_hdr(struct wl1251 *wl, struct sk_buff *skb,  	tx_hdr->expiry_time = cpu_to_le32(1 << 16);  	tx_hdr->id = id; -	/* FIXME: how to get the correct queue id? */ -	tx_hdr->xmit_queue = 0; +	tx_hdr->xmit_queue = wl1251_tx_get_queue(skb_get_queue_mapping(skb));  	wl1251_tx_control(tx_hdr, control, fc);  	wl1251_tx_frag_block_num(tx_hdr); @@ -220,6 +219,7 @@ static int wl1251_tx_send_packet(struct wl1251 *wl, struct sk_buff *skb,  			/* align the buffer on a 4-byte boundary */  			skb_reserve(skb, offset);  			memmove(skb->data, src, skb->len); +			tx_hdr = (struct tx_double_buffer_desc *) skb->data;  		} else {  			wl1251_info("No handler, fixme!");  			return -EINVAL; @@ -237,8 +237,9 @@ static int wl1251_tx_send_packet(struct wl1251 *wl, struct sk_buff *skb,  	wl1251_mem_write(wl, addr, skb->data, len); -	wl1251_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x", -		     tx_hdr->id, skb, tx_hdr->length, tx_hdr->rate); +	wl1251_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x " +		     "queue %d", tx_hdr->id, skb, tx_hdr->length, +		     tx_hdr->rate, tx_hdr->xmit_queue);  	return 0;  } diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.h b/drivers/net/wireless/wl12xx/wl1251_tx.h index 7c1c1665c810..55856c6bb97a 100644 --- a/drivers/net/wireless/wl12xx/wl1251_tx.h +++ b/drivers/net/wireless/wl12xx/wl1251_tx.h @@ -26,6 +26,7 @@  #define __WL1251_TX_H__  #include <linux/bitops.h> +#include "wl1251_acx.h"  /*   * @@ -209,6 +210,22 @@ struct tx_result {  	u8 done_2;  } __attribute__ ((packed)); +static inline int wl1251_tx_get_queue(int queue) +{ +	switch (queue) { +	case 0: +		return QOS_AC_VO; +	case 1: +		return QOS_AC_VI; +	case 2: +		return QOS_AC_BE; +	case 3: +		return QOS_AC_BK; +	default: +		return QOS_AC_BE; +	} +} +  void wl1251_tx_work(struct work_struct *work);  void wl1251_tx_complete(struct wl1251 *wl);  void wl1251_tx_flush(struct wl1251 *wl); diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index ac19ecd19cfe..4daf1c94ec04 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -1078,11 +1078,15 @@ static int eject_installer(struct usb_interface *intf)  	int r;  	/* Find bulk out endpoint */ -	endpoint = &iface_desc->endpoint[1].desc; -	if (usb_endpoint_dir_out(endpoint) && -	    usb_endpoint_xfer_bulk(endpoint)) { -		bulk_out_ep = endpoint->bEndpointAddress; -	} else { +	for (r = 1; r >= 0; r--) { +		endpoint = &iface_desc->endpoint[r].desc; +		if (usb_endpoint_dir_out(endpoint) && +		    usb_endpoint_xfer_bulk(endpoint)) { +			bulk_out_ep = endpoint->bEndpointAddress; +			break; +		} +	} +	if (r == -1) {  		dev_err(&udev->dev,  			"zd1211rw: Could not find bulk out endpoint\n");  		return -ENODEV; | 
