diff options
Diffstat (limited to 'drivers/net/wireless')
47 files changed, 1199 insertions, 1088 deletions
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 53295418f57..6125adb520a 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -4506,108 +4506,75 @@ static int setup_proc_entry( struct net_device *dev,  	apriv->proc_entry = proc_mkdir_mode(apriv->proc_name, airo_perm,  					    airo_entry);  	if (!apriv->proc_entry) -		goto fail; -	apriv->proc_entry->uid = proc_kuid; -	apriv->proc_entry->gid = proc_kgid; +		return -ENOMEM; +	proc_set_user(apriv->proc_entry, proc_kuid, proc_kgid);  	/* Setup the StatsDelta */  	entry = proc_create_data("StatsDelta", S_IRUGO & proc_perm,  				 apriv->proc_entry, &proc_statsdelta_ops, dev);  	if (!entry) -		goto fail_stats_delta; -	entry->uid = proc_kuid; -	entry->gid = proc_kgid; +		goto fail; +	proc_set_user(entry, proc_kuid, proc_kgid);  	/* Setup the Stats */  	entry = proc_create_data("Stats", S_IRUGO & proc_perm,  				 apriv->proc_entry, &proc_stats_ops, dev);  	if (!entry) -		goto fail_stats; -	entry->uid = proc_kuid; -	entry->gid = proc_kgid; +		goto fail; +	proc_set_user(entry, proc_kuid, proc_kgid);  	/* Setup the Status */  	entry = proc_create_data("Status", S_IRUGO & proc_perm,  				 apriv->proc_entry, &proc_status_ops, dev);  	if (!entry) -		goto fail_status; -	entry->uid = proc_kuid; -	entry->gid = proc_kgid; +		goto fail; +	proc_set_user(entry, proc_kuid, proc_kgid);  	/* Setup the Config */  	entry = proc_create_data("Config", proc_perm,  				 apriv->proc_entry, &proc_config_ops, dev);  	if (!entry) -		goto fail_config; -	entry->uid = proc_kuid; -	entry->gid = proc_kgid; +		goto fail; +	proc_set_user(entry, proc_kuid, proc_kgid);  	/* Setup the SSID */  	entry = proc_create_data("SSID", proc_perm,  				 apriv->proc_entry, &proc_SSID_ops, dev);  	if (!entry) -		goto fail_ssid; -	entry->uid = proc_kuid; -	entry->gid = proc_kgid; +		goto fail; +	proc_set_user(entry, proc_kuid, proc_kgid);  	/* Setup the APList */  	entry = proc_create_data("APList", proc_perm,  				 apriv->proc_entry, &proc_APList_ops, dev);  	if (!entry) -		goto fail_aplist; -	entry->uid = proc_kuid; -	entry->gid = proc_kgid; +		goto fail; +	proc_set_user(entry, proc_kuid, proc_kgid);  	/* Setup the BSSList */  	entry = proc_create_data("BSSList", proc_perm,  				 apriv->proc_entry, &proc_BSSList_ops, dev);  	if (!entry) -		goto fail_bsslist; -	entry->uid = proc_kuid; -	entry->gid = proc_kgid; +		goto fail; +	proc_set_user(entry, proc_kuid, proc_kgid);  	/* Setup the WepKey */  	entry = proc_create_data("WepKey", proc_perm,  				 apriv->proc_entry, &proc_wepkey_ops, dev);  	if (!entry) -		goto fail_wepkey; -	entry->uid = proc_kuid; -	entry->gid = proc_kgid; - +		goto fail; +	proc_set_user(entry, proc_kuid, proc_kgid);  	return 0; -fail_wepkey: -	remove_proc_entry("BSSList", apriv->proc_entry); -fail_bsslist: -	remove_proc_entry("APList", apriv->proc_entry); -fail_aplist: -	remove_proc_entry("SSID", apriv->proc_entry); -fail_ssid: -	remove_proc_entry("Config", apriv->proc_entry); -fail_config: -	remove_proc_entry("Status", apriv->proc_entry); -fail_status: -	remove_proc_entry("Stats", apriv->proc_entry); -fail_stats: -	remove_proc_entry("StatsDelta", apriv->proc_entry); -fail_stats_delta: -	remove_proc_entry(apriv->proc_name, airo_entry);  fail: +	remove_proc_subtree(apriv->proc_name, airo_entry);  	return -ENOMEM;  }  static int takedown_proc_entry( struct net_device *dev, -				struct airo_info *apriv ) { -	if ( !apriv->proc_entry->namelen ) return 0; -	remove_proc_entry("Stats",apriv->proc_entry); -	remove_proc_entry("StatsDelta",apriv->proc_entry); -	remove_proc_entry("Status",apriv->proc_entry); -	remove_proc_entry("Config",apriv->proc_entry); -	remove_proc_entry("SSID",apriv->proc_entry); -	remove_proc_entry("APList",apriv->proc_entry); -	remove_proc_entry("BSSList",apriv->proc_entry); -	remove_proc_entry("WepKey",apriv->proc_entry); -	remove_proc_entry(apriv->proc_name,airo_entry); +				struct airo_info *apriv ) +{ +	remove_proc_subtree(apriv->proc_name, airo_entry);  	return 0;  } @@ -4663,8 +4630,7 @@ static ssize_t proc_write( struct file *file,  static int proc_status_open(struct inode *inode, struct file *file)  {  	struct proc_data *data; -	struct proc_dir_entry *dp = PDE(inode); -	struct net_device *dev = dp->data; +	struct net_device *dev = PDE_DATA(inode);  	struct airo_info *apriv = dev->ml_priv;  	CapabilityRid cap_rid;  	StatusRid status_rid; @@ -4746,8 +4712,7 @@ static int proc_stats_rid_open( struct inode *inode,  				u16 rid )  {  	struct proc_data *data; -	struct proc_dir_entry *dp = PDE(inode); -	struct net_device *dev = dp->data; +	struct net_device *dev = PDE_DATA(inode);  	struct airo_info *apriv = dev->ml_priv;  	StatsRid stats;  	int i, j; @@ -4809,8 +4774,7 @@ static inline int sniffing_mode(struct airo_info *ai)  static void proc_config_on_close(struct inode *inode, struct file *file)  {  	struct proc_data *data = file->private_data; -	struct proc_dir_entry *dp = PDE(inode); -	struct net_device *dev = dp->data; +	struct net_device *dev = PDE_DATA(inode);  	struct airo_info *ai = dev->ml_priv;  	char *line; @@ -5021,8 +4985,7 @@ static const char *get_rmode(__le16 mode)  static int proc_config_open(struct inode *inode, struct file *file)  {  	struct proc_data *data; -	struct proc_dir_entry *dp = PDE(inode); -	struct net_device *dev = dp->data; +	struct net_device *dev = PDE_DATA(inode);  	struct airo_info *ai = dev->ml_priv;  	int i;  	__le16 mode; @@ -5112,8 +5075,7 @@ static int proc_config_open(struct inode *inode, struct file *file)  static void proc_SSID_on_close(struct inode *inode, struct file *file)  {  	struct proc_data *data = file->private_data; -	struct proc_dir_entry *dp = PDE(inode); -	struct net_device *dev = dp->data; +	struct net_device *dev = PDE_DATA(inode);  	struct airo_info *ai = dev->ml_priv;  	SsidRid SSID_rid;  	int i; @@ -5148,8 +5110,7 @@ static void proc_SSID_on_close(struct inode *inode, struct file *file)  static void proc_APList_on_close( struct inode *inode, struct file *file ) {  	struct proc_data *data = file->private_data; -	struct proc_dir_entry *dp = PDE(inode); -	struct net_device *dev = dp->data; +	struct net_device *dev = PDE_DATA(inode);  	struct airo_info *ai = dev->ml_priv;  	APListRid APList_rid;  	int i; @@ -5283,8 +5244,7 @@ static int set_wep_tx_idx(struct airo_info *ai, u16 index, int perm, int lock)  static void proc_wepkey_on_close( struct inode *inode, struct file *file ) {  	struct proc_data *data; -	struct proc_dir_entry *dp = PDE(inode); -	struct net_device *dev = dp->data; +	struct net_device *dev = PDE_DATA(inode);  	struct airo_info *ai = dev->ml_priv;  	int i, rc;  	char key[16]; @@ -5335,8 +5295,7 @@ static void proc_wepkey_on_close( struct inode *inode, struct file *file ) {  static int proc_wepkey_open( struct inode *inode, struct file *file )  {  	struct proc_data *data; -	struct proc_dir_entry *dp = PDE(inode); -	struct net_device *dev = dp->data; +	struct net_device *dev = PDE_DATA(inode);  	struct airo_info *ai = dev->ml_priv;  	char *ptr;  	WepKeyRid wkr; @@ -5384,8 +5343,7 @@ static int proc_wepkey_open( struct inode *inode, struct file *file )  static int proc_SSID_open(struct inode *inode, struct file *file)  {  	struct proc_data *data; -	struct proc_dir_entry *dp = PDE(inode); -	struct net_device *dev = dp->data; +	struct net_device *dev = PDE_DATA(inode);  	struct airo_info *ai = dev->ml_priv;  	int i;  	char *ptr; @@ -5428,8 +5386,7 @@ static int proc_SSID_open(struct inode *inode, struct file *file)  static int proc_APList_open( struct inode *inode, struct file *file ) {  	struct proc_data *data; -	struct proc_dir_entry *dp = PDE(inode); -	struct net_device *dev = dp->data; +	struct net_device *dev = PDE_DATA(inode);  	struct airo_info *ai = dev->ml_priv;  	int i;  	char *ptr; @@ -5468,8 +5425,7 @@ static int proc_APList_open( struct inode *inode, struct file *file ) {  static int proc_BSSList_open( struct inode *inode, struct file *file ) {  	struct proc_data *data; -	struct proc_dir_entry *dp = PDE(inode); -	struct net_device *dev = dp->data; +	struct net_device *dev = PDE_DATA(inode);  	struct airo_info *ai = dev->ml_priv;  	char *ptr;  	BSSListRid BSSList_rid; @@ -5706,10 +5662,8 @@ static int __init airo_init_module( void )  	airo_entry = proc_mkdir_mode("driver/aironet", airo_perm, NULL); -	if (airo_entry) { -		airo_entry->uid = proc_kuid; -		airo_entry->gid = proc_kgid; -	} +	if (airo_entry) +		proc_set_user(airo_entry, proc_kuid, proc_kgid);  	for (i = 0; i < 4 && io[i] && irq[i]; i++) {  		airo_print_info("", "Trying to configure ISA adapter at irq=%d " diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index 4cc13940c89..f76c3ca07a4 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -1023,6 +1023,7 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,  					  AR_PHY_AGC_CONTROL_FLTR_CAL   |  					  AR_PHY_AGC_CONTROL_PKDET_CAL; +	/* Use chip chainmask only for calibration */  	ar9003_hw_set_chain_masks(ah, ah->caps.rx_chainmask, ah->caps.tx_chainmask);  	if (rtt) { @@ -1150,6 +1151,9 @@ skip_tx_iqcal:  		ar9003_hw_rtt_disable(ah);  	} +	/* Revert chainmask to runtime parameters */ +	ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask); +  	/* Initialize list pointers */  	ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h index 5f845beeb18..050ca4a4850 100644 --- a/drivers/net/wireless/ath/ath9k/common.h +++ b/drivers/net/wireless/ath/ath9k/common.h @@ -27,7 +27,7 @@  #define WME_MAX_BA              WME_BA_BMP_SIZE  #define ATH_TID_MAX_BUFS        (2 * WME_MAX_BA) -#define ATH_RSSI_DUMMY_MARKER   0x127 +#define ATH_RSSI_DUMMY_MARKER   127  #define ATH_RSSI_LPF_LEN 		10  #define RSSI_LPF_THRESHOLD		-20  #define ATH_RSSI_EP_MULTIPLIER     (1<<7) diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 96bfb18078f..d3b099d7898 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -22,6 +22,7 @@  #include <linux/firmware.h>  #include <linux/skbuff.h>  #include <linux/netdevice.h> +#include <linux/etherdevice.h>  #include <linux/leds.h>  #include <linux/slab.h>  #include <net/mac80211.h> diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index 3ad1fd05c5e..bd8251c1c74 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -1067,15 +1067,19 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,  	last_rssi = priv->rx.last_rssi; -	if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER)) -		rxbuf->rxstatus.rs_rssi = ATH_EP_RND(last_rssi, -						     ATH_RSSI_EP_MULTIPLIER); +	if (ieee80211_is_beacon(hdr->frame_control) && +	    !is_zero_ether_addr(common->curbssid) && +	    ether_addr_equal(hdr->addr3, common->curbssid)) { +		s8 rssi = rxbuf->rxstatus.rs_rssi; -	if (rxbuf->rxstatus.rs_rssi < 0) -		rxbuf->rxstatus.rs_rssi = 0; +		if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER)) +			rssi = ATH_EP_RND(last_rssi, ATH_RSSI_EP_MULTIPLIER); -	if (ieee80211_is_beacon(fc)) -		priv->ah->stats.avgbrssi = rxbuf->rxstatus.rs_rssi; +		if (rssi < 0) +			rssi = 0; + +		priv->ah->stats.avgbrssi = rssi; +	}  	rx_status->mactime = be64_to_cpu(rxbuf->rxstatus.rs_tstamp);  	rx_status->band = hw->conf.channel->band; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 2a2ae403e0e..07e25260c31 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1463,7 +1463,9 @@ static bool ath9k_hw_chip_reset(struct ath_hw *ah,  			reset_type = ATH9K_RESET_POWER_ON;  		else  			reset_type = ATH9K_RESET_COLD; -	} +	} else if (ah->chip_fullsleep || REG_READ(ah, AR_Q_TXE) || +		   (REG_READ(ah, AR_CR) & AR_CR_RXE)) +		reset_type = ATH9K_RESET_COLD;  	if (!ath9k_hw_set_reset_reg(ah, reset_type))  		return false; diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c index ade3afb21f9..39c84ecf6a4 100644 --- a/drivers/net/wireless/ath/ath9k/link.c +++ b/drivers/net/wireless/ath/ath9k/link.c @@ -28,21 +28,21 @@ void ath_tx_complete_poll_work(struct work_struct *work)  	int i;  	bool needreset = false; -	for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) -		if (ATH_TXQ_SETUP(sc, i)) { -			txq = &sc->tx.txq[i]; -			ath_txq_lock(sc, txq); -			if (txq->axq_depth) { -				if (txq->axq_tx_inprogress) { -					needreset = true; -					ath_txq_unlock(sc, txq); -					break; -				} else { -					txq->axq_tx_inprogress = true; -				} +	for (i = 0; i < IEEE80211_NUM_ACS; i++) { +		txq = sc->tx.txq_map[i]; + +		ath_txq_lock(sc, txq); +		if (txq->axq_depth) { +			if (txq->axq_tx_inprogress) { +				needreset = true; +				ath_txq_unlock(sc, txq); +				break; +			} else { +				txq->axq_tx_inprogress = true;  			} -			ath_txq_unlock_complete(sc, txq);  		} +		ath_txq_unlock_complete(sc, txq); +	}  	if (needreset) {  		ath_dbg(ath9k_hw_common(sc->sc_ah), RESET, diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 65fc9683bfd..76c7694518d 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -216,7 +216,7 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32, wil_debugfs_iomem_x32_get,  			wil_debugfs_iomem_x32_set, "0x%08llx\n");  static struct dentry *wil_debugfs_create_iomem_x32(const char *name, -						   mode_t mode, +						   umode_t mode,  						   struct dentry *parent,  						   void __iomem *value)  { @@ -367,7 +367,7 @@ static const struct file_operations fops_ioblob = {  static  struct dentry *wil_debugfs_create_ioblob(const char *name, -					 mode_t mode, +					 umode_t mode,  					 struct dentry *parent,  					 struct debugfs_blob_wrapper *blob)  { diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index 4374079dfc2..23a3498f14d 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -63,6 +63,7 @@  #include <net/iw_handler.h>  #include <linux/crc32.h>  #include <linux/proc_fs.h> +#include <linux/seq_file.h>  #include <linux/device.h>  #include <linux/moduleparam.h>  #include <linux/firmware.h> @@ -1409,30 +1410,28 @@ static int atmel_validate_channel(struct atmel_private *priv, int channel)  	return 0;  } -static int atmel_proc_output (char *buf, struct atmel_private *priv) +static int atmel_proc_show(struct seq_file *m, void *v)  { +	struct atmel_private *priv = m->private;  	int i; -	char *p = buf;  	char *s, *r, *c; -	p += sprintf(p, "Driver version:\t\t%d.%d\n", -		     DRIVER_MAJOR, DRIVER_MINOR); +	seq_printf(m, "Driver version:\t\t%d.%d\n", DRIVER_MAJOR, DRIVER_MINOR);  	if (priv->station_state != STATION_STATE_DOWN) { -		p += sprintf(p, "Firmware version:\t%d.%d build %d\n" -				"Firmware location:\t", -			     priv->host_info.major_version, -			     priv->host_info.minor_version, -			     priv->host_info.build_version); +		seq_printf(m, +			   "Firmware version:\t%d.%d build %d\n" +			   "Firmware location:\t", +			   priv->host_info.major_version, +			   priv->host_info.minor_version, +			   priv->host_info.build_version);  		if (priv->card_type != CARD_TYPE_EEPROM) -			p += sprintf(p, "on card\n"); +			seq_puts(m, "on card\n");  		else if (priv->firmware) -			p += sprintf(p, "%s loaded by host\n", -				     priv->firmware_id); +			seq_printf(m, "%s loaded by host\n", priv->firmware_id);  		else -			p += sprintf(p, "%s loaded by hotplug\n", -				     priv->firmware_id); +			seq_printf(m, "%s loaded by hotplug\n", priv->firmware_id);  		switch (priv->card_type) {  		case CARD_TYPE_PARALLEL_FLASH: @@ -1453,12 +1452,12 @@ static int atmel_proc_output (char *buf, struct atmel_private *priv)  			if (priv->reg_domain == channel_table[i].reg_domain)  				r = channel_table[i].name; -		p += sprintf(p, "MAC memory type:\t%s\n", c); -		p += sprintf(p, "Regulatory domain:\t%s\n", r); -		p += sprintf(p, "Host CRC checking:\t%s\n", -			     priv->do_rx_crc ? "On" : "Off"); -		p += sprintf(p, "WPA-capable firmware:\t%s\n", -			     priv->use_wpa ? "Yes" : "No"); +		seq_printf(m, "MAC memory type:\t%s\n", c); +		seq_printf(m, "Regulatory domain:\t%s\n", r); +		seq_printf(m, "Host CRC checking:\t%s\n", +			 priv->do_rx_crc ? "On" : "Off"); +		seq_printf(m, "WPA-capable firmware:\t%s\n", +			 priv->use_wpa ? "Yes" : "No");  	}  	switch (priv->station_state) { @@ -1490,26 +1489,22 @@ static int atmel_proc_output (char *buf, struct atmel_private *priv)  		s = "<unknown>";  	} -	p += sprintf(p, "Current state:\t\t%s\n", s); -	return p - buf; +	seq_printf(m, "Current state:\t\t%s\n", s); +	return 0;  } -static int atmel_read_proc(char *page, char **start, off_t off, -			   int count, int *eof, void *data) +static int atmel_proc_open(struct inode *inode, struct file *file)  { -	struct atmel_private *priv = data; -	int len = atmel_proc_output (page, priv); -	if (len <= off+count) -		*eof = 1; -	*start = page + off; -	len -= off; -	if (len > count) -		len = count; -	if (len < 0) -		len = 0; -	return len; +	return single_open(file, atmel_proc_show, PDE_DATA(inode));  } +static const struct file_operations atmel_proc_fops = { +	.open		= atmel_proc_open, +	.read		= seq_read, +	.llseek		= seq_lseek, +	.release	= seq_release, +}; +  static const struct net_device_ops atmel_netdev_ops = {  	.ndo_open 		= atmel_open,  	.ndo_stop		= atmel_close, @@ -1525,7 +1520,6 @@ struct net_device *init_atmel_card(unsigned short irq, unsigned long port,  				   struct device *sys_dev,  				   int (*card_present)(void *), void *card)  { -	struct proc_dir_entry *ent;  	struct net_device *dev;  	struct atmel_private *priv;  	int rc; @@ -1630,8 +1624,7 @@ struct net_device *init_atmel_card(unsigned short irq, unsigned long port,  	netif_carrier_off(dev); -	ent = create_proc_read_entry ("driver/atmel", 0, NULL, atmel_read_proc, priv); -	if (!ent) +	if (!proc_create_data("driver/atmel", 0, NULL, &atmel_proc_fops, priv));  		printk(KERN_WARNING "atmel: unable to create /proc entry.\n");  	printk(KERN_INFO "%s: Atmel at76c50x. Version %d.%d. MAC %pM\n", diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c index dd9a18f8dbc..19c45e363aa 100644 --- a/drivers/net/wireless/hostap/hostap_ap.c +++ b/drivers/net/wireless/hostap/hostap_ap.c @@ -17,6 +17,7 @@   */  #include <linux/proc_fs.h> +#include <linux/seq_file.h>  #include <linux/delay.h>  #include <linux/random.h>  #include <linux/if_arp.h> @@ -64,28 +65,32 @@ static void prism2_send_mgmt(struct net_device *dev,  #ifndef PRISM2_NO_PROCFS_DEBUG -static int ap_debug_proc_read(char *page, char **start, off_t off, -			      int count, int *eof, void *data) +static int ap_debug_proc_show(struct seq_file *m, void *v)  { -	char *p = page; -	struct ap_data *ap = (struct ap_data *) data; +	struct ap_data *ap = m->private; -	if (off != 0) { -		*eof = 1; -		return 0; -	} - -	p += sprintf(p, "BridgedUnicastFrames=%u\n", ap->bridged_unicast); -	p += sprintf(p, "BridgedMulticastFrames=%u\n", ap->bridged_multicast); -	p += sprintf(p, "max_inactivity=%u\n", ap->max_inactivity / HZ); -	p += sprintf(p, "bridge_packets=%u\n", ap->bridge_packets); -	p += sprintf(p, "nullfunc_ack=%u\n", ap->nullfunc_ack); -	p += sprintf(p, "autom_ap_wds=%u\n", ap->autom_ap_wds); -	p += sprintf(p, "auth_algs=%u\n", ap->local->auth_algs); -	p += sprintf(p, "tx_drop_nonassoc=%u\n", ap->tx_drop_nonassoc); +	seq_printf(m, "BridgedUnicastFrames=%u\n", ap->bridged_unicast); +	seq_printf(m, "BridgedMulticastFrames=%u\n", ap->bridged_multicast); +	seq_printf(m, "max_inactivity=%u\n", ap->max_inactivity / HZ); +	seq_printf(m, "bridge_packets=%u\n", ap->bridge_packets); +	seq_printf(m, "nullfunc_ack=%u\n", ap->nullfunc_ack); +	seq_printf(m, "autom_ap_wds=%u\n", ap->autom_ap_wds); +	seq_printf(m, "auth_algs=%u\n", ap->local->auth_algs); +	seq_printf(m, "tx_drop_nonassoc=%u\n", ap->tx_drop_nonassoc); +	return 0; +} -	return (p - page); +static int ap_debug_proc_open(struct inode *inode, struct file *file) +{ +	return single_open(file, ap_debug_proc_show, PDE_DATA(inode));  } + +static const struct file_operations ap_debug_proc_fops = { +	.open		= ap_debug_proc_open, +	.read		= seq_read, +	.llseek		= seq_lseek, +	.release	= seq_release, +};  #endif /* PRISM2_NO_PROCFS_DEBUG */ @@ -325,50 +330,81 @@ void hostap_deauth_all_stas(struct net_device *dev, struct ap_data *ap,  } -static int ap_control_proc_read(char *page, char **start, off_t off, -				int count, int *eof, void *data) +static int ap_control_proc_show(struct seq_file *m, void *v)  { -	char *p = page; -	struct ap_data *ap = (struct ap_data *) data; +	struct ap_data *ap = m->private;  	char *policy_txt;  	struct mac_entry *entry; -	if (off != 0) { -		*eof = 1; +	if (v == SEQ_START_TOKEN) { +		switch (ap->mac_restrictions.policy) { +		case MAC_POLICY_OPEN: +			policy_txt = "open"; +			break; +		case MAC_POLICY_ALLOW: +			policy_txt = "allow"; +			break; +		case MAC_POLICY_DENY: +			policy_txt = "deny"; +			break; +		default: +			policy_txt = "unknown"; +			break; +		} +		seq_printf(m, "MAC policy: %s\n", policy_txt); +		seq_printf(m, "MAC entries: %u\n", ap->mac_restrictions.entries); +		seq_puts(m, "MAC list:\n");  		return 0;  	} -	switch (ap->mac_restrictions.policy) { -	case MAC_POLICY_OPEN: -		policy_txt = "open"; -		break; -	case MAC_POLICY_ALLOW: -		policy_txt = "allow"; -		break; -	case MAC_POLICY_DENY: -		policy_txt = "deny"; -		break; -	default: -		policy_txt = "unknown"; -		break; -	} -	p += sprintf(p, "MAC policy: %s\n", policy_txt); -	p += sprintf(p, "MAC entries: %u\n", ap->mac_restrictions.entries); -	p += sprintf(p, "MAC list:\n"); +	entry = v; +	seq_printf(m, "%pM\n", entry->addr); +	return 0; +} + +static void *ap_control_proc_start(struct seq_file *m, loff_t *_pos) +{ +	struct ap_data *ap = m->private;  	spin_lock_bh(&ap->mac_restrictions.lock); -	list_for_each_entry(entry, &ap->mac_restrictions.mac_list, list) { -		if (p - page > PAGE_SIZE - 80) { -			p += sprintf(p, "All entries did not fit one page.\n"); -			break; -		} +	return seq_list_start_head(&ap->mac_restrictions.mac_list, *_pos); +} -		p += sprintf(p, "%pM\n", entry->addr); -	} +static void *ap_control_proc_next(struct seq_file *m, void *v, loff_t *_pos) +{ +	struct ap_data *ap = m->private; +	return seq_list_next(v, &ap->mac_restrictions.mac_list, _pos); +} + +static void ap_control_proc_stop(struct seq_file *m, void *v) +{ +	struct ap_data *ap = m->private;  	spin_unlock_bh(&ap->mac_restrictions.lock); +} + +static const struct seq_operations ap_control_proc_seqops = { +	.start	= ap_control_proc_start, +	.next	= ap_control_proc_next, +	.stop	= ap_control_proc_stop, +	.show	= ap_control_proc_show, +}; -	return (p - page); +static int ap_control_proc_open(struct inode *inode, struct file *file) +{ +	int ret = seq_open(file, &ap_control_proc_seqops); +	if (ret == 0) { +		struct seq_file *m = file->private_data; +		m->private = PDE_DATA(inode); +	} +	return ret;  } +static const struct file_operations ap_control_proc_fops = { +	.open		= ap_control_proc_open, +	.read		= seq_read, +	.llseek		= seq_lseek, +	.release	= seq_release, +}; +  int ap_control_add_mac(struct mac_restrictions *mac_restrictions, u8 *mac)  { @@ -510,61 +546,84 @@ void ap_control_kickall(struct ap_data *ap)  #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT -#define PROC_LIMIT (PAGE_SIZE - 80) - -static int prism2_ap_proc_read(char *page, char **start, off_t off, -			       int count, int *eof, void *data) +static int prism2_ap_proc_show(struct seq_file *m, void *v)  { -	char *p = page; -	struct ap_data *ap = (struct ap_data *) data; -	struct sta_info *sta; +	struct sta_info *sta = v;  	int i; -	if (off > PROC_LIMIT) { -		*eof = 1; +	if (v == SEQ_START_TOKEN) { +		seq_printf(m, "# BSSID CHAN SIGNAL NOISE RATE SSID FLAGS\n");  		return 0;  	} -	p += sprintf(p, "# BSSID CHAN SIGNAL NOISE RATE SSID FLAGS\n"); -	spin_lock_bh(&ap->sta_table_lock); -	list_for_each_entry(sta, &ap->sta_list, list) { -		if (!sta->ap) -			continue; +	if (!sta->ap) +		return 0; -		p += sprintf(p, "%pM %d %d %d %d '", -			     sta->addr, -			     sta->u.ap.channel, sta->last_rx_signal, -			     sta->last_rx_silence, sta->last_rx_rate); -		for (i = 0; i < sta->u.ap.ssid_len; i++) -			p += sprintf(p, ((sta->u.ap.ssid[i] >= 32 && -					  sta->u.ap.ssid[i] < 127) ? -					 "%c" : "<%02x>"), -				     sta->u.ap.ssid[i]); -		p += sprintf(p, "'"); -		if (sta->capability & WLAN_CAPABILITY_ESS) -			p += sprintf(p, " [ESS]"); -		if (sta->capability & WLAN_CAPABILITY_IBSS) -			p += sprintf(p, " [IBSS]"); -		if (sta->capability & WLAN_CAPABILITY_PRIVACY) -			p += sprintf(p, " [WEP]"); -		p += sprintf(p, "\n"); +	seq_printf(m, "%pM %d %d %d %d '", +		   sta->addr, +		   sta->u.ap.channel, sta->last_rx_signal, +		   sta->last_rx_silence, sta->last_rx_rate); -		if ((p - page) > PROC_LIMIT) { -			printk(KERN_DEBUG "hostap: ap proc did not fit\n"); -			break; -		} +	for (i = 0; i < sta->u.ap.ssid_len; i++) { +		if (sta->u.ap.ssid[i] >= 32 && sta->u.ap.ssid[i] < 127) +			seq_putc(m, sta->u.ap.ssid[i]); +		else +			seq_printf(m, "<%02x>", sta->u.ap.ssid[i]);  	} -	spin_unlock_bh(&ap->sta_table_lock); -	if ((p - page) <= off) { -		*eof = 1; -		return 0; -	} +	seq_putc(m, '\''); +	if (sta->capability & WLAN_CAPABILITY_ESS) +		seq_puts(m, " [ESS]"); +	if (sta->capability & WLAN_CAPABILITY_IBSS) +		seq_puts(m, " [IBSS]"); +	if (sta->capability & WLAN_CAPABILITY_PRIVACY) +		seq_puts(m, " [WEP]"); +	seq_putc(m, '\n'); +	return 0; +} -	*start = page + off; +static void *prism2_ap_proc_start(struct seq_file *m, loff_t *_pos) +{ +	struct ap_data *ap = m->private; +	spin_lock_bh(&ap->sta_table_lock); +	return seq_list_start_head(&ap->sta_list, *_pos); +} -	return (p - page - off); +static void *prism2_ap_proc_next(struct seq_file *m, void *v, loff_t *_pos) +{ +	struct ap_data *ap = m->private; +	return seq_list_next(v, &ap->sta_list, _pos);  } + +static void prism2_ap_proc_stop(struct seq_file *m, void *v) +{ +	struct ap_data *ap = m->private; +	spin_unlock_bh(&ap->sta_table_lock); +} + +static const struct seq_operations prism2_ap_proc_seqops = { +	.start	= prism2_ap_proc_start, +	.next	= prism2_ap_proc_next, +	.stop	= prism2_ap_proc_stop, +	.show	= prism2_ap_proc_show, +}; + +static int prism2_ap_proc_open(struct inode *inode, struct file *file) +{ +	int ret = seq_open(file, &prism2_ap_proc_seqops); +	if (ret == 0) { +		struct seq_file *m = file->private_data; +		m->private = PDE_DATA(inode); +	} +	return ret; +} + +static const struct file_operations prism2_ap_proc_fops = { +	.open		= prism2_ap_proc_open, +	.read		= seq_read, +	.llseek		= seq_lseek, +	.release	= seq_release, +};  #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ @@ -836,15 +895,12 @@ void hostap_init_ap_proc(local_info_t *local)  		return;  #ifndef PRISM2_NO_PROCFS_DEBUG -	create_proc_read_entry("ap_debug", 0, ap->proc, -			       ap_debug_proc_read, ap); +	proc_create_data("ap_debug", 0, ap->proc, &ap_debug_proc_fops, ap);  #endif /* PRISM2_NO_PROCFS_DEBUG */  #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT -	create_proc_read_entry("ap_control", 0, ap->proc, -			       ap_control_proc_read, ap); -	create_proc_read_entry("ap", 0, ap->proc, -			       prism2_ap_proc_read, ap); +	proc_create_data("ap_control", 0, ap->proc, &ap_control_proc_fops, ap); +	proc_create_data("ap", 0, ap->proc, &prism2_ap_proc_fops, ap);  #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */  } @@ -982,79 +1038,86 @@ static void prism2_send_mgmt(struct net_device *dev,  #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ -static int prism2_sta_proc_read(char *page, char **start, off_t off, -				int count, int *eof, void *data) +static int prism2_sta_proc_show(struct seq_file *m, void *v)  { -	char *p = page; -	struct sta_info *sta = (struct sta_info *) data; +	struct sta_info *sta = m->private;  	int i;  	/* FIX: possible race condition.. the STA data could have just expired,  	 * but proc entry was still here so that the read could have started;  	 * some locking should be done here.. */ -	if (off != 0) { -		*eof = 1; -		return 0; -	} - -	p += sprintf(p, "%s=%pM\nusers=%d\naid=%d\n" -		     "flags=0x%04x%s%s%s%s%s%s%s\n" -		     "capability=0x%02x\nlisten_interval=%d\nsupported_rates=", -		     sta->ap ? "AP" : "STA", -		     sta->addr, atomic_read(&sta->users), sta->aid, -		     sta->flags, -		     sta->flags & WLAN_STA_AUTH ? " AUTH" : "", -		     sta->flags & WLAN_STA_ASSOC ? " ASSOC" : "", -		     sta->flags & WLAN_STA_PS ? " PS" : "", -		     sta->flags & WLAN_STA_TIM ? " TIM" : "", -		     sta->flags & WLAN_STA_PERM ? " PERM" : "", -		     sta->flags & WLAN_STA_AUTHORIZED ? " AUTHORIZED" : "", -		     sta->flags & WLAN_STA_PENDING_POLL ? " POLL" : "", -		     sta->capability, sta->listen_interval); +	seq_printf(m, +		   "%s=%pM\nusers=%d\naid=%d\n" +		   "flags=0x%04x%s%s%s%s%s%s%s\n" +		   "capability=0x%02x\nlisten_interval=%d\nsupported_rates=", +		   sta->ap ? "AP" : "STA", +		   sta->addr, atomic_read(&sta->users), sta->aid, +		   sta->flags, +		   sta->flags & WLAN_STA_AUTH ? " AUTH" : "", +		   sta->flags & WLAN_STA_ASSOC ? " ASSOC" : "", +		   sta->flags & WLAN_STA_PS ? " PS" : "", +		   sta->flags & WLAN_STA_TIM ? " TIM" : "", +		   sta->flags & WLAN_STA_PERM ? " PERM" : "", +		   sta->flags & WLAN_STA_AUTHORIZED ? " AUTHORIZED" : "", +		   sta->flags & WLAN_STA_PENDING_POLL ? " POLL" : "", +		   sta->capability, sta->listen_interval);  	/* supported_rates: 500 kbit/s units with msb ignored */  	for (i = 0; i < sizeof(sta->supported_rates); i++)  		if (sta->supported_rates[i] != 0) -			p += sprintf(p, "%d%sMbps ", -				     (sta->supported_rates[i] & 0x7f) / 2, -				     sta->supported_rates[i] & 1 ? ".5" : ""); -	p += sprintf(p, "\njiffies=%lu\nlast_auth=%lu\nlast_assoc=%lu\n" -		     "last_rx=%lu\nlast_tx=%lu\nrx_packets=%lu\n" -		     "tx_packets=%lu\n" -		     "rx_bytes=%lu\ntx_bytes=%lu\nbuffer_count=%d\n" -		     "last_rx: silence=%d dBm signal=%d dBm rate=%d%s Mbps\n" -		     "tx_rate=%d\ntx[1M]=%d\ntx[2M]=%d\ntx[5.5M]=%d\n" -		     "tx[11M]=%d\n" -		     "rx[1M]=%d\nrx[2M]=%d\nrx[5.5M]=%d\nrx[11M]=%d\n", -		     jiffies, sta->last_auth, sta->last_assoc, sta->last_rx, -		     sta->last_tx, -		     sta->rx_packets, sta->tx_packets, sta->rx_bytes, -		     sta->tx_bytes, skb_queue_len(&sta->tx_buf), -		     sta->last_rx_silence, -		     sta->last_rx_signal, sta->last_rx_rate / 10, -		     sta->last_rx_rate % 10 ? ".5" : "", -		     sta->tx_rate, sta->tx_count[0], sta->tx_count[1], -		     sta->tx_count[2], sta->tx_count[3],  sta->rx_count[0], -		     sta->rx_count[1], sta->rx_count[2], sta->rx_count[3]); +			seq_printf(m, "%d%sMbps ", +				   (sta->supported_rates[i] & 0x7f) / 2, +				   sta->supported_rates[i] & 1 ? ".5" : ""); +	seq_printf(m, +		   "\njiffies=%lu\nlast_auth=%lu\nlast_assoc=%lu\n" +		   "last_rx=%lu\nlast_tx=%lu\nrx_packets=%lu\n" +		   "tx_packets=%lu\n" +		   "rx_bytes=%lu\ntx_bytes=%lu\nbuffer_count=%d\n" +		   "last_rx: silence=%d dBm signal=%d dBm rate=%d%s Mbps\n" +		   "tx_rate=%d\ntx[1M]=%d\ntx[2M]=%d\ntx[5.5M]=%d\n" +		   "tx[11M]=%d\n" +		   "rx[1M]=%d\nrx[2M]=%d\nrx[5.5M]=%d\nrx[11M]=%d\n", +		   jiffies, sta->last_auth, sta->last_assoc, sta->last_rx, +		   sta->last_tx, +		   sta->rx_packets, sta->tx_packets, sta->rx_bytes, +		   sta->tx_bytes, skb_queue_len(&sta->tx_buf), +		   sta->last_rx_silence, +		   sta->last_rx_signal, sta->last_rx_rate / 10, +		   sta->last_rx_rate % 10 ? ".5" : "", +		   sta->tx_rate, sta->tx_count[0], sta->tx_count[1], +		   sta->tx_count[2], sta->tx_count[3],  sta->rx_count[0], +		   sta->rx_count[1], sta->rx_count[2], sta->rx_count[3]);  	if (sta->crypt && sta->crypt->ops && sta->crypt->ops->print_stats) -		p = sta->crypt->ops->print_stats(p, sta->crypt->priv); +		sta->crypt->ops->print_stats(m, sta->crypt->priv);  #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT  	if (sta->ap) {  		if (sta->u.ap.channel >= 0) -			p += sprintf(p, "channel=%d\n", sta->u.ap.channel); -		p += sprintf(p, "ssid="); -		for (i = 0; i < sta->u.ap.ssid_len; i++) -			p += sprintf(p, ((sta->u.ap.ssid[i] >= 32 && -					  sta->u.ap.ssid[i] < 127) ? -					 "%c" : "<%02x>"), -				     sta->u.ap.ssid[i]); -		p += sprintf(p, "\n"); +			seq_printf(m, "channel=%d\n", sta->u.ap.channel); +		seq_puts(m, "ssid="); +		for (i = 0; i < sta->u.ap.ssid_len; i++) { +			if (sta->u.ap.ssid[i] >= 32 && sta->u.ap.ssid[i] < 127) +				seq_putc(m, sta->u.ap.ssid[i]); +			else +				seq_printf(m, "<%02x>", sta->u.ap.ssid[i]); +		} +		seq_putc(m, '\n');  	}  #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ -	return (p - page); +	return 0; +} + +static int prism2_sta_proc_open(struct inode *inode, struct file *file) +{ +	return single_open(file, prism2_sta_proc_show, PDE_DATA(inode));  } +static const struct file_operations prism2_sta_proc_fops = { +	.open		= prism2_sta_proc_open, +	.read		= seq_read, +	.llseek		= seq_lseek, +	.release	= seq_release, +};  static void handle_add_proc_queue(struct work_struct *work)  { @@ -1076,9 +1139,9 @@ static void handle_add_proc_queue(struct work_struct *work)  		if (sta) {  			sprintf(name, "%pM", sta->addr); -			sta->proc = create_proc_read_entry( +			sta->proc = proc_create_data(  				name, 0, ap->proc, -				prism2_sta_proc_read, sta); +				&prism2_sta_proc_fops, sta);  			atomic_dec(&sta->users);  		} diff --git a/drivers/net/wireless/hostap/hostap_download.c b/drivers/net/wireless/hostap/hostap_download.c index e73bf739fd9..705fe668b96 100644 --- a/drivers/net/wireless/hostap/hostap_download.c +++ b/drivers/net/wireless/hostap/hostap_download.c @@ -174,20 +174,70 @@ static int prism2_pda_ok(u8 *buf)  } -static int prism2_download_aux_dump(struct net_device *dev, -				     unsigned int addr, int len, u8 *buf) -{ -	int res; +#define prism2_download_aux_dump_npages 65536 -	prism2_enable_aux_port(dev, 1); -	res = hfa384x_from_aux(dev, addr, len, buf); -	prism2_enable_aux_port(dev, 0); -	if (res) -		return -1; +struct prism2_download_aux_dump { +	local_info_t *local; +	u16 page[0x80]; +}; + +static int prism2_download_aux_dump_proc_show(struct seq_file *m, void *v) +{ +	struct prism2_download_aux_dump *ctx = m->private; +	hfa384x_from_aux(ctx->local->dev, (unsigned long)v - 1, 0x80, ctx->page); +	seq_write(m, ctx->page, 0x80);  	return 0;  } +static void *prism2_download_aux_dump_proc_start(struct seq_file *m, loff_t *_pos) +{ +	struct prism2_download_aux_dump *ctx = m->private; +	prism2_enable_aux_port(ctx->local->dev, 1); +	if (*_pos >= prism2_download_aux_dump_npages) +		return NULL; +	return (void *)((unsigned long)*_pos + 1); +} + +static void *prism2_download_aux_dump_proc_next(struct seq_file *m, void *v, loff_t *_pos) +{ +	++*_pos; +	if (*_pos >= prism2_download_aux_dump_npages) +		return NULL; +	return (void *)((unsigned long)*_pos + 1); +} + +static void prism2_download_aux_dump_proc_stop(struct seq_file *m, void *v) +{ +	struct prism2_download_aux_dump *ctx = m->private; +	prism2_enable_aux_port(ctx->local->dev, 0); +} + +static const struct seq_operations prism2_download_aux_dump_proc_seqops = { +	.start	= prism2_download_aux_dump_proc_start, +	.next	= prism2_download_aux_dump_proc_next, +	.stop	= prism2_download_aux_dump_proc_stop, +	.show	= prism2_download_aux_dump_proc_show, +}; + +static int prism2_download_aux_dump_proc_open(struct inode *inode, struct file *file) +{ +	int ret = seq_open_private(file, &prism2_download_aux_dump_proc_seqops, +				   sizeof(struct prism2_download_aux_dump)); +	if (ret == 0) { +		struct seq_file *m = file->private_data; +		m->private = PDE_DATA(inode); +	} +	return ret; +} + +static const struct file_operations prism2_download_aux_dump_proc_fops = { +	.open		= prism2_download_aux_dump_proc_open, +	.read		= seq_read, +	.llseek		= seq_lseek, +	.release	= seq_release_private, +}; +  static u8 * prism2_read_pda(struct net_device *dev)  { diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c index 8e7000fd441..507ab99eef4 100644 --- a/drivers/net/wireless/hostap/hostap_hw.c +++ b/drivers/net/wireless/hostap/hostap_hw.c @@ -38,6 +38,7 @@  #include <linux/netdevice.h>  #include <linux/etherdevice.h>  #include <linux/proc_fs.h> +#include <linux/seq_file.h>  #include <linux/if_arp.h>  #include <linux/delay.h>  #include <linux/random.h> @@ -129,8 +130,7 @@ static void prism2_check_sta_fw_version(local_info_t *local);  #ifdef PRISM2_DOWNLOAD_SUPPORT  /* hostap_download.c */ -static int prism2_download_aux_dump(struct net_device *dev, -				    unsigned int addr, int len, u8 *buf); +static const struct file_operations prism2_download_aux_dump_proc_fops;  static u8 * prism2_read_pda(struct net_device *dev);  static int prism2_download(local_info_t *local,  			   struct prism2_download_param *param); @@ -2894,19 +2894,12 @@ static void hostap_tick_timer(unsigned long data)  #ifndef PRISM2_NO_PROCFS_DEBUG -static int prism2_registers_proc_read(char *page, char **start, off_t off, -				      int count, int *eof, void *data) +static int prism2_registers_proc_show(struct seq_file *m, void *v)  { -	char *p = page; -	local_info_t *local = (local_info_t *) data; - -	if (off != 0) { -		*eof = 1; -		return 0; -	} +	local_info_t *local = m->private;  #define SHOW_REG(n) \ -p += sprintf(p, #n "=%04x\n", hfa384x_read_reg(local->dev, HFA384X_##n##_OFF)) +  seq_printf(m, #n "=%04x\n", hfa384x_read_reg(local->dev, HFA384X_##n##_OFF))  	SHOW_REG(CMD);  	SHOW_REG(PARAM0); @@ -2952,8 +2945,21 @@ p += sprintf(p, #n "=%04x\n", hfa384x_read_reg(local->dev, HFA384X_##n##_OFF))  	SHOW_REG(PCI_M1_CTL);  #endif /* PRISM2_PCI */ -	return (p - page); +	return 0;  } + +static int prism2_registers_proc_open(struct inode *inode, struct file *file) +{ +	return single_open(file, prism2_registers_proc_show, PDE_DATA(inode)); +} + +static const struct file_operations prism2_registers_proc_fops = { +	.open		= prism2_registers_proc_open, +	.read		= seq_read, +	.llseek		= seq_lseek, +	.release	= seq_release, +}; +  #endif /* PRISM2_NO_PROCFS_DEBUG */ @@ -3128,7 +3134,7 @@ prism2_init_local_data(struct prism2_helper_functions *funcs, int card_idx,  	local->func->reset_port = prism2_reset_port;  	local->func->schedule_reset = prism2_schedule_reset;  #ifdef PRISM2_DOWNLOAD_SUPPORT -	local->func->read_aux = prism2_download_aux_dump; +	local->func->read_aux_fops = &prism2_download_aux_dump_proc_fops;  	local->func->download = prism2_download;  #endif /* PRISM2_DOWNLOAD_SUPPORT */  	local->func->tx = prism2_tx_80211; @@ -3274,8 +3280,8 @@ static int hostap_hw_ready(struct net_device *dev)  		}  		hostap_init_proc(local);  #ifndef PRISM2_NO_PROCFS_DEBUG -		create_proc_read_entry("registers", 0, local->proc, -				       prism2_registers_proc_read, local); +		proc_create_data("registers", 0, local->proc, +				 &prism2_registers_proc_fops, local);  #endif /* PRISM2_NO_PROCFS_DEBUG */  		hostap_init_ap_proc(local);  		return 0; diff --git a/drivers/net/wireless/hostap/hostap_proc.c b/drivers/net/wireless/hostap/hostap_proc.c index dc447c1b5ab..7491dab2c10 100644 --- a/drivers/net/wireless/hostap/hostap_proc.c +++ b/drivers/net/wireless/hostap/hostap_proc.c @@ -12,259 +12,297 @@  #ifndef PRISM2_NO_PROCFS_DEBUG -static int prism2_debug_proc_read(char *page, char **start, off_t off, -				  int count, int *eof, void *data) +static int prism2_debug_proc_show(struct seq_file *m, void *v)  { -	char *p = page; -	local_info_t *local = (local_info_t *) data; +	local_info_t *local = m->private;  	int i; -	if (off != 0) { -		*eof = 1; -		return 0; -	} - -	p += sprintf(p, "next_txfid=%d next_alloc=%d\n", -		     local->next_txfid, local->next_alloc); +	seq_printf(m, "next_txfid=%d next_alloc=%d\n", +		   local->next_txfid, local->next_alloc);  	for (i = 0; i < PRISM2_TXFID_COUNT; i++) -		p += sprintf(p, "FID: tx=%04X intransmit=%04X\n", -			     local->txfid[i], local->intransmitfid[i]); -	p += sprintf(p, "FW TX rate control: %d\n", local->fw_tx_rate_control); -	p += sprintf(p, "beacon_int=%d\n", local->beacon_int); -	p += sprintf(p, "dtim_period=%d\n", local->dtim_period); -	p += sprintf(p, "wds_max_connections=%d\n", -		     local->wds_max_connections); -	p += sprintf(p, "dev_enabled=%d\n", local->dev_enabled); -	p += sprintf(p, "sw_tick_stuck=%d\n", local->sw_tick_stuck); +		seq_printf(m, "FID: tx=%04X intransmit=%04X\n", +			   local->txfid[i], local->intransmitfid[i]); +	seq_printf(m, "FW TX rate control: %d\n", local->fw_tx_rate_control); +	seq_printf(m, "beacon_int=%d\n", local->beacon_int); +	seq_printf(m, "dtim_period=%d\n", local->dtim_period); +	seq_printf(m, "wds_max_connections=%d\n", local->wds_max_connections); +	seq_printf(m, "dev_enabled=%d\n", local->dev_enabled); +	seq_printf(m, "sw_tick_stuck=%d\n", local->sw_tick_stuck);  	for (i = 0; i < WEP_KEYS; i++) {  		if (local->crypt_info.crypt[i] &&  		    local->crypt_info.crypt[i]->ops) { -			p += sprintf(p, "crypt[%d]=%s\n", i, -				     local->crypt_info.crypt[i]->ops->name); +			seq_printf(m, "crypt[%d]=%s\n", i, +				   local->crypt_info.crypt[i]->ops->name);  		}  	} -	p += sprintf(p, "pri_only=%d\n", local->pri_only); -	p += sprintf(p, "pci=%d\n", local->func->hw_type == HOSTAP_HW_PCI); -	p += sprintf(p, "sram_type=%d\n", local->sram_type); -	p += sprintf(p, "no_pri=%d\n", local->no_pri); +	seq_printf(m, "pri_only=%d\n", local->pri_only); +	seq_printf(m, "pci=%d\n", local->func->hw_type == HOSTAP_HW_PCI); +	seq_printf(m, "sram_type=%d\n", local->sram_type); +	seq_printf(m, "no_pri=%d\n", local->no_pri); -	return (p - page); +	return 0;  } + +static int prism2_debug_proc_open(struct inode *inode, struct file *file) +{ +	return single_open(file, prism2_debug_proc_show, PDE_DATA(inode)); +} + +static const struct file_operations prism2_debug_proc_fops = { +	.open		= prism2_debug_proc_open, +	.read		= seq_read, +	.llseek		= seq_lseek, +	.release	= seq_release, +};  #endif /* PRISM2_NO_PROCFS_DEBUG */ -static int prism2_stats_proc_read(char *page, char **start, off_t off, -				  int count, int *eof, void *data) +static int prism2_stats_proc_show(struct seq_file *m, void *v)  { -	char *p = page; -	local_info_t *local = (local_info_t *) data; +	local_info_t *local = m->private;  	struct comm_tallies_sums *sums = &local->comm_tallies; -	if (off != 0) { -		*eof = 1; -		return 0; -	} - -	p += sprintf(p, "TxUnicastFrames=%u\n", sums->tx_unicast_frames); -	p += sprintf(p, "TxMulticastframes=%u\n", sums->tx_multicast_frames); -	p += sprintf(p, "TxFragments=%u\n", sums->tx_fragments); -	p += sprintf(p, "TxUnicastOctets=%u\n", sums->tx_unicast_octets); -	p += sprintf(p, "TxMulticastOctets=%u\n", sums->tx_multicast_octets); -	p += sprintf(p, "TxDeferredTransmissions=%u\n", -		     sums->tx_deferred_transmissions); -	p += sprintf(p, "TxSingleRetryFrames=%u\n", -		     sums->tx_single_retry_frames); -	p += sprintf(p, "TxMultipleRetryFrames=%u\n", -		     sums->tx_multiple_retry_frames); -	p += sprintf(p, "TxRetryLimitExceeded=%u\n", -		     sums->tx_retry_limit_exceeded); -	p += sprintf(p, "TxDiscards=%u\n", sums->tx_discards); -	p += sprintf(p, "RxUnicastFrames=%u\n", sums->rx_unicast_frames); -	p += sprintf(p, "RxMulticastFrames=%u\n", sums->rx_multicast_frames); -	p += sprintf(p, "RxFragments=%u\n", sums->rx_fragments); -	p += sprintf(p, "RxUnicastOctets=%u\n", sums->rx_unicast_octets); -	p += sprintf(p, "RxMulticastOctets=%u\n", sums->rx_multicast_octets); -	p += sprintf(p, "RxFCSErrors=%u\n", sums->rx_fcs_errors); -	p += sprintf(p, "RxDiscardsNoBuffer=%u\n", -		     sums->rx_discards_no_buffer); -	p += sprintf(p, "TxDiscardsWrongSA=%u\n", sums->tx_discards_wrong_sa); -	p += sprintf(p, "RxDiscardsWEPUndecryptable=%u\n", -		     sums->rx_discards_wep_undecryptable); -	p += sprintf(p, "RxMessageInMsgFragments=%u\n", -		     sums->rx_message_in_msg_fragments); -	p += sprintf(p, "RxMessageInBadMsgFragments=%u\n", -		     sums->rx_message_in_bad_msg_fragments); +	seq_printf(m, "TxUnicastFrames=%u\n", sums->tx_unicast_frames); +	seq_printf(m, "TxMulticastframes=%u\n", sums->tx_multicast_frames); +	seq_printf(m, "TxFragments=%u\n", sums->tx_fragments); +	seq_printf(m, "TxUnicastOctets=%u\n", sums->tx_unicast_octets); +	seq_printf(m, "TxMulticastOctets=%u\n", sums->tx_multicast_octets); +	seq_printf(m, "TxDeferredTransmissions=%u\n", +		   sums->tx_deferred_transmissions); +	seq_printf(m, "TxSingleRetryFrames=%u\n", sums->tx_single_retry_frames); +	seq_printf(m, "TxMultipleRetryFrames=%u\n", +		   sums->tx_multiple_retry_frames); +	seq_printf(m, "TxRetryLimitExceeded=%u\n", +		   sums->tx_retry_limit_exceeded); +	seq_printf(m, "TxDiscards=%u\n", sums->tx_discards); +	seq_printf(m, "RxUnicastFrames=%u\n", sums->rx_unicast_frames); +	seq_printf(m, "RxMulticastFrames=%u\n", sums->rx_multicast_frames); +	seq_printf(m, "RxFragments=%u\n", sums->rx_fragments); +	seq_printf(m, "RxUnicastOctets=%u\n", sums->rx_unicast_octets); +	seq_printf(m, "RxMulticastOctets=%u\n", sums->rx_multicast_octets); +	seq_printf(m, "RxFCSErrors=%u\n", sums->rx_fcs_errors); +	seq_printf(m, "RxDiscardsNoBuffer=%u\n", sums->rx_discards_no_buffer); +	seq_printf(m, "TxDiscardsWrongSA=%u\n", sums->tx_discards_wrong_sa); +	seq_printf(m, "RxDiscardsWEPUndecryptable=%u\n", +		   sums->rx_discards_wep_undecryptable); +	seq_printf(m, "RxMessageInMsgFragments=%u\n", +		   sums->rx_message_in_msg_fragments); +	seq_printf(m, "RxMessageInBadMsgFragments=%u\n", +		   sums->rx_message_in_bad_msg_fragments);  	/* FIX: this may grow too long for one page(?) */ -	return (p - page); +	return 0;  } +static int prism2_stats_proc_open(struct inode *inode, struct file *file) +{ +	return single_open(file, prism2_stats_proc_show, PDE_DATA(inode)); +} + +static const struct file_operations prism2_stats_proc_fops = { +	.open		= prism2_stats_proc_open, +	.read		= seq_read, +	.llseek		= seq_lseek, +	.release	= seq_release, +}; + -static int prism2_wds_proc_read(char *page, char **start, off_t off, -				int count, int *eof, void *data) +static int prism2_wds_proc_show(struct seq_file *m, void *v)  { -	char *p = page; -	local_info_t *local = (local_info_t *) data; -	struct list_head *ptr; +	struct list_head *ptr = v;  	struct hostap_interface *iface; -	if (off > PROC_LIMIT) { -		*eof = 1; -		return 0; -	} +	iface = list_entry(ptr, struct hostap_interface, list); +	if (iface->type == HOSTAP_INTERFACE_WDS) +		seq_printf(m, "%s\t%pM\n", +			   iface->dev->name, iface->u.wds.remote_addr); +	return 0; +} +static void *prism2_wds_proc_start(struct seq_file *m, loff_t *_pos) +{ +	local_info_t *local = m->private;  	read_lock_bh(&local->iface_lock); -	list_for_each(ptr, &local->hostap_interfaces) { -		iface = list_entry(ptr, struct hostap_interface, list); -		if (iface->type != HOSTAP_INTERFACE_WDS) -			continue; -		p += sprintf(p, "%s\t%pM\n", -			     iface->dev->name, -			     iface->u.wds.remote_addr); -		if ((p - page) > PROC_LIMIT) { -			printk(KERN_DEBUG "%s: wds proc did not fit\n", -			       local->dev->name); -			break; -		} -	} -	read_unlock_bh(&local->iface_lock); +	return seq_list_start(&local->hostap_interfaces, *_pos); +} -	if ((p - page) <= off) { -		*eof = 1; -		return 0; -	} +static void *prism2_wds_proc_next(struct seq_file *m, void *v, loff_t *_pos) +{ +	local_info_t *local = m->private; +	return seq_list_next(v, &local->hostap_interfaces, _pos); +} -	*start = page + off; +static void prism2_wds_proc_stop(struct seq_file *m, void *v) +{ +	local_info_t *local = m->private; +	read_unlock_bh(&local->iface_lock); +} + +static const struct seq_operations prism2_wds_proc_seqops = { +	.start	= prism2_wds_proc_start, +	.next	= prism2_wds_proc_next, +	.stop	= prism2_wds_proc_stop, +	.show	= prism2_wds_proc_show, +}; -	return (p - page - off); +static int prism2_wds_proc_open(struct inode *inode, struct file *file) +{ +	int ret = seq_open(file, &prism2_wds_proc_seqops); +	if (ret == 0) { +		struct seq_file *m = file->private_data; +		m->private = PDE_DATA(inode); +	} +	return ret;  } +static const struct file_operations prism2_wds_proc_fops = { +	.open		= prism2_wds_proc_open, +	.read		= seq_read, +	.llseek		= seq_lseek, +	.release	= seq_release, +}; -static int prism2_bss_list_proc_read(char *page, char **start, off_t off, -				     int count, int *eof, void *data) + +static int prism2_bss_list_proc_show(struct seq_file *m, void *v)  { -	char *p = page; -	local_info_t *local = (local_info_t *) data; -	struct list_head *ptr; +	local_info_t *local = m->private; +	struct list_head *ptr = v;  	struct hostap_bss_info *bss;  	int i; -	if (off > PROC_LIMIT) { -		*eof = 1; +	if (ptr == &local->bss_list) { +		seq_printf(m, "#BSSID\tlast_update\tcount\tcapab_info\tSSID(txt)\t" +			   "SSID(hex)\tWPA IE\n");  		return 0;  	} -	p += sprintf(p, "#BSSID\tlast_update\tcount\tcapab_info\tSSID(txt)\t" -		     "SSID(hex)\tWPA IE\n"); -	spin_lock_bh(&local->lock); -	list_for_each(ptr, &local->bss_list) { -		bss = list_entry(ptr, struct hostap_bss_info, list); -		p += sprintf(p, "%pM\t%lu\t%u\t0x%x\t", -			     bss->bssid, bss->last_update, -			     bss->count, bss->capab_info); -		for (i = 0; i < bss->ssid_len; i++) { -			p += sprintf(p, "%c", -				     bss->ssid[i] >= 32 && bss->ssid[i] < 127 ? -				     bss->ssid[i] : '_'); -		} -		p += sprintf(p, "\t"); -		for (i = 0; i < bss->ssid_len; i++) { -			p += sprintf(p, "%02x", bss->ssid[i]); -		} -		p += sprintf(p, "\t"); -		for (i = 0; i < bss->wpa_ie_len; i++) { -			p += sprintf(p, "%02x", bss->wpa_ie[i]); -		} -		p += sprintf(p, "\n"); -		if ((p - page) > PROC_LIMIT) { -			printk(KERN_DEBUG "%s: BSS proc did not fit\n", -			       local->dev->name); -			break; -		} -	} -	spin_unlock_bh(&local->lock); +	bss = list_entry(ptr, struct hostap_bss_info, list); +	seq_printf(m, "%pM\t%lu\t%u\t0x%x\t", +		   bss->bssid, bss->last_update, +		   bss->count, bss->capab_info); -	if ((p - page) <= off) { -		*eof = 1; -		return 0; -	} +	for (i = 0; i < bss->ssid_len; i++) +		seq_putc(m,bss->ssid[i] >= 32 && bss->ssid[i] < 127 ? +			   bss->ssid[i] : '_'); -	*start = page + off; +	seq_putc(m, '\t'); +	for (i = 0; i < bss->ssid_len; i++) +		seq_printf(m, "%02x", bss->ssid[i]); +	seq_putc(m, '\t'); +	for (i = 0; i < bss->wpa_ie_len; i++) +		seq_printf(m, "%02x", bss->wpa_ie[i]); +	seq_putc(m, '\n'); +	return 0; +} -	return (p - page - off); +static void *prism2_bss_list_proc_start(struct seq_file *m, loff_t *_pos) +{ +	local_info_t *local = m->private; +	spin_lock_bh(&local->lock); +	return seq_list_start_head(&local->bss_list, *_pos);  } +static void *prism2_bss_list_proc_next(struct seq_file *m, void *v, loff_t *_pos) +{ +	local_info_t *local = m->private; +	return seq_list_next(v, &local->bss_list, _pos); +} -static int prism2_crypt_proc_read(char *page, char **start, off_t off, -				  int count, int *eof, void *data) +static void prism2_bss_list_proc_stop(struct seq_file *m, void *v)  { -	char *p = page; -	local_info_t *local = (local_info_t *) data; -	int i; +	local_info_t *local = m->private; +	spin_unlock_bh(&local->lock); +} -	if (off > PROC_LIMIT) { -		*eof = 1; -		return 0; +static const struct seq_operations prism2_bss_list_proc_seqops = { +	.start	= prism2_bss_list_proc_start, +	.next	= prism2_bss_list_proc_next, +	.stop	= prism2_bss_list_proc_stop, +	.show	= prism2_bss_list_proc_show, +}; + +static int prism2_bss_list_proc_open(struct inode *inode, struct file *file) +{ +	int ret = seq_open(file, &prism2_bss_list_proc_seqops); +	if (ret == 0) { +		struct seq_file *m = file->private_data; +		m->private = PDE_DATA(inode);  	} +	return ret; +} -	p += sprintf(p, "tx_keyidx=%d\n", local->crypt_info.tx_keyidx); +static const struct file_operations prism2_bss_list_proc_fops = { +	.open		= prism2_bss_list_proc_open, +	.read		= seq_read, +	.llseek		= seq_lseek, +	.release	= seq_release, +}; + + +static int prism2_crypt_proc_show(struct seq_file *m, void *v) +{ +	local_info_t *local = m->private; +	int i; + +	seq_printf(m, "tx_keyidx=%d\n", local->crypt_info.tx_keyidx);  	for (i = 0; i < WEP_KEYS; i++) {  		if (local->crypt_info.crypt[i] &&  		    local->crypt_info.crypt[i]->ops &&  		    local->crypt_info.crypt[i]->ops->print_stats) { -			p = local->crypt_info.crypt[i]->ops->print_stats( -				p, local->crypt_info.crypt[i]->priv); +			local->crypt_info.crypt[i]->ops->print_stats( +				m, local->crypt_info.crypt[i]->priv);  		}  	} +	return 0; +} -	if ((p - page) <= off) { -		*eof = 1; -		return 0; -	} - -	*start = page + off; - -	return (p - page - off); +static int prism2_crypt_proc_open(struct inode *inode, struct file *file) +{ +	return single_open(file, prism2_crypt_proc_show, PDE_DATA(inode));  } +static const struct file_operations prism2_crypt_proc_fops = { +	.open		= prism2_crypt_proc_open, +	.read		= seq_read, +	.llseek		= seq_lseek, +	.release	= seq_release, +}; -static int prism2_pda_proc_read(char *page, char **start, off_t off, -				int count, int *eof, void *data) + +static ssize_t prism2_pda_proc_read(struct file *file, char __user *buf, +				    size_t count, loff_t *_pos)  { -	local_info_t *local = (local_info_t *) data; +	local_info_t *local = PDE_DATA(file_inode(file)); +	size_t off; -	if (local->pda == NULL || off >= PRISM2_PDA_SIZE) { -		*eof = 1; +	if (local->pda == NULL || *_pos >= PRISM2_PDA_SIZE)  		return 0; -	} -	if (off + count > PRISM2_PDA_SIZE) +	off = *_pos; +	if (count > PRISM2_PDA_SIZE - off)  		count = PRISM2_PDA_SIZE - off; - -	memcpy(page, local->pda + off, count); +	if (copy_to_user(buf, local->pda + off, count) != 0) +		return -EFAULT; +	*_pos += count;  	return count;  } +static const struct file_operations prism2_pda_proc_fops = { +	.read		= prism2_pda_proc_read, +	.llseek		= generic_file_llseek, +}; -static int prism2_aux_dump_proc_read(char *page, char **start, off_t off, -				     int count, int *eof, void *data) -{ -	local_info_t *local = (local_info_t *) data; -	if (local->func->read_aux == NULL) { -		*eof = 1; -		return 0; -	} - -	if (local->func->read_aux(local->dev, off, count, page)) { -		*eof = 1; -		return 0; -	} -	*start = page; - -	return count; +static ssize_t prism2_aux_dump_proc_no_read(struct file *file, char __user *buf, +					    size_t bufsize, loff_t *_pos) +{ +	return 0;  } +static const struct file_operations prism2_aux_dump_proc_fops = { +	.read		= prism2_aux_dump_proc_no_read, +}; +  #ifdef PRISM2_IO_DEBUG  static int prism2_io_debug_proc_read(char *page, char **start, off_t off, @@ -306,82 +344,108 @@ static int prism2_io_debug_proc_read(char *page, char **start, off_t off,  #ifndef PRISM2_NO_STATION_MODES -static int prism2_scan_results_proc_read(char *page, char **start, off_t off, -					 int count, int *eof, void *data) +static int prism2_scan_results_proc_show(struct seq_file *m, void *v)  { -	char *p = page; -	local_info_t *local = (local_info_t *) data; -	int entry, i, len, total = 0; +	local_info_t *local = m->private; +	unsigned long entry; +	int i, len;  	struct hfa384x_hostscan_result *scanres; -	u8 *pos; +	u8 *p; -	p += sprintf(p, "CHID ANL SL BcnInt Capab Rate BSSID ATIM SupRates " -		     "SSID\n"); +	if (v == SEQ_START_TOKEN) { +		seq_printf(m, +			   "CHID ANL SL BcnInt Capab Rate BSSID ATIM SupRates SSID\n"); +		return 0; +	} -	spin_lock_bh(&local->lock); -	for (entry = 0; entry < local->last_scan_results_count; entry++) { -		scanres = &local->last_scan_results[entry]; +	entry = (unsigned long)v - 2; +	scanres = &local->last_scan_results[entry]; -		if (total + (p - page) <= off) { -			total += p - page; -			p = page; -		} -		if (total + (p - page) > off + count) -			break; -		if ((p - page) > (PAGE_SIZE - 200)) +	seq_printf(m, "%d %d %d %d 0x%02x %d %pM %d ", +		   le16_to_cpu(scanres->chid), +		   (s16) le16_to_cpu(scanres->anl), +		   (s16) le16_to_cpu(scanres->sl), +		   le16_to_cpu(scanres->beacon_interval), +		   le16_to_cpu(scanres->capability), +		   le16_to_cpu(scanres->rate), +		   scanres->bssid, +		   le16_to_cpu(scanres->atim)); + +	p = scanres->sup_rates; +	for (i = 0; i < sizeof(scanres->sup_rates); i++) { +		if (p[i] == 0)  			break; +		seq_printf(m, "<%02x>", p[i]); +	} +	seq_putc(m, ' '); -		p += sprintf(p, "%d %d %d %d 0x%02x %d %pM %d ", -			     le16_to_cpu(scanres->chid), -			     (s16) le16_to_cpu(scanres->anl), -			     (s16) le16_to_cpu(scanres->sl), -			     le16_to_cpu(scanres->beacon_interval), -			     le16_to_cpu(scanres->capability), -			     le16_to_cpu(scanres->rate), -			     scanres->bssid, -			     le16_to_cpu(scanres->atim)); +	p = scanres->ssid; +	len = le16_to_cpu(scanres->ssid_len); +	if (len > 32) +		len = 32; +	for (i = 0; i < len; i++) { +		unsigned char c = p[i]; +		if (c >= 32 && c < 127) +			seq_putc(m, c); +		else +			seq_printf(m, "<%02x>", c); +	} +	seq_putc(m, '\n'); +	return 0; +} -		pos = scanres->sup_rates; -		for (i = 0; i < sizeof(scanres->sup_rates); i++) { -			if (pos[i] == 0) -				break; -			p += sprintf(p, "<%02x>", pos[i]); -		} -		p += sprintf(p, " "); +static void *prism2_scan_results_proc_start(struct seq_file *m, loff_t *_pos) +{ +	local_info_t *local = m->private; +	spin_lock_bh(&local->lock); -		pos = scanres->ssid; -		len = le16_to_cpu(scanres->ssid_len); -		if (len > 32) -			len = 32; -		for (i = 0; i < len; i++) { -			unsigned char c = pos[i]; -			if (c >= 32 && c < 127) -				p += sprintf(p, "%c", c); -			else -				p += sprintf(p, "<%02x>", c); -		} -		p += sprintf(p, "\n"); -	} +	/* We have a header (pos 0) + N results to show (pos 1...N) */ +	if (*_pos > local->last_scan_results_count) +		return NULL; +	return (void *)(unsigned long)(*_pos + 1); /* 0 would be EOF */ +} + +static void *prism2_scan_results_proc_next(struct seq_file *m, void *v, loff_t *_pos) +{ +	local_info_t *local = m->private; + +	++*_pos; +	if (*_pos > local->last_scan_results_count) +		return NULL; +	return (void *)(unsigned long)(*_pos + 1); /* 0 would be EOF */ +} + +static void prism2_scan_results_proc_stop(struct seq_file *m, void *v) +{ +	local_info_t *local = m->private;  	spin_unlock_bh(&local->lock); +} -	total += (p - page); -	if (total >= off + count) -		*eof = 1; +static const struct seq_operations prism2_scan_results_proc_seqops = { +	.start	= prism2_scan_results_proc_start, +	.next	= prism2_scan_results_proc_next, +	.stop	= prism2_scan_results_proc_stop, +	.show	= prism2_scan_results_proc_show, +}; -	if (total < off) { -		*eof = 1; -		return 0; +static int prism2_scan_results_proc_open(struct inode *inode, struct file *file) +{ +	int ret = seq_open(file, &prism2_scan_results_proc_seqops); +	if (ret == 0) { +		struct seq_file *m = file->private_data; +		m->private = PDE_DATA(inode);  	} +	return ret; +} + +static const struct file_operations prism2_scan_results_proc_fops = { +	.open		= prism2_scan_results_proc_open, +	.read		= seq_read, +	.llseek		= seq_lseek, +	.release	= seq_release, +}; -	len = total - off; -	if (len > (p - page)) -		len = p - page; -	*start = p - len; -	if (len > count) -		len = count; -	return len; -}  #endif /* PRISM2_NO_STATION_MODES */ @@ -403,53 +467,36 @@ void hostap_init_proc(local_info_t *local)  	}  #ifndef PRISM2_NO_PROCFS_DEBUG -	create_proc_read_entry("debug", 0, local->proc, -			       prism2_debug_proc_read, local); +	proc_create_data("debug", 0, local->proc, +			 &prism2_debug_proc_fops, local);  #endif /* PRISM2_NO_PROCFS_DEBUG */ -	create_proc_read_entry("stats", 0, local->proc, -			       prism2_stats_proc_read, local); -	create_proc_read_entry("wds", 0, local->proc, -			       prism2_wds_proc_read, local); -	create_proc_read_entry("pda", 0, local->proc, -			       prism2_pda_proc_read, local); -	create_proc_read_entry("aux_dump", 0, local->proc, -			       prism2_aux_dump_proc_read, local); -	create_proc_read_entry("bss_list", 0, local->proc, -			       prism2_bss_list_proc_read, local); -	create_proc_read_entry("crypt", 0, local->proc, -			       prism2_crypt_proc_read, local); +	proc_create_data("stats", 0, local->proc, +			 &prism2_stats_proc_fops, local); +	proc_create_data("wds", 0, local->proc, +			 &prism2_wds_proc_fops, local); +	proc_create_data("pda", 0, local->proc, +			 &prism2_pda_proc_fops, local); +	proc_create_data("aux_dump", 0, local->proc, +			 local->func->read_aux_fops ?: &prism2_aux_dump_proc_fops, +			 local); +	proc_create_data("bss_list", 0, local->proc, +			 &prism2_bss_list_proc_fops, local); +	proc_create_data("crypt", 0, local->proc, +			 &prism2_crypt_proc_fops, local);  #ifdef PRISM2_IO_DEBUG -	create_proc_read_entry("io_debug", 0, local->proc, -			       prism2_io_debug_proc_read, local); +	proc_create_data("io_debug", 0, local->proc, +			 &prism2_io_debug_proc_fops, local);  #endif /* PRISM2_IO_DEBUG */  #ifndef PRISM2_NO_STATION_MODES -	create_proc_read_entry("scan_results", 0, local->proc, -			       prism2_scan_results_proc_read, local); +	proc_create_data("scan_results", 0, local->proc, +			 &prism2_scan_results_proc_fops, local);  #endif /* PRISM2_NO_STATION_MODES */  }  void hostap_remove_proc(local_info_t *local)  { -	if (local->proc != NULL) { -#ifndef PRISM2_NO_STATION_MODES -		remove_proc_entry("scan_results", local->proc); -#endif /* PRISM2_NO_STATION_MODES */ -#ifdef PRISM2_IO_DEBUG -		remove_proc_entry("io_debug", local->proc); -#endif /* PRISM2_IO_DEBUG */ -		remove_proc_entry("pda", local->proc); -		remove_proc_entry("aux_dump", local->proc); -		remove_proc_entry("wds", local->proc); -		remove_proc_entry("stats", local->proc); -		remove_proc_entry("bss_list", local->proc); -		remove_proc_entry("crypt", local->proc); -#ifndef PRISM2_NO_PROCFS_DEBUG -		remove_proc_entry("debug", local->proc); -#endif /* PRISM2_NO_PROCFS_DEBUG */ -		if (hostap_proc != NULL) -			remove_proc_entry(local->proc->name, hostap_proc); -	} +	remove_proc_subtree(local->ddev->name, hostap_proc);  } diff --git a/drivers/net/wireless/hostap/hostap_wlan.h b/drivers/net/wireless/hostap/hostap_wlan.h index 7bb0b4b3f2c..57904015380 100644 --- a/drivers/net/wireless/hostap/hostap_wlan.h +++ b/drivers/net/wireless/hostap/hostap_wlan.h @@ -596,8 +596,7 @@ struct prism2_helper_functions {  			struct prism2_download_param *param);  	int (*tx)(struct sk_buff *skb, struct net_device *dev);  	int (*set_tim)(struct net_device *dev, int aid, int set); -	int (*read_aux)(struct net_device *dev, unsigned addr, int len, -			u8 *buf); +	const struct file_operations *read_aux_fops;  	int need_tx_headroom; /* number of bytes of headroom needed before  			       * IEEE 802.11 header */ diff --git a/drivers/net/wireless/iwlegacy/3945-mac.c b/drivers/net/wireless/iwlegacy/3945-mac.c index 3630a41df50..c353b5f19c8 100644 --- a/drivers/net/wireless/iwlegacy/3945-mac.c +++ b/drivers/net/wireless/iwlegacy/3945-mac.c @@ -475,6 +475,7 @@ il3945_tx_skb(struct il_priv *il,  	dma_addr_t txcmd_phys;  	int txq_id = skb_get_queue_mapping(skb);  	u16 len, idx, hdr_len; +	u16 firstlen, secondlen;  	u8 id;  	u8 unicast;  	u8 sta_id; @@ -589,21 +590,22 @@ il3945_tx_skb(struct il_priv *il,  	len =  	    sizeof(struct il3945_tx_cmd) + sizeof(struct il_cmd_header) +  	    hdr_len; -	len = (len + 3) & ~3; +	firstlen = (len + 3) & ~3;  	/* Physical address of this Tx command's header (not MAC header!),  	 * within command buffer array. */  	txcmd_phys = -	    pci_map_single(il->pci_dev, &out_cmd->hdr, len, PCI_DMA_TODEVICE); +	    pci_map_single(il->pci_dev, &out_cmd->hdr, firstlen, +			   PCI_DMA_TODEVICE);  	if (unlikely(pci_dma_mapping_error(il->pci_dev, txcmd_phys)))  		goto drop_unlock;  	/* Set up TFD's 2nd entry to point directly to remainder of skb,  	 * if any (802.11 null frames have no payload). */ -	len = skb->len - hdr_len; -	if (len) { +	secondlen = skb->len - hdr_len; +	if (secondlen > 0) {  		phys_addr = -		    pci_map_single(il->pci_dev, skb->data + hdr_len, len, +		    pci_map_single(il->pci_dev, skb->data + hdr_len, secondlen,  				   PCI_DMA_TODEVICE);  		if (unlikely(pci_dma_mapping_error(il->pci_dev, phys_addr)))  			goto drop_unlock; @@ -611,12 +613,12 @@ il3945_tx_skb(struct il_priv *il,  	/* Add buffer containing Tx command and MAC(!) header to TFD's  	 * first entry */ -	il->ops->txq_attach_buf_to_tfd(il, txq, txcmd_phys, len, 1, 0); +	il->ops->txq_attach_buf_to_tfd(il, txq, txcmd_phys, firstlen, 1, 0);  	dma_unmap_addr_set(out_meta, mapping, txcmd_phys); -	dma_unmap_len_set(out_meta, len, len); -	if (len) -		il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, len, 0, -					       U32_PAD(len)); +	dma_unmap_len_set(out_meta, len, firstlen); +	if (secondlen > 0) +		il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, secondlen, 0, +					       U32_PAD(secondlen));  	if (!ieee80211_has_morefrags(hdr->frame_control)) {  		txq->need_update = 1; diff --git a/drivers/net/wireless/iwlwifi/dvm/sta.c b/drivers/net/wireless/iwlwifi/dvm/sta.c index 94ef33838bc..b775769f832 100644 --- a/drivers/net/wireless/iwlwifi/dvm/sta.c +++ b/drivers/net/wireless/iwlwifi/dvm/sta.c @@ -151,7 +151,7 @@ int iwl_send_add_sta(struct iwl_priv *priv,  		       sta_id, sta->sta.addr, flags & CMD_ASYNC ?  "a" : "");  	if (!(flags & CMD_ASYNC)) { -		cmd.flags |= CMD_WANT_SKB | CMD_WANT_HCMD; +		cmd.flags |= CMD_WANT_SKB;  		might_sleep();  	} diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h index 9a0f45ec9e0..81aa91fab5a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h @@ -349,25 +349,23 @@ TRACE_EVENT(iwlwifi_dev_rx_data,  TRACE_EVENT(iwlwifi_dev_hcmd,  	TP_PROTO(const struct device *dev,  		 struct iwl_host_cmd *cmd, u16 total_size, -		 const void *hdr, size_t hdr_len), -	TP_ARGS(dev, cmd, total_size, hdr, hdr_len), +		 struct iwl_cmd_header *hdr), +	TP_ARGS(dev, cmd, total_size, hdr),  	TP_STRUCT__entry(  		DEV_ENTRY  		__dynamic_array(u8, hcmd, total_size)  		__field(u32, flags)  	),  	TP_fast_assign( -		int i, offset = hdr_len; +		int i, offset = sizeof(*hdr);  		DEV_ASSIGN;  		__entry->flags = cmd->flags; -		memcpy(__get_dynamic_array(hcmd), hdr, hdr_len); +		memcpy(__get_dynamic_array(hcmd), hdr, sizeof(*hdr)); -		for (i = 0; i < IWL_MAX_CMD_TFDS; i++) { +		for (i = 0; i < IWL_MAX_CMD_TBS_PER_TFD; i++) {  			if (!cmd->len[i])  				continue; -			if (!(cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY)) -				continue;  			memcpy((u8 *)__get_dynamic_array(hcmd) + offset,  			       cmd->data[i], cmd->len[i]);  			offset += cmd->len[i]; diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index 6f228bb2b84..fbfd2d13711 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -1102,7 +1102,6 @@ void iwl_drv_stop(struct iwl_drv *drv)  /* shared module parameters */  struct iwl_mod_params iwlwifi_mod_params = { -	.amsdu_size_8K = 1,  	.restart_fw = 1,  	.plcp_check = true,  	.bt_coex_active = true, @@ -1207,7 +1206,7 @@ MODULE_PARM_DESC(11n_disable,  	"disable 11n functionality, bitmap: 1: full, 2: agg TX, 4: agg RX");  module_param_named(amsdu_size_8K, iwlwifi_mod_params.amsdu_size_8K,  		   int, S_IRUGO); -MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size"); +MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size (default 0)");  module_param_named(fw_restart, iwlwifi_mod_params.restart_fw, int, S_IRUGO);  MODULE_PARM_DESC(fw_restart, "restart firmware in case of error"); diff --git a/drivers/net/wireless/iwlwifi/iwl-modparams.h b/drivers/net/wireless/iwlwifi/iwl-modparams.h index e5e3a79eae2..2c2a729092f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-modparams.h +++ b/drivers/net/wireless/iwlwifi/iwl-modparams.h @@ -91,7 +91,7 @@ enum iwl_power_level {   * @sw_crypto: using hardware encryption, default = 0   * @disable_11n: disable 11n capabilities, default = 0,   *	use IWL_DISABLE_HT_* constants - * @amsdu_size_8K: enable 8K amsdu size, default = 1 + * @amsdu_size_8K: enable 8K amsdu size, default = 0   * @restart_fw: restart firmware, default = 1   * @plcp_check: enable plcp health check, default = true   * @wd_disable: enable stuck queue check, default = 0 diff --git a/drivers/net/wireless/iwlwifi/iwl-phy-db.c b/drivers/net/wireless/iwlwifi/iwl-phy-db.c index 14fc8d39fc2..3392011a876 100644 --- a/drivers/net/wireless/iwlwifi/iwl-phy-db.c +++ b/drivers/net/wireless/iwlwifi/iwl-phy-db.c @@ -136,12 +136,6 @@ struct iwl_calib_res_notif_phy_db {  	u8 data[];  } __packed; -#define IWL_PHY_DB_STATIC_PIC cpu_to_le32(0x21436587) -static inline void iwl_phy_db_test_pic(__le32 pic) -{ -	WARN_ON(IWL_PHY_DB_STATIC_PIC != pic); -} -  struct iwl_phy_db *iwl_phy_db_init(struct iwl_trans *trans)  {  	struct iwl_phy_db *phy_db = kzalloc(sizeof(struct iwl_phy_db), @@ -260,11 +254,6 @@ int iwl_phy_db_set_section(struct iwl_phy_db *phy_db, struct iwl_rx_packet *pkt,  			(size - CHANNEL_NUM_SIZE) / phy_db->channel_num;  	} -	/* Test PIC */ -	if (type != IWL_PHY_DB_CFG) -		iwl_phy_db_test_pic(*(((__le32 *)phy_db_notif->data) + -				      (size / sizeof(__le32)) - 1)); -  	IWL_DEBUG_INFO(phy_db->trans,  		       "%s(%d): [PHYDB]SET: Type %d , Size: %d\n",  		       __func__, __LINE__, type, size); @@ -372,11 +361,6 @@ int iwl_phy_db_get_section_data(struct iwl_phy_db *phy_db,  		*size = entry->size;  	} -	/* Test PIC */ -	if (type != IWL_PHY_DB_CFG) -		iwl_phy_db_test_pic(*(((__le32 *)*data) + -				      (*size / sizeof(__le32)) - 1)); -  	IWL_DEBUG_INFO(phy_db->trans,  		       "%s(%d): [PHYDB] GET: Type %d , Size: %d\n",  		       __func__, __LINE__, type, *size); diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 8c7bec6b9a0..0cac2b7af78 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -186,19 +186,13 @@ struct iwl_rx_packet {   * @CMD_ASYNC: Return right away and don't want for the response   * @CMD_WANT_SKB: valid only with CMD_SYNC. The caller needs the buffer of the   *	response. The caller needs to call iwl_free_resp when done. - * @CMD_WANT_HCMD: The caller needs to get the HCMD that was sent in the - *	response handler. Chunks flagged by %IWL_HCMD_DFL_NOCOPY won't be - *	copied. The pointer passed to the response handler is in the transport - *	ownership and don't need to be freed by the op_mode. This also means - *	that the pointer is invalidated after the op_mode's handler returns.   * @CMD_ON_DEMAND: This command is sent by the test mode pipe.   */  enum CMD_MODE {  	CMD_SYNC		= 0,  	CMD_ASYNC		= BIT(0),  	CMD_WANT_SKB		= BIT(1), -	CMD_WANT_HCMD		= BIT(2), -	CMD_ON_DEMAND		= BIT(3), +	CMD_ON_DEMAND		= BIT(2),  };  #define DEF_CMD_PAYLOAD_SIZE 320 @@ -217,7 +211,11 @@ struct iwl_device_cmd {  #define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_device_cmd)) -#define IWL_MAX_CMD_TFDS	2 +/* + * number of transfer buffers (fragments) per transmit frame descriptor; + * this is just the driver's idea, the hardware supports 20 + */ +#define IWL_MAX_CMD_TBS_PER_TFD	2  /**   * struct iwl_hcmd_dataflag - flag for each one of the chunks of the command @@ -254,15 +252,15 @@ enum iwl_hcmd_dataflag {   * @id: id of the host command   */  struct iwl_host_cmd { -	const void *data[IWL_MAX_CMD_TFDS]; +	const void *data[IWL_MAX_CMD_TBS_PER_TFD];  	struct iwl_rx_packet *resp_pkt;  	unsigned long _rx_page_addr;  	u32 _rx_page_order;  	int handler_status;  	u32 flags; -	u16 len[IWL_MAX_CMD_TFDS]; -	u8 dataflags[IWL_MAX_CMD_TFDS]; +	u16 len[IWL_MAX_CMD_TBS_PER_TFD]; +	u8 dataflags[IWL_MAX_CMD_TBS_PER_TFD];  	u8 id;  }; diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index c64d864799c..994c8c263dc 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -61,6 +61,7 @@   *   *****************************************************************************/ +#include <linux/etherdevice.h>  #include <net/cfg80211.h>  #include <net/ipv6.h>  #include "iwl-modparams.h" @@ -192,6 +193,11 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,  					   sizeof(wkc), &wkc);  		data->error = ret != 0; +		mvm->ptk_ivlen = key->iv_len; +		mvm->ptk_icvlen = key->icv_len; +		mvm->gtk_ivlen = key->iv_len; +		mvm->gtk_icvlen = key->icv_len; +  		/* don't upload key again */  		goto out_unlock;  	} @@ -304,9 +310,13 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,  	 */  	if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) {  		key->hw_key_idx = 0; +		mvm->ptk_ivlen = key->iv_len; +		mvm->ptk_icvlen = key->icv_len;  	} else {  		data->gtk_key_idx++;  		key->hw_key_idx = data->gtk_key_idx; +		mvm->gtk_ivlen = key->iv_len; +		mvm->gtk_icvlen = key->icv_len;  	}  	ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, true); @@ -649,6 +659,11 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)  	/* We reprogram keys and shouldn't allocate new key indices */  	memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table)); +	mvm->ptk_ivlen = 0; +	mvm->ptk_icvlen = 0; +	mvm->ptk_ivlen = 0; +	mvm->ptk_icvlen = 0; +  	/*  	 * The D3 firmware still hardcodes the AP station ID for the  	 * BSS we're associated with as 0. As a result, we have to move @@ -783,7 +798,6 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,  	struct iwl_wowlan_status *status;  	u32 reasons;  	int ret, len; -	bool pkt8023 = false;  	struct sk_buff *pkt = NULL;  	iwl_trans_read_mem_bytes(mvm->trans, base, @@ -824,7 +838,8 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,  	status = (void *)cmd.resp_pkt->data;  	if (len - sizeof(struct iwl_cmd_header) != -	    sizeof(*status) + le32_to_cpu(status->wake_packet_bufsize)) { +	    sizeof(*status) + +	    ALIGN(le32_to_cpu(status->wake_packet_bufsize), 4)) {  		IWL_ERR(mvm, "Invalid WoWLAN status response!\n");  		goto out;  	} @@ -836,61 +851,96 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,  		goto report;  	} -	if (reasons & IWL_WOWLAN_WAKEUP_BY_MAGIC_PACKET) { +	if (reasons & IWL_WOWLAN_WAKEUP_BY_MAGIC_PACKET)  		wakeup.magic_pkt = true; -		pkt8023 = true; -	} -	if (reasons & IWL_WOWLAN_WAKEUP_BY_PATTERN) { +	if (reasons & IWL_WOWLAN_WAKEUP_BY_PATTERN)  		wakeup.pattern_idx =  			le16_to_cpu(status->pattern_number); -		pkt8023 = true; -	}  	if (reasons & (IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON |  		       IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH))  		wakeup.disconnect = true; -	if (reasons & IWL_WOWLAN_WAKEUP_BY_GTK_REKEY_FAILURE) { +	if (reasons & IWL_WOWLAN_WAKEUP_BY_GTK_REKEY_FAILURE)  		wakeup.gtk_rekey_failure = true; -		pkt8023 = true; -	} -	if (reasons & IWL_WOWLAN_WAKEUP_BY_RFKILL_DEASSERTED) { +	if (reasons & IWL_WOWLAN_WAKEUP_BY_RFKILL_DEASSERTED)  		wakeup.rfkill_release = true; -		pkt8023 = true; -	} -	if (reasons & IWL_WOWLAN_WAKEUP_BY_EAPOL_REQUEST) { +	if (reasons & IWL_WOWLAN_WAKEUP_BY_EAPOL_REQUEST)  		wakeup.eap_identity_req = true; -		pkt8023 = true; -	} -	if (reasons & IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE) { +	if (reasons & IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE)  		wakeup.four_way_handshake = true; -		pkt8023 = true; -	}  	if (status->wake_packet_bufsize) { -		u32 pktsize = le32_to_cpu(status->wake_packet_bufsize); -		u32 pktlen = le32_to_cpu(status->wake_packet_length); +		int pktsize = le32_to_cpu(status->wake_packet_bufsize); +		int pktlen = le32_to_cpu(status->wake_packet_length); +		const u8 *pktdata = status->wake_packet; +		struct ieee80211_hdr *hdr = (void *)pktdata; +		int truncated = pktlen - pktsize; + +		/* this would be a firmware bug */ +		if (WARN_ON_ONCE(truncated < 0)) +			truncated = 0; + +		if (ieee80211_is_data(hdr->frame_control)) { +			int hdrlen = ieee80211_hdrlen(hdr->frame_control); +			int ivlen = 0, icvlen = 4; /* also FCS */ -		if (pkt8023) {  			pkt = alloc_skb(pktsize, GFP_KERNEL);  			if (!pkt)  				goto report; -			memcpy(skb_put(pkt, pktsize), status->wake_packet, -			       pktsize); + +			memcpy(skb_put(pkt, hdrlen), pktdata, hdrlen); +			pktdata += hdrlen; +			pktsize -= hdrlen; + +			if (ieee80211_has_protected(hdr->frame_control)) { +				if (is_multicast_ether_addr(hdr->addr1)) { +					ivlen = mvm->gtk_ivlen; +					icvlen += mvm->gtk_icvlen; +				} else { +					ivlen = mvm->ptk_ivlen; +					icvlen += mvm->ptk_icvlen; +				} +			} + +			/* if truncated, FCS/ICV is (partially) gone */ +			if (truncated >= icvlen) { +				icvlen = 0; +				truncated -= icvlen; +			} else { +				icvlen -= truncated; +				truncated = 0; +			} + +			pktsize -= ivlen + icvlen; +			pktdata += ivlen; + +			memcpy(skb_put(pkt, pktsize), pktdata, pktsize); +  			if (ieee80211_data_to_8023(pkt, vif->addr, vif->type))  				goto report;  			wakeup.packet = pkt->data;  			wakeup.packet_present_len = pkt->len; -			wakeup.packet_len = pkt->len - (pktlen - pktsize); +			wakeup.packet_len = pkt->len - truncated;  			wakeup.packet_80211 = false;  		} else { +			int fcslen = 4; + +			if (truncated >= 4) { +				truncated -= 4; +				fcslen = 0; +			} else { +				fcslen -= truncated; +				truncated = 0; +			} +			pktsize -= fcslen;  			wakeup.packet = status->wake_packet;  			wakeup.packet_present_len = pktsize; -			wakeup.packet_len = pktlen; +			wakeup.packet_len = pktlen - truncated;  			wakeup.packet_80211 = true;  		}  	} diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 23eebda848b..2adb61f103f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -762,18 +762,20 @@ struct iwl_phy_context_cmd {  #define IWL_RX_INFO_PHY_CNT 8  #define IWL_RX_INFO_AGC_IDX 1  #define IWL_RX_INFO_RSSI_AB_IDX 2 -#define IWL_RX_INFO_RSSI_C_IDX 3 -#define IWL_OFDM_AGC_DB_MSK 0xfe00 -#define IWL_OFDM_AGC_DB_POS 9 +#define IWL_OFDM_AGC_A_MSK 0x0000007f +#define IWL_OFDM_AGC_A_POS 0 +#define IWL_OFDM_AGC_B_MSK 0x00003f80 +#define IWL_OFDM_AGC_B_POS 7 +#define IWL_OFDM_AGC_CODE_MSK 0x3fe00000 +#define IWL_OFDM_AGC_CODE_POS 20  #define IWL_OFDM_RSSI_INBAND_A_MSK 0x00ff -#define IWL_OFDM_RSSI_ALLBAND_A_MSK 0xff00  #define IWL_OFDM_RSSI_A_POS 0 +#define IWL_OFDM_RSSI_ALLBAND_A_MSK 0xff00 +#define IWL_OFDM_RSSI_ALLBAND_A_POS 8  #define IWL_OFDM_RSSI_INBAND_B_MSK 0xff0000 -#define IWL_OFDM_RSSI_ALLBAND_B_MSK 0xff000000  #define IWL_OFDM_RSSI_B_POS 16 -#define IWL_OFDM_RSSI_INBAND_C_MSK 0x00ff -#define IWL_OFDM_RSSI_ALLBAND_C_MSK 0xff00 -#define IWL_OFDM_RSSI_C_POS 0 +#define IWL_OFDM_RSSI_ALLBAND_B_MSK 0xff000000 +#define IWL_OFDM_RSSI_ALLBAND_B_POS 24  /**   * struct iwl_rx_phy_info - phy info diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index d3d959db03a..500f818dba0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -79,17 +79,8 @@  #define UCODE_VALID_OK	cpu_to_le32(0x1)  /* Default calibration values for WkP - set to INIT image w/o running */ -static const u8 wkp_calib_values_bb_filter[] = { 0xbf, 0x00, 0x5f, 0x00, 0x2f, -						 0x00, 0x18, 0x00 }; -static const u8 wkp_calib_values_rx_dc[] = { 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, -					     0x7f, 0x7f, 0x7f }; -static const u8 wkp_calib_values_tx_lo[] = { 0x00, 0x00, 0x00, 0x00 }; -static const u8 wkp_calib_values_tx_iq[] = { 0xff, 0x00, 0xff, 0x00, 0x00, -					     0x00 }; -static const u8 wkp_calib_values_rx_iq[] = { 0xff, 0x00, 0x00, 0x00 };  static const u8 wkp_calib_values_rx_iq_skew[] = { 0x00, 0x00, 0x01, 0x00 };  static const u8 wkp_calib_values_tx_iq_skew[] = { 0x01, 0x00, 0x00, 0x00 }; -static const u8 wkp_calib_values_xtal[] = { 0xd2, 0xd2 };  struct iwl_calib_default_data {  	u16 size; @@ -99,12 +90,7 @@ struct iwl_calib_default_data {  #define CALIB_SIZE_N_DATA(_buf) {.size = sizeof(_buf), .data = &_buf}  static const struct iwl_calib_default_data wkp_calib_default_data[12] = { -	[5] = CALIB_SIZE_N_DATA(wkp_calib_values_rx_dc), -	[6] = CALIB_SIZE_N_DATA(wkp_calib_values_bb_filter), -	[7] = CALIB_SIZE_N_DATA(wkp_calib_values_tx_lo), -	[8] = CALIB_SIZE_N_DATA(wkp_calib_values_tx_iq),  	[9] = CALIB_SIZE_N_DATA(wkp_calib_values_tx_iq_skew), -	[10] = CALIB_SIZE_N_DATA(wkp_calib_values_rx_iq),  	[11] = CALIB_SIZE_N_DATA(wkp_calib_values_rx_iq_skew),  }; @@ -241,20 +227,6 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,  	return 0;  } -#define IWL_HW_REV_ID_RAINBOW	0x2 -#define IWL_PROJ_TYPE_LHP	0x5 - -static u32 iwl_mvm_build_phy_cfg(struct iwl_mvm *mvm) -{ -	struct iwl_nvm_data *data = mvm->nvm_data; -	/* Temp calls to static definitions, will be changed to CSR calls */ -	u8 hw_rev_id = IWL_HW_REV_ID_RAINBOW; -	u8 project_type = IWL_PROJ_TYPE_LHP; - -	return data->radio_cfg_dash | (data->radio_cfg_step << 2) | -		(hw_rev_id << 4) | ((project_type & 0x7f) << 6) | -		(data->valid_tx_ant << 16) | (data->valid_rx_ant << 20); -}  static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm)  { @@ -262,7 +234,7 @@ static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm)  	enum iwl_ucode_type ucode_type = mvm->cur_ucode;  	/* Set parameters */ -	phy_cfg_cmd.phy_cfg = cpu_to_le32(iwl_mvm_build_phy_cfg(mvm)); +	phy_cfg_cmd.phy_cfg = cpu_to_le32(mvm->fw->phy_config);  	phy_cfg_cmd.calib_control.event_trigger =  		mvm->fw->default_calib[ucode_type].event_trigger;  	phy_cfg_cmd.calib_control.flow_trigger = @@ -275,103 +247,6 @@ static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm)  				    sizeof(phy_cfg_cmd), &phy_cfg_cmd);  } -/* Starting with the new PHY DB implementation - New calibs are enabled */ -/* Value - 0x405e7 */ -#define IWL_CALIB_DEFAULT_FLOW_INIT	(IWL_CALIB_CFG_XTAL_IDX		|\ -					 IWL_CALIB_CFG_TEMPERATURE_IDX	|\ -					 IWL_CALIB_CFG_VOLTAGE_READ_IDX	|\ -					 IWL_CALIB_CFG_DC_IDX		|\ -					 IWL_CALIB_CFG_BB_FILTER_IDX	|\ -					 IWL_CALIB_CFG_LO_LEAKAGE_IDX	|\ -					 IWL_CALIB_CFG_TX_IQ_IDX	|\ -					 IWL_CALIB_CFG_RX_IQ_IDX	|\ -					 IWL_CALIB_CFG_AGC_IDX) - -#define IWL_CALIB_DEFAULT_EVENT_INIT	0x0 - -/* Value 0x41567 */ -#define IWL_CALIB_DEFAULT_FLOW_RUN	(IWL_CALIB_CFG_XTAL_IDX		|\ -					 IWL_CALIB_CFG_TEMPERATURE_IDX	|\ -					 IWL_CALIB_CFG_VOLTAGE_READ_IDX	|\ -					 IWL_CALIB_CFG_BB_FILTER_IDX	|\ -					 IWL_CALIB_CFG_DC_IDX		|\ -					 IWL_CALIB_CFG_TX_IQ_IDX	|\ -					 IWL_CALIB_CFG_RX_IQ_IDX	|\ -					 IWL_CALIB_CFG_SENSITIVITY_IDX	|\ -					 IWL_CALIB_CFG_AGC_IDX) - -#define IWL_CALIB_DEFAULT_EVENT_RUN	(IWL_CALIB_CFG_XTAL_IDX		|\ -					 IWL_CALIB_CFG_TEMPERATURE_IDX	|\ -					 IWL_CALIB_CFG_VOLTAGE_READ_IDX	|\ -					 IWL_CALIB_CFG_TX_PWR_IDX	|\ -					 IWL_CALIB_CFG_DC_IDX		|\ -					 IWL_CALIB_CFG_TX_IQ_IDX	|\ -					 IWL_CALIB_CFG_SENSITIVITY_IDX) - -/* - * Sets the calibrations trigger values that will be sent to the FW for runtime - * and init calibrations. - * The ones given in the FW TLV are not correct. - */ -static void iwl_set_default_calib_trigger(struct iwl_mvm *mvm) -{ -	struct iwl_tlv_calib_ctrl default_calib; - -	/* -	 * WkP FW TLV calib bits are wrong, overwrite them. -	 * This defines the dynamic calibrations which are implemented in the -	 * uCode both for init(flow) calculation and event driven calibs. -	 */ - -	/* Init Image */ -	default_calib.event_trigger = cpu_to_le32(IWL_CALIB_DEFAULT_EVENT_INIT); -	default_calib.flow_trigger = cpu_to_le32(IWL_CALIB_DEFAULT_FLOW_INIT); - -	if (default_calib.event_trigger != -	    mvm->fw->default_calib[IWL_UCODE_INIT].event_trigger) -		IWL_ERR(mvm, -			"Updating the event calib for INIT image: 0x%x -> 0x%x\n", -			mvm->fw->default_calib[IWL_UCODE_INIT].event_trigger, -			default_calib.event_trigger); -	if (default_calib.flow_trigger != -	    mvm->fw->default_calib[IWL_UCODE_INIT].flow_trigger) -		IWL_ERR(mvm, -			"Updating the flow calib for INIT image: 0x%x -> 0x%x\n", -			mvm->fw->default_calib[IWL_UCODE_INIT].flow_trigger, -			default_calib.flow_trigger); - -	memcpy((void *)&mvm->fw->default_calib[IWL_UCODE_INIT], -	       &default_calib, sizeof(struct iwl_tlv_calib_ctrl)); -	IWL_ERR(mvm, -		"Setting uCode init calibrations event 0x%x, trigger 0x%x\n", -		default_calib.event_trigger, -		default_calib.flow_trigger); - -	/* Run time image */ -	default_calib.event_trigger = cpu_to_le32(IWL_CALIB_DEFAULT_EVENT_RUN); -	default_calib.flow_trigger = cpu_to_le32(IWL_CALIB_DEFAULT_FLOW_RUN); - -	if (default_calib.event_trigger != -	    mvm->fw->default_calib[IWL_UCODE_REGULAR].event_trigger) -		IWL_ERR(mvm, -			"Updating the event calib for RT image: 0x%x -> 0x%x\n", -			mvm->fw->default_calib[IWL_UCODE_REGULAR].event_trigger, -			default_calib.event_trigger); -	if (default_calib.flow_trigger != -	    mvm->fw->default_calib[IWL_UCODE_REGULAR].flow_trigger) -		IWL_ERR(mvm, -			"Updating the flow calib for RT image: 0x%x -> 0x%x\n", -			mvm->fw->default_calib[IWL_UCODE_REGULAR].flow_trigger, -			default_calib.flow_trigger); - -	memcpy((void *)&mvm->fw->default_calib[IWL_UCODE_REGULAR], -	       &default_calib, sizeof(struct iwl_tlv_calib_ctrl)); -	IWL_ERR(mvm, -		"Setting uCode runtime calibs event 0x%x, trigger 0x%x\n", -		default_calib.event_trigger, -		default_calib.flow_trigger); -} -  static int iwl_set_default_calibrations(struct iwl_mvm *mvm)  {  	u8 cmd_raw[16]; /* holds the variable size commands */ @@ -446,8 +321,10 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)  	ret = iwl_nvm_check_version(mvm->nvm_data, mvm->trans);  	WARN_ON(ret); -	/* Override the calibrations from TLV and the const of fw */ -	iwl_set_default_calib_trigger(mvm); +	/* Send TX valid antennas before triggering calibrations */ +	ret = iwl_send_tx_ant_cfg(mvm, mvm->nvm_data->valid_tx_ant); +	if (ret) +		goto error;  	/* WkP doesn't have all calibrations, need to set default values */  	if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) { diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index e8264e11b12..7e169b085af 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -557,11 +557,9 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,  	return ret;  } -static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw, -					 struct ieee80211_vif *vif) +static void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm, +					struct ieee80211_vif *vif)  { -	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); -	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);  	u32 tfd_msk = 0, ac;  	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) @@ -594,12 +592,21 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,  		 */  		flush_work(&mvm->sta_drained_wk);  	} +} + +static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw, +					 struct ieee80211_vif *vif) +{ +	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); +	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + +	iwl_mvm_prepare_mac_removal(mvm, vif);  	mutex_lock(&mvm->mutex);  	/*  	 * For AP/GO interface, the tear down of the resources allocated to the -	 * interface should be handled as part of the bss_info_changed flow. +	 * interface is be handled as part of the stop_ap flow.  	 */  	if (vif->type == NL80211_IFTYPE_AP) {  		iwl_mvm_dealloc_int_sta(mvm, &mvmvif->bcast_sta); @@ -763,6 +770,8 @@ static void iwl_mvm_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif)  	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);  	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); +	iwl_mvm_prepare_mac_removal(mvm, vif); +  	mutex_lock(&mvm->mutex);  	mvmvif->ap_active = false; diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 4e339ccfa80..bdae700c769 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -80,7 +80,8 @@  #define IWL_INVALID_MAC80211_QUEUE	0xff  #define IWL_MVM_MAX_ADDRESSES		2 -#define IWL_RSSI_OFFSET 44 +/* RSSI offset for WkP */ +#define IWL_RSSI_OFFSET 50  enum iwl_mvm_tx_fifo {  	IWL_MVM_TX_FIFO_BK = 0, @@ -327,6 +328,10 @@ struct iwl_mvm {  	struct led_classdev led;  	struct ieee80211_vif *p2p_device_vif; + +#ifdef CONFIG_PM_SLEEP +	int gtk_ivlen, gtk_icvlen, ptk_ivlen, ptk_icvlen; +#endif  };  /* Extract MVM priv from op_mode and _hw */ diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index aa59adf87db..d0f9c1e0475 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -624,12 +624,8 @@ static void iwl_mvm_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb)  	ieee80211_free_txskb(mvm->hw, skb);  } -static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode) +static void iwl_mvm_nic_restart(struct iwl_mvm *mvm)  { -	struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); - -	iwl_mvm_dump_nic_error_log(mvm); -  	iwl_abort_notification_waits(&mvm->notif_wait);  	/* @@ -663,9 +659,21 @@ static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode)  	}  } +static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode) +{ +	struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); + +	iwl_mvm_dump_nic_error_log(mvm); + +	iwl_mvm_nic_restart(mvm); +} +  static void iwl_mvm_cmd_queue_full(struct iwl_op_mode *op_mode)  { +	struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); +  	WARN_ON(1); +	iwl_mvm_nic_restart(mvm);  }  static const struct iwl_op_mode_ops iwl_mvm_ops = { diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index 3f40ab05bbd..b0b190d0ec2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c @@ -131,33 +131,42 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm,  static int iwl_mvm_calc_rssi(struct iwl_mvm *mvm,  			     struct iwl_rx_phy_info *phy_info)  { -	u32 rssi_a, rssi_b, rssi_c, max_rssi, agc_db; +	int rssi_a, rssi_b, rssi_a_dbm, rssi_b_dbm, max_rssi_dbm; +	int rssi_all_band_a, rssi_all_band_b; +	u32 agc_a, agc_b, max_agc;  	u32 val; -	/* Find max rssi among 3 possible receivers. +	/* Find max rssi among 2 possible receivers.  	 * These values are measured by the Digital Signal Processor (DSP).  	 * They should stay fairly constant even as the signal strength varies,  	 * if the radio's Automatic Gain Control (AGC) is working right.  	 * AGC value (see below) will provide the "interesting" info.  	 */ +	val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_AGC_IDX]); +	agc_a = (val & IWL_OFDM_AGC_A_MSK) >> IWL_OFDM_AGC_A_POS; +	agc_b = (val & IWL_OFDM_AGC_B_MSK) >> IWL_OFDM_AGC_B_POS; +	max_agc = max_t(u32, agc_a, agc_b); +  	val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_RSSI_AB_IDX]);  	rssi_a = (val & IWL_OFDM_RSSI_INBAND_A_MSK) >> IWL_OFDM_RSSI_A_POS;  	rssi_b = (val & IWL_OFDM_RSSI_INBAND_B_MSK) >> IWL_OFDM_RSSI_B_POS; -	val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_RSSI_C_IDX]); -	rssi_c = (val & IWL_OFDM_RSSI_INBAND_C_MSK) >> IWL_OFDM_RSSI_C_POS; - -	val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_AGC_IDX]); -	agc_db = (val & IWL_OFDM_AGC_DB_MSK) >> IWL_OFDM_AGC_DB_POS; +	rssi_all_band_a = (val & IWL_OFDM_RSSI_ALLBAND_A_MSK) >> +				IWL_OFDM_RSSI_ALLBAND_A_POS; +	rssi_all_band_b = (val & IWL_OFDM_RSSI_ALLBAND_B_MSK) >> +				IWL_OFDM_RSSI_ALLBAND_B_POS; -	max_rssi = max_t(u32, rssi_a, rssi_b); -	max_rssi = max_t(u32, max_rssi, rssi_c); +	/* +	 * dBm = rssi dB - agc dB - constant. +	 * Higher AGC (higher radio gain) means lower signal. +	 */ +	rssi_a_dbm = rssi_a - IWL_RSSI_OFFSET - agc_a; +	rssi_b_dbm = rssi_b - IWL_RSSI_OFFSET - agc_b; +	max_rssi_dbm = max_t(int, rssi_a_dbm, rssi_b_dbm); -	IWL_DEBUG_STATS(mvm, "Rssi In A %d B %d C %d Max %d AGC dB %d\n", -			rssi_a, rssi_b, rssi_c, max_rssi, agc_db); +	IWL_DEBUG_STATS(mvm, "Rssi In A %d B %d Max %d AGCA %d AGCB %d\n", +			rssi_a_dbm, rssi_b_dbm, max_rssi_dbm, agc_a, agc_b); -	/* dBm = max_rssi dB - agc dB - constant. -	 * Higher AGC (higher radio gain) means lower signal. */ -	return max_rssi - agc_db - IWL_RSSI_OFFSET; +	return max_rssi_dbm;  }  /* diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 861a7f9f8e7..274f44e2ef6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -770,6 +770,16 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  	u16 txq_id;  	int err; + +	/* +	 * If mac80211 is cleaning its state, then say that we finished since +	 * our state has been cleared anyway. +	 */ +	if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { +		ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); +		return 0; +	} +  	spin_lock_bh(&mvmsta->lock);  	txq_id = tid_data->txq_id; diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index 6b67ce3f679..6645efe5c03 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -607,12 +607,8 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,  		/* Single frame failure in an AMPDU queue => send BAR */  		if (txq_id >= IWL_FIRST_AMPDU_QUEUE && -		    !(info->flags & IEEE80211_TX_STAT_ACK)) { -			/* there must be only one skb in the skb_list */ -			WARN_ON_ONCE(skb_freed > 1 || -				     !skb_queue_empty(&skbs)); +		    !(info->flags & IEEE80211_TX_STAT_ACK))  			info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; -		}  		/* W/A FW bug: seq_ctl is wrong when the queue is flushed */  		if (status == TX_STATUS_FAIL_FIFO_FLUSHED) { diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index aa2a39a637d..148843e7f34 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h @@ -137,10 +137,6 @@ static inline int iwl_queue_dec_wrap(int index, int n_bd)  struct iwl_cmd_meta {  	/* only for SYNC commands, iff the reply skb is wanted */  	struct iwl_host_cmd *source; - -	DEFINE_DMA_UNMAP_ADDR(mapping); -	DEFINE_DMA_UNMAP_LEN(len); -  	u32 flags;  }; @@ -182,19 +178,39 @@ struct iwl_queue {  #define TFD_TX_CMD_SLOTS 256  #define TFD_CMD_SLOTS 32 +/* + * The FH will write back to the first TB only, so we need + * to copy some data into the buffer regardless of whether + * it should be mapped or not. This indicates how big the + * first TB must be to include the scratch buffer. Since + * the scratch is 4 bytes at offset 12, it's 16 now. If we + * make it bigger then allocations will be bigger and copy + * slower, so that's probably not useful. + */ +#define IWL_HCMD_SCRATCHBUF_SIZE	16 +  struct iwl_pcie_txq_entry {  	struct iwl_device_cmd *cmd; -	struct iwl_device_cmd *copy_cmd;  	struct sk_buff *skb;  	/* buffer to free after command completes */  	const void *free_buf;  	struct iwl_cmd_meta meta;  }; +struct iwl_pcie_txq_scratch_buf { +	struct iwl_cmd_header hdr; +	u8 buf[8]; +	__le32 scratch; +}; +  /**   * struct iwl_txq - Tx Queue for DMA   * @q: generic Rx/Tx queue descriptor   * @tfds: transmit frame descriptors (DMA memory) + * @scratchbufs: start of command headers, including scratch buffers, for + *	the writeback -- this is DMA memory and an array holding one buffer + *	for each command on the queue + * @scratchbufs_dma: DMA address for the scratchbufs start   * @entries: transmit entries (driver state)   * @lock: queue lock   * @stuck_timer: timer that fires if queue gets stuck @@ -208,6 +224,8 @@ struct iwl_pcie_txq_entry {  struct iwl_txq {  	struct iwl_queue q;  	struct iwl_tfd *tfds; +	struct iwl_pcie_txq_scratch_buf *scratchbufs; +	dma_addr_t scratchbufs_dma;  	struct iwl_pcie_txq_entry *entries;  	spinlock_t lock;  	struct timer_list stuck_timer; @@ -216,6 +234,13 @@ struct iwl_txq {  	u8 active;  }; +static inline dma_addr_t +iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx) +{ +	return txq->scratchbufs_dma + +	       sizeof(struct iwl_pcie_txq_scratch_buf) * idx; +} +  /**   * struct iwl_trans_pcie - PCIe transport specific data   * @rxq: all the RX queue data diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index b0ae06d2456..567e67ad1f6 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c @@ -637,22 +637,14 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,  		index = SEQ_TO_INDEX(sequence);  		cmd_index = get_cmd_index(&txq->q, index); -		if (reclaim) { -			struct iwl_pcie_txq_entry *ent; -			ent = &txq->entries[cmd_index]; -			cmd = ent->copy_cmd; -			WARN_ON_ONCE(!cmd && ent->meta.flags & CMD_WANT_HCMD); -		} else { +		if (reclaim) +			cmd = txq->entries[cmd_index].cmd; +		else  			cmd = NULL; -		}  		err = iwl_op_mode_rx(trans->op_mode, &rxcb, cmd);  		if (reclaim) { -			/* The original command isn't needed any more */ -			kfree(txq->entries[cmd_index].copy_cmd); -			txq->entries[cmd_index].copy_cmd = NULL; -			/* nor is the duplicated part of the command */  			kfree(txq->entries[cmd_index].free_buf);  			txq->entries[cmd_index].free_buf = NULL;  		} diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 8e9e3212fe7..8595c16f74d 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -191,12 +191,9 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data)  	}  	for (i = q->read_ptr; i != q->write_ptr; -	     i = iwl_queue_inc_wrap(i, q->n_bd)) { -		struct iwl_tx_cmd *tx_cmd = -			(struct iwl_tx_cmd *)txq->entries[i].cmd->payload; +	     i = iwl_queue_inc_wrap(i, q->n_bd))  		IWL_ERR(trans, "scratch %d = 0x%08x\n", i, -			get_unaligned_le32(&tx_cmd->scratch)); -	} +			le32_to_cpu(txq->scratchbufs[i].scratch));  	iwl_op_mode_nic_error(trans->op_mode);  } @@ -367,8 +364,8 @@ static inline u8 iwl_pcie_tfd_get_num_tbs(struct iwl_tfd *tfd)  }  static void iwl_pcie_tfd_unmap(struct iwl_trans *trans, -			       struct iwl_cmd_meta *meta, struct iwl_tfd *tfd, -			       enum dma_data_direction dma_dir) +			       struct iwl_cmd_meta *meta, +			       struct iwl_tfd *tfd)  {  	int i;  	int num_tbs; @@ -382,17 +379,12 @@ static void iwl_pcie_tfd_unmap(struct iwl_trans *trans,  		return;  	} -	/* Unmap tx_cmd */ -	if (num_tbs) -		dma_unmap_single(trans->dev, -				dma_unmap_addr(meta, mapping), -				dma_unmap_len(meta, len), -				DMA_BIDIRECTIONAL); +	/* first TB is never freed - it's the scratchbuf data */ -	/* Unmap chunks, if any. */  	for (i = 1; i < num_tbs; i++)  		dma_unmap_single(trans->dev, iwl_pcie_tfd_tb_get_addr(tfd, i), -				 iwl_pcie_tfd_tb_get_len(tfd, i), dma_dir); +				 iwl_pcie_tfd_tb_get_len(tfd, i), +				 DMA_TO_DEVICE);  	tfd->num_tbs = 0;  } @@ -406,8 +398,7 @@ static void iwl_pcie_tfd_unmap(struct iwl_trans *trans,   * Does NOT advance any TFD circular buffer read/write indexes   * Does NOT free the TFD itself (which is within circular buffer)   */ -static void iwl_pcie_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq, -				  enum dma_data_direction dma_dir) +static void iwl_pcie_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq)  {  	struct iwl_tfd *tfd_tmp = txq->tfds; @@ -418,8 +409,7 @@ static void iwl_pcie_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq,  	lockdep_assert_held(&txq->lock);  	/* We have only q->n_window txq->entries, but we use q->n_bd tfds */ -	iwl_pcie_tfd_unmap(trans, &txq->entries[idx].meta, &tfd_tmp[rd_ptr], -			   dma_dir); +	iwl_pcie_tfd_unmap(trans, &txq->entries[idx].meta, &tfd_tmp[rd_ptr]);  	/* free SKB */  	if (txq->entries) { @@ -479,6 +469,7 @@ static int iwl_pcie_txq_alloc(struct iwl_trans *trans,  {  	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);  	size_t tfd_sz = sizeof(struct iwl_tfd) * TFD_QUEUE_SIZE_MAX; +	size_t scratchbuf_sz;  	int i;  	if (WARN_ON(txq->entries || txq->tfds)) @@ -514,9 +505,25 @@ static int iwl_pcie_txq_alloc(struct iwl_trans *trans,  		IWL_ERR(trans, "dma_alloc_coherent(%zd) failed\n", tfd_sz);  		goto error;  	} + +	BUILD_BUG_ON(IWL_HCMD_SCRATCHBUF_SIZE != sizeof(*txq->scratchbufs)); +	BUILD_BUG_ON(offsetof(struct iwl_pcie_txq_scratch_buf, scratch) != +			sizeof(struct iwl_cmd_header) + +			offsetof(struct iwl_tx_cmd, scratch)); + +	scratchbuf_sz = sizeof(*txq->scratchbufs) * slots_num; + +	txq->scratchbufs = dma_alloc_coherent(trans->dev, scratchbuf_sz, +					      &txq->scratchbufs_dma, +					      GFP_KERNEL); +	if (!txq->scratchbufs) +		goto err_free_tfds; +  	txq->q.id = txq_id;  	return 0; +err_free_tfds: +	dma_free_coherent(trans->dev, tfd_sz, txq->tfds, txq->q.dma_addr);  error:  	if (txq->entries && txq_id == trans_pcie->cmd_queue)  		for (i = 0; i < slots_num; i++) @@ -565,22 +572,13 @@ static void iwl_pcie_txq_unmap(struct iwl_trans *trans, int txq_id)  	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);  	struct iwl_txq *txq = &trans_pcie->txq[txq_id];  	struct iwl_queue *q = &txq->q; -	enum dma_data_direction dma_dir;  	if (!q->n_bd)  		return; -	/* In the command queue, all the TBs are mapped as BIDI -	 * so unmap them as such. -	 */ -	if (txq_id == trans_pcie->cmd_queue) -		dma_dir = DMA_BIDIRECTIONAL; -	else -		dma_dir = DMA_TO_DEVICE; -  	spin_lock_bh(&txq->lock);  	while (q->write_ptr != q->read_ptr) { -		iwl_pcie_txq_free_tfd(trans, txq, dma_dir); +		iwl_pcie_txq_free_tfd(trans, txq);  		q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd);  	}  	spin_unlock_bh(&txq->lock); @@ -610,7 +608,6 @@ static void iwl_pcie_txq_free(struct iwl_trans *trans, int txq_id)  	if (txq_id == trans_pcie->cmd_queue)  		for (i = 0; i < txq->q.n_window; i++) {  			kfree(txq->entries[i].cmd); -			kfree(txq->entries[i].copy_cmd);  			kfree(txq->entries[i].free_buf);  		} @@ -619,6 +616,10 @@ static void iwl_pcie_txq_free(struct iwl_trans *trans, int txq_id)  		dma_free_coherent(dev, sizeof(struct iwl_tfd) *  				  txq->q.n_bd, txq->tfds, txq->q.dma_addr);  		txq->q.dma_addr = 0; + +		dma_free_coherent(dev, +				  sizeof(*txq->scratchbufs) * txq->q.n_window, +				  txq->scratchbufs, txq->scratchbufs_dma);  	}  	kfree(txq->entries); @@ -962,7 +963,7 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,  		iwl_pcie_txq_inval_byte_cnt_tbl(trans, txq); -		iwl_pcie_txq_free_tfd(trans, txq, DMA_TO_DEVICE); +		iwl_pcie_txq_free_tfd(trans, txq);  	}  	iwl_pcie_txq_progress(trans_pcie, txq); @@ -1152,20 +1153,37 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,  	void *dup_buf = NULL;  	dma_addr_t phys_addr;  	int idx; -	u16 copy_size, cmd_size; +	u16 copy_size, cmd_size, scratch_size;  	bool had_nocopy = false;  	int i;  	u32 cmd_pos; +	const u8 *cmddata[IWL_MAX_CMD_TBS_PER_TFD]; +	u16 cmdlen[IWL_MAX_CMD_TBS_PER_TFD];  	copy_size = sizeof(out_cmd->hdr);  	cmd_size = sizeof(out_cmd->hdr);  	/* need one for the header if the first is NOCOPY */ -	BUILD_BUG_ON(IWL_MAX_CMD_TFDS > IWL_NUM_OF_TBS - 1); +	BUILD_BUG_ON(IWL_MAX_CMD_TBS_PER_TFD > IWL_NUM_OF_TBS - 1); + +	for (i = 0; i < IWL_MAX_CMD_TBS_PER_TFD; i++) { +		cmddata[i] = cmd->data[i]; +		cmdlen[i] = cmd->len[i]; -	for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {  		if (!cmd->len[i])  			continue; + +		/* need at least IWL_HCMD_SCRATCHBUF_SIZE copied */ +		if (copy_size < IWL_HCMD_SCRATCHBUF_SIZE) { +			int copy = IWL_HCMD_SCRATCHBUF_SIZE - copy_size; + +			if (copy > cmdlen[i]) +				copy = cmdlen[i]; +			cmdlen[i] -= copy; +			cmddata[i] += copy; +			copy_size += copy; +		} +  		if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY) {  			had_nocopy = true;  			if (WARN_ON(cmd->dataflags[i] & IWL_HCMD_DFL_DUP)) { @@ -1185,7 +1203,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,  				goto free_dup_buf;  			} -			dup_buf = kmemdup(cmd->data[i], cmd->len[i], +			dup_buf = kmemdup(cmddata[i], cmdlen[i],  					  GFP_ATOMIC);  			if (!dup_buf)  				return -ENOMEM; @@ -1195,7 +1213,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,  				idx = -EINVAL;  				goto free_dup_buf;  			} -			copy_size += cmd->len[i]; +			copy_size += cmdlen[i];  		}  		cmd_size += cmd->len[i];  	} @@ -1242,30 +1260,30 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,  	/* and copy the data that needs to be copied */  	cmd_pos = offsetof(struct iwl_device_cmd, payload); -	for (i = 0; i < IWL_MAX_CMD_TFDS; i++) { -		if (!cmd->len[i]) +	copy_size = sizeof(out_cmd->hdr); +	for (i = 0; i < IWL_MAX_CMD_TBS_PER_TFD; i++) { +		int copy = 0; + +		if (!cmd->len)  			continue; -		if (cmd->dataflags[i] & (IWL_HCMD_DFL_NOCOPY | -					 IWL_HCMD_DFL_DUP)) -			break; -		memcpy((u8 *)out_cmd + cmd_pos, cmd->data[i], cmd->len[i]); -		cmd_pos += cmd->len[i]; -	} -	WARN_ON_ONCE(txq->entries[idx].copy_cmd); +		/* need at least IWL_HCMD_SCRATCHBUF_SIZE copied */ +		if (copy_size < IWL_HCMD_SCRATCHBUF_SIZE) { +			copy = IWL_HCMD_SCRATCHBUF_SIZE - copy_size; -	/* -	 * since out_cmd will be the source address of the FH, it will write -	 * the retry count there. So when the user needs to receivce the HCMD -	 * that corresponds to the response in the response handler, it needs -	 * to set CMD_WANT_HCMD. -	 */ -	if (cmd->flags & CMD_WANT_HCMD) { -		txq->entries[idx].copy_cmd = -			kmemdup(out_cmd, cmd_pos, GFP_ATOMIC); -		if (unlikely(!txq->entries[idx].copy_cmd)) { -			idx = -ENOMEM; -			goto out; +			if (copy > cmd->len[i]) +				copy = cmd->len[i]; +		} + +		/* copy everything if not nocopy/dup */ +		if (!(cmd->dataflags[i] & (IWL_HCMD_DFL_NOCOPY | +					   IWL_HCMD_DFL_DUP))) +			copy = cmd->len[i]; + +		if (copy) { +			memcpy((u8 *)out_cmd + cmd_pos, cmd->data[i], copy); +			cmd_pos += copy; +			copy_size += copy;  		}  	} @@ -1275,22 +1293,35 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,  		     out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence),  		     cmd_size, q->write_ptr, idx, trans_pcie->cmd_queue); -	phys_addr = dma_map_single(trans->dev, &out_cmd->hdr, copy_size, -				   DMA_BIDIRECTIONAL); -	if (unlikely(dma_mapping_error(trans->dev, phys_addr))) { -		idx = -ENOMEM; -		goto out; -	} +	/* start the TFD with the scratchbuf */ +	scratch_size = min_t(int, copy_size, IWL_HCMD_SCRATCHBUF_SIZE); +	memcpy(&txq->scratchbufs[q->write_ptr], &out_cmd->hdr, scratch_size); +	iwl_pcie_txq_build_tfd(trans, txq, +			       iwl_pcie_get_scratchbuf_dma(txq, q->write_ptr), +			       scratch_size, 1); -	dma_unmap_addr_set(out_meta, mapping, phys_addr); -	dma_unmap_len_set(out_meta, len, copy_size); +	/* map first command fragment, if any remains */ +	if (copy_size > scratch_size) { +		phys_addr = dma_map_single(trans->dev, +					   ((u8 *)&out_cmd->hdr) + scratch_size, +					   copy_size - scratch_size, +					   DMA_TO_DEVICE); +		if (dma_mapping_error(trans->dev, phys_addr)) { +			iwl_pcie_tfd_unmap(trans, out_meta, +					   &txq->tfds[q->write_ptr]); +			idx = -ENOMEM; +			goto out; +		} -	iwl_pcie_txq_build_tfd(trans, txq, phys_addr, copy_size, 1); +		iwl_pcie_txq_build_tfd(trans, txq, phys_addr, +				       copy_size - scratch_size, 0); +	} -	for (i = 0; i < IWL_MAX_CMD_TFDS; i++) { -		const void *data = cmd->data[i]; +	/* map the remaining (adjusted) nocopy/dup fragments */ +	for (i = 0; i < IWL_MAX_CMD_TBS_PER_TFD; i++) { +		const void *data = cmddata[i]; -		if (!cmd->len[i]) +		if (!cmdlen[i])  			continue;  		if (!(cmd->dataflags[i] & (IWL_HCMD_DFL_NOCOPY |  					   IWL_HCMD_DFL_DUP))) @@ -1298,16 +1329,15 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,  		if (cmd->dataflags[i] & IWL_HCMD_DFL_DUP)  			data = dup_buf;  		phys_addr = dma_map_single(trans->dev, (void *)data, -					   cmd->len[i], DMA_BIDIRECTIONAL); +					   cmdlen[i], DMA_TO_DEVICE);  		if (dma_mapping_error(trans->dev, phys_addr)) {  			iwl_pcie_tfd_unmap(trans, out_meta, -					   &txq->tfds[q->write_ptr], -					   DMA_BIDIRECTIONAL); +					   &txq->tfds[q->write_ptr]);  			idx = -ENOMEM;  			goto out;  		} -		iwl_pcie_txq_build_tfd(trans, txq, phys_addr, cmd->len[i], 0); +		iwl_pcie_txq_build_tfd(trans, txq, phys_addr, cmdlen[i], 0);  	}  	out_meta->flags = cmd->flags; @@ -1317,8 +1347,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,  	txq->need_update = 1; -	trace_iwlwifi_dev_hcmd(trans->dev, cmd, cmd_size, -			       &out_cmd->hdr, copy_size); +	trace_iwlwifi_dev_hcmd(trans->dev, cmd, cmd_size, &out_cmd->hdr);  	/* start timer if queue currently empty */  	if (q->read_ptr == q->write_ptr && trans_pcie->wd_timeout) @@ -1377,7 +1406,7 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans,  	cmd = txq->entries[cmd_index].cmd;  	meta = &txq->entries[cmd_index].meta; -	iwl_pcie_tfd_unmap(trans, meta, &txq->tfds[index], DMA_BIDIRECTIONAL); +	iwl_pcie_tfd_unmap(trans, meta, &txq->tfds[index]);  	/* Input error checking is done when commands are added to queue. */  	if (meta->flags & CMD_WANT_SKB) { @@ -1556,10 +1585,9 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,  	struct iwl_cmd_meta *out_meta;  	struct iwl_txq *txq;  	struct iwl_queue *q; -	dma_addr_t phys_addr = 0; -	dma_addr_t txcmd_phys; -	dma_addr_t scratch_phys; -	u16 len, firstlen, secondlen; +	dma_addr_t tb0_phys, tb1_phys, scratch_phys; +	void *tb1_addr; +	u16 len, tb1_len, tb2_len;  	u8 wait_write_ptr = 0;  	__le16 fc = hdr->frame_control;  	u8 hdr_len = ieee80211_hdrlen(fc); @@ -1597,85 +1625,80 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,  		cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) |  			    INDEX_TO_SEQ(q->write_ptr))); +	tb0_phys = iwl_pcie_get_scratchbuf_dma(txq, q->write_ptr); +	scratch_phys = tb0_phys + sizeof(struct iwl_cmd_header) + +		       offsetof(struct iwl_tx_cmd, scratch); + +	tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys); +	tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys); +  	/* Set up first empty entry in queue's array of Tx/cmd buffers */  	out_meta = &txq->entries[q->write_ptr].meta;  	/* -	 * Use the first empty entry in this queue's command buffer array -	 * to contain the Tx command and MAC header concatenated together -	 * (payload data will be in another buffer). -	 * Size of this varies, due to varying MAC header length. -	 * If end is not dword aligned, we'll have 2 extra bytes at the end -	 * of the MAC header (device reads on dword boundaries). -	 * We'll tell device about this padding later. +	 * The second TB (tb1) points to the remainder of the TX command +	 * and the 802.11 header - dword aligned size +	 * (This calculation modifies the TX command, so do it before the +	 * setup of the first TB)  	 */ -	len = sizeof(struct iwl_tx_cmd) + -		sizeof(struct iwl_cmd_header) + hdr_len; -	firstlen = (len + 3) & ~3; +	len = sizeof(struct iwl_tx_cmd) + sizeof(struct iwl_cmd_header) + +	      hdr_len - IWL_HCMD_SCRATCHBUF_SIZE; +	tb1_len = (len + 3) & ~3;  	/* Tell NIC about any 2-byte padding after MAC header */ -	if (firstlen != len) +	if (tb1_len != len)  		tx_cmd->tx_flags |= TX_CMD_FLG_MH_PAD_MSK; -	/* Physical address of this Tx command's header (not MAC header!), -	 * within command buffer array. */ -	txcmd_phys = dma_map_single(trans->dev, -				    &dev_cmd->hdr, firstlen, -				    DMA_BIDIRECTIONAL); -	if (unlikely(dma_mapping_error(trans->dev, txcmd_phys))) -		goto out_err; -	dma_unmap_addr_set(out_meta, mapping, txcmd_phys); -	dma_unmap_len_set(out_meta, len, firstlen); +	/* The first TB points to the scratchbuf data - min_copy bytes */ +	memcpy(&txq->scratchbufs[q->write_ptr], &dev_cmd->hdr, +	       IWL_HCMD_SCRATCHBUF_SIZE); +	iwl_pcie_txq_build_tfd(trans, txq, tb0_phys, +			       IWL_HCMD_SCRATCHBUF_SIZE, 1); -	if (!ieee80211_has_morefrags(fc)) { -		txq->need_update = 1; -	} else { -		wait_write_ptr = 1; -		txq->need_update = 0; -	} +	/* there must be data left over for TB1 or this code must be changed */ +	BUILD_BUG_ON(sizeof(struct iwl_tx_cmd) < IWL_HCMD_SCRATCHBUF_SIZE); + +	/* map the data for TB1 */ +	tb1_addr = ((u8 *)&dev_cmd->hdr) + IWL_HCMD_SCRATCHBUF_SIZE; +	tb1_phys = dma_map_single(trans->dev, tb1_addr, tb1_len, DMA_TO_DEVICE); +	if (unlikely(dma_mapping_error(trans->dev, tb1_phys))) +		goto out_err; +	iwl_pcie_txq_build_tfd(trans, txq, tb1_phys, tb1_len, 0); -	/* Set up TFD's 2nd entry to point directly to remainder of skb, -	 * if any (802.11 null frames have no payload). */ -	secondlen = skb->len - hdr_len; -	if (secondlen > 0) { -		phys_addr = dma_map_single(trans->dev, skb->data + hdr_len, -					   secondlen, DMA_TO_DEVICE); -		if (unlikely(dma_mapping_error(trans->dev, phys_addr))) { -			dma_unmap_single(trans->dev, -					 dma_unmap_addr(out_meta, mapping), -					 dma_unmap_len(out_meta, len), -					 DMA_BIDIRECTIONAL); +	/* +	 * Set up TFD's third entry to point directly to remainder +	 * of skb, if any (802.11 null frames have no payload). +	 */ +	tb2_len = skb->len - hdr_len; +	if (tb2_len > 0) { +		dma_addr_t tb2_phys = dma_map_single(trans->dev, +						     skb->data + hdr_len, +						     tb2_len, DMA_TO_DEVICE); +		if (unlikely(dma_mapping_error(trans->dev, tb2_phys))) { +			iwl_pcie_tfd_unmap(trans, out_meta, +					   &txq->tfds[q->write_ptr]);  			goto out_err;  		} +		iwl_pcie_txq_build_tfd(trans, txq, tb2_phys, tb2_len, 0);  	} -	/* Attach buffers to TFD */ -	iwl_pcie_txq_build_tfd(trans, txq, txcmd_phys, firstlen, 1); -	if (secondlen > 0) -		iwl_pcie_txq_build_tfd(trans, txq, phys_addr, secondlen, 0); - -	scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) + -				offsetof(struct iwl_tx_cmd, scratch); - -	/* take back ownership of DMA buffer to enable update */ -	dma_sync_single_for_cpu(trans->dev, txcmd_phys, firstlen, -				DMA_BIDIRECTIONAL); -	tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys); -	tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys); -  	/* Set up entry for this TFD in Tx byte-count array */  	iwl_pcie_txq_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len)); -	dma_sync_single_for_device(trans->dev, txcmd_phys, firstlen, -				   DMA_BIDIRECTIONAL); -  	trace_iwlwifi_dev_tx(trans->dev, skb,  			     &txq->tfds[txq->q.write_ptr],  			     sizeof(struct iwl_tfd), -			     &dev_cmd->hdr, firstlen, -			     skb->data + hdr_len, secondlen); +			     &dev_cmd->hdr, IWL_HCMD_SCRATCHBUF_SIZE + tb1_len, +			     skb->data + hdr_len, tb2_len);  	trace_iwlwifi_dev_tx_data(trans->dev, skb, -				  skb->data + hdr_len, secondlen); +				  skb->data + hdr_len, tb2_len); + +	if (!ieee80211_has_morefrags(fc)) { +		txq->need_update = 1; +	} else { +		wait_write_ptr = 1; +		txq->need_update = 0; +	}  	/* start timer if queue currently empty */  	if (txq->need_update && q->read_ptr == q->write_ptr && diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index 739309e70d8..45578335e42 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c @@ -825,6 +825,11 @@ static void if_sdio_finish_power_on(struct if_sdio_card *card)  	sdio_release_host(func); +	/* Set fw_ready before queuing any commands so that +	 * lbs_thread won't block from sending them to firmware. +	 */ +	priv->fw_ready = 1; +  	/*  	 * FUNC_INIT is required for SD8688 WLAN/BT multiple functions  	 */ @@ -839,7 +844,6 @@ static void if_sdio_finish_power_on(struct if_sdio_card *card)  			netdev_alert(priv->dev, "CMD_FUNC_INIT cmd failed\n");  	} -	priv->fw_ready = 1;  	wake_up(&card->pwron_waitq);  	if (!card->started) { diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 20a6c555587..b5c8b962ce1 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -157,6 +157,20 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,  		return -1;  	} +	cmd_code = le16_to_cpu(host_cmd->command); +	cmd_size = le16_to_cpu(host_cmd->size); + +	if (adapter->hw_status == MWIFIEX_HW_STATUS_RESET && +	    cmd_code != HostCmd_CMD_FUNC_SHUTDOWN && +	    cmd_code != HostCmd_CMD_FUNC_INIT) { +		dev_err(adapter->dev, +			"DNLD_CMD: FW in reset state, ignore cmd %#x\n", +			cmd_code); +		mwifiex_complete_cmd(adapter, cmd_node); +		mwifiex_insert_cmd_to_free_q(adapter, cmd_node); +		return -1; +	} +  	/* Set command sequence number */  	adapter->seq_num++;  	host_cmd->seq_num = cpu_to_le16(HostCmd_SET_SEQ_NO_BSS_INFO @@ -168,9 +182,6 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,  	adapter->curr_cmd = cmd_node;  	spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); -	cmd_code = le16_to_cpu(host_cmd->command); -	cmd_size = le16_to_cpu(host_cmd->size); -  	/* Adjust skb length */  	if (cmd_node->cmd_skb->len > cmd_size)  		/* @@ -484,8 +495,6 @@ int mwifiex_send_cmd_sync(struct mwifiex_private *priv, uint16_t cmd_no,  	ret = mwifiex_send_cmd_async(priv, cmd_no, cmd_action, cmd_oid,  				     data_buf); -	if (!ret) -		ret = mwifiex_wait_queue_complete(adapter);  	return ret;  } @@ -588,9 +597,10 @@ int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no,  	if (cmd_no == HostCmd_CMD_802_11_SCAN) {  		mwifiex_queue_scan_cmd(priv, cmd_node);  	} else { -		adapter->cmd_queued = cmd_node;  		mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true);  		queue_work(adapter->workqueue, &adapter->main_work); +		if (cmd_node->wait_q_enabled) +			ret = mwifiex_wait_queue_complete(adapter, cmd_node);  	}  	return ret; diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index e38aa9b3663..0ff4c37ab42 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -709,6 +709,14 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter)  		return ret;  	} +	/* cancel current command */ +	if (adapter->curr_cmd) { +		dev_warn(adapter->dev, "curr_cmd is still in processing\n"); +		del_timer(&adapter->cmd_timer); +		mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd); +		adapter->curr_cmd = NULL; +	} +  	/* shut down mwifiex */  	dev_dbg(adapter->dev, "info: shutdown mwifiex...\n"); diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c index 246aa62a481..2fe0ceba440 100644 --- a/drivers/net/wireless/mwifiex/join.c +++ b/drivers/net/wireless/mwifiex/join.c @@ -1117,10 +1117,9 @@ mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv,  		adhoc_join->bss_descriptor.bssid,  		adhoc_join->bss_descriptor.ssid); -	for (i = 0; bss_desc->supported_rates[i] && -			i < MWIFIEX_SUPPORTED_RATES; -			i++) -			; +	for (i = 0; i < MWIFIEX_SUPPORTED_RATES && +		    bss_desc->supported_rates[i]; i++) +		;  	rates_size = i;  	/* Copy Data Rates from the Rates recorded in scan response */ diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 553adfb0aa8..7035ade9af7 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -723,7 +723,6 @@ struct mwifiex_adapter {  	u16 cmd_wait_q_required;  	struct mwifiex_wait_queue cmd_wait_q;  	u8 scan_wait_q_woken; -	struct cmd_ctrl_node *cmd_queued;  	spinlock_t queue_lock;		/* lock for tx queues */  	struct completion fw_load;  	u8 country_code[IEEE80211_COUNTRY_STRING_LEN]; @@ -1018,7 +1017,8 @@ int mwifiex_request_set_multicast_list(struct mwifiex_private *priv,  			struct mwifiex_multicast_list *mcast_list);  int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist,  			    struct net_device *dev); -int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter); +int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter, +				struct cmd_ctrl_node *cmd_queued);  int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,  		      struct cfg80211_ssid *req_ssid);  int mwifiex_cancel_hs(struct mwifiex_private *priv, int cmd_type); diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index 35c79722c36..5c395e2e6a2 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c @@ -302,7 +302,7 @@ static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter)  		i++;  		usleep_range(10, 20);  		/* 50ms max wait */ -		if (i == 50000) +		if (i == 5000)  			break;  	} diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index bb60c2754a9..d215b4d3c51 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -1388,10 +1388,13 @@ int mwifiex_scan_networks(struct mwifiex_private *priv,  			list_del(&cmd_node->list);  			spin_unlock_irqrestore(&adapter->scan_pending_q_lock,  					       flags); -			adapter->cmd_queued = cmd_node;  			mwifiex_insert_cmd_to_pending_q(adapter, cmd_node,  							true);  			queue_work(adapter->workqueue, &adapter->main_work); + +			/* Perform internal scan synchronously */ +			if (!priv->scan_request) +				mwifiex_wait_queue_complete(adapter, cmd_node);  		} else {  			spin_unlock_irqrestore(&adapter->scan_pending_q_lock,  					       flags); @@ -1946,9 +1949,6 @@ int mwifiex_request_scan(struct mwifiex_private *priv,  		/* Normal scan */  		ret = mwifiex_scan_networks(priv, NULL); -	if (!ret) -		ret = mwifiex_wait_queue_complete(priv->adapter); -  	up(&priv->async_sem);  	return ret; diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index 9f33c92c90f..13100f8de3d 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -54,16 +54,10 @@ int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist,   * This function waits on a cmd wait queue. It also cancels the pending   * request after waking up, in case of errors.   */ -int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter) +int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter, +				struct cmd_ctrl_node *cmd_queued)  {  	int status; -	struct cmd_ctrl_node *cmd_queued; - -	if (!adapter->cmd_queued) -		return 0; - -	cmd_queued = adapter->cmd_queued; -	adapter->cmd_queued = NULL;  	dev_dbg(adapter->dev, "cmd pending\n");  	atomic_inc(&adapter->cmd_pending); diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 3109c0db66e..a6f660c0190 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -2778,7 +2778,7 @@ static ssize_t int_proc_write(struct file *file, const char __user *buffer,  		nr = nr * 10 + c;  		p++;  	} while (--len); -	*(int *)PDE(file_inode(file))->data = nr; +	*(int *)PDE_DATA(file_inode(file)) = nr;  	return count;  } diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index 44d6ead4334..2bf4efa3318 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -55,10 +55,10 @@ config RT61PCI  config RT2800PCI  	tristate "Ralink rt27xx/rt28xx/rt30xx (PCI/PCIe/PCMCIA) support" -	depends on PCI || RALINK_RT288X || RALINK_RT305X +	depends on PCI || SOC_RT288X || SOC_RT305X  	select RT2800_LIB  	select RT2X00_LIB_PCI if PCI -	select RT2X00_LIB_SOC if RALINK_RT288X || RALINK_RT305X +	select RT2X00_LIB_SOC if SOC_RT288X || SOC_RT305X  	select RT2X00_LIB_FIRMWARE  	select RT2X00_LIB_CRYPTO  	select CRC_CCITT diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 48a01aa21f1..ded73da4de0 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -89,7 +89,7 @@ static void rt2800pci_mcu_status(struct rt2x00_dev *rt2x00dev, const u8 token)  	rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);  } -#if defined(CONFIG_RALINK_RT288X) || defined(CONFIG_RALINK_RT305X) +#if defined(CONFIG_SOC_RT288X) || defined(CONFIG_SOC_RT305X)  static int rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)  {  	void __iomem *base_addr = ioremap(0x1F040000, EEPROM_SIZE); @@ -107,7 +107,7 @@ static inline int rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)  {  	return -ENOMEM;  } -#endif /* CONFIG_RALINK_RT288X || CONFIG_RALINK_RT305X */ +#endif /* CONFIG_SOC_RT288X || CONFIG_SOC_RT305X */  #ifdef CONFIG_PCI  static void rt2800pci_eepromregister_read(struct eeprom_93cx6 *eeprom) @@ -1177,7 +1177,7 @@ MODULE_DEVICE_TABLE(pci, rt2800pci_device_table);  #endif /* CONFIG_PCI */  MODULE_LICENSE("GPL"); -#if defined(CONFIG_RALINK_RT288X) || defined(CONFIG_RALINK_RT305X) +#if defined(CONFIG_SOC_RT288X) || defined(CONFIG_SOC_RT305X)  static int rt2800soc_probe(struct platform_device *pdev)  {  	return rt2x00soc_probe(pdev, &rt2800pci_ops); @@ -1194,7 +1194,7 @@ static struct platform_driver rt2800soc_driver = {  	.suspend	= rt2x00soc_suspend,  	.resume		= rt2x00soc_resume,  }; -#endif /* CONFIG_RALINK_RT288X || CONFIG_RALINK_RT305X */ +#endif /* CONFIG_SOC_RT288X || CONFIG_SOC_RT305X */  #ifdef CONFIG_PCI  static int rt2800pci_probe(struct pci_dev *pci_dev, @@ -1217,7 +1217,7 @@ static int __init rt2800pci_init(void)  {  	int ret = 0; -#if defined(CONFIG_RALINK_RT288X) || defined(CONFIG_RALINK_RT305X) +#if defined(CONFIG_SOC_RT288X) || defined(CONFIG_SOC_RT305X)  	ret = platform_driver_register(&rt2800soc_driver);  	if (ret)  		return ret; @@ -1225,7 +1225,7 @@ static int __init rt2800pci_init(void)  #ifdef CONFIG_PCI  	ret = pci_register_driver(&rt2800pci_driver);  	if (ret) { -#if defined(CONFIG_RALINK_RT288X) || defined(CONFIG_RALINK_RT305X) +#if defined(CONFIG_SOC_RT288X) || defined(CONFIG_SOC_RT305X)  		platform_driver_unregister(&rt2800soc_driver);  #endif  		return ret; @@ -1240,7 +1240,7 @@ static void __exit rt2800pci_exit(void)  #ifdef CONFIG_PCI  	pci_unregister_driver(&rt2800pci_driver);  #endif -#if defined(CONFIG_RALINK_RT288X) || defined(CONFIG_RALINK_RT305X) +#if defined(CONFIG_SOC_RT288X) || defined(CONFIG_SOC_RT305X)  	platform_driver_unregister(&rt2800soc_driver);  #endif  } diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 1031db66474..189744db65e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -1236,8 +1236,10 @@ static inline void rt2x00lib_set_if_combinations(struct rt2x00_dev *rt2x00dev)  	 */  	if_limit = &rt2x00dev->if_limits_ap;  	if_limit->max = rt2x00dev->ops->max_ap_intf; -	if_limit->types = BIT(NL80211_IFTYPE_AP) | -			BIT(NL80211_IFTYPE_MESH_POINT); +	if_limit->types = BIT(NL80211_IFTYPE_AP); +#ifdef CONFIG_MAC80211_MESH +	if_limit->types |= BIT(NL80211_IFTYPE_MESH_POINT); +#endif  	/*  	 * Build up AP interface combinations structure. @@ -1309,7 +1311,9 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)  		rt2x00dev->hw->wiphy->interface_modes |=  		    BIT(NL80211_IFTYPE_ADHOC) |  		    BIT(NL80211_IFTYPE_AP) | +#ifdef CONFIG_MAC80211_MESH  		    BIT(NL80211_IFTYPE_MESH_POINT) | +#endif  		    BIT(NL80211_IFTYPE_WDS);  	rt2x00dev->hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c index b1ccff474c7..c08d0f4c5f3 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c @@ -1377,74 +1377,57 @@ void rtl92cu_card_disable(struct ieee80211_hw *hw)  void rtl92cu_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid)  { -	/* dummy routine needed for callback from rtl_op_configure_filter() */ -} - -/*========================================================================== */ - -static void _rtl92cu_set_check_bssid(struct ieee80211_hw *hw, -			      enum nl80211_iftype type) -{  	struct rtl_priv *rtlpriv = rtl_priv(hw); -	u32 reg_rcr = rtl_read_dword(rtlpriv, REG_RCR);  	struct rtl_hal *rtlhal = rtl_hal(rtlpriv); -	struct rtl_phy *rtlphy = &(rtlpriv->phy); -	u8 filterout_non_associated_bssid = false; +	u32 reg_rcr = rtl_read_dword(rtlpriv, REG_RCR); -	switch (type) { -	case NL80211_IFTYPE_ADHOC: -	case NL80211_IFTYPE_STATION: -		filterout_non_associated_bssid = true; -		break; -	case NL80211_IFTYPE_UNSPECIFIED: -	case NL80211_IFTYPE_AP: -	default: -		break; -	} -	if (filterout_non_associated_bssid) { +	if (rtlpriv->psc.rfpwr_state != ERFON) +		return; + +	if (check_bssid) { +		u8 tmp;  		if (IS_NORMAL_CHIP(rtlhal->version)) { -			switch (rtlphy->current_io_type) { -			case IO_CMD_RESUME_DM_BY_SCAN: -				reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN); -				rtlpriv->cfg->ops->set_hw_reg(hw, -						 HW_VAR_RCR, (u8 *)(®_rcr)); -				/* enable update TSF */ -				_rtl92cu_set_bcn_ctrl_reg(hw, 0, BIT(4)); -				break; -			case IO_CMD_PAUSE_DM_BY_SCAN: -				reg_rcr &= ~(RCR_CBSSID_DATA | RCR_CBSSID_BCN); -				rtlpriv->cfg->ops->set_hw_reg(hw, -						 HW_VAR_RCR, (u8 *)(®_rcr)); -				/* disable update TSF */ -				_rtl92cu_set_bcn_ctrl_reg(hw, BIT(4), 0); -				break; -			} +			reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN); +			tmp = BIT(4);  		} else { -			reg_rcr |= (RCR_CBSSID); -			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, -						      (u8 *)(®_rcr)); -			_rtl92cu_set_bcn_ctrl_reg(hw, 0, (BIT(4)|BIT(5))); +			reg_rcr |= RCR_CBSSID; +			tmp = BIT(4) | BIT(5);  		} -	} else if (filterout_non_associated_bssid == false) { +		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, +					      (u8 *) (®_rcr)); +		_rtl92cu_set_bcn_ctrl_reg(hw, 0, tmp); +	} else { +		u8 tmp;  		if (IS_NORMAL_CHIP(rtlhal->version)) { -			reg_rcr &= (~(RCR_CBSSID_DATA | RCR_CBSSID_BCN)); -			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, -						      (u8 *)(®_rcr)); -			_rtl92cu_set_bcn_ctrl_reg(hw, BIT(4), 0); +			reg_rcr &= ~(RCR_CBSSID_DATA | RCR_CBSSID_BCN); +			tmp = BIT(4);  		} else { -			reg_rcr &= (~RCR_CBSSID); -			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, -						      (u8 *)(®_rcr)); -			_rtl92cu_set_bcn_ctrl_reg(hw, (BIT(4)|BIT(5)), 0); +			reg_rcr &= ~RCR_CBSSID; +			tmp = BIT(4) | BIT(5);  		} +		reg_rcr &= (~(RCR_CBSSID_DATA | RCR_CBSSID_BCN)); +		rtlpriv->cfg->ops->set_hw_reg(hw, +					      HW_VAR_RCR, (u8 *) (®_rcr)); +		_rtl92cu_set_bcn_ctrl_reg(hw, tmp, 0);  	}  } +/*========================================================================== */ +  int rtl92cu_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type)  { +	struct rtl_priv *rtlpriv = rtl_priv(hw); +  	if (_rtl92cu_set_media_status(hw, type))  		return -EOPNOTSUPP; -	_rtl92cu_set_check_bssid(hw, type); + +	if (rtlpriv->mac80211.link_state == MAC80211_LINKED) { +		if (type != NL80211_IFTYPE_AP) +			rtl92cu_set_check_bssid(hw, true); +	} else { +		rtl92cu_set_check_bssid(hw, false); +	} +  	return 0;  } @@ -2058,8 +2041,6 @@ void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw,  			       (shortgi_rate << 4) | (shortgi_rate);  	}  	rtl_write_dword(rtlpriv, REG_ARFR0 + ratr_index * 4, ratr_value); -	RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, "%x\n", -		 rtl_read_dword(rtlpriv, REG_ARFR0));  }  void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level) diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index 156b52732f3..5847d6d0881 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -851,6 +851,7 @@ static void _rtl_usb_transmit(struct ieee80211_hw *hw, struct sk_buff *skb,  	if (unlikely(!_urb)) {  		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,  			 "Can't allocate urb. Drop skb!\n"); +		kfree_skb(skb);  		return;  	}  	_rtl_submit_tx_urb(hw, _urb);  |