diff options
Diffstat (limited to 'drivers/net/wireless/p54')
| -rw-r--r-- | drivers/net/wireless/p54/Kconfig | 9 | ||||
| -rw-r--r-- | drivers/net/wireless/p54/eeprom.c | 346 | ||||
| -rw-r--r-- | drivers/net/wireless/p54/eeprom.h | 19 | ||||
| -rw-r--r-- | drivers/net/wireless/p54/fwio.c | 62 | ||||
| -rw-r--r-- | drivers/net/wireless/p54/led.c | 1 | ||||
| -rw-r--r-- | drivers/net/wireless/p54/lmac.h | 6 | ||||
| -rw-r--r-- | drivers/net/wireless/p54/main.c | 250 | ||||
| -rw-r--r-- | drivers/net/wireless/p54/net2280.h | 3 | ||||
| -rw-r--r-- | drivers/net/wireless/p54/p54.h | 28 | ||||
| -rw-r--r-- | drivers/net/wireless/p54/p54pci.c | 179 | ||||
| -rw-r--r-- | drivers/net/wireless/p54/p54pci.h | 2 | ||||
| -rw-r--r-- | drivers/net/wireless/p54/p54spi.c | 82 | ||||
| -rw-r--r-- | drivers/net/wireless/p54/p54spi_eeprom.h | 9 | ||||
| -rw-r--r-- | drivers/net/wireless/p54/p54usb.c | 251 | ||||
| -rw-r--r-- | drivers/net/wireless/p54/p54usb.h | 3 | ||||
| -rw-r--r-- | drivers/net/wireless/p54/txrx.c | 131 | 
16 files changed, 1009 insertions, 372 deletions
diff --git a/drivers/net/wireless/p54/Kconfig b/drivers/net/wireless/p54/Kconfig index 25f965ffc88..cdafb8c73e8 100644 --- a/drivers/net/wireless/p54/Kconfig +++ b/drivers/net/wireless/p54/Kconfig @@ -1,6 +1,6 @@  config P54_COMMON  	tristate "Softmac Prism54 support" -	depends on MAC80211 && EXPERIMENTAL +	depends on MAC80211  	select FW_LOADER  	select CRC_CCITT  	---help--- @@ -41,11 +41,10 @@ config P54_PCI  config P54_SPI  	tristate "Prism54 SPI (stlc45xx) support" -	depends on P54_COMMON && SPI_MASTER && GENERIC_HARDIRQS +	depends on P54_COMMON && SPI_MASTER  	---help--- -	  This driver is for stlc4550 or stlc4560 based wireless chips. -	  This driver is experimental, untested and will probably only work on -	  Nokia's N800/N810 Portable Internet Tablet. +	  This driver is for stlc4550 or stlc4560 based wireless chips +	  such as Nokia's N800/N810 Portable Internet Tablet.  	  If you choose to build a module, it'll be called p54spi. diff --git a/drivers/net/wireless/p54/eeprom.c b/drivers/net/wireless/p54/eeprom.c index 35b09aa0529..0fe67d2da20 100644 --- a/drivers/net/wireless/p54/eeprom.c +++ b/drivers/net/wireless/p54/eeprom.c @@ -16,7 +16,6 @@   * published by the Free Software Foundation.   */ -#include <linux/init.h>  #include <linux/firmware.h>  #include <linux/etherdevice.h>  #include <linux/sort.h> @@ -24,6 +23,7 @@  #include <net/mac80211.h>  #include <linux/crc-ccitt.h> +#include <linux/export.h>  #include "p54.h"  #include "eeprom.h" @@ -55,6 +55,17 @@ static struct ieee80211_rate p54_arates[] = {  	{ .bitrate = 540, .hw_value = 11, },  }; +static struct p54_rssi_db_entry p54_rssi_default = { +	/* +	 * The defaults are taken from usb-logs of the +	 * vendor driver. So, they should be safe to +	 * use in case we can't get a match from the +	 * rssi <-> dBm conversion database. +	 */ +	.mul = 130, +	.add = -398, +}; +  #define CHAN_HAS_CAL		BIT(0)  #define CHAN_HAS_LIMIT		BIT(1)  #define CHAN_HAS_CURVE		BIT(2) @@ -64,6 +75,7 @@ struct p54_channel_entry {  	u16 freq;  	u16 data;  	int index; +	int max_power;  	enum ieee80211_band band;  }; @@ -87,13 +99,27 @@ static int p54_get_band_from_freq(u16 freq)  	return -1;  } +static int same_band(u16 freq, u16 freq2) +{ +	return p54_get_band_from_freq(freq) == p54_get_band_from_freq(freq2); +} +  static int p54_compare_channels(const void *_a,  				const void *_b)  {  	const struct p54_channel_entry *a = _a;  	const struct p54_channel_entry *b = _b; -	return a->index - b->index; +	return a->freq - b->freq; +} + +static int p54_compare_rssichan(const void *_a, +				const void *_b) +{ +	const struct p54_rssi_db_entry *a = _a; +	const struct p54_rssi_db_entry *b = _b; + +	return a->freq - b->freq;  }  static int p54_fill_band_bitrates(struct ieee80211_hw *dev, @@ -120,6 +146,7 @@ static int p54_fill_band_bitrates(struct ieee80211_hw *dev,  static int p54_generate_band(struct ieee80211_hw *dev,  			     struct p54_channel_list *list, +			     unsigned int *chan_num,  			     enum ieee80211_band band)  {  	struct p54_common *priv = dev->priv; @@ -145,26 +172,36 @@ static int p54_generate_band(struct ieee80211_hw *dev,  	for (i = 0, j = 0; (j < list->band_channel_num[band]) &&  			   (i < list->entries); i++) { +		struct p54_channel_entry *chan = &list->channels[i]; +		struct ieee80211_channel *dest = &tmp->channels[j]; -		if (list->channels[i].band != band) +		if (chan->band != band)  			continue; -		if (list->channels[i].data != CHAN_HAS_ALL) { -			wiphy_err(dev->wiphy, -				  "%s%s%s is/are missing for channel:%d [%d MHz].\n", -				  (list->channels[i].data & CHAN_HAS_CAL ? "" : +		if (chan->data != CHAN_HAS_ALL) { +			wiphy_err(dev->wiphy, "%s%s%s is/are missing for " +				  "channel:%d [%d MHz].\n", +				  (chan->data & CHAN_HAS_CAL ? "" :  				   " [iqauto calibration data]"), -				  (list->channels[i].data & CHAN_HAS_LIMIT ? "" : +				  (chan->data & CHAN_HAS_LIMIT ? "" :  				   " [output power limits]"), -				  (list->channels[i].data & CHAN_HAS_CURVE ? "" : +				  (chan->data & CHAN_HAS_CURVE ? "" :  				   " [curve data]"), -				  list->channels[i].index, list->channels[i].freq); +				  chan->index, chan->freq);  			continue;  		} -		tmp->channels[j].band = list->channels[i].band; -		tmp->channels[j].center_freq = list->channels[i].freq; +		dest->band = chan->band; +		dest->center_freq = chan->freq; +		dest->max_power = chan->max_power; +		priv->survey[*chan_num].channel = &tmp->channels[j]; +		priv->survey[*chan_num].filled = SURVEY_INFO_NOISE_DBM | +			SURVEY_INFO_CHANNEL_TIME | +			SURVEY_INFO_CHANNEL_TIME_BUSY | +			SURVEY_INFO_CHANNEL_TIME_TX; +		dest->hw_value = (*chan_num);  		j++; +		(*chan_num)++;  	}  	if (j == 0) { @@ -194,10 +231,11 @@ err_out:  	return ret;  } -static void p54_update_channel_param(struct p54_channel_list *list, -				     u16 freq, u16 data) +static struct p54_channel_entry *p54_update_channel_param(struct p54_channel_list *list, +							  u16 freq, u16 data)  { -	int band, i; +	int i; +	struct p54_channel_entry *entry = NULL;  	/*  	 * usually all lists in the eeprom are mostly sorted. @@ -206,30 +244,78 @@ static void p54_update_channel_param(struct p54_channel_list *list,  	 */  	for (i = list->entries; i >= 0; i--) {  		if (freq == list->channels[i].freq) { -			list->channels[i].data |= data; +			entry = &list->channels[i];  			break;  		}  	}  	if ((i < 0) && (list->entries < list->max_entries)) {  		/* entry does not exist yet. Initialize a new one. */ -		band = p54_get_band_from_freq(freq); +		int band = p54_get_band_from_freq(freq);  		/*  		 * filter out frequencies which don't belong into  		 * any supported band.  		 */ -		if (band < 0) -			return ; +		if (band >= 0) { +			i = list->entries++; +			list->band_channel_num[band]++; + +			entry = &list->channels[i]; +			entry->freq = freq; +			entry->band = band; +			entry->index = ieee80211_frequency_to_channel(freq); +			entry->max_power = 0; +			entry->data = 0; +		} +	} + +	if (entry) +		entry->data |= data; -		i = list->entries++; -		list->band_channel_num[band]++; +	return entry; +} -		list->channels[i].freq = freq; -		list->channels[i].data = data; -		list->channels[i].band = band; -		list->channels[i].index = ieee80211_frequency_to_channel(freq); -		/* TODO: parse output_limit and fill max_power */ +static int p54_get_maxpower(struct p54_common *priv, void *data) +{ +	switch (priv->rxhw & PDR_SYNTH_FRONTEND_MASK) { +	case PDR_SYNTH_FRONTEND_LONGBOW: { +		struct pda_channel_output_limit_longbow *pda = data; +		int j; +		u16 rawpower = 0; +		pda = data; +		for (j = 0; j < ARRAY_SIZE(pda->point); j++) { +			struct pda_channel_output_limit_point_longbow *point = +				&pda->point[j]; +			rawpower = max_t(u16, +				rawpower, le16_to_cpu(point->val_qpsk)); +			rawpower = max_t(u16, +				rawpower, le16_to_cpu(point->val_bpsk)); +			rawpower = max_t(u16, +				rawpower, le16_to_cpu(point->val_16qam)); +			rawpower = max_t(u16, +				rawpower, le16_to_cpu(point->val_64qam)); +		} +		/* longbow seems to use 1/16 dBm units */ +		return rawpower / 16; +		} + +	case PDR_SYNTH_FRONTEND_DUETTE3: +	case PDR_SYNTH_FRONTEND_DUETTE2: +	case PDR_SYNTH_FRONTEND_FRISBEE: +	case PDR_SYNTH_FRONTEND_XBOW: { +		struct pda_channel_output_limit *pda = data; +		u8 rawpower = 0; +		rawpower = max(rawpower, pda->val_qpsk); +		rawpower = max(rawpower, pda->val_bpsk); +		rawpower = max(rawpower, pda->val_16qam); +		rawpower = max(rawpower, pda->val_64qam); +		/* raw values are in 1/4 dBm units */ +		return rawpower / 4; +		} + +	default: +		return 20;  	}  } @@ -237,7 +323,7 @@ static int p54_generate_channel_lists(struct ieee80211_hw *dev)  {  	struct p54_common *priv = dev->priv;  	struct p54_channel_list *list; -	unsigned int i, j, max_channel_num; +	unsigned int i, j, k, max_channel_num;  	int ret = 0;  	u16 freq; @@ -257,6 +343,13 @@ static int p54_generate_channel_lists(struct ieee80211_hw *dev)  		ret = -ENOMEM;  		goto free;  	} +	priv->chan_num = max_channel_num; +	priv->survey = kzalloc(sizeof(struct survey_info) * max_channel_num, +			       GFP_KERNEL); +	if (!priv->survey) { +		ret = -ENOMEM; +		goto free; +	}  	list->max_entries = max_channel_num;  	list->channels = kzalloc(sizeof(struct p54_channel_entry) * @@ -273,12 +366,19 @@ static int p54_generate_channel_lists(struct ieee80211_hw *dev)  		}  		if (i < priv->output_limit->entries) { -			freq = le16_to_cpup((__le16 *) (i * -					    priv->output_limit->entry_size + -					    priv->output_limit->offset + -					    priv->output_limit->data)); - -			p54_update_channel_param(list, freq, CHAN_HAS_LIMIT); +			struct p54_channel_entry *tmp; + +			void *data = (void *) ((unsigned long) i * +				priv->output_limit->entry_size + +				priv->output_limit->offset + +				priv->output_limit->data); + +			freq = le16_to_cpup((__le16 *) data); +			tmp = p54_update_channel_param(list, freq, +						       CHAN_HAS_LIMIT); +			if (tmp) { +				tmp->max_power = p54_get_maxpower(priv, data); +			}  		}  		if (i < priv->curve_data->entries) { @@ -291,12 +391,13 @@ static int p54_generate_channel_lists(struct ieee80211_hw *dev)  		}  	} -	/* sort the list by the channel index */ +	/* sort the channel list by frequency */  	sort(list->channels, list->entries, sizeof(struct p54_channel_entry),  	     p54_compare_channels, NULL); +	k = 0;  	for (i = 0, j = 0; i < IEEE80211_NUM_BANDS; i++) { -		if (p54_generate_band(dev, list, i) == 0) +		if (p54_generate_band(dev, list, &k, i) == 0)  			j++;  	}  	if (j == 0) { @@ -309,6 +410,10 @@ free:  		kfree(list->channels);  		kfree(list);  	} +	if (ret) { +		kfree(priv->survey); +		priv->survey = NULL; +	}  	return ret;  } @@ -410,33 +515,122 @@ static int p54_convert_rev1(struct ieee80211_hw *dev,  static const char *p54_rf_chips[] = { "INVALID-0", "Duette3", "Duette2",  	"Frisbee", "Xbow", "Longbow", "INVALID-6", "INVALID-7" }; -static void p54_parse_rssical(struct ieee80211_hw *dev, void *data, int len, -			     u16 type) +static int p54_parse_rssical(struct ieee80211_hw *dev, +			     u8 *data, int len, u16 type)  {  	struct p54_common *priv = dev->priv; -	int offset = (type == PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED) ? 2 : 0; -	int entry_size = sizeof(struct pda_rssi_cal_entry) + offset; -	int num_entries = (type == PDR_RSSI_LINEAR_APPROXIMATION) ? 1 : 2; -	int i; +	struct p54_rssi_db_entry *entry; +	size_t db_len, entries; +	int offset = 0, i; + +	if (type != PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED) { +		entries = (type == PDR_RSSI_LINEAR_APPROXIMATION) ? 1 : 2; +		if (len != sizeof(struct pda_rssi_cal_entry) * entries) { +			wiphy_err(dev->wiphy, "rssical size mismatch.\n"); +			goto err_data; +		} +	} else { +		/* +		 * Some devices (Dell 1450 USB, Xbow 5GHz card, etc...) +		 * have an empty two byte header. +		 */ +		if (*((__le16 *)&data[offset]) == cpu_to_le16(0)) +			offset += 2; -	if (len != (entry_size * num_entries)) { -		wiphy_err(dev->wiphy, -			  "unknown rssi calibration data packing type:(%x) len:%d.\n", -			  type, len); +		entries = (len - offset) / +			sizeof(struct pda_rssi_cal_ext_entry); -		print_hex_dump_bytes("rssical:", DUMP_PREFIX_NONE, -				     data, len); +		if (len < offset || +		    (len - offset) % sizeof(struct pda_rssi_cal_ext_entry) || +		    entries == 0) { +			wiphy_err(dev->wiphy, "invalid rssi database.\n"); +			goto err_data; +		} +	} -		wiphy_err(dev->wiphy, "please report this issue.\n"); -		return; +	db_len = sizeof(*entry) * entries; +	priv->rssi_db = kzalloc(db_len + sizeof(*priv->rssi_db), GFP_KERNEL); +	if (!priv->rssi_db) +		return -ENOMEM; + +	priv->rssi_db->offset = 0; +	priv->rssi_db->entries = entries; +	priv->rssi_db->entry_size = sizeof(*entry); +	priv->rssi_db->len = db_len; + +	entry = (void *)((unsigned long)priv->rssi_db->data + priv->rssi_db->offset); +	if (type == PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED) { +		struct pda_rssi_cal_ext_entry *cal = (void *) &data[offset]; + +		for (i = 0; i < entries; i++) { +			entry[i].freq = le16_to_cpu(cal[i].freq); +			entry[i].mul = (s16) le16_to_cpu(cal[i].mul); +			entry[i].add = (s16) le16_to_cpu(cal[i].add); +		} +	} else { +		struct pda_rssi_cal_entry *cal = (void *) &data[offset]; + +		for (i = 0; i < entries; i++) { +			u16 freq = 0; +			switch (i) { +			case IEEE80211_BAND_2GHZ: +				freq = 2437; +				break; +			case IEEE80211_BAND_5GHZ: +				freq = 5240; +				break; +			} + +			entry[i].freq = freq; +			entry[i].mul = (s16) le16_to_cpu(cal[i].mul); +			entry[i].add = (s16) le16_to_cpu(cal[i].add); +		}  	} -	for (i = 0; i < num_entries; i++) { -		struct pda_rssi_cal_entry *cal = data + -						 (offset + i * entry_size); -		priv->rssical_db[i].mul = (s16) le16_to_cpu(cal->mul); -		priv->rssical_db[i].add = (s16) le16_to_cpu(cal->add); +	/* sort the list by channel frequency */ +	sort(entry, entries, sizeof(*entry), p54_compare_rssichan, NULL); +	return 0; + +err_data: +	wiphy_err(dev->wiphy, +		  "rssi calibration data packing type:(%x) len:%d.\n", +		  type, len); + +	print_hex_dump_bytes("rssical:", DUMP_PREFIX_NONE, data, len); + +	wiphy_err(dev->wiphy, "please report this issue.\n"); +	return -EINVAL; +} + +struct p54_rssi_db_entry *p54_rssi_find(struct p54_common *priv, const u16 freq) +{ +	struct p54_rssi_db_entry *entry; +	int i, found = -1; + +	if (!priv->rssi_db) +		return &p54_rssi_default; + +	entry = (void *)(priv->rssi_db->data + priv->rssi_db->offset); +	for (i = 0; i < priv->rssi_db->entries; i++) { +		if (!same_band(freq, entry[i].freq)) +			continue; + +		if (found == -1) { +			found = i; +			continue; +		} + +		/* nearest match */ +		if (abs(freq - entry[i].freq) < +		    abs(freq - entry[found].freq)) { +			found = i; +			continue; +		} else { +			break; +		}  	} + +	return found < 0 ? &p54_rssi_default : &entry[found];  }  static void p54_parse_default_country(struct ieee80211_hw *dev, @@ -627,21 +821,30 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)  		case PDR_RSSI_LINEAR_APPROXIMATION:  		case PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND:  		case PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED: -			p54_parse_rssical(dev, entry->data, data_len, -					  le16_to_cpu(entry->code)); +			err = p54_parse_rssical(dev, entry->data, data_len, +						le16_to_cpu(entry->code)); +			if (err) +				goto err;  			break; -		case PDR_RSSI_LINEAR_APPROXIMATION_CUSTOM: { -			__le16 *src = (void *) entry->data; -			s16 *dst = (void *) &priv->rssical_db; +		case PDR_RSSI_LINEAR_APPROXIMATION_CUSTOMV2: { +			struct pda_custom_wrapper *pda = (void *) entry->data; +			__le16 *src; +			u16 *dst;  			int i; -			if (data_len != sizeof(priv->rssical_db)) { -				err = -EINVAL; -				goto err; -			} -			for (i = 0; i < sizeof(priv->rssical_db) / -					sizeof(*src); i++) +			if (priv->rssi_db || data_len < sizeof(*pda)) +				break; + +			priv->rssi_db = p54_convert_db(pda, data_len); +			if (!priv->rssi_db) +				break; + +			src = (void *) priv->rssi_db->data; +			dst = (void *) priv->rssi_db->data; + +			for (i = 0; i < priv->rssi_db->entries; i++)  				*(dst++) = (s16) le16_to_cpu(*(src++)); +  			}  			break;  		case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM: { @@ -690,11 +893,12 @@ good_eeprom:  		goto err;  	} +	priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK; +  	err = p54_generate_channel_lists(dev);  	if (err)  		goto err; -	priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK;  	if (priv->rxhw == PDR_SYNTH_FRONTEND_XBOW)  		p54_init_xbow_synth(priv);  	if (!(synth & PDR_SYNTH_24_GHZ_DISABLED)) @@ -713,10 +917,12 @@ good_eeprom:  		wiphy_warn(dev->wiphy,  			   "Invalid hwaddr! Using randomly generated MAC addr\n"); -		random_ether_addr(perm_addr); +		eth_random_addr(perm_addr);  		SET_IEEE80211_PERM_ADDR(dev, perm_addr);  	} +	priv->cur_rssi = &p54_rssi_default; +  	wiphy_info(dev->wiphy, "hwaddr %pM, MAC:isl38%02x RF:%s\n",  		   dev->wiphy->perm_addr, priv->version,  		   p54_rf_chips[priv->rxhw]); @@ -727,9 +933,13 @@ err:  	kfree(priv->iq_autocal);  	kfree(priv->output_limit);  	kfree(priv->curve_data); +	kfree(priv->rssi_db); +	kfree(priv->survey);  	priv->iq_autocal = NULL;  	priv->output_limit = NULL;  	priv->curve_data = NULL; +	priv->rssi_db = NULL; +	priv->survey = NULL;  	wiphy_err(dev->wiphy, "eeprom parse failed!\n");  	return err; @@ -755,7 +965,7 @@ int p54_read_eeprom(struct ieee80211_hw *dev)  	while (eeprom_size) {  		blocksize = min(eeprom_size, maxblocksize); -		ret = p54_download_eeprom(priv, (void *) (eeprom + offset), +		ret = p54_download_eeprom(priv, eeprom + offset,  					  offset, blocksize);  		if (unlikely(ret))  			goto free; diff --git a/drivers/net/wireless/p54/eeprom.h b/drivers/net/wireless/p54/eeprom.h index 9051aef1124..20ebe39a3f4 100644 --- a/drivers/net/wireless/p54/eeprom.h +++ b/drivers/net/wireless/p54/eeprom.h @@ -57,6 +57,18 @@ struct pda_channel_output_limit {  	u8 rate_set_size;  } __packed; +struct pda_channel_output_limit_point_longbow { +	__le16 val_bpsk; +	__le16 val_qpsk; +	__le16 val_16qam; +	__le16 val_64qam; +} __packed; + +struct pda_channel_output_limit_longbow { +	__le16 freq; +	struct pda_channel_output_limit_point_longbow point[3]; +} __packed; +  struct pda_pa_curve_data_sample_rev0 {  	u8 rf_power;  	u8 pa_detector; @@ -81,6 +93,12 @@ struct pda_pa_curve_data {  	u8 data[0];  } __packed; +struct pda_rssi_cal_ext_entry { +	__le16 freq; +	__le16 mul; +	__le16 add; +} __packed; +  struct pda_rssi_cal_entry {  	__le16 mul;  	__le16 add; @@ -179,6 +197,7 @@ struct pda_custom_wrapper {  /* used by our modificated eeprom image */  #define PDR_RSSI_LINEAR_APPROXIMATION_CUSTOM		0xDEAD +#define PDR_RSSI_LINEAR_APPROXIMATION_CUSTOMV2		0xCAFF  #define PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM	0xBEEF  #define PDR_PRISM_PA_CAL_CURVE_DATA_CUSTOM		0xB05D diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c index 92b9b1f05fd..bc065e8e348 100644 --- a/drivers/net/wireless/p54/fwio.c +++ b/drivers/net/wireless/p54/fwio.c @@ -16,10 +16,10 @@   * published by the Free Software Foundation.   */ -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/firmware.h>  #include <linux/etherdevice.h> +#include <linux/export.h>  #include <net/mac80211.h> @@ -385,6 +385,7 @@ int p54_setup_mac(struct p54_common *priv)  		setup->v2.osc_start_delay = cpu_to_le16(65535);  	}  	p54_tx(priv, skb); +	priv->phy_idle = mode == P54_FILTER_TYPE_HIBERNATE;  	return 0;  } @@ -397,10 +398,10 @@ int p54_scan(struct p54_common *priv, u16 mode, u16 dwell)  	union p54_scan_body_union *body;  	struct p54_scan_tail_rate *rate;  	struct pda_rssi_cal_entry *rssi; +	struct p54_rssi_db_entry *rssi_data;  	unsigned int i;  	void *entry; -	int band = priv->hw->conf.channel->band; -	__le16 freq = cpu_to_le16(priv->hw->conf.channel->center_freq); +	__le16 freq = cpu_to_le16(priv->hw->conf.chandef.chan->center_freq);  	skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*head) +  			    2 + sizeof(*iq_autocal) + sizeof(*body) + @@ -476,7 +477,7 @@ int p54_scan(struct p54_common *priv, u16 mode, u16 dwell)  		if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {  			memcpy(&body->longbow.curve_data, -				(void *) entry + sizeof(__le16), +				entry + sizeof(__le16),  				priv->curve_data->entry_size);  		} else {  			struct p54_scan_body *chan = &body->normal; @@ -503,13 +504,14 @@ int p54_scan(struct p54_common *priv, u16 mode, u16 dwell)  	}  	rssi = (struct pda_rssi_cal_entry *) skb_put(skb, sizeof(*rssi)); -	rssi->mul = cpu_to_le16(priv->rssical_db[band].mul); -	rssi->add = cpu_to_le16(priv->rssical_db[band].add); +	rssi_data = p54_rssi_find(priv, le16_to_cpu(freq)); +	rssi->mul = cpu_to_le16(rssi_data->mul); +	rssi->add = cpu_to_le16(rssi_data->add);  	if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {  		/* Longbow frontend needs ever more */  		rssi = (void *) skb_put(skb, sizeof(*rssi)); -		rssi->mul = cpu_to_le16(priv->rssical_db[band].longbow_unkn); -		rssi->add = cpu_to_le16(priv->rssical_db[band].longbow_unk2); +		rssi->mul = cpu_to_le16(rssi_data->longbow_unkn); +		rssi->add = cpu_to_le16(rssi_data->longbow_unk2);  	}  	if (priv->fw_var >= 0x509) { @@ -523,12 +525,13 @@ int p54_scan(struct p54_common *priv, u16 mode, u16 dwell)  	hdr->len = cpu_to_le16(skb->len - sizeof(*hdr));  	p54_tx(priv, skb); +	priv->cur_rssi = rssi_data;  	return 0;  err:  	wiphy_err(priv->hw->wiphy, "frequency change to channel %d failed.\n",  		  ieee80211_frequency_to_channel( -			  priv->hw->conf.channel->center_freq)); +			  priv->hw->conf.chandef.chan->center_freq));  	dev_kfree_skb_any(skb);  	return -EINVAL; @@ -557,6 +560,7 @@ int p54_set_edcf(struct p54_common *priv)  {  	struct sk_buff *skb;  	struct p54_edcf *edcf; +	u8 rtd;  	skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*edcf),  			    P54_CONTROL_TYPE_DCFINIT, GFP_ATOMIC); @@ -573,9 +577,15 @@ int p54_set_edcf(struct p54_common *priv)  		edcf->sifs = 0x0a;  		edcf->eofpad = 0x06;  	} +	/* +	 * calculate the extra round trip delay according to the +	 * formula from 802.11-2007 17.3.8.6. +	 */ +	rtd = 3 * priv->coverage_class; +	edcf->slottime += rtd; +	edcf->round_trip_delay = cpu_to_le16(rtd);  	/* (see prism54/isl_oid.h for further details) */  	edcf->frameburst = cpu_to_le16(0); -	edcf->round_trip_delay = cpu_to_le16(0);  	edcf->flags = 0;  	memset(edcf->mapping, 0, sizeof(edcf->mapping));  	memcpy(edcf->queue, priv->qos_params, sizeof(edcf->queue)); @@ -617,6 +627,7 @@ int p54_set_ps(struct p54_common *priv)  	psm->exclude[0] = WLAN_EID_TIM;  	p54_tx(priv, skb); +	priv->phy_ps = mode != P54_PSM_CAM;  	return 0;  } @@ -718,3 +729,34 @@ int p54_fetch_statistics(struct p54_common *priv)  	p54_tx(priv, skb);  	return 0;  } + +int p54_set_groupfilter(struct p54_common *priv) +{ +	struct p54_group_address_table *grp; +	struct sk_buff *skb; +	bool on = false; + +	skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*grp), +			    P54_CONTROL_TYPE_GROUP_ADDRESS_TABLE, GFP_KERNEL); +	if (!skb) +		return -ENOMEM; + +	grp = (struct p54_group_address_table *)skb_put(skb, sizeof(*grp)); + +	on = !(priv->filter_flags & FIF_ALLMULTI) && +	     (priv->mc_maclist_num > 0 && +	      priv->mc_maclist_num <= MC_FILTER_ADDRESS_NUM); + +	if (on) { +		grp->filter_enable = cpu_to_le16(1); +		grp->num_address = cpu_to_le16(priv->mc_maclist_num); +		memcpy(grp->mac_list, priv->mc_maclist, sizeof(grp->mac_list)); +	} else { +		grp->filter_enable = cpu_to_le16(0); +		grp->num_address = cpu_to_le16(0); +		memset(grp->mac_list, 0, sizeof(grp->mac_list)); +	} + +	p54_tx(priv, skb); +	return 0; +} diff --git a/drivers/net/wireless/p54/led.c b/drivers/net/wireless/p54/led.c index 3837e1eec5f..1f6fd5ff553 100644 --- a/drivers/net/wireless/p54/led.c +++ b/drivers/net/wireless/p54/led.c @@ -16,7 +16,6 @@   * published by the Free Software Foundation.   */ -#include <linux/init.h>  #include <linux/firmware.h>  #include <linux/etherdevice.h> diff --git a/drivers/net/wireless/p54/lmac.h b/drivers/net/wireless/p54/lmac.h index 04b63ec80fa..de1d46bf97d 100644 --- a/drivers/net/wireless/p54/lmac.h +++ b/drivers/net/wireless/p54/lmac.h @@ -526,7 +526,9 @@ int p54_init_leds(struct p54_common *priv);  void p54_unregister_leds(struct p54_common *priv);  /* xmit functions */ -int p54_tx_80211(struct ieee80211_hw *dev, struct sk_buff *skb); +void p54_tx_80211(struct ieee80211_hw *dev, +		  struct ieee80211_tx_control *control, +		  struct sk_buff *skb);  int p54_tx_cancel(struct p54_common *priv, __le32 req_id);  void p54_tx(struct p54_common *priv, struct sk_buff *skb); @@ -540,6 +542,7 @@ int p54_update_beacon_tim(struct p54_common *priv, u16 aid, bool set);  int p54_setup_mac(struct p54_common *priv);  int p54_set_ps(struct p54_common *priv);  int p54_fetch_statistics(struct p54_common *priv); +int p54_set_groupfilter(struct p54_common *priv);  /* e/v DCF setup */  int p54_set_edcf(struct p54_common *priv); @@ -551,6 +554,7 @@ int p54_upload_key(struct p54_common *priv, u8 algo, int slot,  /* eeprom */  int p54_download_eeprom(struct p54_common *priv, void *buf,  			u16 offset, u16 len); +struct p54_rssi_db_entry *p54_rssi_find(struct p54_common *p, const u16 freq);  /* utility */  u8 *p54_find_ie(struct sk_buff *skb, u8 ie); diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index 622d27b6d8f..7be3a483964 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c @@ -16,17 +16,17 @@   * published by the Free Software Foundation.   */ -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/firmware.h>  #include <linux/etherdevice.h> +#include <linux/module.h>  #include <net/mac80211.h>  #include "p54.h"  #include "lmac.h" -static int modparam_nohwcrypt; +static bool modparam_nohwcrypt;  module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);  MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");  MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>"); @@ -138,6 +138,7 @@ static int p54_beacon_format_ie_tim(struct sk_buff *skb)  static int p54_beacon_update(struct p54_common *priv,  			struct ieee80211_vif *vif)  { +	struct ieee80211_tx_control control = { };  	struct sk_buff *beacon;  	int ret; @@ -157,7 +158,7 @@ static int p54_beacon_update(struct p54_common *priv,  	 * to cancel the old beacon template by hand, instead the firmware  	 * will release the previous one through the feedback mechanism.  	 */ -	WARN_ON(p54_tx_80211(priv->hw, beacon)); +	p54_tx_80211(priv->hw, &control, beacon);  	priv->tsf_high32 = 0;  	priv->tsf_low32 = 0; @@ -204,13 +205,11 @@ static void p54_stop(struct ieee80211_hw *dev)  	struct p54_common *priv = dev->priv;  	int i; -	mutex_lock(&priv->conf_mutex);  	priv->mode = NL80211_IFTYPE_UNSPECIFIED;  	priv->softled_state = 0; -	p54_set_leds(priv); -  	cancel_delayed_work_sync(&priv->work); - +	mutex_lock(&priv->conf_mutex); +	p54_set_leds(priv);  	priv->stop(dev);  	skb_queue_purge(&priv->tx_pending);  	skb_queue_purge(&priv->tx_queue); @@ -228,6 +227,9 @@ static int p54_add_interface(struct ieee80211_hw *dev,  			     struct ieee80211_vif *vif)  {  	struct p54_common *priv = dev->priv; +	int err; + +	vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER;  	mutex_lock(&priv->conf_mutex);  	if (priv->mode != NL80211_IFTYPE_MONITOR) { @@ -250,9 +252,9 @@ static int p54_add_interface(struct ieee80211_hw *dev,  	}  	memcpy(priv->mac_addr, vif->addr, ETH_ALEN); -	p54_setup_mac(priv); +	err = p54_setup_mac(priv);  	mutex_unlock(&priv->conf_mutex); -	return 0; +	return err;  }  static void p54_remove_interface(struct ieee80211_hw *dev, @@ -278,6 +280,42 @@ static void p54_remove_interface(struct ieee80211_hw *dev,  	mutex_unlock(&priv->conf_mutex);  } +static int p54_wait_for_stats(struct ieee80211_hw *dev) +{ +	struct p54_common *priv = dev->priv; +	int ret; + +	priv->update_stats = true; +	ret = p54_fetch_statistics(priv); +	if (ret) +		return ret; + +	ret = wait_for_completion_interruptible_timeout(&priv->stat_comp, HZ); +	if (ret == 0) +		return -ETIMEDOUT; + +	return 0; +} + +static void p54_reset_stats(struct p54_common *priv) +{ +	struct ieee80211_channel *chan = priv->curchan; + +	if (chan) { +		struct survey_info *info = &priv->survey[chan->hw_value]; + +		/* only reset channel statistics, don't touch .filled, etc. */ +		info->channel_time = 0; +		info->channel_time_busy = 0; +		info->channel_time_tx = 0; +	} + +	priv->update_stats = true; +	priv->survey_raw.active = 0; +	priv->survey_raw.cca = 0; +	priv->survey_raw.tx = 0; +} +  static int p54_config(struct ieee80211_hw *dev, u32 changed)  {  	int ret = 0; @@ -288,19 +326,36 @@ static int p54_config(struct ieee80211_hw *dev, u32 changed)  	if (changed & IEEE80211_CONF_CHANGE_POWER)  		priv->output_power = conf->power_level << 2;  	if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { +		struct ieee80211_channel *oldchan; +		WARN_ON(p54_wait_for_stats(dev)); +		oldchan = priv->curchan; +		priv->curchan = NULL;  		ret = p54_scan(priv, P54_SCAN_EXIT, 0); -		if (ret) +		if (ret) { +			priv->curchan = oldchan;  			goto out; +		} +		/* +		 * TODO: Use the LM_SCAN_TRAP to determine the current +		 * operating channel. +		 */ +		priv->curchan = priv->hw->conf.chandef.chan; +		p54_reset_stats(priv); +		WARN_ON(p54_fetch_statistics(priv));  	}  	if (changed & IEEE80211_CONF_CHANGE_PS) { +		WARN_ON(p54_wait_for_stats(dev));  		ret = p54_set_ps(priv);  		if (ret)  			goto out; +		WARN_ON(p54_wait_for_stats(dev));  	}  	if (changed & IEEE80211_CONF_CHANGE_IDLE) { +		WARN_ON(p54_wait_for_stats(dev));  		ret = p54_setup_mac(priv);  		if (ret)  			goto out; +		WARN_ON(p54_wait_for_stats(dev));  	}  out: @@ -308,6 +363,31 @@ out:  	return ret;  } +static u64 p54_prepare_multicast(struct ieee80211_hw *dev, +				 struct netdev_hw_addr_list *mc_list) +{ +	struct p54_common *priv = dev->priv; +	struct netdev_hw_addr *ha; +	int i; + +	BUILD_BUG_ON(ARRAY_SIZE(priv->mc_maclist) != +		ARRAY_SIZE(((struct p54_group_address_table *)NULL)->mac_list)); +	/* +	 * The first entry is reserved for the global broadcast MAC. +	 * Otherwise the firmware will drop it and ARP will no longer work. +	 */ +	i = 1; +	priv->mc_maclist_num = netdev_hw_addr_list_count(mc_list) + i; +	netdev_hw_addr_list_for_each(ha, mc_list) { +		memcpy(&priv->mc_maclist[i], ha->addr, ETH_ALEN); +		i++; +		if (i >= ARRAY_SIZE(priv->mc_maclist)) +			break; +	} + +	return 1; /* update */ +} +  static void p54_configure_filter(struct ieee80211_hw *dev,  				 unsigned int changed_flags,  				 unsigned int *total_flags, @@ -316,15 +396,20 @@ static void p54_configure_filter(struct ieee80211_hw *dev,  	struct p54_common *priv = dev->priv;  	*total_flags &= FIF_PROMISC_IN_BSS | +			FIF_ALLMULTI |  			FIF_OTHER_BSS;  	priv->filter_flags = *total_flags;  	if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS))  		p54_setup_mac(priv); + +	if (changed_flags & FIF_ALLMULTI || multicast) +		p54_set_groupfilter(priv);  } -static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue, +static int p54_conf_tx(struct ieee80211_hw *dev, +		       struct ieee80211_vif *vif, u16 queue,  		       const struct ieee80211_tx_queue_params *params)  {  	struct p54_common *priv = dev->priv; @@ -355,7 +440,9 @@ static void p54_work(struct work_struct *work)  	 *      2. cancel stuck frames / reset the device if necessary.  	 */ -	p54_fetch_statistics(priv); +	mutex_lock(&priv->conf_mutex); +	WARN_ON_ONCE(p54_fetch_statistics(priv)); +	mutex_unlock(&priv->conf_mutex);  }  static int p54_get_stats(struct ieee80211_hw *dev, @@ -392,7 +479,7 @@ static void p54_bss_info_changed(struct ieee80211_hw *dev,  		p54_set_edcf(priv);  	}  	if (changed & BSS_CHANGED_BASIC_RATES) { -		if (dev->conf.channel->band == IEEE80211_BAND_5GHZ) +		if (dev->conf.chandef.chan->band == IEEE80211_BAND_5GHZ)  			priv->basic_rate_mask = (info->basic_rates << 4);  		else  			priv->basic_rate_mask = info->basic_rates; @@ -427,6 +514,17 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,  	if (modparam_nohwcrypt)  		return -EOPNOTSUPP; +	if (key->flags & IEEE80211_KEY_FLAG_RX_MGMT) { +		/* +		 * Unfortunately most/all firmwares are trying to decrypt +		 * incoming management frames if a suitable key can be found. +		 * However, in doing so the data in these frames gets +		 * corrupted. So, we can't have firmware supported crypto +		 * offload in this case. +		 */ +		return -EOPNOTSUPP; +	} +  	mutex_lock(&priv->conf_mutex);  	if (cmd == SET_KEY) {  		switch (key->cipher) { @@ -465,7 +563,7 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,  		if (slot < 0) {  			/* -			 * The device supports the choosen algorithm, but the +			 * The device supports the chosen algorithm, but the  			 * firmware does not provide enough key slots to store  			 * all of them.  			 * But encryption offload for outgoing frames is always @@ -512,16 +610,101 @@ static int p54_get_survey(struct ieee80211_hw *dev, int idx,  				struct survey_info *survey)  {  	struct p54_common *priv = dev->priv; -	struct ieee80211_conf *conf = &dev->conf; +	struct ieee80211_channel *chan; +	int err, tries; +	bool in_use = false; -	if (idx != 0) +	if (idx >= priv->chan_num)  		return -ENOENT; -	survey->channel = conf->channel; -	survey->filled = SURVEY_INFO_NOISE_DBM; -	survey->noise = clamp_t(s8, priv->noise, -128, 127); +#define MAX_TRIES 1 +	for (tries = 0; tries < MAX_TRIES; tries++) { +		chan = priv->curchan; +		if (chan && chan->hw_value == idx) { +			mutex_lock(&priv->conf_mutex); +			err = p54_wait_for_stats(dev); +			mutex_unlock(&priv->conf_mutex); +			if (err) +				return err; + +			in_use = true; +		} -	return 0; +		memcpy(survey, &priv->survey[idx], sizeof(*survey)); + +		if (in_use) { +			/* test if the reported statistics are valid. */ +			if  (survey->channel_time != 0) { +				survey->filled |= SURVEY_INFO_IN_USE; +			} else { +				/* +				 * hw/fw has not accumulated enough sample sets. +				 * Wait for 100ms, this ought to be enough to +				 * to get at least one non-null set of channel +				 * usage statistics. +				 */ +				msleep(100); +				continue; +			} +		} +		return 0; +	} +	return -ETIMEDOUT; +#undef MAX_TRIES +} + +static unsigned int p54_flush_count(struct p54_common *priv) +{ +	unsigned int total = 0, i; + +	BUILD_BUG_ON(P54_QUEUE_NUM > ARRAY_SIZE(priv->tx_stats)); + +	/* +	 * Because the firmware has the sole control over any frames +	 * in the P54_QUEUE_BEACON or P54_QUEUE_SCAN queues, they +	 * don't really count as pending or active. +	 */ +	for (i = P54_QUEUE_MGMT; i < P54_QUEUE_NUM; i++) +		total += priv->tx_stats[i].len; +	return total; +} + +static void p54_flush(struct ieee80211_hw *dev, struct ieee80211_vif *vif, +		      u32 queues, bool drop) +{ +	struct p54_common *priv = dev->priv; +	unsigned int total, i; + +	/* +	 * Currently, it wouldn't really matter if we wait for one second +	 * or 15 minutes. But once someone gets around and completes the +	 * TODOs [ancel stuck frames / reset device] in p54_work, it will +	 * suddenly make sense to wait that long. +	 */ +	i = P54_STATISTICS_UPDATE * 2 / 20; + +	/* +	 * In this case no locking is required because as we speak the +	 * queues have already been stopped and no new frames can sneak +	 * up from behind. +	 */ +	while ((total = p54_flush_count(priv) && i--)) { +		/* waste time */ +		msleep(20); +	} + +	WARN(total, "tx flush timeout, unresponsive firmware"); +} + +static void p54_set_coverage_class(struct ieee80211_hw *dev, u8 coverage_class) +{ +	struct p54_common *priv = dev->priv; + +	mutex_lock(&priv->conf_mutex); +	/* support all coverage class values as in 802.11-2007 Table 7-27 */ +	priv->coverage_class = clamp_t(u8, coverage_class, 0, 31); +	p54_set_edcf(priv); +	mutex_unlock(&priv->conf_mutex);  }  static const struct ieee80211_ops p54_ops = { @@ -536,11 +719,14 @@ static const struct ieee80211_ops p54_ops = {  	.sta_remove		= p54_sta_add_remove,  	.set_key		= p54_set_key,  	.config			= p54_config, +	.flush			= p54_flush,  	.bss_info_changed	= p54_bss_info_changed, +	.prepare_multicast	= p54_prepare_multicast,  	.configure_filter	= p54_configure_filter,  	.conf_tx		= p54_conf_tx,  	.get_stats		= p54_get_stats,  	.get_survey		= p54_get_survey, +	.set_coverage_class	= p54_set_coverage_class,  };  struct ieee80211_hw *p54_init_common(size_t priv_data_len) @@ -563,7 +749,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)  		     IEEE80211_HW_SIGNAL_DBM |  		     IEEE80211_HW_SUPPORTS_PS |  		     IEEE80211_HW_PS_NULLFUNC_STACK | -		     IEEE80211_HW_BEACON_FILTER | +		     IEEE80211_HW_MFP_CAPABLE |  		     IEEE80211_HW_REPORTS_TX_ACK_STATUS;  	dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | @@ -571,7 +757,6 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)  				      BIT(NL80211_IFTYPE_AP) |  				      BIT(NL80211_IFTYPE_MESH_POINT); -	dev->channel_change_time = 1000;	/* TODO: find actual value */  	priv->beacon_req_id = cpu_to_le32(0);  	priv->tx_stats[P54_QUEUE_BEACON].limit = 1;  	priv->tx_stats[P54_QUEUE_FWSCAN].limit = 1; @@ -601,17 +786,21 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)  	mutex_init(&priv->conf_mutex);  	mutex_init(&priv->eeprom_mutex); +	init_completion(&priv->stat_comp);  	init_completion(&priv->eeprom_comp);  	init_completion(&priv->beacon_comp);  	INIT_DELAYED_WORK(&priv->work, p54_work); +	memset(&priv->mc_maclist[0], ~0, ETH_ALEN); +	priv->curchan = NULL; +	p54_reset_stats(priv);  	return dev;  }  EXPORT_SYMBOL_GPL(p54_init_common);  int p54_register_common(struct ieee80211_hw *dev, struct device *pdev)  { -	struct p54_common *priv = dev->priv; +	struct p54_common __maybe_unused *priv = dev->priv;  	int err;  	err = ieee80211_register_hw(dev); @@ -619,11 +808,14 @@ int p54_register_common(struct ieee80211_hw *dev, struct device *pdev)  		dev_err(pdev, "Cannot register device (%d).\n", err);  		return err;  	} +	priv->registered = true;  #ifdef CONFIG_P54_LEDS  	err = p54_init_leds(priv); -	if (err) +	if (err) { +		p54_unregister_common(dev);  		return err; +	}  #endif /* CONFIG_P54_LEDS */  	dev_info(pdev, "is registered as '%s'\n", wiphy_name(dev->wiphy)); @@ -642,11 +834,15 @@ void p54_free_common(struct ieee80211_hw *dev)  	kfree(priv->iq_autocal);  	kfree(priv->output_limit);  	kfree(priv->curve_data); +	kfree(priv->rssi_db);  	kfree(priv->used_rxkeys); +	kfree(priv->survey);  	priv->iq_autocal = NULL;  	priv->output_limit = NULL;  	priv->curve_data = NULL; +	priv->rssi_db = NULL;  	priv->used_rxkeys = NULL; +	priv->survey = NULL;  	ieee80211_free_hw(dev);  }  EXPORT_SYMBOL_GPL(p54_free_common); @@ -659,7 +855,11 @@ void p54_unregister_common(struct ieee80211_hw *dev)  	p54_unregister_leds(priv);  #endif /* CONFIG_P54_LEDS */ -	ieee80211_unregister_hw(dev); +	if (priv->registered) { +		priv->registered = false; +		ieee80211_unregister_hw(dev); +	} +  	mutex_destroy(&priv->conf_mutex);  	mutex_destroy(&priv->eeprom_mutex);  } diff --git a/drivers/net/wireless/p54/net2280.h b/drivers/net/wireless/p54/net2280.h index e3ed893b5aa..aedfaf24f38 100644 --- a/drivers/net/wireless/p54/net2280.h +++ b/drivers/net/wireless/p54/net2280.h @@ -20,8 +20,7 @@   * GNU General Public License for more details.   *   * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + * along with this program; if not, see <http://www.gnu.org/licenses/>.   */  /*-------------------------------------------------------------------------*/ diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index 43a3b2ead81..40b401ed684 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -116,7 +116,8 @@ struct p54_edcf_queue_param {  	__le16 txop;  } __packed; -struct p54_rssi_linear_approximation { +struct p54_rssi_db_entry { +	u16 freq;  	s16 mul;  	s16 add;  	s16 longbow_unkn; @@ -172,6 +173,7 @@ struct p54_common {  	struct sk_buff_head tx_pending;  	struct sk_buff_head tx_queue;  	struct mutex conf_mutex; +	bool registered;  	/* memory management (as seen by the firmware) */  	u32 rx_start; @@ -197,24 +199,46 @@ struct p54_common {  	u8 rx_diversity_mask;  	u8 tx_diversity_mask;  	unsigned int output_power; +	struct p54_rssi_db_entry *cur_rssi; +	struct ieee80211_channel *curchan; +	struct survey_info *survey; +	unsigned int chan_num; +	struct completion stat_comp; +	bool update_stats; +	struct { +		unsigned int timestamp; +		unsigned int cached_cca; +		unsigned int cached_tx; +		unsigned int cached_rssi; +		u64 active; +		u64 cca; +		u64 tx; +		u64 rssi; +	} survey_raw; +  	int noise;  	/* calibration, output power limit and rssi<->dBm conversation data */  	struct pda_iq_autocal_entry *iq_autocal;  	unsigned int iq_autocal_len;  	struct p54_cal_database *curve_data;  	struct p54_cal_database *output_limit; -	struct p54_rssi_linear_approximation rssical_db[IEEE80211_NUM_BANDS]; +	struct p54_cal_database *rssi_db;  	struct ieee80211_supported_band *band_table[IEEE80211_NUM_BANDS];  	/* BBP/MAC state */  	u8 mac_addr[ETH_ALEN];  	u8 bssid[ETH_ALEN]; +	u8 mc_maclist[4][ETH_ALEN];  	u16 wakeup_timer;  	unsigned int filter_flags; +	int mc_maclist_num;  	int mode;  	u32 tsf_low32, tsf_high32;  	u32 basic_rate_mask;  	u16 aid; +	u8 coverage_class; +	bool phy_idle; +	bool phy_ps;  	bool powersave_override;  	__le32 beacon_req_id;  	struct completion beacon_comp; diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index 1eacba4daa5..d411de40905 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -13,13 +13,13 @@   * published by the Free Software Foundation.   */ -#include <linux/init.h>  #include <linux/pci.h>  #include <linux/slab.h>  #include <linux/firmware.h>  #include <linux/etherdevice.h>  #include <linux/delay.h>  #include <linux/completion.h> +#include <linux/module.h>  #include <net/mac80211.h>  #include "p54.h" @@ -199,6 +199,7 @@ static void p54p_check_rx_ring(struct ieee80211_hw *dev, u32 *index,  	while (i != idx) {  		u16 len;  		struct sk_buff *skb; +		dma_addr_t dma_addr;  		desc = &ring[i];  		len = le16_to_cpu(desc->len);  		skb = rx_buf[i]; @@ -216,17 +217,20 @@ static void p54p_check_rx_ring(struct ieee80211_hw *dev, u32 *index,  			len = priv->common.rx_mtu;  		} +		dma_addr = le32_to_cpu(desc->host_addr); +		pci_dma_sync_single_for_cpu(priv->pdev, dma_addr, +			priv->common.rx_mtu + 32, PCI_DMA_FROMDEVICE);  		skb_put(skb, len);  		if (p54_rx(dev, skb)) { -			pci_unmap_single(priv->pdev, -					 le32_to_cpu(desc->host_addr), -					 priv->common.rx_mtu + 32, -					 PCI_DMA_FROMDEVICE); +			pci_unmap_single(priv->pdev, dma_addr, +				priv->common.rx_mtu + 32, PCI_DMA_FROMDEVICE);  			rx_buf[i] = NULL; -			desc->host_addr = 0; +			desc->host_addr = cpu_to_le32(0);  		} else {  			skb_trim(skb, 0); +			pci_dma_sync_single_for_device(priv->pdev, dma_addr, +				priv->common.rx_mtu + 32, PCI_DMA_FROMDEVICE);  			desc->len = cpu_to_le16(priv->common.rx_mtu + 32);  		} @@ -327,10 +331,9 @@ static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb)  	struct p54p_ring_control *ring_control = priv->ring_control;  	struct p54p_desc *desc;  	dma_addr_t mapping; -	u32 device_idx, idx, i; +	u32 idx, i;  	spin_lock_irqsave(&priv->lock, flags); -	device_idx = le32_to_cpu(ring_control->device_idx[1]);  	idx = le32_to_cpu(ring_control->host_idx[1]);  	i = idx % ARRAY_SIZE(ring_control->tx_data); @@ -484,7 +487,59 @@ static int p54p_open(struct ieee80211_hw *dev)  	return 0;  } -static int __devinit p54p_probe(struct pci_dev *pdev, +static void p54p_firmware_step2(const struct firmware *fw, +				void *context) +{ +	struct p54p_priv *priv = context; +	struct ieee80211_hw *dev = priv->common.hw; +	struct pci_dev *pdev = priv->pdev; +	int err; + +	if (!fw) { +		dev_err(&pdev->dev, "Cannot find firmware (isl3886pci)\n"); +		err = -ENOENT; +		goto out; +	} + +	priv->firmware = fw; + +	err = p54p_open(dev); +	if (err) +		goto out; +	err = p54_read_eeprom(dev); +	p54p_stop(dev); +	if (err) +		goto out; + +	err = p54_register_common(dev, &pdev->dev); +	if (err) +		goto out; + +out: + +	complete(&priv->fw_loaded); + +	if (err) { +		struct device *parent = pdev->dev.parent; + +		if (parent) +			device_lock(parent); + +		/* +		 * This will indirectly result in a call to p54p_remove. +		 * Hence, we don't need to bother with freeing any +		 * allocated ressources at all. +		 */ +		device_release_driver(&pdev->dev); + +		if (parent) +			device_unlock(parent); +	} + +	pci_dev_put(pdev); +} + +static int p54p_probe(struct pci_dev *pdev,  				const struct pci_device_id *id)  {  	struct p54p_priv *priv; @@ -492,6 +547,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev,  	unsigned long mem_addr, mem_len;  	int err; +	pci_dev_get(pdev);  	err = pci_enable_device(pdev);  	if (err) {  		dev_err(&pdev->dev, "Cannot enable new PCI device\n"); @@ -502,6 +558,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev,  	mem_len = pci_resource_len(pdev, 0);  	if (mem_len < sizeof(struct p54p_csr)) {  		dev_err(&pdev->dev, "Too short PCI resources\n"); +		err = -ENODEV;  		goto err_disable_dev;  	} @@ -511,8 +568,10 @@ static int __devinit p54p_probe(struct pci_dev *pdev,  		goto err_disable_dev;  	} -	if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) || -	    pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) { +	err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); +	if (!err) +		err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); +	if (err) {  		dev_err(&pdev->dev, "No suitable DMA available\n");  		goto err_free_reg;  	} @@ -533,6 +592,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev,  	priv = dev->priv;  	priv->pdev = pdev; +	init_completion(&priv->fw_loaded);  	SET_IEEE80211_DEV(dev, &pdev->dev);  	pci_set_drvdata(pdev, dev); @@ -557,32 +617,12 @@ static int __devinit p54p_probe(struct pci_dev *pdev,  	spin_lock_init(&priv->lock);  	tasklet_init(&priv->tasklet, p54p_tasklet, (unsigned long)dev); -	err = request_firmware(&priv->firmware, "isl3886pci", -			       &priv->pdev->dev); -	if (err) { -		dev_err(&pdev->dev, "Cannot find firmware (isl3886pci)\n"); -		err = request_firmware(&priv->firmware, "isl3886", -				       &priv->pdev->dev); -		if (err) -			goto err_free_common; -	} - -	err = p54p_open(dev); -	if (err) -		goto err_free_common; -	err = p54_read_eeprom(dev); -	p54p_stop(dev); -	if (err) -		goto err_free_common; +	err = request_firmware_nowait(THIS_MODULE, 1, "isl3886pci", +				      &priv->pdev->dev, GFP_KERNEL, +				      priv, p54p_firmware_step2); +	if (!err) +		return 0; -	err = p54_register_common(dev, &pdev->dev); -	if (err) -		goto err_free_common; - -	return 0; - - err_free_common: -	release_firmware(priv->firmware);  	pci_free_consistent(pdev, sizeof(*priv->ring_control),  			    priv->ring_control, priv->ring_control_dma); @@ -590,17 +630,17 @@ static int __devinit p54p_probe(struct pci_dev *pdev,  	iounmap(priv->map);   err_free_dev: -	pci_set_drvdata(pdev, NULL);  	p54_free_common(dev);   err_free_reg:  	pci_release_regions(pdev);   err_disable_dev:  	pci_disable_device(pdev); +	pci_dev_put(pdev);  	return err;  } -static void __devexit p54p_remove(struct pci_dev *pdev) +static void p54p_remove(struct pci_dev *pdev)  {  	struct ieee80211_hw *dev = pci_get_drvdata(pdev);  	struct p54p_priv *priv; @@ -608,8 +648,9 @@ static void __devexit p54p_remove(struct pci_dev *pdev)  	if (!dev)  		return; -	p54_unregister_common(dev);  	priv = dev->priv; +	wait_for_completion(&priv->fw_loaded); +	p54_unregister_common(dev);  	release_firmware(priv->firmware);  	pci_free_consistent(pdev, sizeof(*priv->ring_control),  			    priv->ring_control, priv->ring_control_dma); @@ -619,59 +660,41 @@ static void __devexit p54p_remove(struct pci_dev *pdev)  	p54_free_common(dev);  } -#ifdef CONFIG_PM -static int p54p_suspend(struct pci_dev *pdev, pm_message_t state) +#ifdef CONFIG_PM_SLEEP +static int p54p_suspend(struct device *device)  { -	struct ieee80211_hw *dev = pci_get_drvdata(pdev); -	struct p54p_priv *priv = dev->priv; - -	if (priv->common.mode != NL80211_IFTYPE_UNSPECIFIED) { -		ieee80211_stop_queues(dev); -		p54p_stop(dev); -	} +	struct pci_dev *pdev = to_pci_dev(device);  	pci_save_state(pdev); -	pci_set_power_state(pdev, pci_choose_state(pdev, state)); +	pci_set_power_state(pdev, PCI_D3hot); +	pci_disable_device(pdev);  	return 0;  } -static int p54p_resume(struct pci_dev *pdev) +static int p54p_resume(struct device *device)  { -	struct ieee80211_hw *dev = pci_get_drvdata(pdev); -	struct p54p_priv *priv = dev->priv; +	struct pci_dev *pdev = to_pci_dev(device); +	int err; -	pci_set_power_state(pdev, PCI_D0); -	pci_restore_state(pdev); +	err = pci_reenable_device(pdev); +	if (err) +		return err; +	return pci_set_power_state(pdev, PCI_D0); +} -	if (priv->common.mode != NL80211_IFTYPE_UNSPECIFIED) { -		p54p_open(dev); -		ieee80211_wake_queues(dev); -	} +static SIMPLE_DEV_PM_OPS(p54pci_pm_ops, p54p_suspend, p54p_resume); -	return 0; -} -#endif /* CONFIG_PM */ +#define P54P_PM_OPS (&p54pci_pm_ops) +#else +#define P54P_PM_OPS (NULL) +#endif /* CONFIG_PM_SLEEP */  static struct pci_driver p54p_driver = {  	.name		= "p54pci",  	.id_table	= p54p_table,  	.probe		= p54p_probe, -	.remove		= __devexit_p(p54p_remove), -#ifdef CONFIG_PM -	.suspend	= p54p_suspend, -	.resume		= p54p_resume, -#endif /* CONFIG_PM */ +	.remove		= p54p_remove, +	.driver.pm	= P54P_PM_OPS,  }; -static int __init p54p_init(void) -{ -	return pci_register_driver(&p54p_driver); -} - -static void __exit p54p_exit(void) -{ -	pci_unregister_driver(&p54p_driver); -} - -module_init(p54p_init); -module_exit(p54p_exit); +module_pci_driver(p54p_driver); diff --git a/drivers/net/wireless/p54/p54pci.h b/drivers/net/wireless/p54/p54pci.h index ee9bc62a4fa..68405c142f9 100644 --- a/drivers/net/wireless/p54/p54pci.h +++ b/drivers/net/wireless/p54/p54pci.h @@ -1,5 +1,6 @@  #ifndef P54PCI_H  #define P54PCI_H +#include <linux/interrupt.h>  /*   * Defines for PCI based mac80211 Prism54 driver @@ -104,6 +105,7 @@ struct p54p_priv {  	struct sk_buff *tx_buf_data[32];  	struct sk_buff *tx_buf_mgmt[4];  	struct completion boot_comp; +	struct completion fw_loaded;  };  #endif /* P54USB_H */ diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c index 18d24b7b1e3..de15171e2cd 100644 --- a/drivers/net/wireless/p54/p54spi.c +++ b/drivers/net/wireless/p54/p54spi.c @@ -41,10 +41,8 @@  #endif /* CONFIG_P54_SPI_DEFAULT_EEPROM */  MODULE_FIRMWARE("3826.arm"); -MODULE_ALIAS("stlc45xx"); -/* - * gpios should be handled in board files and provided via platform data, +/* gpios should be handled in board files and provided via platform data,   * but because it's currently impossible for p54spi to have a header file   * in include/linux, let's use module paramaters for now   */ @@ -192,8 +190,7 @@ static int p54spi_request_eeprom(struct ieee80211_hw *dev)  	const struct firmware *eeprom;  	int ret; -	/* -	 * allow users to customize their eeprom. +	/* allow users to customize their eeprom.  	 */  	ret = request_firmware(&eeprom, "3826.eeprom", &priv->spi->dev); @@ -286,8 +283,7 @@ static void p54spi_power_on(struct p54s_priv *priv)  	gpio_set_value(p54spi_gpio_power, 1);  	enable_irq(gpio_to_irq(p54spi_gpio_irq)); -	/* -	 * need to wait a while before device can be accessed, the lenght +	/* need to wait a while before device can be accessed, the length  	 * is just a guess  	 */  	msleep(10); @@ -366,7 +362,8 @@ static int p54spi_rx(struct p54s_priv *priv)  	/* Firmware may insert up to 4 padding bytes after the lmac header,  	 * but it does not amend the size of SPI data transfer.  	 * Such packets has correct data size in header, thus referencing -	 * past the end of allocated skb. Reserve extra 4 bytes for this case */ +	 * past the end of allocated skb. Reserve extra 4 bytes for this case +	 */  	skb = dev_alloc_skb(len + 4);  	if (!skb) {  		p54spi_sleep(priv); @@ -384,7 +381,8 @@ static int p54spi_rx(struct p54s_priv *priv)  	}  	p54spi_sleep(priv);  	/* Put additional bytes to compensate for the possible -	 * alignment-caused truncation */ +	 * alignment-caused truncation +	 */  	skb_put(skb, 4);  	if (p54_rx(priv->hw, skb) == 0) @@ -397,7 +395,7 @@ static int p54spi_rx(struct p54s_priv *priv)  static irqreturn_t p54spi_interrupt(int irq, void *config)  {  	struct spi_device *spi = config; -	struct p54s_priv *priv = dev_get_drvdata(&spi->dev); +	struct p54s_priv *priv = spi_get_drvdata(spi);  	ieee80211_queue_work(priv->hw, &priv->work); @@ -582,15 +580,9 @@ static void p54spi_op_stop(struct ieee80211_hw *dev)  	struct p54s_priv *priv = dev->priv;  	unsigned long flags; -	if (mutex_lock_interruptible(&priv->mutex)) { -		/* FIXME: how to handle this error? */ -		return; -	} - +	mutex_lock(&priv->mutex);  	WARN_ON(priv->fw_state != FW_STATE_READY); -	cancel_work_sync(&priv->work); -  	p54spi_power_off(priv);  	spin_lock_irqsave(&priv->tx_lock, flags);  	INIT_LIST_HEAD(&priv->tx_pending); @@ -598,9 +590,11 @@ static void p54spi_op_stop(struct ieee80211_hw *dev)  	priv->fw_state = FW_STATE_OFF;  	mutex_unlock(&priv->mutex); + +	cancel_work_sync(&priv->work);  } -static int __devinit p54spi_probe(struct spi_device *spi) +static int p54spi_probe(struct spi_device *spi)  {  	struct p54s_priv *priv = NULL;  	struct ieee80211_hw *hw; @@ -614,7 +608,7 @@ static int __devinit p54spi_probe(struct spi_device *spi)  	priv = hw->priv;  	priv->hw = hw; -	dev_set_drvdata(&spi->dev, priv); +	spi_set_drvdata(spi, priv);  	priv->spi = spi;  	spi->bits_per_word = 16; @@ -623,34 +617,33 @@ static int __devinit p54spi_probe(struct spi_device *spi)  	ret = spi_setup(spi);  	if (ret < 0) {  		dev_err(&priv->spi->dev, "spi_setup failed"); -		goto err_free_common; +		goto err_free;  	}  	ret = gpio_request(p54spi_gpio_power, "p54spi power");  	if (ret < 0) {  		dev_err(&priv->spi->dev, "power GPIO request failed: %d", ret); -		goto err_free_common; +		goto err_free;  	}  	ret = gpio_request(p54spi_gpio_irq, "p54spi irq");  	if (ret < 0) {  		dev_err(&priv->spi->dev, "irq GPIO request failed: %d", ret); -		goto err_free_common; +		goto err_free_gpio_power;  	}  	gpio_direction_output(p54spi_gpio_power, 0);  	gpio_direction_input(p54spi_gpio_irq);  	ret = request_irq(gpio_to_irq(p54spi_gpio_irq), -			  p54spi_interrupt, IRQF_DISABLED, "p54spi", +			  p54spi_interrupt, 0, "p54spi",  			  priv->spi);  	if (ret < 0) {  		dev_err(&priv->spi->dev, "request_irq() failed"); -		goto err_free_common; +		goto err_free_gpio_irq;  	} -	set_irq_type(gpio_to_irq(p54spi_gpio_irq), -		     IRQ_TYPE_EDGE_RISING); +	irq_set_irq_type(gpio_to_irq(p54spi_gpio_irq), IRQ_TYPE_EDGE_RISING);  	disable_irq(gpio_to_irq(p54spi_gpio_irq)); @@ -658,6 +651,7 @@ static int __devinit p54spi_probe(struct spi_device *spi)  	init_completion(&priv->fw_comp);  	INIT_LIST_HEAD(&priv->tx_pending);  	mutex_init(&priv->mutex); +	spin_lock_init(&priv->tx_lock);  	SET_IEEE80211_DEV(hw, &spi->dev);  	priv->common.open = p54spi_op_start;  	priv->common.stop = p54spi_op_stop; @@ -678,13 +672,19 @@ static int __devinit p54spi_probe(struct spi_device *spi)  	return 0;  err_free_common: +	free_irq(gpio_to_irq(p54spi_gpio_irq), spi); +err_free_gpio_irq: +	gpio_free(p54spi_gpio_irq); +err_free_gpio_power: +	gpio_free(p54spi_gpio_power); +err_free:  	p54_free_common(priv->hw);  	return ret;  } -static int __devexit p54spi_remove(struct spi_device *spi) +static int p54spi_remove(struct spi_device *spi)  { -	struct p54s_priv *priv = dev_get_drvdata(&spi->dev); +	struct p54s_priv *priv = spi_get_drvdata(spi);  	p54_unregister_common(priv->hw); @@ -705,37 +705,17 @@ static int __devexit p54spi_remove(struct spi_device *spi)  static struct spi_driver p54spi_driver = {  	.driver = {  		.name		= "p54spi", -		.bus		= &spi_bus_type,  		.owner		= THIS_MODULE,  	},  	.probe		= p54spi_probe, -	.remove		= __devexit_p(p54spi_remove), +	.remove		= p54spi_remove,  }; -static int __init p54spi_init(void) -{ -	int ret; - -	ret = spi_register_driver(&p54spi_driver); -	if (ret < 0) { -		printk(KERN_ERR "failed to register SPI driver: %d", ret); -		goto out; -	} - -out: -	return ret; -} - -static void __exit p54spi_exit(void) -{ -	spi_unregister_driver(&p54spi_driver); -} - -module_init(p54spi_init); -module_exit(p54spi_exit); +module_spi_driver(p54spi_driver);  MODULE_LICENSE("GPL");  MODULE_AUTHOR("Christian Lamparter <chunkeey@web.de>");  MODULE_ALIAS("spi:cx3110x");  MODULE_ALIAS("spi:p54spi"); +MODULE_ALIAS("spi:stlc45xx"); diff --git a/drivers/net/wireless/p54/p54spi_eeprom.h b/drivers/net/wireless/p54/p54spi_eeprom.h index d592cbd34d7..0b7bfb0adcf 100644 --- a/drivers/net/wireless/p54/p54spi_eeprom.h +++ b/drivers/net/wireless/p54/p54spi_eeprom.h @@ -65,9 +65,10 @@ static unsigned char p54spi_eeprom[] = {  0x03, 0x00, 0x00, 0x11,		/* PDR_ANTENNA_GAIN */  	0x08, 0x08, 0x08, 0x08, -0x09, 0x00, 0xad, 0xde,		/* PDR_RSSI_LINEAR_APPROXIMATION_CUSTOM */ -	0x0a, 0x01, 0x72, 0xfe, 0x1a, 0x00, 0x00, 0x00, -	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x0a, 0x00, 0xff, 0xca,		/* PDR_RSSI_LINEAR_APPROXIMATION_CUSTOMV2 */ +	0x01, 0x00, 0x0a, 0x00, +	0x00, 0x00, 0x0a, 0x00, +		0x85, 0x09, 0x0a, 0x01, 0x72, 0xfe, 0x1a, 0x00, 0x00, 0x00,  /* struct pda_custom_wrapper */  0x10, 0x06, 0x5d, 0xb0,		/* PDR_PRISM_PA_CAL_CURVE_DATA_CUSTOM */ @@ -671,7 +672,7 @@ static unsigned char p54spi_eeprom[] = {  	0xa8, 0x09, 0x25, 0x00, 0xf5, 0xff, 0xf9, 0xff, 0x00, 0x01,  0x02, 0x00, 0x00, 0x00,		/* PDR_END */ -	0x67, 0x99, +	0xb6, 0x04,  };  #endif /* P54SPI_EEPROM_H */ diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index d5bc21e5a02..043bd1c23c1 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -12,7 +12,6 @@   * published by the Free Software Foundation.   */ -#include <linux/init.h>  #include <linux/usb.h>  #include <linux/pci.h>  #include <linux/slab.h> @@ -20,6 +19,7 @@  #include <linux/etherdevice.h>  #include <linux/delay.h>  #include <linux/crc32.h> +#include <linux/module.h>  #include <net/mac80211.h>  #include "p54.h" @@ -41,10 +41,12 @@ MODULE_FIRMWARE("isl3887usb");   * whenever you add a new device.   */ -static struct usb_device_id p54u_table[] __devinitdata = { +static struct usb_device_id p54u_table[] = {  	/* Version 1 devices (pci chip + net2280) */ +	{USB_DEVICE(0x0411, 0x0050)},	/* Buffalo WLI2-USB2-G54 */  	{USB_DEVICE(0x045e, 0x00c2)},	/* Microsoft MN-710 */  	{USB_DEVICE(0x0506, 0x0a11)},	/* 3COM 3CRWE254G72 */ +	{USB_DEVICE(0x0675, 0x0530)},	/* DrayTek Vigor 530 */  	{USB_DEVICE(0x06b9, 0x0120)},	/* Thomson SpeedTouch 120g */  	{USB_DEVICE(0x0707, 0xee06)},	/* SMC 2862W-G */  	{USB_DEVICE(0x07aa, 0x001c)},	/* Corega CG-WLUSB2GT */ @@ -55,14 +57,20 @@ static struct usb_device_id p54u_table[] __devinitdata = {  	{USB_DEVICE(0x0846, 0x4210)},	/* Netgear WG121 the second ? */  	{USB_DEVICE(0x0846, 0x4220)},	/* Netgear WG111 */  	{USB_DEVICE(0x09aa, 0x1000)},	/* Spinnaker Proto board */ +	{USB_DEVICE(0x0bf8, 0x1007)},	/* Fujitsu E-5400 USB */  	{USB_DEVICE(0x0cde, 0x0006)},	/* Medion 40900, Roper Europe */ +	{USB_DEVICE(0x0db0, 0x6826)},	/* MSI UB54G (MS-6826) */  	{USB_DEVICE(0x107b, 0x55f2)},	/* Gateway WGU-210 (Gemtek) */  	{USB_DEVICE(0x124a, 0x4023)},	/* Shuttle PN15, Airvast WM168g, IOGear GWU513 */ +	{USB_DEVICE(0x1435, 0x0210)},	/* Inventel UR054G */ +	{USB_DEVICE(0x15a9, 0x0002)},	/* Gemtek WUBI-100GW 802.11g */  	{USB_DEVICE(0x1630, 0x0005)},	/* 2Wire 802.11g USB (v1) / Z-Com */ +	{USB_DEVICE(0x182d, 0x096b)},	/* Sitecom WL-107 */  	{USB_DEVICE(0x1915, 0x2234)},	/* Linksys WUSB54G OEM */  	{USB_DEVICE(0x1915, 0x2235)},	/* Linksys WUSB54G Portable OEM */  	{USB_DEVICE(0x2001, 0x3701)},	/* DLink DWL-G120 Spinnaker */  	{USB_DEVICE(0x2001, 0x3703)},	/* DLink DWL-G122 */ +	{USB_DEVICE(0x2001, 0x3762)},	/* Conceptronic C54U */  	{USB_DEVICE(0x5041, 0x2234)},	/* Linksys WUSB54G */  	{USB_DEVICE(0x5041, 0x2235)},	/* Linksys WUSB54G Portable */ @@ -74,7 +82,11 @@ static struct usb_device_id p54u_table[] __devinitdata = {  	{USB_DEVICE(0x06a9, 0x000e)},	/* Westell 802.11g USB (A90-211WG-01) */  	{USB_DEVICE(0x06b9, 0x0121)},	/* Thomson SpeedTouch 121g */  	{USB_DEVICE(0x0707, 0xee13)},   /* SMC 2862W-G version 2 */ +	{USB_DEVICE(0x07aa, 0x0020)},	/* Corega WLUSB2GTST USB */ +	{USB_DEVICE(0x0803, 0x4310)},	/* Zoom 4410a */  	{USB_DEVICE(0x083a, 0x4521)},   /* Siemens Gigaset USB Adapter 54 version 2 */ +	{USB_DEVICE(0x083a, 0x4531)},	/* T-Com Sinus 154 data II */ +	{USB_DEVICE(0x083a, 0xc501)},	/* Zoom Wireless-G 4410 */  	{USB_DEVICE(0x083a, 0xf503)},	/* Accton FD7050E ver 1010ec  */  	{USB_DEVICE(0x0846, 0x4240)},	/* Netgear WG111 (v2) */  	{USB_DEVICE(0x0915, 0x2000)},	/* Cohiba Proto board */ @@ -92,8 +104,11 @@ static struct usb_device_id p54u_table[] __devinitdata = {  	{USB_DEVICE(0x13B1, 0x000C)},	/* Linksys WUSB54AG */  	{USB_DEVICE(0x1413, 0x5400)},   /* Telsey 802.11g USB2.0 Adapter */  	{USB_DEVICE(0x1435, 0x0427)},	/* Inventel UR054G */ +	/* {USB_DEVICE(0x15a9, 0x0002)}, * Also SparkLAN WL-682 with 3887 */  	{USB_DEVICE(0x1668, 0x1050)},	/* Actiontec 802UIG-1 */ +	{USB_DEVICE(0x1740, 0x1000)},	/* Senao NUB-350 */  	{USB_DEVICE(0x2001, 0x3704)},	/* DLink DWL-G122 rev A2 */ +	{USB_DEVICE(0x2001, 0x3705)},	/* D-Link DWL-G120 rev C1 */  	{USB_DEVICE(0x413c, 0x5513)},	/* Dell WLA3310 USB Wireless Adapter */  	{USB_DEVICE(0x413c, 0x8102)},	/* Spinnaker DUT */  	{USB_DEVICE(0x413c, 0x8104)},	/* Cohiba Proto board */ @@ -106,21 +121,18 @@ static const struct {  	u32 intf;  	enum p54u_hw_type type;  	const char *fw; -	const char *fw_legacy;  	char hw[20];  } p54u_fwlist[__NUM_P54U_HWTYPES] = {  	{  		.type = P54U_NET2280,  		.intf = FW_LM86,  		.fw = "isl3886usb", -		.fw_legacy = "isl3890usb",  		.hw = "ISL3886 + net2280",  	},  	{  		.type = P54U_3887,  		.intf = FW_LM87,  		.fw = "isl3887usb", -		.fw_legacy = "isl3887usb_bare",  		.hw = "ISL3887",  	},  }; @@ -183,7 +195,7 @@ static void p54u_rx_cb(struct urb *urb)  static void p54u_tx_cb(struct urb *urb)  {  	struct sk_buff *skb = urb->context; -	struct ieee80211_hw *dev = (struct ieee80211_hw *) +	struct ieee80211_hw *dev =  		usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));  	p54_free_skb(dev, skb); @@ -197,6 +209,16 @@ static void p54u_free_urbs(struct ieee80211_hw *dev)  	usb_kill_anchored_urbs(&priv->submitted);  } +static void p54u_stop(struct ieee80211_hw *dev) +{ +	/* +	 * TODO: figure out how to reliably stop the 3887 and net2280 so +	 * the hardware is still usable next time we want to start it. +	 * until then, we just stop listening to the hardware.. +	 */ +	p54u_free_urbs(dev); +} +  static int p54u_init_urbs(struct ieee80211_hw *dev)  {  	struct p54u_priv *priv = dev->priv; @@ -246,6 +268,16 @@ static int p54u_init_urbs(struct ieee80211_hw *dev)  	return ret;  } +static int p54u_open(struct ieee80211_hw *dev) +{ +	/* +	 * TODO: Because we don't know how to reliably stop the 3887 and +	 * the isl3886+net2280, other than brutally cut off all +	 * communications. We have to reinitialize the urbs on every start. +	 */ +	return p54u_init_urbs(dev); +} +  static __le32 p54u_lm87_chksum(const __le32 *data, size_t length)  {  	u32 chk = 0; @@ -478,13 +510,10 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)  		return err;  	tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL); -	if (!buf) { -		dev_err(&priv->udev->dev, "(p54usb) cannot allocate firmware" -					  "upload buffer!\n"); +	if (!buf)  		return -ENOMEM; -	} -	left = block_size = min((size_t)P54U_FW_BLOCK, priv->fw->size); +	left = block_size = min_t(size_t, P54U_FW_BLOCK, priv->fw->size);  	strcpy(buf, p54u_firmware_upload_3887);  	left -= strlen(p54u_firmware_upload_3887);  	tmp += strlen(p54u_firmware_upload_3887); @@ -605,11 +634,8 @@ static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev)  	const u8 *data;  	buf = kmalloc(512, GFP_KERNEL); -	if (!buf) { -		dev_err(&priv->udev->dev, "(p54usb) firmware buffer " -					  "alloc failed!\n"); +	if (!buf)  		return -ENOMEM; -	}  #define P54U_WRITE(type, addr, data) \  	do {\ @@ -825,73 +851,141 @@ fail:  	return err;  } -static int p54u_load_firmware(struct ieee80211_hw *dev) +static int p54_find_type(struct p54u_priv *priv)  { -	struct p54u_priv *priv = dev->priv; -	int err, i; - -	BUILD_BUG_ON(ARRAY_SIZE(p54u_fwlist) != __NUM_P54U_HWTYPES); +	int i;  	for (i = 0; i < __NUM_P54U_HWTYPES; i++)  		if (p54u_fwlist[i].type == priv->hw_type)  			break; -  	if (i == __NUM_P54U_HWTYPES)  		return -EOPNOTSUPP; -	err = request_firmware(&priv->fw, p54u_fwlist[i].fw, &priv->udev->dev); -	if (err) { -		dev_err(&priv->udev->dev, "(p54usb) cannot load firmware %s " -					  "(%d)!\n", p54u_fwlist[i].fw, err); +	return i; +} -		err = request_firmware(&priv->fw, p54u_fwlist[i].fw_legacy, -				       &priv->udev->dev); -		if (err) -			return err; -	} +static int p54u_start_ops(struct p54u_priv *priv) +{ +	struct ieee80211_hw *dev = priv->common.hw; +	int ret; -	err = p54_parse_firmware(dev, priv->fw); -	if (err) -		goto out; +	ret = p54_parse_firmware(dev, priv->fw); +	if (ret) +		goto err_out; + +	ret = p54_find_type(priv); +	if (ret < 0) +		goto err_out; -	if (priv->common.fw_interface != p54u_fwlist[i].intf) { +	if (priv->common.fw_interface != p54u_fwlist[ret].intf) {  		dev_err(&priv->udev->dev, "wrong firmware, please get "  			"a firmware for \"%s\" and try again.\n", -			p54u_fwlist[i].hw); -		err = -EINVAL; +			p54u_fwlist[ret].hw); +		ret = -ENODEV; +		goto err_out;  	} -out: -	if (err) -		release_firmware(priv->fw); +	ret = priv->upload_fw(dev); +	if (ret) +		goto err_out; -	return err; +	ret = p54u_open(dev); +	if (ret) +		goto err_out; + +	ret = p54_read_eeprom(dev); +	if (ret) +		goto err_stop; + +	p54u_stop(dev); + +	ret = p54_register_common(dev, &priv->udev->dev); +	if (ret) +		goto err_stop; + +	return 0; + +err_stop: +	p54u_stop(dev); + +err_out: +	/* +	 * p54u_disconnect will do the rest of the +	 * cleanup +	 */ +	return ret;  } -static int p54u_open(struct ieee80211_hw *dev) +static void p54u_load_firmware_cb(const struct firmware *firmware, +				  void *context)  { -	struct p54u_priv *priv = dev->priv; +	struct p54u_priv *priv = context; +	struct usb_device *udev = priv->udev;  	int err; -	err = p54u_init_urbs(dev); -	if (err) { -		return err; +	complete(&priv->fw_wait_load); +	if (firmware) { +		priv->fw = firmware; +		err = p54u_start_ops(priv); +	} else { +		err = -ENOENT; +		dev_err(&udev->dev, "Firmware not found.\n");  	} -	priv->common.open = p54u_init_urbs; +	if (err) { +		struct device *parent = priv->udev->dev.parent; -	return 0; +		dev_err(&udev->dev, "failed to initialize device (%d)\n", err); + +		if (parent) +			device_lock(parent); + +		device_release_driver(&udev->dev); +		/* +		 * At this point p54u_disconnect has already freed +		 * the "priv" context. Do not use it anymore! +		 */ +		priv = NULL; + +		if (parent) +			device_unlock(parent); +	} + +	usb_put_dev(udev);  } -static void p54u_stop(struct ieee80211_hw *dev) +static int p54u_load_firmware(struct ieee80211_hw *dev, +			      struct usb_interface *intf)  { -	/* TODO: figure out how to reliably stop the 3887 and net2280 so -	   the hardware is still usable next time we want to start it. -	   until then, we just stop listening to the hardware.. */ -	p54u_free_urbs(dev); +	struct usb_device *udev = interface_to_usbdev(intf); +	struct p54u_priv *priv = dev->priv; +	struct device *device = &udev->dev; +	int err, i; + +	BUILD_BUG_ON(ARRAY_SIZE(p54u_fwlist) != __NUM_P54U_HWTYPES); + +	init_completion(&priv->fw_wait_load); +	i = p54_find_type(priv); +	if (i < 0) +		return i; + +	dev_info(&priv->udev->dev, "Loading firmware file %s\n", +	       p54u_fwlist[i].fw); + +	usb_get_dev(udev); +	err = request_firmware_nowait(THIS_MODULE, 1, p54u_fwlist[i].fw, +				      device, GFP_KERNEL, priv, +				      p54u_load_firmware_cb); +	if (err) { +		dev_err(&priv->udev->dev, "(p54usb) cannot load firmware %s " +					  "(%d)!\n", p54u_fwlist[i].fw, err); +		usb_put_dev(udev); +	} + +	return err;  } -static int __devinit p54u_probe(struct usb_interface *intf, +static int p54u_probe(struct usb_interface *intf,  				const struct usb_device_id *id)  {  	struct usb_device *udev = interface_to_usbdev(intf); @@ -958,37 +1052,15 @@ static int __devinit p54u_probe(struct usb_interface *intf,  		priv->common.tx = p54u_tx_net2280;  		priv->upload_fw = p54u_upload_firmware_net2280;  	} -	err = p54u_load_firmware(dev); -	if (err) -		goto err_free_dev; - -	err = priv->upload_fw(dev); -	if (err) -		goto err_free_fw; - -	p54u_open(dev); -	err = p54_read_eeprom(dev); -	p54u_stop(dev); -	if (err) -		goto err_free_fw; - -	err = p54_register_common(dev, &udev->dev); -	if (err) -		goto err_free_fw; - -	return 0; - -err_free_fw: -	release_firmware(priv->fw); - -err_free_dev: -	p54_free_common(dev); -	usb_set_intfdata(intf, NULL); -	usb_put_dev(udev); +	err = p54u_load_firmware(dev, intf); +	if (err) { +		usb_put_dev(udev); +		p54_free_common(dev); +	}  	return err;  } -static void __devexit p54u_disconnect(struct usb_interface *intf) +static void p54u_disconnect(struct usb_interface *intf)  {  	struct ieee80211_hw *dev = usb_get_intfdata(intf);  	struct p54u_priv *priv; @@ -996,9 +1068,10 @@ static void __devexit p54u_disconnect(struct usb_interface *intf)  	if (!dev)  		return; +	priv = dev->priv; +	wait_for_completion(&priv->fw_wait_load);  	p54_unregister_common(dev); -	priv = dev->priv;  	usb_put_dev(interface_to_usbdev(intf));  	release_firmware(priv->fw);  	p54_free_common(dev); @@ -1070,17 +1143,7 @@ static struct usb_driver p54u_driver = {  	.reset_resume = p54u_resume,  #endif /* CONFIG_PM */  	.soft_unbind = 1, +	.disable_hub_initiated_lpm = 1,  }; -static int __init p54u_init(void) -{ -	return usb_register(&p54u_driver); -} - -static void __exit p54u_exit(void) -{ -	usb_deregister(&p54u_driver); -} - -module_init(p54u_init); -module_exit(p54u_exit); +module_usb_driver(p54u_driver); diff --git a/drivers/net/wireless/p54/p54usb.h b/drivers/net/wireless/p54/p54usb.h index ed4034ade59..d273be7272b 100644 --- a/drivers/net/wireless/p54/p54usb.h +++ b/drivers/net/wireless/p54/p54usb.h @@ -143,6 +143,9 @@ struct p54u_priv {  	struct sk_buff_head rx_queue;  	struct usb_anchor submitted;  	const struct firmware *fw; + +	/* asynchronous firmware callback */ +	struct completion fw_wait_load;  };  #endif /* P54USB_H */ diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c index 76b2318a7dc..153c61539ec 100644 --- a/drivers/net/wireless/p54/txrx.c +++ b/drivers/net/wireless/p54/txrx.c @@ -16,9 +16,10 @@   * published by the Free Software Foundation.   */ -#include <linux/init.h> +#include <linux/export.h>  #include <linux/firmware.h>  #include <linux/etherdevice.h> +#include <asm/div64.h>  #include <net/mac80211.h> @@ -240,7 +241,7 @@ void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb)  	skb_unlink(skb, &priv->tx_queue);  	p54_tx_qos_accounting_free(priv, skb); -	dev_kfree_skb_any(skb); +	ieee80211_free_txskb(dev, skb);  }  EXPORT_SYMBOL_GPL(p54_free_skb); @@ -273,11 +274,9 @@ void p54_tx(struct p54_common *priv, struct sk_buff *skb)  static int p54_rssi_to_dbm(struct p54_common *priv, int rssi)  { -	int band = priv->hw->conf.channel->band; -  	if (priv->rxhw != 5) { -		return ((rssi * priv->rssical_db[band].mul) / 64 + -			 priv->rssical_db[band].add) / 4; +		return ((rssi * priv->cur_rssi->mul) / 64 + +			 priv->cur_rssi->add) / 4;  	} else {  		/*  		 * TODO: find the correct formula @@ -308,7 +307,7 @@ static void p54_pspoll_workaround(struct p54_common *priv, struct sk_buff *skb)  		return;  	/* only consider beacons from the associated BSSID */ -	if (compare_ether_addr(hdr->addr3, priv->bssid)) +	if (!ether_addr_equal_64bits(hdr->addr3, priv->bssid))  		return;  	tim = p54_find_ie(skb, WLAN_EID_TIM); @@ -354,13 +353,13 @@ static int p54_rx_data(struct p54_common *priv, struct sk_buff *skb)  	rx_status->signal = p54_rssi_to_dbm(priv, hdr->rssi);  	if (hdr->rate & 0x10)  		rx_status->flag |= RX_FLAG_SHORTPRE; -	if (priv->hw->conf.channel->band == IEEE80211_BAND_5GHZ) +	if (priv->hw->conf.chandef.chan->band == IEEE80211_BAND_5GHZ)  		rx_status->rate_idx = (rate < 4) ? 0 : rate - 4;  	else  		rx_status->rate_idx = rate;  	rx_status->freq = freq; -	rx_status->band =  priv->hw->conf.channel->band; +	rx_status->band =  priv->hw->conf.chandef.chan->band;  	rx_status->antenna = hdr->antenna;  	tsf32 = le32_to_cpu(hdr->tsf32); @@ -369,7 +368,11 @@ static int p54_rx_data(struct p54_common *priv, struct sk_buff *skb)  	rx_status->mactime = ((u64)priv->tsf_high32) << 32 | tsf32;  	priv->tsf_low32 = tsf32; -	rx_status->flag |= RX_FLAG_TSFT; +	/* LMAC API Page 10/29 - s_lm_data_in - clock +	 * "usec accurate timestamp of hardware clock +	 * at end of frame (before OFDM SIFS EOF padding" +	 */ +	rx_status->flag |= RX_FLAG_MACTIME_END;  	if (hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN))  		header_len += hdr->align[0]; @@ -422,11 +425,11 @@ static void p54_rx_frame_sent(struct p54_common *priv, struct sk_buff *skb)  	 * Clear manually, ieee80211_tx_info_clear_status would  	 * clear the counts too and we need them.  	 */ -	memset(&info->status.ampdu_ack_len, 0, +	memset(&info->status.ack_signal, 0,  	       sizeof(struct ieee80211_tx_info) - -	       offsetof(struct ieee80211_tx_info, status.ampdu_ack_len)); +	       offsetof(struct ieee80211_tx_info, status.ack_signal));  	BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, -			      status.ampdu_ack_len) != 23); +			      status.ack_signal) != 20);  	if (entry_hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN))  		pad = entry_data->align[0]; @@ -509,6 +512,8 @@ static void p54_rx_stats(struct p54_common *priv, struct sk_buff *skb)  	struct p54_hdr *hdr = (struct p54_hdr *) skb->data;  	struct p54_statistics *stats = (struct p54_statistics *) hdr->data;  	struct sk_buff *tmp; +	struct ieee80211_channel *chan; +	unsigned int i, rssi, tx, cca, dtime, dtotal, dcca, dtx, drssi, unit;  	u32 tsf32;  	if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) @@ -525,8 +530,75 @@ static void p54_rx_stats(struct p54_common *priv, struct sk_buff *skb)  	priv->noise = p54_rssi_to_dbm(priv, le32_to_cpu(stats->noise)); +	/* +	 * STSW450X LMAC API page 26 - 3.8 Statistics +	 * "The exact measurement period can be derived from the +	 * timestamp member". +	 */ +	dtime = tsf32 - priv->survey_raw.timestamp; + +	/* +	 * STSW450X LMAC API page 26 - 3.8.1 Noise histogram +	 * The LMAC samples RSSI, CCA and transmit state at regular +	 * periods (typically 8 times per 1k [as in 1024] usec). +	 */ +	cca = le32_to_cpu(stats->sample_cca); +	tx = le32_to_cpu(stats->sample_tx); +	rssi = 0; +	for (i = 0; i < ARRAY_SIZE(stats->sample_noise); i++) +		rssi += le32_to_cpu(stats->sample_noise[i]); + +	dcca = cca - priv->survey_raw.cached_cca; +	drssi = rssi - priv->survey_raw.cached_rssi; +	dtx = tx - priv->survey_raw.cached_tx; +	dtotal = dcca + drssi + dtx; + +	/* +	 * update statistics when more than a second is over since the +	 * last call, or when a update is badly needed. +	 */ +	if (dtotal && (priv->update_stats || dtime >= USEC_PER_SEC) && +	    dtime >= dtotal) { +		priv->survey_raw.timestamp = tsf32; +		priv->update_stats = false; +		unit = dtime / dtotal; + +		if (dcca) { +			priv->survey_raw.cca += dcca * unit; +			priv->survey_raw.cached_cca = cca; +		} +		if (dtx) { +			priv->survey_raw.tx += dtx * unit; +			priv->survey_raw.cached_tx = tx; +		} +		if (drssi) { +			priv->survey_raw.rssi += drssi * unit; +			priv->survey_raw.cached_rssi = rssi; +		} + +		/* 1024 usec / 8 times = 128 usec / time */ +		if (!(priv->phy_ps || priv->phy_idle)) +			priv->survey_raw.active += dtotal * unit; +		else +			priv->survey_raw.active += (dcca + dtx) * unit; +	} + +	chan = priv->curchan; +	if (chan) { +		struct survey_info *survey = &priv->survey[chan->hw_value]; +		survey->noise = clamp(priv->noise, -128, 127); +		survey->channel_time = priv->survey_raw.active; +		survey->channel_time_tx = priv->survey_raw.tx; +		survey->channel_time_busy = priv->survey_raw.tx + +			priv->survey_raw.cca; +		do_div(survey->channel_time, 1024); +		do_div(survey->channel_time_tx, 1024); +		do_div(survey->channel_time_busy, 1024); +	} +  	tmp = p54_find_and_unlink_skb(priv, hdr->req_id);  	dev_kfree_skb_any(tmp); +	complete(&priv->stat_comp);  }  static void p54_rx_trap(struct p54_common *priv, struct sk_buff *skb) @@ -607,8 +679,9 @@ int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb)  EXPORT_SYMBOL_GPL(p54_rx);  static void p54_tx_80211_header(struct p54_common *priv, struct sk_buff *skb, -				struct ieee80211_tx_info *info, u8 *queue, -				u32 *extra_len, u16 *flags, u16 *aid, +				struct ieee80211_tx_info *info, +				struct ieee80211_sta *sta, +				u8 *queue, u32 *extra_len, u16 *flags, u16 *aid,  				bool *burst_possible)  {  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; @@ -618,10 +691,10 @@ static void p54_tx_80211_header(struct p54_common *priv, struct sk_buff *skb,  	else  		*burst_possible = false; -	if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) +	if (!(info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ))  		*flags |= P54_HDR_FLAG_DATA_OUT_SEQNR; -	if (info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE) +	if (info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER)  		*flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL;  	if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) @@ -677,8 +750,8 @@ static void p54_tx_80211_header(struct p54_common *priv, struct sk_buff *skb,  			}  		} -		if (info->control.sta) -			*aid = info->control.sta->aid; +		if (sta) +			*aid = sta->aid;  		break;  	}  } @@ -698,14 +771,16 @@ static u8 p54_convert_algo(u32 cipher)  	}  } -int p54_tx_80211(struct ieee80211_hw *dev, struct sk_buff *skb) +void p54_tx_80211(struct ieee80211_hw *dev, +		  struct ieee80211_tx_control *control, +		  struct sk_buff *skb)  {  	struct p54_common *priv = dev->priv;  	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);  	struct p54_tx_info *p54info;  	struct p54_hdr *hdr;  	struct p54_tx_data *txhdr; -	unsigned int padding, len, extra_len; +	unsigned int padding, len, extra_len = 0;  	int i, j, ridx;  	u16 hdr_flags = 0, aid = 0;  	u8 rate, queue = 0, crypt_offset = 0; @@ -715,16 +790,12 @@ int p54_tx_80211(struct ieee80211_hw *dev, struct sk_buff *skb)  	u8 nrates = 0, nremaining = 8;  	bool burst_allowed = false; -	p54_tx_80211_header(priv, skb, info, &queue, &extra_len, +	p54_tx_80211_header(priv, skb, info, control->sta, &queue, &extra_len,  			    &hdr_flags, &aid, &burst_allowed);  	if (p54_tx_qos_accounting_alloc(priv, skb, queue)) { -		if (!IS_QOS_QUEUE(queue)) { -			dev_kfree_skb_any(skb); -			return NETDEV_TX_OK; -		} else { -			return NETDEV_TX_BUSY; -		} +		ieee80211_free_txskb(dev, skb); +		return;  	}  	padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3; @@ -849,8 +920,7 @@ int p54_tx_80211(struct ieee80211_hw *dev, struct sk_buff *skb)  	txhdr->hw_queue = queue;  	txhdr->backlog = priv->tx_stats[queue].len - 1;  	memset(txhdr->durations, 0, sizeof(txhdr->durations)); -	txhdr->tx_antenna = ((info->antenna_sel_tx == 0) ? -		2 : info->antenna_sel_tx - 1) & priv->tx_diversity_mask; +	txhdr->tx_antenna = 2 & priv->tx_diversity_mask;  	if (priv->rxhw == 5) {  		txhdr->longbow.cts_rate = cts_rate;  		txhdr->longbow.output_power = cpu_to_le16(priv->output_power); @@ -867,5 +937,4 @@ int p54_tx_80211(struct ieee80211_hw *dev, struct sk_buff *skb)  	p54info->extra_len = extra_len;  	p54_tx(priv, skb); -	return NETDEV_TX_OK;  }  | 
