From e174961ca1a0b28f7abf0be47973ad57cb74e5f0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 27 Oct 2008 15:59:26 -0700 Subject: net: convert print_mac to %pM This converts pretty much everything to print_mac. There were a few things that had conflicts which I have just dropped for now, no harm done. I've built an allyesconfig with this and looked at the files that weren't built very carefully, but it's a huge patch. Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- drivers/net/wireless/p54/p54common.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/p54/p54common.c') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 2d022f83774..72859decd90 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -320,7 +320,6 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) int err; u8 *end = (u8 *)eeprom + len; u16 synth; - DECLARE_MAC_BUF(mac); wrap = (struct eeprom_pda_wrap *) eeprom; entry = (void *)wrap->data + le16_to_cpu(wrap->len); @@ -445,9 +444,9 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) SET_IEEE80211_PERM_ADDR(dev, perm_addr); } - printk(KERN_INFO "%s: hwaddr %s, MAC:isl38%02x RF:%s\n", + printk(KERN_INFO "%s: hwaddr %pM, MAC:isl38%02x RF:%s\n", wiphy_name(dev->wiphy), - print_mac(mac, dev->wiphy->perm_addr), + dev->wiphy->perm_addr, priv->version, p54_rf_chips[priv->rxhw]); return 0; -- cgit v1.2.3-70-g09d2 From 40333e4fb476014cdd939d27e20eb54573172b32 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Wed, 8 Oct 2008 20:52:22 +0200 Subject: p54: honour bss_info_changed's short slot time settings This patch was made on behalf of Johannes request. "mac80211 and IEEE80211_CONF_SHORT_SLOT_TIME" Of course, bss_info_changed provides some more useful data. e.g.: basic_rates, dtim_period, beacon_int and maybe even more. Everything can be hooked up if it's necessary. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54.h | 1 + drivers/net/wireless/p54/p54common.c | 23 ++++++++++++++++------- 2 files changed, 17 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless/p54/p54common.c') diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index 1d0704fe146..8da4d302059 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -81,6 +81,7 @@ struct p54_common { unsigned int output_limit_len; struct pda_pa_curve_data *curve_data; unsigned int filter_flags; + bool use_short_slot; u16 rxhw; u8 version; u8 rx_antenna; diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 6370c44c64d..b1dc10ccd32 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -901,12 +901,10 @@ static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type, memset(filter->bssid, ~0, ETH_ALEN); else memcpy(filter->bssid, bssid, ETH_ALEN); - filter->rx_antenna = priv->rx_antenna; - if (priv->fw_var < 0x500) { data_len = P54_TX_CONTROL_FILTER_V1_LEN; - filter->v1.basic_rate_mask = cpu_to_le32(0x15F); + filter->v1.basic_rate_mask = cpu_to_le32(0x15f); filter->v1.rx_addr = cpu_to_le32(priv->rx_end); filter->v1.max_rx = cpu_to_le16(priv->rx_mtu); filter->v1.rxhw = cpu_to_le16(priv->rxhw); @@ -918,7 +916,6 @@ static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type, filter->v2.rxhw = cpu_to_le16(priv->rxhw); filter->v2.timer = cpu_to_le16(1000); } - hdr->len = cpu_to_le16(data_len); p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + data_len); priv->tx(dev, hdr, sizeof(*hdr) + data_len, 1); @@ -1088,7 +1085,7 @@ static void p54_set_vdcf(struct ieee80211_hw *dev) vdcf = (struct p54_tx_control_vdcf *) hdr->data; - if (dev->conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME) { + if (priv->use_short_slot) { vdcf->slottime = 9; vdcf->magic1 = 0x10; vdcf->magic2 = 0x00; @@ -1135,7 +1132,6 @@ static int p54_start(struct ieee80211_hw *dev) priv->mode = NL80211_IFTYPE_MONITOR; p54_init_vdcf(dev); - mod_timer(&priv->stats_timer, jiffies + HZ); return err; } @@ -1351,6 +1347,19 @@ static int p54_get_tx_stats(struct ieee80211_hw *dev, return 0; } +static void p54_bss_info_changed(struct ieee80211_hw *dev, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, + u32 changed) +{ + struct p54_common *priv = dev->priv; + + if (changed & BSS_CHANGED_ERP_SLOT) { + priv->use_short_slot = info->use_short_slot; + p54_set_vdcf(dev); + } +} + static const struct ieee80211_ops p54_ops = { .tx = p54_tx, .start = p54_start, @@ -1359,6 +1368,7 @@ static const struct ieee80211_ops p54_ops = { .remove_interface = p54_remove_interface, .config = p54_config, .config_interface = p54_config_interface, + .bss_info_changed = p54_bss_info_changed, .configure_filter = p54_configure_filter, .conf_tx = p54_conf_tx, .get_stats = p54_get_stats, @@ -1385,7 +1395,6 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); dev->channel_change_time = 1000; /* TODO: find actual value */ - priv->tx_stats[0].limit = 1; priv->tx_stats[1].limit = 1; priv->tx_stats[2].limit = 1; -- cgit v1.2.3-70-g09d2 From 0f4ac38b5999c3d51adad52d61c56c1b99c247ec Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 9 Oct 2008 12:18:04 +0200 Subject: mac80211: kill hw.conf.antenna_sel_{rx,tx} Never actually used. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 25 +++---------------------- drivers/net/wireless/b43legacy/main.c | 18 ++---------------- drivers/net/wireless/p54/p54common.c | 3 +-- drivers/net/wireless/rt2x00/rt2x00config.c | 20 ++++---------------- drivers/net/wireless/rt2x00/rt2x00dev.c | 6 ++---- include/net/mac80211.h | 7 +------ net/mac80211/debugfs.c | 8 -------- net/mac80211/ieee80211_i.h | 2 -- net/mac80211/tx.c | 1 - 9 files changed, 13 insertions(+), 77 deletions(-) (limited to 'drivers/net/wireless/p54/p54common.c') diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 6e773018cba..6b85428b0e1 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1339,25 +1339,6 @@ u8 b43_ieee80211_antenna_sanitize(struct b43_wldev *dev, return antenna_nr; } -static int b43_antenna_from_ieee80211(struct b43_wldev *dev, u8 antenna) -{ - antenna = b43_ieee80211_antenna_sanitize(dev, antenna); - switch (antenna) { - case 0: /* default/diversity */ - return B43_ANTENNA_DEFAULT; - case 1: /* Antenna 0 */ - return B43_ANTENNA0; - case 2: /* Antenna 1 */ - return B43_ANTENNA1; - case 3: /* Antenna 2 */ - return B43_ANTENNA2; - case 4: /* Antenna 3 */ - return B43_ANTENNA3; - default: - return B43_ANTENNA_DEFAULT; - } -} - /* Convert a b43 antenna number value to the PHY TX control value. */ static u16 b43_antenna_to_phyctl(int antenna) { @@ -1399,7 +1380,7 @@ static void b43_write_beacon_template(struct b43_wldev *dev, len, ram_offset, shm_size_offset, rate); /* Write the PHY TX control parameters. */ - antenna = b43_antenna_from_ieee80211(dev, info->antenna_sel_tx); + antenna = B43_ANTENNA_DEFAULT; antenna = b43_antenna_to_phyctl(antenna); ctl = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL); /* We can't send beacons with short preamble. Would get PHY errors. */ @@ -3399,9 +3380,9 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) } /* Antennas for RX and management frame TX. */ - antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_tx); + antenna = B43_ANTENNA_DEFAULT; b43_mgmtframe_txantenna(dev, antenna); - antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_rx); + antenna = B43_ANTENNA_DEFAULT; if (phy->ops->set_rx_antenna) phy->ops->set_rx_antenna(dev, antenna); diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index c66d57560e7..867f01ce45c 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -2556,20 +2556,6 @@ init_failure: return err; } -static int b43legacy_antenna_from_ieee80211(u8 antenna) -{ - switch (antenna) { - case 0: /* default/diversity */ - return B43legacy_ANTENNA_DEFAULT; - case 1: /* Antenna 0 */ - return B43legacy_ANTENNA0; - case 2: /* Antenna 1 */ - return B43legacy_ANTENNA1; - default: - return B43legacy_ANTENNA_DEFAULT; - } -} - static int b43legacy_op_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) { @@ -2583,8 +2569,8 @@ static int b43legacy_op_dev_config(struct ieee80211_hw *hw, int err = 0; u32 savedirqs; - antenna_tx = b43legacy_antenna_from_ieee80211(conf->antenna_sel_tx); - antenna_rx = b43legacy_antenna_from_ieee80211(conf->antenna_sel_rx); + antenna_tx = B43legacy_ANTENNA_DEFAULT; + antenna_rx = B43legacy_ANTENNA_DEFAULT; mutex_lock(&wl->mutex); dev = wl->current_dev; diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index b1dc10ccd32..b3e75eb4d5b 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -1198,8 +1198,7 @@ static int p54_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) struct p54_common *priv = dev->priv; mutex_lock(&priv->conf_mutex); - priv->rx_antenna = (conf->antenna_sel_rx == 0) ? - 2 : conf->antenna_sel_tx - 1; + priv->rx_antenna = 2; /* automatic */ priv->output_power = conf->power_level << 2; ret = p54_set_freq(dev, cpu_to_le16(conf->channel->center_freq)); p54_set_vdcf(dev); diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index 4d5e87b015a..7910147157b 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -199,23 +199,15 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, * to work with untill the link tuner decides that an antenna * switch should be performed. */ - if (!conf->antenna_sel_rx && - default_ant->rx != ANTENNA_SW_DIVERSITY && + if (default_ant->rx != ANTENNA_SW_DIVERSITY && default_ant->rx != active_ant->rx) flags |= CONFIG_UPDATE_ANTENNA; - else if (conf->antenna_sel_rx && - conf->antenna_sel_rx != active_ant->rx) - flags |= CONFIG_UPDATE_ANTENNA; else if (active_ant->rx == ANTENNA_SW_DIVERSITY) flags |= CONFIG_UPDATE_ANTENNA; - if (!conf->antenna_sel_tx && - default_ant->tx != ANTENNA_SW_DIVERSITY && + if (default_ant->tx != ANTENNA_SW_DIVERSITY && default_ant->tx != active_ant->tx) flags |= CONFIG_UPDATE_ANTENNA; - else if (conf->antenna_sel_tx && - conf->antenna_sel_tx != active_ant->tx) - flags |= CONFIG_UPDATE_ANTENNA; else if (active_ant->tx == ANTENNA_SW_DIVERSITY) flags |= CONFIG_UPDATE_ANTENNA; @@ -252,18 +244,14 @@ config: } if (flags & CONFIG_UPDATE_ANTENNA) { - if (conf->antenna_sel_rx) - libconf.ant.rx = conf->antenna_sel_rx; - else if (default_ant->rx != ANTENNA_SW_DIVERSITY) + if (default_ant->rx != ANTENNA_SW_DIVERSITY) libconf.ant.rx = default_ant->rx; else if (active_ant->rx == ANTENNA_SW_DIVERSITY) libconf.ant.rx = ANTENNA_B; else libconf.ant.rx = active_ant->rx; - if (conf->antenna_sel_tx) - libconf.ant.tx = conf->antenna_sel_tx; - else if (default_ant->tx != ANTENNA_SW_DIVERSITY) + if (default_ant->tx != ANTENNA_SW_DIVERSITY) libconf.ant.tx = default_ant->tx; else if (active_ant->tx == ANTENNA_SW_DIVERSITY) libconf.ant.tx = ANTENNA_B; diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 86840e3585e..9e0472bd1ed 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -249,11 +249,9 @@ static void rt2x00lib_evaluate_antenna(struct rt2x00_dev *rt2x00dev) rt2x00dev->link.ant.flags &= ~ANTENNA_RX_DIVERSITY; rt2x00dev->link.ant.flags &= ~ANTENNA_TX_DIVERSITY; - if (rt2x00dev->hw->conf.antenna_sel_rx == 0 && - rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY) + if (rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY) rt2x00dev->link.ant.flags |= ANTENNA_RX_DIVERSITY; - if (rt2x00dev->hw->conf.antenna_sel_tx == 0 && - rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY) + if (rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY) rt2x00dev->link.ant.flags |= ANTENNA_TX_DIVERSITY; if (!(rt2x00dev->link.ant.flags & ANTENNA_RX_DIVERSITY) && diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 2870f3973f1..5f28b7f8988 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -324,7 +324,7 @@ struct ieee80211_tx_altrate { * @flags: transmit info flags, defined above * @band: TBD * @tx_rate_idx: TBD - * @antenna_sel_tx: TBD + * @antenna_sel_tx: antenna to use, 0 for automatic diversity * @control: union for control data * @status: union for status data * @driver_data: array of driver_data pointers @@ -474,9 +474,6 @@ static inline int __deprecated __IEEE80211_CONF_SHORT_SLOT_TIME(void) * @listen_interval: listen interval in units of beacon interval * @flags: configuration flags defined above * @power_level: requested transmit power (in dBm) - * @antenna_sel_tx: transmit antenna selection, 0: default/diversity, - * 1/2: antenna 0/1 - * @antenna_sel_rx: receive antenna selection, like @antenna_sel_tx * @ht_cap: describes current self configuration of 802.11n HT capabilities * @ht_bss_conf: describes current BSS configuration of 802.11n HT parameters * @channel: the channel to tune to @@ -488,8 +485,6 @@ struct ieee80211_conf { u16 listen_interval; u32 flags; int power_level; - u8 antenna_sel_tx; - u8 antenna_sel_rx; struct ieee80211_channel *channel; diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 24ce5446331..767dbca50ad 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -47,10 +47,6 @@ static const struct file_operations name## _ops = { \ DEBUGFS_READONLY_FILE(frequency, 20, "%d", local->hw.conf.channel->center_freq); -DEBUGFS_READONLY_FILE(antenna_sel_tx, 20, "%d", - local->hw.conf.antenna_sel_tx); -DEBUGFS_READONLY_FILE(antenna_sel_rx, 20, "%d", - local->hw.conf.antenna_sel_rx); DEBUGFS_READONLY_FILE(rts_threshold, 20, "%d", local->rts_threshold); DEBUGFS_READONLY_FILE(fragmentation_threshold, 20, "%d", @@ -202,8 +198,6 @@ void debugfs_hw_add(struct ieee80211_local *local) local->debugfs.keys = debugfs_create_dir("keys", phyd); DEBUGFS_ADD(frequency); - DEBUGFS_ADD(antenna_sel_tx); - DEBUGFS_ADD(antenna_sel_rx); DEBUGFS_ADD(rts_threshold); DEBUGFS_ADD(fragmentation_threshold); DEBUGFS_ADD(short_retry_limit); @@ -258,8 +252,6 @@ void debugfs_hw_add(struct ieee80211_local *local) void debugfs_hw_del(struct ieee80211_local *local) { DEBUGFS_DEL(frequency); - DEBUGFS_DEL(antenna_sel_tx); - DEBUGFS_DEL(antenna_sel_rx); DEBUGFS_DEL(rts_threshold); DEBUGFS_DEL(fragmentation_threshold); DEBUGFS_DEL(short_retry_limit); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index ae4ca3e8b44..88015838a63 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -727,8 +727,6 @@ struct ieee80211_local { struct dentry *rcdir; struct dentry *rcname; struct dentry *frequency; - struct dentry *antenna_sel_tx; - struct dentry *antenna_sel_rx; struct dentry *rts_threshold; struct dentry *fragmentation_threshold; struct dentry *short_retry_limit; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 9191b510bff..22494bcf488 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1971,7 +1971,6 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, sband->bitrates[rsel.rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE) info->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE; - info->antenna_sel_tx = local->hw.conf.antenna_sel_tx; info->control.retry_limit = 1; out: -- cgit v1.2.3-70-g09d2 From e8975581f63870be42ff4662b293d1b0c8c21350 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 9 Oct 2008 12:18:51 +0200 Subject: mac80211: introduce hw config change flags This makes mac80211 notify the driver which configuration actually changed, e.g. channel etc. No driver changes, this is just plumbing, driver authors are expected to act on this if they want to. Also remove the HW CONFIG debug printk, it's incorrect, often we configure something else. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/adm8211.c | 3 ++- drivers/net/wireless/ath5k/base.c | 7 +++---- drivers/net/wireless/ath9k/main.c | 4 ++-- drivers/net/wireless/b43/main.c | 3 ++- drivers/net/wireless/b43legacy/main.c | 3 ++- drivers/net/wireless/iwlwifi/iwl-agn.c | 3 ++- drivers/net/wireless/iwlwifi/iwl3945-base.c | 7 ++++--- drivers/net/wireless/libertas_tf/main.c | 4 +++- drivers/net/wireless/mac80211_hwsim.c | 4 ++-- drivers/net/wireless/p54/p54common.c | 3 ++- drivers/net/wireless/rt2x00/rt2x00.h | 2 +- drivers/net/wireless/rt2x00/rt2x00dev.c | 2 +- drivers/net/wireless/rt2x00/rt2x00mac.c | 3 ++- drivers/net/wireless/rtl8180_dev.c | 3 ++- drivers/net/wireless/rtl8187_dev.c | 3 ++- drivers/net/wireless/zd1211rw/zd_mac.c | 4 +++- include/net/mac80211.h | 30 ++++++++++++++++++++++++----- net/mac80211/cfg.c | 3 ++- net/mac80211/ieee80211_i.h | 2 +- net/mac80211/iface.c | 25 ++++++++++++++++++------ net/mac80211/main.c | 29 +++++++++++++++------------- net/mac80211/scan.c | 12 +++++++++--- net/mac80211/util.c | 3 ++- net/mac80211/wext.c | 14 +++++++------- 24 files changed, 116 insertions(+), 60 deletions(-) (limited to 'drivers/net/wireless/p54/p54common.c') diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index 6e18c9d3678..9a1e0c514c0 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -1314,9 +1314,10 @@ static int adm8211_set_ssid(struct ieee80211_hw *dev, u8 *ssid, size_t ssid_len) return 0; } -static int adm8211_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) +static int adm8211_config(struct ieee80211_hw *dev, u32 changed) { struct adm8211_priv *priv = dev->priv; + struct ieee80211_conf *conf = &dev->conf; int channel = ieee80211_frequency_to_channel(conf->channel->center_freq); if (channel != priv->channel) { diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 9e47d727e22..fcd688765d0 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -219,8 +219,7 @@ static int ath5k_add_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf); static void ath5k_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf); -static int ath5k_config(struct ieee80211_hw *hw, - struct ieee80211_conf *conf); +static int ath5k_config(struct ieee80211_hw *hw, u32 changed); static int ath5k_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_if_conf *conf); @@ -2780,10 +2779,10 @@ end: * TODO: Phy disable/diversity etc */ static int -ath5k_config(struct ieee80211_hw *hw, - struct ieee80211_conf *conf) +ath5k_config(struct ieee80211_hw *hw, u32 changed) { struct ath5k_softc *sc = hw->priv; + struct ieee80211_conf *conf = &hw->conf; sc->bintval = conf->beacon_int; sc->power_level = conf->power_level; diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 5e087c92a6d..f49910799ed 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -1230,11 +1230,11 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, __func__, error); } -static int ath9k_config(struct ieee80211_hw *hw, - struct ieee80211_conf *conf) +static int ath9k_config(struct ieee80211_hw *hw, u32 changed) { struct ath_softc *sc = hw->priv; struct ieee80211_channel *curchan = hw->conf.channel; + struct ieee80211_conf *conf = &hw->conf; int pos; DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set channel: %d MHz\n", diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 6b85428b0e1..2e81af1022e 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -3320,11 +3320,12 @@ init_failure: return err; } -static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) +static int b43_op_config(struct ieee80211_hw *hw, u32 changed) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev; struct b43_phy *phy; + struct ieee80211_conf *conf = &hw->conf; unsigned long flags; int antenna; int err = 0; diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 867f01ce45c..793cc396562 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -2557,11 +2557,12 @@ init_failure: } static int b43legacy_op_dev_config(struct ieee80211_hw *hw, - struct ieee80211_conf *conf) + u32 changed) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev; struct b43legacy_phy *phy; + struct ieee80211_conf *conf = &hw->conf; unsigned long flags; unsigned int new_phymode = 0xFFFF; int antenna_tx; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index e6695e80fb5..79a24410dd0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2734,10 +2734,11 @@ static int iwl4965_mac_add_interface(struct ieee80211_hw *hw, * be set inappropriately and the driver currently sets the hardware up to * use it whenever needed. */ -static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) +static int iwl4965_mac_config(struct ieee80211_hw *hw, u32 changed) { struct iwl_priv *priv = hw->priv; const struct iwl_channel_info *ch_info; + struct ieee80211_conf *conf = &hw->conf; unsigned long flags; int ret = 0; u16 channel; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index d3a2966d918..b1464c71ea0 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -6415,7 +6415,7 @@ static void iwl3945_bg_abort_scan(struct work_struct *work) mutex_unlock(&priv->mutex); } -static int iwl3945_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf); +static int iwl3945_mac_config(struct ieee80211_hw *hw, u32 changed); static void iwl3945_bg_scan_completed(struct work_struct *work) { @@ -6428,7 +6428,7 @@ static void iwl3945_bg_scan_completed(struct work_struct *work) return; if (test_bit(STATUS_CONF_PENDING, &priv->status)) - iwl3945_mac_config(priv->hw, ieee80211_get_hw_conf(priv->hw)); + iwl3945_mac_config(priv->hw, 0); ieee80211_scan_completed(priv->hw); @@ -6616,10 +6616,11 @@ static int iwl3945_mac_add_interface(struct ieee80211_hw *hw, * be set inappropriately and the driver currently sets the hardware up to * use it whenever needed. */ -static int iwl3945_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) +static int iwl3945_mac_config(struct ieee80211_hw *hw, u32 changed) { struct iwl3945_priv *priv = hw->priv; const struct iwl3945_channel_info *ch_info; + struct ieee80211_conf *conf = &hw->conf; unsigned long flags; int ret = 0; diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c index feff945ad85..241ddcfa352 100644 --- a/drivers/net/wireless/libertas_tf/main.c +++ b/drivers/net/wireless/libertas_tf/main.c @@ -354,9 +354,11 @@ static void lbtf_op_remove_interface(struct ieee80211_hw *hw, priv->vif = NULL; } -static int lbtf_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) +static int lbtf_op_config(struct ieee80211_hw *hw, u32 changed) { struct lbtf_private *priv = hw->priv; + struct ieee80211_conf *conf = &hw->conf; + if (conf->channel->center_freq != priv->cur_freq) { priv->cur_freq = conf->channel->center_freq; lbtf_set_channel(priv, conf->channel->hw_value); diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 3f236b54668..e2aeef8de70 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -359,10 +359,10 @@ static void mac80211_hwsim_beacon(unsigned long arg) } -static int mac80211_hwsim_config(struct ieee80211_hw *hw, - struct ieee80211_conf *conf) +static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed) { struct mac80211_hwsim_data *data = hw->priv; + struct ieee80211_conf *conf = &hw->conf; printk(KERN_DEBUG "%s:%s (freq=%d radio_enabled=%d beacon_int=%d)\n", wiphy_name(hw->wiphy), __func__, diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index b3e75eb4d5b..b3c297ed00c 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -1192,10 +1192,11 @@ static void p54_remove_interface(struct ieee80211_hw *dev, p54_set_filter(dev, 0, NULL); } -static int p54_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) +static int p54_config(struct ieee80211_hw *dev, u32 changed) { int ret; struct p54_common *priv = dev->priv; + struct ieee80211_conf *conf = &dev->conf; mutex_lock(&priv->conf_mutex); priv->rx_antenna = 2; /* automatic */ diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 1359a376840..8ec8f7e9ec6 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -997,7 +997,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf); void rt2x00mac_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf); -int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf); +int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed); int rt2x00mac_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_if_conf *conf); diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 9e0472bd1ed..697806cf94e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -1245,7 +1245,7 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) /* * Reconfigure device. */ - retval = rt2x00mac_config(rt2x00dev->hw, &rt2x00dev->hw->conf); + retval = rt2x00mac_config(rt2x00dev->hw, ~0); if (retval) goto exit; diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 2c6cc5c374f..da7b49a364f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -335,9 +335,10 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw, } EXPORT_SYMBOL_GPL(rt2x00mac_remove_interface); -int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) +int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed) { struct rt2x00_dev *rt2x00dev = hw->priv; + struct ieee80211_conf *conf = &hw->conf; int radio_on; int status; diff --git a/drivers/net/wireless/rtl8180_dev.c b/drivers/net/wireless/rtl8180_dev.c index 9de8f57486d..e8d22393797 100644 --- a/drivers/net/wireless/rtl8180_dev.c +++ b/drivers/net/wireless/rtl8180_dev.c @@ -692,9 +692,10 @@ static void rtl8180_remove_interface(struct ieee80211_hw *dev, priv->vif = NULL; } -static int rtl8180_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) +static int rtl8180_config(struct ieee80211_hw *dev, u32 changed) { struct rtl8180_priv *priv = dev->priv; + struct ieee80211_conf *conf = &dev->conf; priv->rf->set_chan(dev, conf); diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index 9ceae9017f8..2c69ab37c65 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -873,9 +873,10 @@ static void rtl8187_remove_interface(struct ieee80211_hw *dev, mutex_unlock(&priv->conf_mutex); } -static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) +static int rtl8187_config(struct ieee80211_hw *dev, u32 changed) { struct rtl8187_priv *priv = dev->priv; + struct ieee80211_conf *conf = &dev->conf; u32 reg; mutex_lock(&priv->conf_mutex); diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index de45509d757..6c3e21887fc 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -743,9 +743,11 @@ static void zd_op_remove_interface(struct ieee80211_hw *hw, zd_write_mac_addr(&mac->chip, NULL); } -static int zd_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) +static int zd_op_config(struct ieee80211_hw *hw, u32 changed) { struct zd_mac *mac = zd_hw_mac(hw); + struct ieee80211_conf *conf = &hw->conf; + return zd_chip_set_channel(&mac->chip, conf->channel->hw_value); } diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 5f28b7f8988..34e8569b59b 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -463,13 +463,33 @@ static inline int __deprecated __IEEE80211_CONF_SHORT_SLOT_TIME(void) } #define IEEE80211_CONF_SHORT_SLOT_TIME (__IEEE80211_CONF_SHORT_SLOT_TIME()) +/** + * enum ieee80211_conf_changed - denotes which configuration changed + * + * @IEEE80211_CONF_CHANGE_RADIO_ENABLED: the value of radio_enabled changed + * @IEEE80211_CONF_CHANGE_BEACON_INTERVAL: the beacon interval changed + * @IEEE80211_CONF_CHANGE_LISTEN_INTERVAL: the listen interval changed + * @IEEE80211_CONF_CHANGE_RADIOTAP: the radiotap flag changed + * @IEEE80211_CONF_CHANGE_PS: the PS flag changed + * @IEEE80211_CONF_CHANGE_POWER: the TX power changed + * @IEEE80211_CONF_CHANGE_CHANNEL: the channel changed + */ +enum ieee80211_conf_changed { + IEEE80211_CONF_CHANGE_RADIO_ENABLED = BIT(0), + IEEE80211_CONF_CHANGE_BEACON_INTERVAL = BIT(1), + IEEE80211_CONF_CHANGE_LISTEN_INTERVAL = BIT(2), + IEEE80211_CONF_CHANGE_RADIOTAP = BIT(3), + IEEE80211_CONF_CHANGE_PS = BIT(4), + IEEE80211_CONF_CHANGE_POWER = BIT(5), + IEEE80211_CONF_CHANGE_CHANNEL = BIT(6), +}; + /** * struct ieee80211_conf - configuration of the device * * This struct indicates how the driver shall configure the hardware. * * @radio_enabled: when zero, driver is required to switch off the radio. - * TODO make a flag * @beacon_int: beacon interval (TODO make interface config) * @listen_interval: listen interval in units of beacon interval * @flags: configuration flags defined above @@ -479,13 +499,13 @@ static inline int __deprecated __IEEE80211_CONF_SHORT_SLOT_TIME(void) * @channel: the channel to tune to */ struct ieee80211_conf { - int radio_enabled; - int beacon_int; - u16 listen_interval; u32 flags; int power_level; + u16 listen_interval; + bool radio_enabled; + struct ieee80211_channel *channel; struct ieee80211_sta_ht_cap ht_cap; @@ -1214,7 +1234,7 @@ struct ieee80211_ops { struct ieee80211_if_init_conf *conf); void (*remove_interface)(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf); - int (*config)(struct ieee80211_hw *hw, struct ieee80211_conf *conf); + int (*config)(struct ieee80211_hw *hw, u32 changed); int (*config_interface)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_if_conf *conf); diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index a5dea617aab..8ea30902d5d 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -394,7 +394,8 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, */ if (params->interval) { sdata->local->hw.conf.beacon_int = params->interval; - ieee80211_hw_config(sdata->local); + ieee80211_hw_config(sdata->local, + IEEE80211_CONF_CHANGE_BEACON_INTERVAL); /* * We updated some parameter so if below bails out * it's not an error. diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 88015838a63..1deb787ff8d 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -875,7 +875,7 @@ static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr) } -int ieee80211_hw_config(struct ieee80211_local *local); +int ieee80211_hw_config(struct ieee80211_local *local, u32 changed); int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed); void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx); void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 8336fee68d3..df28c5f7c9c 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -65,7 +65,7 @@ static int ieee80211_open(struct net_device *dev) struct ieee80211_if_init_conf conf; u32 changed = 0; int res; - bool need_hw_reconfig = 0; + u32 hw_reconf_flags = 0; u8 null_addr[ETH_ALEN] = {0}; /* fail early if user set an invalid address */ @@ -152,7 +152,8 @@ static int ieee80211_open(struct net_device *dev) res = local->ops->start(local_to_hw(local)); if (res) goto err_del_bss; - need_hw_reconfig = 1; + /* we're brought up, everything changes */ + hw_reconf_flags = ~0; ieee80211_led_radio(local, local->hw.conf.radio_enabled); } @@ -198,8 +199,10 @@ static int ieee80211_open(struct net_device *dev) /* must be before the call to ieee80211_configure_filter */ local->monitors++; - if (local->monitors == 1) + if (local->monitors == 1) { local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP; + hw_reconf_flags |= IEEE80211_CONF_CHANGE_RADIOTAP; + } if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL) local->fif_fcsfail++; @@ -279,8 +282,8 @@ static int ieee80211_open(struct net_device *dev) atomic_inc(&local->iff_promiscs); local->open_count++; - if (need_hw_reconfig) { - ieee80211_hw_config(local); + if (hw_reconf_flags) { + ieee80211_hw_config(local, hw_reconf_flags); /* * set default queue parameters so drivers don't * need to initialise the hardware if the hardware @@ -322,6 +325,7 @@ static int ieee80211_stop(struct net_device *dev) struct ieee80211_local *local = sdata->local; struct ieee80211_if_init_conf conf; struct sta_info *sta; + u32 hw_reconf_flags = 0; /* * Stop TX on this interface first. @@ -405,8 +409,10 @@ static int ieee80211_stop(struct net_device *dev) } local->monitors--; - if (local->monitors == 0) + if (local->monitors == 0) { local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP; + hw_reconf_flags |= IEEE80211_CONF_CHANGE_RADIOTAP; + } if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL) local->fif_fcsfail--; @@ -504,8 +510,15 @@ static int ieee80211_stop(struct net_device *dev) tasklet_disable(&local->tx_pending_tasklet); tasklet_disable(&local->tasklet); + + /* no reconfiguring after stop! */ + hw_reconf_flags = 0; } + /* do after stop to avoid reconfiguring when we stop anyway */ + if (hw_reconf_flags) + ieee80211_hw_config(local, hw_reconf_flags); + return 0; } diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 07f812755e5..c936017f6d4 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -197,31 +197,34 @@ int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed) &sdata->vif, &conf); } -int ieee80211_hw_config(struct ieee80211_local *local) +int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) { struct ieee80211_channel *chan; int ret = 0; + int power; if (local->sw_scanning) chan = local->scan_channel; else chan = local->oper_channel; - local->hw.conf.channel = chan; + if (chan != local->hw.conf.channel) { + local->hw.conf.channel = chan; + changed |= IEEE80211_CONF_CHANGE_CHANNEL; + } + if (!local->hw.conf.power_level) - local->hw.conf.power_level = chan->max_power; + power = chan->max_power; else - local->hw.conf.power_level = min(chan->max_power, - local->hw.conf.power_level); - -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: HW CONFIG: freq=%d\n", - wiphy_name(local->hw.wiphy), chan->center_freq); -#endif + power = min(chan->max_power, local->hw.conf.power_level); + if (local->hw.conf.power_level != power) { + changed |= IEEE80211_CONF_CHANGE_POWER; + local->hw.conf.power_level = power; + } - if (local->open_count) { - ret = local->ops->config(local_to_hw(local), &local->hw.conf); + if (changed && local->open_count) { + ret = local->ops->config(local_to_hw(local), changed); /* * HW reconfiguration should never fail, the driver has told * us what it can support so it should live up to that promise. @@ -672,7 +675,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD; local->short_retry_limit = 7; local->long_retry_limit = 4; - local->hw.conf.radio_enabled = 1; + local->hw.conf.radio_enabled = true; INIT_LIST_HEAD(&local->interfaces); diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 0989b1c062e..7372d7abb8c 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -448,12 +448,17 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw) if (local->hw_scanning) { local->hw_scanning = false; - ieee80211_hw_config(local); + /* + * Somebody might have requested channel change during scan + * that we won't have acted upon, try now. ieee80211_hw_config + * will set the flag based on actual changes. + */ + ieee80211_hw_config(local, 0); goto done; } local->sw_scanning = false; - ieee80211_hw_config(local); + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); netif_tx_lock_bh(local->mdev); netif_addr_lock(local->mdev); @@ -540,7 +545,8 @@ void ieee80211_scan_work(struct work_struct *work) if (!skip) { local->scan_channel = chan; - if (ieee80211_hw_config(local)) + if (ieee80211_hw_config(local, + IEEE80211_CONF_CHANGE_CHANNEL)) skip = 1; } diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 9941a60a232..3288c3de67c 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -645,7 +645,8 @@ int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freqMHz) if (local->sw_scanning || local->hw_scanning) ret = 0; else - ret = ieee80211_hw_config(local); + ret = ieee80211_hw_config( + local, IEEE80211_CONF_CHANGE_CHANNEL); rate_control_clear(local); } diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index a3af1514124..94c4b35eeb1 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c @@ -656,7 +656,7 @@ static int ieee80211_ioctl_siwtxpower(struct net_device *dev, union iwreq_data *data, char *extra) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - bool need_reconfig = 0; + u32 reconf_flags = 0; int new_power_level; if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) @@ -680,17 +680,17 @@ static int ieee80211_ioctl_siwtxpower(struct net_device *dev, if (local->hw.conf.power_level != new_power_level) { local->hw.conf.power_level = new_power_level; - need_reconfig = 1; + reconf_flags |= IEEE80211_CONF_CHANGE_POWER; } if (local->hw.conf.radio_enabled != !(data->txpower.disabled)) { local->hw.conf.radio_enabled = !(data->txpower.disabled); - need_reconfig = 1; + reconf_flags |= IEEE80211_CONF_CHANGE_RADIO_ENABLED; ieee80211_led_radio(local, local->hw.conf.radio_enabled); } - if (need_reconfig) - ieee80211_hw_config(local); + if (reconf_flags) + ieee80211_hw_config(local, reconf_flags); return 0; } @@ -976,7 +976,7 @@ static int ieee80211_ioctl_siwpower(struct net_device *dev, if (wrq->disabled) { conf->flags &= ~IEEE80211_CONF_PS; - return ieee80211_hw_config(local); + return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); } switch (wrq->flags & IW_POWER_MODE) { @@ -989,7 +989,7 @@ static int ieee80211_ioctl_siwpower(struct net_device *dev, return -EINVAL; } - return ieee80211_hw_config(local); + return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); } static int ieee80211_ioctl_giwpower(struct net_device *dev, -- cgit v1.2.3-70-g09d2 From 2e20cc3986cbee410fbe8e3e116bdcb12d70fcce Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 9 Oct 2008 17:38:52 -0700 Subject: p54: Move rx_mtu to struct bootrec_desc The patch entitled "[PATCH] p54: Fix sparse warnings" added the __le16 variable rx_mtu to struct bootrec, but it could equally well be placed in the struct bootrec_desc, which overlays the 'data' section of bootrec. Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 2 +- drivers/net/wireless/p54/p54common.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/p54/p54common.c') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index b3c297ed00c..f8cdd88e010 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -183,7 +183,7 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) priv->headroom = desc->headroom; priv->tailroom = desc->tailroom; if (le32_to_cpu(bootrec->len) == 11) - priv->rx_mtu = le16_to_cpu(bootrec->rx_mtu); + priv->rx_mtu = le16_to_cpu(desc->rx_mtu); else priv->rx_mtu = (size_t) 0x620 - priv->tx_hdr_len; diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h index 2fa994cfcfe..22af41c7dab 100644 --- a/drivers/net/wireless/p54/p54common.h +++ b/drivers/net/wireless/p54/p54common.h @@ -19,7 +19,6 @@ struct bootrec { __le32 code; __le32 len; u32 data[10]; - __le16 rx_mtu; } __attribute__((packed)); struct bootrec_exp_if { @@ -39,6 +38,8 @@ struct bootrec_desc { u8 tailroom; u8 unimportant[6]; u8 rates[16]; + u8 padding2[4]; + __le16 rx_mtu; } __attribute__((packed)); #define BR_CODE_MIN 0x80000000 -- cgit v1.2.3-70-g09d2 From 94778280fabdb6bc76db5509bd95859f1141385b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 10 Oct 2008 13:21:59 +0200 Subject: mac80211: provide sequence numbers I've come to think that not providing sequence numbers for the normal STA mode case was a mistake, at least two drivers now had to implement code they wouldn't otherwise need, and I believe at76_usb and adm8211 might be broken. This patch makes mac80211 assign a sequence number to all those frames that need one except beacons. That means that if a driver only implements modes that do not do beaconing it need not worry about the sequence number. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54.h | 1 - drivers/net/wireless/p54/p54common.c | 18 +++++------------- drivers/net/wireless/rtl8187.h | 1 - drivers/net/wireless/rtl8187_dev.c | 18 ++++-------------- net/mac80211/ieee80211_i.h | 2 ++ net/mac80211/tx.c | 10 ++++++++++ 6 files changed, 21 insertions(+), 29 deletions(-) (limited to 'drivers/net/wireless/p54/p54common.c') diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index 8da4d302059..1da96fe5024 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -67,7 +67,6 @@ struct p54_common { int (*open)(struct ieee80211_hw *dev); void (*stop)(struct ieee80211_hw *dev); int mode; - u16 seqno; u16 rx_mtu; u8 headroom; u8 tailroom; diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index f8cdd88e010..7c37d3fc1e2 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -856,19 +856,6 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) if (padding) txhdr->align[0] = padding; - /* FIXME: The sequence that follows is needed for this driver to - * work with mac80211 since "mac80211: fix TX sequence numbers". - * As with the temporary code in rt2x00, changes will be needed - * to get proper sequence numbers on beacons. In addition, this - * patch places the sequence number in the hardware state, which - * limits us to a single virtual state. - */ - if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { - if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) - priv->seqno += 0x10; - ieee80211hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); - ieee80211hdr->seq_ctrl |= cpu_to_le16(priv->seqno); - } /* modifies skb->cb and with it info, so must be last! */ p54_assign_address(dev, skb, hdr, skb->len); @@ -1392,6 +1379,11 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; + /* + * XXX: when this driver gets support for any mode that + * requires beacons (AP, MESH, IBSS) then it must + * implement IEEE80211_TX_CTL_ASSIGN_SEQ. + */ dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); dev->channel_change_time = 1000; /* TODO: find actual value */ diff --git a/drivers/net/wireless/rtl8187.h b/drivers/net/wireless/rtl8187.h index e82bb4d289e..33725d0978b 100644 --- a/drivers/net/wireless/rtl8187.h +++ b/drivers/net/wireless/rtl8187.h @@ -100,7 +100,6 @@ struct rtl8187_priv { struct usb_device *udev; u32 rx_conf; u16 txpwr_base; - u16 seqno; u8 asic_rev; u8 is_rtl8187b; enum { diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index 2c69ab37c65..16f2fe2d849 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -241,20 +241,6 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) ep = epmap[skb_get_queue_mapping(skb)]; } - /* FIXME: The sequence that follows is needed for this driver to - * work with mac80211 since "mac80211: fix TX sequence numbers". - * As with the temporary code in rt2x00, changes will be needed - * to get proper sequence numbers on beacons. In addition, this - * patch places the sequence number in the hardware state, which - * limits us to a single virtual state. - */ - if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { - if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) - priv->seqno += 0x10; - ieee80211hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); - ieee80211hdr->seq_ctrl |= cpu_to_le16(priv->seqno); - } - info->driver_data[0] = dev; info->driver_data[1] = urb; @@ -1187,6 +1173,10 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, dev->max_signal = 65; } + /* + * XXX: Once this driver supports anything that requires + * beacons it must implement IEEE80211_TX_CTL_ASSIGN_SEQ. + */ dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); if ((id->driver_info == DEVICE_RTL8187) && priv->is_rtl8187b) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 1deb787ff8d..819844726dd 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -438,6 +438,8 @@ struct ieee80211_sub_if_data { struct ieee80211_key *keys[NUM_DEFAULT_KEYS]; struct ieee80211_key *default_key; + u16 sequence_number; + /* BSS configuration for this interface. */ struct ieee80211_bss_conf bss_conf; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 22494bcf488..8bcabefa86e 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -600,8 +600,18 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx) if (ieee80211_hdrlen(hdr->frame_control) < 24) return TX_CONTINUE; + /* + * Anything but QoS data that has a sequence number field + * (is long enough) gets a sequence number from the global + * counter. + */ if (!ieee80211_is_data_qos(hdr->frame_control)) { + /* driver should assign sequence number */ info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ; + /* for pure STA mode without beacons, we can do it */ + hdr->seq_ctrl = cpu_to_le16(tx->sdata->sequence_number); + tx->sdata->sequence_number += 0x10; + tx->sdata->sequence_number &= IEEE80211_SCTL_SEQ; return TX_CONTINUE; } -- cgit v1.2.3-70-g09d2 From 7eb27af766e4a1db3dbc02a5b3d175885bf2ce93 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 12 Oct 2008 00:39:55 +0200 Subject: p54/rtl8187: fix up the seqno patch Sorry about that, for some reason I didn't notice that I'd left some unused variables in there. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 1 - drivers/net/wireless/rtl8187_dev.c | 1 - 2 files changed, 2 deletions(-) (limited to 'drivers/net/wireless/p54/p54common.c') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 7c37d3fc1e2..81a9756254f 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -802,7 +802,6 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) struct ieee80211_tx_queue_stats *current_queue; struct p54_common *priv = dev->priv; struct p54_control_hdr *hdr; - struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data; struct p54_tx_control_allocdata *txhdr; size_t padding, len; u8 rate; diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index 16f2fe2d849..b211a515428 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -175,7 +175,6 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) { struct rtl8187_priv *priv = dev->priv; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data; unsigned int ep; void *buf; struct urb *urb; -- cgit v1.2.3-70-g09d2 From e6a9854b05c1a6af1308fe2b8c68f35abf28a3ee Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 21 Oct 2008 12:40:02 +0200 Subject: mac80211/drivers: rewrite the rate control API So after the previous changes we were still unhappy with how convoluted the API is and decided to make things simpler for everybody. This completely changes the rate control API, now taking into account 802.11n with MCS rates and more control, most drivers don't support that though. Signed-off-by: Felix Fietkau Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/adm8211.c | 21 +- drivers/net/wireless/ath5k/base.c | 34 ++- drivers/net/wireless/ath9k/main.c | 18 +- drivers/net/wireless/ath9k/rc.c | 40 +-- drivers/net/wireless/ath9k/xmit.c | 28 ++- drivers/net/wireless/b43/dma.c | 4 +- drivers/net/wireless/b43/main.c | 2 +- drivers/net/wireless/b43/pio.c | 3 +- drivers/net/wireless/b43/xmit.c | 60 ++++- drivers/net/wireless/b43/xmit.h | 5 +- drivers/net/wireless/b43legacy/dma.c | 46 ++-- drivers/net/wireless/b43legacy/main.c | 2 +- drivers/net/wireless/b43legacy/pio.c | 31 ++- drivers/net/wireless/b43legacy/xmit.c | 26 +- drivers/net/wireless/b43legacy/xmit.h | 2 +- drivers/net/wireless/iwlwifi/iwl-3945-rs.c | 57 ++--- drivers/net/wireless/iwlwifi/iwl-3945.c | 65 ++++- drivers/net/wireless/iwlwifi/iwl-3945.h | 2 + drivers/net/wireless/iwlwifi/iwl-4965.c | 8 +- drivers/net/wireless/iwlwifi/iwl-5000.c | 8 +- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 37 ++- drivers/net/wireless/iwlwifi/iwl-core.c | 19 +- drivers/net/wireless/iwlwifi/iwl3945-base.c | 5 +- drivers/net/wireless/libertas_tf/main.c | 4 +- drivers/net/wireless/mac80211_hwsim.c | 12 +- drivers/net/wireless/p54/p54common.c | 26 +- drivers/net/wireless/rt2x00/rt2x00dev.c | 14 +- drivers/net/wireless/rt2x00/rt2x00mac.c | 14 +- drivers/net/wireless/rt2x00/rt2x00queue.c | 22 +- drivers/net/wireless/rt2x00/rt2x00queue.h | 9 +- drivers/net/wireless/rtl8180_dev.c | 28 +-- drivers/net/wireless/rtl8187_dev.c | 18 +- drivers/net/wireless/zd1211rw/zd_mac.c | 32 +-- drivers/net/wireless/zd1211rw/zd_usb.c | 2 +- include/net/mac80211.h | 254 +++++++++++-------- net/mac80211/ieee80211_i.h | 8 - net/mac80211/main.c | 54 +++- net/mac80211/mesh_hwmp.c | 6 +- net/mac80211/rate.c | 52 ++-- net/mac80211/rate.h | 5 +- net/mac80211/rc80211_minstrel.c | 72 +++--- net/mac80211/rc80211_pid.h | 1 + net/mac80211/rc80211_pid_algo.c | 27 +- net/mac80211/rc80211_pid_debugfs.c | 5 +- net/mac80211/sta_info.h | 4 +- net/mac80211/tx.c | 378 +++++++++++++--------------- net/mac80211/wext.c | 4 +- 47 files changed, 889 insertions(+), 685 deletions(-) (limited to 'drivers/net/wireless/p54/p54common.c') diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index 9a1e0c514c0..b96ebfe4ef3 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -341,15 +341,14 @@ static void adm8211_interrupt_tci(struct ieee80211_hw *dev) pci_unmap_single(priv->pdev, info->mapping, info->skb->len, PCI_DMA_TODEVICE); - memset(&txi->status, 0, sizeof(txi->status)); + ieee80211_tx_info_clear_status(txi); + skb_pull(skb, sizeof(struct adm8211_tx_hdr)); memcpy(skb_push(skb, info->hdrlen), skb->cb, info->hdrlen); - if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK)) { - if (status & TDES0_STATUS_ES) - txi->status.excessive_retries = 1; - else - txi->flags |= IEEE80211_TX_STAT_ACK; - } + if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK) && + !(status & TDES0_STATUS_ES)) + txi->flags |= IEEE80211_TX_STAT_ACK; + ieee80211_tx_status_irqsafe(dev, skb); info->skb = NULL; @@ -1691,8 +1690,10 @@ static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb) struct ieee80211_hdr *hdr; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_rate *txrate = ieee80211_get_tx_rate(dev, info); + u8 rc_flags; - short_preamble = !!(txrate->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE); + rc_flags = info->control.rates[0].flags; + short_preamble = !!(rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE); plcp_signal = txrate->bitrate; hdr = (struct ieee80211_hdr *)skb->data; @@ -1724,10 +1725,10 @@ static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb) if (short_preamble) txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_SHORT_PREAMBLE); - if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) + if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_RTS); - txhdr->retry_limit = info->control.retry_limit; + txhdr->retry_limit = info->control.rates[0].count; adm8211_tx_raw(dev, skb, plcp_signal, hdrlen); diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 44401f6f578..3773d983ea6 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -541,8 +541,8 @@ ath5k_pci_probe(struct pci_dev *pdev, /* set up multi-rate retry capabilities */ if (sc->ah->ah_version == AR5K_AR5212) { - hw->max_altrates = 3; - hw->max_altrate_tries = 11; + hw->max_rates = 4; + hw->max_rate_tries = 11; } /* Finish private driver data initialization */ @@ -1181,7 +1181,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL, (sc->power_level * 2), ieee80211_get_tx_rate(sc->hw, info)->hw_value, - info->control.retry_limit, keyidx, 0, flags, 0, 0); + info->control.rates[0].count, keyidx, 0, flags, 0, 0); if (ret) goto err_unmap; @@ -1193,7 +1193,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) break; mrr_rate[i] = rate->hw_value; - mrr_tries[i] = info->control.retries[i].limit; + mrr_tries[i] = info->control.rates[i + 1].count; } ah->ah_setup_mrr_tx_desc(ah, ds, @@ -1849,30 +1849,26 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, PCI_DMA_TODEVICE); - memset(&info->status, 0, sizeof(info->status)); - info->tx_rate_idx = ath5k_hw_to_driver_rix(sc, - ts.ts_rate[ts.ts_final_idx]); - info->status.retry_count = ts.ts_longretry; - + ieee80211_tx_info_clear_status(info); for (i = 0; i < 4; i++) { - struct ieee80211_tx_altrate *r = - &info->status.retries[i]; + struct ieee80211_tx_rate *r = + &info->status.rates[i]; if (ts.ts_rate[i]) { - r->rate_idx = ath5k_hw_to_driver_rix(sc, ts.ts_rate[i]); - r->limit = ts.ts_retry[i]; + r->idx = ath5k_hw_to_driver_rix(sc, ts.ts_rate[i]); + r->count = ts.ts_retry[i]; } else { - r->rate_idx = -1; - r->limit = 0; + r->idx = -1; + r->count = 0; } } - info->status.excessive_retries = 0; + /* count the successful attempt as well */ + info->status.rates[ts.ts_final_idx].count++; + if (unlikely(ts.ts_status)) { sc->ll_stats.dot11ACKFailureCount++; - if (ts.ts_status & AR5K_TXERR_XRETRY) - info->status.excessive_retries = 1; - else if (ts.ts_status & AR5K_TXERR_FILT) + if (ts.ts_status & AR5K_TXERR_FILT) info->flags |= IEEE80211_TX_STAT_TX_FILTERED; } else { info->flags |= IEEE80211_TX_STAT_ACK; diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 32acaf7ff62..a7656a3ea1b 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -457,12 +457,13 @@ void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, DPRINTF(sc, ATH_DBG_XMIT, "%s: TX complete: skb: %p\n", __func__, skb); + ieee80211_tx_info_clear_status(tx_info); if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK || tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) { - /* free driver's private data area of tx_info */ - if (tx_info->driver_data[0] != NULL) - kfree(tx_info->driver_data[0]); - tx_info->driver_data[0] = NULL; + /* free driver's private data area of tx_info, XXX: HACK! */ + if (tx_info->control.vif != NULL) + kfree(tx_info->control.vif); + tx_info->control.vif = NULL; } if (tx_status->flags & ATH_TX_BAR) { @@ -470,17 +471,12 @@ void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, tx_status->flags &= ~ATH_TX_BAR; } - if (tx_status->flags & (ATH_TX_ERROR | ATH_TX_XRETRY)) { - if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) { - /* Frame was not ACKed, but an ACK was expected */ - tx_info->status.excessive_retries = 1; - } - } else { + if (!(tx_status->flags & (ATH_TX_ERROR | ATH_TX_XRETRY))) { /* Frame was ACKed */ tx_info->flags |= IEEE80211_TX_STAT_ACK; } - tx_info->status.retry_count = tx_status->retries; + tx_info->status.rates[0].count = tx_status->retries + 1; ieee80211_tx_status(hw, skb); if (an) diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index 9b252603096..6afafeddeda 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -1864,24 +1864,21 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, hdr = (struct ieee80211_hdr *)skb->data; fc = hdr->frame_control; - tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0]; + /* XXX: UGLY HACK!! */ + tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif; spin_lock_bh(&sc->node_lock); an = ath_node_find(sc, hdr->addr1); spin_unlock_bh(&sc->node_lock); - if (!an || !priv_sta || !ieee80211_is_data(fc)) { - if (tx_info->driver_data[0] != NULL) { - kfree(tx_info->driver_data[0]); - tx_info->driver_data[0] = NULL; - } + if (tx_info_priv == NULL) return; - } - if (tx_info->driver_data[0] != NULL) { + + if (an && priv_sta && ieee80211_is_data(fc)) ath_rate_tx_complete(sc, an, priv_sta, tx_info_priv); - kfree(tx_info->driver_data[0]); - tx_info->driver_data[0] = NULL; - } + + kfree(tx_info_priv); + tx_info->control.vif = NULL; } static void ath_tx_aggr_resp(struct ath_softc *sc, @@ -1927,10 +1924,11 @@ static void ath_tx_aggr_resp(struct ath_softc *sc, } } -static void ath_get_rate(void *priv, struct ieee80211_supported_band *sband, - struct ieee80211_sta *sta, void *priv_sta, - struct sk_buff *skb, struct rate_selection *sel) +static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, + struct ieee80211_tx_rate_control *txrc) { + struct ieee80211_supported_band *sband = txrc->sband; + struct sk_buff *skb = txrc->skb; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ath_softc *sc = priv; struct ieee80211_hw *hw = sc->hw; @@ -1945,17 +1943,17 @@ static void ath_get_rate(void *priv, struct ieee80211_supported_band *sband, DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); - /* allocate driver private area of tx_info */ - tx_info->driver_data[0] = kzalloc(sizeof(*tx_info_priv), GFP_ATOMIC); - ASSERT(tx_info->driver_data[0] != NULL); - tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0]; + /* allocate driver private area of tx_info, XXX: UGLY HACK! */ + tx_info->control.vif = kzalloc(sizeof(*tx_info_priv), GFP_ATOMIC); + tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif; + ASSERT(tx_info_priv != NULL); lowest_idx = rate_lowest_index(sband, sta); tx_info_priv->min_rate = (sband->bitrates[lowest_idx].bitrate * 2) / 10; /* lowest rate for management and multicast/broadcast frames */ if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) || !sta) { - sel->rate_idx = lowest_idx; + tx_info->control.rates[0].idx = lowest_idx; return; } @@ -1966,8 +1964,10 @@ static void ath_get_rate(void *priv, struct ieee80211_supported_band *sband, tx_info_priv->rcs, &is_probe, false); +#if 0 if (is_probe) sel->probe_idx = ath_rc_priv->tx_ratectrl.probe_rate; +#endif /* Ratecontrol sometimes returns invalid rate index */ if (tx_info_priv->rcs[0].rix != 0xff) @@ -1975,7 +1975,7 @@ static void ath_get_rate(void *priv, struct ieee80211_supported_band *sband, else tx_info_priv->rcs[0].rix = ath_rc_priv->prev_data_rix; - sel->rate_idx = tx_info_priv->rcs[0].rix; + tx_info->control.rates[0].idx = tx_info_priv->rcs[0].rix; /* Check if aggregation has to be enabled for this tid */ diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index ba818cc2fb5..9fa395418a6 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -168,7 +168,9 @@ static void fill_min_rates(struct sk_buff *skb, struct ath_tx_control *txctl) hdr = (struct ieee80211_hdr *)skb->data; fc = hdr->frame_control; - tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0]; + + /* XXX: HACK! */ + tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif; if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc)) { txctl->use_minrate = 1; @@ -288,13 +290,16 @@ static int ath_tx_prepare(struct ath_softc *sc, if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) txctl->flags |= ATH9K_TXDESC_NOACK; - if (tx_info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) + + if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) txctl->flags |= ATH9K_TXDESC_RTSENA; /* * Setup for rate calculations. */ - tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0]; + + /* XXX: HACK! */ + tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif; rcs = tx_info_priv->rcs; if (ieee80211_is_data(fc) && !txctl->use_minrate) { @@ -855,7 +860,9 @@ static int ath_tx_send_normal(struct ath_softc *sc, skb = (struct sk_buff *)bf->bf_mpdu; tx_info = IEEE80211_SKB_CB(skb); - tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0]; + + /* XXX: HACK! */ + tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif; memcpy(bf->bf_rcs, tx_info_priv->rcs, 4 * sizeof(tx_info_priv->rcs[0])); /* update starting sequence number for subsequent ADDBA request */ @@ -1249,8 +1256,9 @@ static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) } skb = bf->bf_mpdu; tx_info = IEEE80211_SKB_CB(skb); - tx_info_priv = (struct ath_tx_info_priv *) - tx_info->driver_data[0]; + + /* XXX: HACK! */ + tx_info_priv = (struct ath_tx_info_priv *) tx_info->control.vif; if (ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; if ((ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) == 0 && @@ -1431,7 +1439,8 @@ static int ath_tx_send_ampdu(struct ath_softc *sc, skb = (struct sk_buff *)bf->bf_mpdu; tx_info = IEEE80211_SKB_CB(skb); - tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0]; + /* XXX: HACK! */ + tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif; memcpy(bf->bf_rcs, tx_info_priv->rcs, 4 * sizeof(tx_info_priv->rcs[0])); /* Add sub-frame to BAW */ @@ -1466,7 +1475,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc, skb = (struct sk_buff *)bf->bf_mpdu; tx_info = IEEE80211_SKB_CB(skb); tx_info_priv = (struct ath_tx_info_priv *) - tx_info->driver_data[0]; + tx_info->control.vif; /* XXX: HACK! */ memcpy(bf->bf_rcs, tx_info_priv->rcs, 4 * sizeof(tx_info_priv->rcs[0])); @@ -1927,7 +1936,8 @@ static int ath_tx_start_dma(struct ath_softc *sc, bf->bf_flags = txctl->flags; bf->bf_keytype = txctl->keytype; - tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0]; + /* XXX: HACK! */ + tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif; rcs = tx_info_priv->rcs; bf->bf_rcs[0] = rcs[0]; bf->bf_rcs[1] = rcs[1]; diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index 098f886976f..6d65a02b705 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -1387,13 +1387,11 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, info = IEEE80211_SKB_CB(meta->skb); - memset(&info->status, 0, sizeof(info->status)); - /* * Call back to inform the ieee80211 subsystem about * the status of the transmission. */ - frame_succeed = b43_fill_txstatus_report(info, status); + frame_succeed = b43_fill_txstatus_report(dev, info, status); #ifdef CONFIG_B43_DEBUG if (frame_succeed) ring->nr_succeed_tx_packets++; diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 9aeeb6553a9..2a599fb772d 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -4555,7 +4555,7 @@ static int b43_wireless_init(struct ssb_device *dev) BIT(NL80211_IFTYPE_ADHOC); hw->queues = b43_modparam_qos ? 4 : 1; - hw->max_altrates = 1; + hw->max_rates = 2; SET_IEEE80211_DEV(hw, dev->dev); if (is_valid_ether_addr(sprom->et1mac)) SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac); diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index 40159126759..1036bef8c4c 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c @@ -587,9 +587,8 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev, spin_lock(&q->lock); /* IRQs are already disabled. */ info = IEEE80211_SKB_CB(pack->skb); - memset(&info->status, 0, sizeof(info->status)); - b43_fill_txstatus_report(info, status); + b43_fill_txstatus_report(dev, info, status); total_len = pack->skb->len + b43_txhdr_size(dev); total_len = roundup(total_len, 4); diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index 2fabcf8f047..adba89b816d 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -185,7 +185,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, u8 *_txhdr, const unsigned char *fragment_data, unsigned int fragment_len, - const struct ieee80211_tx_info *info, + struct ieee80211_tx_info *info, u16 cookie) { struct b43_txhdr *txhdr = (struct b43_txhdr *)_txhdr; @@ -202,6 +202,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, u16 phy_ctl = 0; u8 extra_ft = 0; struct ieee80211_rate *txrate; + struct ieee80211_tx_rate *rates; memset(txhdr, 0, sizeof(*txhdr)); @@ -291,7 +292,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, phy_ctl |= B43_TXH_PHY_ENC_OFDM; else phy_ctl |= B43_TXH_PHY_ENC_CCK; - if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE) + if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) phy_ctl |= B43_TXH_PHY_SHORTPRMBL; switch (b43_ieee80211_antenna_sanitize(dev, info->antenna_sel_tx)) { @@ -314,6 +315,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, B43_WARN_ON(1); } + rates = info->control.rates; /* MAC control */ if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) mac_ctl |= B43_TXH_MAC_ACK; @@ -324,12 +326,22 @@ int b43_generate_txhdr(struct b43_wldev *dev, mac_ctl |= B43_TXH_MAC_STMSDU; if (phy->type == B43_PHYTYPE_A) mac_ctl |= B43_TXH_MAC_5GHZ; - if (info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT) + + /* Overwrite rates[0].count to make the retry calculation + * in the tx status easier. need the actual retry limit to + * detect whether the fallback rate was used. + */ + if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) || + (rates[0].count <= dev->wl->hw->conf.long_frame_max_tx_count)) { + rates[0].count = dev->wl->hw->conf.long_frame_max_tx_count; mac_ctl |= B43_TXH_MAC_LONGFRAME; + } else { + rates[0].count = dev->wl->hw->conf.short_frame_max_tx_count; + } /* Generate the RTS or CTS-to-self frame */ - if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) || - (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) { + if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) || + (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) { unsigned int len; struct ieee80211_hdr *hdr; int rts_rate, rts_rate_fb; @@ -344,7 +356,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, rts_rate_fb = b43_calc_fallback_rate(rts_rate); rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb); - if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { + if (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { struct ieee80211_cts *cts; if (b43_is_old_txhdr_format(dev)) { @@ -687,10 +699,18 @@ void b43_handle_txstatus(struct b43_wldev *dev, /* Fill out the mac80211 TXstatus report based on the b43-specific * txstatus report data. This returns a boolean whether the frame was * successfully transmitted. */ -bool b43_fill_txstatus_report(struct ieee80211_tx_info *report, +bool b43_fill_txstatus_report(struct b43_wldev *dev, + struct ieee80211_tx_info *report, const struct b43_txstatus *status) { bool frame_success = 1; + int retry_limit; + + /* preserve the confiured retry limit before clearing the status + * The xmit function has overwritten the rc's value with the actual + * retry limit done by the hardware */ + retry_limit = report->status.rates[0].count; + ieee80211_tx_info_clear_status(report); if (status->acked) { /* The frame was ACKed. */ @@ -700,14 +720,32 @@ bool b43_fill_txstatus_report(struct ieee80211_tx_info *report, if (!(report->flags & IEEE80211_TX_CTL_NO_ACK)) { /* ...but we expected an ACK. */ frame_success = 0; - report->status.excessive_retries = 1; } } if (status->frame_count == 0) { /* The frame was not transmitted at all. */ - report->status.retry_count = 0; - } else - report->status.retry_count = status->frame_count - 1; + report->status.rates[0].count = 0; + } else if (status->rts_count > dev->wl->hw->conf.short_frame_max_tx_count) { + /* + * If the short retries (RTS, not data frame) have exceeded + * the limit, the hw will not have tried the selected rate, + * but will have used the fallback rate instead. + * Don't let the rate control count attempts for the selected + * rate in this case, otherwise the statistics will be off. + */ + report->status.rates[0].count = 0; + report->status.rates[1].count = status->frame_count; + } else { + if (status->frame_count > retry_limit) { + report->status.rates[0].count = retry_limit; + report->status.rates[1].count = status->frame_count - + retry_limit; + + } else { + report->status.rates[0].count = status->frame_count; + report->status.rates[1].idx = -1; + } + } return frame_success; } diff --git a/drivers/net/wireless/b43/xmit.h b/drivers/net/wireless/b43/xmit.h index 0215faf4754..4fb2a190f7a 100644 --- a/drivers/net/wireless/b43/xmit.h +++ b/drivers/net/wireless/b43/xmit.h @@ -178,7 +178,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, u8 * txhdr, const unsigned char *fragment_data, unsigned int fragment_len, - const struct ieee80211_tx_info *txctl, u16 cookie); + struct ieee80211_tx_info *txctl, u16 cookie); /* Transmit Status */ struct b43_txstatus { @@ -294,7 +294,8 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr); void b43_handle_txstatus(struct b43_wldev *dev, const struct b43_txstatus *status); -bool b43_fill_txstatus_report(struct ieee80211_tx_info *report, +bool b43_fill_txstatus_report(struct b43_wldev *dev, + struct ieee80211_tx_info *report, const struct b43_txstatus *status); void b43_tx_suspend(struct b43_wldev *dev); diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c index fb6819e40f3..308c2647f00 100644 --- a/drivers/net/wireless/b43legacy/dma.c +++ b/drivers/net/wireless/b43legacy/dma.c @@ -1411,6 +1411,7 @@ void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev, struct b43legacy_dmaring *ring; struct b43legacy_dmadesc_generic *desc; struct b43legacy_dmadesc_meta *meta; + int retry_limit; int slot; ring = parse_cookie(dev, status->cookie, &slot); @@ -1437,25 +1438,42 @@ void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev, struct ieee80211_tx_info *info; BUG_ON(!meta->skb); info = IEEE80211_SKB_CB(meta->skb); - /* Call back to inform the ieee80211 subsystem about the - * status of the transmission. - * Some fields of txstat are already filled in dma_tx(). - */ - memset(&info->status, 0, sizeof(info->status)); + /* preserve the confiured retry limit before clearing the status + * The xmit function has overwritten the rc's value with the actual + * retry limit done by the hardware */ + retry_limit = info->status.rates[0].count; + ieee80211_tx_info_clear_status(info); - if (status->acked) { + if (status->acked) info->flags |= IEEE80211_TX_STAT_ACK; + + if (status->rts_count > dev->wl->hw->conf.short_frame_max_tx_count) { + /* + * If the short retries (RTS, not data frame) have exceeded + * the limit, the hw will not have tried the selected rate, + * but will have used the fallback rate instead. + * Don't let the rate control count attempts for the selected + * rate in this case, otherwise the statistics will be off. + */ + info->status.rates[0].count = 0; + info->status.rates[1].count = status->frame_count; } else { - if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) - info->status.excessive_retries = 1; + if (status->frame_count > retry_limit) { + info->status.rates[0].count = retry_limit; + info->status.rates[1].count = status->frame_count - + retry_limit; + + } else { + info->status.rates[0].count = status->frame_count; + info->status.rates[1].idx = -1; + } } - if (status->frame_count == 0) { - /* The frame was not transmitted at all. */ - info->status.retry_count = 0; - } else - info->status.retry_count = status->frame_count - - 1; + + /* Call back to inform the ieee80211 subsystem about the + * status of the transmission. + * Some fields of txstat are already filled in dma_tx(). + */ ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb); /* skb is freed by ieee80211_tx_status_irqsafe() */ meta->skb = NULL; diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 78e46365f69..9edbdf9cb50 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -3682,7 +3682,7 @@ static int b43legacy_wireless_init(struct ssb_device *dev) BIT(NL80211_IFTYPE_WDS) | BIT(NL80211_IFTYPE_ADHOC); hw->queues = 1; /* FIXME: hardware has more queues */ - hw->max_altrates = 1; + hw->max_rates = 2; SET_IEEE80211_DEV(hw, dev->dev); if (is_valid_ether_addr(sprom->et1mac)) SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac); diff --git a/drivers/net/wireless/b43legacy/pio.c b/drivers/net/wireless/b43legacy/pio.c index a86c7647fa2..746d5361bba 100644 --- a/drivers/net/wireless/b43legacy/pio.c +++ b/drivers/net/wireless/b43legacy/pio.c @@ -491,6 +491,7 @@ void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev, struct b43legacy_pioqueue *queue; struct b43legacy_pio_txpacket *packet; struct ieee80211_tx_info *info; + int retry_limit; queue = parse_cookie(dev, status->cookie, &packet); B43legacy_WARN_ON(!queue); @@ -503,11 +504,37 @@ void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev, sizeof(struct b43legacy_txhdr_fw3)); info = IEEE80211_SKB_CB(packet->skb); - memset(&info->status, 0, sizeof(info->status)); + + /* preserve the confiured retry limit before clearing the status + * The xmit function has overwritten the rc's value with the actual + * retry limit done by the hardware */ + retry_limit = info->status.rates[0].count; + ieee80211_tx_info_clear_status(info); if (status->acked) info->flags |= IEEE80211_TX_STAT_ACK; - info->status.retry_count = status->frame_count - 1; + + if (status->rts_count > dev->wl->hw->conf.short_frame_max_tx_count) { + /* + * If the short retries (RTS, not data frame) have exceeded + * the limit, the hw will not have tried the selected rate, + * but will have used the fallback rate instead. + * Don't let the rate control count attempts for the selected + * rate in this case, otherwise the statistics will be off. + */ + info->status.rates[0].count = 0; + info->status.rates[1].count = status->frame_count; + } else { + if (status->frame_count > retry_limit) { + info->status.rates[0].count = retry_limit; + info->status.rates[1].count = status->frame_count - + retry_limit; + + } else { + info->status.rates[0].count = status->frame_count; + info->status.rates[1].idx = -1; + } + } ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb); packet->skb = NULL; diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c index 65e83378160..12fca99f757 100644 --- a/drivers/net/wireless/b43legacy/xmit.c +++ b/drivers/net/wireless/b43legacy/xmit.c @@ -188,7 +188,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, struct b43legacy_txhdr_fw3 *txhdr, const unsigned char *fragment_data, unsigned int fragment_len, - const struct ieee80211_tx_info *info, + struct ieee80211_tx_info *info, u16 cookie) { const struct ieee80211_hdr *wlhdr; @@ -201,6 +201,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, u32 mac_ctl = 0; u16 phy_ctl = 0; struct ieee80211_rate *tx_rate; + struct ieee80211_tx_rate *rates; wlhdr = (const struct ieee80211_hdr *)fragment_data; @@ -274,7 +275,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, /* PHY TX Control word */ if (rate_ofdm) phy_ctl |= B43legacy_TX4_PHY_OFDM; - if (dev->short_preamble) + if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) phy_ctl |= B43legacy_TX4_PHY_SHORTPRMBL; switch (info->antenna_sel_tx) { case 0: @@ -291,6 +292,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, } /* MAC control */ + rates = info->control.rates; if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) mac_ctl |= B43legacy_TX4_MAC_ACK; if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) @@ -299,12 +301,22 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, mac_ctl |= B43legacy_TX4_MAC_STMSDU; if (rate_fb_ofdm) mac_ctl |= B43legacy_TX4_MAC_FALLBACKOFDM; - if (info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT) + + /* Overwrite rates[0].count to make the retry calculation + * in the tx status easier. need the actual retry limit to + * detect whether the fallback rate was used. + */ + if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) || + (rates[0].count <= dev->wl->hw->conf.long_frame_max_tx_count)) { + rates[0].count = dev->wl->hw->conf.long_frame_max_tx_count; mac_ctl |= B43legacy_TX4_MAC_LONGFRAME; + } else { + rates[0].count = dev->wl->hw->conf.short_frame_max_tx_count; + } /* Generate the RTS or CTS-to-self frame */ - if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) || - (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) { + if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) || + (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) { unsigned int len; struct ieee80211_hdr *hdr; int rts_rate; @@ -319,7 +331,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, if (rts_rate_fb_ofdm) mac_ctl |= B43legacy_TX4_MAC_CTSFALLBACKOFDM; - if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { + if (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { ieee80211_ctstoself_get(dev->wl->hw, info->control.vif, fragment_data, @@ -362,7 +374,7 @@ int b43legacy_generate_txhdr(struct b43legacy_wldev *dev, u8 *txhdr, const unsigned char *fragment_data, unsigned int fragment_len, - const struct ieee80211_tx_info *info, + struct ieee80211_tx_info *info, u16 cookie) { return generate_txhdr_fw3(dev, (struct b43legacy_txhdr_fw3 *)txhdr, diff --git a/drivers/net/wireless/b43legacy/xmit.h b/drivers/net/wireless/b43legacy/xmit.h index e56777e0fea..62e09d02788 100644 --- a/drivers/net/wireless/b43legacy/xmit.h +++ b/drivers/net/wireless/b43legacy/xmit.h @@ -80,7 +80,7 @@ int b43legacy_generate_txhdr(struct b43legacy_wldev *dev, u8 *txhdr, const unsigned char *fragment_data, unsigned int fragment_len, - const struct ieee80211_tx_info *info, + struct ieee80211_tx_info *info, u16 cookie); diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index c25daec4f93..f440ed0fe54 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -422,34 +422,6 @@ static void rs_free_sta(void *priv, struct ieee80211_sta *sta, } -/* - * get ieee prev rate from rate scale table. - * for A and B mode we need to overright prev - * value - */ -static int rs_adjust_next_rate(struct iwl3945_priv *priv, int rate) -{ - int next_rate = iwl3945_get_prev_ieee_rate(rate); - - switch (priv->band) { - case IEEE80211_BAND_5GHZ: - if (rate == IWL_RATE_12M_INDEX) - next_rate = IWL_RATE_9M_INDEX; - else if (rate == IWL_RATE_6M_INDEX) - next_rate = IWL_RATE_6M_INDEX; - break; -/* XXX cannot be invoked in current mac80211 so not a regression - case MODE_IEEE80211B: - if (rate == IWL_RATE_11M_INDEX_TABLE) - next_rate = IWL_RATE_5M_INDEX_TABLE; - break; - */ - default: - break; - } - - return next_rate; -} /** * rs_tx_status - Update rate control values based on Tx results * @@ -460,17 +432,21 @@ static void rs_tx_status(void *priv_rate, struct ieee80211_supported_band *sband struct ieee80211_sta *sta, void *priv_sta, struct sk_buff *skb) { - u8 retries, current_count; + u8 retries = 0, current_count; int scale_rate_index, first_index, last_index; unsigned long flags; struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_rate; struct iwl3945_rs_sta *rs_sta = priv_sta; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + int i; IWL_DEBUG_RATE("enter\n"); - retries = info->status.retry_count; - first_index = sband->bitrates[info->tx_rate_idx].hw_value; + for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) + retries += info->status.rates[i].count; + retries--; + + first_index = sband->bitrates[info->status.rates[0].idx].hw_value; if ((first_index < 0) || (first_index >= IWL_RATE_COUNT)) { IWL_DEBUG_RATE("leave: Rate out of bounds: %d\n", first_index); return; @@ -502,7 +478,7 @@ static void rs_tx_status(void *priv_rate, struct ieee80211_supported_band *sband last_index = scale_rate_index; } else { current_count = priv->retry_rate; - last_index = rs_adjust_next_rate(priv, + last_index = iwl3945_rs_next_rate(priv, scale_rate_index); } @@ -518,7 +494,7 @@ static void rs_tx_status(void *priv_rate, struct ieee80211_supported_band *sband if (retries) scale_rate_index = - rs_adjust_next_rate(priv, scale_rate_index); + iwl3945_rs_next_rate(priv, scale_rate_index); } @@ -630,10 +606,11 @@ static u16 iwl3945_get_adjacent_rate(struct iwl3945_rs_sta *rs_sta, * rate table and must reference the driver allocated rate table * */ -static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, - struct ieee80211_sta *sta, void *priv_sta, - struct sk_buff *skb, struct rate_selection *sel) +static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, + void *priv_sta, struct ieee80211_tx_rate_control *txrc) { + struct ieee80211_supported_band *sband = txrc->sband; + struct sk_buff *skb = txrc->skb; u8 low = IWL_RATE_INVALID; u8 high = IWL_RATE_INVALID; u16 high_low; @@ -649,6 +626,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; u16 fc, rate_mask; struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_r; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); IWL_DEBUG_RATE("enter\n"); @@ -659,7 +637,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, is_multicast_ether_addr(hdr->addr1) || !sta || !priv_sta) { IWL_DEBUG_RATE("leave: No STA priv data to update!\n"); - sel->rate_idx = rate_lowest_index(sband, sta); + info->control.rates[0].idx = rate_lowest_index(sband, sta); return; } @@ -792,9 +770,10 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, rs_sta->last_txrate_idx = index; if (sband->band == IEEE80211_BAND_5GHZ) - sel->rate_idx = rs_sta->last_txrate_idx - IWL_FIRST_OFDM_RATE; + info->control.rates[0].idx = rs_sta->last_txrate_idx - + IWL_FIRST_OFDM_RATE; else - sel->rate_idx = rs_sta->last_txrate_idx; + info->control.rates[0].idx = rs_sta->last_txrate_idx; IWL_DEBUG_RATE("leave: %d\n", index); } diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 8a00245be51..7afafb62970 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -261,6 +261,35 @@ static inline const char *iwl3945_get_tx_fail_reason(u32 status) } #endif +/* + * get ieee prev rate from rate scale table. + * for A and B mode we need to overright prev + * value + */ +int iwl3945_rs_next_rate(struct iwl3945_priv *priv, int rate) +{ + int next_rate = iwl3945_get_prev_ieee_rate(rate); + + switch (priv->band) { + case IEEE80211_BAND_5GHZ: + if (rate == IWL_RATE_12M_INDEX) + next_rate = IWL_RATE_9M_INDEX; + else if (rate == IWL_RATE_6M_INDEX) + next_rate = IWL_RATE_6M_INDEX; + break; +/* XXX cannot be invoked in current mac80211 so not a regression + case MODE_IEEE80211B: + if (rate == IWL_RATE_11M_INDEX_TABLE) + next_rate = IWL_RATE_5M_INDEX_TABLE; + break; + */ + default: + break; + } + + return next_rate; +} + /** * iwl3945_tx_queue_reclaim - Reclaim Tx queue entries already Tx'd @@ -308,6 +337,7 @@ static void iwl3945_rx_reply_tx(struct iwl3945_priv *priv, struct iwl3945_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; u32 status = le32_to_cpu(tx_resp->status); int rate_idx; + int fail, i; if ((index >= txq->q.n_bd) || (iwl3945_x2_queue_used(&txq->q, index) == 0)) { IWL_ERROR("Read index for DMA queue txq_id (%d) index %d " @@ -318,9 +348,36 @@ static void iwl3945_rx_reply_tx(struct iwl3945_priv *priv, } info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]); - memset(&info->status, 0, sizeof(info->status)); + ieee80211_tx_info_clear_status(info); + + /* Fill the MRR chain with some info about on-chip retransmissions */ + rate_idx = iwl3945_hwrate_to_plcp_idx(tx_resp->rate); + if (info->band == IEEE80211_BAND_5GHZ) + rate_idx -= IWL_FIRST_OFDM_RATE; + + fail = tx_resp->failure_frame; + for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { + int next = iwl3945_rs_next_rate(priv, rate_idx); + + info->status.rates[i].idx = rate_idx; + + /* + * Put remaining into the last count as best approximation + * of saying exactly what the hardware would have done... + */ + if ((rate_idx == next) || (i == IEEE80211_TX_MAX_RATES - 1)) { + info->status.rates[i].count = fail; + break; + } + + info->status.rates[i].count = priv->retry_rate; + fail -= priv->retry_rate; + rate_idx = next; + if (fail <= 0) + break; + } + info->status.rates[i].count++; /* add final attempt */ - info->status.retry_count = tx_resp->failure_frame; /* tx_status->rts_retry_count = tx_resp->failure_rts; */ info->flags |= ((status & TX_STATUS_MSK) == TX_STATUS_SUCCESS) ? IEEE80211_TX_STAT_ACK : 0; @@ -329,10 +386,6 @@ static void iwl3945_rx_reply_tx(struct iwl3945_priv *priv, txq_id, iwl3945_get_tx_fail_reason(status), status, tx_resp->rate, tx_resp->failure_frame); - rate_idx = iwl3945_hwrate_to_plcp_idx(tx_resp->rate); - if (info->band == IEEE80211_BAND_5GHZ) - rate_idx -= IWL_FIRST_OFDM_RATE; - info->tx_rate_idx = rate_idx; IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index); iwl3945_tx_queue_reclaim(priv, txq_id, index); diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index bdd32475b99..592c5958723 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -954,6 +954,8 @@ static inline int is_channel_ibss(const struct iwl3945_channel_info *ch) extern const struct iwl3945_channel_info *iwl3945_get_channel_info( const struct iwl3945_priv *priv, enum ieee80211_band band, u16 channel); +extern int iwl3945_rs_next_rate(struct iwl3945_priv *priv, int rate); + /* Requires full declaration of iwl3945_priv before including */ #include "iwl-3945-io.h" diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 9838de5f436..222c2baa95c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -619,10 +619,10 @@ static void iwl4965_gain_computation(struct iwl_priv *priv, static void iwl4965_rts_tx_cmd_flag(struct ieee80211_tx_info *info, __le32 *tx_flags) { - if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) { + if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) { *tx_flags |= TX_CMD_FLG_RTS_MSK; *tx_flags &= ~TX_CMD_FLG_CTS_MSK; - } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { + } else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { *tx_flags &= ~TX_CMD_FLG_RTS_MSK; *tx_flags |= TX_CMD_FLG_CTS_MSK; } @@ -2070,7 +2070,7 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv, agg->frame_count, agg->start_idx, idx); info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]); - info->status.retry_count = tx_resp->failure_frame; + info->status.rates[0].count = tx_resp->failure_frame + 1; info->flags &= ~IEEE80211_TX_CTL_AMPDU; info->flags |= iwl_is_tx_success(status)? IEEE80211_TX_STAT_ACK : 0; @@ -2227,7 +2227,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, iwl_txq_check_empty(priv, sta_id, tid, txq_id); } } else { - info->status.retry_count = tx_resp->failure_frame; + info->status.rates[0].count = tx_resp->failure_frame + 1; info->flags |= iwl_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0; iwl_hwrate_to_tx_control(priv, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 56a3f0c84a1..d5282fa6508 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -390,8 +390,8 @@ static void iwl5000_chain_noise_reset(struct iwl_priv *priv) static void iwl5000_rts_tx_cmd_flag(struct ieee80211_tx_info *info, __le32 *tx_flags) { - if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) || - (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) + if ((info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) || + (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) *tx_flags |= TX_CMD_FLG_RTS_CTS_MSK; else *tx_flags &= ~TX_CMD_FLG_RTS_CTS_MSK; @@ -1154,7 +1154,7 @@ static int iwl5000_tx_status_reply_tx(struct iwl_priv *priv, agg->frame_count, agg->start_idx, idx); info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]); - info->status.retry_count = tx_resp->failure_frame; + info->status.rates[0].count = tx_resp->failure_frame + 1; info->flags &= ~IEEE80211_TX_CTL_AMPDU; info->flags |= iwl_is_tx_success(status)? IEEE80211_TX_STAT_ACK : 0; @@ -1307,7 +1307,7 @@ static void iwl5000_rx_reply_tx(struct iwl_priv *priv, iwl_txq_check_empty(priv, sta_id, tid, txq_id); } } else { - info->status.retry_count = tx_resp->failure_frame; + info->status.rates[0].count = tx_resp->failure_frame + 1; info->flags = iwl_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0; iwl_hwrate_to_tx_control(priv, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index e10e0ca09ce..f685e5d6c28 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -798,7 +798,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, !(info->flags & IEEE80211_TX_STAT_AMPDU)) return; - retries = info->status.retry_count; + retries = info->status.rates[0].count - 1; if (retries > 15) retries = 15; @@ -830,20 +830,15 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, if (priv->band == IEEE80211_BAND_5GHZ) rs_index -= IWL_FIRST_OFDM_RATE; - if ((info->tx_rate_idx < 0) || - (tbl_type.is_SGI ^ - !!(info->flags & IEEE80211_TX_CTL_SHORT_GI)) || - (tbl_type.is_fat ^ - !!(info->flags & IEEE80211_TX_CTL_40_MHZ_WIDTH)) || - (tbl_type.is_dup ^ - !!(info->flags & IEEE80211_TX_CTL_DUP_DATA)) || - (tbl_type.ant_type ^ info->antenna_sel_tx) || - (!!(tx_rate & RATE_MCS_HT_MSK) ^ - !!(info->flags & IEEE80211_TX_CTL_OFDM_HT)) || - (!!(tx_rate & RATE_MCS_GF_MSK) ^ - !!(info->flags & IEEE80211_TX_CTL_GREEN_FIELD)) || + if ((info->status.rates[0].idx < 0) || + (tbl_type.is_SGI != !!(info->status.rates[0].flags & IEEE80211_TX_RC_SHORT_GI)) || + (tbl_type.is_fat != !!(info->status.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)) || + (tbl_type.is_dup != !!(info->status.rates[0].flags & IEEE80211_TX_RC_DUP_DATA)) || + (tbl_type.ant_type != info->antenna_sel_tx) || + (!!(tx_rate & RATE_MCS_HT_MSK) != !!(info->status.rates[0].flags & IEEE80211_TX_RC_MCS)) || + (!!(tx_rate & RATE_MCS_GF_MSK) != !!(info->status.rates[0].flags & IEEE80211_TX_RC_GREEN_FIELD)) || (hw->wiphy->bands[priv->band]->bitrates[rs_index].bitrate != - hw->wiphy->bands[info->band]->bitrates[info->tx_rate_idx].bitrate)) { + hw->wiphy->bands[info->band]->bitrates[info->status.rates[0].idx].bitrate)) { IWL_DEBUG_RATE("initial rate does not match 0x%x\n", tx_rate); goto out; } @@ -2098,15 +2093,17 @@ static void rs_initialize_lq(struct iwl_priv *priv, return; } -static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, - struct ieee80211_sta *sta, void *priv_sta, - struct sk_buff *skb, struct rate_selection *sel) +static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, + struct ieee80211_tx_rate_control *txrc) { int i; + struct sk_buff *skb = txrc->skb; + struct ieee80211_supported_band *sband = txrc->sband; struct iwl_priv *priv = (struct iwl_priv *)priv_r; struct ieee80211_conf *conf = &priv->hw->conf; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); __le16 fc; struct iwl_lq_sta *lq_sta; @@ -2117,7 +2114,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, fc = hdr->frame_control; if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) || !sta || !priv_sta) { - sel->rate_idx = rate_lowest_index(sband, sta); + info->control.rates[0].idx = rate_lowest_index(sband, sta); return; } @@ -2143,13 +2140,13 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, } if ((i < 0) || (i > IWL_RATE_COUNT)) { - sel->rate_idx = rate_lowest_index(sband, sta); + info->control.rates[0].idx = rate_lowest_index(sband, sta); return; } if (sband->band == IEEE80211_BAND_5GHZ) i -= IWL_FIRST_OFDM_RATE; - sel->rate_idx = i; + info->control.rates[0].idx = i; } static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 10f5a0a233f..2c4162e4814 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -88,26 +88,27 @@ EXPORT_SYMBOL(iwl_rates); * translate ucode response to mac80211 tx status control values */ void iwl_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, - struct ieee80211_tx_info *control) + struct ieee80211_tx_info *info) { int rate_index; + struct ieee80211_tx_rate *r = &info->control.rates[0]; - control->antenna_sel_tx = + info->antenna_sel_tx = ((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS); if (rate_n_flags & RATE_MCS_HT_MSK) - control->flags |= IEEE80211_TX_CTL_OFDM_HT; + r->flags |= IEEE80211_TX_RC_MCS; if (rate_n_flags & RATE_MCS_GF_MSK) - control->flags |= IEEE80211_TX_CTL_GREEN_FIELD; + r->flags |= IEEE80211_TX_RC_GREEN_FIELD; if (rate_n_flags & RATE_MCS_FAT_MSK) - control->flags |= IEEE80211_TX_CTL_40_MHZ_WIDTH; + r->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; if (rate_n_flags & RATE_MCS_DUP_MSK) - control->flags |= IEEE80211_TX_CTL_DUP_DATA; + r->flags |= IEEE80211_TX_RC_DUP_DATA; if (rate_n_flags & RATE_MCS_SGI_MSK) - control->flags |= IEEE80211_TX_CTL_SHORT_GI; + r->flags |= IEEE80211_TX_RC_SHORT_GI; rate_index = iwl_hwrate_to_plcp_idx(rate_n_flags); - if (control->band == IEEE80211_BAND_5GHZ) + if (info->band == IEEE80211_BAND_5GHZ) rate_index -= IWL_FIRST_OFDM_RATE; - control->tx_rate_idx = rate_index; + r->idx = rate_index; } EXPORT_SYMBOL(iwl_hwrate_to_tx_control); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index b1464c71ea0..2cd33b4e9e1 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -2395,6 +2395,7 @@ static void iwl3945_build_tx_cmd_basic(struct iwl3945_priv *priv, { __le16 fc = hdr->frame_control; __le32 tx_flags = cmd->cmd.tx.tx_flags; + u8 rc_flags = info->control.rates[0].flags; cmd->cmd.tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { @@ -2421,10 +2422,10 @@ static void iwl3945_build_tx_cmd_basic(struct iwl3945_priv *priv, tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; } - if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) { + if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) { tx_flags |= TX_CMD_FLG_RTS_MSK; tx_flags &= ~TX_CMD_FLG_CTS_MSK; - } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { + } else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { tx_flags &= ~TX_CMD_FLG_RTS_MSK; tx_flags |= TX_CMD_FLG_CTS_MSK; } diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c index 241ddcfa352..d1fc305de5f 100644 --- a/drivers/net/wireless/libertas_tf/main.c +++ b/drivers/net/wireless/libertas_tf/main.c @@ -592,14 +592,14 @@ EXPORT_SYMBOL_GPL(lbtf_remove_card); void lbtf_send_tx_feedback(struct lbtf_private *priv, u8 retrycnt, u8 fail) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(priv->tx_skb); - memset(&info->status, 0, sizeof(info->status)); + + ieee80211_tx_info_clear_status(info); /* * Commented out, otherwise we never go beyond 1Mbit/s using mac80211 * default pid rc algorithm. * * info->status.retry_count = MRVL_DEFAULT_RETRIES - retrycnt; */ - info->status.excessive_retries = fail ? 1 : 0; if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && !fail) info->flags |= IEEE80211_TX_STAT_ACK; skb_pull(priv->tx_skb, sizeof(struct txpd)); diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index e2aeef8de70..c5765232528 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -209,7 +209,7 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, /* TODO: set mactime */ rx_status.freq = data->channel->center_freq; rx_status.band = data->channel->band; - rx_status.rate_idx = info->tx_rate_idx; + rx_status.rate_idx = info->control.rates[0].idx; /* TODO: simulate signal strength (and optional packet drop) */ /* Copy skb to all enabled radios that are on the current frequency */ @@ -269,13 +269,9 @@ static int mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb) if (txi->control.sta) hwsim_check_sta_magic(txi->control.sta); - memset(&txi->status, 0, sizeof(txi->status)); - if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK)) { - if (ack) - txi->flags |= IEEE80211_TX_STAT_ACK; - else - txi->status.excessive_retries = 1; - } + ieee80211_tx_info_clear_status(txi); + if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK) && ack) + txi->flags |= IEEE80211_TX_STAT_ACK; ieee80211_tx_status_irqsafe(hw, skb); return NETDEV_TX_OK; } diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 81a9756254f..65be5eca234 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -548,7 +548,7 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) spin_lock_irqsave(&priv->tx_queue.lock, flags); while (entry != (struct sk_buff *)&priv->tx_queue) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry); - range = (void *)info->driver_data; + range = (void *)info->rate_driver_data; if (range->start_addr == addr) { struct p54_control_hdr *entry_hdr; struct p54_tx_control_allocdata *entry_data; @@ -559,7 +559,7 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) struct memrecord *mr; ni = IEEE80211_SKB_CB(entry->next); - mr = (struct memrecord *)ni->driver_data; + mr = (struct memrecord *)ni->rate_driver_data; freed = mr->start_addr - last_addr; } else freed = priv->rx_end - last_addr; @@ -568,7 +568,7 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) __skb_unlink(entry, &priv->tx_queue); spin_unlock_irqrestore(&priv->tx_queue.lock, flags); - memset(&info->status, 0, sizeof(info->status)); + ieee80211_tx_info_clear_status(info); entry_hdr = (struct p54_control_hdr *) entry->data; entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data; if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0) @@ -578,10 +578,8 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { if (!(payload->status & 0x01)) info->flags |= IEEE80211_TX_STAT_ACK; - else - info->status.excessive_retries = 1; } - info->status.retry_count = payload->retries - 1; + info->status.rates[0].count = payload->retries; info->status.ack_signal = p54_rssi_to_dbm(dev, le16_to_cpu(payload->ack_rssi)); skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data)); @@ -699,7 +697,7 @@ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, while (left--) { u32 hole_size; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry); - struct memrecord *range = (void *)info->driver_data; + struct memrecord *range = (void *)info->rate_driver_data; hole_size = range->start_addr - last_addr; if (!target_skb && hole_size >= len) { target_skb = entry->prev; @@ -715,7 +713,7 @@ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, largest_hole = max(largest_hole, priv->rx_end - last_addr - len); if (!skb_queue_empty(&priv->tx_queue)) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(target_skb); - struct memrecord *range = (void *)info->driver_data; + struct memrecord *range = (void *)info->rate_driver_data; target_addr = range->end_addr; } } else @@ -723,7 +721,7 @@ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, if (skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct memrecord *range = (void *)info->driver_data; + struct memrecord *range = (void *)info->rate_driver_data; range->start_addr = target_addr; range->end_addr = target_addr + len; __skb_queue_after(&priv->tx_queue, target_skb, skb); @@ -806,6 +804,7 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) size_t padding, len; u8 rate; u8 cts_rate = 0x20; + u8 rc_flags; current_queue = &priv->tx_stats[skb_get_queue_mapping(skb) + 4]; if (unlikely(current_queue->len > current_queue->limit)) @@ -828,18 +827,19 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) hdr->magic1 = cpu_to_le16(0x0010); hdr->len = cpu_to_le16(len); hdr->type = (info->flags & IEEE80211_TX_CTL_NO_ACK) ? 0 : cpu_to_le16(1); - hdr->retry1 = hdr->retry2 = info->control.retry_limit; + hdr->retry1 = hdr->retry2 = info->control.rates[0].count; /* TODO: add support for alternate retry TX rates */ rate = ieee80211_get_tx_rate(dev, info)->hw_value; - if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE) { + rc_flags = info->control.rates[0].flags; + if (rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) { rate |= 0x10; cts_rate |= 0x10; } - if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) { + if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) { rate |= 0x40; cts_rate |= ieee80211_get_rts_cts_rate(dev, info)->hw_value; - } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { + } else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { rate |= 0x20; cts_rate |= ieee80211_get_rts_cts_rate(dev, info)->hw_value; } diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 697806cf94e..e1feab8b6b0 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -498,7 +498,9 @@ void rt2x00lib_txdone(struct queue_entry *entry, { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); enum data_queue_qid qid = skb_get_queue_mapping(entry->skb); + u8 rate_idx, rate_flags; /* * Unmap the skb. @@ -528,14 +530,18 @@ void rt2x00lib_txdone(struct queue_entry *entry, rt2x00dev->link.qual.tx_failed += test_bit(TXDONE_FAILURE, &txdesc->flags); + rate_idx = skbdesc->tx_rate_idx; + rate_flags = skbdesc->tx_rate_flags; + /* * Initialize TX status */ memset(&tx_info->status, 0, sizeof(tx_info->status)); tx_info->status.ack_signal = 0; - tx_info->status.excessive_retries = - test_bit(TXDONE_EXCESSIVE_RETRY, &txdesc->flags); - tx_info->status.retry_count = txdesc->retry; + tx_info->status.rates[0].idx = rate_idx; + tx_info->status.rates[0].flags = rate_flags; + tx_info->status.rates[0].count = txdesc->retry + 1; + tx_info->status.rates[1].idx = -1; /* terminate */ if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) { if (test_bit(TXDONE_SUCCESS, &txdesc->flags)) @@ -544,7 +550,7 @@ void rt2x00lib_txdone(struct queue_entry *entry, rt2x00dev->low_level_stats.dot11ACKFailureCount++; } - if (tx_info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) { + if (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS) { if (test_bit(TXDONE_SUCCESS, &txdesc->flags)) rt2x00dev->low_level_stats.dot11RTSSuccessCount++; else if (test_bit(TXDONE_FAILURE, &txdesc->flags)) diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 931183369f0..b32d59eafaa 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -39,7 +39,7 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, unsigned int data_length; int retval = 0; - if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) + if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) data_length = sizeof(struct ieee80211_cts); else data_length = sizeof(struct ieee80211_rts); @@ -64,11 +64,11 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, */ memcpy(skb->cb, frag_skb->cb, sizeof(skb->cb)); rts_info = IEEE80211_SKB_CB(skb); - rts_info->flags &= ~IEEE80211_TX_CTL_USE_RTS_CTS; - rts_info->flags &= ~IEEE80211_TX_CTL_USE_CTS_PROTECT; + rts_info->control.rates[0].flags &= ~IEEE80211_TX_RC_USE_RTS_CTS; + rts_info->control.rates[0].flags &= ~IEEE80211_TX_RC_USE_CTS_PROTECT; rts_info->flags &= ~IEEE80211_TX_CTL_REQ_TX_STATUS; - if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) + if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) rts_info->flags |= IEEE80211_TX_CTL_NO_ACK; else rts_info->flags &= ~IEEE80211_TX_CTL_NO_ACK; @@ -84,7 +84,7 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, data_length += rt2x00crypto_tx_overhead(tx_info); #endif /* CONFIG_RT2X00_LIB_CRYPTO */ - if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) + if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) ieee80211_ctstoself_get(rt2x00dev->hw, tx_info->control.vif, frag_skb->data, data_length, tx_info, (struct ieee80211_cts *)(skb->data)); @@ -146,8 +146,8 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) * inside the hardware. */ frame_control = le16_to_cpu(ieee80211hdr->frame_control); - if ((tx_info->flags & (IEEE80211_TX_CTL_USE_RTS_CTS | - IEEE80211_TX_CTL_USE_CTS_PROTECT)) && + if ((tx_info->control.rates[0].flags & (IEEE80211_TX_RC_USE_RTS_CTS | + IEEE80211_TX_RC_USE_CTS_PROTECT)) && !rt2x00dev->ops->hw->set_rts_threshold) { if (rt2x00queue_available(queue) <= 1) goto exit_fail; diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 451d410ecda..070786ebd07 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -230,8 +230,15 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, /* * Determine retry information. */ - txdesc->retry_limit = tx_info->control.retry_limit; - if (tx_info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT) + txdesc->retry_limit = tx_info->control.rates[0].count - 1; + /* + * XXX: If at this point we knew whether the HW is going to use + * the RETRY_MODE bit or the retry_limit (currently all + * use the RETRY_MODE bit) we could do something like b43 + * does, set the RETRY_MODE bit when the RC algorithm is + * requesting more than the long retry limit. + */ + if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) __set_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags); /* @@ -371,10 +378,12 @@ static void rt2x00queue_write_tx_descriptor(struct queue_entry *entry, int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) { + struct ieee80211_tx_info *tx_info; struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX); struct txentry_desc txdesc; struct skb_frame_desc *skbdesc; unsigned int iv_len = 0; + u8 rate_idx, rate_flags; if (unlikely(rt2x00queue_full(queue))) return -EINVAL; @@ -399,13 +408,18 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) iv_len = IEEE80211_SKB_CB(skb)->control.hw_key->iv_len; /* - * All information is retreived from the skb->cb array, + * All information is retrieved from the skb->cb array, * now we should claim ownership of the driver part of that - * array. + * array, preserving the bitrate index and flags. */ + tx_info = IEEE80211_SKB_CB(skb); + rate_idx = tx_info->control.rates[0].idx; + rate_flags = tx_info->control.rates[0].flags; skbdesc = get_skb_frame_desc(entry->skb); memset(skbdesc, 0, sizeof(*skbdesc)); skbdesc->entry = entry; + skbdesc->tx_rate_idx = rate_idx; + skbdesc->tx_rate_flags = rate_flags; /* * When hardware encryption is supported, and this frame diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 9dbf04f0f04..4d3c7246f9a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -104,6 +104,8 @@ enum skb_frame_desc_flags { * * @flags: Frame flags, see &enum skb_frame_desc_flags. * @desc_len: Length of the frame descriptor. + * @tx_rate_idx: the index of the TX rate, used for TX status reporting + * @tx_rate_flags: the TX rate flags, used for TX status reporting * @desc: Pointer to descriptor part of the frame. * Note that this pointer could point to something outside * of the scope of the skb->data pointer. @@ -113,9 +115,12 @@ enum skb_frame_desc_flags { * @entry: The entry to which this sk buffer belongs. */ struct skb_frame_desc { - unsigned int flags; + u8 flags; + + u8 desc_len; + u8 tx_rate_idx; + u8 tx_rate_flags; - unsigned int desc_len; void *desc; __le32 iv; diff --git a/drivers/net/wireless/rtl8180_dev.c b/drivers/net/wireless/rtl8180_dev.c index e8d22393797..6c226c024dd 100644 --- a/drivers/net/wireless/rtl8180_dev.c +++ b/drivers/net/wireless/rtl8180_dev.c @@ -182,15 +182,13 @@ static void rtl8180_handle_tx(struct ieee80211_hw *dev, unsigned int prio) skb->len, PCI_DMA_TODEVICE); info = IEEE80211_SKB_CB(skb); - memset(&info->status, 0, sizeof(info->status)); + ieee80211_tx_info_clear_status(info); - if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { - if (flags & RTL818X_TX_DESC_FLAG_TX_OK) - info->flags |= IEEE80211_TX_STAT_ACK; - else - info->status.excessive_retries = 1; - } - info->status.retry_count = flags & 0xFF; + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && + (flags & RTL818X_TX_DESC_FLAG_TX_OK)) + info->flags |= IEEE80211_TX_STAT_ACK; + + info->status.rates[0].count = (flags & 0xFF) + 1; ieee80211_tx_status_irqsafe(dev, skb); if (ring->entries - skb_queue_len(&ring->queue) == 2) @@ -243,6 +241,7 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb) unsigned int idx, prio; dma_addr_t mapping; u32 tx_flags; + u8 rc_flags; u16 plcp_len = 0; __le16 rts_duration = 0; @@ -261,15 +260,16 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb) tx_flags |= RTL818X_TX_DESC_FLAG_DMA | RTL818X_TX_DESC_FLAG_NO_ENC; - if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) { + rc_flags = info->control.rates[0].flags; + if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) { tx_flags |= RTL818X_TX_DESC_FLAG_RTS; tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; - } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { + } else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { tx_flags |= RTL818X_TX_DESC_FLAG_CTS; tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; } - if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) + if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) rts_duration = ieee80211_rts_duration(dev, priv->vif, skb->len, info); @@ -292,9 +292,9 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb) entry->plcp_len = cpu_to_le16(plcp_len); entry->tx_buf = cpu_to_le32(mapping); entry->frame_len = cpu_to_le32(skb->len); - entry->flags2 = info->control.retries[0].rate_idx >= 0 ? + entry->flags2 = info->control.rates[1].idx >= 0 ? ieee80211_get_alt_retry_rate(dev, info, 0)->bitrate << 4 : 0; - entry->retry_limit = info->control.retry_limit; + entry->retry_limit = info->control.rates[0].count; entry->flags = cpu_to_le32(tx_flags); __skb_queue_tail(&ring->queue, skb); if (ring->entries - skb_queue_len(&ring->queue) < 2) @@ -855,7 +855,7 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev, priv = dev->priv; priv->pdev = pdev; - dev->max_altrates = 1; + dev->max_rates = 2; SET_IEEE80211_DEV(dev, &pdev->dev); pci_set_drvdata(pdev, dev); diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index cd839bcb6d7..6260ed8ce12 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -160,13 +160,13 @@ static void rtl8187_tx_cb(struct urb *urb) { struct sk_buff *skb = (struct sk_buff *)urb->context; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_hw *hw = info->driver_data[0]; + struct ieee80211_hw *hw = info->rate_driver_data[0]; struct rtl8187_priv *priv = hw->priv; - usb_free_urb(info->driver_data[1]); + usb_free_urb(info->rate_driver_data[1]); skb_pull(skb, priv->is_rtl8187b ? sizeof(struct rtl8187b_tx_hdr) : sizeof(struct rtl8187_tx_hdr)); - memset(&info->status, 0, sizeof(info->status)); + ieee80211_tx_info_clear_status(info); info->flags |= IEEE80211_TX_STAT_ACK; ieee80211_tx_status_irqsafe(hw, skb); } @@ -194,12 +194,12 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) flags |= ieee80211_get_tx_rate(dev, info)->hw_value << 24; if (ieee80211_has_morefrags(((struct ieee80211_hdr *)skb->data)->frame_control)) flags |= RTL818X_TX_DESC_FLAG_MOREFRAG; - if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) { + if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) { flags |= RTL818X_TX_DESC_FLAG_RTS; flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; rts_dur = ieee80211_rts_duration(dev, priv->vif, skb->len, info); - } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { + } else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { flags |= RTL818X_TX_DESC_FLAG_CTS; flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; } @@ -210,7 +210,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) hdr->flags = cpu_to_le32(flags); hdr->len = 0; hdr->rts_duration = rts_dur; - hdr->retry = cpu_to_le32(info->control.retry_limit << 8); + hdr->retry = cpu_to_le32((info->control.rates[0].count - 1) << 8); buf = hdr; ep = 2; @@ -228,7 +228,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) memset(hdr, 0, sizeof(*hdr)); hdr->flags = cpu_to_le32(flags); hdr->rts_duration = rts_dur; - hdr->retry = cpu_to_le32(info->control.retry_limit << 8); + hdr->retry = cpu_to_le32((info->control.rates[0].count - 1) << 8); hdr->tx_duration = ieee80211_generic_frame_duration(dev, priv->vif, skb->len, txrate); @@ -240,8 +240,8 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) ep = epmap[skb_get_queue_mapping(skb)]; } - info->driver_data[0] = dev; - info->driver_data[1] = urb; + info->rate_driver_data[0] = dev; + info->rate_driver_data[1] = urb; usb_fill_bulk_urb(urb, priv->udev, usb_sndbulkpipe(priv->udev, ep), buf, skb->len, rtl8187_tx_cb, skb); diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 6c3e21887fc..2f0802b29c4 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -296,15 +296,14 @@ static void zd_op_stop(struct ieee80211_hw *hw) * If no status information has been requested, the skb is freed. */ static void tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, - u32 flags, int ackssi, bool success) + int ackssi, bool success) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - memset(&info->status, 0, sizeof(info->status)); + ieee80211_tx_info_clear_status(info); - if (!success) - info->status.excessive_retries = 1; - info->flags |= flags; + if (success) + info->flags |= IEEE80211_TX_STAT_ACK; info->status.ack_signal = ackssi; ieee80211_tx_status_irqsafe(hw, skb); } @@ -326,7 +325,7 @@ void zd_mac_tx_failed(struct ieee80211_hw *hw) if (skb == NULL) return; - tx_status(hw, skb, 0, 0, 0); + tx_status(hw, skb, 0, 0); } /** @@ -342,12 +341,12 @@ void zd_mac_tx_failed(struct ieee80211_hw *hw) void zd_mac_tx_to_dev(struct sk_buff *skb, int error) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_hw *hw = info->driver_data[0]; + struct ieee80211_hw *hw = info->rate_driver_data[0]; skb_pull(skb, sizeof(struct zd_ctrlset)); if (unlikely(error || (info->flags & IEEE80211_TX_CTL_NO_ACK))) { - tx_status(hw, skb, 0, 0, !error); + tx_status(hw, skb, 0, !error); } else { struct sk_buff_head *q = &zd_hw_mac(hw)->ack_wait_queue; @@ -406,7 +405,8 @@ static int zd_calc_tx_length_us(u8 *service, u8 zd_rate, u16 tx_length) } static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs, - struct ieee80211_hdr *header, u32 flags) + struct ieee80211_hdr *header, + struct ieee80211_tx_info *info) { /* * CONTROL TODO: @@ -417,7 +417,7 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs, cs->control = 0; /* First fragment */ - if (flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) + if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) cs->control |= ZD_CS_NEED_RANDOM_BACKOFF; /* Multicast */ @@ -428,10 +428,10 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs, if (ieee80211_is_pspoll(header->frame_control)) cs->control |= ZD_CS_PS_POLL_FRAME; - if (flags & IEEE80211_TX_CTL_USE_RTS_CTS) + if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) cs->control |= ZD_CS_RTS; - if (flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) + if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) cs->control |= ZD_CS_SELF_CTS; /* FIXME: Management frame? */ @@ -517,12 +517,12 @@ static int fill_ctrlset(struct zd_mac *mac, txrate = ieee80211_get_tx_rate(mac->hw, info); cs->modulation = txrate->hw_value; - if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE) + if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) cs->modulation = txrate->hw_value_short; cs->tx_length = cpu_to_le16(frag_len); - cs_set_control(mac, cs, hdr, info->flags); + cs_set_control(mac, cs, hdr, info); packet_length = frag_len + sizeof(struct zd_ctrlset) + 10; ZD_ASSERT(packet_length <= 0xffff); @@ -577,7 +577,7 @@ static int zd_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) if (r) return r; - info->driver_data[0] = hw; + info->rate_driver_data[0] = hw; r = zd_usb_tx(&mac->chip.usb, skb); if (r) @@ -618,7 +618,7 @@ static int filter_ack(struct ieee80211_hw *hw, struct ieee80211_hdr *rx_hdr, if (likely(!compare_ether_addr(tx_hdr->addr2, rx_hdr->addr1))) { __skb_unlink(skb, q); - tx_status(hw, skb, IEEE80211_TX_STAT_ACK, stats->signal, 1); + tx_status(hw, skb, stats->signal, 1); goto out; } } diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index a60ae86bd5c..d7a2f52e40c 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -907,7 +907,7 @@ free_urb: * it might be freed by zd_mac_tx_to_dev or mac80211) */ info = IEEE80211_SKB_CB(skb); - usb = &zd_hw_mac(info->driver_data[0])->chip.usb; + usb = &zd_hw_mac(info->rate_driver_data[0])->chip.usb; zd_mac_tx_to_dev(skb, urb->status); free_tx_urb(usb, urb); tx_dec_submitted_urbs(usb); diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 9801afb6254..3741c0a7978 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -214,29 +214,24 @@ struct ieee80211_bss_conf { * These flags are used with the @flags member of &ieee80211_tx_info. * * @IEEE80211_TX_CTL_REQ_TX_STATUS: request TX status callback for this frame. - * @IEEE80211_TX_CTL_USE_RTS_CTS: use RTS-CTS before sending frame - * @IEEE80211_TX_CTL_USE_CTS_PROTECT: use CTS protection for the frame (e.g., - * for combined 802.11g / 802.11b networks) + * @IEEE80211_TX_CTL_ASSIGN_SEQ: The driver has to assign a sequence + * number to this frame, taking care of not overwriting the fragment + * number and increasing the sequence number only when the + * IEEE80211_TX_CTL_FIRST_FRAGMENT flag is set. mac80211 will properly + * assign sequence numbers to QoS-data frames but cannot do so correctly + * for non-QoS-data and management frames because beacons need them from + * that counter as well and mac80211 cannot guarantee proper sequencing. + * If this flag is set, the driver should instruct the hardware to + * assign a sequence number to the frame or assign one itself. Cf. IEEE + * 802.11-2007 7.1.3.4.1 paragraph 3. This flag will always be set for + * beacons and always be clear for frames without a sequence number field. * @IEEE80211_TX_CTL_NO_ACK: tell the low level not to wait for an ack - * @IEEE80211_TX_CTL_RATE_CTRL_PROBE: TBD * @IEEE80211_TX_CTL_CLEAR_PS_FILT: clear powersave filter for destination * station - * @IEEE80211_TX_CTL_REQUEUE: TBD * @IEEE80211_TX_CTL_FIRST_FRAGMENT: this is a first fragment of the frame - * @IEEE80211_TX_CTL_SHORT_PREAMBLE: TBD - * @IEEE80211_TX_CTL_LONG_RETRY_LIMIT: this frame should be send using the - * through set_retry_limit configured long retry value * @IEEE80211_TX_CTL_SEND_AFTER_DTIM: send this frame after DTIM beacon * @IEEE80211_TX_CTL_AMPDU: this frame should be sent as part of an A-MPDU - * @IEEE80211_TX_CTL_OFDM_HT: this frame can be sent in HT OFDM rates. number - * of streams when this flag is on can be extracted from antenna_sel_tx, - * so if 1 antenna is marked use SISO, 2 antennas marked use MIMO, n - * antennas marked use MIMO_n. - * @IEEE80211_TX_CTL_GREEN_FIELD: use green field protection for this frame - * @IEEE80211_TX_CTL_40_MHZ_WIDTH: send this frame using 40 Mhz channel width - * @IEEE80211_TX_CTL_DUP_DATA: duplicate data frame on both 20 Mhz channels - * @IEEE80211_TX_CTL_SHORT_GI: send this frame using short guard interval - * @IEEE80211_TX_CTL_INJECTED: TBD + * @IEEE80211_TX_CTL_INJECTED: Frame was injected, internal to mac80211. * @IEEE80211_TX_STAT_TX_FILTERED: The frame was not transmitted * because the destination STA was in powersave mode. * @IEEE80211_TX_STAT_ACK: Frame was acknowledged @@ -244,62 +239,70 @@ struct ieee80211_bss_conf { * is for the whole aggregation. * @IEEE80211_TX_STAT_AMPDU_NO_BACK: no block ack was returned, * so consider using block ack request (BAR). - * @IEEE80211_TX_CTL_ASSIGN_SEQ: The driver has to assign a sequence - * number to this frame, taking care of not overwriting the fragment - * number and increasing the sequence number only when the - * IEEE80211_TX_CTL_FIRST_FRAGMENT flags is set. mac80211 will properly - * assign sequence numbers to QoS-data frames but cannot do so correctly - * for non-QoS-data and management frames because beacons need them from - * that counter as well and mac80211 cannot guarantee proper sequencing. - * If this flag is set, the driver should instruct the hardware to - * assign a sequence number to the frame or assign one itself. Cf. IEEE - * 802.11-2007 7.1.3.4.1 paragraph 3. This flag will always be set for - * beacons always be clear for frames without a sequence number field. + * @IEEE80211_TX_CTL_RATE_CTRL_PROBE: internal to mac80211, can be + * set by rate control algorithms to indicate probe rate, will + * be cleared for fragmented frames (except on the last fragment) + * @IEEE80211_TX_CTL_REQUEUE: REMOVE THIS */ enum mac80211_tx_control_flags { IEEE80211_TX_CTL_REQ_TX_STATUS = BIT(0), - IEEE80211_TX_CTL_USE_RTS_CTS = BIT(2), - IEEE80211_TX_CTL_USE_CTS_PROTECT = BIT(3), - IEEE80211_TX_CTL_NO_ACK = BIT(4), - IEEE80211_TX_CTL_RATE_CTRL_PROBE = BIT(5), - IEEE80211_TX_CTL_CLEAR_PS_FILT = BIT(6), - IEEE80211_TX_CTL_REQUEUE = BIT(7), - IEEE80211_TX_CTL_FIRST_FRAGMENT = BIT(8), - IEEE80211_TX_CTL_SHORT_PREAMBLE = BIT(9), - IEEE80211_TX_CTL_LONG_RETRY_LIMIT = BIT(10), - IEEE80211_TX_CTL_SEND_AFTER_DTIM = BIT(12), - IEEE80211_TX_CTL_AMPDU = BIT(13), - IEEE80211_TX_CTL_OFDM_HT = BIT(14), - IEEE80211_TX_CTL_GREEN_FIELD = BIT(15), - IEEE80211_TX_CTL_40_MHZ_WIDTH = BIT(16), - IEEE80211_TX_CTL_DUP_DATA = BIT(17), - IEEE80211_TX_CTL_SHORT_GI = BIT(18), - IEEE80211_TX_CTL_INJECTED = BIT(19), - IEEE80211_TX_STAT_TX_FILTERED = BIT(20), - IEEE80211_TX_STAT_ACK = BIT(21), - IEEE80211_TX_STAT_AMPDU = BIT(22), - IEEE80211_TX_STAT_AMPDU_NO_BACK = BIT(23), - IEEE80211_TX_CTL_ASSIGN_SEQ = BIT(24), + IEEE80211_TX_CTL_ASSIGN_SEQ = BIT(1), + IEEE80211_TX_CTL_NO_ACK = BIT(2), + IEEE80211_TX_CTL_CLEAR_PS_FILT = BIT(3), + IEEE80211_TX_CTL_FIRST_FRAGMENT = BIT(4), + IEEE80211_TX_CTL_SEND_AFTER_DTIM = BIT(5), + IEEE80211_TX_CTL_AMPDU = BIT(6), + IEEE80211_TX_CTL_INJECTED = BIT(7), + IEEE80211_TX_STAT_TX_FILTERED = BIT(8), + IEEE80211_TX_STAT_ACK = BIT(9), + IEEE80211_TX_STAT_AMPDU = BIT(10), + IEEE80211_TX_STAT_AMPDU_NO_BACK = BIT(11), + IEEE80211_TX_CTL_RATE_CTRL_PROBE = BIT(12), + + /* XXX: remove this */ + IEEE80211_TX_CTL_REQUEUE = BIT(13), }; +enum mac80211_rate_control_flags { + IEEE80211_TX_RC_USE_RTS_CTS = BIT(0), + IEEE80211_TX_RC_USE_CTS_PROTECT = BIT(1), + IEEE80211_TX_RC_USE_SHORT_PREAMBLE = BIT(2), + + /* rate index is an MCS rate number instead of an index */ + IEEE80211_TX_RC_MCS = BIT(3), + IEEE80211_TX_RC_GREEN_FIELD = BIT(4), + IEEE80211_TX_RC_40_MHZ_WIDTH = BIT(5), + IEEE80211_TX_RC_DUP_DATA = BIT(6), + IEEE80211_TX_RC_SHORT_GI = BIT(7), +}; + + +/* there are 40 bytes if you don't need the rateset to be kept */ +#define IEEE80211_TX_INFO_DRIVER_DATA_SIZE 40 -#define IEEE80211_TX_INFO_DRIVER_DATA_SIZE \ - (sizeof(((struct sk_buff *)0)->cb) - 8) -#define IEEE80211_TX_INFO_DRIVER_DATA_PTRS \ - (IEEE80211_TX_INFO_DRIVER_DATA_SIZE / sizeof(void *)) +/* if you do need the rateset, then you have less space */ +#define IEEE80211_TX_INFO_RATE_DRIVER_DATA_SIZE 24 -/* maximum number of alternate rate retry stages */ -#define IEEE80211_TX_MAX_ALTRATE 3 +/* maximum number of rate stages */ +#define IEEE80211_TX_MAX_RATES 5 /** - * struct ieee80211_tx_altrate - alternate rate selection/status + * struct ieee80211_tx_rate - rate selection/status * - * @rate_idx: rate index to attempt to send with + * @idx: rate index to attempt to send with + * @flags: rate control flags (&enum mac80211_rate_control_flags) * @limit: number of retries before fallback + * + * A value of -1 for @idx indicates an invalid rate and, if used + * in an array of retry rates, that no more rates should be tried. + * + * When used for transmit status reporting, the driver should + * always report the rate along with the flags it used. */ -struct ieee80211_tx_altrate { - s8 rate_idx; - u8 limit; +struct ieee80211_tx_rate { + s8 idx; + u8 count; + u8 flags; }; /** @@ -314,15 +317,12 @@ struct ieee80211_tx_altrate { * it may be NULL. * * @flags: transmit info flags, defined above - * @band: TBD - * @tx_rate_idx: TBD + * @band: the band to transmit on (use for checking for races) * @antenna_sel_tx: antenna to use, 0 for automatic diversity * @control: union for control data * @status: union for status data * @driver_data: array of driver_data pointers * @retry_count: number of retries - * @excessive_retries: set to 1 if the frame was retried many times - * but not acknowledged * @ampdu_ack_len: number of aggregated frames. * relevant only if IEEE80211_TX_STATUS_AMPDU was set. * @ampdu_ack_map: block ack bit map for the aggregation. @@ -333,31 +333,43 @@ struct ieee80211_tx_info { /* common information */ u32 flags; u8 band; - s8 tx_rate_idx; + u8 antenna_sel_tx; - /* 1 byte hole */ + /* 2 byte hole */ union { struct { + union { + /* rate control */ + struct { + struct ieee80211_tx_rate rates[ + IEEE80211_TX_MAX_RATES]; + s8 rts_cts_rate_idx; + }; + /* only needed before rate control */ + unsigned long jiffies; + }; /* NB: vif can be NULL for injected frames */ struct ieee80211_vif *vif; struct ieee80211_key_conf *hw_key; struct ieee80211_sta *sta; - unsigned long jiffies; - s8 rts_cts_rate_idx; - u8 retry_limit; - struct ieee80211_tx_altrate retries[IEEE80211_TX_MAX_ALTRATE]; } control; struct { + struct ieee80211_tx_rate rates[IEEE80211_TX_MAX_RATES]; + u8 ampdu_ack_len; u64 ampdu_ack_map; int ack_signal; - struct ieee80211_tx_altrate retries[IEEE80211_TX_MAX_ALTRATE + 1]; - u8 retry_count; - bool excessive_retries; - u8 ampdu_ack_len; + /* 8 bytes free */ } status; - void *driver_data[IEEE80211_TX_INFO_DRIVER_DATA_PTRS]; + struct { + struct ieee80211_tx_rate driver_rates[ + IEEE80211_TX_MAX_RATES]; + void *rate_driver_data[ + IEEE80211_TX_INFO_RATE_DRIVER_DATA_SIZE / sizeof(void *)]; + }; + void *driver_data[ + IEEE80211_TX_INFO_DRIVER_DATA_SIZE / sizeof(void *)]; }; }; @@ -366,6 +378,41 @@ static inline struct ieee80211_tx_info *IEEE80211_SKB_CB(struct sk_buff *skb) return (struct ieee80211_tx_info *)skb->cb; } +/** + * ieee80211_tx_info_clear_status - clear TX status + * + * @info: The &struct ieee80211_tx_info to be cleared. + * + * When the driver passes an skb back to mac80211, it must report + * a number of things in TX status. This function clears everything + * in the TX status but the rate control information (it does clear + * the count since you need to fill that in anyway). + * + * NOTE: You can only use this function if you do NOT use + * info->driver_data! Use info->rate_driver_data + * instead if you need only the less space that allows. + */ +static inline void +ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info) +{ + int i; + + BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, status.rates) != + offsetof(struct ieee80211_tx_info, control.rates)); + BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, status.rates) != + offsetof(struct ieee80211_tx_info, driver_rates)); + BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, status.rates) != 8); + /* clear the rate counts */ + for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) + info->status.rates[i].count = 0; + + BUILD_BUG_ON( + offsetof(struct ieee80211_tx_info, status.ampdu_ack_len) != 23); + memset(&info->status.ampdu_ack_len, 0, + sizeof(struct ieee80211_tx_info) - + offsetof(struct ieee80211_tx_info, status.ampdu_ack_len)); +} + /** * enum mac80211_rx_flags - receive flags @@ -869,8 +916,8 @@ enum ieee80211_hw_flags { * @sta_data_size: size (in bytes) of the drv_priv data area * within &struct ieee80211_sta. * - * @max_altrates: maximum number of alternate rate retry stages - * @max_altrate_tries: maximum number of tries for each stage + * @max_rates: maximum number of alternate rate retry stages + * @max_rate_tries: maximum number of tries for each stage */ struct ieee80211_hw { struct ieee80211_conf conf; @@ -887,8 +934,8 @@ struct ieee80211_hw { u16 ampdu_queues; u16 max_listen_interval; s8 max_signal; - u8 max_altrates; - u8 max_altrate_tries; + u8 max_rates; + u8 max_rate_tries; }; /** @@ -927,9 +974,9 @@ static inline struct ieee80211_rate * ieee80211_get_tx_rate(const struct ieee80211_hw *hw, const struct ieee80211_tx_info *c) { - if (WARN_ON(c->tx_rate_idx < 0)) + if (WARN_ON(c->control.rates[0].idx < 0)) return NULL; - return &hw->wiphy->bands[c->band]->bitrates[c->tx_rate_idx]; + return &hw->wiphy->bands[c->band]->bitrates[c->control.rates[0].idx]; } static inline struct ieee80211_rate * @@ -945,9 +992,9 @@ static inline struct ieee80211_rate * ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw, const struct ieee80211_tx_info *c, int idx) { - if (c->control.retries[idx].rate_idx < 0) + if (c->control.rates[idx + 1].idx < 0) return NULL; - return &hw->wiphy->bands[c->band]->bitrates[c->control.retries[idx].rate_idx]; + return &hw->wiphy->bands[c->band]->bitrates[c->control.rates[idx + 1].idx]; } /** @@ -1840,17 +1887,30 @@ struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_hw *hw, /* Rate control API */ + /** - * struct rate_selection - rate information for/from rate control algorithms - * - * @rate_idx: selected transmission rate index - * @nonerp_idx: Non-ERP rate to use instead if ERP cannot be used - * @probe_idx: rate for probing (or -1) - * @max_rate_idx: maximum rate index that can be used, this is - * input to the algorithm and will be enforced - */ -struct rate_selection { - s8 rate_idx, nonerp_idx, probe_idx, max_rate_idx; + * struct ieee80211_tx_rate_control - rate control information for/from RC algo + * + * @hw: The hardware the algorithm is invoked for. + * @sband: The band this frame is being transmitted on. + * @bss_conf: the current BSS configuration + * @reported_rate: The rate control algorithm can fill this in to indicate + * which rate should be reported to userspace as the current rate and + * used for rate calculations in the mesh network. + * @rts: whether RTS will be used for this frame because it is longer than the + * RTS threshold + * @short_preamble: whether mac80211 will request short-preamble transmission + * if the selected rate supports it + * @max_rate_idx: user-requested maximum rate (not MCS for now) + */ +struct ieee80211_tx_rate_control { + struct ieee80211_hw *hw; + struct ieee80211_supported_band *sband; + struct ieee80211_bss_conf *bss_conf; + struct sk_buff *skb; + struct ieee80211_tx_rate reported_rate; + bool rts, short_preamble; + u8 max_rate_idx; }; struct rate_control_ops { @@ -1869,10 +1929,8 @@ struct rate_control_ops { void (*tx_status)(void *priv, struct ieee80211_supported_band *sband, struct ieee80211_sta *sta, void *priv_sta, struct sk_buff *skb); - void (*get_rate)(void *priv, struct ieee80211_supported_band *sband, - struct ieee80211_sta *sta, void *priv_sta, - struct sk_buff *skb, - struct rate_selection *sel); + void (*get_rate)(void *priv, struct ieee80211_sta *sta, void *priv_sta, + struct ieee80211_tx_rate_control *txrc); void (*add_sta_debugfs)(void *priv, void *priv_sta, struct dentry *dir); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 6f8756d26a9..fe4efdd4253 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -142,7 +142,6 @@ typedef unsigned __bitwise__ ieee80211_tx_result; #define IEEE80211_TX_FRAGMENTED BIT(0) #define IEEE80211_TX_UNICAST BIT(1) #define IEEE80211_TX_PS_BUFFERED BIT(2) -#define IEEE80211_TX_PROBE_LAST_FRAG BIT(3) struct ieee80211_tx_data { struct sk_buff *skb; @@ -153,11 +152,6 @@ struct ieee80211_tx_data { struct ieee80211_key *key; struct ieee80211_channel *channel; - s8 rate_idx; - /* use this rate (if set) for last fragment; rate can - * be set to lower rate for the first fragments, e.g., - * when using CTS protection with IEEE 802.11g. */ - s8 last_frag_rate_idx; /* Extra fragments (in addition to the first fragment * in skb) */ @@ -203,9 +197,7 @@ struct ieee80211_rx_data { struct ieee80211_tx_stored_packet { struct sk_buff *skb; struct sk_buff **extra_frag; - s8 last_frag_rate_idx; int num_extra_frag; - bool last_frag_rate_ctrl_probe; }; struct beacon_data { diff --git a/net/mac80211/main.c b/net/mac80211/main.c index ffff54944f9..88c1975a97a 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -41,6 +41,8 @@ */ struct ieee80211_tx_status_rtap_hdr { struct ieee80211_radiotap_header hdr; + u8 rate; + u8 padding_for_rate; __le16 tx_flags; u8 data_retries; } __attribute__ ((packed)); @@ -465,13 +467,28 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) struct ieee80211_sub_if_data *sdata; struct net_device *prev_dev = NULL; struct sta_info *sta; + int retry_count = -1, i; + + for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { + /* the HW cannot have attempted that rate */ + if (i >= hw->max_rates) { + info->status.rates[i].idx = -1; + info->status.rates[i].count = 0; + } + + retry_count += info->status.rates[i].count; + } + if (retry_count < 0) + retry_count = 0; rcu_read_lock(); + sband = local->hw.wiphy->bands[info->band]; + sta = sta_info_get(local, hdr->addr1); if (sta) { - if (info->status.excessive_retries && + if (!(info->flags & IEEE80211_TX_STAT_ACK) && test_sta_flags(sta, WLAN_STA_PS)) { /* * The STA is in power save mode, so assume @@ -502,12 +519,11 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) rcu_read_unlock(); return; } else { - if (info->status.excessive_retries) + if (!(info->flags & IEEE80211_TX_STAT_ACK)) sta->tx_retry_failed++; - sta->tx_retry_count += info->status.retry_count; + sta->tx_retry_count += retry_count; } - sband = local->hw.wiphy->bands[info->band]; rate_control_tx_status(local, sband, sta, skb); } @@ -528,9 +544,9 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) local->dot11TransmittedFrameCount++; if (is_multicast_ether_addr(hdr->addr1)) local->dot11MulticastTransmittedFrameCount++; - if (info->status.retry_count > 0) + if (retry_count > 0) local->dot11RetryCount++; - if (info->status.retry_count > 1) + if (retry_count > 1) local->dot11MultipleRetryCount++; } @@ -574,19 +590,30 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr)); rthdr->hdr.it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) | - (1 << IEEE80211_RADIOTAP_DATA_RETRIES)); + (1 << IEEE80211_RADIOTAP_DATA_RETRIES) | + (1 << IEEE80211_RADIOTAP_RATE)); if (!(info->flags & IEEE80211_TX_STAT_ACK) && !is_multicast_ether_addr(hdr->addr1)) rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL); - if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) && - (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) + /* + * XXX: Once radiotap gets the bitmap reset thing the vendor + * extensions proposal contains, we can actually report + * the whole set of tries we did. + */ + if ((info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) || + (info->status.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS); - else if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) + else if (info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS); + if (info->status.rates[0].idx >= 0 && + !(info->status.rates[0].flags & IEEE80211_TX_RC_MCS)) + rthdr->rate = sband->bitrates[ + info->status.rates[0].idx].bitrate / 5; - rthdr->data_retries = info->status.retry_count; + /* for now report the total retry_count */ + rthdr->data_retries = retry_count; /* XXX: is this sufficient for BPF? */ skb_set_mac_header(skb, 0); @@ -671,8 +698,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, BUG_ON(!ops->configure_filter); local->ops = ops; - local->hw.queues = 1; /* default */ - + /* set up some defaults */ + local->hw.queues = 1; + local->hw.max_rates = 1; local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD; local->hw.conf.long_frame_max_tx_count = 4; diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 501c7831adb..e8d573d592e 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -218,12 +218,16 @@ static u32 airtime_link_metric_get(struct ieee80211_local *local, if (sta->fail_avg >= 100) return MAX_METRIC; + + if (sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS) + return MAX_METRIC; + err = (sta->fail_avg << ARITH_SHIFT) / 100; /* bitrate is in units of 100 Kbps, while we need rate in units of * 1Mbps. This will be corrected on tx_time computation. */ - rate = sband->bitrates[sta->last_txrate_idx].bitrate; + rate = sband->bitrates[sta->last_tx_rate.idx].bitrate; tx_time = (device_constant + 10 * test_frame_len / rate); estimated_retx = ((1 << (2 * ARITH_SHIFT)) / (s_unit - err)); result = (tx_time * estimated_retx) >> (2 * ARITH_SHIFT) ; diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index 5d786720d93..3fa7ab28506 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -199,48 +199,44 @@ static void rate_control_release(struct kref *kref) } void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, - struct ieee80211_supported_band *sband, - struct sta_info *sta, struct sk_buff *skb, - struct rate_selection *sel) + struct sta_info *sta, + struct ieee80211_tx_rate_control *txrc) { struct rate_control_ref *ref = sdata->local->rate_ctrl; void *priv_sta = NULL; struct ieee80211_sta *ista = NULL; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb); int i; - sel->rate_idx = -1; - sel->nonerp_idx = -1; - sel->probe_idx = -1; - sel->max_rate_idx = sdata->max_ratectrl_rateidx; - if (sta) { ista = &sta->sta; priv_sta = sta->rate_ctrl_priv; } + for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { + info->control.rates[i].idx = -1; + info->control.rates[i].flags = 0; + info->control.rates[i].count = 1; + } + if (sta && sdata->force_unicast_rateidx > -1) - sel->rate_idx = sdata->force_unicast_rateidx; + info->control.rates[0].idx = sdata->force_unicast_rateidx; else - ref->ops->get_rate(ref->priv, sband, ista, priv_sta, skb, sel); - - if (sdata->max_ratectrl_rateidx > -1 && - sel->rate_idx > sdata->max_ratectrl_rateidx) - sel->rate_idx = sdata->max_ratectrl_rateidx; - - BUG_ON(sel->rate_idx < 0); - - /* Select a non-ERP backup rate. */ - if (sel->nonerp_idx < 0) { - for (i = 0; i < sband->n_bitrates; i++) { - struct ieee80211_rate *rate = &sband->bitrates[i]; - if (sband->bitrates[sel->rate_idx].bitrate < rate->bitrate) - break; - - if (rate_supported(ista, sband->band, i) && - !(rate->flags & IEEE80211_RATE_ERP_G)) - sel->nonerp_idx = i; - } + ref->ops->get_rate(ref->priv, ista, priv_sta, txrc); + + /* + * try to enforce the maximum rate the user wanted + */ + if (sdata->max_ratectrl_rateidx > -1) + for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { + if (info->control.rates[i].flags & IEEE80211_TX_RC_MCS) + continue; + info->control.rates[i].idx = + min_t(s8, info->control.rates[i].idx, + sdata->max_ratectrl_rateidx); } + + BUG_ON(info->control.rates[0].idx < 0); } struct rate_control_ref *rate_control_get(struct rate_control_ref *ref) diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index d0092f847f8..7c25edf9ac5 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h @@ -31,9 +31,8 @@ struct rate_control_ref { struct rate_control_ref *rate_control_alloc(const char *name, struct ieee80211_local *local); void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, - struct ieee80211_supported_band *sband, - struct sta_info *sta, struct sk_buff *skb, - struct rate_selection *sel); + struct sta_info *sta, + struct ieee80211_tx_rate_control *txrc); struct rate_control_ref *rate_control_get(struct rate_control_ref *ref); void rate_control_put(struct rate_control_ref *ref); diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index f6d69dab07a..759ddd8bf0f 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c @@ -169,30 +169,20 @@ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband, { struct minstrel_sta_info *mi = priv_sta; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_tx_altrate *ar = info->status.retries; - struct minstrel_priv *mp = priv; - int i, ndx, tries; - int success = 0; + struct ieee80211_tx_rate *ar = info->status.rates; + int i, ndx; + int success; - if (!info->status.excessive_retries) - success = 1; + success = !!(info->flags & IEEE80211_TX_STAT_ACK); - if (!mp->has_mrr || (ar[0].rate_idx < 0)) { - ndx = rix_to_ndx(mi, info->tx_rate_idx); - tries = info->status.retry_count + 1; - mi->r[ndx].success += success; - mi->r[ndx].attempts += tries; - return; - } - - for (i = 0; i < 4; i++) { - if (ar[i].rate_idx < 0) + for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { + if (ar[i].idx < 0) break; - ndx = rix_to_ndx(mi, ar[i].rate_idx); - mi->r[ndx].attempts += ar[i].limit + 1; + ndx = rix_to_ndx(mi, ar[i].idx); + mi->r[ndx].attempts += ar[i].count; - if ((i != 3) && (ar[i + 1].rate_idx < 0)) + if ((i != IEEE80211_TX_MAX_RATES - 1) && (ar[i + 1].idx < 0)) mi->r[ndx].success += success; } @@ -210,9 +200,9 @@ minstrel_get_retry_count(struct minstrel_rate *mr, { unsigned int retry = mr->adjusted_retry_count; - if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) + if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) retry = max(2U, min(mr->retry_count_rtscts, retry)); - else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) + else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) retry = max(2U, min(mr->retry_count_cts, retry)); return retry; } @@ -234,14 +224,15 @@ minstrel_get_next_sample(struct minstrel_sta_info *mi) } void -minstrel_get_rate(void *priv, struct ieee80211_supported_band *sband, - struct ieee80211_sta *sta, void *priv_sta, - struct sk_buff *skb, struct rate_selection *sel) +minstrel_get_rate(void *priv, struct ieee80211_sta *sta, + void *priv_sta, struct ieee80211_tx_rate_control *txrc) { + struct sk_buff *skb = txrc->skb; + struct ieee80211_supported_band *sband = txrc->sband; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct minstrel_sta_info *mi = priv_sta; struct minstrel_priv *mp = priv; - struct ieee80211_tx_altrate *ar = info->control.retries; + struct ieee80211_tx_rate *ar = info->control.rates; unsigned int ndx, sample_ndx = 0; bool mrr; bool sample_slower = false; @@ -251,16 +242,12 @@ minstrel_get_rate(void *priv, struct ieee80211_supported_band *sband, int sample_rate; if (!sta || !mi || use_low_rate(skb)) { - sel->rate_idx = rate_lowest_index(sband, sta); + ar[0].idx = rate_lowest_index(sband, sta); + ar[0].count = mp->max_retry; return; } - mrr = mp->has_mrr; - - /* mac80211 does not allow mrr for RTS/CTS */ - if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) || - (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) - mrr = false; + mrr = mp->has_mrr && !txrc->rts && !txrc->bss_conf->use_cts_prot; if (time_after(jiffies, mi->stats_update + (mp->update_interval * HZ) / 1000)) @@ -315,13 +302,12 @@ minstrel_get_rate(void *priv, struct ieee80211_supported_band *sband, mi->sample_deferred++; } } - sel->rate_idx = mi->r[ndx].rix; - info->control.retry_limit = minstrel_get_retry_count(&mi->r[ndx], info); + ar[0].idx = mi->r[ndx].rix; + ar[0].count = minstrel_get_retry_count(&mi->r[ndx], info); if (!mrr) { - ar[0].rate_idx = mi->lowest_rix; - ar[0].limit = mp->max_retry; - ar[1].rate_idx = -1; + ar[1].idx = mi->lowest_rix; + ar[1].count = mp->max_retry; return; } @@ -336,9 +322,9 @@ minstrel_get_rate(void *priv, struct ieee80211_supported_band *sband, } mrr_ndx[1] = mi->max_prob_rate; mrr_ndx[2] = 0; - for (i = 0; i < 3; i++) { - ar[i].rate_idx = mi->r[mrr_ndx[i]].rix; - ar[i].limit = mi->r[mrr_ndx[i]].adjusted_retry_count; + for (i = 1; i < 4; i++) { + ar[i].idx = mi->r[mrr_ndx[i - 1]].rix; + ar[i].count = mi->r[mrr_ndx[i - 1]].adjusted_retry_count; } } @@ -532,13 +518,13 @@ minstrel_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) /* maximum time that the hw is allowed to stay in one MRR segment */ mp->segment_size = 6000; - if (hw->max_altrate_tries > 0) - mp->max_retry = hw->max_altrate_tries; + if (hw->max_rate_tries > 0) + mp->max_retry = hw->max_rate_tries; else /* safe default, does not necessarily have to match hw properties */ mp->max_retry = 7; - if (hw->max_altrates >= 3) + if (hw->max_rates >= 4) mp->has_mrr = true; mp->hw = hw; diff --git a/net/mac80211/rc80211_pid.h b/net/mac80211/rc80211_pid.h index ce099ea1d5d..1a873f00691 100644 --- a/net/mac80211/rc80211_pid.h +++ b/net/mac80211/rc80211_pid.h @@ -61,6 +61,7 @@ enum rc_pid_event_type { union rc_pid_event_data { /* RC_PID_EVENT_TX_STATUS */ struct { + u32 flags; struct ieee80211_tx_info tx_status; }; /* RC_PID_EVENT_TYPE_RATE_CHANGE */ diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c index 86eb374e3b8..92caecfcee7 100644 --- a/net/mac80211/rc80211_pid_algo.c +++ b/net/mac80211/rc80211_pid_algo.c @@ -241,7 +241,7 @@ static void rate_control_pid_tx_status(void *priv, struct ieee80211_supported_ba /* Ignore all frames that were sent with a different rate than the rate * we currently advise mac80211 to use. */ - if (info->tx_rate_idx != spinfo->txrate_idx) + if (info->status.rates[0].idx != spinfo->txrate_idx) return; spinfo->tx_num_xmit++; @@ -253,10 +253,10 @@ static void rate_control_pid_tx_status(void *priv, struct ieee80211_supported_ba /* We count frames that totally failed to be transmitted as two bad * frames, those that made it out but had some retries as one good and * one bad frame. */ - if (info->status.excessive_retries) { + if (!(info->flags & IEEE80211_TX_STAT_ACK)) { spinfo->tx_num_failed += 2; spinfo->tx_num_xmit++; - } else if (info->status.retry_count) { + } else if (info->status.rates[0].count) { spinfo->tx_num_failed++; spinfo->tx_num_xmit++; } @@ -270,23 +270,32 @@ static void rate_control_pid_tx_status(void *priv, struct ieee80211_supported_ba } static void -rate_control_pid_get_rate(void *priv, struct ieee80211_supported_band *sband, - struct ieee80211_sta *sta, void *priv_sta, - struct sk_buff *skb, - struct rate_selection *sel) +rate_control_pid_get_rate(void *priv, struct ieee80211_sta *sta, + void *priv_sta, + struct ieee80211_tx_rate_control *txrc) { + struct sk_buff *skb = txrc->skb; + struct ieee80211_supported_band *sband = txrc->sband; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct rc_pid_sta_info *spinfo = priv_sta; int rateidx; u16 fc; + if (txrc->rts) + info->control.rates[0].count = + txrc->hw->conf.long_frame_max_tx_count; + else + info->control.rates[0].count = + txrc->hw->conf.short_frame_max_tx_count; + /* Send management frames and broadcast/multicast data using lowest * rate. */ fc = le16_to_cpu(hdr->frame_control); if (!sta || !spinfo || (fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || is_multicast_ether_addr(hdr->addr1)) { - sel->rate_idx = rate_lowest_index(sband, sta); + info->control.rates[0].idx = rate_lowest_index(sband, sta); return; } @@ -295,7 +304,7 @@ rate_control_pid_get_rate(void *priv, struct ieee80211_supported_band *sband, if (rateidx >= sband->n_bitrates) rateidx = sband->n_bitrates - 1; - sel->rate_idx = rateidx; + info->control.rates[0].idx = rateidx; #ifdef CONFIG_MAC80211_DEBUGFS rate_control_pid_event_tx_rate(&spinfo->events, diff --git a/net/mac80211/rc80211_pid_debugfs.c b/net/mac80211/rc80211_pid_debugfs.c index 8121d3bc683..a08a9b53034 100644 --- a/net/mac80211/rc80211_pid_debugfs.c +++ b/net/mac80211/rc80211_pid_debugfs.c @@ -43,6 +43,7 @@ void rate_control_pid_event_tx_status(struct rc_pid_event_buffer *buf, { union rc_pid_event_data evd; + evd.flags = stat->flags; memcpy(&evd.tx_status, stat, sizeof(struct ieee80211_tx_info)); rate_control_pid_event(buf, RC_PID_EVENT_TYPE_TX_STATUS, &evd); } @@ -167,8 +168,8 @@ static ssize_t rate_control_pid_events_read(struct file *file, char __user *buf, switch (ev->type) { case RC_PID_EVENT_TYPE_TX_STATUS: p += snprintf(pb + p, length - p, "tx_status %u %u", - ev->data.tx_status.status.excessive_retries, - ev->data.tx_status.status.retry_count); + !(ev->data.flags & IEEE80211_TX_STAT_ACK), + ev->data.tx_status.status.rates[0].idx); break; case RC_PID_EVENT_TYPE_RATE_CHANGE: p += snprintf(pb + p, length - p, "rate_change %d %d", diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 168a39a298b..4ac372aa75c 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -196,7 +196,7 @@ struct sta_ampdu_mlme { * @tx_packets: number of RX/TX MSDUs * @tx_bytes: TBD * @tx_fragments: number of transmitted MPDUs - * @last_txrate_idx: Index of the last used transmit rate + * @last_txrate: description of the last used transmit rate * @tid_seq: TBD * @ampdu_mlme: TBD * @timer_to_tid: identity mapping to ID timers @@ -267,7 +267,7 @@ struct sta_info { unsigned long tx_packets; unsigned long tx_bytes; unsigned long tx_fragments; - unsigned int last_txrate_idx; + struct ieee80211_tx_rate last_tx_rate; u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1]; /* diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 6f3e4be9763..21951bac1ef 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -46,13 +46,20 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr, struct ieee80211_local *local = tx->local; struct ieee80211_supported_band *sband; struct ieee80211_hdr *hdr; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); + + /* assume HW handles this */ + if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS) + return 0; + + /* uh huh? */ + if (WARN_ON_ONCE(info->control.rates[0].idx < 0)) + return 0; sband = local->hw.wiphy->bands[tx->channel->band]; - txrate = &sband->bitrates[tx->rate_idx]; + txrate = &sband->bitrates[info->control.rates[0].idx]; - erp = 0; - if (tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) - erp = txrate->flags & IEEE80211_RATE_ERP_G; + erp = txrate->flags & IEEE80211_RATE_ERP_G; /* * data and mgmt (except PS Poll): @@ -437,140 +444,154 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) static ieee80211_tx_result debug_noinline ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) { - struct rate_selection rsel; - struct ieee80211_supported_band *sband; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); + struct ieee80211_hdr *hdr = (void *)tx->skb->data; + struct ieee80211_supported_band *sband; + struct ieee80211_rate *rate; + int i, len; + bool inval = false, rts = false, short_preamble = false; + struct ieee80211_tx_rate_control txrc; - sband = tx->local->hw.wiphy->bands[tx->channel->band]; + memset(&txrc, 0, sizeof(txrc)); - if (likely(tx->rate_idx < 0)) { - rate_control_get_rate(tx->sdata, sband, tx->sta, - tx->skb, &rsel); - if (tx->sta) - tx->sta->last_txrate_idx = rsel.rate_idx; - tx->rate_idx = rsel.rate_idx; - if (unlikely(rsel.probe_idx >= 0)) { - info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; - tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG; - info->control.retries[0].rate_idx = tx->rate_idx; - info->control.retries[0].limit = tx->local->hw.max_altrate_tries; - tx->rate_idx = rsel.probe_idx; - } else if (info->control.retries[0].limit == 0) - info->control.retries[0].rate_idx = -1; - - if (unlikely(tx->rate_idx < 0)) - return TX_DROP; - } else - info->control.retries[0].rate_idx = -1; + sband = tx->local->hw.wiphy->bands[tx->channel->band]; - if (tx->sdata->vif.bss_conf.use_cts_prot && - (tx->flags & IEEE80211_TX_FRAGMENTED) && (rsel.nonerp_idx >= 0)) { - tx->last_frag_rate_idx = tx->rate_idx; - if (rsel.probe_idx >= 0) - tx->flags &= ~IEEE80211_TX_PROBE_LAST_FRAG; - else - tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG; - tx->rate_idx = rsel.nonerp_idx; - info->tx_rate_idx = rsel.nonerp_idx; - info->flags &= ~IEEE80211_TX_CTL_RATE_CTRL_PROBE; - } else { - tx->last_frag_rate_idx = tx->rate_idx; - info->tx_rate_idx = tx->rate_idx; + len = min_t(int, tx->skb->len + FCS_LEN, + tx->local->fragmentation_threshold); + + /* set up the tx rate control struct we give the RC algo */ + txrc.hw = local_to_hw(tx->local); + txrc.sband = sband; + txrc.bss_conf = &tx->sdata->vif.bss_conf; + txrc.skb = tx->skb; + txrc.reported_rate.idx = -1; + txrc.max_rate_idx = tx->sdata->max_ratectrl_rateidx; + + /* set up RTS protection if desired */ + if (tx->local->rts_threshold < IEEE80211_MAX_RTS_THRESHOLD && + len > tx->local->rts_threshold) { + txrc.rts = rts = true; } - info->tx_rate_idx = tx->rate_idx; - return TX_CONTINUE; -} + /* + * Use short preamble if the BSS can handle it, but not for + * management frames unless we know the receiver can handle + * that -- the management frame might be to a station that + * just wants a probe response. + */ + if (tx->sdata->vif.bss_conf.use_short_preamble && + (ieee80211_is_data(hdr->frame_control) || + (tx->sta && test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE)))) + txrc.short_preamble = short_preamble = true; -static ieee80211_tx_result debug_noinline -ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); - struct ieee80211_supported_band *sband; - sband = tx->local->hw.wiphy->bands[tx->channel->band]; + rate_control_get_rate(tx->sdata, tx->sta, &txrc); + + if (unlikely(info->control.rates[0].idx < 0)) + return TX_DROP; + + if (txrc.reported_rate.idx < 0) + txrc.reported_rate = info->control.rates[0]; if (tx->sta) - info->control.sta = &tx->sta->sta; + tx->sta->last_tx_rate = txrc.reported_rate; - if (!info->control.retry_limit) { - if (!is_multicast_ether_addr(hdr->addr1)) { - int len = min_t(int, tx->skb->len + FCS_LEN, - tx->local->fragmentation_threshold); - if (len > tx->local->rts_threshold - && tx->local->rts_threshold < - IEEE80211_MAX_RTS_THRESHOLD) { - info->flags |= IEEE80211_TX_CTL_USE_RTS_CTS; - info->flags |= - IEEE80211_TX_CTL_LONG_RETRY_LIMIT; - info->control.retry_limit = - tx->local->hw.conf.long_frame_max_tx_count - 1; - } else { - info->control.retry_limit = - tx->local->hw.conf.short_frame_max_tx_count - 1; - } - } else { - info->control.retry_limit = 1; - } - } + if (unlikely(!info->control.rates[0].count)) + info->control.rates[0].count = 1; - if (tx->flags & IEEE80211_TX_FRAGMENTED) { - /* Do not use multiple retry rates when sending fragmented - * frames. - * TODO: The last fragment could still use multiple retry - * rates. */ - info->control.retries[0].rate_idx = -1; + if (is_multicast_ether_addr(hdr->addr1)) { + /* + * XXX: verify the rate is in the basic rateset + */ + return TX_CONTINUE; } - /* Use CTS protection for unicast frames sent using extended rates if - * there are associated non-ERP stations and RTS/CTS is not configured - * for the frame. */ - if ((tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) && - (sband->bitrates[tx->rate_idx].flags & IEEE80211_RATE_ERP_G) && - (tx->flags & IEEE80211_TX_UNICAST) && - tx->sdata->vif.bss_conf.use_cts_prot && - !(info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)) - info->flags |= IEEE80211_TX_CTL_USE_CTS_PROTECT; - - /* Transmit data frames using short preambles if the driver supports - * short preambles at the selected rate and short preambles are - * available on the network at the current point in time. */ - if (ieee80211_is_data(hdr->frame_control) && - (sband->bitrates[tx->rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE) && - tx->sdata->vif.bss_conf.use_short_preamble && - (!tx->sta || test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE))) { - info->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE; + /* + * set up the RTS/CTS rate as the fastest basic rate + * that is not faster than the data rate + * + * XXX: Should this check all retry rates? + */ + if (!(info->control.rates[0].flags & IEEE80211_TX_RC_MCS)) { + s8 baserate = 0; + + rate = &sband->bitrates[info->control.rates[0].idx]; + + for (i = 0; i < sband->n_bitrates; i++) { + /* must be a basic rate */ + if (!(tx->sdata->vif.bss_conf.basic_rates & BIT(i))) + continue; + /* must not be faster than the data rate */ + if (sband->bitrates[i].bitrate > rate->bitrate) + continue; + /* maximum */ + if (sband->bitrates[baserate].bitrate < + sband->bitrates[i].bitrate) + baserate = i; + } + + info->control.rts_cts_rate_idx = baserate; } - if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) || - (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) { - struct ieee80211_rate *rate; - s8 baserate = -1; - int idx; + for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { + /* + * make sure there's no valid rate following + * an invalid one, just in case drivers don't + * take the API seriously to stop at -1. + */ + if (inval) { + info->control.rates[i].idx = -1; + continue; + } + if (info->control.rates[i].idx < 0) { + inval = true; + continue; + } - /* Do not use multiple retry rates when using RTS/CTS */ - info->control.retries[0].rate_idx = -1; + /* + * For now assume MCS is already set up correctly, this + * needs to be fixed. + */ + if (info->control.rates[i].flags & IEEE80211_TX_RC_MCS) { + WARN_ON(info->control.rates[i].idx > 76); + continue; + } - /* Use min(data rate, max base rate) as CTS/RTS rate */ - rate = &sband->bitrates[tx->rate_idx]; + /* set up RTS protection if desired */ + if (rts) + info->control.rates[i].flags |= + IEEE80211_TX_RC_USE_RTS_CTS; - for (idx = 0; idx < sband->n_bitrates; idx++) { - if (sband->bitrates[idx].bitrate > rate->bitrate) - continue; - if (tx->sdata->vif.bss_conf.basic_rates & BIT(idx) && - (baserate < 0 || - (sband->bitrates[baserate].bitrate - < sband->bitrates[idx].bitrate))) - baserate = idx; + /* RC is busted */ + if (WARN_ON(info->control.rates[i].idx >= + sband->n_bitrates)) { + info->control.rates[i].idx = -1; + continue; } - if (baserate >= 0) - info->control.rts_cts_rate_idx = baserate; - else - info->control.rts_cts_rate_idx = 0; + rate = &sband->bitrates[info->control.rates[i].idx]; + + /* set up short preamble */ + if (short_preamble && + rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) + info->control.rates[i].flags |= + IEEE80211_TX_RC_USE_SHORT_PREAMBLE; + + /* set up G protection */ + if (!rts && tx->sdata->vif.bss_conf.use_cts_prot && + rate->flags & IEEE80211_RATE_ERP_G) + info->control.rates[i].flags |= + IEEE80211_TX_RC_USE_CTS_PROTECT; } + return TX_CONTINUE; +} + +static ieee80211_tx_result debug_noinline +ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); + if (tx->sta) info->control.sta = &tx->sta->sta; @@ -678,6 +699,7 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) left = payload_len - per_fragm; for (i = 0; i < num_fragm - 1; i++) { struct ieee80211_hdr *fhdr; + struct ieee80211_tx_info *info; size_t copylen; if (left <= 0) @@ -692,20 +714,45 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) IEEE80211_ENCRYPT_TAILROOM); if (!frag) goto fail; + /* Make sure that all fragments use the same priority so * that they end up using the same TX queue */ frag->priority = first->priority; + skb_reserve(frag, tx->local->tx_headroom + IEEE80211_ENCRYPT_HEADROOM); + + /* copy TX information */ + info = IEEE80211_SKB_CB(frag); + memcpy(info, first->cb, sizeof(frag->cb)); + + /* copy/fill in 802.11 header */ fhdr = (struct ieee80211_hdr *) skb_put(frag, hdrlen); memcpy(fhdr, first->data, hdrlen); - if (i == num_fragm - 2) - fhdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREFRAGS); fhdr->seq_ctrl = cpu_to_le16(seq | ((i + 1) & IEEE80211_SCTL_FRAG)); + + if (i == num_fragm - 2) { + /* clear MOREFRAGS bit for the last fragment */ + fhdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREFRAGS); + } else { + /* + * No multi-rate retries for fragmented frames, that + * would completely throw off the NAV at other STAs. + */ + info->control.rates[1].idx = -1; + info->control.rates[2].idx = -1; + info->control.rates[3].idx = -1; + info->control.rates[4].idx = -1; + BUILD_BUG_ON(IEEE80211_TX_MAX_RATES != 5); + info->flags &= ~IEEE80211_TX_CTL_RATE_CTRL_PROBE; + } + + /* copy data */ copylen = left > per_fragm ? per_fragm : left; memcpy(skb_put(frag, copylen), pos, copylen); - memcpy(frag->cb, first->cb, sizeof(frag->cb)); + skb_copy_queue_mapping(frag, first); + frag->do_not_encrypt = first->do_not_encrypt; pos += copylen; @@ -765,12 +812,10 @@ ieee80211_tx_h_calculate_duration(struct ieee80211_tx_data *tx) tx->extra_frag[0]->len); for (i = 0; i < tx->num_extra_frag; i++) { - if (i + 1 < tx->num_extra_frag) { + if (i + 1 < tx->num_extra_frag) next_len = tx->extra_frag[i + 1]->len; - } else { + else next_len = 0; - tx->rate_idx = tx->last_frag_rate_idx; - } hdr = (struct ieee80211_hdr *)tx->extra_frag[i]->data; hdr->duration_id = ieee80211_duration(tx, 0, next_len); @@ -823,7 +868,6 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, (struct ieee80211_radiotap_header *) skb->data; struct ieee80211_supported_band *sband; int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len); - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); sband = tx->local->hw.wiphy->bands[tx->channel->band]; @@ -837,8 +881,6 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, */ while (!ret) { - int i, target_rate; - ret = ieee80211_radiotap_iterator_next(&iterator); if (ret) @@ -852,38 +894,6 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, * get_unaligned((type *)iterator.this_arg) to dereference * iterator.this_arg for type "type" safely on all arches. */ - case IEEE80211_RADIOTAP_RATE: - /* - * radiotap rate u8 is in 500kbps units eg, 0x02=1Mbps - * ieee80211 rate int is in 100kbps units eg, 0x0a=1Mbps - */ - target_rate = (*iterator.this_arg) * 5; - for (i = 0; i < sband->n_bitrates; i++) { - struct ieee80211_rate *r; - - r = &sband->bitrates[i]; - - if (r->bitrate == target_rate) { - tx->rate_idx = i; - break; - } - } - break; - - case IEEE80211_RADIOTAP_ANTENNA: - /* - * radiotap uses 0 for 1st ant, mac80211 is 1 for - * 1st ant - */ - info->antenna_sel_tx = (*iterator.this_arg) + 1; - break; - -#if 0 - case IEEE80211_RADIOTAP_DBM_TX_POWER: - control->power_level = *iterator.this_arg; - break; -#endif - case IEEE80211_RADIOTAP_FLAGS: if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FCS) { /* @@ -949,8 +959,6 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx, tx->local = local; tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev); tx->channel = local->hw.conf.channel; - tx->rate_idx = -1; - tx->last_frag_rate_idx = -1; /* * Set this flag (used below to indicate "automatic fragmentation"), * it will be cleared/left by radiotap as desired. @@ -1051,23 +1059,11 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, if (!tx->extra_frag[i]) continue; info = IEEE80211_SKB_CB(tx->extra_frag[i]); - info->flags &= ~(IEEE80211_TX_CTL_USE_RTS_CTS | - IEEE80211_TX_CTL_USE_CTS_PROTECT | - IEEE80211_TX_CTL_CLEAR_PS_FILT | + info->flags &= ~(IEEE80211_TX_CTL_CLEAR_PS_FILT | IEEE80211_TX_CTL_FIRST_FRAGMENT); if (netif_subqueue_stopped(local->mdev, tx->extra_frag[i])) return IEEE80211_TX_FRAG_AGAIN; - if (i == tx->num_extra_frag) { - info->tx_rate_idx = tx->last_frag_rate_idx; - - if (tx->flags & IEEE80211_TX_PROBE_LAST_FRAG) - info->flags |= - IEEE80211_TX_CTL_RATE_CTRL_PROBE; - else - info->flags &= - ~IEEE80211_TX_CTL_RATE_CTRL_PROBE; - } ret = local->ops->tx(local_to_hw(local), tx->extra_frag[i]); @@ -1204,9 +1200,6 @@ retry: store->skb = skb; store->extra_frag = tx.extra_frag; store->num_extra_frag = tx.num_extra_frag; - store->last_frag_rate_idx = tx.last_frag_rate_idx; - store->last_frag_rate_ctrl_probe = - !!(tx.flags & IEEE80211_TX_PROBE_LAST_FRAG); } out: rcu_read_unlock(); @@ -1763,10 +1756,7 @@ void ieee80211_tx_pending(unsigned long data) store = &local->pending_packet[i]; tx.extra_frag = store->extra_frag; tx.num_extra_frag = store->num_extra_frag; - tx.last_frag_rate_idx = store->last_frag_rate_idx; tx.flags = 0; - if (store->last_frag_rate_ctrl_probe) - tx.flags |= IEEE80211_TX_PROBE_LAST_FRAG; ret = __ieee80211_tx(local, store->skb, &tx); if (ret) { if (ret == IEEE80211_TX_FRAG_AGAIN) @@ -1854,7 +1844,6 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, struct ieee80211_sub_if_data *sdata = NULL; struct ieee80211_if_ap *ap = NULL; struct ieee80211_if_sta *ifsta = NULL; - struct rate_selection rsel; struct beacon_data *beacon; struct ieee80211_supported_band *sband; enum ieee80211_band band = local->hw.conf.channel->band; @@ -1958,32 +1947,23 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, skb->do_not_encrypt = 1; info->band = band; - rate_control_get_rate(sdata, sband, NULL, skb, &rsel); - - if (unlikely(rsel.rate_idx < 0)) { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: ieee80211_beacon_get: " - "no rate found\n", - wiphy_name(local->hw.wiphy)); - } - dev_kfree_skb_any(skb); - skb = NULL; - goto out; - } + /* + * XXX: For now, always use the lowest rate + */ + info->control.rates[0].idx = 0; + info->control.rates[0].count = 1; + info->control.rates[1].idx = -1; + info->control.rates[2].idx = -1; + info->control.rates[3].idx = -1; + info->control.rates[4].idx = -1; + BUILD_BUG_ON(IEEE80211_TX_MAX_RATES != 5); info->control.vif = vif; - info->tx_rate_idx = rsel.rate_idx; info->flags |= IEEE80211_TX_CTL_NO_ACK; info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ; - if (sdata->vif.bss_conf.use_short_preamble && - sband->bitrates[rsel.rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE) - info->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE; - - info->control.retry_limit = 1; - -out: + out: rcu_read_unlock(); return skb; } diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index f7e442f80a1..31d2e74a1bc 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c @@ -636,8 +636,8 @@ static int ieee80211_ioctl_giwrate(struct net_device *dev, sta = sta_info_get(local, sdata->u.sta.bssid); - if (sta && sta->last_txrate_idx < sband->n_bitrates) - rate->value = sband->bitrates[sta->last_txrate_idx].bitrate; + if (sta && !(sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS)) + rate->value = sband->bitrates[sta->last_tx_rate.idx].bitrate; else rate->value = 0; -- cgit v1.2.3-70-g09d2 From c12abae333ac550acacf9d324ed54b7d17ead0c0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 14 Oct 2008 16:56:51 +0200 Subject: p54: implement MRR This implements multi-rate retry in p54. With lots of help and testing from Christian and the limiting idea from nbd. Signed-off-by: Johannes Berg Cc: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 130 +++++++++++++++++++++++++++++------ 1 file changed, 108 insertions(+), 22 deletions(-) (limited to 'drivers/net/wireless/p54/p54common.c') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 65be5eca234..23709014024 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -1,9 +1,9 @@ - /* * Common code for mac80211 Prism54 drivers * * Copyright (c) 2006, Michael Wu * Copyright (c) 2007, Christian Lamparter + * Copyright 2008, Johannes Berg * * Based on the islsm (softmac prism54) driver, which is: * Copyright 2004-2006 Jean-Baptiste Note , et al. @@ -544,6 +544,7 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) u32 freed = 0; u32 last_addr = priv->rx_start; unsigned long flags; + int count, idx; spin_lock_irqsave(&priv->tx_queue.lock, flags); while (entry != (struct sk_buff *)&priv->tx_queue) { @@ -568,18 +569,39 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) __skb_unlink(entry, &priv->tx_queue); spin_unlock_irqrestore(&priv->tx_queue.lock, flags); - ieee80211_tx_info_clear_status(info); + /* + * Clear manually, ieee80211_tx_info_clear_status would + * clear the counts too and we need them. + */ + memset(&info->status.ampdu_ack_len, 0, + sizeof(struct ieee80211_tx_info) - + offsetof(struct ieee80211_tx_info, status.ampdu_ack_len)); + BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, + status.ampdu_ack_len) != 23); + entry_hdr = (struct p54_control_hdr *) entry->data; entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data; if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0) pad = entry_data->align[0]; - priv->tx_stats[entry_data->hw_queue].len--; - if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { - if (!(payload->status & 0x01)) - info->flags |= IEEE80211_TX_STAT_ACK; + /* walk through the rates array and adjust the counts */ + count = payload->retries; + for (idx = 0; idx < 4; idx++) { + if (count >= info->status.rates[idx].count) { + count -= info->status.rates[idx].count; + } else if (count > 0) { + info->status.rates[idx].count = count; + count = 0; + } else { + info->status.rates[idx].idx = -1; + info->status.rates[idx].count = 0; + } } - info->status.rates[0].count = payload->retries; + + priv->tx_stats[entry_data->hw_queue].len--; + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && + !(payload->status & 0x01)) + info->flags |= IEEE80211_TX_STAT_ACK; info->status.ack_signal = p54_rssi_to_dbm(dev, le16_to_cpu(payload->ack_rssi)); skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data)); @@ -802,9 +824,12 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) struct p54_control_hdr *hdr; struct p54_tx_control_allocdata *txhdr; size_t padding, len; + int i, j, ridx; u8 rate; u8 cts_rate = 0x20; u8 rc_flags; + u8 calculated_tries[4]; + u8 nrates = 0, nremaining = 8; current_queue = &priv->tx_stats[skb_get_queue_mapping(skb) + 4]; if (unlikely(current_queue->len > current_queue->limit)) @@ -827,23 +852,74 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) hdr->magic1 = cpu_to_le16(0x0010); hdr->len = cpu_to_le16(len); hdr->type = (info->flags & IEEE80211_TX_CTL_NO_ACK) ? 0 : cpu_to_le16(1); - hdr->retry1 = hdr->retry2 = info->control.rates[0].count; - - /* TODO: add support for alternate retry TX rates */ - rate = ieee80211_get_tx_rate(dev, info)->hw_value; - rc_flags = info->control.rates[0].flags; - if (rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) { - rate |= 0x10; - cts_rate |= 0x10; + hdr->retry1 = info->control.rates[0].count; + + /* + * we register the rates in perfect order, and + * RTS/CTS won't happen on 5 GHz + */ + cts_rate = info->control.rts_cts_rate_idx; + + memset(&txhdr->rateset, 0, sizeof(txhdr->rateset)); + + /* see how many rates got used */ + for (i = 0; i < 4; i++) { + if (info->control.rates[i].idx < 0) + break; + nrates++; + } + + /* limit tries to 8/nrates per rate */ + for (i = 0; i < nrates; i++) { + /* + * The magic expression here is equivalent to 8/nrates for + * all values that matter, but avoids division and jumps. + * Note that nrates can only take the values 1 through 4. + */ + calculated_tries[i] = min_t(int, ((15 >> nrates) | 1) + 1, + info->control.rates[i].count); + nremaining -= calculated_tries[i]; } - if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) { - rate |= 0x40; - cts_rate |= ieee80211_get_rts_cts_rate(dev, info)->hw_value; - } else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { - rate |= 0x20; - cts_rate |= ieee80211_get_rts_cts_rate(dev, info)->hw_value; + + /* if there are tries left, distribute from back to front */ + for (i = nrates - 1; nremaining > 0 && i >= 0; i--) { + int tmp = info->control.rates[i].count - calculated_tries[i]; + + if (tmp <= 0) + continue; + /* RC requested more tries at this rate */ + + tmp = min_t(int, tmp, nremaining); + calculated_tries[i] += tmp; + nremaining -= tmp; } - memset(txhdr->rateset, rate, 8); + + ridx = 0; + for (i = 0; i < nrates && ridx < 8; i++) { + /* we register the rates in perfect order */ + rate = info->control.rates[i].idx; + if (info->band == IEEE80211_BAND_5GHZ) + rate += 4; + + /* store the count we actually calculated for TX status */ + info->control.rates[i].count = calculated_tries[i]; + + rc_flags = info->control.rates[i].flags; + if (rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) { + rate |= 0x10; + cts_rate |= 0x10; + } + if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) + rate |= 0x40; + else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) + rate |= 0x20; + for (j = 0; j < calculated_tries[i] && ridx < 8; j++) { + txhdr->rateset[ridx] = rate; + ridx++; + } + } + hdr->retry2 = ridx; + txhdr->key_type = 0; txhdr->key_len = 0; txhdr->hw_queue = skb_get_queue_mapping(skb) + 4; @@ -1393,6 +1469,16 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) priv->tx_stats[4].limit = 5; dev->queues = 1; priv->noise = -94; + /* + * We support at most 8 tries no matter which rate they're at, + * we cannot support max_rates * max_rate_tries as we set it + * here, but setting it correctly to 4/2 or so would limit us + * artificially if the RC algorithm wants just two rates, so + * let's say 4/7, we'll redistribute it at TX time, see the + * comments there. + */ + dev->max_rates = 4; + dev->max_rate_tries = 7; dev->extra_tx_headroom = sizeof(struct p54_control_hdr) + 4 + sizeof(struct p54_tx_control_allocdata); -- cgit v1.2.3-70-g09d2 From 0fdd7c5d2defe8c6873eb8a40a880eb0dc59573d Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Wed, 15 Oct 2008 03:55:37 +0200 Subject: p54: broken out edcf changes This patch series hopefully increases p54's "longterm" stability. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54.h | 9 +++- drivers/net/wireless/p54/p54common.c | 99 ++++++++++++++---------------------- drivers/net/wireless/p54/p54common.h | 28 +++++----- 3 files changed, 58 insertions(+), 78 deletions(-) (limited to 'drivers/net/wireless/p54/p54common.c') diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index 1da96fe5024..1dace10feb7 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -49,6 +49,13 @@ struct p54_control_hdr { u8 data[0]; } __attribute__ ((packed)); +struct p54_edcf_queue_param { + __le16 aifs; + __le16 cwmin; + __le16 cwmax; + __le16 txop; +} __attribute__ ((packed)); + #define EEPROM_READBACK_LEN 0x3fc #define ISL38XX_DEV_FIRMWARE_ADDR 0x20000 @@ -85,13 +92,13 @@ struct p54_common { u8 version; u8 rx_antenna; unsigned int tx_hdr_len; - void *cached_vdcf; unsigned int fw_var; unsigned int fw_interface; unsigned int output_power; u32 tsf_low32; u32 tsf_high32; struct ieee80211_tx_queue_stats tx_stats[8]; + struct p54_edcf_queue_param qos_params[8]; struct ieee80211_low_level_stats stats; struct timer_list stats_timer; struct completion stats_comp; diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 23709014024..7ddb93bb60a 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -1114,53 +1114,41 @@ do { \ queue.txop = cpu_to_le16(_txop); \ } while(0) -static void p54_init_vdcf(struct ieee80211_hw *dev) +static int p54_set_edcf(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; struct p54_control_hdr *hdr; - struct p54_tx_control_vdcf *vdcf; + struct p54_edcf *edcf; - /* all USB V1 adapters need a extra headroom */ - hdr = (void *)priv->cached_vdcf + priv->tx_hdr_len; + hdr = kzalloc(priv->tx_hdr_len + sizeof(*hdr) + sizeof(*edcf), + GFP_ATOMIC); + if (!hdr) + return -ENOMEM; + + hdr = (void *)hdr + priv->tx_hdr_len; hdr->magic1 = cpu_to_le16(0x8001); - hdr->len = cpu_to_le16(sizeof(*vdcf)); + hdr->len = cpu_to_le16(sizeof(*edcf)); hdr->type = cpu_to_le16(P54_CONTROL_TYPE_DCFINIT); - hdr->req_id = cpu_to_le32(priv->rx_start); - - vdcf = (struct p54_tx_control_vdcf *) hdr->data; - - P54_SET_QUEUE(vdcf->queue[0], 0x0002, 0x0003, 0x0007, 47); - P54_SET_QUEUE(vdcf->queue[1], 0x0002, 0x0007, 0x000f, 94); - P54_SET_QUEUE(vdcf->queue[2], 0x0003, 0x000f, 0x03ff, 0); - P54_SET_QUEUE(vdcf->queue[3], 0x0007, 0x000f, 0x03ff, 0); -} - -static void p54_set_vdcf(struct ieee80211_hw *dev) -{ - struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr; - struct p54_tx_control_vdcf *vdcf; - - hdr = (void *)priv->cached_vdcf + priv->tx_hdr_len; - - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*vdcf)); - - vdcf = (struct p54_tx_control_vdcf *) hdr->data; - + hdr->retry1 = hdr->retry2 = 0; + edcf = (struct p54_edcf *)hdr->data; if (priv->use_short_slot) { - vdcf->slottime = 9; - vdcf->magic1 = 0x10; - vdcf->magic2 = 0x00; + edcf->slottime = 9; + edcf->sifs = 0x10; + edcf->eofpad = 0x00; } else { - vdcf->slottime = 20; - vdcf->magic1 = 0x0a; - vdcf->magic2 = 0x06; + edcf->slottime = 20; + edcf->sifs = 0x0a; + edcf->eofpad = 0x06; } - /* (see prism54/isl_oid.h for further details) */ - vdcf->frameburst = cpu_to_le16(0); + edcf->frameburst = cpu_to_le16(0); + edcf->round_trip_delay = cpu_to_le16(0); + memset(edcf->mapping, 0, sizeof(edcf->mapping)); + memcpy(edcf->queue, priv->qos_params, sizeof(edcf->queue)); - priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*vdcf), 0); + p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*edcf)); + priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*edcf), 1); + return 0; } static int p54_start(struct ieee80211_hw *dev) @@ -1168,33 +1156,26 @@ static int p54_start(struct ieee80211_hw *dev) struct p54_common *priv = dev->priv; int err; - if (!priv->cached_vdcf) { - priv->cached_vdcf = kzalloc(sizeof(struct p54_tx_control_vdcf)+ - priv->tx_hdr_len + sizeof(struct p54_control_hdr), - GFP_KERNEL); - - if (!priv->cached_vdcf) - return -ENOMEM; - } - if (!priv->cached_stats) { priv->cached_stats = kzalloc(sizeof(struct p54_statistics) + priv->tx_hdr_len + sizeof(struct p54_control_hdr), GFP_KERNEL); - if (!priv->cached_stats) { - kfree(priv->cached_vdcf); - priv->cached_vdcf = NULL; + if (!priv->cached_stats) return -ENOMEM; - } } err = priv->open(dev); if (!err) priv->mode = NL80211_IFTYPE_MONITOR; + P54_SET_QUEUE(priv->qos_params[0], 0x0002, 0x0003, 0x0007, 47); + P54_SET_QUEUE(priv->qos_params[1], 0x0002, 0x0007, 0x000f, 94); + P54_SET_QUEUE(priv->qos_params[2], 0x0003, 0x000f, 0x03ff, 0); + P54_SET_QUEUE(priv->qos_params[3], 0x0007, 0x000f, 0x03ff, 0); + err = p54_set_edcf(dev); + if (!err) + mod_timer(&priv->stats_timer, jiffies + HZ); - p54_init_vdcf(dev); - mod_timer(&priv->stats_timer, jiffies + HZ); return err; } @@ -1264,7 +1245,8 @@ static int p54_config(struct ieee80211_hw *dev, u32 changed) priv->rx_antenna = 2; /* automatic */ priv->output_power = conf->power_level << 2; ret = p54_set_freq(dev, cpu_to_le16(conf->channel->center_freq)); - p54_set_vdcf(dev); + if (!ret) + ret = p54_set_edcf(dev); mutex_unlock(&priv->conf_mutex); return ret; } @@ -1319,20 +1301,14 @@ static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue, const struct ieee80211_tx_queue_params *params) { struct p54_common *priv = dev->priv; - struct p54_tx_control_vdcf *vdcf; - - vdcf = (struct p54_tx_control_vdcf *)(((struct p54_control_hdr *) - ((void *)priv->cached_vdcf + priv->tx_hdr_len))->data); if ((params) && !(queue > 4)) { - P54_SET_QUEUE(vdcf->queue[queue], params->aifs, + P54_SET_QUEUE(priv->qos_params[queue], params->aifs, params->cw_min, params->cw_max, params->txop); } else return -EINVAL; - p54_set_vdcf(dev); - - return 0; + return p54_set_edcf(dev); } static int p54_init_xbow_synth(struct ieee80211_hw *dev) @@ -1418,7 +1394,7 @@ static void p54_bss_info_changed(struct ieee80211_hw *dev, if (changed & BSS_CHANGED_ERP_SLOT) { priv->use_short_slot = info->use_short_slot; - p54_set_vdcf(dev); + p54_set_edcf(dev); } } @@ -1499,7 +1475,6 @@ void p54_free_common(struct ieee80211_hw *dev) kfree(priv->iq_autocal); kfree(priv->output_limit); kfree(priv->curve_data); - kfree(priv->cached_vdcf); } EXPORT_SYMBOL_GPL(p54_free_common); diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h index 22af41c7dab..2cb3885c021 100644 --- a/drivers/net/wireless/p54/p54common.h +++ b/drivers/net/wireless/p54/p54common.h @@ -7,8 +7,12 @@ * Copyright (c) 2006, Michael Wu * Copyright (c) 2007, Christian Lamparter * - * Based on the islsm (softmac prism54) driver, which is: - * Copyright 2004-2006 Jean-Baptiste Note , et al. + * Based on: + * - the islsm (softmac prism54) driver, which is: + * Copyright 2004-2006 Jean-Baptiste Note , et al. + * + * - LMAC API interface header file for STLC4560 (lmac_longbow.h) + * Copyright (C) 2007 Conexant Systems, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -286,21 +290,15 @@ struct p54_tx_control_led { __le16 duration; } __attribute__ ((packed)); -struct p54_tx_vdcf_queues { - __le16 aifs; - __le16 cwmin; - __le16 cwmax; - __le16 txop; -} __attribute__ ((packed)); - -struct p54_tx_control_vdcf { - u8 padding; +struct p54_edcf { + u8 flags; u8 slottime; - u8 magic1; - u8 magic2; - struct p54_tx_vdcf_queues queue[8]; - u8 pad2[4]; + u8 sifs; + u8 eofpad; + struct p54_edcf_queue_param queue[8]; + u8 mapping[4]; __le16 frameburst; + __le16 round_trip_delay; } __attribute__ ((packed)); struct p54_statistics { -- cgit v1.2.3-70-g09d2 From 0f1be978910092bed5d8dac0774e5cf85d4b4e12 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Wed, 15 Oct 2008 03:56:20 +0200 Subject: p54: refactor statistic timer code Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 39 +++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless/p54/p54common.c') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 7ddb93bb60a..fcde424adb0 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -1151,19 +1151,32 @@ static int p54_set_edcf(struct ieee80211_hw *dev) return 0; } -static int p54_start(struct ieee80211_hw *dev) +static int p54_init_stats(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; - int err; + struct p54_control_hdr *hdr; + struct p54_statistics *stats; - if (!priv->cached_stats) { - priv->cached_stats = kzalloc(sizeof(struct p54_statistics) + - priv->tx_hdr_len + sizeof(struct p54_control_hdr), - GFP_KERNEL); + priv->cached_stats = kzalloc(priv->tx_hdr_len + + sizeof(*hdr) + sizeof(*stats), GFP_KERNEL); - if (!priv->cached_stats) + if (!priv->cached_stats) return -ENOMEM; - } + + hdr = (void *) priv->cached_stats + priv->tx_hdr_len; + hdr->magic1 = cpu_to_le16(0x8000); + hdr->len = cpu_to_le16(sizeof(*stats)); + hdr->type = cpu_to_le16(P54_CONTROL_TYPE_STAT_READBACK); + hdr->retry1 = hdr->retry2 = 0; + + mod_timer(&priv->stats_timer, jiffies + HZ); + return 0; +} + +static int p54_start(struct ieee80211_hw *dev) +{ + struct p54_common *priv = dev->priv; + int err; err = priv->open(dev); if (!err) @@ -1174,7 +1187,7 @@ static int p54_start(struct ieee80211_hw *dev) P54_SET_QUEUE(priv->qos_params[3], 0x0007, 0x000f, 0x03ff, 0); err = p54_set_edcf(dev); if (!err) - mod_timer(&priv->stats_timer, jiffies + HZ); + err = p54_init_stats(dev); return err; } @@ -1185,6 +1198,8 @@ static void p54_stop(struct ieee80211_hw *dev) struct sk_buff *skb; del_timer(&priv->stats_timer); + kfree(priv->cached_stats); + priv->cached_stats = NULL; while ((skb = skb_dequeue(&priv->tx_queue))) kfree_skb(skb); priv->stop(dev); @@ -1346,11 +1361,7 @@ static void p54_statistics_timer(unsigned long data) struct p54_statistics *stats; BUG_ON(!priv->cached_stats); - - hdr = (void *)priv->cached_stats + priv->tx_hdr_len; - hdr->magic1 = cpu_to_le16(0x8000); - hdr->len = cpu_to_le16(sizeof(*stats)); - hdr->type = cpu_to_le16(P54_CONTROL_TYPE_STAT_READBACK); + hdr = (void *) priv->cached_stats + priv->tx_hdr_len; p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*stats)); priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*stats), 0); -- cgit v1.2.3-70-g09d2 From 9de5776ff33a006b864341a6ec8d31f1a3c628cf Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Wed, 15 Oct 2008 04:05:51 +0200 Subject: p54: p54: refactor p54_rx_frame_sent the long names and the nesting in p54_rx_frame_sent really became a "line longer than 80 characters" problem. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 118 ++++++++++++++++++----------------- 1 file changed, 61 insertions(+), 57 deletions(-) (limited to 'drivers/net/wireless/p54/p54common.c') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index fcde424adb0..68ae8c06bbd 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -549,73 +549,77 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) spin_lock_irqsave(&priv->tx_queue.lock, flags); while (entry != (struct sk_buff *)&priv->tx_queue) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry); + struct p54_control_hdr *entry_hdr; + struct p54_tx_control_allocdata *entry_data; + int pad = 0; + range = (void *)info->rate_driver_data; - if (range->start_addr == addr) { - struct p54_control_hdr *entry_hdr; - struct p54_tx_control_allocdata *entry_data; - int pad = 0; + if (range->start_addr != addr) { + last_addr = range->end_addr; + entry = entry->next; + continue; + } - if (entry->next != (struct sk_buff *)&priv->tx_queue) { - struct ieee80211_tx_info *ni; - struct memrecord *mr; + if (entry->next != (struct sk_buff *)&priv->tx_queue) { + struct ieee80211_tx_info *ni; + struct memrecord *mr; - ni = IEEE80211_SKB_CB(entry->next); - mr = (struct memrecord *)ni->rate_driver_data; - freed = mr->start_addr - last_addr; - } else - freed = priv->rx_end - last_addr; + ni = IEEE80211_SKB_CB(entry->next); + mr = (struct memrecord *)ni->rate_driver_data; + freed = mr->start_addr - last_addr; + } else + freed = priv->rx_end - last_addr; - last_addr = range->end_addr; - __skb_unlink(entry, &priv->tx_queue); - spin_unlock_irqrestore(&priv->tx_queue.lock, flags); - - /* - * Clear manually, ieee80211_tx_info_clear_status would - * clear the counts too and we need them. - */ - memset(&info->status.ampdu_ack_len, 0, - sizeof(struct ieee80211_tx_info) - - offsetof(struct ieee80211_tx_info, status.ampdu_ack_len)); - BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, - status.ampdu_ack_len) != 23); - - entry_hdr = (struct p54_control_hdr *) entry->data; - entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data; - if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0) - pad = entry_data->align[0]; - - /* walk through the rates array and adjust the counts */ - count = payload->retries; - for (idx = 0; idx < 4; idx++) { - if (count >= info->status.rates[idx].count) { - count -= info->status.rates[idx].count; - } else if (count > 0) { - info->status.rates[idx].count = count; - count = 0; - } else { - info->status.rates[idx].idx = -1; - info->status.rates[idx].count = 0; - } + last_addr = range->end_addr; + __skb_unlink(entry, &priv->tx_queue); + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + + /* + * Clear manually, ieee80211_tx_info_clear_status would + * clear the counts too and we need them. + */ + memset(&info->status.ampdu_ack_len, 0, + sizeof(struct ieee80211_tx_info) - + offsetof(struct ieee80211_tx_info, status.ampdu_ack_len)); + BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, + status.ampdu_ack_len) != 23); + + entry_hdr = (struct p54_control_hdr *) entry->data; + entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data; + if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0) + pad = entry_data->align[0]; + + /* walk through the rates array and adjust the counts */ + count = payload->retries; + for (idx = 0; idx < 4; idx++) { + if (count >= info->status.rates[idx].count) { + count -= info->status.rates[idx].count; + } else if (count > 0) { + info->status.rates[idx].count = count; + count = 0; + } else { + info->status.rates[idx].idx = -1; + info->status.rates[idx].count = 0; } + } - priv->tx_stats[entry_data->hw_queue].len--; - if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && - !(payload->status & 0x01)) - info->flags |= IEEE80211_TX_STAT_ACK; - info->status.ack_signal = p54_rssi_to_dbm(dev, - le16_to_cpu(payload->ack_rssi)); - skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data)); - ieee80211_tx_status_irqsafe(dev, entry); - goto out; - } else - last_addr = range->end_addr; - entry = entry->next; + priv->tx_stats[entry_data->hw_queue].len--; + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && + (!payload->status)) + info->flags |= IEEE80211_TX_STAT_ACK; + if (payload->status & 0x02) + info->flags |= IEEE80211_TX_STAT_TX_FILTERED; + info->status.ack_signal = p54_rssi_to_dbm(dev, + le16_to_cpu(payload->ack_rssi)); + skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data)); + ieee80211_tx_status_irqsafe(dev, entry); + goto out; } spin_unlock_irqrestore(&priv->tx_queue.lock, flags); out: - if (freed >= IEEE80211_MAX_RTS_THRESHOLD + 0x170 + - sizeof(struct p54_control_hdr)) + if (freed >= priv->headroom + sizeof(struct p54_control_hdr) + 48 + + IEEE80211_MAX_RTS_THRESHOLD + priv->tailroom) p54_wake_free_queues(dev); } -- cgit v1.2.3-70-g09d2 From b92f30d65aeb0502e2ed8beb80c8465578b40002 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Wed, 15 Oct 2008 04:07:16 +0200 Subject: p54: fix memory management We have to be careful if multiple "control frames" are passed in a very short intervals to the device's firmware. As p54_assign_address always put them into same memory location. To guarantee that this won't happen anymore, we have to treat control frames like normal data frames in the devices own memory management. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54.h | 7 +- drivers/net/wireless/p54/p54common.c | 288 ++++++++++++++++++++--------------- drivers/net/wireless/p54/p54pci.c | 23 +-- drivers/net/wireless/p54/p54usb.c | 74 ++++++--- 4 files changed, 229 insertions(+), 163 deletions(-) (limited to 'drivers/net/wireless/p54/p54common.c') diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index 1dace10feb7..e9988e78a0c 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -69,8 +69,8 @@ struct p54_common { u32 rx_start; u32 rx_end; struct sk_buff_head tx_queue; - void (*tx)(struct ieee80211_hw *dev, struct p54_control_hdr *data, - size_t len, int free_on_tx); + void (*tx)(struct ieee80211_hw *dev, struct sk_buff *skb, + int free_on_tx); int (*open)(struct ieee80211_hw *dev); void (*stop)(struct ieee80211_hw *dev); int mode; @@ -102,13 +102,14 @@ struct p54_common { struct ieee80211_low_level_stats stats; struct timer_list stats_timer; struct completion stats_comp; - void *cached_stats; + struct sk_buff *cached_stats; int noise; void *eeprom; struct completion eeprom_comp; }; int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb); +void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb); int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw); int p54_read_eeprom(struct ieee80211_hw *dev); struct ieee80211_hw *p54_init_common(size_t priv_data_len); diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 68ae8c06bbd..13080b1ba5e 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -528,11 +528,55 @@ static void inline p54_wake_free_queues(struct ieee80211_hw *dev) struct p54_common *priv = dev->priv; int i; + if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) + return ; + for (i = 0; i < dev->queues; i++) if (priv->tx_stats[i + 4].len < priv->tx_stats[i + 4].limit) ieee80211_wake_queue(dev, i); } +void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb) +{ + struct p54_common *priv = dev->priv; + struct ieee80211_tx_info *info; + struct memrecord *range; + unsigned long flags; + u32 freed = 0, last_addr = priv->rx_start; + + if (!skb || !dev) + return; + + spin_lock_irqsave(&priv->tx_queue.lock, flags); + info = IEEE80211_SKB_CB(skb); + range = (void *)info->rate_driver_data; + if (skb->prev != (struct sk_buff *)&priv->tx_queue) { + struct ieee80211_tx_info *ni; + struct memrecord *mr; + + ni = IEEE80211_SKB_CB(skb->prev); + mr = (struct memrecord *)ni->rate_driver_data; + last_addr = mr->end_addr; + } + if (skb->next != (struct sk_buff *)&priv->tx_queue) { + struct ieee80211_tx_info *ni; + struct memrecord *mr; + + ni = IEEE80211_SKB_CB(skb->next); + mr = (struct memrecord *)ni->rate_driver_data; + freed = mr->start_addr - last_addr; + } else + freed = priv->rx_end - last_addr; + __skb_unlink(skb, &priv->tx_queue); + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + kfree_skb(skb); + + if (freed >= priv->headroom + sizeof(struct p54_control_hdr) + 48 + + IEEE80211_MAX_RTS_THRESHOLD + priv->tailroom) + p54_wake_free_queues(dev); +} +EXPORT_SYMBOL_GPL(p54_free_skb); + static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54_common *priv = dev->priv; @@ -705,12 +749,14 @@ EXPORT_SYMBOL_GPL(p54_rx); * marks allocated areas as reserved if necessary. p54_rx_frame_sent frees * allocated areas. */ -static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, +static int p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, struct p54_control_hdr *data, u32 len) { struct p54_common *priv = dev->priv; struct sk_buff *entry = priv->tx_queue.next; struct sk_buff *target_skb = NULL; + struct ieee80211_tx_info *info; + struct memrecord *range; u32 last_addr = priv->rx_start; u32 largest_hole = 0; u32 target_addr = priv->rx_start; @@ -718,12 +764,15 @@ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, unsigned int left; len = (len + priv->headroom + priv->tailroom + 3) & ~0x3; + if (!skb) + return -EINVAL; + spin_lock_irqsave(&priv->tx_queue.lock, flags); left = skb_queue_len(&priv->tx_queue); while (left--) { u32 hole_size; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry); - struct memrecord *range = (void *)info->rate_driver_data; + info = IEEE80211_SKB_CB(entry); + range = (void *)info->rate_driver_data; hole_size = range->start_addr - last_addr; if (!target_skb && hole_size >= len) { target_skb = entry->prev; @@ -738,27 +787,57 @@ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, target_skb = priv->tx_queue.prev; largest_hole = max(largest_hole, priv->rx_end - last_addr - len); if (!skb_queue_empty(&priv->tx_queue)) { - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(target_skb); - struct memrecord *range = (void *)info->rate_driver_data; + info = IEEE80211_SKB_CB(target_skb); + range = (void *)info->rate_driver_data; target_addr = range->end_addr; } } else largest_hole = max(largest_hole, priv->rx_end - last_addr); - if (skb) { - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct memrecord *range = (void *)info->rate_driver_data; - range->start_addr = target_addr; - range->end_addr = target_addr + len; - __skb_queue_after(&priv->tx_queue, target_skb, skb); - if (largest_hole < priv->rx_mtu + priv->headroom + - priv->tailroom + - sizeof(struct p54_control_hdr)) - ieee80211_stop_queues(dev); + if (!target_skb) { + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + ieee80211_stop_queues(dev); + return -ENOMEM; } + + info = IEEE80211_SKB_CB(skb); + range = (void *)info->rate_driver_data; + range->start_addr = target_addr; + range->end_addr = target_addr + len; + __skb_queue_after(&priv->tx_queue, target_skb, skb); spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + if (largest_hole < priv->headroom + sizeof(struct p54_control_hdr) + + 48 + IEEE80211_MAX_RTS_THRESHOLD + priv->tailroom) + ieee80211_stop_queues(dev); + data->req_id = cpu_to_le32(target_addr + priv->headroom); + return 0; +} + +static struct sk_buff *p54_alloc_skb(struct ieee80211_hw *dev, + u16 hdr_flags, u16 len, u16 type, gfp_t memflags) +{ + struct p54_common *priv = dev->priv; + struct p54_control_hdr *hdr; + struct sk_buff *skb; + + skb = __dev_alloc_skb(len + priv->tx_hdr_len, memflags); + if (!skb) + return NULL; + skb_reserve(skb, priv->tx_hdr_len); + + hdr = (struct p54_control_hdr *) skb_put(skb, sizeof(*hdr)); + hdr->magic1 = cpu_to_le16(hdr_flags); + hdr->len = cpu_to_le16(len - sizeof(*hdr)); + hdr->type = cpu_to_le16(type); + hdr->retry1 = hdr->retry2 = 0; + + if (unlikely(p54_assign_address(dev, skb, hdr, len))) { + kfree_skb(skb); + return NULL; + } + return skb; } int p54_read_eeprom(struct ieee80211_hw *dev) @@ -766,36 +845,31 @@ int p54_read_eeprom(struct ieee80211_hw *dev) struct p54_common *priv = dev->priv; struct p54_control_hdr *hdr = NULL; struct p54_eeprom_lm86 *eeprom_hdr; + struct sk_buff *skb; size_t eeprom_size = 0x2020, offset = 0, blocksize; int ret = -ENOMEM; void *eeprom = NULL; - hdr = (struct p54_control_hdr *)kzalloc(sizeof(*hdr) + - sizeof(*eeprom_hdr) + EEPROM_READBACK_LEN, GFP_KERNEL); - if (!hdr) + skb = p54_alloc_skb(dev, 0x8000, sizeof(*hdr) + sizeof(*eeprom_hdr) + + EEPROM_READBACK_LEN, + P54_CONTROL_TYPE_EEPROM_READBACK, GFP_KERNEL); + if (!skb) goto free; - priv->eeprom = kzalloc(EEPROM_READBACK_LEN, GFP_KERNEL); if (!priv->eeprom) goto free; - eeprom = kzalloc(eeprom_size, GFP_KERNEL); if (!eeprom) goto free; - hdr->magic1 = cpu_to_le16(0x8000); - hdr->type = cpu_to_le16(P54_CONTROL_TYPE_EEPROM_READBACK); - hdr->retry1 = hdr->retry2 = 0; - eeprom_hdr = (struct p54_eeprom_lm86 *) hdr->data; + eeprom_hdr = (struct p54_eeprom_lm86 *) skb_put(skb, + sizeof(*eeprom_hdr) + EEPROM_READBACK_LEN); while (eeprom_size) { blocksize = min(eeprom_size, (size_t)EEPROM_READBACK_LEN); - hdr->len = cpu_to_le16(blocksize + sizeof(*eeprom_hdr)); eeprom_hdr->offset = cpu_to_le16(offset); eeprom_hdr->len = cpu_to_le16(blocksize); - p54_assign_address(dev, NULL, hdr, le16_to_cpu(hdr->len) + - sizeof(*hdr)); - priv->tx(dev, hdr, le16_to_cpu(hdr->len) + sizeof(*hdr), 0); + priv->tx(dev, skb, 0); if (!wait_for_completion_interruptible_timeout(&priv->eeprom_comp, HZ)) { printk(KERN_ERR "%s: device does not respond!\n", @@ -813,7 +887,7 @@ int p54_read_eeprom(struct ieee80211_hw *dev) free: kfree(priv->eeprom); priv->eeprom = NULL; - kfree(hdr); + p54_free_skb(dev, skb); kfree(eeprom); return ret; @@ -936,9 +1010,11 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) txhdr->align[0] = padding; /* modifies skb->cb and with it info, so must be last! */ - p54_assign_address(dev, skb, hdr, skb->len); - - priv->tx(dev, hdr, skb->len, 0); + if (unlikely(p54_assign_address(dev, skb, hdr, skb->len))) { + skb_pull(skb, sizeof(*hdr) + sizeof(*txhdr) + padding); + return NETDEV_TX_BUSY; + } + priv->tx(dev, skb, 0); return 0; } @@ -946,22 +1022,22 @@ static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type, const u8 *bssid) { struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr; + struct sk_buff *skb; struct p54_tx_control_filter *filter; - size_t data_len; - - hdr = kzalloc(sizeof(*hdr) + sizeof(*filter) + - priv->tx_hdr_len, GFP_ATOMIC); - if (!hdr) - return -ENOMEM; + u16 data_len = sizeof(struct p54_control_hdr) + sizeof(*filter); - hdr = (void *)hdr + priv->tx_hdr_len; + if (priv->fw_var < 0x500) + data_len += P54_TX_CONTROL_FILTER_V1_LEN; + else + data_len += P54_TX_CONTROL_FILTER_V2_LEN; - filter = (struct p54_tx_control_filter *) hdr->data; - hdr->magic1 = cpu_to_le16(0x8001); - hdr->type = cpu_to_le16(P54_CONTROL_TYPE_FILTER_SET); + skb = p54_alloc_skb(dev, 0x8001, data_len, P54_CONTROL_TYPE_FILTER_SET, + GFP_ATOMIC); + if (!skb) + return -ENOMEM; - priv->filter_type = filter->filter_type = cpu_to_le16(filter_type); + filter = (struct p54_tx_control_filter *) skb_put(skb, sizeof(*filter)); + filter->filter_type = priv->filter_type = cpu_to_le16(filter_type); memcpy(filter->mac_addr, priv->mac_addr, ETH_ALEN); if (!bssid) memset(filter->bssid, ~0, ETH_ALEN); @@ -969,47 +1045,37 @@ static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type, memcpy(filter->bssid, bssid, ETH_ALEN); filter->rx_antenna = priv->rx_antenna; if (priv->fw_var < 0x500) { - data_len = P54_TX_CONTROL_FILTER_V1_LEN; filter->v1.basic_rate_mask = cpu_to_le32(0x15f); filter->v1.rx_addr = cpu_to_le32(priv->rx_end); filter->v1.max_rx = cpu_to_le16(priv->rx_mtu); filter->v1.rxhw = cpu_to_le16(priv->rxhw); filter->v1.wakeup_timer = cpu_to_le16(500); } else { - data_len = P54_TX_CONTROL_FILTER_V2_LEN; filter->v2.rx_addr = cpu_to_le32(priv->rx_end); filter->v2.max_rx = cpu_to_le16(priv->rx_mtu); filter->v2.rxhw = cpu_to_le16(priv->rxhw); filter->v2.timer = cpu_to_le16(1000); } - hdr->len = cpu_to_le16(data_len); - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + data_len); - priv->tx(dev, hdr, sizeof(*hdr) + data_len, 1); + priv->tx(dev, skb, 1); return 0; } static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq) { struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr; + struct sk_buff *skb; struct p54_tx_control_channel *chan; unsigned int i; - size_t data_len; + size_t data_len = sizeof(struct p54_control_hdr) + sizeof(*chan); void *entry; - hdr = kzalloc(sizeof(*hdr) + sizeof(*chan) + - priv->tx_hdr_len, GFP_KERNEL); - if (!hdr) + skb = p54_alloc_skb(dev, 0x8001, data_len, + P54_CONTROL_TYPE_CHANNEL_CHANGE, GFP_ATOMIC); + if (!skb) return -ENOMEM; - hdr = (void *)hdr + priv->tx_hdr_len; - - chan = (struct p54_tx_control_channel *) hdr->data; - - hdr->magic1 = cpu_to_le16(0x8001); - - hdr->type = cpu_to_le16(P54_CONTROL_TYPE_CHANNEL_CHANGE); - + chan = (struct p54_tx_control_channel *) skb_put(skb, sizeof(*chan)); + memset(chan->padding1, 0, sizeof(chan->padding1)); chan->flags = cpu_to_le16(0x1); chan->dwell = cpu_to_le16(0x0); @@ -1065,48 +1131,37 @@ static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq) chan->v1.rssical_mul = cpu_to_le16(130); chan->v1.rssical_add = cpu_to_le16(0xfe70); } else { - data_len = P54_TX_CONTROL_CHANNEL_V2_LEN; chan->v2.rssical_mul = cpu_to_le16(130); chan->v2.rssical_add = cpu_to_le16(0xfe70); chan->v2.basic_rate_mask = cpu_to_le32(0x15f); } - - hdr->len = cpu_to_le16(data_len); - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + data_len); - priv->tx(dev, hdr, sizeof(*hdr) + data_len, 1); + priv->tx(dev, skb, 1); return 0; err: printk(KERN_ERR "%s: frequency change failed\n", wiphy_name(dev->wiphy)); - kfree(hdr); + kfree_skb(skb); return -EINVAL; } static int p54_set_leds(struct ieee80211_hw *dev, int mode, int link, int act) { struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr; + struct sk_buff *skb; struct p54_tx_control_led *led; - hdr = kzalloc(sizeof(*hdr) + sizeof(*led) + - priv->tx_hdr_len, GFP_KERNEL); - if (!hdr) + skb = p54_alloc_skb(dev, 0x8001, sizeof(*led) + + sizeof(struct p54_control_hdr), + P54_CONTROL_TYPE_LED, GFP_ATOMIC); + if (!skb) return -ENOMEM; - hdr = (void *)hdr + priv->tx_hdr_len; - hdr->magic1 = cpu_to_le16(0x8001); - hdr->len = cpu_to_le16(sizeof(*led)); - hdr->type = cpu_to_le16(P54_CONTROL_TYPE_LED); - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*led)); - - led = (struct p54_tx_control_led *) hdr->data; + led = (struct p54_tx_control_led *)skb_put(skb, sizeof(*led)); led->mode = cpu_to_le16(mode); led->led_permanent = cpu_to_le16(link); led->led_temporary = cpu_to_le16(act); led->duration = cpu_to_le16(1000); - - priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*led), 1); - + priv->tx(dev, skb, 1); return 0; } @@ -1121,20 +1176,15 @@ do { \ static int p54_set_edcf(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr; + struct sk_buff *skb; struct p54_edcf *edcf; - hdr = kzalloc(priv->tx_hdr_len + sizeof(*hdr) + sizeof(*edcf), - GFP_ATOMIC); - if (!hdr) + skb = p54_alloc_skb(dev, 0x8001, sizeof(struct p54_control_hdr) + + sizeof(*edcf), P54_CONTROL_TYPE_DCFINIT, GFP_ATOMIC); + if (!skb) return -ENOMEM; - hdr = (void *)hdr + priv->tx_hdr_len; - hdr->magic1 = cpu_to_le16(0x8001); - hdr->len = cpu_to_le16(sizeof(*edcf)); - hdr->type = cpu_to_le16(P54_CONTROL_TYPE_DCFINIT); - hdr->retry1 = hdr->retry2 = 0; - edcf = (struct p54_edcf *)hdr->data; + edcf = (struct p54_edcf *)skb_put(skb, sizeof(*edcf)); if (priv->use_short_slot) { edcf->slottime = 9; edcf->sifs = 0x10; @@ -1149,30 +1199,22 @@ static int p54_set_edcf(struct ieee80211_hw *dev) edcf->round_trip_delay = cpu_to_le16(0); memset(edcf->mapping, 0, sizeof(edcf->mapping)); memcpy(edcf->queue, priv->qos_params, sizeof(edcf->queue)); - - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*edcf)); - priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*edcf), 1); + priv->tx(dev, skb, 1); return 0; } static int p54_init_stats(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr; - struct p54_statistics *stats; - - priv->cached_stats = kzalloc(priv->tx_hdr_len + - sizeof(*hdr) + sizeof(*stats), GFP_KERNEL); + priv->cached_stats = p54_alloc_skb(dev, 0x8000, + sizeof(struct p54_control_hdr) + + sizeof(struct p54_statistics), + P54_CONTROL_TYPE_STAT_READBACK, + GFP_KERNEL); if (!priv->cached_stats) return -ENOMEM; - hdr = (void *) priv->cached_stats + priv->tx_hdr_len; - hdr->magic1 = cpu_to_le16(0x8000); - hdr->len = cpu_to_le16(sizeof(*stats)); - hdr->type = cpu_to_le16(P54_CONTROL_TYPE_STAT_READBACK); - hdr->retry1 = hdr->retry2 = 0; - mod_timer(&priv->stats_timer, jiffies + HZ); return 0; } @@ -1202,10 +1244,11 @@ static void p54_stop(struct ieee80211_hw *dev) struct sk_buff *skb; del_timer(&priv->stats_timer); - kfree(priv->cached_stats); + p54_free_skb(dev, priv->cached_stats); priv->cached_stats = NULL; while ((skb = skb_dequeue(&priv->tx_queue))) kfree_skb(skb); + priv->stop(dev); priv->tsf_high32 = priv->tsf_low32 = 0; priv->mode = NL80211_IFTYPE_UNSPECIFIED; @@ -1333,27 +1376,21 @@ static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue, static int p54_init_xbow_synth(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr; + struct sk_buff *skb; struct p54_tx_control_xbow_synth *xbow; - hdr = kzalloc(sizeof(*hdr) + sizeof(*xbow) + - priv->tx_hdr_len, GFP_KERNEL); - if (!hdr) + skb = p54_alloc_skb(dev, 0x8001, sizeof(struct p54_control_hdr) + + sizeof(*xbow), P54_CONTROL_TYPE_XBOW_SYNTH_CFG, + GFP_KERNEL); + if (!skb) return -ENOMEM; - hdr = (void *)hdr + priv->tx_hdr_len; - hdr->magic1 = cpu_to_le16(0x8001); - hdr->len = cpu_to_le16(sizeof(*xbow)); - hdr->type = cpu_to_le16(P54_CONTROL_TYPE_XBOW_SYNTH_CFG); - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*xbow)); - - xbow = (struct p54_tx_control_xbow_synth *) hdr->data; + xbow = (struct p54_tx_control_xbow_synth *)skb_put(skb, sizeof(*xbow)); xbow->magic1 = cpu_to_le16(0x1); xbow->magic2 = cpu_to_le16(0x2); xbow->freq = cpu_to_le16(5390); - - priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*xbow), 1); - + memset(xbow->padding, 0, sizeof(xbow->padding)); + priv->tx(dev, skb, 1); return 0; } @@ -1361,14 +1398,10 @@ static void p54_statistics_timer(unsigned long data) { struct ieee80211_hw *dev = (struct ieee80211_hw *) data; struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr; - struct p54_statistics *stats; BUG_ON(!priv->cached_stats); - hdr = (void *) priv->cached_stats + priv->tx_hdr_len; - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*stats)); - priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*stats), 0); + priv->tx(dev, priv->cached_stats, 0); } static int p54_get_stats(struct ieee80211_hw *dev, @@ -1486,7 +1519,8 @@ EXPORT_SYMBOL_GPL(p54_init_common); void p54_free_common(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; - kfree(priv->cached_stats); + del_timer(&priv->stats_timer); + kfree_skb(priv->cached_stats); kfree(priv->iq_autocal); kfree(priv->output_limit); kfree(priv->curve_data); diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index bba2c90e533..1bb9584f035 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -235,7 +235,7 @@ static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index, while (i != idx) { desc = &ring[i]; - kfree(tx_buf[i]); + p54_free_skb(dev, tx_buf[i]); tx_buf[i] = NULL; pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr), @@ -306,8 +306,8 @@ static irqreturn_t p54p_interrupt(int irq, void *dev_id) return reg ? IRQ_HANDLED : IRQ_NONE; } -static void p54p_tx(struct ieee80211_hw *dev, struct p54_control_hdr *data, - size_t len, int free_on_tx) +static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb, + int free_on_tx) { struct p54p_priv *priv = dev->priv; struct p54p_ring_control *ring_control = priv->ring_control; @@ -322,18 +322,19 @@ static void p54p_tx(struct ieee80211_hw *dev, struct p54_control_hdr *data, idx = le32_to_cpu(ring_control->host_idx[1]); i = idx % ARRAY_SIZE(ring_control->tx_data); - mapping = pci_map_single(priv->pdev, data, len, PCI_DMA_TODEVICE); + mapping = pci_map_single(priv->pdev, skb->data, skb->len, + PCI_DMA_TODEVICE); desc = &ring_control->tx_data[i]; desc->host_addr = cpu_to_le32(mapping); - desc->device_addr = data->req_id; - desc->len = cpu_to_le16(len); + desc->device_addr = ((struct p54_control_hdr *)skb->data)->req_id; + desc->len = cpu_to_le16(skb->len); desc->flags = 0; wmb(); ring_control->host_idx[1] = cpu_to_le32(idx + 1); if (free_on_tx) - priv->tx_buf_data[i] = data; + priv->tx_buf_data[i] = skb; spin_unlock_irqrestore(&priv->lock, flags); @@ -342,8 +343,10 @@ static void p54p_tx(struct ieee80211_hw *dev, struct p54_control_hdr *data, /* FIXME: unlikely to happen because the device usually runs out of memory before we fill the ring up, but we can make it impossible */ - if (idx - device_idx > ARRAY_SIZE(ring_control->tx_data) - 2) + if (idx - device_idx > ARRAY_SIZE(ring_control->tx_data) - 2) { + p54_free_skb(dev, skb); printk(KERN_INFO "%s: tx overflow.\n", wiphy_name(dev->wiphy)); + } } static void p54p_stop(struct ieee80211_hw *dev) @@ -393,7 +396,7 @@ static void p54p_stop(struct ieee80211_hw *dev) le16_to_cpu(desc->len), PCI_DMA_TODEVICE); - kfree(priv->tx_buf_data[i]); + p54_free_skb(dev, priv->tx_buf_data[i]); priv->tx_buf_data[i] = NULL; } @@ -405,7 +408,7 @@ static void p54p_stop(struct ieee80211_hw *dev) le16_to_cpu(desc->len), PCI_DMA_TODEVICE); - kfree(priv->tx_buf_mgmt[i]); + p54_free_skb(dev, priv->tx_buf_mgmt[i]); priv->tx_buf_mgmt[i] = NULL; } diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index 68f1b80f04d..88fb65046c7 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -135,6 +135,16 @@ static void p54u_rx_cb(struct urb *urb) usb_submit_urb(urb, GFP_ATOMIC); } +static void p54u_tx_reuse_skb_cb(struct urb *urb) +{ + struct sk_buff *skb = urb->context; + struct p54u_priv *priv = (struct p54u_priv *)((struct ieee80211_hw *) + usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)))->priv; + + skb_pull(skb, priv->common.tx_hdr_len); + usb_free_urb(urb); +} + static void p54u_tx_cb(struct urb *urb) { usb_free_urb(urb); @@ -146,6 +156,16 @@ static void p54u_tx_free_cb(struct urb *urb) usb_free_urb(urb); } +static void p54u_tx_free_skb_cb(struct urb *urb) +{ + struct sk_buff *skb = urb->context; + struct ieee80211_hw *dev = (struct ieee80211_hw *) + usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)); + + p54_free_skb(dev, skb); + usb_free_urb(urb); +} + static int p54u_init_urbs(struct ieee80211_hw *dev) { struct p54u_priv *priv = dev->priv; @@ -192,8 +212,8 @@ static void p54u_free_urbs(struct ieee80211_hw *dev) } } -static void p54u_tx_3887(struct ieee80211_hw *dev, struct p54_control_hdr *data, - size_t len, int free_on_tx) +static void p54u_tx_3887(struct ieee80211_hw *dev, struct sk_buff *skb, + int free_on_tx) { struct p54u_priv *priv = dev->priv; struct urb *addr_urb, *data_urb; @@ -209,11 +229,14 @@ static void p54u_tx_3887(struct ieee80211_hw *dev, struct p54_control_hdr *data, } usb_fill_bulk_urb(addr_urb, priv->udev, - usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), &data->req_id, - sizeof(data->req_id), p54u_tx_cb, dev); + usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), + &((struct p54_control_hdr *)skb->data)->req_id, 4, + p54u_tx_cb, dev); usb_fill_bulk_urb(data_urb, priv->udev, - usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), data, len, - free_on_tx ? p54u_tx_free_cb : p54u_tx_cb, dev); + usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), + skb->data, skb->len, + free_on_tx ? p54u_tx_free_skb_cb : + p54u_tx_reuse_skb_cb, skb); usb_submit_urb(addr_urb, GFP_ATOMIC); usb_submit_urb(data_urb, GFP_ATOMIC); @@ -232,31 +255,35 @@ static __le32 p54u_lm87_chksum(const u32 *data, size_t length) return cpu_to_le32(chk); } -static void p54u_tx_lm87(struct ieee80211_hw *dev, - struct p54_control_hdr *data, - size_t len, int free_on_tx) +static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb, + int free_on_tx) { struct p54u_priv *priv = dev->priv; struct urb *data_urb; - struct lm87_tx_hdr *hdr = (void *)data - sizeof(*hdr); + struct lm87_tx_hdr *hdr; + __le32 checksum; + __le32 addr = ((struct p54_control_hdr *)skb->data)->req_id; data_urb = usb_alloc_urb(0, GFP_ATOMIC); if (!data_urb) return; - hdr->chksum = p54u_lm87_chksum((u32 *)data, len); - hdr->device_addr = data->req_id; + checksum = p54u_lm87_chksum((u32 *)skb->data, skb->len); + hdr = (struct lm87_tx_hdr *)skb_push(skb, sizeof(*hdr)); + hdr->chksum = checksum; + hdr->device_addr = addr; usb_fill_bulk_urb(data_urb, priv->udev, - usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), hdr, - len + sizeof(*hdr), free_on_tx ? p54u_tx_free_cb : p54u_tx_cb, - dev); + usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), + skb->data, skb->len, + free_on_tx ? p54u_tx_free_skb_cb : + p54u_tx_reuse_skb_cb, skb); usb_submit_urb(data_urb, GFP_ATOMIC); } -static void p54u_tx_net2280(struct ieee80211_hw *dev, struct p54_control_hdr *data, - size_t len, int free_on_tx) +static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb, + int free_on_tx) { struct p54u_priv *priv = dev->priv; struct urb *int_urb, *data_urb; @@ -284,11 +311,10 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct p54_control_hdr *da reg->addr = cpu_to_le32(P54U_DEV_BASE); reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA); - len += sizeof(*data); - hdr = (void *)data - sizeof(*hdr); + hdr = (void *)skb_push(skb, sizeof(*hdr)); memset(hdr, 0, sizeof(*hdr)); - hdr->device_addr = data->req_id; - hdr->len = cpu_to_le16(len); + hdr->device_addr = ((struct p54_control_hdr *)skb->data)->req_id; + hdr->len = cpu_to_le16(skb->len + sizeof(struct p54_control_hdr)); usb_fill_bulk_urb(int_urb, priv->udev, usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg), @@ -296,8 +322,10 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct p54_control_hdr *da usb_submit_urb(int_urb, GFP_ATOMIC); usb_fill_bulk_urb(data_urb, priv->udev, - usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), hdr, len + sizeof(*hdr), - free_on_tx ? p54u_tx_free_cb : p54u_tx_cb, dev); + usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), + skb->data, skb->len, + free_on_tx ? p54u_tx_free_skb_cb : + p54u_tx_reuse_skb_cb, skb); usb_submit_urb(data_urb, GFP_ATOMIC); } -- cgit v1.2.3-70-g09d2 From 5e73444e91889ea6c7a83bc174ef8e8b6aaeea9b Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Wed, 15 Oct 2008 04:07:56 +0200 Subject: p54: borrow some setup code from stlc45xx This patch initialize all remaining values which are necessary for SPI firmwares. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54.h | 4 +- drivers/net/wireless/p54/p54common.c | 75 ++++++++++++++++++------------------ drivers/net/wireless/p54/p54common.h | 18 +++++---- 3 files changed, 51 insertions(+), 46 deletions(-) (limited to 'drivers/net/wireless/p54/p54common.c') diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index e9988e78a0c..7a3bf759a40 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -15,7 +15,7 @@ */ enum control_frame_types { - P54_CONTROL_TYPE_FILTER_SET = 0, + P54_CONTROL_TYPE_SETUP = 0, P54_CONTROL_TYPE_CHANNEL_CHANGE, P54_CONTROL_TYPE_FREQDONE, P54_CONTROL_TYPE_DCFINIT, @@ -80,7 +80,7 @@ struct p54_common { struct mutex conf_mutex; u8 mac_addr[ETH_ALEN]; u8 bssid[ETH_ALEN]; - __le16 filter_type; + u16 mac_mode; struct pda_iq_autocal_entry *iq_autocal; unsigned int iq_autocal_len; struct pda_channel_output_limit *output_limit; diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 13080b1ba5e..525a684c57b 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -1018,43 +1018,48 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) return 0; } -static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type, - const u8 *bssid) +static int p54_setup_mac(struct ieee80211_hw *dev, u16 mode, const u8 *bssid) { struct p54_common *priv = dev->priv; struct sk_buff *skb; - struct p54_tx_control_filter *filter; - u16 data_len = sizeof(struct p54_control_hdr) + sizeof(*filter); + struct p54_setup_mac *setup; - if (priv->fw_var < 0x500) - data_len += P54_TX_CONTROL_FILTER_V1_LEN; - else - data_len += P54_TX_CONTROL_FILTER_V2_LEN; - - skb = p54_alloc_skb(dev, 0x8001, data_len, P54_CONTROL_TYPE_FILTER_SET, + skb = p54_alloc_skb(dev, 0x8001, sizeof(struct p54_control_hdr) + + sizeof(*setup), P54_CONTROL_TYPE_SETUP, GFP_ATOMIC); if (!skb) return -ENOMEM; - filter = (struct p54_tx_control_filter *) skb_put(skb, sizeof(*filter)); - filter->filter_type = priv->filter_type = cpu_to_le16(filter_type); - memcpy(filter->mac_addr, priv->mac_addr, ETH_ALEN); + setup = (struct p54_setup_mac *) skb_put(skb, sizeof(*setup)); + priv->mac_mode = mode; + setup->mac_mode = cpu_to_le16(mode); + memcpy(setup->mac_addr, priv->mac_addr, ETH_ALEN); if (!bssid) - memset(filter->bssid, ~0, ETH_ALEN); + memset(setup->bssid, ~0, ETH_ALEN); else - memcpy(filter->bssid, bssid, ETH_ALEN); - filter->rx_antenna = priv->rx_antenna; + memcpy(setup->bssid, bssid, ETH_ALEN); + setup->rx_antenna = priv->rx_antenna; if (priv->fw_var < 0x500) { - filter->v1.basic_rate_mask = cpu_to_le32(0x15f); - filter->v1.rx_addr = cpu_to_le32(priv->rx_end); - filter->v1.max_rx = cpu_to_le16(priv->rx_mtu); - filter->v1.rxhw = cpu_to_le16(priv->rxhw); - filter->v1.wakeup_timer = cpu_to_le16(500); + setup->v1.basic_rate_mask = cpu_to_le32(0x15f); + setup->v1.rx_addr = cpu_to_le32(priv->rx_end); + setup->v1.max_rx = cpu_to_le16(priv->rx_mtu); + setup->v1.rxhw = cpu_to_le16(priv->rxhw); + setup->v1.wakeup_timer = cpu_to_le16(500); + setup->v1.unalloc0 = cpu_to_le16(0); } else { - filter->v2.rx_addr = cpu_to_le32(priv->rx_end); - filter->v2.max_rx = cpu_to_le16(priv->rx_mtu); - filter->v2.rxhw = cpu_to_le16(priv->rxhw); - filter->v2.timer = cpu_to_le16(1000); + setup->v2.rx_addr = cpu_to_le32(priv->rx_end); + setup->v2.max_rx = cpu_to_le16(priv->rx_mtu); + setup->v2.rxhw = cpu_to_le16(priv->rxhw); + setup->v2.timer = cpu_to_le16(1000); + setup->v2.truncate = cpu_to_le16(48896); + setup->v2.basic_rate_mask = cpu_to_le32(0x15f); + setup->v2.sbss_offset = 0; + setup->v2.mcast_window = 0; + setup->v2.rx_rssi_threshold = 0; + setup->v2.rx_ed_threshold = 0; + setup->v2.ref_clock = cpu_to_le32(644245094); + setup->v2.lpf_bandwidth = cpu_to_le16(65535); + setup->v2.osc_start_delay = cpu_to_le16(65535); } priv->tx(dev, skb, 1); return 0; @@ -1272,11 +1277,11 @@ static int p54_add_interface(struct ieee80211_hw *dev, memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); - p54_set_filter(dev, 0, NULL); + p54_setup_mac(dev, 0, NULL); switch (conf->type) { case NL80211_IFTYPE_STATION: - p54_set_filter(dev, 1, NULL); + p54_setup_mac(dev, 1, NULL); break; default: BUG(); /* impossible */ @@ -1294,7 +1299,7 @@ static void p54_remove_interface(struct ieee80211_hw *dev, struct p54_common *priv = dev->priv; priv->mode = NL80211_IFTYPE_MONITOR; memset(priv->mac_addr, 0, ETH_ALEN); - p54_set_filter(dev, 0, NULL); + p54_setup_mac(dev, 0, NULL); } static int p54_config(struct ieee80211_hw *dev, u32 changed) @@ -1320,7 +1325,7 @@ static int p54_config_interface(struct ieee80211_hw *dev, struct p54_common *priv = dev->priv; mutex_lock(&priv->conf_mutex); - p54_set_filter(dev, 0, conf->bssid); + p54_setup_mac(dev, 0, conf->bssid); p54_set_leds(dev, 1, !is_multicast_ether_addr(conf->bssid), 0); memcpy(priv->bssid, conf->bssid, ETH_ALEN); mutex_unlock(&priv->conf_mutex); @@ -1342,20 +1347,16 @@ static void p54_configure_filter(struct ieee80211_hw *dev, if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { if (*total_flags & FIF_BCN_PRBRESP_PROMISC) - p54_set_filter(dev, le16_to_cpu(priv->filter_type), - NULL); + p54_setup_mac(dev, priv->mac_mode, NULL); else - p54_set_filter(dev, le16_to_cpu(priv->filter_type), - priv->bssid); + p54_setup_mac(dev, priv->mac_mode, priv->bssid); } if (changed_flags & FIF_PROMISC_IN_BSS) { if (*total_flags & FIF_PROMISC_IN_BSS) - p54_set_filter(dev, le16_to_cpu(priv->filter_type) | - 0x8, NULL); + p54_setup_mac(dev, priv->mac_mode | 0x8, NULL); else - p54_set_filter(dev, le16_to_cpu(priv->filter_type) & - ~0x8, priv->bssid); + p54_setup_mac(dev, priv->mac_mode & ~0x8, priv->bssid); } } diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h index 2cb3885c021..125f70a90da 100644 --- a/drivers/net/wireless/p54/p54common.h +++ b/drivers/net/wireless/p54/p54common.h @@ -219,8 +219,8 @@ struct p54_tx_control_allocdata { u8 align[0]; } __attribute__ ((packed)); -struct p54_tx_control_filter { - __le16 filter_type; +struct p54_setup_mac { + __le16 mac_mode; u8 mac_addr[ETH_ALEN]; u8 bssid[ETH_ALEN]; u8 rx_antenna; @@ -240,15 +240,19 @@ struct p54_tx_control_filter { __le16 max_rx; __le16 rxhw; __le16 timer; - __le16 unalloc0; - __le32 unalloc1; + __le16 truncate; + __le32 basic_rate_mask; + u8 sbss_offset; + u8 mcast_window; + u8 rx_rssi_threshold; + u8 rx_ed_threshold; + __le32 ref_clock; + __le16 lpf_bandwidth; + __le16 osc_start_delay; } v2 __attribute__ ((packed)); } __attribute__ ((packed)); } __attribute__ ((packed)); -#define P54_TX_CONTROL_FILTER_V1_LEN (sizeof(struct p54_tx_control_filter)) -#define P54_TX_CONTROL_FILTER_V2_LEN (sizeof(struct p54_tx_control_filter)-8) - struct p54_tx_control_channel { __le16 flags; __le16 dwell; -- cgit v1.2.3-70-g09d2 From 27df605ebe2c106c53957dfdaee5d948f01cfc97 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Wed, 22 Oct 2008 16:41:55 -0400 Subject: p54: integrate parts of lmac_longbow.h and other parts of stlc45xx This patch removes most/all? of the "magic" numbers and unknown structure variables inside the code and replaces them with meaningful prototypes. (Plus a one line warning fix from Larry Finger .) Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54.h | 29 +++-- drivers/net/wireless/p54/p54common.c | 142 +++++++++++---------- drivers/net/wireless/p54/p54common.h | 240 ++++++++++++++++++++++++++++++++--- drivers/net/wireless/p54/p54pci.c | 2 +- drivers/net/wireless/p54/p54usb.c | 8 +- 5 files changed, 316 insertions(+), 105 deletions(-) (limited to 'drivers/net/wireless/p54/p54common.c') diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index 7a3bf759a40..eb69b904f65 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -14,17 +14,17 @@ * published by the Free Software Foundation. */ -enum control_frame_types { +enum p54_control_frame_types { P54_CONTROL_TYPE_SETUP = 0, - P54_CONTROL_TYPE_CHANNEL_CHANGE, - P54_CONTROL_TYPE_FREQDONE, + P54_CONTROL_TYPE_SCAN, + P54_CONTROL_TYPE_TRAP, P54_CONTROL_TYPE_DCFINIT, - P54_CONTROL_TYPE_ENCRYPTION, + P54_CONTROL_TYPE_RX_KEYCACHE, P54_CONTROL_TYPE_TIM, - P54_CONTROL_TYPE_POWERMGT, - P54_CONTROL_TYPE_FREEQUEUE, + P54_CONTROL_TYPE_PSM, + P54_CONTROL_TYPE_TXCANCEL, P54_CONTROL_TYPE_TXDONE, - P54_CONTROL_TYPE_PING, + P54_CONTROL_TYPE_BURST, P54_CONTROL_TYPE_STAT_READBACK, P54_CONTROL_TYPE_BBP, P54_CONTROL_TYPE_EEPROM_READBACK, @@ -37,15 +37,20 @@ enum control_frame_types { P54_CONTROL_TYPE_XBOW_SYNTH_CFG, P54_CONTROL_TYPE_CCE_QUIET, P54_CONTROL_TYPE_PSM_STA_UNLOCK, + P54_CONTROL_TYPE_PCS, + P54_CONTROL_TYPE_BT_BALANCER = 28, + P54_CONTROL_TYPE_GROUP_ADDRESS_TABLE = 30, + P54_CONTROL_TYPE_ARPTABLE = 31, + P54_CONTROL_TYPE_BT_OPTIONS = 35 }; -struct p54_control_hdr { - __le16 magic1; +struct p54_hdr { + __le16 flags; __le16 len; __le32 req_id; - __le16 type; /* enum control_frame_types */ - u8 retry1; - u8 retry2; + __le16 type; /* enum p54_control_frame_types */ + u8 rts_tries; + u8 tries; u8 data[0]; } __attribute__ ((packed)); diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 525a684c57b..cf04c721a01 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -5,8 +5,11 @@ * Copyright (c) 2007, Christian Lamparter * Copyright 2008, Johannes Berg * - * Based on the islsm (softmac prism54) driver, which is: - * Copyright 2004-2006 Jean-Baptiste Note , et al. + * Based on: + * - the islsm (softmac prism54) driver, which is: + * Copyright 2004-2006 Jean-Baptiste Note , et al. + * - stlc45xx driver + * C Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -481,13 +484,13 @@ static int p54_rssi_to_dbm(struct ieee80211_hw *dev, int rssi) static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54_common *priv = dev->priv; - struct p54_rx_hdr *hdr = (struct p54_rx_hdr *) skb->data; + struct p54_rx_data *hdr = (struct p54_rx_data *) skb->data; struct ieee80211_rx_status rx_status = {0}; u16 freq = le16_to_cpu(hdr->freq); size_t header_len = sizeof(*hdr); u32 tsf32; - if (!(hdr->magic & cpu_to_le16(0x0001))) { + if (!(hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_IN_FCS_GOOD))) { if (priv->filter_flags & FIF_FCSFAIL) rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; else @@ -512,7 +515,7 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) rx_status.flag |= RX_FLAG_TSFT; - if (hdr->magic & cpu_to_le16(0x4000)) + if (hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN)) header_len += hdr->align[0]; skb_pull(skb, header_len); @@ -571,7 +574,7 @@ void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb) spin_unlock_irqrestore(&priv->tx_queue.lock, flags); kfree_skb(skb); - if (freed >= priv->headroom + sizeof(struct p54_control_hdr) + 48 + + if (freed >= priv->headroom + sizeof(struct p54_hdr) + 48 + IEEE80211_MAX_RTS_THRESHOLD + priv->tailroom) p54_wake_free_queues(dev); } @@ -580,8 +583,8 @@ EXPORT_SYMBOL_GPL(p54_free_skb); static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data; - struct p54_frame_sent_hdr *payload = (struct p54_frame_sent_hdr *) hdr->data; + struct p54_hdr *hdr = (struct p54_hdr *) skb->data; + struct p54_frame_sent *payload = (struct p54_frame_sent *) hdr->data; struct sk_buff *entry = (struct sk_buff *) priv->tx_queue.next; u32 addr = le32_to_cpu(hdr->req_id) - priv->headroom; struct memrecord *range = NULL; @@ -593,8 +596,8 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) spin_lock_irqsave(&priv->tx_queue.lock, flags); while (entry != (struct sk_buff *)&priv->tx_queue) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry); - struct p54_control_hdr *entry_hdr; - struct p54_tx_control_allocdata *entry_data; + struct p54_hdr *entry_hdr; + struct p54_tx_data *entry_data; int pad = 0; range = (void *)info->rate_driver_data; @@ -628,13 +631,13 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, status.ampdu_ack_len) != 23); - entry_hdr = (struct p54_control_hdr *) entry->data; - entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data; - if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0) + entry_hdr = (struct p54_hdr *) entry->data; + entry_data = (struct p54_tx_data *) entry_hdr->data; + if (entry_hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN)) pad = entry_data->align[0]; /* walk through the rates array and adjust the counts */ - count = payload->retries; + count = payload->tries; for (idx = 0; idx < 4; idx++) { if (count >= info->status.rates[idx].count) { count -= info->status.rates[idx].count; @@ -654,7 +657,7 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) if (payload->status & 0x02) info->flags |= IEEE80211_TX_STAT_TX_FILTERED; info->status.ack_signal = p54_rssi_to_dbm(dev, - le16_to_cpu(payload->ack_rssi)); + (int)payload->ack_rssi); skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data)); ieee80211_tx_status_irqsafe(dev, entry); goto out; @@ -662,7 +665,7 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) spin_unlock_irqrestore(&priv->tx_queue.lock, flags); out: - if (freed >= priv->headroom + sizeof(struct p54_control_hdr) + 48 + + if (freed >= priv->headroom + sizeof(struct p54_hdr) + 48 + IEEE80211_MAX_RTS_THRESHOLD + priv->tailroom) p54_wake_free_queues(dev); } @@ -670,7 +673,7 @@ out: static void p54_rx_eeprom_readback(struct ieee80211_hw *dev, struct sk_buff *skb) { - struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data; + struct p54_hdr *hdr = (struct p54_hdr *) skb->data; struct p54_eeprom_lm86 *eeprom = (struct p54_eeprom_lm86 *) hdr->data; struct p54_common *priv = dev->priv; @@ -685,7 +688,7 @@ static void p54_rx_eeprom_readback(struct ieee80211_hw *dev, static void p54_rx_stats(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data; + struct p54_hdr *hdr = (struct p54_hdr *) skb->data; struct p54_statistics *stats = (struct p54_statistics *) hdr->data; u32 tsf32 = le32_to_cpu(stats->tsf32); @@ -705,7 +708,7 @@ static void p54_rx_stats(struct ieee80211_hw *dev, struct sk_buff *skb) static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb) { - struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data; + struct p54_hdr *hdr = (struct p54_hdr *) skb->data; switch (le16_to_cpu(hdr->type)) { case P54_CONTROL_TYPE_TXDONE: @@ -750,7 +753,7 @@ EXPORT_SYMBOL_GPL(p54_rx); * allocated areas. */ static int p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, - struct p54_control_hdr *data, u32 len) + struct p54_hdr *data, u32 len) { struct p54_common *priv = dev->priv; struct sk_buff *entry = priv->tx_queue.next; @@ -807,7 +810,7 @@ static int p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, __skb_queue_after(&priv->tx_queue, target_skb, skb); spin_unlock_irqrestore(&priv->tx_queue.lock, flags); - if (largest_hole < priv->headroom + sizeof(struct p54_control_hdr) + + if (largest_hole < priv->headroom + sizeof(struct p54_hdr) + 48 + IEEE80211_MAX_RTS_THRESHOLD + priv->tailroom) ieee80211_stop_queues(dev); @@ -819,7 +822,7 @@ static struct sk_buff *p54_alloc_skb(struct ieee80211_hw *dev, u16 hdr_flags, u16 len, u16 type, gfp_t memflags) { struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr; + struct p54_hdr *hdr; struct sk_buff *skb; skb = __dev_alloc_skb(len + priv->tx_hdr_len, memflags); @@ -827,11 +830,11 @@ static struct sk_buff *p54_alloc_skb(struct ieee80211_hw *dev, return NULL; skb_reserve(skb, priv->tx_hdr_len); - hdr = (struct p54_control_hdr *) skb_put(skb, sizeof(*hdr)); - hdr->magic1 = cpu_to_le16(hdr_flags); + hdr = (struct p54_hdr *) skb_put(skb, sizeof(*hdr)); + hdr->flags = cpu_to_le16(hdr_flags); hdr->len = cpu_to_le16(len - sizeof(*hdr)); hdr->type = cpu_to_le16(type); - hdr->retry1 = hdr->retry2 = 0; + hdr->tries = hdr->rts_tries = 0; if (unlikely(p54_assign_address(dev, skb, hdr, len))) { kfree_skb(skb); @@ -843,7 +846,7 @@ static struct sk_buff *p54_alloc_skb(struct ieee80211_hw *dev, int p54_read_eeprom(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr = NULL; + struct p54_hdr *hdr = NULL; struct p54_eeprom_lm86 *eeprom_hdr; struct sk_buff *skb; size_t eeprom_size = 0x2020, offset = 0, blocksize; @@ -899,8 +902,8 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_queue_stats *current_queue; struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr; - struct p54_tx_control_allocdata *txhdr; + struct p54_hdr *hdr; + struct p54_tx_data *txhdr; size_t padding, len; int i, j, ridx; u8 rate; @@ -920,17 +923,16 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3; len = skb->len; - txhdr = (struct p54_tx_control_allocdata *) - skb_push(skb, sizeof(*txhdr) + padding); - hdr = (struct p54_control_hdr *) skb_push(skb, sizeof(*hdr)); + txhdr = (struct p54_tx_data *) skb_push(skb, sizeof(*txhdr) + padding); + hdr = (struct p54_hdr *) skb_push(skb, sizeof(*hdr)); if (padding) - hdr->magic1 = cpu_to_le16(0x4010); + hdr->flags = cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN); else - hdr->magic1 = cpu_to_le16(0x0010); + hdr->flags = cpu_to_le16(0); hdr->len = cpu_to_le16(len); hdr->type = (info->flags & IEEE80211_TX_CTL_NO_ACK) ? 0 : cpu_to_le16(1); - hdr->retry1 = info->control.rates[0].count; + hdr->rts_tries = info->control.rates[0].count; /* * we register the rates in perfect order, and @@ -996,16 +998,18 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) ridx++; } } - hdr->retry2 = ridx; - + hdr->tries = ridx; + txhdr->crypt_offset = 0; + txhdr->rts_rate_idx = 0; txhdr->key_type = 0; txhdr->key_len = 0; txhdr->hw_queue = skb_get_queue_mapping(skb) + 4; + txhdr->backlog = 32; + memset(txhdr->durations, 0, sizeof(txhdr->durations)); txhdr->tx_antenna = (info->antenna_sel_tx == 0) ? 2 : info->antenna_sel_tx - 1; txhdr->output_power = priv->output_power; - txhdr->cts_rate = (info->flags & IEEE80211_TX_CTL_NO_ACK) ? - 0 : cts_rate; + txhdr->cts_rate = cts_rate; if (padding) txhdr->align[0] = padding; @@ -1024,8 +1028,8 @@ static int p54_setup_mac(struct ieee80211_hw *dev, u16 mode, const u8 *bssid) struct sk_buff *skb; struct p54_setup_mac *setup; - skb = p54_alloc_skb(dev, 0x8001, sizeof(struct p54_control_hdr) + - sizeof(*setup), P54_CONTROL_TYPE_SETUP, + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*setup) + + sizeof(struct p54_hdr), P54_CONTROL_TYPE_SETUP, GFP_ATOMIC); if (!skb) return -ENOMEM; @@ -1069,19 +1073,19 @@ static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq) { struct p54_common *priv = dev->priv; struct sk_buff *skb; - struct p54_tx_control_channel *chan; + struct p54_scan *chan; unsigned int i; - size_t data_len = sizeof(struct p54_control_hdr) + sizeof(*chan); void *entry; - skb = p54_alloc_skb(dev, 0x8001, data_len, - P54_CONTROL_TYPE_CHANNEL_CHANGE, GFP_ATOMIC); + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*chan) + + sizeof(struct p54_hdr), P54_CONTROL_TYPE_SCAN, + GFP_ATOMIC); if (!skb) return -ENOMEM; - chan = (struct p54_tx_control_channel *) skb_put(skb, sizeof(*chan)); + chan = (struct p54_scan *) skb_put(skb, sizeof(*chan)); memset(chan->padding1, 0, sizeof(chan->padding1)); - chan->flags = cpu_to_le16(0x1); + chan->mode = cpu_to_le16(P54_SCAN_EXIT); chan->dwell = cpu_to_le16(0x0); for (i = 0; i < priv->iq_autocal_len; i++) { @@ -1132,13 +1136,13 @@ static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq) } if (priv->fw_var < 0x500) { - data_len = P54_TX_CONTROL_CHANNEL_V1_LEN; chan->v1.rssical_mul = cpu_to_le16(130); chan->v1.rssical_add = cpu_to_le16(0xfe70); } else { chan->v2.rssical_mul = cpu_to_le16(130); chan->v2.rssical_add = cpu_to_le16(0xfe70); chan->v2.basic_rate_mask = cpu_to_le32(0x15f); + memset(chan->v2.rts_rates, 0, 8); } priv->tx(dev, skb, 1); return 0; @@ -1153,15 +1157,15 @@ static int p54_set_leds(struct ieee80211_hw *dev, int mode, int link, int act) { struct p54_common *priv = dev->priv; struct sk_buff *skb; - struct p54_tx_control_led *led; + struct p54_led *led; - skb = p54_alloc_skb(dev, 0x8001, sizeof(*led) + - sizeof(struct p54_control_hdr), - P54_CONTROL_TYPE_LED, GFP_ATOMIC); + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*led) + + sizeof(struct p54_hdr), P54_CONTROL_TYPE_LED, + GFP_ATOMIC); if (!skb) return -ENOMEM; - led = (struct p54_tx_control_led *)skb_put(skb, sizeof(*led)); + led = (struct p54_led *)skb_put(skb, sizeof(*led)); led->mode = cpu_to_le16(mode); led->led_permanent = cpu_to_le16(link); led->led_temporary = cpu_to_le16(act); @@ -1184,8 +1188,9 @@ static int p54_set_edcf(struct ieee80211_hw *dev) struct sk_buff *skb; struct p54_edcf *edcf; - skb = p54_alloc_skb(dev, 0x8001, sizeof(struct p54_control_hdr) + - sizeof(*edcf), P54_CONTROL_TYPE_DCFINIT, GFP_ATOMIC); + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*edcf) + + sizeof(struct p54_hdr), P54_CONTROL_TYPE_DCFINIT, + GFP_ATOMIC); if (!skb) return -ENOMEM; @@ -1212,11 +1217,9 @@ static int p54_init_stats(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; - priv->cached_stats = p54_alloc_skb(dev, 0x8000, - sizeof(struct p54_control_hdr) + - sizeof(struct p54_statistics), - P54_CONTROL_TYPE_STAT_READBACK, - GFP_KERNEL); + priv->cached_stats = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL, + sizeof(struct p54_hdr) + sizeof(struct p54_statistics), + P54_CONTROL_TYPE_STAT_READBACK, GFP_KERNEL); if (!priv->cached_stats) return -ENOMEM; @@ -1277,11 +1280,11 @@ static int p54_add_interface(struct ieee80211_hw *dev, memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); - p54_setup_mac(dev, 0, NULL); + p54_setup_mac(dev, P54_FILTER_TYPE_NONE, NULL); switch (conf->type) { case NL80211_IFTYPE_STATION: - p54_setup_mac(dev, 1, NULL); + p54_setup_mac(dev, P54_FILTER_TYPE_STATION, NULL); break; default: BUG(); /* impossible */ @@ -1299,7 +1302,7 @@ static void p54_remove_interface(struct ieee80211_hw *dev, struct p54_common *priv = dev->priv; priv->mode = NL80211_IFTYPE_MONITOR; memset(priv->mac_addr, 0, ETH_ALEN); - p54_setup_mac(dev, 0, NULL); + p54_setup_mac(dev, P54_FILTER_TYPE_NONE, NULL); } static int p54_config(struct ieee80211_hw *dev, u32 changed) @@ -1325,7 +1328,7 @@ static int p54_config_interface(struct ieee80211_hw *dev, struct p54_common *priv = dev->priv; mutex_lock(&priv->conf_mutex); - p54_setup_mac(dev, 0, conf->bssid); + p54_setup_mac(dev, P54_FILTER_TYPE_STATION, conf->bssid); p54_set_leds(dev, 1, !is_multicast_ether_addr(conf->bssid), 0); memcpy(priv->bssid, conf->bssid, ETH_ALEN); mutex_unlock(&priv->conf_mutex); @@ -1378,15 +1381,16 @@ static int p54_init_xbow_synth(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; struct sk_buff *skb; - struct p54_tx_control_xbow_synth *xbow; + struct p54_xbow_synth *xbow; - skb = p54_alloc_skb(dev, 0x8001, sizeof(struct p54_control_hdr) + - sizeof(*xbow), P54_CONTROL_TYPE_XBOW_SYNTH_CFG, + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*xbow) + + sizeof(struct p54_hdr), + P54_CONTROL_TYPE_XBOW_SYNTH_CFG, GFP_KERNEL); if (!skb) return -ENOMEM; - xbow = (struct p54_tx_control_xbow_synth *)skb_put(skb, sizeof(*xbow)); + xbow = (struct p54_xbow_synth *)skb_put(skb, sizeof(*xbow)); xbow->magic1 = cpu_to_le16(0x1); xbow->magic2 = cpu_to_le16(0x2); xbow->freq = cpu_to_le16(5390); @@ -1504,8 +1508,8 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) */ dev->max_rates = 4; dev->max_rate_tries = 7; - dev->extra_tx_headroom = sizeof(struct p54_control_hdr) + 4 + - sizeof(struct p54_tx_control_allocdata); + dev->extra_tx_headroom = sizeof(struct p54_hdr) + 4 + + sizeof(struct p54_tx_data); mutex_init(&priv->conf_mutex); init_completion(&priv->eeprom_comp); diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h index 125f70a90da..b1101feace6 100644 --- a/drivers/net/wireless/p54/p54common.h +++ b/drivers/net/wireless/p54/p54common.h @@ -33,6 +33,13 @@ struct bootrec_exp_if { __le16 top_compat; } __attribute__((packed)); +#define BR_DESC_PRIV_CAP_WEP BIT(0) +#define BR_DESC_PRIV_CAP_TKIP BIT(1) +#define BR_DESC_PRIV_CAP_MICHAEL BIT(2) +#define BR_DESC_PRIV_CAP_CCX_CP BIT(3) +#define BR_DESC_PRIV_CAP_CCX_MIC BIT(4) +#define BR_DESC_PRIV_CAP_AESCCMP BIT(5) + struct bootrec_desc { __le16 modes; __le16 flags; @@ -40,7 +47,12 @@ struct bootrec_desc { __le32 rx_end; u8 headroom; u8 tailroom; - u8 unimportant[6]; + u8 tx_queues; + u8 tx_depth; + u8 privacy_caps; + u8 rx_keycache_size; + u8 time_size; + u8 padding; u8 rates[16]; u8 padding2[4]; __le16 rx_mtu; @@ -56,6 +68,34 @@ struct bootrec_desc { #define BR_CODE_END_OF_BRA 0xFF0000FF #define LEGACY_BR_CODE_END_OF_BRA 0xFFFFFFFF +#define P54_HDR_FLAG_CONTROL BIT(15) +#define P54_HDR_FLAG_CONTROL_OPSET (BIT(15) + BIT(0)) + +#define P54_HDR_FLAG_DATA_ALIGN BIT(14) +#define P54_HDR_FLAG_DATA_OUT_PROMISC BIT(0) +#define P54_HDR_FLAG_DATA_OUT_TIMESTAMP BIT(1) +#define P54_HDR_FLAG_DATA_OUT_SEQNR BIT(2) +#define P54_HDR_FLAG_DATA_OUT_BIT3 BIT(3) +#define P54_HDR_FLAG_DATA_OUT_BURST BIT(4) +#define P54_HDR_FLAG_DATA_OUT_NOCANCEL BIT(5) +#define P54_HDR_FLAG_DATA_OUT_CLEARTIM BIT(6) +#define P54_HDR_FLAG_DATA_OUT_HITCHHIKE BIT(7) +#define P54_HDR_FLAG_DATA_OUT_COMPRESS BIT(8) +#define P54_HDR_FLAG_DATA_OUT_CONCAT BIT(9) +#define P54_HDR_FLAG_DATA_OUT_PCS_ACCEPT BIT(10) +#define P54_HDR_FLAG_DATA_OUT_WAITEOSP BIT(11) + +#define P54_HDR_FLAG_DATA_IN_FCS_GOOD BIT(0) +#define P54_HDR_FLAG_DATA_IN_MATCH_MAC BIT(1) +#define P54_HDR_FLAG_DATA_IN_MCBC BIT(2) +#define P54_HDR_FLAG_DATA_IN_BEACON BIT(3) +#define P54_HDR_FLAG_DATA_IN_MATCH_BSS BIT(4) +#define P54_HDR_FLAG_DATA_IN_BCAST_BSS BIT(5) +#define P54_HDR_FLAG_DATA_IN_DATA BIT(6) +#define P54_HDR_FLAG_DATA_IN_TRUNCATED BIT(7) +#define P54_HDR_FLAG_DATA_IN_BIT8 BIT(8) +#define P54_HDR_FLAG_DATA_IN_TRANSPARENT BIT(9) + /* PDA defines are Copyright (C) 2005 Nokia Corporation (taken from islsm_pda.h) */ struct pda_entry { @@ -182,36 +222,91 @@ struct p54_eeprom_lm86 { u8 data[0]; } __attribute__ ((packed)); -struct p54_rx_hdr { - __le16 magic; +enum p54_rx_decrypt_status { + P54_DECRYPT_NONE = 0, + P54_DECRYPT_OK, + P54_DECRYPT_NOKEY, + P54_DECRYPT_NOMICHAEL, + P54_DECRYPT_NOCKIPMIC, + P54_DECRYPT_FAIL_WEP, + P54_DECRYPT_FAIL_TKIP, + P54_DECRYPT_FAIL_MICAHEL, + P54_DECRYPT_FAIL_CKIPKP, + P54_DECRYPT_FAIL_CKIPMIC, + P54_DECRYPT_FAIL_AESCCMP +}; + +struct p54_rx_data { + __le16 flags; __le16 len; __le16 freq; u8 antenna; u8 rate; u8 rssi; u8 quality; - u16 unknown2; + u8 decrypt_status; + u8 rssi_raw; __le32 tsf32; __le32 unalloc0; u8 align[0]; } __attribute__ ((packed)); -struct p54_frame_sent_hdr { +enum p54_trap_type { + P54_TRAP_SCAN = 0, + P54_TRAP_TIMER, + P54_TRAP_BEACON_TX, + P54_TRAP_FAA_RADIO_ON, + P54_TRAP_FAA_RADIO_OFF, + P54_TRAP_RADAR, + P54_TRAP_NO_BEACON, + P54_TRAP_TBTT, + P54_TRAP_SCO_ENTER, + P54_TRAP_SCO_EXIT +}; + +struct p54_trap { + __le16 event; + __le16 frequency; +} __attribute__ ((packed)); + +enum p54_frame_sent_status { + P54_TX_OK = 0, + P54_TX_FAILED, + P54_TX_PSM, + P54_TX_PSM_CANCELLED +}; + +struct p54_frame_sent { u8 status; - u8 retries; - __le16 ack_rssi; + u8 tries; + u8 ack_rssi; + u8 quality; __le16 seq; - u16 rate; + u8 antenna; + u8 padding; } __attribute__ ((packed)); -struct p54_tx_control_allocdata { +enum p54_tx_data_crypt { + P54_CRYPTO_NONE = 0, + P54_CRYPTO_WEP, + P54_CRYPTO_TKIP, + P54_CRYPTO_TKIPMICHAEL, + P54_CRYPTO_CCX_WEPMIC, + P54_CRYPTO_CCX_KPMIC, + P54_CRYPTO_CCX_KP, + P54_CRYPTO_AESCCMP +}; + +struct p54_tx_data { u8 rateset[8]; - u8 unalloc0[2]; + u8 rts_rate_idx; + u8 crypt_offset; u8 key_type; u8 key_len; u8 key[16]; u8 hw_queue; - u8 unalloc1[9]; + u8 backlog; + __le16 durations[4]; u8 tx_antenna; u8 output_power; u8 cts_rate; @@ -219,6 +314,16 @@ struct p54_tx_control_allocdata { u8 align[0]; } __attribute__ ((packed)); +#define P54_FILTER_TYPE_NONE 0 +#define P54_FILTER_TYPE_STATION BIT(0) +#define P54_FILTER_TYPE_IBSS BIT(1) +#define P54_FILTER_TYPE_AP BIT(2) +#define P54_FILTER_TYPE_TRANSPARENT BIT(3) +#define P54_FILTER_TYPE_PROMISCUOUS BIT(4) +#define P54_FILTER_TYPE_HIBERNATE BIT(5) +#define P54_FILTER_TYPE_NOACK BIT(6) +#define P54_FILTER_TYPE_RX_DISABLED BIT(7) + struct p54_setup_mac { __le16 mac_mode; u8 mac_addr[ETH_ALEN]; @@ -253,8 +358,16 @@ struct p54_setup_mac { } __attribute__ ((packed)); } __attribute__ ((packed)); -struct p54_tx_control_channel { - __le16 flags; +#define P54_SETUP_V1_LEN 40 +#define P54_SETUP_V2_LEN (sizeof(struct p54_setup_mac)) + +#define P54_SCAN_EXIT BIT(0) +#define P54_SCAN_TRAP BIT(1) +#define P54_SCAN_ACTIVE BIT(2) +#define P54_SCAN_FILTER BIT(3) + +struct p54_scan { + __le16 mode; __le16 dwell; u8 padding1[20]; struct pda_iq_autocal_entry iq_autocal; @@ -277,17 +390,17 @@ struct p54_tx_control_channel { struct { __le32 basic_rate_mask; - u8 rts_rates[8]; + u8 rts_rates[8]; __le16 rssical_mul; __le16 rssical_add; } v2 __attribute__ ((packed)); } __attribute__ ((packed)); } __attribute__ ((packed)); -#define P54_TX_CONTROL_CHANNEL_V1_LEN (sizeof(struct p54_tx_control_channel)-12) -#define P54_TX_CONTROL_CHANNEL_V2_LEN (sizeof(struct p54_tx_control_channel)) +#define P54_SCAN_V1_LEN (sizeof(struct p54_scan)-12) +#define P54_SCAN_V2_LEN (sizeof(struct p54_scan)) -struct p54_tx_control_led { +struct p54_led { __le16 mode; __le16 led_temporary; __le16 led_permanent; @@ -315,14 +428,103 @@ struct p54_statistics { __le32 tsf32; __le32 airtime; __le32 noise; - __le32 unkn[10]; /* CCE / CCA / RADAR */ + __le32 sample_noise[8]; + __le32 sample_cca; + __le32 sample_tx; } __attribute__ ((packed)); -struct p54_tx_control_xbow_synth { +struct p54_xbow_synth { __le16 magic1; __le16 magic2; __le16 freq; u32 padding[5]; } __attribute__ ((packed)); +struct p54_timer { + __le32 interval; +} __attribute__ ((packed)); + +struct p54_keycache { + u8 entry; + u8 key_id; + u8 mac[ETH_ALEN]; + u8 padding[2]; + u8 key_type; + u8 key_len; + u8 key[24]; +} __attribute__ ((packed)); + +struct p54_burst { + u8 flags; + u8 queue; + u8 backlog; + u8 pad; + __le16 durations[32]; +} __attribute__ ((packed)); + +struct p54_psm_interval { + __le16 interval; + __le16 periods; +} __attribute__ ((packed)); + +#define P54_PSM BIT(0) +#define P54_PSM_DTIM BIT(1) +#define P54_PSM_MCBC BIT(2) +#define P54_PSM_CHECKSUM BIT(3) +#define P54_PSM_SKIP_MORE_DATA BIT(4) +#define P54_PSM_BEACON_TIMEOUT BIT(5) +#define P54_PSM_HFOSLEEP BIT(6) +#define P54_PSM_AUTOSWITCH_SLEEP BIT(7) +#define P54_PSM_LPIT BIT(8) +#define P54_PSM_BF_UCAST_SKIP BIT(9) +#define P54_PSM_BF_MCAST_SKIP BIT(10) + +struct p54_psm { + __le16 mode; + __le16 aid; + struct p54_psm_interval intervals[4]; + u8 beacon_rssi_skip_max; + u8 rssi_delta_threshold; + u8 nr; + u8 exclude[1]; +} __attribute__ ((packed)); + +#define MC_FILTER_ADDRESS_NUM 4 + +struct p54_group_address_table { + __le16 filter_enable; + __le16 num_address; + u8 mac_list[MC_FILTER_ADDRESS_NUM][ETH_ALEN]; +} __attribute__ ((packed)); + +struct p54_txcancel { + __le32 req_id; +} __attribute__ ((packed)); + +struct p54_sta_unlock { + u8 addr[ETH_ALEN]; + u16 padding; +} __attribute__ ((packed)); + +#define P54_TIM_CLEAR BIT(15) +struct p54_tx_control_tim { + u8 count; + u8 padding[3]; + __le16 entry[8]; +} __attribute__ ((packed)); + +struct p54_cce_quiet { + __le32 period; +} __attribute__ ((packed)); + +struct p54_bt_balancer { + __le16 prio_thresh; + __le16 acl_thresh; +} __attribute__ ((packed)); + +struct p54_arp_table { + __le16 filter_enable; + u8 ipv4_addr[4]; +} __attribute__ ((packed)); + #endif /* P54COMMON_H */ diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index 1bb9584f035..3c9d030ccb8 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -326,7 +326,7 @@ static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb, PCI_DMA_TODEVICE); desc = &ring_control->tx_data[i]; desc->host_addr = cpu_to_le32(mapping); - desc->device_addr = ((struct p54_control_hdr *)skb->data)->req_id; + desc->device_addr = ((struct p54_hdr *)skb->data)->req_id; desc->len = cpu_to_le16(skb->len); desc->flags = 0; diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index 88fb65046c7..49739c36a44 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -230,7 +230,7 @@ static void p54u_tx_3887(struct ieee80211_hw *dev, struct sk_buff *skb, usb_fill_bulk_urb(addr_urb, priv->udev, usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), - &((struct p54_control_hdr *)skb->data)->req_id, 4, + &((struct p54_hdr *)skb->data)->req_id, 4, p54u_tx_cb, dev); usb_fill_bulk_urb(data_urb, priv->udev, usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), @@ -262,7 +262,7 @@ static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb, struct urb *data_urb; struct lm87_tx_hdr *hdr; __le32 checksum; - __le32 addr = ((struct p54_control_hdr *)skb->data)->req_id; + __le32 addr = ((struct p54_hdr *)skb->data)->req_id; data_urb = usb_alloc_urb(0, GFP_ATOMIC); if (!data_urb) @@ -313,8 +313,8 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb, hdr = (void *)skb_push(skb, sizeof(*hdr)); memset(hdr, 0, sizeof(*hdr)); - hdr->device_addr = ((struct p54_control_hdr *)skb->data)->req_id; - hdr->len = cpu_to_le16(skb->len + sizeof(struct p54_control_hdr)); + hdr->device_addr = ((struct p54_hdr *)skb->data)->req_id; + hdr->len = cpu_to_le16(skb->len + sizeof(struct p54_hdr)); usb_fill_bulk_urb(int_urb, priv->udev, usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg), -- cgit v1.2.3-70-g09d2 From 9a8675d712d57da0993ad2e43b168c9585892097 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 18 Oct 2008 23:04:15 +0200 Subject: p54: introduce new names for device firmwares Johannes thought it would have been a good idea to change the firmware names. Note: we still have fallbacks in case our users don't want to "break their running system", but we won't advertise them with MODULE_FIRMWARE. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 5 +++++ drivers/net/wireless/p54/p54pci.c | 9 ++++++--- drivers/net/wireless/p54/p54usb.c | 23 ++++++++++++++++------- 3 files changed, 27 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless/p54/p54common.c') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index cf04c721a01..8e5e1abfe88 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -214,6 +214,11 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) printk(KERN_INFO "p54: FW rev %s - Softmac protocol %x.%x\n", fw_version, priv->fw_var >> 8, priv->fw_var & 0xff); + if (priv->fw_var < 0x500) + printk(KERN_INFO "p54: you are using an obsolete firmware. " + "visit http://wireless.kernel.org/en/users/Drivers/p54 " + "and grab one for \"kernel >= 2.6.28\"!\n"); + if (priv->fw_var >= 0x300) { /* Firmware supports QoS, use it! */ priv->tx_stats[4].limit = 3; diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index 3c9d030ccb8..c4a868ae6d6 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -28,6 +28,7 @@ MODULE_AUTHOR("Michael Wu "); MODULE_DESCRIPTION("Prism54 PCI wireless driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("prism54pci"); +MODULE_FIRMWARE("isl3886pci"); static struct pci_device_id p54p_table[] __devinitdata = { /* Intersil PRISM Duette/Prism GT Wireless LAN adapter */ @@ -72,11 +73,13 @@ static int p54p_upload_firmware(struct ieee80211_hw *dev) P54P_WRITE(ctrl_stat, reg); wmb(); - err = request_firmware(&fw_entry, "isl3886", &priv->pdev->dev); + err = request_firmware(&fw_entry, "isl3886pci", &priv->pdev->dev); if (err) { printk(KERN_ERR "%s (p54pci): cannot find firmware " - "(isl3886)\n", pci_name(priv->pdev)); - return err; + "(isl3886pci)\n", pci_name(priv->pdev)); + err = request_firmware(&fw_entry, "isl3886", &priv->pdev->dev); + if (err) + return err; } err = p54_parse_firmware(dev, fw_entry); diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index 49739c36a44..21ba526a45b 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -28,6 +28,8 @@ MODULE_AUTHOR("Michael Wu "); MODULE_DESCRIPTION("Prism54 USB wireless driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("prism54usb"); +MODULE_FIRMWARE("isl3886usb"); +MODULE_FIRMWARE("isl3887usb"); static struct usb_device_id p54u_table[] __devinitdata = { /* Version 1 devices (pci chip + net2280) */ @@ -415,10 +417,13 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) goto err_reset; } - err = request_firmware(&fw_entry, "isl3887usb_bare", &priv->udev->dev); + err = request_firmware(&fw_entry, "isl3887usb", &priv->udev->dev); if (err) { - printk(KERN_ERR "p54usb: cannot find firmware (isl3887usb_bare)!\n"); - goto err_req_fw_failed; + printk(KERN_ERR "p54usb: cannot find firmware (isl3887usb)\n"); + err = request_firmware(&fw_entry, "isl3887usb_bare", + &priv->udev->dev); + if (err) + goto err_req_fw_failed; } err = p54_parse_firmware(dev, fw_entry); @@ -553,11 +558,15 @@ static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev) return -ENOMEM; } - err = request_firmware(&fw_entry, "isl3890usb", &priv->udev->dev); + err = request_firmware(&fw_entry, "isl3886usb", &priv->udev->dev); if (err) { - printk(KERN_ERR "p54usb: cannot find firmware (isl3890usb)!\n"); - kfree(buf); - return err; + printk(KERN_ERR "p54usb: cannot find firmware (isl3886usb)\n"); + err = request_firmware(&fw_entry, "isl3890usb", + &priv->udev->dev); + if (err) { + kfree(buf); + return err; + } } err = p54_parse_firmware(dev, fw_entry); -- cgit v1.2.3-70-g09d2 From 9e7f3f8e4acdc480584d6b5e6a6be5d1f7bda8fa Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 18 Oct 2008 23:18:01 +0200 Subject: p54: more definitions form lmac_longbow.h and pda.h This patch ports more useful features to p54 - PDR definitions for the synth chips & regulatory domain. - honour IEEE80211_TX_CTL_ASSIGN_SEQ flag, if it's set. - adds some lost mutex_lock & mutex_unlock. - replace two more "magic values" that sneaked past. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 83 ++++++++++++++++++++++-------------- drivers/net/wireless/p54/p54common.h | 31 +++++++++++++- 2 files changed, 82 insertions(+), 32 deletions(-) (limited to 'drivers/net/wireless/p54/p54common.c') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 8e5e1abfe88..ae8d1f66631 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -221,10 +221,10 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) if (priv->fw_var >= 0x300) { /* Firmware supports QoS, use it! */ - priv->tx_stats[4].limit = 3; - priv->tx_stats[5].limit = 4; - priv->tx_stats[6].limit = 3; - priv->tx_stats[7].limit = 1; + priv->tx_stats[4].limit = 3; /* AC_VO */ + priv->tx_stats[5].limit = 4; /* AC_VI */ + priv->tx_stats[6].limit = 3; /* AC_BE */ + priv->tx_stats[7].limit = 2; /* AC_BK */ dev->queues = 4; } @@ -436,12 +436,12 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) goto err; } - priv->rxhw = synth & 0x07; + priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK; if (priv->rxhw == 4) p54_init_xbow_synth(dev); - if (!(synth & 0x40)) + if (!(synth & PDR_SYNTH_24_GHZ_DISABLED)) dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz; - if (!(synth & 0x80)) + if (!(synth & PDR_SYNTH_5_GHZ_DISABLED)) dev->wiphy->bands[IEEE80211_BAND_5GHZ] = &band_5GHz; if (!is_valid_ether_addr(dev->wiphy->perm_addr)) { @@ -659,7 +659,7 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && (!payload->status)) info->flags |= IEEE80211_TX_STAT_ACK; - if (payload->status & 0x02) + if (payload->status & P54_TX_PSM_CANCELLED) info->flags |= IEEE80211_TX_STAT_TX_FILTERED; info->status.ack_signal = p54_rssi_to_dbm(dev, (int)payload->ack_rssi); @@ -739,9 +739,9 @@ static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb) /* returns zero if skb can be reused */ int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb) { - u8 type = le16_to_cpu(*((__le16 *)skb->data)) >> 8; + u16 type = le16_to_cpu(*((__le16 *)skb->data)); - if (type == 0x80) + if (type & P54_HDR_FLAG_CONTROL) return p54_rx_control(dev, skb); else return p54_rx_data(dev, skb); @@ -905,12 +905,13 @@ EXPORT_SYMBOL_GPL(p54_read_eeprom); static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_tx_queue_stats *current_queue; + struct ieee80211_tx_queue_stats *current_queue = NULL; struct p54_common *priv = dev->priv; struct p54_hdr *hdr; struct p54_tx_data *txhdr; size_t padding, len; int i, j, ridx; + u16 hdr_flags = 0; u8 rate; u8 cts_rate = 0x20; u8 rc_flags; @@ -932,9 +933,7 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) hdr = (struct p54_hdr *) skb_push(skb, sizeof(*hdr)); if (padding) - hdr->flags = cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN); - else - hdr->flags = cpu_to_le16(0); + hdr_flags |= P54_HDR_FLAG_DATA_ALIGN; hdr->len = cpu_to_le16(len); hdr->type = (info->flags & IEEE80211_TX_CTL_NO_ACK) ? 0 : cpu_to_le16(1); hdr->rts_tries = info->control.rates[0].count; @@ -1003,6 +1002,12 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) ridx++; } } + + if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) + hdr_flags |= P54_HDR_FLAG_DATA_OUT_SEQNR; + + /* TODO: enable bursting */ + hdr->flags = cpu_to_le16(hdr_flags); hdr->tries = ridx; txhdr->crypt_offset = 0; txhdr->rts_rate_idx = 0; @@ -1021,6 +1026,10 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) /* modifies skb->cb and with it info, so must be last! */ if (unlikely(p54_assign_address(dev, skb, hdr, skb->len))) { skb_pull(skb, sizeof(*hdr) + sizeof(*txhdr) + padding); + if (current_queue) { + current_queue->len--; + current_queue->count--; + } return NETDEV_TX_BUSY; } priv->tx(dev, skb, 0); @@ -1074,13 +1083,14 @@ static int p54_setup_mac(struct ieee80211_hw *dev, u16 mode, const u8 *bssid) return 0; } -static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq) +static int p54_set_freq(struct ieee80211_hw *dev, u16 frequency) { struct p54_common *priv = dev->priv; struct sk_buff *skb; struct p54_scan *chan; unsigned int i; void *entry; + __le16 freq = cpu_to_le16(frequency); skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*chan) + sizeof(struct p54_hdr), P54_CONTROL_TYPE_SCAN, @@ -1237,6 +1247,7 @@ static int p54_start(struct ieee80211_hw *dev) struct p54_common *priv = dev->priv; int err; + mutex_lock(&priv->conf_mutex); err = priv->open(dev); if (!err) priv->mode = NL80211_IFTYPE_MONITOR; @@ -1248,6 +1259,7 @@ static int p54_start(struct ieee80211_hw *dev) if (!err) err = p54_init_stats(dev); + mutex_unlock(&priv->conf_mutex); return err; } @@ -1256,6 +1268,7 @@ static void p54_stop(struct ieee80211_hw *dev) struct p54_common *priv = dev->priv; struct sk_buff *skb; + mutex_lock(&priv->conf_mutex); del_timer(&priv->stats_timer); p54_free_skb(dev, priv->cached_stats); priv->cached_stats = NULL; @@ -1265,6 +1278,7 @@ static void p54_stop(struct ieee80211_hw *dev) priv->stop(dev); priv->tsf_high32 = priv->tsf_low32 = 0; priv->mode = NL80211_IFTYPE_UNSPECIFIED; + mutex_unlock(&priv->conf_mutex); } static int p54_add_interface(struct ieee80211_hw *dev, @@ -1272,14 +1286,18 @@ static int p54_add_interface(struct ieee80211_hw *dev, { struct p54_common *priv = dev->priv; - if (priv->mode != NL80211_IFTYPE_MONITOR) + mutex_lock(&priv->conf_mutex); + if (priv->mode != NL80211_IFTYPE_MONITOR) { + mutex_unlock(&priv->conf_mutex); return -EOPNOTSUPP; + } switch (conf->type) { case NL80211_IFTYPE_STATION: priv->mode = conf->type; break; default: + mutex_unlock(&priv->conf_mutex); return -EOPNOTSUPP; } @@ -1298,6 +1316,7 @@ static int p54_add_interface(struct ieee80211_hw *dev, p54_set_leds(dev, 1, 0, 0); + mutex_unlock(&priv->conf_mutex); return 0; } @@ -1305,9 +1324,12 @@ static void p54_remove_interface(struct ieee80211_hw *dev, struct ieee80211_if_init_conf *conf) { struct p54_common *priv = dev->priv; + + mutex_lock(&priv->conf_mutex); + p54_setup_mac(dev, P54_FILTER_TYPE_NONE, NULL); priv->mode = NL80211_IFTYPE_MONITOR; memset(priv->mac_addr, 0, ETH_ALEN); - p54_setup_mac(dev, P54_FILTER_TYPE_NONE, NULL); + mutex_unlock(&priv->conf_mutex); } static int p54_config(struct ieee80211_hw *dev, u32 changed) @@ -1319,7 +1341,7 @@ static int p54_config(struct ieee80211_hw *dev, u32 changed) mutex_lock(&priv->conf_mutex); priv->rx_antenna = 2; /* automatic */ priv->output_power = conf->power_level << 2; - ret = p54_set_freq(dev, cpu_to_le16(conf->channel->center_freq)); + ret = p54_set_freq(dev, conf->channel->center_freq); if (!ret) ret = p54_set_edcf(dev); mutex_unlock(&priv->conf_mutex); @@ -1372,14 +1394,18 @@ static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue, const struct ieee80211_tx_queue_params *params) { struct p54_common *priv = dev->priv; + int ret; + mutex_lock(&priv->conf_mutex); if ((params) && !(queue > 4)) { P54_SET_QUEUE(priv->qos_params[queue], params->aifs, params->cw_min, params->cw_max, params->txop); } else - return -EINVAL; - - return p54_set_edcf(dev); + ret = -EINVAL; + if (!ret) + ret = p54_set_edcf(dev); + mutex_unlock(&priv->conf_mutex); + return ret; } static int p54_init_xbow_synth(struct ieee80211_hw *dev) @@ -1488,19 +1514,14 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; - /* - * XXX: when this driver gets support for any mode that - * requires beacons (AP, MESH, IBSS) then it must - * implement IEEE80211_TX_CTL_ASSIGN_SEQ. - */ dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); dev->channel_change_time = 1000; /* TODO: find actual value */ - priv->tx_stats[0].limit = 1; - priv->tx_stats[1].limit = 1; - priv->tx_stats[2].limit = 1; - priv->tx_stats[3].limit = 1; - priv->tx_stats[4].limit = 5; + priv->tx_stats[0].limit = 1; /* Beacon queue */ + priv->tx_stats[1].limit = 1; /* Probe queue for HW scan */ + priv->tx_stats[2].limit = 3; /* queue for MLMEs */ + priv->tx_stats[3].limit = 3; /* Broadcast / MC queue */ + priv->tx_stats[4].limit = 5; /* Data */ dev->queues = 1; priv->noise = -94; /* diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h index b1101feace6..8c8793cb2d7 100644 --- a/drivers/net/wireless/p54/p54common.h +++ b/drivers/net/wireless/p54/p54common.h @@ -25,6 +25,22 @@ struct bootrec { u32 data[10]; } __attribute__((packed)); +#define PDR_SYNTH_FRONTEND_MASK 0x0007 +#define PDR_SYNTH_IQ_CAL_MASK 0x0018 +#define PDR_SYNTH_IQ_CAL_PA_DETECTOR 0x0000 +#define PDR_SYNTH_IQ_CAL_DISABLED 0x0008 +#define PDR_SYNTH_IQ_CAL_ZIF 0x0010 +#define PDR_SYNTH_FAA_SWITCH_MASK 0x0020 +#define PDR_SYNTH_FAA_SWITCH_ENABLED 0x0001 +#define PDR_SYNTH_24_GHZ_MASK 0x0040 +#define PDR_SYNTH_24_GHZ_DISABLED 0x0040 +#define PDR_SYNTH_5_GHZ_MASK 0x0080 +#define PDR_SYNTH_5_GHZ_DISABLED 0x0080 +#define PDR_SYNTH_RX_DIV_MASK 0x0100 +#define PDR_SYNTH_RX_DIV_SUPPORTED 0x0100 +#define PDR_SYNTH_TX_DIV_MASK 0x0200 +#define PDR_SYNTH_TX_DIV_SUPPORTED 0x0200 + struct bootrec_exp_if { __le16 role; __le16 if_id; @@ -210,6 +226,19 @@ struct pda_pa_curve_data { #define PDR_BASEBAND_REGISTERS 0x8000 #define PDR_PER_CHANNEL_BASEBAND_REGISTERS 0x8001 +/* PDR definitions for default country & country list */ +#define PDR_COUNTRY_CERT_CODE 0x80 +#define PDR_COUNTRY_CERT_CODE_REAL 0x00 +#define PDR_COUNTRY_CERT_CODE_PSEUDO 0x80 +#define PDR_COUNTRY_CERT_BAND 0x40 +#define PDR_COUNTRY_CERT_BAND_2GHZ 0x00 +#define PDR_COUNTRY_CERT_BAND_5GHZ 0x40 +#define PDR_COUNTRY_CERT_IODOOR 0x30 +#define PDR_COUNTRY_CERT_IODOOR_BOTH 0x00 +#define PDR_COUNTRY_CERT_IODOOR_INDOOR 0x20 +#define PDR_COUNTRY_CERT_IODOOR_OUTDOOR 0x30 +#define PDR_COUNTRY_CERT_INDEX 0x0F + /* stored in skb->cb */ struct memrecord { u32 start_addr; @@ -507,7 +536,7 @@ struct p54_sta_unlock { } __attribute__ ((packed)); #define P54_TIM_CLEAR BIT(15) -struct p54_tx_control_tim { +struct p54_tim { u8 count; u8 padding[3]; __le16 entry[8]; -- cgit v1.2.3-70-g09d2 From 94585b090baf982a850678a1dc3395bce0c1e302 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 18 Oct 2008 23:18:44 +0200 Subject: p54: put broadcast frames into the right queues stlc45xx's specs finally brought some light what all the 4 extra queues for. now CAB data and managment frames have their own queue. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 82 +++++++++++++++++++++++++++++------- 1 file changed, 67 insertions(+), 15 deletions(-) (limited to 'drivers/net/wireless/p54/p54common.c') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index ae8d1f66631..e93bca8263c 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -902,6 +902,55 @@ free: } EXPORT_SYMBOL_GPL(p54_read_eeprom); +static int p54_tx_fill(struct ieee80211_hw *dev, struct sk_buff *skb, + struct ieee80211_tx_info *info, u8 *queue, size_t *extra_len, + u16 *flags, u16 *aid) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct p54_common *priv = dev->priv; + int ret = 0; + + if (unlikely(ieee80211_is_mgmt(hdr->frame_control))) { + if (ieee80211_is_beacon(hdr->frame_control)) { + *aid = 0; + *queue = 0; + *extra_len = IEEE80211_MAX_TIM_LEN; + *flags = P54_HDR_FLAG_DATA_OUT_TIMESTAMP; + return 0; + } else if (ieee80211_is_probe_resp(hdr->frame_control)) { + *aid = 0; + *queue = 2; + *flags = P54_HDR_FLAG_DATA_OUT_TIMESTAMP | + P54_HDR_FLAG_DATA_OUT_NOCANCEL; + return 0; + } else { + *queue = 2; + ret = 0; + } + } else { + *queue += 4; + ret = 1; + } + + switch (priv->mode) { + case NL80211_IFTYPE_STATION: + *aid = 1; + break; + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_ADHOC: + if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { + *aid = 0; + *queue = 3; + return 0; + } + if (info->control.sta) + *aid = info->control.sta->aid; + else + *flags = P54_HDR_FLAG_DATA_OUT_NOCANCEL; + } + return ret; +} + static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); @@ -909,22 +958,26 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) struct p54_common *priv = dev->priv; struct p54_hdr *hdr; struct p54_tx_data *txhdr; - size_t padding, len; + size_t padding, len, tim_len; int i, j, ridx; - u16 hdr_flags = 0; - u8 rate; + u16 hdr_flags = 0, aid = 0; + u8 rate, queue; u8 cts_rate = 0x20; u8 rc_flags; u8 calculated_tries[4]; u8 nrates = 0, nremaining = 8; - current_queue = &priv->tx_stats[skb_get_queue_mapping(skb) + 4]; - if (unlikely(current_queue->len > current_queue->limit)) - return NETDEV_TX_BUSY; - current_queue->len++; - current_queue->count++; - if (current_queue->len == current_queue->limit) - ieee80211_stop_queue(dev, skb_get_queue_mapping(skb)); + queue = skb_get_queue_mapping(skb); + + if (p54_tx_fill(dev, skb, info, &queue, &tim_len, &hdr_flags, &aid)) { + current_queue = &priv->tx_stats[queue]; + if (unlikely(current_queue->len > current_queue->limit)) + return NETDEV_TX_BUSY; + current_queue->len++; + current_queue->count++; + if (current_queue->len == current_queue->limit) + ieee80211_stop_queue(dev, skb_get_queue_mapping(skb)); + } padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3; len = skb->len; @@ -935,7 +988,7 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) if (padding) hdr_flags |= P54_HDR_FLAG_DATA_ALIGN; hdr->len = cpu_to_le16(len); - hdr->type = (info->flags & IEEE80211_TX_CTL_NO_ACK) ? 0 : cpu_to_le16(1); + hdr->type = cpu_to_le16(aid); hdr->rts_tries = info->control.rates[0].count; /* @@ -1013,7 +1066,7 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) txhdr->rts_rate_idx = 0; txhdr->key_type = 0; txhdr->key_len = 0; - txhdr->hw_queue = skb_get_queue_mapping(skb) + 4; + txhdr->hw_queue = queue; txhdr->backlog = 32; memset(txhdr->durations, 0, sizeof(txhdr->durations)); txhdr->tx_antenna = (info->antenna_sel_tx == 0) ? @@ -1024,7 +1077,7 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) txhdr->align[0] = padding; /* modifies skb->cb and with it info, so must be last! */ - if (unlikely(p54_assign_address(dev, skb, hdr, skb->len))) { + if (unlikely(p54_assign_address(dev, skb, hdr, skb->len + tim_len))) { skb_pull(skb, sizeof(*hdr) + sizeof(*txhdr) + padding); if (current_queue) { current_queue->len--; @@ -1509,8 +1562,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) priv = dev->priv; priv->mode = NL80211_IFTYPE_UNSPECIFIED; skb_queue_head_init(&priv->tx_queue); - dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | /* not sure */ - IEEE80211_HW_RX_INCLUDES_FCS | + dev->flags = IEEE80211_HW_RX_INCLUDES_FCS | IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; -- cgit v1.2.3-70-g09d2 From e5ea92a7528d304e8e327d0d261653e98b163e8a Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 18 Oct 2008 23:19:00 +0200 Subject: p54: AP & Ad-hoc testing This patch finally adds all necessary code to test Ad-hoc & AP mode with p54. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54.h | 1 + drivers/net/wireless/p54/p54common.c | 245 ++++++++++++++++++++++++++++++++++- 2 files changed, 241 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless/p54/p54common.c') diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index eb69b904f65..b585ff65e0e 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -108,6 +108,7 @@ struct p54_common { struct timer_list stats_timer; struct completion stats_comp; struct sk_buff *cached_stats; + struct sk_buff *cached_beacon; int noise; void *eeprom; struct completion eeprom_comp; diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index e93bca8263c..8423c430b71 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -626,6 +626,12 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) __skb_unlink(entry, &priv->tx_queue); spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + if (unlikely(entry == priv->cached_beacon)) { + kfree_skb(entry); + priv->cached_beacon = NULL; + goto out; + } + /* * Clear manually, ieee80211_tx_info_clear_status would * clear the counts too and we need them. @@ -711,6 +717,35 @@ static void p54_rx_stats(struct ieee80211_hw *dev, struct sk_buff *skb) mod_timer(&priv->stats_timer, jiffies + 5 * HZ); } +static void p54_rx_trap(struct ieee80211_hw *dev, struct sk_buff *skb) +{ + struct p54_hdr *hdr = (struct p54_hdr *) skb->data; + struct p54_trap *trap = (struct p54_trap *) hdr->data; + u16 event = le16_to_cpu(trap->event); + u16 freq = le16_to_cpu(trap->frequency); + + switch (event) { + case P54_TRAP_BEACON_TX: + break; + case P54_TRAP_RADAR: + printk(KERN_INFO "%s: radar (freq:%d MHz)\n", + wiphy_name(dev->wiphy), freq); + break; + case P54_TRAP_NO_BEACON: + break; + case P54_TRAP_SCAN: + break; + case P54_TRAP_TBTT: + break; + case P54_TRAP_TIMER: + break; + default: + printk(KERN_INFO "%s: received event:%x freq:%d\n", + wiphy_name(dev->wiphy), event, freq); + break; + } +} + static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54_hdr *hdr = (struct p54_hdr *) skb->data; @@ -719,6 +754,9 @@ static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb) case P54_CONTROL_TYPE_TXDONE: p54_rx_frame_sent(dev, skb); break; + case P54_CONTROL_TYPE_TRAP: + p54_rx_trap(dev, skb); + break; case P54_CONTROL_TYPE_BBP: break; case P54_CONTROL_TYPE_STAT_READBACK: @@ -902,6 +940,64 @@ free: } EXPORT_SYMBOL_GPL(p54_read_eeprom); +static int p54_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta, + bool set) +{ + struct p54_common *priv = dev->priv; + struct sk_buff *skb; + struct p54_tim *tim; + + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, + sizeof(struct p54_hdr) + sizeof(*tim), + P54_CONTROL_TYPE_TIM, GFP_KERNEL); + if (!skb) + return -ENOMEM; + + tim = (struct p54_tim *) skb_put(skb, sizeof(*tim)); + tim->count = 1; + tim->entry[0] = cpu_to_le16(set ? (sta->aid | 0x8000) : sta->aid); + priv->tx(dev, skb, 1); + return 0; +} + +static int p54_sta_unlock(struct ieee80211_hw *dev, u8 *addr) +{ + struct p54_common *priv = dev->priv; + struct sk_buff *skb; + struct p54_sta_unlock *sta; + + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, + sizeof(struct p54_hdr) + sizeof(*sta), + P54_CONTROL_TYPE_PSM_STA_UNLOCK, GFP_ATOMIC); + if (!skb) + return -ENOMEM; + + sta = (struct p54_sta_unlock *)skb_put(skb, sizeof(*sta)); + memcpy(sta->addr, addr, ETH_ALEN); + priv->tx(dev, skb, 1); + return 0; +} + +static int p54_tx_cancel(struct ieee80211_hw *dev, struct sk_buff *entry) +{ + struct p54_common *priv = dev->priv; + struct sk_buff *skb; + struct p54_hdr *hdr; + struct p54_txcancel *cancel; + + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, + sizeof(struct p54_hdr) + sizeof(*cancel), + P54_CONTROL_TYPE_TXCANCEL, GFP_ATOMIC); + if (!skb) + return -ENOMEM; + + hdr = (void *)entry->data; + cancel = (struct p54_txcancel *)skb_put(skb, sizeof(*cancel)); + cancel->req_id = hdr->req_id; + priv->tx(dev, skb, 1); + return 0; +} + static int p54_tx_fill(struct ieee80211_hw *dev, struct sk_buff *skb, struct ieee80211_tx_info *info, u8 *queue, size_t *extra_len, u16 *flags, u16 *aid) @@ -982,6 +1078,17 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3; len = skb->len; + if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) { + if (info->control.sta) + if (p54_sta_unlock(dev, info->control.sta->addr)) { + if (current_queue) { + current_queue->len--; + current_queue->count--; + } + return NETDEV_TX_BUSY; + } + } + txhdr = (struct p54_tx_data *) skb_push(skb, sizeof(*txhdr) + padding); hdr = (struct p54_hdr *) skb_push(skb, sizeof(*hdr)); @@ -1295,6 +1402,88 @@ static int p54_init_stats(struct ieee80211_hw *dev) return 0; } +static int p54_beacon_tim(struct sk_buff *skb) +{ + /* + * the good excuse for this mess is ... the firmware. + * The dummy TIM MUST be at the end of the beacon frame, + * because it'll be overwritten! + */ + + struct ieee80211_mgmt *mgmt = (void *)skb->data; + u8 *pos, *end; + + if (skb->len <= sizeof(mgmt)) { + printk(KERN_ERR "p54: beacon is too short!\n"); + return -EINVAL; + } + + pos = (u8 *)mgmt->u.beacon.variable; + end = skb->data + skb->len; + while (pos < end) { + if (pos + 2 + pos[1] > end) { + printk(KERN_ERR "p54: parsing beacon failed\n"); + return -EINVAL; + } + + if (pos[0] == WLAN_EID_TIM) { + u8 dtim_len = pos[1]; + u8 dtim_period = pos[3]; + u8 *next = pos + 2 + dtim_len; + + if (dtim_len < 3) { + printk(KERN_ERR "p54: invalid dtim len!\n"); + return -EINVAL; + } + memmove(pos, next, end - next); + + if (dtim_len > 3) + skb_trim(skb, skb->len - (dtim_len - 3)); + + pos = end - (dtim_len + 2); + + /* add the dummy at the end */ + pos[0] = WLAN_EID_TIM; + pos[1] = 3; + pos[2] = 0; + pos[3] = dtim_period; + pos[4] = 0; + return 0; + } + pos += 2 + pos[1]; + } + return 0; +} + +static int p54_beacon_update(struct ieee80211_hw *dev, + struct ieee80211_vif *vif) +{ + struct p54_common *priv = dev->priv; + struct sk_buff *beacon; + int ret; + + if (priv->cached_beacon) { + p54_tx_cancel(dev, priv->cached_beacon); + /* wait for the last beacon the be freed */ + msleep(10); + } + + beacon = ieee80211_beacon_get(dev, vif); + if (!beacon) + return -ENOMEM; + ret = p54_beacon_tim(beacon); + if (ret) + return ret; + ret = p54_tx(dev, beacon); + if (ret) + return ret; + priv->cached_beacon = beacon; + priv->tsf_high32 = 0; + priv->tsf_low32 = 0; + + return 0; +} + static int p54_start(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; @@ -1325,9 +1514,14 @@ static void p54_stop(struct ieee80211_hw *dev) del_timer(&priv->stats_timer); p54_free_skb(dev, priv->cached_stats); priv->cached_stats = NULL; + if (priv->cached_beacon) + p54_tx_cancel(dev, priv->cached_beacon); + while ((skb = skb_dequeue(&priv->tx_queue))) kfree_skb(skb); + kfree(priv->cached_beacon); + priv->cached_beacon = NULL; priv->stop(dev); priv->tsf_high32 = priv->tsf_low32 = 0; priv->mode = NL80211_IFTYPE_UNSPECIFIED; @@ -1347,6 +1541,8 @@ static int p54_add_interface(struct ieee80211_hw *dev, switch (conf->type) { case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_AP: priv->mode = conf->type; break; default: @@ -1362,6 +1558,12 @@ static int p54_add_interface(struct ieee80211_hw *dev, case NL80211_IFTYPE_STATION: p54_setup_mac(dev, P54_FILTER_TYPE_STATION, NULL); break; + case NL80211_IFTYPE_AP: + p54_setup_mac(dev, P54_FILTER_TYPE_AP, priv->mac_addr); + break; + case NL80211_IFTYPE_ADHOC: + p54_setup_mac(dev, P54_FILTER_TYPE_IBSS, NULL); + break; default: BUG(); /* impossible */ break; @@ -1379,6 +1581,8 @@ static void p54_remove_interface(struct ieee80211_hw *dev, struct p54_common *priv = dev->priv; mutex_lock(&priv->conf_mutex); + if (priv->cached_beacon) + p54_tx_cancel(dev, priv->cached_beacon); p54_setup_mac(dev, P54_FILTER_TYPE_NONE, NULL); priv->mode = NL80211_IFTYPE_MONITOR; memset(priv->mac_addr, 0, ETH_ALEN); @@ -1406,13 +1610,41 @@ static int p54_config_interface(struct ieee80211_hw *dev, struct ieee80211_if_conf *conf) { struct p54_common *priv = dev->priv; + int ret = 0; mutex_lock(&priv->conf_mutex); - p54_setup_mac(dev, P54_FILTER_TYPE_STATION, conf->bssid); - p54_set_leds(dev, 1, !is_multicast_ether_addr(conf->bssid), 0); - memcpy(priv->bssid, conf->bssid, ETH_ALEN); + switch (priv->mode) { + case NL80211_IFTYPE_STATION: + ret = p54_setup_mac(dev, P54_FILTER_TYPE_STATION, conf->bssid); + if (ret) + goto out; + ret = p54_set_leds(dev, 1, + !is_multicast_ether_addr(conf->bssid), 0); + if (ret) + goto out; + memcpy(priv->bssid, conf->bssid, ETH_ALEN); + break; + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_ADHOC: + memcpy(priv->bssid, conf->bssid, ETH_ALEN); + ret = p54_set_freq(dev, dev->conf.channel->center_freq); + if (ret) + goto out; + ret = p54_setup_mac(dev, priv->mac_mode, priv->bssid); + if (ret) + goto out; + if (conf->changed & IEEE80211_IFCC_BEACON) { + ret = p54_beacon_update(dev, vif); + if (ret) + goto out; + ret = p54_set_edcf(dev); + if (ret) + goto out; + } + } +out: mutex_unlock(&priv->conf_mutex); - return 0; + return ret; } static void p54_configure_filter(struct ieee80211_hw *dev, @@ -1541,6 +1773,7 @@ static const struct ieee80211_ops p54_ops = { .stop = p54_stop, .add_interface = p54_add_interface, .remove_interface = p54_remove_interface, + .set_tim = p54_set_tim, .config = p54_config, .config_interface = p54_config_interface, .bss_info_changed = p54_bss_info_changed, @@ -1566,7 +1799,9 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; - dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); + dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION | + NL80211_IFTYPE_ADHOC | + NL80211_IFTYPE_AP); dev->channel_change_time = 1000; /* TODO: find actual value */ priv->tx_stats[0].limit = 1; /* Beacon queue */ -- cgit v1.2.3-70-g09d2 From db4186cf15a5a7e8e8526f7c158f042ccc3ed576 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Fri, 31 Oct 2008 15:53:12 -0400 Subject: p54: eliminate warning for uninitialized variable 'tim_len' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/net/wireless/p54/p54common.c: In function ‘p54_tx’: drivers/net/wireless/p54/p54common.c:1058: warning: ‘tim_len’ may be used uninitialized in this function Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/p54/p54common.c') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 8423c430b71..a2e2150403d 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -1054,7 +1054,7 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) struct p54_common *priv = dev->priv; struct p54_hdr *hdr; struct p54_tx_data *txhdr; - size_t padding, len, tim_len; + size_t padding, len, tim_len = 0; int i, j, ridx; u16 hdr_flags = 0, aid = 0; u8 rate, queue; -- cgit v1.2.3-70-g09d2 From c8034c44851ba4c6b55ec6e6b60573cf51589be3 Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Wed, 29 Oct 2008 17:31:43 -0400 Subject: p54: don't report known but unhandled EEPROM codes as unknown Signed-off-by: Pavel Roskin Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers/net/wireless/p54/p54common.c') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index a2e2150403d..6f0aa7981b3 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -420,6 +420,30 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) /* make it overrun */ entry_len = len; break; + case PDR_MANUFACTURING_PART_NUMBER: + case PDR_PDA_VERSION: + case PDR_NIC_SERIAL_NUMBER: + case PDR_REGULATORY_DOMAIN_LIST: + case PDR_TEMPERATURE_TYPE: + case PDR_PRISM_PCI_IDENTIFIER: + case PDR_COUNTRY_INFORMATION: + case PDR_OEM_NAME: + case PDR_PRODUCT_NAME: + case PDR_UTF8_OEM_NAME: + case PDR_UTF8_PRODUCT_NAME: + case PDR_COUNTRY_LIST: + case PDR_DEFAULT_COUNTRY: + case PDR_ANTENNA_GAIN: + case PDR_PRISM_INDIGO_PA_CALIBRATION_DATA: + case PDR_RSSI_LINEAR_APPROXIMATION: + case PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND: + case PDR_REGULATORY_POWER_LIMITS: + case PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED: + case PDR_RADIATED_TRANSMISSION_CORRECTION: + case PDR_PRISM_TX_IQ_CALIBRATION: + case PDR_BASEBAND_REGISTERS: + case PDR_PER_CHANNEL_BASEBAND_REGISTERS: + break; default: printk(KERN_INFO "p54: unknown eeprom code : 0x%x\n", le16_to_cpu(entry->code)); -- cgit v1.2.3-70-g09d2 From 9483407d09077c0bfc612c72835b1e9bbdda0a10 Mon Sep 17 00:00:00 2001 From: Chr Date: Wed, 29 Oct 2008 22:39:50 +0100 Subject: p54: initialize all deprecated fields The new mechanism for allocing space for control frames, didn't "zero" out the payload data... However I haven't heard of any hiccups so far... Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless/p54/p54common.c') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 6f0aa7981b3..1796b8c6c5b 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -9,7 +9,7 @@ * - the islsm (softmac prism54) driver, which is: * Copyright 2004-2006 Jean-Baptiste Note , et al. * - stlc45xx driver - * C Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -1241,8 +1241,10 @@ static int p54_setup_mac(struct ieee80211_hw *dev, u16 mode, const u8 *bssid) else memcpy(setup->bssid, bssid, ETH_ALEN); setup->rx_antenna = priv->rx_antenna; + setup->rx_align = 0; if (priv->fw_var < 0x500) { setup->v1.basic_rate_mask = cpu_to_le32(0x15f); + memset(setup->v1.rts_rates, 0, 8); setup->v1.rx_addr = cpu_to_le32(priv->rx_end); setup->v1.max_rx = cpu_to_le16(priv->rx_mtu); setup->v1.rxhw = cpu_to_le16(priv->rxhw); @@ -1326,11 +1328,11 @@ static int p54_set_freq(struct ieee80211_hw *dev, u16 frequency) } entry += sizeof(__le16); - chan->pa_points_per_curve = - min(priv->curve_data->points_per_channel, (u8) 8); - - memcpy(chan->curve_data, entry, sizeof(*chan->curve_data) * - chan->pa_points_per_curve); + chan->pa_points_per_curve = 8; + memset(chan->curve_data, 0, sizeof(*chan->curve_data)); + memcpy(chan->curve_data, entry, + sizeof(struct p54_pa_curve_data_sample) * + min((u8)8, priv->curve_data->points_per_channel)); break; } @@ -1406,6 +1408,7 @@ static int p54_set_edcf(struct ieee80211_hw *dev) /* (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)); priv->tx(dev, skb, 1); -- cgit v1.2.3-70-g09d2 From d131bb59c142585c389b5284d93743e4e065e393 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 15 Nov 2008 17:02:31 +0100 Subject: p54: enable Mesh Point support This patch enables Mesh Point operation for any p54 device. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/p54/p54common.c') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 1796b8c6c5b..e0066c4c034 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -1058,6 +1058,7 @@ static int p54_tx_fill(struct ieee80211_hw *dev, struct sk_buff *skb, break; case NL80211_IFTYPE_AP: case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { *aid = 0; *queue = 3; @@ -1570,6 +1571,7 @@ static int p54_add_interface(struct ieee80211_hw *dev, case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_MESH_POINT: priv->mode = conf->type; break; default: @@ -1589,6 +1591,7 @@ static int p54_add_interface(struct ieee80211_hw *dev, p54_setup_mac(dev, P54_FILTER_TYPE_AP, priv->mac_addr); break; case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: p54_setup_mac(dev, P54_FILTER_TYPE_IBSS, NULL); break; default: @@ -1653,6 +1656,7 @@ static int p54_config_interface(struct ieee80211_hw *dev, break; case NL80211_IFTYPE_AP: case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: memcpy(priv->bssid, conf->bssid, ETH_ALEN); ret = p54_set_freq(dev, dev->conf.channel->center_freq); if (ret) @@ -1826,9 +1830,10 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; - dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION | - NL80211_IFTYPE_ADHOC | - NL80211_IFTYPE_AP); + dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC) | + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_MESH_POINT); dev->channel_change_time = 1000; /* TODO: find actual value */ priv->tx_stats[0].limit = 1; /* Beacon queue */ -- cgit v1.2.3-70-g09d2 From ffed785898a6dfd5f80d069bcb607b8cd5613c76 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Fri, 14 Nov 2008 19:41:22 +0100 Subject: p54: minor fixes This patch contains only contains a one-liner fixes and enhancements Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 10 +++++++--- drivers/net/wireless/p54/p54common.h | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless/p54/p54common.c') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index e0066c4c034..6bf5123c10b 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -530,6 +530,8 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) rx_status.noise = priv->noise; /* XX correct? */ rx_status.qual = (100 * hdr->rssi) / 127; + if (hdr->rate & 0x10) + rx_status.flag |= RX_FLAG_SHORTPRE; rx_status.rate_idx = (dev->conf.channel->band == IEEE80211_BAND_2GHZ ? hdr->rate : (hdr->rate - 4)) & 0xf; rx_status.freq = freq; @@ -576,7 +578,7 @@ void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb) unsigned long flags; u32 freed = 0, last_addr = priv->rx_start; - if (!skb || !dev) + if (unlikely(!skb || !dev || !skb_queue_len(&priv->tx_queue))) return; spin_lock_irqsave(&priv->tx_queue.lock, flags); @@ -1199,7 +1201,10 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) txhdr->key_type = 0; txhdr->key_len = 0; txhdr->hw_queue = queue; - txhdr->backlog = 32; + if (current_queue) + txhdr->backlog = current_queue->len; + else + txhdr->backlog = 0; memset(txhdr->durations, 0, sizeof(txhdr->durations)); txhdr->tx_antenna = (info->antenna_sel_tx == 0) ? 2 : info->antenna_sel_tx - 1; @@ -1548,7 +1553,6 @@ static void p54_stop(struct ieee80211_hw *dev) while ((skb = skb_dequeue(&priv->tx_queue))) kfree_skb(skb); - kfree(priv->cached_beacon); priv->cached_beacon = NULL; priv->stop(dev); priv->tsf_high32 = priv->tsf_low32 = 0; diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h index 8c8793cb2d7..3419f16be93 100644 --- a/drivers/net/wireless/p54/p54common.h +++ b/drivers/net/wireless/p54/p54common.h @@ -259,7 +259,7 @@ enum p54_rx_decrypt_status { P54_DECRYPT_NOCKIPMIC, P54_DECRYPT_FAIL_WEP, P54_DECRYPT_FAIL_TKIP, - P54_DECRYPT_FAIL_MICAHEL, + P54_DECRYPT_FAIL_MICHAEL, P54_DECRYPT_FAIL_CKIPKP, P54_DECRYPT_FAIL_CKIPMIC, P54_DECRYPT_FAIL_AESCCMP -- cgit v1.2.3-70-g09d2 From 40db0b22591f59811feeb7cad26fdde92a190663 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sun, 16 Nov 2008 12:20:32 +0100 Subject: p54pci: cache firmware for suspend/resume Johannes pointed out that the driver has cache the firmware for suspend/resume cycles. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 16 ++++++++++---- drivers/net/wireless/p54/p54pci.c | 42 +++++++++++++++++++----------------- drivers/net/wireless/p54/p54pci.h | 2 +- 3 files changed, 35 insertions(+), 25 deletions(-) (limited to 'drivers/net/wireless/p54/p54common.c') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 6bf5123c10b..3373b022d91 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -1524,16 +1524,24 @@ static int p54_start(struct ieee80211_hw *dev) mutex_lock(&priv->conf_mutex); err = priv->open(dev); - if (!err) - priv->mode = NL80211_IFTYPE_MONITOR; + if (err) + goto out; P54_SET_QUEUE(priv->qos_params[0], 0x0002, 0x0003, 0x0007, 47); P54_SET_QUEUE(priv->qos_params[1], 0x0002, 0x0007, 0x000f, 94); P54_SET_QUEUE(priv->qos_params[2], 0x0003, 0x000f, 0x03ff, 0); P54_SET_QUEUE(priv->qos_params[3], 0x0007, 0x000f, 0x03ff, 0); err = p54_set_edcf(dev); - if (!err) - err = p54_init_stats(dev); + if (err) + goto out; + err = p54_init_stats(dev); + if (err) + goto out; + err = p54_setup_mac(dev, P54_FILTER_TYPE_NONE, NULL); + if (err) + goto out; + priv->mode = NL80211_IFTYPE_MONITOR; +out: mutex_unlock(&priv->conf_mutex); return err; } diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index c4a868ae6d6..d21c509325f 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -47,7 +47,6 @@ MODULE_DEVICE_TABLE(pci, p54p_table); static int p54p_upload_firmware(struct ieee80211_hw *dev) { struct p54p_priv *priv = dev->priv; - const struct firmware *fw_entry = NULL; __le32 reg; int err; __le32 *data; @@ -73,23 +72,15 @@ static int p54p_upload_firmware(struct ieee80211_hw *dev) P54P_WRITE(ctrl_stat, reg); wmb(); - err = request_firmware(&fw_entry, "isl3886pci", &priv->pdev->dev); - if (err) { - printk(KERN_ERR "%s (p54pci): cannot find firmware " - "(isl3886pci)\n", pci_name(priv->pdev)); - err = request_firmware(&fw_entry, "isl3886", &priv->pdev->dev); - if (err) - return err; - } + /* wait for the firmware to reset properly */ + mdelay(10); - err = p54_parse_firmware(dev, fw_entry); - if (err) { - release_firmware(fw_entry); + err = p54_parse_firmware(dev, priv->firmware); + if (err) return err; - } - data = (__le32 *) fw_entry->data; - remains = fw_entry->size; + data = (__le32 *) priv->firmware->data; + remains = priv->firmware->size; device_addr = ISL38XX_DEV_FIRMWARE_ADDR; while (remains) { u32 i = 0; @@ -107,8 +98,6 @@ static int p54p_upload_firmware(struct ieee80211_hw *dev) P54P_READ(int_enable); } - release_firmware(fw_entry); - reg = P54P_READ(ctrl_stat); reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN); reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET); @@ -500,15 +489,14 @@ static int __devinit p54p_probe(struct pci_dev *pdev, if (mem_len < sizeof(struct p54p_csr)) { printk(KERN_ERR "%s (p54pci): Too short PCI resources\n", pci_name(pdev)); - pci_disable_device(pdev); - return err; + goto err_disable_dev; } err = pci_request_regions(pdev, "p54pci"); if (err) { printk(KERN_ERR "%s (p54pci): Cannot obtain PCI resources\n", pci_name(pdev)); - return err; + goto err_disable_dev; } if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) || @@ -561,6 +549,17 @@ static int __devinit p54p_probe(struct pci_dev *pdev, spin_lock_init(&priv->lock); tasklet_init(&priv->rx_tasklet, p54p_rx_tasklet, (unsigned long)dev); + err = request_firmware(&priv->firmware, "isl3886pci", + &priv->pdev->dev); + if (err) { + printk(KERN_ERR "%s (p54pci): cannot find firmware " + "(isl3886pci)\n", pci_name(priv->pdev)); + 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; @@ -579,6 +578,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev, return 0; err_free_common: + release_firmware(priv->firmware); p54_free_common(dev); pci_free_consistent(pdev, sizeof(*priv->ring_control), priv->ring_control, priv->ring_control_dma); @@ -592,6 +592,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev, err_free_reg: pci_release_regions(pdev); + err_disable_dev: pci_disable_device(pdev); return err; } @@ -606,6 +607,7 @@ static void __devexit p54p_remove(struct pci_dev *pdev) ieee80211_unregister_hw(dev); priv = dev->priv; + release_firmware(priv->firmware); pci_free_consistent(pdev, sizeof(*priv->ring_control), priv->ring_control, priv->ring_control_dma); p54_free_common(dev); diff --git a/drivers/net/wireless/p54/p54pci.h b/drivers/net/wireless/p54/p54pci.h index 4a6778070af..fbb683953fb 100644 --- a/drivers/net/wireless/p54/p54pci.h +++ b/drivers/net/wireless/p54/p54pci.h @@ -93,7 +93,7 @@ struct p54p_priv { struct pci_dev *pdev; struct p54p_csr __iomem *map; struct tasklet_struct rx_tasklet; - + const struct firmware *firmware; spinlock_t lock; struct p54p_ring_control *ring_control; dma_addr_t ring_control_dma; -- cgit v1.2.3-70-g09d2 From ced0957442af69c5c41b00db85a933ed7876cc40 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Fri, 14 Nov 2008 19:42:39 +0100 Subject: p54: honour bss_info_changed's basic_rates and other settings As was pointed out in "p54: honour bss_info_changed's short slot time settings", bss_info_changed provides more useful settings that can be used by the driver. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54.h | 3 +++ drivers/net/wireless/p54/p54common.c | 29 ++++++++++++++++++++++++----- 2 files changed, 27 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless/p54/p54common.c') diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index b585ff65e0e..491ab96c7b6 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -102,6 +102,9 @@ struct p54_common { unsigned int output_power; u32 tsf_low32; u32 tsf_high32; + u64 basic_rate_mask; + u16 wakeup_timer; + u16 aid; struct ieee80211_tx_queue_stats tx_stats[8]; struct p54_edcf_queue_param qos_params[8]; struct ieee80211_low_level_stats stats; diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 3373b022d91..829b3f916db 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -1249,20 +1249,20 @@ static int p54_setup_mac(struct ieee80211_hw *dev, u16 mode, const u8 *bssid) setup->rx_antenna = priv->rx_antenna; setup->rx_align = 0; if (priv->fw_var < 0x500) { - setup->v1.basic_rate_mask = cpu_to_le32(0x15f); + setup->v1.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask); memset(setup->v1.rts_rates, 0, 8); setup->v1.rx_addr = cpu_to_le32(priv->rx_end); setup->v1.max_rx = cpu_to_le16(priv->rx_mtu); setup->v1.rxhw = cpu_to_le16(priv->rxhw); - setup->v1.wakeup_timer = cpu_to_le16(500); + setup->v1.wakeup_timer = cpu_to_le16(priv->wakeup_timer); setup->v1.unalloc0 = cpu_to_le16(0); } else { setup->v2.rx_addr = cpu_to_le32(priv->rx_end); setup->v2.max_rx = cpu_to_le16(priv->rx_mtu); setup->v2.rxhw = cpu_to_le16(priv->rxhw); - setup->v2.timer = cpu_to_le16(1000); + setup->v2.timer = cpu_to_le16(priv->wakeup_timer); setup->v2.truncate = cpu_to_le16(48896); - setup->v2.basic_rate_mask = cpu_to_le32(0x15f); + setup->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask); setup->v2.sbss_offset = 0; setup->v2.mcast_window = 0; setup->v2.rx_rssi_threshold = 0; @@ -1348,7 +1348,7 @@ static int p54_set_freq(struct ieee80211_hw *dev, u16 frequency) } else { chan->v2.rssical_mul = cpu_to_le16(130); chan->v2.rssical_add = cpu_to_le16(0xfe70); - chan->v2.basic_rate_mask = cpu_to_le32(0x15f); + chan->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask); memset(chan->v2.rts_rates, 0, 8); } priv->tx(dev, skb, 1); @@ -1808,6 +1808,24 @@ static void p54_bss_info_changed(struct ieee80211_hw *dev, priv->use_short_slot = info->use_short_slot; p54_set_edcf(dev); } + if (changed & BSS_CHANGED_BASIC_RATES) { + if (dev->conf.channel->band == IEEE80211_BAND_5GHZ) + priv->basic_rate_mask = (info->basic_rates << 4); + else + priv->basic_rate_mask = info->basic_rates; + p54_setup_mac(dev, priv->mac_mode, priv->bssid); + if (priv->fw_var >= 0x500) + p54_set_freq(dev, dev->conf.channel->center_freq); + } + if (changed & BSS_CHANGED_ASSOC) { + if (info->assoc) { + priv->aid = info->aid; + priv->wakeup_timer = info->beacon_int * + info->dtim_period * 5; + p54_setup_mac(dev, priv->mac_mode, priv->bssid); + } + } + } static const struct ieee80211_ops p54_ops = { @@ -1837,6 +1855,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) priv = dev->priv; priv->mode = NL80211_IFTYPE_UNSPECIFIED; + priv->basic_rate_mask = 0x15f; skb_queue_head_init(&priv->tx_queue); dev->flags = IEEE80211_HW_RX_INCLUDES_FCS | IEEE80211_HW_SIGNAL_DBM | -- cgit v1.2.3-70-g09d2 From b50563a68520dea3a19b5a8013c4ae0f8e3b49dd Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Mon, 24 Nov 2008 14:52:51 +0100 Subject: p54: fix wmm queue settings This patch fixes a regression (introduced by "p54: more definitions form lmac_longbow.h and pda.h") It turned out that the "ret" variable wasn't initialized and this caused the following warnings/errors to appear: wmaster1: failed to set TX queue parameters for queue 2 wmaster1: failed to set TX queue parameters for queue 3 wmaster1: failed to set TX queue parameters for queue 1 wmaster1: failed to set TX queue parameters for queue 0 Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net/wireless/p54/p54common.c') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 829b3f916db..602392628e4 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -1728,10 +1728,9 @@ static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue, if ((params) && !(queue > 4)) { P54_SET_QUEUE(priv->qos_params[queue], params->aifs, params->cw_min, params->cw_max, params->txop); + ret = p54_set_edcf(dev); } else ret = -EINVAL; - if (!ret) - ret = p54_set_edcf(dev); mutex_unlock(&priv->conf_mutex); return ret; } -- cgit v1.2.3-70-g09d2 From c772a08ba7192fa5450f85ef53adcbc6e0c5e1c9 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 29 Nov 2008 22:33:57 +0100 Subject: p54: revamp station power save management in access point mode This patch addresses the problem in: http://marc.info/?l=linux-wireless&m=122727674810057&w=2 Thanks to Stefan Steuerwald extensive iPod touch tests. We could finally squash some bugs in p54's master mode / access point implementation. Let's hope we got everything right this time and all stations from now on will wake up on TIM and receive their queued frames and go to sleep again without any hiccups. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 73 ++++++++++++++++++++++++------------ drivers/net/wireless/p54/p54common.h | 2 +- 2 files changed, 49 insertions(+), 26 deletions(-) (limited to 'drivers/net/wireless/p54/p54common.c') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 602392628e4..de92b58d450 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -652,6 +652,10 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) __skb_unlink(entry, &priv->tx_queue); spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + entry_hdr = (struct p54_hdr *) entry->data; + entry_data = (struct p54_tx_data *) entry_hdr->data; + priv->tx_stats[entry_data->hw_queue].len--; + if (unlikely(entry == priv->cached_beacon)) { kfree_skb(entry); priv->cached_beacon = NULL; @@ -668,8 +672,6 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, status.ampdu_ack_len) != 23); - entry_hdr = (struct p54_hdr *) entry->data; - entry_data = (struct p54_tx_data *) entry_hdr->data; if (entry_hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN)) pad = entry_data->align[0]; @@ -687,7 +689,6 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) } } - priv->tx_stats[entry_data->hw_queue].len--; if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && (!payload->status)) info->flags |= IEEE80211_TX_STAT_ACK; @@ -1004,6 +1005,38 @@ static int p54_sta_unlock(struct ieee80211_hw *dev, u8 *addr) return 0; } +static void p54_sta_notify_ps(struct ieee80211_hw *dev, + enum sta_notify_ps_cmd notify_cmd, + struct ieee80211_sta *sta) +{ + switch (notify_cmd) { + case STA_NOTIFY_AWAKE: + p54_sta_unlock(dev, sta->addr); + break; + default: + break; + } +} + +static void p54_sta_notify(struct ieee80211_hw *dev, struct ieee80211_vif *vif, + enum sta_notify_cmd notify_cmd, + struct ieee80211_sta *sta) +{ + switch (notify_cmd) { + case STA_NOTIFY_ADD: + case STA_NOTIFY_REMOVE: + /* + * Notify the firmware that we don't want or we don't + * need to buffer frames for this station anymore. + */ + + p54_sta_unlock(dev, sta->addr); + break; + default: + break; + } +} + static int p54_tx_cancel(struct ieee80211_hw *dev, struct sk_buff *entry) { struct p54_common *priv = dev->priv; @@ -1069,7 +1102,7 @@ static int p54_tx_fill(struct ieee80211_hw *dev, struct sk_buff *skb, if (info->control.sta) *aid = info->control.sta->aid; else - *flags = P54_HDR_FLAG_DATA_OUT_NOCANCEL; + *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL; } return ret; } @@ -1082,7 +1115,7 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) struct p54_hdr *hdr; struct p54_tx_data *txhdr; size_t padding, len, tim_len = 0; - int i, j, ridx; + int i, j, ridx, ret; u16 hdr_flags = 0, aid = 0; u8 rate, queue; u8 cts_rate = 0x20; @@ -1092,30 +1125,18 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) queue = skb_get_queue_mapping(skb); - if (p54_tx_fill(dev, skb, info, &queue, &tim_len, &hdr_flags, &aid)) { - current_queue = &priv->tx_stats[queue]; - if (unlikely(current_queue->len > current_queue->limit)) - return NETDEV_TX_BUSY; - current_queue->len++; - current_queue->count++; - if (current_queue->len == current_queue->limit) - ieee80211_stop_queue(dev, skb_get_queue_mapping(skb)); - } + ret = p54_tx_fill(dev, skb, info, &queue, &tim_len, &hdr_flags, &aid); + current_queue = &priv->tx_stats[queue]; + if (unlikely((current_queue->len > current_queue->limit) && ret)) + return NETDEV_TX_BUSY; + current_queue->len++; + current_queue->count++; + if ((current_queue->len == current_queue->limit) && ret) + ieee80211_stop_queue(dev, skb_get_queue_mapping(skb)); padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3; len = skb->len; - if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) { - if (info->control.sta) - if (p54_sta_unlock(dev, info->control.sta->addr)) { - if (current_queue) { - current_queue->len--; - current_queue->count--; - } - return NETDEV_TX_BUSY; - } - } - txhdr = (struct p54_tx_data *) skb_push(skb, sizeof(*txhdr) + padding); hdr = (struct p54_hdr *) skb_push(skb, sizeof(*hdr)); @@ -1834,6 +1855,8 @@ static const struct ieee80211_ops p54_ops = { .add_interface = p54_add_interface, .remove_interface = p54_remove_interface, .set_tim = p54_set_tim, + .sta_notify_ps = p54_sta_notify_ps, + .sta_notify = p54_sta_notify, .config = p54_config, .config_interface = p54_config_interface, .bss_info_changed = p54_bss_info_changed, diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h index 3419f16be93..d292ffbec08 100644 --- a/drivers/net/wireless/p54/p54common.h +++ b/drivers/net/wireless/p54/p54common.h @@ -302,7 +302,7 @@ enum p54_frame_sent_status { P54_TX_OK = 0, P54_TX_FAILED, P54_TX_PSM, - P54_TX_PSM_CANCELLED + P54_TX_PSM_CANCELLED = 4 }; struct p54_frame_sent { -- cgit v1.2.3-70-g09d2 From 25900ef0191af98bbb24d8088c6887af31c1ba27 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 29 Nov 2008 22:34:37 +0100 Subject: p54: utilize cryptographic accelerator This patch allows p54 to utilize its WEP, TKIP and CCMP accelerator. Tested-by: Larry Finger Signed-off-by: Christian Lamparter Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54.h | 2 + drivers/net/wireless/p54/p54common.c | 179 ++++++++++++++++++++++++++++++++--- 2 files changed, 168 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless/p54/p54common.c') diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index 491ab96c7b6..ebe1ea1f565 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -115,6 +115,8 @@ struct p54_common { int noise; void *eeprom; struct completion eeprom_comp; + u8 privacy_caps; + u8 rx_keycache_size; }; int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb); diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index de92b58d450..6f7e82b56cb 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -25,6 +25,9 @@ #include "p54.h" #include "p54common.h" +static int modparam_nohwcrypt; +module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); +MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); MODULE_AUTHOR("Michael Wu "); MODULE_DESCRIPTION("Softmac Prism54 common code"); MODULE_LICENSE("GPL"); @@ -185,6 +188,8 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) priv->rx_end = le32_to_cpu(desc->rx_end) - 0x3500; priv->headroom = desc->headroom; priv->tailroom = desc->tailroom; + priv->privacy_caps = desc->privacy_caps; + priv->rx_keycache_size = desc->rx_keycache_size; if (le32_to_cpu(bootrec->len) == 11) priv->rx_mtu = le16_to_cpu(desc->rx_mtu); else @@ -228,6 +233,16 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) dev->queues = 4; } + if (!modparam_nohwcrypt) + printk(KERN_INFO "%s: cryptographic accelerator " + "WEP:%s, TKIP:%s, CCMP:%s\n", + wiphy_name(dev->wiphy), + (priv->privacy_caps & BR_DESC_PRIV_CAP_WEP) ? "YES" : + "no", (priv->privacy_caps & (BR_DESC_PRIV_CAP_TKIP | + BR_DESC_PRIV_CAP_MICHAEL)) ? "YES" : "no", + (priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP) ? + "YES" : "no"); + return 0; } EXPORT_SYMBOL_GPL(p54_parse_firmware); @@ -526,6 +541,12 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) return 0; } + if (hdr->decrypt_status == P54_DECRYPT_OK) + rx_status.flag |= RX_FLAG_DECRYPTED; + if ((hdr->decrypt_status == P54_DECRYPT_FAIL_MICHAEL) || + (hdr->decrypt_status == P54_DECRYPT_FAIL_TKIP)) + rx_status.flag |= RX_FLAG_MMIC_ERROR; + rx_status.signal = p54_rssi_to_dbm(dev, hdr->rssi); rx_status.noise = priv->noise; /* XX correct? */ @@ -1107,6 +1128,20 @@ static int p54_tx_fill(struct ieee80211_hw *dev, struct sk_buff *skb, return ret; } +static u8 p54_convert_algo(enum ieee80211_key_alg alg) +{ + switch (alg) { + case ALG_WEP: + return P54_CRYPTO_WEP; + case ALG_TKIP: + return P54_CRYPTO_TKIPMICHAEL; + case ALG_CCMP: + return P54_CRYPTO_AESCCMP; + default: + return 0; + } +} + static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); @@ -1117,7 +1152,7 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) size_t padding, len, tim_len = 0; int i, j, ridx, ret; u16 hdr_flags = 0, aid = 0; - u8 rate, queue; + u8 rate, queue, crypt_offset = 0; u8 cts_rate = 0x20; u8 rc_flags; u8 calculated_tries[4]; @@ -1137,12 +1172,25 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3; len = skb->len; + if (info->control.hw_key) { + crypt_offset = ieee80211_get_hdrlen_from_skb(skb); + if (info->control.hw_key->alg == ALG_TKIP) { + u8 *iv = (u8 *)(skb->data + crypt_offset); + /* + * The firmware excepts that the IV has to have + * this special format + */ + iv[1] = iv[0]; + iv[0] = iv[2]; + iv[2] = 0; + } + } + txhdr = (struct p54_tx_data *) skb_push(skb, sizeof(*txhdr) + padding); hdr = (struct p54_hdr *) skb_push(skb, sizeof(*hdr)); if (padding) hdr_flags |= P54_HDR_FLAG_DATA_ALIGN; - hdr->len = cpu_to_le16(len); hdr->type = cpu_to_le16(aid); hdr->rts_tries = info->control.rates[0].count; @@ -1217,10 +1265,27 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) /* TODO: enable bursting */ hdr->flags = cpu_to_le16(hdr_flags); hdr->tries = ridx; - txhdr->crypt_offset = 0; txhdr->rts_rate_idx = 0; - txhdr->key_type = 0; - txhdr->key_len = 0; + if (info->control.hw_key) { + crypt_offset += info->control.hw_key->iv_len; + txhdr->key_type = p54_convert_algo(info->control.hw_key->alg); + txhdr->key_len = min((u8)16, info->control.hw_key->keylen); + memcpy(txhdr->key, info->control.hw_key->key, txhdr->key_len); + if (info->control.hw_key->alg == ALG_TKIP) { + if (unlikely(skb_tailroom(skb) < 12)) + goto err; + /* reserve space for the MIC key */ + len += 8; + memcpy(skb_put(skb, 8), &(info->control.hw_key->key + [NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY]), 8); + } + /* reserve some space for ICV */ + len += info->control.hw_key->icv_len; + } else { + txhdr->key_type = 0; + txhdr->key_len = 0; + } + txhdr->crypt_offset = crypt_offset; txhdr->hw_queue = queue; if (current_queue) txhdr->backlog = current_queue->len; @@ -1234,17 +1299,20 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) if (padding) txhdr->align[0] = padding; + hdr->len = cpu_to_le16(len); /* modifies skb->cb and with it info, so must be last! */ - if (unlikely(p54_assign_address(dev, skb, hdr, skb->len + tim_len))) { - skb_pull(skb, sizeof(*hdr) + sizeof(*txhdr) + padding); - if (current_queue) { - current_queue->len--; - current_queue->count--; - } - return NETDEV_TX_BUSY; - } + if (unlikely(p54_assign_address(dev, skb, hdr, skb->len + tim_len))) + goto err; priv->tx(dev, skb, 0); return 0; + + err: + skb_pull(skb, sizeof(*hdr) + sizeof(*txhdr) + padding); + if (current_queue) { + current_queue->len--; + current_queue->count--; + } + return NETDEV_TX_BUSY; } static int p54_setup_mac(struct ieee80211_hw *dev, u16 mode, const u8 *bssid) @@ -1848,6 +1916,90 @@ static void p54_bss_info_changed(struct ieee80211_hw *dev, } +static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, + const u8 *local_address, const u8 *address, + struct ieee80211_key_conf *key) +{ + struct p54_common *priv = dev->priv; + struct sk_buff *skb; + struct p54_keycache *rxkey; + u8 algo = 0; + + if (modparam_nohwcrypt) + return -EOPNOTSUPP; + + if (cmd == DISABLE_KEY) + algo = 0; + else { + switch (key->alg) { + case ALG_TKIP: + if (!(priv->privacy_caps & (BR_DESC_PRIV_CAP_MICHAEL | + BR_DESC_PRIV_CAP_TKIP))) + return -EOPNOTSUPP; + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + algo = P54_CRYPTO_TKIPMICHAEL; + break; + case ALG_WEP: + if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_WEP)) + return -EOPNOTSUPP; + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + algo = P54_CRYPTO_WEP; + break; + case ALG_CCMP: + if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP)) + return -EOPNOTSUPP; + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + algo = P54_CRYPTO_AESCCMP; + break; + default: + return -EINVAL; + } + } + + if (key->keyidx > priv->rx_keycache_size) { + /* + * The device supports the choosen algorithm, but the firmware + * does not provide enough key slots to store all of them. + * So, incoming frames have to be decoded by the mac80211 stack, + * but we can still offload encryption for outgoing frames. + */ + + return 0; + } + + mutex_lock(&priv->conf_mutex); + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*rxkey) + + sizeof(struct p54_hdr), P54_CONTROL_TYPE_RX_KEYCACHE, + GFP_ATOMIC); + if (!skb) { + mutex_unlock(&priv->conf_mutex); + return -ENOMEM; + } + + /* TODO: some devices have 4 more free slots for rx keys */ + rxkey = (struct p54_keycache *)skb_put(skb, sizeof(*rxkey)); + rxkey->entry = key->keyidx; + rxkey->key_id = key->keyidx; + rxkey->key_type = algo; + if (address) + memcpy(rxkey->mac, address, ETH_ALEN); + else + memset(rxkey->mac, ~0, ETH_ALEN); + if (key->alg != ALG_TKIP) { + rxkey->key_len = min((u8)16, key->keylen); + memcpy(rxkey->key, key->key, rxkey->key_len); + } else { + rxkey->key_len = 24; + memcpy(rxkey->key, key->key, 16); + memcpy(&(rxkey->key[16]), &(key->key + [NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]), 8); + } + + priv->tx(dev, skb, 1); + mutex_unlock(&priv->conf_mutex); + return 0; +} + static const struct ieee80211_ops p54_ops = { .tx = p54_tx, .start = p54_start, @@ -1857,6 +2009,7 @@ static const struct ieee80211_ops p54_ops = { .set_tim = p54_set_tim, .sta_notify_ps = p54_sta_notify_ps, .sta_notify = p54_sta_notify, + .set_key = p54_set_key, .config = p54_config, .config_interface = p54_config_interface, .bss_info_changed = p54_bss_info_changed, -- cgit v1.2.3-70-g09d2 From 64c354ddcd65c98d9a1e2a8f7fb5cc80c7fa488e Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 29 Nov 2008 22:35:43 +0100 Subject: p54: include support for 2.13.24.0 USB LM87 Firmwares Those firmwares are probably capable of reprogramming the device's eeprom. We better support them officially, before all the accidents happen. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 35 +++++++++++++++++++++++++++-------- drivers/net/wireless/p54/p54common.h | 18 +++++++++++++++--- 2 files changed, 42 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless/p54/p54common.c') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 6f7e82b56cb..1b5627d4062 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -739,7 +739,13 @@ static void p54_rx_eeprom_readback(struct ieee80211_hw *dev, if (!priv->eeprom) return ; - memcpy(priv->eeprom, eeprom->data, le16_to_cpu(eeprom->len)); + if (priv->fw_var >= 0x509) { + memcpy(priv->eeprom, eeprom->v2.data, + le16_to_cpu(eeprom->v2.len)); + } else { + memcpy(priv->eeprom, eeprom->v1.data, + le16_to_cpu(eeprom->v1.len)); + } complete(&priv->eeprom_comp); } @@ -940,12 +946,18 @@ int p54_read_eeprom(struct ieee80211_hw *dev) struct p54_hdr *hdr = NULL; struct p54_eeprom_lm86 *eeprom_hdr; struct sk_buff *skb; - size_t eeprom_size = 0x2020, offset = 0, blocksize; + size_t eeprom_size = 0x2020, offset = 0, blocksize, maxblocksize; int ret = -ENOMEM; void *eeprom = NULL; - skb = p54_alloc_skb(dev, 0x8000, sizeof(*hdr) + sizeof(*eeprom_hdr) + - EEPROM_READBACK_LEN, + maxblocksize = EEPROM_READBACK_LEN; + if (priv->fw_var >= 0x509) + maxblocksize -= 0xc; + else + maxblocksize -= 0x4; + + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL, sizeof(*hdr) + + sizeof(*eeprom_hdr) + maxblocksize, P54_CONTROL_TYPE_EEPROM_READBACK, GFP_KERNEL); if (!skb) goto free; @@ -957,12 +969,19 @@ int p54_read_eeprom(struct ieee80211_hw *dev) goto free; eeprom_hdr = (struct p54_eeprom_lm86 *) skb_put(skb, - sizeof(*eeprom_hdr) + EEPROM_READBACK_LEN); + sizeof(*eeprom_hdr) + maxblocksize); while (eeprom_size) { - blocksize = min(eeprom_size, (size_t)EEPROM_READBACK_LEN); - eeprom_hdr->offset = cpu_to_le16(offset); - eeprom_hdr->len = cpu_to_le16(blocksize); + blocksize = min(eeprom_size, maxblocksize); + if (priv->fw_var < 0x509) { + eeprom_hdr->v1.offset = cpu_to_le16(offset); + eeprom_hdr->v1.len = cpu_to_le16(blocksize); + } else { + eeprom_hdr->v2.offset = cpu_to_le32(offset); + eeprom_hdr->v2.len = cpu_to_le16(blocksize); + eeprom_hdr->v2.magic2 = 0xf; + memcpy(eeprom_hdr->v2.magic, (const char *)"LOCK", 4); + } priv->tx(dev, skb, 0); if (!wait_for_completion_interruptible_timeout(&priv->eeprom_comp, HZ)) { diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h index d292ffbec08..5a68fdae773 100644 --- a/drivers/net/wireless/p54/p54common.h +++ b/drivers/net/wireless/p54/p54common.h @@ -246,9 +246,21 @@ struct memrecord { }; struct p54_eeprom_lm86 { - __le16 offset; - __le16 len; - u8 data[0]; + union { + struct { + __le16 offset; + __le16 len; + u8 data[0]; + } v1; + struct { + __le32 offset; + __le16 len; + u8 magic2; + u8 pad; + u8 magic[4]; + u8 data[0]; + } v2; + } __attribute__ ((packed)); } __attribute__ ((packed)); enum p54_rx_decrypt_status { -- cgit v1.2.3-70-g09d2 From b2023ddcfa6b79f26ef459867324f3d32b91aa07 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 29 Nov 2008 22:37:31 +0100 Subject: p54: refactoring Thanks to the introduction of "changed" flags, we no longer have to do the bookkeeping of p54's firmware state for everything. Thus we can cut down redundancy code. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54.h | 2 - drivers/net/wireless/p54/p54common.c | 158 +++++++++++++++++------------------ 2 files changed, 79 insertions(+), 81 deletions(-) (limited to 'drivers/net/wireless/p54/p54common.c') diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index ebe1ea1f565..d2dbb9e15d9 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -85,7 +85,6 @@ struct p54_common { struct mutex conf_mutex; u8 mac_addr[ETH_ALEN]; u8 bssid[ETH_ALEN]; - u16 mac_mode; struct pda_iq_autocal_entry *iq_autocal; unsigned int iq_autocal_len; struct pda_channel_output_limit *output_limit; @@ -95,7 +94,6 @@ struct p54_common { bool use_short_slot; u16 rxhw; u8 version; - u8 rx_antenna; unsigned int tx_hdr_len; unsigned int fw_var; unsigned int fw_interface; diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 1b5627d4062..06c8321f4e3 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -1334,11 +1334,12 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) return NETDEV_TX_BUSY; } -static int p54_setup_mac(struct ieee80211_hw *dev, u16 mode, const u8 *bssid) +static int p54_setup_mac(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; struct sk_buff *skb; struct p54_setup_mac *setup; + u16 mode; skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*setup) + sizeof(struct p54_hdr), P54_CONTROL_TYPE_SETUP, @@ -1347,14 +1348,31 @@ static int p54_setup_mac(struct ieee80211_hw *dev, u16 mode, const u8 *bssid) return -ENOMEM; setup = (struct p54_setup_mac *) skb_put(skb, sizeof(*setup)); - priv->mac_mode = mode; + if (dev->conf.radio_enabled) { + switch (priv->mode) { + case NL80211_IFTYPE_STATION: + mode = P54_FILTER_TYPE_STATION; + break; + case NL80211_IFTYPE_AP: + mode = P54_FILTER_TYPE_AP; + break; + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: + mode = P54_FILTER_TYPE_IBSS; + break; + default: + mode = P54_FILTER_TYPE_NONE; + break; + } + if (priv->filter_flags & FIF_PROMISC_IN_BSS) + mode |= P54_FILTER_TYPE_TRANSPARENT; + } else + mode = P54_FILTER_TYPE_RX_DISABLED; + setup->mac_mode = cpu_to_le16(mode); memcpy(setup->mac_addr, priv->mac_addr, ETH_ALEN); - if (!bssid) - memset(setup->bssid, ~0, ETH_ALEN); - else - memcpy(setup->bssid, bssid, ETH_ALEN); - setup->rx_antenna = priv->rx_antenna; + memcpy(setup->bssid, priv->bssid, ETH_ALEN); + setup->rx_antenna = 2; /* automatic */ setup->rx_align = 0; if (priv->fw_var < 0x500) { setup->v1.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask); @@ -1383,7 +1401,8 @@ static int p54_setup_mac(struct ieee80211_hw *dev, u16 mode, const u8 *bssid) return 0; } -static int p54_set_freq(struct ieee80211_hw *dev, u16 frequency) +static int p54_scan(struct ieee80211_hw *dev, u16 mode, u16 dwell, + u16 frequency) { struct p54_common *priv = dev->priv; struct sk_buff *skb; @@ -1400,8 +1419,8 @@ static int p54_set_freq(struct ieee80211_hw *dev, u16 frequency) chan = (struct p54_scan *) skb_put(skb, sizeof(*chan)); memset(chan->padding1, 0, sizeof(chan->padding1)); - chan->mode = cpu_to_le16(P54_SCAN_EXIT); - chan->dwell = cpu_to_le16(0x0); + chan->mode = cpu_to_le16(mode); + chan->dwell = cpu_to_le16(dwell); for (i = 0; i < priv->iq_autocal_len; i++) { if (priv->iq_autocal[i].freq != freq) @@ -1644,10 +1663,14 @@ static int p54_start(struct ieee80211_hw *dev) err = p54_init_stats(dev); if (err) goto out; - err = p54_setup_mac(dev, P54_FILTER_TYPE_NONE, NULL); - if (err) - goto out; + + memset(priv->bssid, ~0, ETH_ALEN); priv->mode = NL80211_IFTYPE_MONITOR; + err = p54_setup_mac(dev); + if (err) { + priv->mode = NL80211_IFTYPE_UNSPECIFIED; + goto out; + } out: mutex_unlock(&priv->conf_mutex); @@ -1700,27 +1723,8 @@ static int p54_add_interface(struct ieee80211_hw *dev, } memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); - - p54_setup_mac(dev, P54_FILTER_TYPE_NONE, NULL); - - switch (conf->type) { - case NL80211_IFTYPE_STATION: - p54_setup_mac(dev, P54_FILTER_TYPE_STATION, NULL); - break; - case NL80211_IFTYPE_AP: - p54_setup_mac(dev, P54_FILTER_TYPE_AP, priv->mac_addr); - break; - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_MESH_POINT: - p54_setup_mac(dev, P54_FILTER_TYPE_IBSS, NULL); - break; - default: - BUG(); /* impossible */ - break; - } - + p54_setup_mac(dev); p54_set_leds(dev, 1, 0, 0); - mutex_unlock(&priv->conf_mutex); return 0; } @@ -1733,9 +1737,10 @@ static void p54_remove_interface(struct ieee80211_hw *dev, mutex_lock(&priv->conf_mutex); if (priv->cached_beacon) p54_tx_cancel(dev, priv->cached_beacon); - p54_setup_mac(dev, P54_FILTER_TYPE_NONE, NULL); priv->mode = NL80211_IFTYPE_MONITOR; memset(priv->mac_addr, 0, ETH_ALEN); + memset(priv->bssid, 0, ETH_ALEN); + p54_setup_mac(dev); mutex_unlock(&priv->conf_mutex); } @@ -1746,11 +1751,21 @@ static int p54_config(struct ieee80211_hw *dev, u32 changed) struct ieee80211_conf *conf = &dev->conf; mutex_lock(&priv->conf_mutex); - priv->rx_antenna = 2; /* automatic */ - priv->output_power = conf->power_level << 2; - ret = p54_set_freq(dev, conf->channel->center_freq); - if (!ret) - ret = p54_set_edcf(dev); + if (changed & IEEE80211_CONF_CHANGE_POWER) + priv->output_power = conf->power_level << 2; + if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) { + ret = p54_setup_mac(dev); + if (ret) + goto out; + } + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { + ret = p54_scan(dev, P54_SCAN_EXIT, 0, + conf->channel->center_freq); + if (ret) + goto out; + } + +out: mutex_unlock(&priv->conf_mutex); return ret; } @@ -1763,36 +1778,31 @@ static int p54_config_interface(struct ieee80211_hw *dev, int ret = 0; mutex_lock(&priv->conf_mutex); - switch (priv->mode) { - case NL80211_IFTYPE_STATION: - ret = p54_setup_mac(dev, P54_FILTER_TYPE_STATION, conf->bssid); + if (conf->changed & IEEE80211_IFCC_BSSID) { + memcpy(priv->bssid, conf->bssid, ETH_ALEN); + ret = p54_setup_mac(dev); if (ret) goto out; - ret = p54_set_leds(dev, 1, - !is_multicast_ether_addr(conf->bssid), 0); + } + + if (conf->changed & IEEE80211_IFCC_BEACON) { + ret = p54_scan(dev, P54_SCAN_EXIT, 0, + dev->conf.channel->center_freq); if (ret) goto out; - memcpy(priv->bssid, conf->bssid, ETH_ALEN); - break; - case NL80211_IFTYPE_AP: - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_MESH_POINT: - memcpy(priv->bssid, conf->bssid, ETH_ALEN); - ret = p54_set_freq(dev, dev->conf.channel->center_freq); + ret = p54_setup_mac(dev); if (ret) goto out; - ret = p54_setup_mac(dev, priv->mac_mode, priv->bssid); + ret = p54_beacon_update(dev, vif); + if (ret) + goto out; + ret = p54_set_edcf(dev); if (ret) goto out; - if (conf->changed & IEEE80211_IFCC_BEACON) { - ret = p54_beacon_update(dev, vif); - if (ret) - goto out; - ret = p54_set_edcf(dev); - if (ret) - goto out; - } } + + ret = p54_set_leds(dev, 1, !is_multicast_ether_addr(priv->bssid), 0); + out: mutex_unlock(&priv->conf_mutex); return ret; @@ -1805,25 +1815,14 @@ static void p54_configure_filter(struct ieee80211_hw *dev, { struct p54_common *priv = dev->priv; - *total_flags &= FIF_BCN_PRBRESP_PROMISC | - FIF_PROMISC_IN_BSS | - FIF_FCSFAIL; + *total_flags &= FIF_PROMISC_IN_BSS | + (*total_flags & FIF_PROMISC_IN_BSS) ? + FIF_FCSFAIL : 0; priv->filter_flags = *total_flags; - if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { - if (*total_flags & FIF_BCN_PRBRESP_PROMISC) - p54_setup_mac(dev, priv->mac_mode, NULL); - else - p54_setup_mac(dev, priv->mac_mode, priv->bssid); - } - - if (changed_flags & FIF_PROMISC_IN_BSS) { - if (*total_flags & FIF_PROMISC_IN_BSS) - p54_setup_mac(dev, priv->mac_mode | 0x8, NULL); - else - p54_setup_mac(dev, priv->mac_mode & ~0x8, priv->bssid); - } + if (changed_flags & FIF_PROMISC_IN_BSS) + p54_setup_mac(dev); } static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue, @@ -1920,16 +1919,17 @@ static void p54_bss_info_changed(struct ieee80211_hw *dev, priv->basic_rate_mask = (info->basic_rates << 4); else priv->basic_rate_mask = info->basic_rates; - p54_setup_mac(dev, priv->mac_mode, priv->bssid); + p54_setup_mac(dev); if (priv->fw_var >= 0x500) - p54_set_freq(dev, dev->conf.channel->center_freq); + p54_scan(dev, P54_SCAN_EXIT, 0, + dev->conf.channel->center_freq); } if (changed & BSS_CHANGED_ASSOC) { if (info->assoc) { priv->aid = info->aid; priv->wakeup_timer = info->beacon_int * info->dtim_period * 5; - p54_setup_mac(dev, priv->mac_mode, priv->bssid); + p54_setup_mac(dev); } } -- cgit v1.2.3-70-g09d2 From 02e37ba1298359baa123cf71ffa03d92abd259b2 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 29 Nov 2008 22:39:08 +0100 Subject: p54: per-device names This patch replaces the static "p54:" strings in front of most printk's with their corresponding per-device names. It was always a bit of a hassle to check which device was generating all the messages. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 59 ++++++++++++++++++------------------ drivers/net/wireless/p54/p54usb.c | 43 +++++++++++++++----------- 2 files changed, 55 insertions(+), 47 deletions(-) (limited to 'drivers/net/wireless/p54/p54common.c') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 06c8321f4e3..89968a5bff8 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -158,21 +158,21 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) priv->fw_interface = be32_to_cpup((__be32 *) bootrec->data); switch (priv->fw_interface) { - case FW_FMAC: - printk(KERN_INFO "p54: FreeMAC firmware\n"); - break; - case FW_LM20: - printk(KERN_INFO "p54: LM20 firmware\n"); - break; case FW_LM86: - printk(KERN_INFO "p54: LM86 firmware\n"); - break; - case FW_LM87: - printk(KERN_INFO "p54: LM87 firmware\n"); + case FW_LM20: + case FW_LM87: { + char *iftype = (char *)bootrec->data; + printk(KERN_INFO "%s: p54 detected a LM%c%c " + "firmware\n", + wiphy_name(dev->wiphy), + iftype[2], iftype[3]); break; + } + case FW_FMAC: default: - printk(KERN_INFO "p54: unknown firmware\n"); - break; + printk(KERN_ERR "%s: unsupported firmware\n", + wiphy_name(dev->wiphy)); + return -ENODEV; } break; case BR_CODE_COMPONENT_VERSION: @@ -216,13 +216,15 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) } if (fw_version) - printk(KERN_INFO "p54: FW rev %s - Softmac protocol %x.%x\n", - fw_version, priv->fw_var >> 8, priv->fw_var & 0xff); + printk(KERN_INFO "%s: FW rev %s - Softmac protocol %x.%x\n", + wiphy_name(dev->wiphy), fw_version, + priv->fw_var >> 8, priv->fw_var & 0xff); if (priv->fw_var < 0x500) - printk(KERN_INFO "p54: you are using an obsolete firmware. " + printk(KERN_INFO "%s: you are using an obsolete firmware. " "visit http://wireless.kernel.org/en/users/Drivers/p54 " - "and grab one for \"kernel >= 2.6.28\"!\n"); + "and grab one for \"kernel >= 2.6.28\"!\n", + wiphy_name(dev->wiphy)); if (priv->fw_var >= 0x300) { /* Firmware supports QoS, use it! */ @@ -399,8 +401,9 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) err = p54_convert_rev1(dev, curve_data); break; default: - printk(KERN_ERR "p54: unknown curve data " + printk(KERN_ERR "%s: unknown curve data " "revision %d\n", + wiphy_name(dev->wiphy), curve_data->cal_method_rev); err = -ENODEV; break; @@ -460,7 +463,8 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) case PDR_PER_CHANNEL_BASEBAND_REGISTERS: break; default: - printk(KERN_INFO "p54: unknown eeprom code : 0x%x\n", + printk(KERN_INFO "%s: unknown eeprom code : 0x%x\n", + wiphy_name(dev->wiphy), le16_to_cpu(entry->code)); break; } @@ -470,7 +474,8 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) if (!synth || !priv->iq_autocal || !priv->output_limit || !priv->curve_data) { - printk(KERN_ERR "p54: not all required entries found in eeprom!\n"); + printk(KERN_ERR "%s: not all required entries found in eeprom!\n", + wiphy_name(dev->wiphy)); err = -EINVAL; goto err; } @@ -515,7 +520,8 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) priv->curve_data = NULL; } - printk(KERN_ERR "p54: eeprom parse failed!\n"); + printk(KERN_ERR "%s: eeprom parse failed!\n", + wiphy_name(dev->wiphy)); return err; } @@ -1573,28 +1579,23 @@ static int p54_beacon_tim(struct sk_buff *skb) struct ieee80211_mgmt *mgmt = (void *)skb->data; u8 *pos, *end; - if (skb->len <= sizeof(mgmt)) { - printk(KERN_ERR "p54: beacon is too short!\n"); + if (skb->len <= sizeof(mgmt)) return -EINVAL; - } pos = (u8 *)mgmt->u.beacon.variable; end = skb->data + skb->len; while (pos < end) { - if (pos + 2 + pos[1] > end) { - printk(KERN_ERR "p54: parsing beacon failed\n"); + if (pos + 2 + pos[1] > end) return -EINVAL; - } if (pos[0] == WLAN_EID_TIM) { u8 dtim_len = pos[1]; u8 dtim_period = pos[3]; u8 *next = pos + 2 + dtim_len; - if (dtim_len < 3) { - printk(KERN_ERR "p54: invalid dtim len!\n"); + if (dtim_len < 3) return -EINVAL; - } + memmove(pos, next, end - next); if (dtim_len > 3) diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index 21ba526a45b..e9630b94925 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -405,7 +405,8 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL); if (!buf) { - printk(KERN_ERR "p54usb: cannot allocate firmware upload buffer!\n"); + dev_err(&priv->udev->dev, "(p54usb) cannot allocate firmware" + "upload buffer!\n"); err = -ENOMEM; goto err_bufalloc; } @@ -413,13 +414,14 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) memcpy(buf, start_string, 4); err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 4); if (err) { - printk(KERN_ERR "p54usb: reset failed! (%d)\n", err); + dev_err(&priv->udev->dev, "(p54usb) reset failed! (%d)\n", err); goto err_reset; } err = request_firmware(&fw_entry, "isl3887usb", &priv->udev->dev); if (err) { - printk(KERN_ERR "p54usb: cannot find firmware (isl3887usb)\n"); + dev_err(&priv->udev->dev, "p54usb: cannot find firmware " + "(isl3887usb)\n"); err = request_firmware(&fw_entry, "isl3887usb_bare", &priv->udev->dev); if (err) @@ -474,7 +476,8 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size); if (err) { - printk(KERN_ERR "p54usb: firmware upload failed!\n"); + dev_err(&priv->udev->dev, "(p54usb) firmware " + "upload failed!\n"); goto err_upload_failed; } @@ -485,10 +488,9 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, fw_entry->data, fw_entry->size)); err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32)); if (err) { - printk(KERN_ERR "p54usb: firmware upload failed!\n"); + dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n"); goto err_upload_failed; } - timeout = jiffies + msecs_to_jiffies(1000); while (!(err = usb_bulk_msg(priv->udev, usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) { @@ -496,25 +498,27 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) break; if (alen > 5 && !memcmp(buf, "ERROR", 5)) { - printk(KERN_INFO "p54usb: firmware upload failed!\n"); err = -EINVAL; break; } if (time_after(jiffies, timeout)) { - printk(KERN_ERR "p54usb: firmware boot timed out!\n"); + dev_err(&priv->udev->dev, "(p54usb) firmware boot " + "timed out!\n"); err = -ETIMEDOUT; break; } } - if (err) + if (err) { + dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n"); goto err_upload_failed; + } buf[0] = 'g'; buf[1] = '\r'; err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2); if (err) { - printk(KERN_ERR "p54usb: firmware boot failed!\n"); + dev_err(&priv->udev->dev, "(p54usb) firmware boot failed!\n"); goto err_upload_failed; } @@ -554,13 +558,15 @@ static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev) buf = kmalloc(512, GFP_KERNEL); if (!buf) { - printk(KERN_ERR "p54usb: firmware buffer alloc failed!\n"); + dev_err(&priv->udev->dev, "(p54usb) firmware buffer " + "alloc failed!\n"); return -ENOMEM; } err = request_firmware(&fw_entry, "isl3886usb", &priv->udev->dev); if (err) { - printk(KERN_ERR "p54usb: cannot find firmware (isl3886usb)\n"); + dev_err(&priv->udev->dev, "(p54usb) cannot find firmware " + "(isl3886usb)\n"); err = request_firmware(&fw_entry, "isl3890usb", &priv->udev->dev); if (err) { @@ -685,8 +691,8 @@ static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev) err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len); if (err) { - printk(KERN_ERR "p54usb: firmware block upload " - "failed\n"); + dev_err(&priv->udev->dev, "(p54usb) firmware block " + "upload failed\n"); goto fail; } @@ -719,8 +725,8 @@ static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev) 0x002C | (unsigned long)&devreg->direct_mem_win); if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) || !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) { - printk(KERN_ERR "p54usb: firmware DMA transfer " - "failed\n"); + dev_err(&priv->udev->dev, "(p54usb) firmware DMA " + "transfer failed\n"); goto fail; } @@ -825,8 +831,9 @@ static int __devinit p54u_probe(struct usb_interface *intf, unsigned int i, recognized_pipes; dev = p54_init_common(sizeof(*priv)); + if (!dev) { - printk(KERN_ERR "p54usb: ieee80211 alloc failed\n"); + dev_err(&udev->dev, "(p54usb) ieee80211 alloc failed\n"); return -ENOMEM; } @@ -887,7 +894,7 @@ static int __devinit p54u_probe(struct usb_interface *intf, err = ieee80211_register_hw(dev); if (err) { - printk(KERN_ERR "p54usb: Cannot register netdevice\n"); + dev_err(&udev->dev, "(p54usb) Cannot register netdevice\n"); goto err_free_dev; } -- cgit v1.2.3-70-g09d2 From 89fad578a61810b7fdf8edd294890f3c0cde4390 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Tue, 9 Dec 2008 16:28:06 +0100 Subject: mac80211: integrate sta_notify_ps cmds into sta_notify This patch replaces the newly introduced sta_notify_ps function, which can be used to notify the driver about every power state transition for all associated stations, by integrating its functionality back into the original sta_notify callback. Signed-off-by: Christian Lamparter Acked-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/mac80211_hwsim.c | 4 ++++ drivers/net/wireless/p54/p54common.c | 18 ++++-------------- include/net/mac80211.h | 27 +++++++-------------------- net/mac80211/rx.c | 12 ++++++------ 4 files changed, 21 insertions(+), 40 deletions(-) (limited to 'drivers/net/wireless/p54/p54common.c') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 530648b3993..fd5a537ac51 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -522,6 +522,10 @@ static void mac80211_hwsim_sta_notify(struct ieee80211_hw *hw, case STA_NOTIFY_REMOVE: hwsim_clear_sta_magic(sta); break; + case STA_NOTIFY_SLEEP: + case STA_NOTIFY_AWAKE: + /* TODO: make good use of these flags */ + break; } } diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 89968a5bff8..409ae930d76 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -1051,19 +1051,6 @@ static int p54_sta_unlock(struct ieee80211_hw *dev, u8 *addr) return 0; } -static void p54_sta_notify_ps(struct ieee80211_hw *dev, - enum sta_notify_ps_cmd notify_cmd, - struct ieee80211_sta *sta) -{ - switch (notify_cmd) { - case STA_NOTIFY_AWAKE: - p54_sta_unlock(dev, sta->addr); - break; - default: - break; - } -} - static void p54_sta_notify(struct ieee80211_hw *dev, struct ieee80211_vif *vif, enum sta_notify_cmd notify_cmd, struct ieee80211_sta *sta) @@ -1076,6 +1063,10 @@ static void p54_sta_notify(struct ieee80211_hw *dev, struct ieee80211_vif *vif, * need to buffer frames for this station anymore. */ + p54_sta_unlock(dev, sta->addr); + break; + case STA_NOTIFY_AWAKE: + /* update the firmware's filter table */ p54_sta_unlock(dev, sta->addr); break; default: @@ -2027,7 +2018,6 @@ static const struct ieee80211_ops p54_ops = { .add_interface = p54_add_interface, .remove_interface = p54_remove_interface, .set_tim = p54_set_tim, - .sta_notify_ps = p54_sta_notify_ps, .sta_notify = p54_sta_notify, .set_key = p54_set_key, .config = p54_config, diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 5ecc686c1f1..046ce692a90 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -773,25 +773,16 @@ struct ieee80211_sta { * enum sta_notify_cmd - sta notify command * * Used with the sta_notify() callback in &struct ieee80211_ops, this - * indicates addition and removal of a station to station table. + * indicates addition and removal of a station to station table, + * or if a associated station made a power state transition. * * @STA_NOTIFY_ADD: a station was added to the station table * @STA_NOTIFY_REMOVE: a station being removed from the station table - */ -enum sta_notify_cmd { - STA_NOTIFY_ADD, STA_NOTIFY_REMOVE -}; - -/** - * enum sta_notify_ps_cmd - sta power save notify command - * - * Used with the sta_notify_ps() callback in &struct ieee80211_ops to - * notify the driver if a station made a power state transition. - * * @STA_NOTIFY_SLEEP: a station is now sleeping * @STA_NOTIFY_AWAKE: a sleeping station woke up */ -enum sta_notify_ps_cmd { +enum sta_notify_cmd { + STA_NOTIFY_ADD, STA_NOTIFY_REMOVE, STA_NOTIFY_SLEEP, STA_NOTIFY_AWAKE, }; @@ -1258,11 +1249,9 @@ enum ieee80211_ampdu_mlme_action { * * @set_rts_threshold: Configuration of RTS threshold (if device needs it) * - * @sta_notify: Notifies low level driver about addition or removal of an - * associated station, AP, IBSS/WDS/mesh peer etc. Must be atomic. - * - * @sta_ps_notify: Notifies low level driver about the power state transition - * of a associated station. Must be atomic. + * @sta_notify: Notifies low level driver about addition, removal or power + * state transition of an associated station, AP, IBSS/WDS/mesh peer etc. + * Must be atomic. * * @conf_tx: Configure TX queue parameters (EDCF (aifs, cw_min, cw_max), * bursting) for a hardware TX queue. @@ -1329,8 +1318,6 @@ struct ieee80211_ops { int (*set_rts_threshold)(struct ieee80211_hw *hw, u32 value); void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum sta_notify_cmd, struct ieee80211_sta *sta); - void (*sta_notify_ps)(struct ieee80211_hw *hw, - enum sta_notify_ps_cmd, struct ieee80211_sta *sta); int (*conf_tx)(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params); int (*get_tx_stats)(struct ieee80211_hw *hw, diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 14be095b852..23443de7ee4 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -658,9 +658,9 @@ static void ap_sta_ps_start(struct sta_info *sta) atomic_inc(&sdata->bss->num_sta_ps); set_and_clear_sta_flags(sta, WLAN_STA_PS, WLAN_STA_PSPOLL); - if (local->ops->sta_notify_ps) - local->ops->sta_notify_ps(local_to_hw(local), STA_NOTIFY_SLEEP, - &sta->sta); + if (local->ops->sta_notify) + local->ops->sta_notify(local_to_hw(local), &sdata->vif, + STA_NOTIFY_SLEEP, &sta->sta); #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "%s: STA %pM aid %d enters power save mode\n", sdata->dev->name, sta->sta.addr, sta->sta.aid); @@ -677,9 +677,9 @@ static int ap_sta_ps_end(struct sta_info *sta) atomic_dec(&sdata->bss->num_sta_ps); clear_sta_flags(sta, WLAN_STA_PS | WLAN_STA_PSPOLL); - if (local->ops->sta_notify_ps) - local->ops->sta_notify_ps(local_to_hw(local), STA_NOTIFY_AWAKE, - &sta->sta); + if (local->ops->sta_notify) + local->ops->sta_notify(local_to_hw(local), &sdata->vif, + STA_NOTIFY_AWAKE, &sta->sta); if (!skb_queue_empty(&sta->ps_tx_buf)) sta_info_clear_tim_bit(sta); -- cgit v1.2.3-70-g09d2 From 39ca5bb76f3382b1cb0062d75ec45abd1c46e6d2 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Tue, 9 Dec 2008 21:09:00 +0100 Subject: p54: enforce strict tx_queue limits The patch fixes an old FIXME in p54pci.c by moving the "queue full" check into the common library, where we can deal with it properly. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 22 +++++++++++++++++++++- drivers/net/wireless/p54/p54pci.c | 7 ------- 2 files changed, 21 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless/p54/p54common.c') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 409ae930d76..fac6b416e9e 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -874,7 +874,27 @@ static int p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, return -EINVAL; spin_lock_irqsave(&priv->tx_queue.lock, flags); + left = skb_queue_len(&priv->tx_queue); + if (unlikely(left >= 28)) { + /* + * The tx_queue is nearly full! + * We have throttle normal data traffic, because we must + * have a few spare slots for control frames left. + */ + ieee80211_stop_queues(dev); + + if (unlikely(left == 32)) { + /* + * The tx_queue is now really full. + * + * TODO: check if the device has crashed and reset it. + */ + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + return -ENOSPC; + } + } + while (left--) { u32 hole_size; info = IEEE80211_SKB_CB(entry); @@ -903,7 +923,7 @@ static int p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, if (!target_skb) { spin_unlock_irqrestore(&priv->tx_queue.lock, flags); ieee80211_stop_queues(dev); - return -ENOMEM; + return -ENOSPC; } info = IEEE80211_SKB_CB(skb); diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index d21c509325f..c28220e401b 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -332,13 +332,6 @@ static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb, P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE)); P54P_READ(dev_int); - - /* FIXME: unlikely to happen because the device usually runs out of - memory before we fill the ring up, but we can make it impossible */ - if (idx - device_idx > ARRAY_SIZE(ring_control->tx_data) - 2) { - p54_free_skb(dev, skb); - printk(KERN_INFO "%s: tx overflow.\n", wiphy_name(dev->wiphy)); - } } static void p54p_stop(struct ieee80211_hw *dev) -- cgit v1.2.3-70-g09d2 From 59651e89187293e88863891b821c7379391ef75c Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Tue, 9 Dec 2008 21:07:50 +0100 Subject: p54: fix oops on faulty devices This patch fixes an oops when the devices suddenly starts to receive martian data frames. bug reference: http://marc.info/?l=linux-wireless&m=122872280317635&w=2 Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/p54/p54common.c') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index fac6b416e9e..a4e99b02af0 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -540,6 +540,14 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) size_t header_len = sizeof(*hdr); u32 tsf32; + /* + * If the device is in a unspecified state we have to + * ignore all data frames. Else we could end up with a + * nasty crash. + */ + if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) + return 0; + if (!(hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_IN_FCS_GOOD))) { if (priv->filter_flags & FIF_FCSFAIL) rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; @@ -608,6 +616,12 @@ void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb) if (unlikely(!skb || !dev || !skb_queue_len(&priv->tx_queue))) return; + /* + * don't try to free an already unlinked skb + */ + if (unlikely((!skb->next) || (!skb->prev))) + return; + spin_lock_irqsave(&priv->tx_queue.lock, flags); info = IEEE80211_SKB_CB(skb); range = (void *)info->rate_driver_data; @@ -1695,19 +1709,18 @@ static void p54_stop(struct ieee80211_hw *dev) struct sk_buff *skb; mutex_lock(&priv->conf_mutex); + priv->mode = NL80211_IFTYPE_UNSPECIFIED; del_timer(&priv->stats_timer); p54_free_skb(dev, priv->cached_stats); priv->cached_stats = NULL; if (priv->cached_beacon) p54_tx_cancel(dev, priv->cached_beacon); + priv->stop(dev); while ((skb = skb_dequeue(&priv->tx_queue))) kfree_skb(skb); - priv->cached_beacon = NULL; - priv->stop(dev); priv->tsf_high32 = priv->tsf_low32 = 0; - priv->mode = NL80211_IFTYPE_UNSPECIFIED; mutex_unlock(&priv->conf_mutex); } -- cgit v1.2.3-70-g09d2 From 54fdb040b4760d5b2994d15c1371e297679420e9 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 13 Dec 2008 14:14:20 +0100 Subject: p54: move statistic timer update routine into a workqueue This patch moves a good chunk of code from the former statistic update timer routine into a workqueue, which is kindly provided by mac80211. Also as a nice side-effect we can lay the foundation for other essential housekeeping features we want to do in the future. e.g: - drain the (clogged) tx_queue. - initiate bursts. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54.h | 5 +- drivers/net/wireless/p54/p54common.c | 104 ++++++++++++++++++++--------------- drivers/net/wireless/p54/p54common.h | 5 ++ 3 files changed, 68 insertions(+), 46 deletions(-) (limited to 'drivers/net/wireless/p54/p54common.c') diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index d2dbb9e15d9..23b80ef4d01 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -71,6 +71,7 @@ struct p54_edcf_queue_param { #define FW_LM20 0x4c4d3230 struct p54_common { + struct ieee80211_hw *hw; u32 rx_start; u32 rx_end; struct sk_buff_head tx_queue; @@ -106,9 +107,7 @@ struct p54_common { struct ieee80211_tx_queue_stats tx_stats[8]; struct p54_edcf_queue_param qos_params[8]; struct ieee80211_low_level_stats stats; - struct timer_list stats_timer; - struct completion stats_comp; - struct sk_buff *cached_stats; + struct delayed_work work; struct sk_buff *cached_beacon; int noise; void *eeprom; diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index a4e99b02af0..36310f88187 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -589,6 +589,9 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) ieee80211_rx_irqsafe(dev, skb, &rx_status); + queue_delayed_work(dev->workqueue, &priv->work, + msecs_to_jiffies(P54_STATISTICS_UPDATE)); + return -1; } @@ -652,6 +655,27 @@ void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb) } EXPORT_SYMBOL_GPL(p54_free_skb); +static struct sk_buff *p54_find_tx_entry(struct ieee80211_hw *dev, + __le32 req_id) +{ + struct p54_common *priv = dev->priv; + struct sk_buff *entry = priv->tx_queue.next; + unsigned long flags; + + spin_lock_irqsave(&priv->tx_queue.lock, flags); + while (entry != (struct sk_buff *)&priv->tx_queue) { + struct p54_hdr *hdr = (struct p54_hdr *) entry->data; + + if (hdr->req_id == req_id) { + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + return entry; + } + entry = entry->next; + } + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + return NULL; +} + static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54_common *priv = dev->priv; @@ -775,8 +799,12 @@ static void p54_rx_stats(struct ieee80211_hw *dev, struct sk_buff *skb) struct p54_common *priv = dev->priv; struct p54_hdr *hdr = (struct p54_hdr *) skb->data; struct p54_statistics *stats = (struct p54_statistics *) hdr->data; - u32 tsf32 = le32_to_cpu(stats->tsf32); + u32 tsf32; + + if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) + return ; + tsf32 = le32_to_cpu(stats->tsf32); if (tsf32 < priv->tsf_low32) priv->tsf_high32++; priv->tsf_low32 = tsf32; @@ -786,9 +814,8 @@ static void p54_rx_stats(struct ieee80211_hw *dev, struct sk_buff *skb) priv->stats.dot11FCSErrorCount = le32_to_cpu(stats->rx_bad_fcs); priv->noise = p54_rssi_to_dbm(dev, le32_to_cpu(stats->noise)); - complete(&priv->stats_comp); - mod_timer(&priv->stats_timer, jiffies + 5 * HZ); + p54_free_skb(dev, p54_find_tx_entry(dev, hdr->req_id)); } static void p54_rx_trap(struct ieee80211_hw *dev, struct sk_buff *skb) @@ -897,6 +924,8 @@ static int p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, * have a few spare slots for control frames left. */ ieee80211_stop_queues(dev); + queue_delayed_work(dev->workqueue, &priv->work, + msecs_to_jiffies(P54_TX_TIMEOUT)); if (unlikely(left == 32)) { /* @@ -1354,6 +1383,10 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) if (unlikely(p54_assign_address(dev, skb, hdr, skb->len + tim_len))) goto err; priv->tx(dev, skb, 0); + + queue_delayed_work(dev->workqueue, &priv->work, + msecs_to_jiffies(P54_TX_FRAME_LIFETIME)); + return 0; err: @@ -1579,20 +1612,6 @@ static int p54_set_edcf(struct ieee80211_hw *dev) return 0; } -static int p54_init_stats(struct ieee80211_hw *dev) -{ - struct p54_common *priv = dev->priv; - - priv->cached_stats = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL, - sizeof(struct p54_hdr) + sizeof(struct p54_statistics), - P54_CONTROL_TYPE_STAT_READBACK, GFP_KERNEL); - if (!priv->cached_stats) - return -ENOMEM; - - mod_timer(&priv->stats_timer, jiffies + HZ); - return 0; -} - static int p54_beacon_tim(struct sk_buff *skb) { /* @@ -1684,9 +1703,6 @@ static int p54_start(struct ieee80211_hw *dev) P54_SET_QUEUE(priv->qos_params[2], 0x0003, 0x000f, 0x03ff, 0); P54_SET_QUEUE(priv->qos_params[3], 0x0007, 0x000f, 0x03ff, 0); err = p54_set_edcf(dev); - if (err) - goto out; - err = p54_init_stats(dev); if (err) goto out; @@ -1698,6 +1714,8 @@ static int p54_start(struct ieee80211_hw *dev) goto out; } + queue_delayed_work(dev->workqueue, &priv->work, 0); + out: mutex_unlock(&priv->conf_mutex); return err; @@ -1710,9 +1728,7 @@ static void p54_stop(struct ieee80211_hw *dev) mutex_lock(&priv->conf_mutex); priv->mode = NL80211_IFTYPE_UNSPECIFIED; - del_timer(&priv->stats_timer); - p54_free_skb(dev, priv->cached_stats); - priv->cached_stats = NULL; + cancel_delayed_work_sync(&priv->work); if (priv->cached_beacon) p54_tx_cancel(dev, priv->cached_beacon); @@ -1889,14 +1905,29 @@ static int p54_init_xbow_synth(struct ieee80211_hw *dev) return 0; } -static void p54_statistics_timer(unsigned long data) +static void p54_work(struct work_struct *work) { - struct ieee80211_hw *dev = (struct ieee80211_hw *) data; - struct p54_common *priv = dev->priv; + struct p54_common *priv = container_of(work, struct p54_common, + work.work); + struct ieee80211_hw *dev = priv->hw; + struct sk_buff *skb; + + if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) + return ; + + /* + * TODO: walk through tx_queue and do the following tasks + * 1. initiate bursts. + * 2. cancel stuck frames / reset the device if necessary. + */ - BUG_ON(!priv->cached_stats); + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL, sizeof(struct p54_hdr) + + sizeof(struct p54_statistics), + P54_CONTROL_TYPE_STAT_READBACK, GFP_KERNEL); + if (!skb) + return ; - priv->tx(dev, priv->cached_stats, 0); + priv->tx(dev, skb, 0); } static int p54_get_stats(struct ieee80211_hw *dev, @@ -1904,17 +1935,7 @@ static int p54_get_stats(struct ieee80211_hw *dev, { struct p54_common *priv = dev->priv; - del_timer(&priv->stats_timer); - p54_statistics_timer((unsigned long)dev); - - if (!wait_for_completion_interruptible_timeout(&priv->stats_comp, HZ)) { - printk(KERN_ERR "%s: device does not respond!\n", - wiphy_name(dev->wiphy)); - return -EBUSY; - } - memcpy(stats, &priv->stats, sizeof(*stats)); - return 0; } @@ -2072,6 +2093,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) return NULL; priv = dev->priv; + priv->hw = dev; priv->mode = NL80211_IFTYPE_UNSPECIFIED; priv->basic_rate_mask = 0x15f; skb_queue_head_init(&priv->tx_queue); @@ -2107,9 +2129,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) mutex_init(&priv->conf_mutex); init_completion(&priv->eeprom_comp); - init_completion(&priv->stats_comp); - setup_timer(&priv->stats_timer, p54_statistics_timer, - (unsigned long)dev); + INIT_DELAYED_WORK(&priv->work, p54_work); return dev; } @@ -2118,8 +2138,6 @@ EXPORT_SYMBOL_GPL(p54_init_common); void p54_free_common(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; - del_timer(&priv->stats_timer); - kfree_skb(priv->cached_stats); kfree(priv->iq_autocal); kfree(priv->output_limit); kfree(priv->curve_data); diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h index 5a68fdae773..06e1643cc29 100644 --- a/drivers/net/wireless/p54/p54common.h +++ b/drivers/net/wireless/p54/p54common.h @@ -355,6 +355,11 @@ struct p54_tx_data { u8 align[0]; } __attribute__ ((packed)); +/* unit is ms */ +#define P54_TX_FRAME_LIFETIME 2000 +#define P54_TX_TIMEOUT 4000 +#define P54_STATISTICS_UPDATE 5000 + #define P54_FILTER_TYPE_NONE 0 #define P54_FILTER_TYPE_STATION BIT(0) #define P54_FILTER_TYPE_IBSS BIT(1) -- cgit v1.2.3-70-g09d2 From ee370ceda823435fe75be7dd4ed7b0e3dc3108b9 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 13 Dec 2008 16:45:38 +0100 Subject: p54: update ACK failure statistic counter in real-time Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless/p54/p54common.c') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 36310f88187..ddb858608a5 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -720,6 +720,7 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) entry_hdr = (struct p54_hdr *) entry->data; entry_data = (struct p54_tx_data *) entry_hdr->data; priv->tx_stats[entry_data->hw_queue].len--; + priv->stats.dot11ACKFailureCount += payload->tries - 1; if (unlikely(entry == priv->cached_beacon)) { kfree_skb(entry); -- cgit v1.2.3-70-g09d2 From 69ba3e5d74a467a64248cd90ccafb524b1fddcb5 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sun, 14 Dec 2008 14:45:30 +0100 Subject: p54: more accurate rssi to dBm conversion This patch replaces the static rssi auto calibration data with more precise values out of the device's eeprom. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54.h | 8 +++++ drivers/net/wireless/p54/p54common.c | 69 ++++++++++++++++++++++++++---------- drivers/net/wireless/p54/p54common.h | 17 ++++----- 3 files changed, 68 insertions(+), 26 deletions(-) (limited to 'drivers/net/wireless/p54/p54common.c') diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index 23b80ef4d01..e0a68815a47 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -61,6 +61,13 @@ struct p54_edcf_queue_param { __le16 txop; } __attribute__ ((packed)); +struct p54_rssi_linear_approximation { + s16 mul; + s16 add; + s16 longbow_unkn; + s16 longbow_unk2; +}; + #define EEPROM_READBACK_LEN 0x3fc #define ISL38XX_DEV_FIRMWARE_ADDR 0x20000 @@ -91,6 +98,7 @@ struct p54_common { struct pda_channel_output_limit *output_limit; unsigned int output_limit_len; struct pda_pa_curve_data *curve_data; + struct p54_rssi_linear_approximation rssical_db[IEEE80211_NUM_BANDS]; unsigned int filter_flags; bool use_short_slot; u16 rxhw; diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index ddb858608a5..05eb677aa3e 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -335,6 +335,36 @@ static const char *p54_rf_chips[] = { "NULL", "Duette3", "Duette2", "Frisbee", "Xbow", "Longbow", "NULL", "NULL" }; static int p54_init_xbow_synth(struct ieee80211_hw *dev); +static void p54_parse_rssical(struct ieee80211_hw *dev, void *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; + + if (len != (entry_size * num_entries)) { + printk(KERN_ERR "%s: unknown rssi calibration data packing " + " type:(%x) len:%d.\n", + wiphy_name(dev->wiphy), type, len); + + print_hex_dump_bytes("rssical:", DUMP_PREFIX_NONE, + data, len); + + printk(KERN_ERR "%s: please report this issue.\n", + wiphy_name(dev->wiphy)); + return; + } + + 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); + } +} + static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) { struct p54_common *priv = dev->priv; @@ -434,6 +464,12 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) case PDR_HARDWARE_PLATFORM_COMPONENT_ID: priv->version = *(u8 *)(entry->data + 1); break; + 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)); + break; case PDR_END: /* make it overrun */ entry_len = len; @@ -453,10 +489,7 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) case PDR_DEFAULT_COUNTRY: case PDR_ANTENNA_GAIN: case PDR_PRISM_INDIGO_PA_CALIBRATION_DATA: - case PDR_RSSI_LINEAR_APPROXIMATION: - case PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND: case PDR_REGULATORY_POWER_LIMITS: - case PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED: case PDR_RADIATED_TRANSMISSION_CORRECTION: case PDR_PRISM_TX_IQ_CALIBRATION: case PDR_BASEBAND_REGISTERS: @@ -527,8 +560,11 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) static int p54_rssi_to_dbm(struct ieee80211_hw *dev, int rssi) { - /* TODO: get the rssi_add & rssi_mul data from the eeprom */ - return ((rssi * 0x83) / 64 - 400) / 4; + struct p54_common *priv = dev->priv; + int band = dev->conf.channel->band; + + return ((rssi * priv->rssical_db[band].mul) / 64 + + priv->rssical_db[band].add) / 4; } static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) @@ -1466,15 +1502,15 @@ static int p54_setup_mac(struct ieee80211_hw *dev) return 0; } -static int p54_scan(struct ieee80211_hw *dev, u16 mode, u16 dwell, - u16 frequency) +static int p54_scan(struct ieee80211_hw *dev, u16 mode, u16 dwell) { struct p54_common *priv = dev->priv; struct sk_buff *skb; struct p54_scan *chan; unsigned int i; void *entry; - __le16 freq = cpu_to_le16(frequency); + __le16 freq = cpu_to_le16(dev->conf.channel->center_freq); + int band = dev->conf.channel->band; skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*chan) + sizeof(struct p54_hdr), P54_CONTROL_TYPE_SCAN, @@ -1535,11 +1571,11 @@ static int p54_scan(struct ieee80211_hw *dev, u16 mode, u16 dwell, } if (priv->fw_var < 0x500) { - chan->v1.rssical_mul = cpu_to_le16(130); - chan->v1.rssical_add = cpu_to_le16(0xfe70); + chan->v1_rssi.mul = cpu_to_le16(priv->rssical_db[band].mul); + chan->v1_rssi.add = cpu_to_le16(priv->rssical_db[band].add); } else { - chan->v2.rssical_mul = cpu_to_le16(130); - chan->v2.rssical_add = cpu_to_le16(0xfe70); + chan->v2.rssi.mul = cpu_to_le16(priv->rssical_db[band].mul); + chan->v2.rssi.add = cpu_to_le16(priv->rssical_db[band].add); chan->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask); memset(chan->v2.rts_rates, 0, 8); } @@ -1801,8 +1837,7 @@ static int p54_config(struct ieee80211_hw *dev, u32 changed) goto out; } if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { - ret = p54_scan(dev, P54_SCAN_EXIT, 0, - conf->channel->center_freq); + ret = p54_scan(dev, P54_SCAN_EXIT, 0); if (ret) goto out; } @@ -1828,8 +1863,7 @@ static int p54_config_interface(struct ieee80211_hw *dev, } if (conf->changed & IEEE80211_IFCC_BEACON) { - ret = p54_scan(dev, P54_SCAN_EXIT, 0, - dev->conf.channel->center_freq); + ret = p54_scan(dev, P54_SCAN_EXIT, 0); if (ret) goto out; ret = p54_setup_mac(dev); @@ -1968,8 +2002,7 @@ static void p54_bss_info_changed(struct ieee80211_hw *dev, priv->basic_rate_mask = info->basic_rates; p54_setup_mac(dev); if (priv->fw_var >= 0x500) - p54_scan(dev, P54_SCAN_EXIT, 0, - dev->conf.channel->center_freq); + p54_scan(dev, P54_SCAN_EXIT, 0); } if (changed & BSS_CHANGED_ASSOC) { if (info->assoc) { diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h index 06e1643cc29..6c824e40f3b 100644 --- a/drivers/net/wireless/p54/p54common.h +++ b/drivers/net/wireless/p54/p54common.h @@ -178,6 +178,11 @@ struct pda_pa_curve_data { u8 data[0]; } __attribute__ ((packed)); +struct pda_rssi_cal_entry { + __le16 mul; + __le16 add; +} __attribute__ ((packed)); + /* * this defines the PDR codes used to build PDAs as defined in document * number 553155. The current implementation mirrors version 1.1 of the @@ -429,22 +434,18 @@ struct p54_scan { u8 dup_16qam; u8 dup_64qam; union { - struct { - __le16 rssical_mul; - __le16 rssical_add; - } v1 __attribute__ ((packed)); + struct pda_rssi_cal_entry v1_rssi; struct { __le32 basic_rate_mask; u8 rts_rates[8]; - __le16 rssical_mul; - __le16 rssical_add; + struct pda_rssi_cal_entry rssi; } v2 __attribute__ ((packed)); } __attribute__ ((packed)); } __attribute__ ((packed)); -#define P54_SCAN_V1_LEN (sizeof(struct p54_scan)-12) -#define P54_SCAN_V2_LEN (sizeof(struct p54_scan)) +#define P54_SCAN_V1_LEN 0x70 +#define P54_SCAN_V2_LEN 0x7c struct p54_led { __le16 mode; -- cgit v1.2.3-70-g09d2 From 0a5ec96ad68516582023a877aceff9db7636d141 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sun, 14 Dec 2008 15:05:42 +0100 Subject: p54: remove free_on_tx parameter This patch simplifies the tx code a bit and will be necessary for the upcoming stlc45xx<->p54 port. In detail: we no longer have to tell all back-end drivers directly, if we want to free a frame right after it was send to the firmware, or if we do it in the library callback later. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54.h | 10 ++++++++-- drivers/net/wireless/p54/p54common.c | 26 ++++++++++++------------- drivers/net/wireless/p54/p54common.h | 3 --- drivers/net/wireless/p54/p54pci.c | 12 +++++------- drivers/net/wireless/p54/p54usb.c | 37 +++++++++++------------------------- 5 files changed, 37 insertions(+), 51 deletions(-) (limited to 'drivers/net/wireless/p54/p54common.c') diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index e0a68815a47..ab79e32f0b2 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -44,6 +44,9 @@ enum p54_control_frame_types { P54_CONTROL_TYPE_BT_OPTIONS = 35 }; +#define P54_HDR_FLAG_CONTROL BIT(15) +#define P54_HDR_FLAG_CONTROL_OPSET (BIT(15) + BIT(0)) + struct p54_hdr { __le16 flags; __le16 len; @@ -54,6 +57,10 @@ struct p54_hdr { u8 data[0]; } __attribute__ ((packed)); +#define FREE_AFTER_TX(skb) \ + ((((struct p54_hdr *) ((struct sk_buff *) skb)->data)-> \ + flags) == cpu_to_le16(P54_HDR_FLAG_CONTROL_OPSET)) + struct p54_edcf_queue_param { __le16 aifs; __le16 cwmin; @@ -82,8 +89,7 @@ struct p54_common { u32 rx_start; u32 rx_end; struct sk_buff_head tx_queue; - void (*tx)(struct ieee80211_hw *dev, struct sk_buff *skb, - int free_on_tx); + void (*tx)(struct ieee80211_hw *dev, struct sk_buff *skb); int (*open)(struct ieee80211_hw *dev); void (*stop)(struct ieee80211_hw *dev); int mode; diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 05eb677aa3e..82354b974a0 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -683,7 +683,7 @@ void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb) freed = priv->rx_end - last_addr; __skb_unlink(skb, &priv->tx_queue); spin_unlock_irqrestore(&priv->tx_queue.lock, flags); - kfree_skb(skb); + dev_kfree_skb_any(skb); if (freed >= priv->headroom + sizeof(struct p54_hdr) + 48 + IEEE80211_MAX_RTS_THRESHOLD + priv->tailroom) @@ -1088,7 +1088,7 @@ int p54_read_eeprom(struct ieee80211_hw *dev) eeprom_hdr->v2.magic2 = 0xf; memcpy(eeprom_hdr->v2.magic, (const char *)"LOCK", 4); } - priv->tx(dev, skb, 0); + priv->tx(dev, skb); if (!wait_for_completion_interruptible_timeout(&priv->eeprom_comp, HZ)) { printk(KERN_ERR "%s: device does not respond!\n", @@ -1129,7 +1129,7 @@ static int p54_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta, tim = (struct p54_tim *) skb_put(skb, sizeof(*tim)); tim->count = 1; tim->entry[0] = cpu_to_le16(set ? (sta->aid | 0x8000) : sta->aid); - priv->tx(dev, skb, 1); + priv->tx(dev, skb); return 0; } @@ -1147,7 +1147,7 @@ static int p54_sta_unlock(struct ieee80211_hw *dev, u8 *addr) sta = (struct p54_sta_unlock *)skb_put(skb, sizeof(*sta)); memcpy(sta->addr, addr, ETH_ALEN); - priv->tx(dev, skb, 1); + priv->tx(dev, skb); return 0; } @@ -1190,7 +1190,7 @@ static int p54_tx_cancel(struct ieee80211_hw *dev, struct sk_buff *entry) hdr = (void *)entry->data; cancel = (struct p54_txcancel *)skb_put(skb, sizeof(*cancel)); cancel->req_id = hdr->req_id; - priv->tx(dev, skb, 1); + priv->tx(dev, skb); return 0; } @@ -1419,7 +1419,7 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) /* modifies skb->cb and with it info, so must be last! */ if (unlikely(p54_assign_address(dev, skb, hdr, skb->len + tim_len))) goto err; - priv->tx(dev, skb, 0); + priv->tx(dev, skb); queue_delayed_work(dev->workqueue, &priv->work, msecs_to_jiffies(P54_TX_FRAME_LIFETIME)); @@ -1498,7 +1498,7 @@ static int p54_setup_mac(struct ieee80211_hw *dev) setup->v2.lpf_bandwidth = cpu_to_le16(65535); setup->v2.osc_start_delay = cpu_to_le16(65535); } - priv->tx(dev, skb, 1); + priv->tx(dev, skb); return 0; } @@ -1579,7 +1579,7 @@ static int p54_scan(struct ieee80211_hw *dev, u16 mode, u16 dwell) chan->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask); memset(chan->v2.rts_rates, 0, 8); } - priv->tx(dev, skb, 1); + priv->tx(dev, skb); return 0; err: @@ -1605,7 +1605,7 @@ static int p54_set_leds(struct ieee80211_hw *dev, int mode, int link, int act) led->led_permanent = cpu_to_le16(link); led->led_temporary = cpu_to_le16(act); led->duration = cpu_to_le16(1000); - priv->tx(dev, skb, 1); + priv->tx(dev, skb); return 0; } @@ -1645,7 +1645,7 @@ static int p54_set_edcf(struct ieee80211_hw *dev) edcf->flags = 0; memset(edcf->mapping, 0, sizeof(edcf->mapping)); memcpy(edcf->queue, priv->qos_params, sizeof(edcf->queue)); - priv->tx(dev, skb, 1); + priv->tx(dev, skb); return 0; } @@ -1936,7 +1936,7 @@ static int p54_init_xbow_synth(struct ieee80211_hw *dev) xbow->magic2 = cpu_to_le16(0x2); xbow->freq = cpu_to_le16(5390); memset(xbow->padding, 0, sizeof(xbow->padding)); - priv->tx(dev, skb, 1); + priv->tx(dev, skb); return 0; } @@ -1962,7 +1962,7 @@ static void p54_work(struct work_struct *work) if (!skb) return ; - priv->tx(dev, skb, 0); + priv->tx(dev, skb); } static int p54_get_stats(struct ieee80211_hw *dev, @@ -2094,7 +2094,7 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, [NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]), 8); } - priv->tx(dev, skb, 1); + priv->tx(dev, skb); mutex_unlock(&priv->conf_mutex); return 0; } diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h index 6c824e40f3b..f5729de83fe 100644 --- a/drivers/net/wireless/p54/p54common.h +++ b/drivers/net/wireless/p54/p54common.h @@ -84,9 +84,6 @@ struct bootrec_desc { #define BR_CODE_END_OF_BRA 0xFF0000FF #define LEGACY_BR_CODE_END_OF_BRA 0xFFFFFFFF -#define P54_HDR_FLAG_CONTROL BIT(15) -#define P54_HDR_FLAG_CONTROL_OPSET (BIT(15) + BIT(0)) - #define P54_HDR_FLAG_DATA_ALIGN BIT(14) #define P54_HDR_FLAG_DATA_OUT_PROMISC BIT(0) #define P54_HDR_FLAG_DATA_OUT_TIMESTAMP BIT(1) diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index c28220e401b..aa367a0ddc4 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -227,7 +227,9 @@ static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index, while (i != idx) { desc = &ring[i]; - p54_free_skb(dev, tx_buf[i]); + if (tx_buf[i]) + if (FREE_AFTER_TX((struct sk_buff *) tx_buf[i])) + p54_free_skb(dev, tx_buf[i]); tx_buf[i] = NULL; pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr), @@ -298,8 +300,7 @@ static irqreturn_t p54p_interrupt(int irq, void *dev_id) return reg ? IRQ_HANDLED : IRQ_NONE; } -static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb, - int free_on_tx) +static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54p_priv *priv = dev->priv; struct p54p_ring_control *ring_control = priv->ring_control; @@ -314,6 +315,7 @@ static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb, idx = le32_to_cpu(ring_control->host_idx[1]); i = idx % ARRAY_SIZE(ring_control->tx_data); + priv->tx_buf_data[i] = skb; mapping = pci_map_single(priv->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); desc = &ring_control->tx_data[i]; @@ -324,10 +326,6 @@ static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb, wmb(); ring_control->host_idx[1] = cpu_to_le32(idx + 1); - - if (free_on_tx) - priv->tx_buf_data[i] = skb; - spin_unlock_irqrestore(&priv->lock, flags); P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE)); diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index c2789e53b98..17f89c7eb09 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -138,22 +138,16 @@ static void p54u_rx_cb(struct urb *urb) } } -static void p54u_tx_reuse_skb_cb(struct urb *urb) -{ - struct sk_buff *skb = urb->context; - struct p54u_priv *priv = (struct p54u_priv *)((struct ieee80211_hw *) - usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)))->priv; - - skb_pull(skb, priv->common.tx_hdr_len); -} - -static void p54u_tx_free_skb_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 *) usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)); + struct p54u_priv *priv = dev->priv; - p54_free_skb(dev, skb); + skb_pull(skb, priv->common.tx_hdr_len); + if (FREE_AFTER_TX(skb)) + p54_free_skb(dev, skb); } static void p54u_tx_dummy_cb(struct urb *urb) { } @@ -213,8 +207,7 @@ static int p54u_init_urbs(struct ieee80211_hw *dev) return ret; } -static void p54u_tx_3887(struct ieee80211_hw *dev, struct sk_buff *skb, - int free_on_tx) +static void p54u_tx_3887(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54u_priv *priv = dev->priv; struct urb *addr_urb, *data_urb; @@ -236,9 +229,7 @@ static void p54u_tx_3887(struct ieee80211_hw *dev, struct sk_buff *skb, p54u_tx_dummy_cb, dev); usb_fill_bulk_urb(data_urb, priv->udev, usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), - skb->data, skb->len, - free_on_tx ? p54u_tx_free_skb_cb : - p54u_tx_reuse_skb_cb, skb); + skb->data, skb->len, p54u_tx_cb, skb); usb_anchor_urb(addr_urb, &priv->submitted); err = usb_submit_urb(addr_urb, GFP_ATOMIC); @@ -273,8 +264,7 @@ static __le32 p54u_lm87_chksum(const __le32 *data, size_t length) return cpu_to_le32(chk); } -static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb, - int free_on_tx) +static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54u_priv *priv = dev->priv; struct urb *data_urb; @@ -293,9 +283,7 @@ static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb, usb_fill_bulk_urb(data_urb, priv->udev, usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), - skb->data, skb->len, - free_on_tx ? p54u_tx_free_skb_cb : - p54u_tx_reuse_skb_cb, skb); + skb->data, skb->len, p54u_tx_cb, skb); usb_anchor_urb(data_urb, &priv->submitted); if (usb_submit_urb(data_urb, GFP_ATOMIC)) { @@ -306,8 +294,7 @@ static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb, usb_free_urb(data_urb); } -static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb, - int free_on_tx) +static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54u_priv *priv = dev->priv; struct urb *int_urb, *data_urb; @@ -354,9 +341,7 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb, usb_fill_bulk_urb(data_urb, priv->udev, usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), - skb->data, skb->len, - free_on_tx ? p54u_tx_free_skb_cb : - p54u_tx_reuse_skb_cb, skb); + skb->data, skb->len, p54u_tx_cb, skb); usb_anchor_urb(int_urb, &priv->submitted); err = usb_submit_urb(int_urb, GFP_ATOMIC); -- cgit v1.2.3-70-g09d2