diff --git a/[refs] b/[refs] index e3695e477bdf..992cc58aa312 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 64463da913bc8f791980ba28d93ac5e716ab9cc5 +refs/heads/master: 89612124d6d62230043ebd827a2b54ea5ea5280c diff --git a/trunk/Documentation/DocBook/mac80211.tmpl b/trunk/Documentation/DocBook/mac80211.tmpl index affb15a344a1..f3f37f141dbd 100644 --- a/trunk/Documentation/DocBook/mac80211.tmpl +++ b/trunk/Documentation/DocBook/mac80211.tmpl @@ -144,7 +144,7 @@ usage should require reading the full document. this though and the recommendation to allow only a single interface in STA mode at first! -!Finclude/net/mac80211.h ieee80211_vif +!Finclude/net/mac80211.h ieee80211_if_init_conf @@ -234,6 +234,7 @@ usage should require reading the full document. Multiple queues and QoS support TBD !Finclude/net/mac80211.h ieee80211_tx_queue_params +!Finclude/net/mac80211.h ieee80211_tx_queue_stats diff --git a/trunk/Documentation/feature-removal-schedule.txt b/trunk/Documentation/feature-removal-schedule.txt index 86f2ec90af87..591e94448e63 100644 --- a/trunk/Documentation/feature-removal-schedule.txt +++ b/trunk/Documentation/feature-removal-schedule.txt @@ -88,6 +88,27 @@ Who: Luis R. Rodriguez --------------------------- +What: CONFIG_WIRELESS_OLD_REGULATORY - old static regulatory information +When: March 2010 / desktop catchup + +Why: The old regulatory infrastructure has been replaced with a new one + which does not require statically defined regulatory domains. We do + not want to keep static regulatory domains in the kernel due to the + the dynamic nature of regulatory law and localization. We kept around + the old static definitions for the regulatory domains of: + + * US + * JP + * EU + + and used by default the US when CONFIG_WIRELESS_OLD_REGULATORY was + set. We will remove this option once the standard Linux desktop catches + up with the new userspace APIs we have implemented. + +Who: Luis R. Rodriguez + +--------------------------- + What: dev->power.power_state When: July 2007 Why: Broken design for runtime control over driver power states, confusing diff --git a/trunk/Documentation/networking/regulatory.txt b/trunk/Documentation/networking/regulatory.txt index 9551622d0a7b..ee31369e9e5b 100644 --- a/trunk/Documentation/networking/regulatory.txt +++ b/trunk/Documentation/networking/regulatory.txt @@ -188,27 +188,3 @@ Then in some part of your code after your wiphy has been registered: &mydriver_jp_regdom.reg_rules[i], sizeof(struct ieee80211_reg_rule)); regulatory_struct_hint(rd); - -Statically compiled regulatory database ---------------------------------------- - -In most situations the userland solution using CRDA as described -above is the preferred solution. However in some cases a set of -rules built into the kernel itself may be desirable. To account -for this situation, a configuration option has been provided -(i.e. CONFIG_CFG80211_INTERNAL_REGDB). With this option enabled, -the wireless database information contained in net/wireless/db.txt is -used to generate a data structure encoded in net/wireless/regdb.c. -That option also enables code in net/wireless/reg.c which queries -the data in regdb.c as an alternative to using CRDA. - -The file net/wireless/db.txt should be kept up-to-date with the db.txt -file available in the git repository here: - - git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-regdb.git - -Again, most users in most situations should be using the CRDA package -provided with their distribution, and in most other situations users -should be building and using CRDA on their own rather than using -this option. If you are not absolutely sure that you should be using -CONFIG_CFG80211_INTERNAL_REGDB then _DO_NOT_USE_IT_. diff --git a/trunk/MAINTAINERS b/trunk/MAINTAINERS index 2b4a4d2f2ece..ea781c1cfb5a 100644 --- a/trunk/MAINTAINERS +++ b/trunk/MAINTAINERS @@ -5863,7 +5863,7 @@ S: Maintained F: drivers/input/misc/wistron_btns.c WL1251 WIRELESS DRIVER -M: Kalle Valo +M: Kalle Valo L: linux-wireless@vger.kernel.org W: http://wireless.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git diff --git a/trunk/arch/powerpc/configs/ppc64_defconfig b/trunk/arch/powerpc/configs/ppc64_defconfig index 070587ae4f74..252401824575 100644 --- a/trunk/arch/powerpc/configs/ppc64_defconfig +++ b/trunk/arch/powerpc/configs/ppc64_defconfig @@ -1000,6 +1000,7 @@ CONFIG_TIGON3=y CONFIG_SPIDER_NET=m CONFIG_GELIC_NET=m CONFIG_GELIC_WIRELESS=y +# CONFIG_GELIC_WIRELESS_OLD_PSK_INTERFACE is not set # CONFIG_QLA3XXX is not set # CONFIG_ATL1 is not set # CONFIG_ATL1E is not set diff --git a/trunk/arch/powerpc/configs/ps3_defconfig b/trunk/arch/powerpc/configs/ps3_defconfig index 32f7058bb173..7de127e4ceef 100644 --- a/trunk/arch/powerpc/configs/ps3_defconfig +++ b/trunk/arch/powerpc/configs/ps3_defconfig @@ -593,6 +593,7 @@ CONFIG_MII=m CONFIG_NETDEV_1000=y CONFIG_GELIC_NET=y CONFIG_GELIC_WIRELESS=y +# CONFIG_GELIC_WIRELESS_OLD_PSK_INTERFACE is not set # CONFIG_NETDEV_10000 is not set # diff --git a/trunk/drivers/net/Kconfig b/trunk/drivers/net/Kconfig index 6460505ab24c..18ff622703be 100644 --- a/trunk/drivers/net/Kconfig +++ b/trunk/drivers/net/Kconfig @@ -2354,6 +2354,20 @@ config GELIC_WIRELESS the driver automatically distinguishes the models, you can safely enable this option even if you have a wireless-less model. +config GELIC_WIRELESS_OLD_PSK_INTERFACE + bool "PS3 Wireless private PSK interface (OBSOLETE)" + depends on GELIC_WIRELESS + select WEXT_PRIV + help + This option retains the obsolete private interface to pass + the PSK from user space programs to the driver. The PSK + stands for 'Pre Shared Key' and is used for WPA[2]-PSK + (WPA-Personal) environment. + If WPA[2]-PSK is used and you need to use old programs that + support only this old interface, say Y. Otherwise N. + + If unsure, say N. + config FSL_PQ_MDIO tristate "Freescale PQ MDIO" depends on FSL_SOC diff --git a/trunk/drivers/net/ps3_gelic_wireless.c b/trunk/drivers/net/ps3_gelic_wireless.c index 2663b2fdc0bb..227b141c4fbd 100644 --- a/trunk/drivers/net/ps3_gelic_wireless.c +++ b/trunk/drivers/net/ps3_gelic_wireless.c @@ -1389,6 +1389,113 @@ static int gelic_wl_get_mode(struct net_device *netdev, return 0; } +#ifdef CONFIG_GELIC_WIRELESS_OLD_PSK_INTERFACE +/* SIOCIWFIRSTPRIV */ +static int hex2bin(u8 *str, u8 *bin, unsigned int len) +{ + unsigned int i; + static unsigned char *hex = "0123456789ABCDEF"; + unsigned char *p, *q; + u8 tmp; + + if (len != WPA_PSK_LEN * 2) + return -EINVAL; + + for (i = 0; i < WPA_PSK_LEN * 2; i += 2) { + p = strchr(hex, toupper(str[i])); + q = strchr(hex, toupper(str[i + 1])); + if (!p || !q) { + pr_info("%s: unconvertible PSK digit=%d\n", + __func__, i); + return -EINVAL; + } + tmp = ((p - hex) << 4) + (q - hex); + *bin++ = tmp; + } + return 0; +}; + +static int gelic_wl_priv_set_psk(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, char *extra) +{ + struct gelic_wl_info *wl = port_wl(netdev_priv(net_dev)); + unsigned int len; + unsigned long irqflag; + int ret = 0; + + pr_debug("%s:<- len=%d\n", __func__, data->data.length); + len = data->data.length - 1; + if (len <= 2) + return -EINVAL; + + spin_lock_irqsave(&wl->lock, irqflag); + if (extra[0] == '"' && extra[len - 1] == '"') { + pr_debug("%s: passphrase mode\n", __func__); + /* pass phrase */ + if (GELIC_WL_EURUS_PSK_MAX_LEN < (len - 2)) { + pr_info("%s: passphrase too long\n", __func__); + ret = -E2BIG; + goto out; + } + memset(wl->psk, 0, sizeof(wl->psk)); + wl->psk_len = len - 2; + memcpy(wl->psk, &(extra[1]), wl->psk_len); + wl->psk_type = GELIC_EURUS_WPA_PSK_PASSPHRASE; + } else { + ret = hex2bin(extra, wl->psk, len); + if (ret) + goto out; + wl->psk_len = WPA_PSK_LEN; + wl->psk_type = GELIC_EURUS_WPA_PSK_BIN; + } + set_bit(GELIC_WL_STAT_WPA_PSK_SET, &wl->stat); +out: + spin_unlock_irqrestore(&wl->lock, irqflag); + pr_debug("%s:->\n", __func__); + return ret; +} + +static int gelic_wl_priv_get_psk(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, char *extra) +{ + struct gelic_wl_info *wl = port_wl(netdev_priv(net_dev)); + char *p; + unsigned long irqflag; + unsigned int i; + + pr_debug("%s:<-\n", __func__); + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + spin_lock_irqsave(&wl->lock, irqflag); + p = extra; + if (test_bit(GELIC_WL_STAT_WPA_PSK_SET, &wl->stat)) { + if (wl->psk_type == GELIC_EURUS_WPA_PSK_BIN) { + for (i = 0; i < wl->psk_len; i++) { + sprintf(p, "%02xu", wl->psk[i]); + p += 2; + } + *p = '\0'; + data->data.length = wl->psk_len * 2; + } else { + *p++ = '"'; + memcpy(p, wl->psk, wl->psk_len); + p += wl->psk_len; + *p++ = '"'; + *p = '\0'; + data->data.length = wl->psk_len + 2; + } + } else + /* no psk set */ + data->data.length = 0; + spin_unlock_irqrestore(&wl->lock, irqflag); + pr_debug("%s:-> %d\n", __func__, data->data.length); + return 0; +} +#endif + /* SIOCGIWNICKN */ static int gelic_wl_get_nick(struct net_device *net_dev, struct iw_request_info *info, @@ -1464,10 +1571,8 @@ static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan, init_completion(&wl->scan_done); /* * If we have already a bss list, don't try to get new - * unless we are doing an ESSID scan */ - if ((!essid_len && !always_scan) - && wl->scan_stat == GELIC_WL_SCAN_STAT_GOT_LIST) { + if (!always_scan && wl->scan_stat == GELIC_WL_SCAN_STAT_GOT_LIST) { pr_debug("%s: already has the list\n", __func__); complete(&wl->scan_done); goto out; @@ -1568,7 +1673,7 @@ static void gelic_wl_scan_complete_event(struct gelic_wl_info *wl) } } - /* put them in the network_list */ + /* put them in the newtork_list */ for (i = 0, scan_info_size = 0, scan_info = buf; scan_info_size < data_len; i++, scan_info_size += be16_to_cpu(scan_info->size), @@ -1904,7 +2009,7 @@ static int gelic_wl_do_wpa_setup(struct gelic_wl_info *wl) /* PSK type */ wpa->psk_type = cpu_to_be16(wl->psk_type); #ifdef DEBUG - pr_debug("%s: sec=%s psktype=%s\n", __func__, + pr_debug("%s: sec=%s psktype=%s\nn", __func__, wpasecstr(wpa->security), (wpa->psk_type == GELIC_EURUS_WPA_PSK_BIN) ? "BIN" : "passphrase"); @@ -1914,9 +2019,9 @@ static int gelic_wl_do_wpa_setup(struct gelic_wl_info *wl) * the debug log because this dumps your precious * passphrase/key. */ - pr_debug("%s: psk=%s\n", __func__, + pr_debug("%s: psk=%s\n", (wpa->psk_type == GELIC_EURUS_WPA_PSK_BIN) ? - "N/A" : wpa->psk); + (char *)"N/A" : (char *)wpa->psk); #endif #endif /* issue wpa setup */ @@ -2301,10 +2406,40 @@ static const iw_handler gelic_wl_wext_handler[] = IW_IOCTL(SIOCGIWNICKN) = gelic_wl_get_nick, }; +#ifdef CONFIG_GELIC_WIRELESS_OLD_PSK_INTERFACE +static struct iw_priv_args gelic_wl_private_args[] = +{ + { + .cmd = GELIC_WL_PRIV_SET_PSK, + .set_args = IW_PRIV_TYPE_CHAR | + (GELIC_WL_EURUS_PSK_MAX_LEN + 2), + .name = "set_psk" + }, + { + .cmd = GELIC_WL_PRIV_GET_PSK, + .get_args = IW_PRIV_TYPE_CHAR | + (GELIC_WL_EURUS_PSK_MAX_LEN + 2), + .name = "get_psk" + } +}; + +static const iw_handler gelic_wl_private_handler[] = +{ + gelic_wl_priv_set_psk, + gelic_wl_priv_get_psk, +}; +#endif + static const struct iw_handler_def gelic_wl_wext_handler_def = { .num_standard = ARRAY_SIZE(gelic_wl_wext_handler), .standard = gelic_wl_wext_handler, .get_wireless_stats = gelic_wl_get_wireless_stats, +#ifdef CONFIG_GELIC_WIRELESS_OLD_PSK_INTERFACE + .num_private = ARRAY_SIZE(gelic_wl_private_handler), + .num_private_args = ARRAY_SIZE(gelic_wl_private_args), + .private = gelic_wl_private_handler, + .private_args = gelic_wl_private_args, +#endif }; static struct net_device * __devinit gelic_wl_alloc(struct gelic_card *card) diff --git a/trunk/drivers/net/wireless/Kconfig b/trunk/drivers/net/wireless/Kconfig index 588943660755..56dd6650c97a 100644 --- a/trunk/drivers/net/wireless/Kconfig +++ b/trunk/drivers/net/wireless/Kconfig @@ -112,7 +112,6 @@ config AIRO_CS depends on PCMCIA && (BROKEN || !M32R) select WIRELESS_EXT select WEXT_SPY - select WEXT_PRIV select CRYPTO select CRYPTO_AES ---help--- diff --git a/trunk/drivers/net/wireless/adm8211.c b/trunk/drivers/net/wireless/adm8211.c index 6508515feed3..39410016b4ff 100644 --- a/trunk/drivers/net/wireless/adm8211.c +++ b/trunk/drivers/net/wireless/adm8211.c @@ -302,6 +302,18 @@ static int adm8211_get_stats(struct ieee80211_hw *dev, return 0; } +static int adm8211_get_tx_stats(struct ieee80211_hw *dev, + struct ieee80211_tx_queue_stats *stats) +{ + struct adm8211_priv *priv = dev->priv; + + stats[0].len = priv->cur_tx - priv->dirty_tx; + stats[0].limit = priv->tx_ring_size - 2; + stats[0].count = priv->dirty_tx; + + return 0; +} + static void adm8211_interrupt_tci(struct ieee80211_hw *dev) { struct adm8211_priv *priv = dev->priv; @@ -1388,15 +1400,15 @@ static void adm8211_configure_filter(struct ieee80211_hw *dev, } static int adm8211_add_interface(struct ieee80211_hw *dev, - struct ieee80211_vif *vif) + struct ieee80211_if_init_conf *conf) { struct adm8211_priv *priv = dev->priv; if (priv->mode != NL80211_IFTYPE_MONITOR) return -EOPNOTSUPP; - switch (vif->type) { + switch (conf->type) { case NL80211_IFTYPE_STATION: - priv->mode = vif->type; + priv->mode = conf->type; break; default: return -EOPNOTSUPP; @@ -1404,8 +1416,8 @@ static int adm8211_add_interface(struct ieee80211_hw *dev, ADM8211_IDLE(); - ADM8211_CSR_WRITE(PAR0, le32_to_cpu(*(__le32 *)vif->addr)); - ADM8211_CSR_WRITE(PAR1, le16_to_cpu(*(__le16 *)(vif->addr + 4))); + ADM8211_CSR_WRITE(PAR0, le32_to_cpu(*(__le32 *)conf->mac_addr)); + ADM8211_CSR_WRITE(PAR1, le16_to_cpu(*(__le16 *)(conf->mac_addr + 4))); adm8211_update_mode(dev); @@ -1415,7 +1427,7 @@ static int adm8211_add_interface(struct ieee80211_hw *dev, } static void adm8211_remove_interface(struct ieee80211_hw *dev, - struct ieee80211_vif *vif) + struct ieee80211_if_init_conf *conf) { struct adm8211_priv *priv = dev->priv; priv->mode = NL80211_IFTYPE_MONITOR; @@ -1761,6 +1773,7 @@ static const struct ieee80211_ops adm8211_ops = { .prepare_multicast = adm8211_prepare_multicast, .configure_filter = adm8211_configure_filter, .get_stats = adm8211_get_stats, + .get_tx_stats = adm8211_get_tx_stats, .get_tsf = adm8211_get_tsft }; diff --git a/trunk/drivers/net/wireless/airo.c b/trunk/drivers/net/wireless/airo.c index 260fb9905e97..4331d675fcc6 100644 --- a/trunk/drivers/net/wireless/airo.c +++ b/trunk/drivers/net/wireless/airo.c @@ -51,7 +51,6 @@ #include #include -#include #include "airo.h" @@ -5255,7 +5254,11 @@ static int set_wep_key(struct airo_info *ai, u16 index, const char *key, WepKeyRid wkr; int rc; - WARN_ON(keylen == 0); + if (keylen == 0) { + airo_print_err(ai->dev->name, "%s: key length to set was zero", + __func__); + return -1; + } memset(&wkr, 0, sizeof(wkr)); wkr.len = cpu_to_le16(sizeof(wkr)); @@ -6402,7 +6405,11 @@ static int airo_set_encode(struct net_device *dev, if (dwrq->length > MIN_KEY_SIZE) key.len = MAX_KEY_SIZE; else - key.len = MIN_KEY_SIZE; + if (dwrq->length > 0) + key.len = MIN_KEY_SIZE; + else + /* Disable the key */ + key.len = 0; /* Check if the key is not marked as invalid */ if(!(dwrq->flags & IW_ENCODE_NOKEY)) { /* Cleanup */ @@ -6583,22 +6590,12 @@ static int airo_set_encodeext(struct net_device *dev, default: return -EINVAL; } - if (key.len == 0) { - rc = set_wep_tx_idx(local, idx, perm, 1); - if (rc < 0) { - airo_print_err(local->dev->name, - "failed to set WEP transmit index to %d: %d.", - idx, rc); - return rc; - } - } else { - rc = set_wep_key(local, idx, key.key, key.len, perm, 1); - if (rc < 0) { - airo_print_err(local->dev->name, - "failed to set WEP key at index %d: %d.", - idx, rc); - return rc; - } + /* Send the key to the card */ + rc = set_wep_key(local, idx, key.key, key.len, perm, 1); + if (rc < 0) { + airo_print_err(local->dev->name, "failed to set WEP key" + " at index %d: %d.", idx, rc); + return rc; } } diff --git a/trunk/drivers/net/wireless/at76c50x-usb.c b/trunk/drivers/net/wireless/at76c50x-usb.c index 0fb419936dff..2517364d3ebe 100644 --- a/trunk/drivers/net/wireless/at76c50x-usb.c +++ b/trunk/drivers/net/wireless/at76c50x-usb.c @@ -1789,7 +1789,7 @@ static void at76_mac80211_stop(struct ieee80211_hw *hw) } static int at76_add_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) + struct ieee80211_if_init_conf *conf) { struct at76_priv *priv = hw->priv; int ret = 0; @@ -1798,7 +1798,7 @@ static int at76_add_interface(struct ieee80211_hw *hw, mutex_lock(&priv->mtx); - switch (vif->type) { + switch (conf->type) { case NL80211_IFTYPE_STATION: priv->iw_mode = IW_MODE_INFRA; break; @@ -1814,7 +1814,7 @@ static int at76_add_interface(struct ieee80211_hw *hw, } static void at76_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) + struct ieee80211_if_init_conf *conf) { at76_dbg(DBG_MAC80211, "%s()", __func__); } diff --git a/trunk/drivers/net/wireless/ath/ar9170/ar9170.h b/trunk/drivers/net/wireless/ath/ar9170/ar9170.h index 8c8ce67971e9..9f9459860d82 100644 --- a/trunk/drivers/net/wireless/ath/ar9170/ar9170.h +++ b/trunk/drivers/net/wireless/ath/ar9170/ar9170.h @@ -109,6 +109,7 @@ struct ar9170_rxstream_mpdu_merge { bool has_plcp; }; +#define AR9170_NUM_MAX_BA_RETRY 5 #define AR9170_NUM_TID 16 #define WME_BA_BMP_SIZE 64 #define AR9170_NUM_MAX_AGG_LEN (2 * WME_BA_BMP_SIZE) @@ -142,12 +143,7 @@ struct ar9170_sta_tid { u16 tid; enum ar9170_tid_state state; bool active; -}; - -struct ar9170_tx_queue_stats { - unsigned int len; - unsigned int limit; - unsigned int count; + u8 retry; }; #define AR9170_QUEUE_TIMEOUT 64 @@ -158,8 +154,6 @@ struct ar9170_tx_queue_stats { #define AR9170_NUM_TX_STATUS 128 #define AR9170_NUM_TX_AGG_MAX 30 -#define AR9170_NUM_TX_LIMIT_HARD AR9170_TXQ_DEPTH -#define AR9170_NUM_TX_LIMIT_SOFT (AR9170_TXQ_DEPTH - 10) struct ar9170 { struct ieee80211_hw *hw; @@ -217,7 +211,7 @@ struct ar9170 { /* qos queue settings */ spinlock_t tx_stats_lock; - struct ar9170_tx_queue_stats tx_stats[5]; + struct ieee80211_tx_queue_stats tx_stats[5]; struct ieee80211_tx_queue_params edcf[5]; spinlock_t cmdlock; @@ -254,8 +248,13 @@ struct ar9170_sta_info { unsigned int ampdu_max_len; }; +#define AR9170_TX_FLAG_WAIT_FOR_ACK BIT(0) +#define AR9170_TX_FLAG_NO_ACK BIT(1) +#define AR9170_TX_FLAG_BLOCK_ACK BIT(2) + struct ar9170_tx_info { unsigned long timeout; + unsigned int flags; }; #define IS_STARTED(a) (((struct ar9170 *)a)->state >= AR9170_STARTED) diff --git a/trunk/drivers/net/wireless/ath/ar9170/hw.h b/trunk/drivers/net/wireless/ath/ar9170/hw.h index 0a1d4c28e68a..701ddb7d8400 100644 --- a/trunk/drivers/net/wireless/ath/ar9170/hw.h +++ b/trunk/drivers/net/wireless/ath/ar9170/hw.h @@ -276,7 +276,6 @@ struct ar9170_tx_control { #define AR9170_TX_MAC_RATE_PROBE 0x8000 /* either-or */ -#define AR9170_TX_PHY_MOD_MASK 0x00000003 #define AR9170_TX_PHY_MOD_CCK 0x00000000 #define AR9170_TX_PHY_MOD_OFDM 0x00000001 #define AR9170_TX_PHY_MOD_HT 0x00000002 diff --git a/trunk/drivers/net/wireless/ath/ar9170/mac.c b/trunk/drivers/net/wireless/ath/ar9170/mac.c index 857e86104295..ddc8c09dc79e 100644 --- a/trunk/drivers/net/wireless/ath/ar9170/mac.c +++ b/trunk/drivers/net/wireless/ath/ar9170/mac.c @@ -117,7 +117,7 @@ int ar9170_set_qos(struct ar9170 *ar) ar9170_regwrite(AR9170_MAC_REG_AC1_AC0_TXOP, ar->edcf[0].txop | ar->edcf[1].txop << 16); ar9170_regwrite(AR9170_MAC_REG_AC3_AC2_TXOP, - ar->edcf[2].txop | ar->edcf[3].txop << 16); + ar->edcf[1].txop | ar->edcf[3].txop << 16); ar9170_regwrite_finish(); diff --git a/trunk/drivers/net/wireless/ath/ar9170/main.c b/trunk/drivers/net/wireless/ath/ar9170/main.c index 8a964f130367..f9d6db8d013e 100644 --- a/trunk/drivers/net/wireless/ath/ar9170/main.c +++ b/trunk/drivers/net/wireless/ath/ar9170/main.c @@ -194,15 +194,12 @@ static inline u16 ar9170_get_seq(struct sk_buff *skb) return ar9170_get_seq_h((void *) txc->frame_data); } -static inline u16 ar9170_get_tid_h(struct ieee80211_hdr *hdr) -{ - return (ieee80211_get_qos_ctl(hdr))[0] & IEEE80211_QOS_CTL_TID_MASK; -} - static inline u16 ar9170_get_tid(struct sk_buff *skb) { struct ar9170_tx_control *txc = (void *) skb->data; - return ar9170_get_tid_h((struct ieee80211_hdr *) txc->frame_data); + struct ieee80211_hdr *hdr = (void *) txc->frame_data; + + return (ieee80211_get_qos_ctl(hdr))[0] & IEEE80211_QOS_CTL_TID_MASK; } #define GET_NEXT_SEQ(seq) ((seq + 1) & 0x0fff) @@ -216,10 +213,10 @@ static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb) struct ar9170_tx_info *arinfo = (void *) txinfo->rate_driver_data; struct ieee80211_hdr *hdr = (void *) txc->frame_data; - printk(KERN_DEBUG "%s: => FRAME [skb:%p, q:%d, DA:[%pM] s:%d " + printk(KERN_DEBUG "%s: => FRAME [skb:%p, q:%d, DA:[%pM] flags:%x s:%d " "mac_ctrl:%04x, phy_ctrl:%08x, timeout:[%d ms]]\n", wiphy_name(ar->hw->wiphy), skb, skb_get_queue_mapping(skb), - ieee80211_get_DA(hdr), ar9170_get_seq_h(hdr), + ieee80211_get_DA(hdr), arinfo->flags, ar9170_get_seq_h(hdr), le16_to_cpu(txc->mac_control), le32_to_cpu(txc->phy_control), jiffies_to_msecs(arinfo->timeout - jiffies)); } @@ -433,7 +430,7 @@ void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb) spin_lock_irqsave(&ar->tx_stats_lock, flags); ar->tx_stats[queue].len--; - if (ar->tx_stats[queue].len < AR9170_NUM_TX_LIMIT_SOFT) { + if (skb_queue_empty(&ar->tx_pending[queue])) { #ifdef AR9170_QUEUE_STOP_DEBUG printk(KERN_DEBUG "%s: wake queue %d\n", wiphy_name(ar->hw->wiphy), queue); @@ -443,17 +440,22 @@ void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb) } spin_unlock_irqrestore(&ar->tx_stats_lock, flags); - if (info->flags & IEEE80211_TX_CTL_NO_ACK) { - ar9170_tx_status(ar, skb, AR9170_TX_STATUS_FAILED); - } else { - if (info->flags & IEEE80211_TX_CTL_AMPDU) { - ar9170_tx_ampdu_callback(ar, skb); - } else { - arinfo->timeout = jiffies + + if (arinfo->flags & AR9170_TX_FLAG_BLOCK_ACK) { + ar9170_tx_ampdu_callback(ar, skb); + } else if (arinfo->flags & AR9170_TX_FLAG_WAIT_FOR_ACK) { + arinfo->timeout = jiffies + msecs_to_jiffies(AR9170_TX_TIMEOUT); - skb_queue_tail(&ar->tx_status[queue], skb); - } + skb_queue_tail(&ar->tx_status[queue], skb); + } else if (arinfo->flags & AR9170_TX_FLAG_NO_ACK) { + ar9170_tx_status(ar, skb, AR9170_TX_STATUS_FAILED); + } else { +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_DEBUG "%s: unsupported frame flags!\n", + wiphy_name(ar->hw->wiphy)); + ar9170_print_txheader(ar, skb); +#endif /* AR9170_QUEUE_DEBUG */ + dev_kfree_skb_any(skb); } if (!ar->tx_stats[queue].len && @@ -1405,6 +1407,17 @@ static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb) if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && (is_valid_ether_addr(ieee80211_get_DA(hdr)))) { + if (info->flags & IEEE80211_TX_CTL_AMPDU) { + if (unlikely(!info->control.sta)) + goto err_out; + + txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_AGGR); + arinfo->flags = AR9170_TX_FLAG_BLOCK_ACK; + + goto out; + } + + txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_RATE_PROBE); /* * WARNING: * Putting the QoS queue bits into an unexplored territory is @@ -1418,17 +1431,12 @@ static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb) txc->phy_control |= cpu_to_le32(queue << AR9170_TX_PHY_QOS_SHIFT); - - if (info->flags & IEEE80211_TX_CTL_AMPDU) { - if (unlikely(!info->control.sta)) - goto err_out; - - txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_AGGR); - } else { - txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_RATE_PROBE); - } + arinfo->flags = AR9170_TX_FLAG_WAIT_FOR_ACK; + } else { + arinfo->flags = AR9170_TX_FLAG_NO_ACK; } +out: return 0; err_out: @@ -1663,7 +1671,8 @@ static bool ar9170_tx_ampdu(struct ar9170 *ar) * tell the FW/HW that this is the last frame, * that way it will wait for the immediate block ack. */ - ar9170_tx_indicate_immba(ar, skb_peek_tail(&agg)); + if (likely(skb_peek_tail(&agg))) + ar9170_tx_indicate_immba(ar, skb_peek_tail(&agg)); #ifdef AR9170_TXAGG_DEBUG printk(KERN_DEBUG "%s: generated A-MPDU looks like this:\n", @@ -1707,21 +1716,6 @@ static void ar9170_tx(struct ar9170 *ar) for (i = 0; i < __AR9170_NUM_TXQ; i++) { spin_lock_irqsave(&ar->tx_stats_lock, flags); - frames = min(ar->tx_stats[i].limit - ar->tx_stats[i].len, - skb_queue_len(&ar->tx_pending[i])); - - if (remaining_space < frames) { -#ifdef AR9170_QUEUE_DEBUG - printk(KERN_DEBUG "%s: tx quota reached queue:%d, " - "remaining slots:%d, needed:%d\n", - wiphy_name(ar->hw->wiphy), i, remaining_space, - frames); -#endif /* AR9170_QUEUE_DEBUG */ - frames = remaining_space; - } - - ar->tx_stats[i].len += frames; - ar->tx_stats[i].count += frames; if (ar->tx_stats[i].len >= ar->tx_stats[i].limit) { #ifdef AR9170_QUEUE_DEBUG printk(KERN_DEBUG "%s: queue %d full\n", @@ -1739,8 +1733,25 @@ static void ar9170_tx(struct ar9170 *ar) __ar9170_dump_txstats(ar); #endif /* AR9170_QUEUE_STOP_DEBUG */ ieee80211_stop_queue(ar->hw, i); + spin_unlock_irqrestore(&ar->tx_stats_lock, flags); + continue; + } + + frames = min(ar->tx_stats[i].limit - ar->tx_stats[i].len, + skb_queue_len(&ar->tx_pending[i])); + + if (remaining_space < frames) { +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_DEBUG "%s: tx quota reached queue:%d, " + "remaining slots:%d, needed:%d\n", + wiphy_name(ar->hw->wiphy), i, remaining_space, + frames); +#endif /* AR9170_QUEUE_DEBUG */ + frames = remaining_space; } + ar->tx_stats[i].len += frames; + ar->tx_stats[i].count += frames; spin_unlock_irqrestore(&ar->tx_stats_lock, flags); if (!frames) @@ -1762,7 +1773,7 @@ static void ar9170_tx(struct ar9170 *ar) arinfo->timeout = jiffies + msecs_to_jiffies(AR9170_TX_TIMEOUT); - if (info->flags & IEEE80211_TX_CTL_AMPDU) + if (arinfo->flags == AR9170_TX_FLAG_BLOCK_ACK) atomic_inc(&ar->tx_ampdu_pending); #ifdef AR9170_QUEUE_DEBUG @@ -1773,7 +1784,7 @@ static void ar9170_tx(struct ar9170 *ar) err = ar->tx(ar, skb); if (unlikely(err)) { - if (info->flags & IEEE80211_TX_CTL_AMPDU) + if (arinfo->flags == AR9170_TX_FLAG_BLOCK_ACK) atomic_dec(&ar->tx_ampdu_pending); frames_failed++; @@ -1939,7 +1950,7 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) } static int ar9170_op_add_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) + struct ieee80211_if_init_conf *conf) { struct ar9170 *ar = hw->priv; struct ath_common *common = &ar->common; @@ -1952,8 +1963,8 @@ static int ar9170_op_add_interface(struct ieee80211_hw *hw, goto unlock; } - ar->vif = vif; - memcpy(common->macaddr, vif->addr, ETH_ALEN); + ar->vif = conf->vif; + memcpy(common->macaddr, conf->mac_addr, ETH_ALEN); if (modparam_nohwcrypt || (ar->vif->type != NL80211_IFTYPE_STATION)) { ar->rx_software_decryption = true; @@ -1973,7 +1984,7 @@ static int ar9170_op_add_interface(struct ieee80211_hw *hw, } static void ar9170_op_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) + struct ieee80211_if_init_conf *conf) { struct ar9170 *ar = hw->priv; @@ -2329,55 +2340,55 @@ static int ar9170_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return err; } -static int ar9170_sta_add(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) +static void ar9170_sta_notify(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum sta_notify_cmd cmd, + struct ieee80211_sta *sta) { struct ar9170 *ar = hw->priv; struct ar9170_sta_info *sta_info = (void *) sta->drv_priv; unsigned int i; - memset(sta_info, 0, sizeof(*sta_info)); + switch (cmd) { + case STA_NOTIFY_ADD: + memset(sta_info, 0, sizeof(*sta_info)); - if (!sta->ht_cap.ht_supported) - return 0; + if (!sta->ht_cap.ht_supported) + break; - if (sta->ht_cap.ampdu_density > ar->global_ampdu_density) - ar->global_ampdu_density = sta->ht_cap.ampdu_density; + if (sta->ht_cap.ampdu_density > ar->global_ampdu_density) + ar->global_ampdu_density = sta->ht_cap.ampdu_density; - if (sta->ht_cap.ampdu_factor < ar->global_ampdu_factor) - ar->global_ampdu_factor = sta->ht_cap.ampdu_factor; + if (sta->ht_cap.ampdu_factor < ar->global_ampdu_factor) + ar->global_ampdu_factor = sta->ht_cap.ampdu_factor; - for (i = 0; i < AR9170_NUM_TID; i++) { - sta_info->agg[i].state = AR9170_TID_STATE_SHUTDOWN; - sta_info->agg[i].active = false; - sta_info->agg[i].ssn = 0; - sta_info->agg[i].tid = i; - INIT_LIST_HEAD(&sta_info->agg[i].list); - skb_queue_head_init(&sta_info->agg[i].queue); - } + for (i = 0; i < AR9170_NUM_TID; i++) { + sta_info->agg[i].state = AR9170_TID_STATE_SHUTDOWN; + sta_info->agg[i].active = false; + sta_info->agg[i].ssn = 0; + sta_info->agg[i].retry = 0; + sta_info->agg[i].tid = i; + INIT_LIST_HEAD(&sta_info->agg[i].list); + skb_queue_head_init(&sta_info->agg[i].queue); + } - sta_info->ampdu_max_len = 1 << (3 + sta->ht_cap.ampdu_factor); + sta_info->ampdu_max_len = 1 << (3 + sta->ht_cap.ampdu_factor); + break; - return 0; -} + case STA_NOTIFY_REMOVE: + if (!sta->ht_cap.ht_supported) + break; -static int ar9170_sta_remove(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) -{ - struct ar9170_sta_info *sta_info = (void *) sta->drv_priv; - unsigned int i; + for (i = 0; i < AR9170_NUM_TID; i++) { + sta_info->agg[i].state = AR9170_TID_STATE_INVALID; + skb_queue_purge(&sta_info->agg[i].queue); + } - if (!sta->ht_cap.ht_supported) - return 0; + break; - for (i = 0; i < AR9170_NUM_TID; i++) { - sta_info->agg[i].state = AR9170_TID_STATE_INVALID; - skb_queue_purge(&sta_info->agg[i].queue); + default: + break; } - - return 0; } static int ar9170_get_stats(struct ieee80211_hw *hw, @@ -2397,6 +2408,18 @@ static int ar9170_get_stats(struct ieee80211_hw *hw, return 0; } +static int ar9170_get_tx_stats(struct ieee80211_hw *hw, + struct ieee80211_tx_queue_stats *tx_stats) +{ + struct ar9170 *ar = hw->priv; + + spin_lock_bh(&ar->tx_stats_lock); + memcpy(tx_stats, ar->tx_stats, sizeof(tx_stats[0]) * hw->queues); + spin_unlock_bh(&ar->tx_stats_lock); + + return 0; +} + static int ar9170_conf_tx(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *param) { @@ -2496,9 +2519,9 @@ static const struct ieee80211_ops ar9170_ops = { .bss_info_changed = ar9170_op_bss_info_changed, .get_tsf = ar9170_op_get_tsf, .set_key = ar9170_set_key, - .sta_add = ar9170_sta_add, - .sta_remove = ar9170_sta_remove, + .sta_notify = ar9170_sta_notify, .get_stats = ar9170_get_stats, + .get_tx_stats = ar9170_get_tx_stats, .ampdu_action = ar9170_ampdu_action, }; diff --git a/trunk/drivers/net/wireless/ath/ar9170/usb.c b/trunk/drivers/net/wireless/ath/ar9170/usb.c index 0f361186b78f..e0799d924057 100644 --- a/trunk/drivers/net/wireless/ath/ar9170/usb.c +++ b/trunk/drivers/net/wireless/ath/ar9170/usb.c @@ -84,8 +84,6 @@ static struct usb_device_id ar9170_usb_ids[] = { { USB_DEVICE(0x0cde, 0x0023) }, /* Z-Com UB82 ABG */ { USB_DEVICE(0x0cde, 0x0026) }, - /* Sphairon Homelink 1202 */ - { USB_DEVICE(0x0cde, 0x0027) }, /* Arcadyan WN7512 */ { USB_DEVICE(0x083a, 0xf522) }, /* Planex GWUS300 */ diff --git a/trunk/drivers/net/wireless/ath/ath.h b/trunk/drivers/net/wireless/ath/ath.h index 71fc960814f0..9e05648356fe 100644 --- a/trunk/drivers/net/wireless/ath/ath.h +++ b/trunk/drivers/net/wireless/ath/ath.h @@ -74,6 +74,7 @@ struct ath_common; struct ath_bus_ops { void (*read_cachesize)(struct ath_common *common, int *csz); + void (*cleanup)(struct ath_common *common); bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data); void (*bt_coex_prep)(struct ath_common *common); }; diff --git a/trunk/drivers/net/wireless/ath/ath5k/ath5k.h b/trunk/drivers/net/wireless/ath/ath5k/ath5k.h index ac67f02e26d8..6a2a96761111 100644 --- a/trunk/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/trunk/drivers/net/wireless/ath/ath5k/ath5k.h @@ -535,12 +535,13 @@ struct ath5k_txq_info { u32 tqi_cbr_period; /* Constant bit rate period */ u32 tqi_cbr_overflow_limit; u32 tqi_burst_time; - u32 tqi_ready_time; /* Time queue waits after an event */ + u32 tqi_ready_time; /* Not used */ }; /* * Transmit packet types. * used on tx control descriptor + * TODO: Use them inside base.c corectly */ enum ath5k_pkt_type { AR5K_PKT_TYPE_NORMAL = 0, @@ -1062,7 +1063,6 @@ struct ath5k_hw { u32 ah_cw_min; u32 ah_cw_max; u32 ah_limit_tx_retries; - u8 ah_coverage_class; /* Antenna Control */ u32 ah_ant_ctl[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX]; @@ -1200,7 +1200,6 @@ extern bool ath5k_eeprom_is_hb63(struct ath5k_hw *ah); /* Protocol Control Unit Functions */ extern int ath5k_hw_set_opmode(struct ath5k_hw *ah); -extern void ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class); /* BSSID Functions */ extern int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac); extern void ath5k_hw_set_associd(struct ath5k_hw *ah); @@ -1232,10 +1231,6 @@ extern int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout); extern unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah); extern int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout); extern unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah); -/* Clock rate related functions */ -unsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec); -unsigned int ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock); -unsigned int ath5k_hw_get_clockrate(struct ath5k_hw *ah); /* Key table (WEP) functions */ extern int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry); extern int ath5k_hw_is_key_valid(struct ath5k_hw *ah, u16 entry); @@ -1315,6 +1310,24 @@ extern int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower); * Functions used internaly */ +/* + * Translate usec to hw clock units + * TODO: Half/quarter rate + */ +static inline unsigned int ath5k_hw_htoclock(unsigned int usec, bool turbo) +{ + return turbo ? (usec * 80) : (usec * 40); +} + +/* + * Translate hw clock units to usec + * TODO: Half/quarter rate + */ +static inline unsigned int ath5k_hw_clocktoh(unsigned int clock, bool turbo) +{ + return turbo ? (clock / 80) : (clock / 40); +} + static inline struct ath_common *ath5k_hw_common(struct ath5k_hw *ah) { return &ah->common; diff --git a/trunk/drivers/net/wireless/ath/ath5k/base.c b/trunk/drivers/net/wireless/ath/ath5k/base.c index 2468c64d6c12..e63b7c40d0ee 100644 --- a/trunk/drivers/net/wireless/ath/ath5k/base.c +++ b/trunk/drivers/net/wireless/ath/ath5k/base.c @@ -225,9 +225,9 @@ static int ath5k_reset_wake(struct ath5k_softc *sc); static int ath5k_start(struct ieee80211_hw *hw); static void ath5k_stop(struct ieee80211_hw *hw); static int ath5k_add_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif); + struct ieee80211_if_init_conf *conf); static void ath5k_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif); + struct ieee80211_if_init_conf *conf); static int ath5k_config(struct ieee80211_hw *hw, u32 changed); static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw, int mc_count, struct dev_addr_list *mc_list); @@ -241,6 +241,8 @@ static int ath5k_set_key(struct ieee80211_hw *hw, struct ieee80211_key_conf *key); static int ath5k_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats); +static int ath5k_get_tx_stats(struct ieee80211_hw *hw, + struct ieee80211_tx_queue_stats *stats); static u64 ath5k_get_tsf(struct ieee80211_hw *hw); static void ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf); static void ath5k_reset_tsf(struct ieee80211_hw *hw); @@ -252,8 +254,6 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw, u32 changes); static void ath5k_sw_scan_start(struct ieee80211_hw *hw); static void ath5k_sw_scan_complete(struct ieee80211_hw *hw); -static void ath5k_set_coverage_class(struct ieee80211_hw *hw, - u8 coverage_class); static const struct ieee80211_ops ath5k_hw_ops = { .tx = ath5k_tx, @@ -267,13 +267,13 @@ static const struct ieee80211_ops ath5k_hw_ops = { .set_key = ath5k_set_key, .get_stats = ath5k_get_stats, .conf_tx = NULL, + .get_tx_stats = ath5k_get_tx_stats, .get_tsf = ath5k_get_tsf, .set_tsf = ath5k_set_tsf, .reset_tsf = ath5k_reset_tsf, .bss_info_changed = ath5k_bss_info_changed, .sw_scan_start = ath5k_sw_scan_start, .sw_scan_complete = ath5k_sw_scan_complete, - .set_coverage_class = ath5k_set_coverage_class, }; /* @@ -1246,29 +1246,6 @@ ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) return 0; } -static enum ath5k_pkt_type get_hw_packet_type(struct sk_buff *skb) -{ - struct ieee80211_hdr *hdr; - enum ath5k_pkt_type htype; - __le16 fc; - - hdr = (struct ieee80211_hdr *)skb->data; - fc = hdr->frame_control; - - if (ieee80211_is_beacon(fc)) - htype = AR5K_PKT_TYPE_BEACON; - else if (ieee80211_is_probe_resp(fc)) - htype = AR5K_PKT_TYPE_PROBE_RESP; - else if (ieee80211_is_atim(fc)) - htype = AR5K_PKT_TYPE_ATIM; - else if (ieee80211_is_pspoll(fc)) - htype = AR5K_PKT_TYPE_PSPOLL; - else - htype = AR5K_PKT_TYPE_NORMAL; - - return htype; -} - static int ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, struct ath5k_txq *txq) @@ -1323,8 +1300,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, sc->vif, pktlen, info)); } ret = ah->ah_setup_tx_desc(ah, ds, pktlen, - ieee80211_get_hdrlen_from_skb(skb), - get_hw_packet_type(skb), + ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL, (sc->power_level * 2), hw_rate, info->control.rates[0].count, keyidx, ah->ah_tx_ant, flags, @@ -1353,6 +1329,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, spin_lock_bh(&txq->lock); list_add_tail(&bf->list, &txq->q); + sc->tx_stats[txq->qnum].len++; if (txq->link == NULL) /* is this first packet? */ ath5k_hw_set_txdp(ah, txq->qnum, bf->daddr); else /* no, so only link it */ @@ -1536,8 +1513,7 @@ ath5k_beaconq_config(struct ath5k_softc *sc) ret = ath5k_hw_get_tx_queueprops(ah, sc->bhalq, &qi); if (ret) - goto err; - + return ret; if (sc->opmode == NL80211_IFTYPE_AP || sc->opmode == NL80211_IFTYPE_MESH_POINT) { /* @@ -1564,25 +1540,10 @@ ath5k_beaconq_config(struct ath5k_softc *sc) if (ret) { ATH5K_ERR(sc, "%s: unable to update parameters for beacon " "hardware queue!\n", __func__); - goto err; + return ret; } - ret = ath5k_hw_reset_tx_queue(ah, sc->bhalq); /* push to h/w */ - if (ret) - goto err; - - /* reconfigure cabq with ready time to 80% of beacon_interval */ - ret = ath5k_hw_get_tx_queueprops(ah, AR5K_TX_QUEUE_ID_CAB, &qi); - if (ret) - goto err; - - qi.tqi_ready_time = (sc->bintval * 80) / 100; - ret = ath5k_hw_set_tx_queueprops(ah, AR5K_TX_QUEUE_ID_CAB, &qi); - if (ret) - goto err; - ret = ath5k_hw_reset_tx_queue(ah, AR5K_TX_QUEUE_ID_CAB); -err: - return ret; + return ath5k_hw_reset_tx_queue(ah, sc->bhalq); /* push to h/w */; } static void @@ -1601,6 +1562,7 @@ ath5k_txq_drainq(struct ath5k_softc *sc, struct ath5k_txq *txq) ath5k_txbuf_free(sc, bf); spin_lock_bh(&sc->txbuflock); + sc->tx_stats[txq->qnum].len--; list_move_tail(&bf->list, &sc->txbuf); sc->txbuf_len++; spin_unlock_bh(&sc->txbuflock); @@ -2030,8 +1992,10 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) } ieee80211_tx_status(sc->hw, skb); + sc->tx_stats[txq->qnum].count++; spin_lock(&sc->txbuflock); + sc->tx_stats[txq->qnum].len--; list_move_tail(&bf->list, &sc->txbuf); sc->txbuf_len++; spin_unlock(&sc->txbuflock); @@ -2809,7 +2773,7 @@ static void ath5k_stop(struct ieee80211_hw *hw) } static int ath5k_add_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) + struct ieee80211_if_init_conf *conf) { struct ath5k_softc *sc = hw->priv; int ret; @@ -2820,22 +2784,22 @@ static int ath5k_add_interface(struct ieee80211_hw *hw, goto end; } - sc->vif = vif; + sc->vif = conf->vif; - switch (vif->type) { + switch (conf->type) { case NL80211_IFTYPE_AP: case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_MONITOR: - sc->opmode = vif->type; + sc->opmode = conf->type; break; default: ret = -EOPNOTSUPP; goto end; } - ath5k_hw_set_lladdr(sc->ah, vif->addr); + ath5k_hw_set_lladdr(sc->ah, conf->mac_addr); ath5k_mode_setup(sc); ret = 0; @@ -2846,13 +2810,13 @@ static int ath5k_add_interface(struct ieee80211_hw *hw, static void ath5k_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) + struct ieee80211_if_init_conf *conf) { struct ath5k_softc *sc = hw->priv; u8 mac[ETH_ALEN] = {}; mutex_lock(&sc->lock); - if (sc->vif != vif) + if (sc->vif != conf->vif) goto end; ath5k_hw_set_lladdr(sc->ah, mac); @@ -3133,6 +3097,17 @@ ath5k_get_stats(struct ieee80211_hw *hw, return 0; } +static int +ath5k_get_tx_stats(struct ieee80211_hw *hw, + struct ieee80211_tx_queue_stats *stats) +{ + struct ath5k_softc *sc = hw->priv; + + memcpy(stats, &sc->tx_stats, sizeof(sc->tx_stats)); + + return 0; +} + static u64 ath5k_get_tsf(struct ieee80211_hw *hw) { @@ -3287,22 +3262,3 @@ static void ath5k_sw_scan_complete(struct ieee80211_hw *hw) ath5k_hw_set_ledstate(sc->ah, sc->assoc ? AR5K_LED_ASSOC : AR5K_LED_INIT); } - -/** - * ath5k_set_coverage_class - Set IEEE 802.11 coverage class - * - * @hw: struct ieee80211_hw pointer - * @coverage_class: IEEE 802.11 coverage class number - * - * Mac80211 callback. Sets slot time, ACK timeout and CTS timeout for given - * coverage class. The values are persistent, they are restored after device - * reset. - */ -static void ath5k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class) -{ - struct ath5k_softc *sc = hw->priv; - - mutex_lock(&sc->lock); - ath5k_hw_set_coverage_class(sc->ah, coverage_class); - mutex_unlock(&sc->lock); -} diff --git a/trunk/drivers/net/wireless/ath/ath5k/base.h b/trunk/drivers/net/wireless/ath/ath5k/base.h index 9c2fbf230ce7..b72338c9bde7 100644 --- a/trunk/drivers/net/wireless/ath/ath5k/base.h +++ b/trunk/drivers/net/wireless/ath/ath5k/base.h @@ -117,6 +117,7 @@ struct ath5k_softc { struct pci_dev *pdev; /* for dma mapping */ void __iomem *iobase; /* address of the device */ struct mutex lock; /* dev-level lock */ + struct ieee80211_tx_queue_stats tx_stats[AR5K_NUM_TX_QUEUES]; struct ieee80211_low_level_stats ll_stats; struct ieee80211_hw *hw; /* IEEE 802.11 common */ struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; diff --git a/trunk/drivers/net/wireless/ath/ath5k/led.c b/trunk/drivers/net/wireless/ath/ath5k/led.c index 67aa52e9bf94..60f547503d75 100644 --- a/trunk/drivers/net/wireless/ath/ath5k/led.c +++ b/trunk/drivers/net/wireless/ath/ath5k/led.c @@ -77,8 +77,6 @@ static const struct pci_device_id ath5k_led_devices[] = { { ATH_SDEVICE(PCI_VENDOR_ID_HP, 0x0137a), ATH_LED(3, 1) }, /* HP Compaq C700 (nitrousnrg@gmail.com) */ { ATH_SDEVICE(PCI_VENDOR_ID_HP, 0x0137b), ATH_LED(3, 1) }, - /* LiteOn AR5BXB63 (magooz@salug.it) */ - { ATH_SDEVICE(PCI_VENDOR_ID_ATHEROS, 0x3067), ATH_LED(3, 0) }, /* IBM-specific AR5212 (all others) */ { PCI_VDEVICE(ATHEROS, PCI_DEVICE_ID_ATHEROS_AR5212_IBM), ATH_LED(0, 0) }, /* Dell Vostro A860 (shahar@shahar-or.co.il) */ diff --git a/trunk/drivers/net/wireless/ath/ath5k/pcu.c b/trunk/drivers/net/wireless/ath/ath5k/pcu.c index aefe84f9c04b..64fc1eb9b6d9 100644 --- a/trunk/drivers/net/wireless/ath/ath5k/pcu.c +++ b/trunk/drivers/net/wireless/ath/ath5k/pcu.c @@ -187,8 +187,8 @@ unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah) { ATH5K_TRACE(ah->ah_sc); - return ath5k_hw_clocktoh(ah, AR5K_REG_MS(ath5k_hw_reg_read(ah, - AR5K_TIME_OUT), AR5K_TIME_OUT_ACK)); + return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah, + AR5K_TIME_OUT), AR5K_TIME_OUT_ACK), ah->ah_turbo); } /** @@ -200,12 +200,12 @@ unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah) int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout) { ATH5K_TRACE(ah->ah_sc); - if (ath5k_hw_clocktoh(ah, AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK)) - <= timeout) + if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK), + ah->ah_turbo) <= timeout) return -EINVAL; AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_ACK, - ath5k_hw_htoclock(ah, timeout)); + ath5k_hw_htoclock(timeout, ah->ah_turbo)); return 0; } @@ -218,8 +218,8 @@ int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout) unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah) { ATH5K_TRACE(ah->ah_sc); - return ath5k_hw_clocktoh(ah, AR5K_REG_MS(ath5k_hw_reg_read(ah, - AR5K_TIME_OUT), AR5K_TIME_OUT_CTS)); + return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah, + AR5K_TIME_OUT), AR5K_TIME_OUT_CTS), ah->ah_turbo); } /** @@ -231,96 +231,16 @@ unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah) int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout) { ATH5K_TRACE(ah->ah_sc); - if (ath5k_hw_clocktoh(ah, AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS)) - <= timeout) + if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS), + ah->ah_turbo) <= timeout) return -EINVAL; AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_CTS, - ath5k_hw_htoclock(ah, timeout)); + ath5k_hw_htoclock(timeout, ah->ah_turbo)); return 0; } -/** - * ath5k_hw_htoclock - Translate usec to hw clock units - * - * @ah: The &struct ath5k_hw - * @usec: value in microseconds - */ -unsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec) -{ - return usec * ath5k_hw_get_clockrate(ah); -} - -/** - * ath5k_hw_clocktoh - Translate hw clock units to usec - * @clock: value in hw clock units - */ -unsigned int ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock) -{ - return clock / ath5k_hw_get_clockrate(ah); -} - -/** - * ath5k_hw_get_clockrate - Get the clock rate for current mode - * - * @ah: The &struct ath5k_hw - */ -unsigned int ath5k_hw_get_clockrate(struct ath5k_hw *ah) -{ - struct ieee80211_channel *channel = ah->ah_current_channel; - int clock; - - if (channel->hw_value & CHANNEL_5GHZ) - clock = 40; /* 802.11a */ - else if (channel->hw_value & CHANNEL_CCK) - clock = 22; /* 802.11b */ - else - clock = 44; /* 802.11g */ - - /* Clock rate in turbo modes is twice the normal rate */ - if (channel->hw_value & CHANNEL_TURBO) - clock *= 2; - - return clock; -} - -/** - * ath5k_hw_get_default_slottime - Get the default slot time for current mode - * - * @ah: The &struct ath5k_hw - */ -unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah) -{ - struct ieee80211_channel *channel = ah->ah_current_channel; - - if (channel->hw_value & CHANNEL_TURBO) - return 6; /* both turbo modes */ - - if (channel->hw_value & CHANNEL_CCK) - return 20; /* 802.11b */ - - return 9; /* 802.11 a/g */ -} - -/** - * ath5k_hw_get_default_sifs - Get the default SIFS for current mode - * - * @ah: The &struct ath5k_hw - */ -unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah) -{ - struct ieee80211_channel *channel = ah->ah_current_channel; - - if (channel->hw_value & CHANNEL_TURBO) - return 8; /* both turbo modes */ - - if (channel->hw_value & CHANNEL_5GHZ) - return 16; /* 802.11a */ - - return 10; /* 802.11 b/g */ -} - /** * ath5k_hw_set_lladdr - Set station id * @@ -1130,24 +1050,3 @@ int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac) return 0; } -/** - * ath5k_hw_set_coverage_class - Set IEEE 802.11 coverage class - * - * @ah: The &struct ath5k_hw - * @coverage_class: IEEE 802.11 coverage class number - * - * Sets slot time, ACK timeout and CTS timeout for given coverage class. - */ -void ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class) -{ - /* As defined by IEEE 802.11-2007 17.3.8.6 */ - int slot_time = ath5k_hw_get_default_slottime(ah) + 3 * coverage_class; - int ack_timeout = ath5k_hw_get_default_sifs(ah) + slot_time; - int cts_timeout = ack_timeout; - - ath5k_hw_set_slot_time(ah, slot_time); - ath5k_hw_set_ack_timeout(ah, ack_timeout); - ath5k_hw_set_cts_timeout(ah, cts_timeout); - - ah->ah_coverage_class = coverage_class; -} diff --git a/trunk/drivers/net/wireless/ath/ath5k/qcu.c b/trunk/drivers/net/wireless/ath/ath5k/qcu.c index 9122a8556f45..eeebb9aef206 100644 --- a/trunk/drivers/net/wireless/ath/ath5k/qcu.c +++ b/trunk/drivers/net/wireless/ath/ath5k/qcu.c @@ -408,13 +408,12 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) break; case AR5K_TX_QUEUE_CAB: - /* XXX: use BCN_SENT_GT, if we can figure out how */ AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), - AR5K_QCU_MISC_FRSHED_DBA_GT | + AR5K_QCU_MISC_FRSHED_BCN_SENT_GT | AR5K_QCU_MISC_CBREXP_DIS | AR5K_QCU_MISC_CBREXP_BCN_DIS); - ath5k_hw_reg_write(ah, ((tq->tqi_ready_time - + ath5k_hw_reg_write(ah, ((AR5K_TUNE_BEACON_INTERVAL - (AR5K_TUNE_SW_BEACON_RESP - AR5K_TUNE_DMA_BEACON_RESP) - AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF) * 1024) | @@ -521,16 +520,12 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) */ unsigned int ath5k_hw_get_slot_time(struct ath5k_hw *ah) { - unsigned int slot_time_clock; - ATH5K_TRACE(ah->ah_sc); - if (ah->ah_version == AR5K_AR5210) - slot_time_clock = ath5k_hw_reg_read(ah, AR5K_SLOT_TIME); + return ath5k_hw_clocktoh(ath5k_hw_reg_read(ah, + AR5K_SLOT_TIME) & 0xffff, ah->ah_turbo); else - slot_time_clock = ath5k_hw_reg_read(ah, AR5K_DCU_GBL_IFS_SLOT); - - return ath5k_hw_clocktoh(ah, slot_time_clock & 0xffff); + return ath5k_hw_reg_read(ah, AR5K_DCU_GBL_IFS_SLOT) & 0xffff; } /* @@ -538,17 +533,15 @@ unsigned int ath5k_hw_get_slot_time(struct ath5k_hw *ah) */ int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time) { - u32 slot_time_clock = ath5k_hw_htoclock(ah, slot_time); - ATH5K_TRACE(ah->ah_sc); - - if (slot_time < 6 || slot_time_clock > AR5K_SLOT_TIME_MAX) + if (slot_time < AR5K_SLOT_TIME_9 || slot_time > AR5K_SLOT_TIME_MAX) return -EINVAL; if (ah->ah_version == AR5K_AR5210) - ath5k_hw_reg_write(ah, slot_time_clock, AR5K_SLOT_TIME); + ath5k_hw_reg_write(ah, ath5k_hw_htoclock(slot_time, + ah->ah_turbo), AR5K_SLOT_TIME); else - ath5k_hw_reg_write(ah, slot_time_clock, AR5K_DCU_GBL_IFS_SLOT); + ath5k_hw_reg_write(ah, slot_time, AR5K_DCU_GBL_IFS_SLOT); return 0; } diff --git a/trunk/drivers/net/wireless/ath/ath5k/reset.c b/trunk/drivers/net/wireless/ath/ath5k/reset.c index a35a7db0fc4c..62954fc77869 100644 --- a/trunk/drivers/net/wireless/ath/ath5k/reset.c +++ b/trunk/drivers/net/wireless/ath/ath5k/reset.c @@ -60,11 +60,12 @@ static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah, !(channel->hw_value & CHANNEL_OFDM)); /* Get coefficient - * ALGO: coef = (5 * clock / carrier_freq) / 2 + * ALGO: coef = (5 * clock * carrier_freq) / 2) * we scale coef by shifting clock value by 24 for * better precision since we use integers */ /* TODO: Half/quarter rate */ - clock = (channel->hw_value & CHANNEL_TURBO) ? 80 : 40; + clock = ath5k_hw_htoclock(1, channel->hw_value & CHANNEL_TURBO); + coef_scaled = ((5 * (clock << 24)) / 2) / channel->center_freq; /* Get exponent @@ -1316,10 +1317,6 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, /* Restore antenna mode */ ath5k_hw_set_antenna_mode(ah, ah->ah_ant_mode); - /* Restore slot time and ACK timeouts */ - if (ah->ah_coverage_class > 0) - ath5k_hw_set_coverage_class(ah, ah->ah_coverage_class); - /* * Configure QCUs/DCUs */ @@ -1374,9 +1371,8 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, * Set clocks to 32KHz operation and use an * external 32KHz crystal when sleeping if one * exists */ - if (ah->ah_version == AR5K_AR5212 && - ah->ah_op_mode != NL80211_IFTYPE_AP) - ath5k_hw_set_sleep_clock(ah, true); + if (ah->ah_version == AR5K_AR5212) + ath5k_hw_set_sleep_clock(ah, true); /* * Disable beacons and reset the register diff --git a/trunk/drivers/net/wireless/ath/ath9k/Makefile b/trunk/drivers/net/wireless/ath/ath9k/Makefile index 6b50d5eb9ec3..4985b2b1b0a9 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/Makefile +++ b/trunk/drivers/net/wireless/ath/ath9k/Makefile @@ -1,6 +1,4 @@ ath9k-y += beacon.o \ - gpio.o \ - init.o \ main.o \ recv.o \ xmit.o \ diff --git a/trunk/drivers/net/wireless/ath/ath9k/ahb.c b/trunk/drivers/net/wireless/ath/ath9k/ahb.c index ca4994f13151..329e6bc137ab 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/ahb.c +++ b/trunk/drivers/net/wireless/ath/ath9k/ahb.c @@ -27,6 +27,12 @@ static void ath_ahb_read_cachesize(struct ath_common *common, int *csz) *csz = L1_CACHE_BYTES >> 2; } +static void ath_ahb_cleanup(struct ath_common *common) +{ + struct ath_softc *sc = (struct ath_softc *)common->priv; + iounmap(sc->mem); +} + static bool ath_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data) { struct ath_softc *sc = (struct ath_softc *)common->priv; @@ -48,6 +54,8 @@ static bool ath_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data) static struct ath_bus_ops ath_ahb_bus_ops = { .read_cachesize = ath_ahb_read_cachesize, + .cleanup = ath_ahb_cleanup, + .eeprom_read = ath_ahb_eeprom_read, }; @@ -113,19 +121,16 @@ static int ath_ahb_probe(struct platform_device *pdev) sc->mem = mem; sc->irq = irq; - /* Will be cleared in ath9k_start() */ - sc->sc_flags |= SC_OP_INVALID; - - ret = request_irq(irq, ath_isr, IRQF_SHARED, "ath9k", sc); + ret = ath_init_device(AR5416_AR9100_DEVID, sc, 0x0, &ath_ahb_bus_ops); if (ret) { - dev_err(&pdev->dev, "request_irq failed\n"); + dev_err(&pdev->dev, "failed to initialize device\n"); goto err_free_hw; } - ret = ath9k_init_device(AR5416_AR9100_DEVID, sc, 0x0, &ath_ahb_bus_ops); + ret = request_irq(irq, ath_isr, IRQF_SHARED, "ath9k", sc); if (ret) { - dev_err(&pdev->dev, "failed to initialize device\n"); - goto err_irq; + dev_err(&pdev->dev, "request_irq failed\n"); + goto err_detach; } ah = sc->sc_ah; @@ -138,8 +143,8 @@ static int ath_ahb_probe(struct platform_device *pdev) return 0; - err_irq: - free_irq(irq, sc); + err_detach: + ath_detach(sc); err_free_hw: ieee80211_free_hw(hw); platform_set_drvdata(pdev, NULL); @@ -156,12 +161,8 @@ static int ath_ahb_remove(struct platform_device *pdev) if (hw) { struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; - void __iomem *mem = sc->mem; - ath9k_deinit_device(sc); - free_irq(sc->irq, sc); - ieee80211_free_hw(sc->hw); - iounmap(mem); + ath_cleanup(sc); platform_set_drvdata(pdev, NULL); } diff --git a/trunk/drivers/net/wireless/ath/ath9k/ath9k.h b/trunk/drivers/net/wireless/ath/ath9k/ath9k.h index 83c7ea4c007f..1597a42731ed 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/trunk/drivers/net/wireless/ath/ath9k/ath9k.h @@ -267,7 +267,6 @@ void ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid, u16 *ssn); void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); -void ath9k_enable_ps(struct ath_softc *sc); /********/ /* VIFs */ @@ -342,12 +341,6 @@ int ath_beaconq_config(struct ath_softc *sc); #define ATH_LONG_CALINTERVAL 30000 /* 30 seconds */ #define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */ -void ath_ani_calibrate(unsigned long data); - -/**********/ -/* BTCOEX */ -/**********/ - /* Defines the BT AR_BT_COEX_WGHT used */ enum ath_stomp_type { ATH_BTCOEX_NO_STOMP, @@ -365,14 +358,9 @@ struct ath_btcoex { int bt_stomp_type; /* Types of BT stomping */ u32 btcoex_no_stomp; /* in usec */ u32 btcoex_period; /* in usec */ - u32 btscan_no_stomp; /* in usec */ struct ath_gen_timer *no_stomp_timer; /* Timer for no BT stomping */ }; -int ath_init_btcoex_timer(struct ath_softc *sc); -void ath9k_btcoex_timer_resume(struct ath_softc *sc); -void ath9k_btcoex_timer_pause(struct ath_softc *sc); - /********************/ /* LED Control */ /********************/ @@ -397,9 +385,6 @@ struct ath_led { bool registered; }; -void ath_init_leds(struct ath_softc *sc); -void ath_deinit_leds(struct ath_softc *sc); - /********************/ /* Main driver core */ /********************/ @@ -418,29 +403,26 @@ void ath_deinit_leds(struct ath_softc *sc); #define ATH_TXPOWER_MAX 100 /* .5 dBm units */ #define ATH_RATE_DUMMY_MARKER 0 -#define SC_OP_INVALID BIT(0) -#define SC_OP_BEACONS BIT(1) -#define SC_OP_RXAGGR BIT(2) -#define SC_OP_TXAGGR BIT(3) -#define SC_OP_FULL_RESET BIT(4) -#define SC_OP_PREAMBLE_SHORT BIT(5) -#define SC_OP_PROTECT_ENABLE BIT(6) -#define SC_OP_RXFLUSH BIT(7) -#define SC_OP_LED_ASSOCIATED BIT(8) -#define SC_OP_LED_ON BIT(9) -#define SC_OP_SCANNING BIT(10) -#define SC_OP_TSF_RESET BIT(11) -#define SC_OP_BT_PRIORITY_DETECTED BIT(12) -#define SC_OP_BT_SCAN BIT(13) - -/* Powersave flags */ -#define PS_WAIT_FOR_BEACON BIT(0) -#define PS_WAIT_FOR_CAB BIT(1) -#define PS_WAIT_FOR_PSPOLL_DATA BIT(2) -#define PS_WAIT_FOR_TX_ACK BIT(3) -#define PS_BEACON_SYNC BIT(4) -#define PS_NULLFUNC_COMPLETED BIT(5) -#define PS_ENABLED BIT(6) +#define SC_OP_INVALID BIT(0) +#define SC_OP_BEACONS BIT(1) +#define SC_OP_RXAGGR BIT(2) +#define SC_OP_TXAGGR BIT(3) +#define SC_OP_FULL_RESET BIT(4) +#define SC_OP_PREAMBLE_SHORT BIT(5) +#define SC_OP_PROTECT_ENABLE BIT(6) +#define SC_OP_RXFLUSH BIT(7) +#define SC_OP_LED_ASSOCIATED BIT(8) +#define SC_OP_WAIT_FOR_BEACON BIT(12) +#define SC_OP_LED_ON BIT(13) +#define SC_OP_SCANNING BIT(14) +#define SC_OP_TSF_RESET BIT(15) +#define SC_OP_WAIT_FOR_CAB BIT(16) +#define SC_OP_WAIT_FOR_PSPOLL_DATA BIT(17) +#define SC_OP_WAIT_FOR_TX_ACK BIT(18) +#define SC_OP_BEACON_SYNC BIT(19) +#define SC_OP_BT_PRIORITY_DETECTED BIT(21) +#define SC_OP_NULLFUNC_COMPLETED BIT(22) +#define SC_OP_PS_ENABLED BIT(23) struct ath_wiphy; struct ath_rate_table; @@ -471,17 +453,16 @@ struct ath_softc { int irq; spinlock_t sc_resetlock; spinlock_t sc_serial_rw; + spinlock_t ani_lock; spinlock_t sc_pm_lock; struct mutex mutex; u32 intrstatus; u32 sc_flags; /* SC_OP_* */ - u16 ps_flags; /* PS_* */ u16 curtxpow; u8 nbcnvifs; u16 nvifs; bool ps_enabled; - bool ps_idle; unsigned long ps_usecount; enum ath9k_int imask; @@ -528,7 +509,6 @@ struct ath_wiphy { int chan_is_ht; }; -void ath9k_tasklet(unsigned long data); int ath_reset(struct ath_softc *sc, bool retry_tx); int ath_get_hal_qnum(u16 queue, struct ath_softc *sc); int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc); @@ -539,16 +519,21 @@ static inline void ath_read_cachesize(struct ath_common *common, int *csz) common->bus_ops->read_cachesize(common, csz); } +static inline void ath_bus_cleanup(struct ath_common *common) +{ + common->bus_ops->cleanup(common); +} + extern struct ieee80211_ops ath9k_ops; -extern int modparam_nohwcrypt; irqreturn_t ath_isr(int irq, void *dev); -int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, +void ath_cleanup(struct ath_softc *sc); +int ath_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, const struct ath_bus_ops *bus_ops); -void ath9k_deinit_device(struct ath_softc *sc); +void ath_detach(struct ath_softc *sc); const char *ath_mac_bb_name(u32 mac_bb_version); const char *ath_rf_name(u16 rf_version); -void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw); +void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw); void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw, struct ath9k_channel *ichan); void ath_update_chainmask(struct ath_softc *sc, int is_ht); @@ -557,7 +542,6 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw); void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw); -bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode); #ifdef CONFIG_PCI int ath_pci_init(void); @@ -599,8 +583,4 @@ void ath_mac80211_stop_queue(struct ath_softc *sc, u16 skb_queue); void ath_mac80211_start_queue(struct ath_softc *sc, u16 skb_queue); int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype); - -void ath_start_rfkill_poll(struct ath_softc *sc); -extern void ath9k_rfkill_poll_state(struct ieee80211_hw *hw); - #endif /* ATH9K_H */ diff --git a/trunk/drivers/net/wireless/ath/ath9k/beacon.c b/trunk/drivers/net/wireless/ath/ath9k/beacon.c index b4a31a43a62c..1660ef17aaf5 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/beacon.c +++ b/trunk/drivers/net/wireless/ath/ath9k/beacon.c @@ -62,7 +62,7 @@ int ath_beaconq_config(struct ath_softc *sc) * Beacons are always sent out at the lowest rate, and are not retried. */ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, - struct ath_buf *bf, int rateidx) + struct ath_buf *bf) { struct sk_buff *skb = bf->bf_mpdu; struct ath_hw *ah = sc->sc_ah; @@ -96,9 +96,9 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, ds->ds_data = bf->bf_buf_addr; sband = &sc->sbands[common->hw->conf.channel->band]; - rate = sband->bitrates[rateidx].hw_value; + rate = sband->bitrates[0].hw_value; if (sc->sc_flags & SC_OP_PREAMBLE_SHORT) - rate |= sband->bitrates[rateidx].hw_value_short; + rate |= sband->bitrates[0].hw_value_short; ath9k_hw_set11n_txdesc(ah, ds, skb->len + FCS_LEN, ATH9K_PKT_TYPE_BEACON, @@ -206,7 +206,7 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw, } } - ath_beacon_setup(sc, avp, bf, info->control.rates[0].idx); + ath_beacon_setup(sc, avp, bf); while (skb) { ath_tx_cabq(hw, skb); @@ -237,7 +237,7 @@ static void ath_beacon_start_adhoc(struct ath_softc *sc, bf = avp->av_bcbuf; skb = bf->bf_mpdu; - ath_beacon_setup(sc, avp, bf, 0); + ath_beacon_setup(sc, avp, bf); /* NB: caller is known to have already stopped tx dma */ ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bf->bf_daddr); @@ -480,8 +480,7 @@ void ath_beacon_tasklet(unsigned long data) sc->beacon.updateslot = COMMIT; /* commit next beacon */ sc->beacon.slotupdate = slot; } else if (sc->beacon.updateslot == COMMIT && sc->beacon.slotupdate == slot) { - ah->slottime = sc->beacon.slottime; - ath9k_hw_init_global_settings(ah); + ath9k_hw_setslottime(sc->sc_ah, sc->beacon.slottime); sc->beacon.updateslot = OK; } if (bfaddr != 0) { @@ -526,13 +525,16 @@ static void ath_beacon_config_ap(struct ath_softc *sc, { u32 nexttbtt, intval; + /* Configure the timers only when the TSF has to be reset */ + + if (!(sc->sc_flags & SC_OP_TSF_RESET)) + return; + /* NB: the beacon interval is kept internally in TU's */ intval = conf->beacon_interval & ATH9K_BEACON_PERIOD; intval /= ATH_BCBUF; /* for staggered beacons */ nexttbtt = intval; - - if (sc->sc_flags & SC_OP_TSF_RESET) - intval |= ATH9K_BEACON_RESET_TSF; + intval |= ATH9K_BEACON_RESET_TSF; /* * In AP mode we enable the beacon timers and SWBA interrupts to @@ -574,13 +576,6 @@ static void ath_beacon_config_sta(struct ath_softc *sc, u64 tsf; int num_beacons, offset, dtim_dec_count, cfp_dec_count; - /* No need to configure beacon if we are not associated */ - if (!common->curaid) { - ath_print(common, ATH_DBG_BEACON, - "STA is not yet associated..skipping beacon config\n"); - return; - } - memset(&bs, 0, sizeof(bs)); intval = conf->beacon_interval & ATH9K_BEACON_PERIOD; @@ -743,6 +738,7 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) enum nl80211_iftype iftype; /* Setup the beacon configuration parameters */ + if (vif) { struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; diff --git a/trunk/drivers/net/wireless/ath/ath9k/btcoex.h b/trunk/drivers/net/wireless/ath/ath9k/btcoex.h index 1ee5a15ccbb1..1ba31a73317c 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/trunk/drivers/net/wireless/ath/ath9k/btcoex.h @@ -25,12 +25,10 @@ #define ATH_BTCOEX_DEF_BT_PERIOD 45 #define ATH_BTCOEX_DEF_DUTY_CYCLE 55 -#define ATH_BTCOEX_BTSCAN_DUTY_CYCLE 90 #define ATH_BTCOEX_BMISS_THRESH 50 #define ATH_BT_PRIORITY_TIME_THRESHOLD 1000 /* ms */ #define ATH_BT_CNT_THRESHOLD 3 -#define ATH_BT_CNT_SCAN_THRESHOLD 15 enum ath_btcoex_scheme { ATH_BTCOEX_CFG_NONE, diff --git a/trunk/drivers/net/wireless/ath/ath9k/debug.c b/trunk/drivers/net/wireless/ath/ath9k/debug.c index 42d2a506845a..b66f72dbf7b9 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/debug.c +++ b/trunk/drivers/net/wireless/ath/ath9k/debug.c @@ -75,24 +75,17 @@ static const struct file_operations fops_debug = { #endif -#define DMA_BUF_LEN 1024 - static ssize_t read_file_dma(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct ath_softc *sc = file->private_data; struct ath_hw *ah = sc->sc_ah; - char *buf; - int retval; + char buf[1024]; unsigned int len = 0; u32 val[ATH9K_NUM_DMA_DEBUG_REGS]; int i, qcuOffset = 0, dcuOffset = 0; u32 *qcuBase = &val[0], *dcuBase = &val[4]; - buf = kmalloc(DMA_BUF_LEN, GFP_KERNEL); - if (!buf) - return 0; - ath9k_ps_wakeup(sc); REG_WRITE_D(ah, AR_MACMISC, @@ -100,20 +93,20 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf, (AR_MACMISC_MISC_OBS_BUS_1 << AR_MACMISC_MISC_OBS_BUS_MSB_S))); - len += snprintf(buf + len, DMA_BUF_LEN - len, + len += snprintf(buf + len, sizeof(buf) - len, "Raw DMA Debug values:\n"); for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++) { if (i % 4 == 0) - len += snprintf(buf + len, DMA_BUF_LEN - len, "\n"); + len += snprintf(buf + len, sizeof(buf) - len, "\n"); val[i] = REG_READ_D(ah, AR_DMADBG_0 + (i * sizeof(u32))); - len += snprintf(buf + len, DMA_BUF_LEN - len, "%d: %08x ", + len += snprintf(buf + len, sizeof(buf) - len, "%d: %08x ", i, val[i]); } - len += snprintf(buf + len, DMA_BUF_LEN - len, "\n\n"); - len += snprintf(buf + len, DMA_BUF_LEN - len, + len += snprintf(buf + len, sizeof(buf) - len, "\n\n"); + len += snprintf(buf + len, sizeof(buf) - len, "Num QCU: chain_st fsp_ok fsp_st DCU: chain_st\n"); for (i = 0; i < ATH9K_NUM_QUEUES; i++, qcuOffset += 4, dcuOffset += 5) { @@ -127,7 +120,7 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf, dcuBase++; } - len += snprintf(buf + len, DMA_BUF_LEN - len, + len += snprintf(buf + len, sizeof(buf) - len, "%2d %2x %1x %2x %2x\n", i, (*qcuBase & (0x7 << qcuOffset)) >> qcuOffset, (*qcuBase & (0x8 << qcuOffset)) >> (qcuOffset + 3), @@ -135,37 +128,35 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf, (*dcuBase & (0x1f << dcuOffset)) >> dcuOffset); } - len += snprintf(buf + len, DMA_BUF_LEN - len, "\n"); + len += snprintf(buf + len, sizeof(buf) - len, "\n"); - len += snprintf(buf + len, DMA_BUF_LEN - len, + len += snprintf(buf + len, sizeof(buf) - len, "qcu_stitch state: %2x qcu_fetch state: %2x\n", (val[3] & 0x003c0000) >> 18, (val[3] & 0x03c00000) >> 22); - len += snprintf(buf + len, DMA_BUF_LEN - len, + len += snprintf(buf + len, sizeof(buf) - len, "qcu_complete state: %2x dcu_complete state: %2x\n", (val[3] & 0x1c000000) >> 26, (val[6] & 0x3)); - len += snprintf(buf + len, DMA_BUF_LEN - len, + len += snprintf(buf + len, sizeof(buf) - len, "dcu_arb state: %2x dcu_fp state: %2x\n", (val[5] & 0x06000000) >> 25, (val[5] & 0x38000000) >> 27); - len += snprintf(buf + len, DMA_BUF_LEN - len, + len += snprintf(buf + len, sizeof(buf) - len, "chan_idle_dur: %3d chan_idle_dur_valid: %1d\n", (val[6] & 0x000003fc) >> 2, (val[6] & 0x00000400) >> 10); - len += snprintf(buf + len, DMA_BUF_LEN - len, + len += snprintf(buf + len, sizeof(buf) - len, "txfifo_valid_0: %1d txfifo_valid_1: %1d\n", (val[6] & 0x00000800) >> 11, (val[6] & 0x00001000) >> 12); - len += snprintf(buf + len, DMA_BUF_LEN - len, + len += snprintf(buf + len, sizeof(buf) - len, "txfifo_dcu_num_0: %2d txfifo_dcu_num_1: %2d\n", (val[6] & 0x0001e000) >> 13, (val[6] & 0x001e0000) >> 17); - len += snprintf(buf + len, DMA_BUF_LEN - len, "pcu observe: 0x%x \n", + len += snprintf(buf + len, sizeof(buf) - len, "pcu observe: 0x%x \n", REG_READ_D(ah, AR_OBS_BUS_1)); - len += snprintf(buf + len, DMA_BUF_LEN - len, + len += snprintf(buf + len, sizeof(buf) - len, "AR_CR: 0x%x \n", REG_READ_D(ah, AR_CR)); ath9k_ps_restore(sc); - retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); - kfree(buf); - return retval; + return simple_read_from_buffer(user_buf, count, ppos, buf, len); } static const struct file_operations fops_dma = { @@ -298,49 +289,23 @@ static ssize_t read_file_rcstat(struct file *file, char __user *user_buf, if (sc->cur_rate_table == NULL) return 0; - max = 80 + sc->cur_rate_table->rate_cnt * 1024; + max = 80 + sc->cur_rate_table->rate_cnt * 64; buf = kmalloc(max + 1, GFP_KERNEL); if (buf == NULL) return 0; buf[max] = 0; - len += sprintf(buf, "%6s %6s %6s " - "%10s %10s %10s %10s\n", - "HT", "MCS", "Rate", - "Success", "Retries", "XRetries", "PER"); + len += sprintf(buf, "%5s %15s %8s %9s %3s\n\n", "Rate", "Success", + "Retries", "XRetries", "PER"); for (i = 0; i < sc->cur_rate_table->rate_cnt; i++) { u32 ratekbps = sc->cur_rate_table->info[i].ratekbps; struct ath_rc_stats *stats = &sc->debug.stats.rcstats[i]; - char mcs[5]; - char htmode[5]; - int used_mcs = 0, used_htmode = 0; - - if (WLAN_RC_PHY_HT(sc->cur_rate_table->info[i].phy)) { - used_mcs = snprintf(mcs, 5, "%d", - sc->cur_rate_table->info[i].ratecode); - - if (WLAN_RC_PHY_40(sc->cur_rate_table->info[i].phy)) - used_htmode = snprintf(htmode, 5, "HT40"); - else if (WLAN_RC_PHY_20(sc->cur_rate_table->info[i].phy)) - used_htmode = snprintf(htmode, 5, "HT20"); - else - used_htmode = snprintf(htmode, 5, "????"); - } - - mcs[used_mcs] = '\0'; - htmode[used_htmode] = '\0'; len += snprintf(buf + len, max - len, - "%6s %6s %3u.%d: " - "%10u %10u %10u %10u\n", - htmode, - mcs, - ratekbps / 1000, - (ratekbps % 1000) / 100, - stats->success, - stats->retries, - stats->xretries, + "%3u.%d: %8u %8u %8u %8u\n", ratekbps / 1000, + (ratekbps % 1000) / 100, stats->success, + stats->retries, stats->xretries, stats->per); } @@ -589,116 +554,6 @@ static const struct file_operations fops_xmit = { .owner = THIS_MODULE }; -static ssize_t read_file_recv(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ -#define PHY_ERR(s, p) \ - len += snprintf(buf + len, size - len, "%18s : %10u\n", s, \ - sc->debug.stats.rxstats.phy_err_stats[p]); - - struct ath_softc *sc = file->private_data; - char *buf; - unsigned int len = 0, size = 1152; - ssize_t retval = 0; - - buf = kzalloc(size, GFP_KERNEL); - if (buf == NULL) - return 0; - - len += snprintf(buf + len, size - len, - "%18s : %10u\n", "CRC ERR", - sc->debug.stats.rxstats.crc_err); - len += snprintf(buf + len, size - len, - "%18s : %10u\n", "DECRYPT CRC ERR", - sc->debug.stats.rxstats.decrypt_crc_err); - len += snprintf(buf + len, size - len, - "%18s : %10u\n", "PHY ERR", - sc->debug.stats.rxstats.phy_err); - len += snprintf(buf + len, size - len, - "%18s : %10u\n", "MIC ERR", - sc->debug.stats.rxstats.mic_err); - len += snprintf(buf + len, size - len, - "%18s : %10u\n", "PRE-DELIM CRC ERR", - sc->debug.stats.rxstats.pre_delim_crc_err); - len += snprintf(buf + len, size - len, - "%18s : %10u\n", "POST-DELIM CRC ERR", - sc->debug.stats.rxstats.post_delim_crc_err); - len += snprintf(buf + len, size - len, - "%18s : %10u\n", "DECRYPT BUSY ERR", - sc->debug.stats.rxstats.decrypt_busy_err); - - PHY_ERR("UNDERRUN", ATH9K_PHYERR_UNDERRUN); - PHY_ERR("TIMING", ATH9K_PHYERR_TIMING); - PHY_ERR("PARITY", ATH9K_PHYERR_PARITY); - PHY_ERR("RATE", ATH9K_PHYERR_RATE); - PHY_ERR("LENGTH", ATH9K_PHYERR_LENGTH); - PHY_ERR("RADAR", ATH9K_PHYERR_RADAR); - PHY_ERR("SERVICE", ATH9K_PHYERR_SERVICE); - PHY_ERR("TOR", ATH9K_PHYERR_TOR); - PHY_ERR("OFDM-TIMING", ATH9K_PHYERR_OFDM_TIMING); - PHY_ERR("OFDM-SIGNAL-PARITY", ATH9K_PHYERR_OFDM_SIGNAL_PARITY); - PHY_ERR("OFDM-RATE", ATH9K_PHYERR_OFDM_RATE_ILLEGAL); - PHY_ERR("OFDM-LENGTH", ATH9K_PHYERR_OFDM_LENGTH_ILLEGAL); - PHY_ERR("OFDM-POWER-DROP", ATH9K_PHYERR_OFDM_POWER_DROP); - PHY_ERR("OFDM-SERVICE", ATH9K_PHYERR_OFDM_SERVICE); - PHY_ERR("OFDM-RESTART", ATH9K_PHYERR_OFDM_RESTART); - PHY_ERR("FALSE-RADAR-EXT", ATH9K_PHYERR_FALSE_RADAR_EXT); - PHY_ERR("CCK-TIMING", ATH9K_PHYERR_CCK_TIMING); - PHY_ERR("CCK-HEADER-CRC", ATH9K_PHYERR_CCK_HEADER_CRC); - PHY_ERR("CCK-RATE", ATH9K_PHYERR_CCK_RATE_ILLEGAL); - PHY_ERR("CCK-SERVICE", ATH9K_PHYERR_CCK_SERVICE); - PHY_ERR("CCK-RESTART", ATH9K_PHYERR_CCK_RESTART); - PHY_ERR("CCK-LENGTH", ATH9K_PHYERR_CCK_LENGTH_ILLEGAL); - PHY_ERR("CCK-POWER-DROP", ATH9K_PHYERR_CCK_POWER_DROP); - PHY_ERR("HT-CRC", ATH9K_PHYERR_HT_CRC_ERROR); - PHY_ERR("HT-LENGTH", ATH9K_PHYERR_HT_LENGTH_ILLEGAL); - PHY_ERR("HT-RATE", ATH9K_PHYERR_HT_RATE_ILLEGAL); - - retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); - kfree(buf); - - return retval; - -#undef PHY_ERR -} - -void ath_debug_stat_rx(struct ath_softc *sc, struct ath_buf *bf) -{ -#define RX_STAT_INC(c) sc->debug.stats.rxstats.c++ -#define RX_PHY_ERR_INC(c) sc->debug.stats.rxstats.phy_err_stats[c]++ - - struct ath_desc *ds = bf->bf_desc; - u32 phyerr; - - if (ds->ds_rxstat.rs_status & ATH9K_RXERR_CRC) - RX_STAT_INC(crc_err); - if (ds->ds_rxstat.rs_status & ATH9K_RXERR_DECRYPT) - RX_STAT_INC(decrypt_crc_err); - if (ds->ds_rxstat.rs_status & ATH9K_RXERR_MIC) - RX_STAT_INC(mic_err); - if (ds->ds_rxstat.rs_status & ATH9K_RX_DELIM_CRC_PRE) - RX_STAT_INC(pre_delim_crc_err); - if (ds->ds_rxstat.rs_status & ATH9K_RX_DELIM_CRC_POST) - RX_STAT_INC(post_delim_crc_err); - if (ds->ds_rxstat.rs_status & ATH9K_RX_DECRYPT_BUSY) - RX_STAT_INC(decrypt_busy_err); - - if (ds->ds_rxstat.rs_status & ATH9K_RXERR_PHY) { - RX_STAT_INC(phy_err); - phyerr = ds->ds_rxstat.rs_phyerr & 0x24; - RX_PHY_ERR_INC(phyerr); - } - -#undef RX_STAT_INC -#undef RX_PHY_ERR_INC -} - -static const struct file_operations fops_recv = { - .read = read_file_recv, - .open = ath9k_debugfs_open, - .owner = THIS_MODULE -}; - int ath9k_init_debug(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); @@ -751,13 +606,6 @@ int ath9k_init_debug(struct ath_hw *ah) if (!sc->debug.debugfs_xmit) goto err; - sc->debug.debugfs_recv = debugfs_create_file("recv", - S_IRUSR, - sc->debug.debugfs_phy, - sc, &fops_recv); - if (!sc->debug.debugfs_recv) - goto err; - return 0; err: ath9k_exit_debug(ah); @@ -769,7 +617,6 @@ void ath9k_exit_debug(struct ath_hw *ah) struct ath_common *common = ath9k_hw_common(ah); struct ath_softc *sc = (struct ath_softc *) common->priv; - debugfs_remove(sc->debug.debugfs_recv); debugfs_remove(sc->debug.debugfs_xmit); debugfs_remove(sc->debug.debugfs_wiphy); debugfs_remove(sc->debug.debugfs_rcstat); diff --git a/trunk/drivers/net/wireless/ath/ath9k/debug.h b/trunk/drivers/net/wireless/ath/ath9k/debug.h index 86780e68b31e..536663e3ee11 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/debug.h +++ b/trunk/drivers/net/wireless/ath/ath9k/debug.h @@ -116,35 +116,10 @@ struct ath_tx_stats { u32 delim_underrun; }; -/** - * struct ath_rx_stats - RX Statistics - * @crc_err: No. of frames with incorrect CRC value - * @decrypt_crc_err: No. of frames whose CRC check failed after - decryption process completed - * @phy_err: No. of frames whose reception failed because the PHY - encountered an error - * @mic_err: No. of frames with incorrect TKIP MIC verification failure - * @pre_delim_crc_err: Pre-Frame delimiter CRC error detections - * @post_delim_crc_err: Post-Frame delimiter CRC error detections - * @decrypt_busy_err: Decryption interruptions counter - * @phy_err_stats: Individual PHY error statistics - */ -struct ath_rx_stats { - u32 crc_err; - u32 decrypt_crc_err; - u32 phy_err; - u32 mic_err; - u32 pre_delim_crc_err; - u32 post_delim_crc_err; - u32 decrypt_busy_err; - u32 phy_err_stats[ATH9K_PHYERR_MAX]; -}; - struct ath_stats { struct ath_interrupt_stats istats; struct ath_rc_stats rcstats[RATE_TABLE_SIZE]; struct ath_tx_stats txstats[ATH9K_NUM_TX_QUEUES]; - struct ath_rx_stats rxstats; }; struct ath9k_debug { @@ -155,7 +130,6 @@ struct ath9k_debug { struct dentry *debugfs_rcstat; struct dentry *debugfs_wiphy; struct dentry *debugfs_xmit; - struct dentry *debugfs_recv; struct ath_stats stats; }; @@ -168,7 +142,6 @@ void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status); void ath_debug_stat_rc(struct ath_softc *sc, int final_rate); void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq, struct ath_buf *bf); -void ath_debug_stat_rx(struct ath_softc *sc, struct ath_buf *bf); void ath_debug_stat_retries(struct ath_softc *sc, int rix, int xretries, int retries, u8 per); @@ -208,11 +181,6 @@ static inline void ath_debug_stat_tx(struct ath_softc *sc, { } -static inline void ath_debug_stat_rx(struct ath_softc *sc, - struct ath_buf *bf) -{ -} - static inline void ath_debug_stat_retries(struct ath_softc *sc, int rix, int xretries, int retries, u8 per) { diff --git a/trunk/drivers/net/wireless/ath/ath9k/gpio.c b/trunk/drivers/net/wireless/ath/ath9k/gpio.c deleted file mode 100644 index deab8beb0680..000000000000 --- a/trunk/drivers/net/wireless/ath/ath9k/gpio.c +++ /dev/null @@ -1,442 +0,0 @@ -/* - * Copyright (c) 2008-2009 Atheros Communications Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "ath9k.h" - -/********************************/ -/* LED functions */ -/********************************/ - -static void ath_led_blink_work(struct work_struct *work) -{ - struct ath_softc *sc = container_of(work, struct ath_softc, - ath_led_blink_work.work); - - if (!(sc->sc_flags & SC_OP_LED_ASSOCIATED)) - return; - - if ((sc->led_on_duration == ATH_LED_ON_DURATION_IDLE) || - (sc->led_off_duration == ATH_LED_OFF_DURATION_IDLE)) - ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0); - else - ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, - (sc->sc_flags & SC_OP_LED_ON) ? 1 : 0); - - ieee80211_queue_delayed_work(sc->hw, - &sc->ath_led_blink_work, - (sc->sc_flags & SC_OP_LED_ON) ? - msecs_to_jiffies(sc->led_off_duration) : - msecs_to_jiffies(sc->led_on_duration)); - - sc->led_on_duration = sc->led_on_cnt ? - max((ATH_LED_ON_DURATION_IDLE - sc->led_on_cnt), 25) : - ATH_LED_ON_DURATION_IDLE; - sc->led_off_duration = sc->led_off_cnt ? - max((ATH_LED_OFF_DURATION_IDLE - sc->led_off_cnt), 10) : - ATH_LED_OFF_DURATION_IDLE; - sc->led_on_cnt = sc->led_off_cnt = 0; - if (sc->sc_flags & SC_OP_LED_ON) - sc->sc_flags &= ~SC_OP_LED_ON; - else - sc->sc_flags |= SC_OP_LED_ON; -} - -static void ath_led_brightness(struct led_classdev *led_cdev, - enum led_brightness brightness) -{ - struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev); - struct ath_softc *sc = led->sc; - - switch (brightness) { - case LED_OFF: - if (led->led_type == ATH_LED_ASSOC || - led->led_type == ATH_LED_RADIO) { - ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, - (led->led_type == ATH_LED_RADIO)); - sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; - if (led->led_type == ATH_LED_RADIO) - sc->sc_flags &= ~SC_OP_LED_ON; - } else { - sc->led_off_cnt++; - } - break; - case LED_FULL: - if (led->led_type == ATH_LED_ASSOC) { - sc->sc_flags |= SC_OP_LED_ASSOCIATED; - ieee80211_queue_delayed_work(sc->hw, - &sc->ath_led_blink_work, 0); - } else if (led->led_type == ATH_LED_RADIO) { - ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0); - sc->sc_flags |= SC_OP_LED_ON; - } else { - sc->led_on_cnt++; - } - break; - default: - break; - } -} - -static int ath_register_led(struct ath_softc *sc, struct ath_led *led, - char *trigger) -{ - int ret; - - led->sc = sc; - led->led_cdev.name = led->name; - led->led_cdev.default_trigger = trigger; - led->led_cdev.brightness_set = ath_led_brightness; - - ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->led_cdev); - if (ret) - ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL, - "Failed to register led:%s", led->name); - else - led->registered = 1; - return ret; -} - -static void ath_unregister_led(struct ath_led *led) -{ - if (led->registered) { - led_classdev_unregister(&led->led_cdev); - led->registered = 0; - } -} - -void ath_deinit_leds(struct ath_softc *sc) -{ - ath_unregister_led(&sc->assoc_led); - sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; - ath_unregister_led(&sc->tx_led); - ath_unregister_led(&sc->rx_led); - ath_unregister_led(&sc->radio_led); - ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); -} - -void ath_init_leds(struct ath_softc *sc) -{ - char *trigger; - int ret; - - if (AR_SREV_9287(sc->sc_ah)) - sc->sc_ah->led_pin = ATH_LED_PIN_9287; - else - sc->sc_ah->led_pin = ATH_LED_PIN_DEF; - - /* Configure gpio 1 for output */ - ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin, - AR_GPIO_OUTPUT_MUX_AS_OUTPUT); - /* LED off, active low */ - ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); - - INIT_DELAYED_WORK(&sc->ath_led_blink_work, ath_led_blink_work); - - trigger = ieee80211_get_radio_led_name(sc->hw); - snprintf(sc->radio_led.name, sizeof(sc->radio_led.name), - "ath9k-%s::radio", wiphy_name(sc->hw->wiphy)); - ret = ath_register_led(sc, &sc->radio_led, trigger); - sc->radio_led.led_type = ATH_LED_RADIO; - if (ret) - goto fail; - - trigger = ieee80211_get_assoc_led_name(sc->hw); - snprintf(sc->assoc_led.name, sizeof(sc->assoc_led.name), - "ath9k-%s::assoc", wiphy_name(sc->hw->wiphy)); - ret = ath_register_led(sc, &sc->assoc_led, trigger); - sc->assoc_led.led_type = ATH_LED_ASSOC; - if (ret) - goto fail; - - trigger = ieee80211_get_tx_led_name(sc->hw); - snprintf(sc->tx_led.name, sizeof(sc->tx_led.name), - "ath9k-%s::tx", wiphy_name(sc->hw->wiphy)); - ret = ath_register_led(sc, &sc->tx_led, trigger); - sc->tx_led.led_type = ATH_LED_TX; - if (ret) - goto fail; - - trigger = ieee80211_get_rx_led_name(sc->hw); - snprintf(sc->rx_led.name, sizeof(sc->rx_led.name), - "ath9k-%s::rx", wiphy_name(sc->hw->wiphy)); - ret = ath_register_led(sc, &sc->rx_led, trigger); - sc->rx_led.led_type = ATH_LED_RX; - if (ret) - goto fail; - - return; - -fail: - cancel_delayed_work_sync(&sc->ath_led_blink_work); - ath_deinit_leds(sc); -} - -/*******************/ -/* Rfkill */ -/*******************/ - -static bool ath_is_rfkill_set(struct ath_softc *sc) -{ - struct ath_hw *ah = sc->sc_ah; - - return ath9k_hw_gpio_get(ah, ah->rfkill_gpio) == - ah->rfkill_polarity; -} - -void ath9k_rfkill_poll_state(struct ieee80211_hw *hw) -{ - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - bool blocked = !!ath_is_rfkill_set(sc); - - wiphy_rfkill_set_hw_state(hw->wiphy, blocked); -} - -void ath_start_rfkill_poll(struct ath_softc *sc) -{ - struct ath_hw *ah = sc->sc_ah; - - if (ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) - wiphy_rfkill_start_polling(sc->hw->wiphy); -} - -/******************/ -/* BTCOEX */ -/******************/ - -/* - * Detects if there is any priority bt traffic - */ -static void ath_detect_bt_priority(struct ath_softc *sc) -{ - struct ath_btcoex *btcoex = &sc->btcoex; - struct ath_hw *ah = sc->sc_ah; - - if (ath9k_hw_gpio_get(sc->sc_ah, ah->btcoex_hw.btpriority_gpio)) - btcoex->bt_priority_cnt++; - - if (time_after(jiffies, btcoex->bt_priority_time + - msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) { - sc->sc_flags &= ~(SC_OP_BT_PRIORITY_DETECTED | SC_OP_BT_SCAN); - /* Detect if colocated bt started scanning */ - if (btcoex->bt_priority_cnt >= ATH_BT_CNT_SCAN_THRESHOLD) { - ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_BTCOEX, - "BT scan detected"); - sc->sc_flags |= (SC_OP_BT_SCAN | - SC_OP_BT_PRIORITY_DETECTED); - } else if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) { - ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_BTCOEX, - "BT priority traffic detected"); - sc->sc_flags |= SC_OP_BT_PRIORITY_DETECTED; - } - - btcoex->bt_priority_cnt = 0; - btcoex->bt_priority_time = jiffies; - } -} - -/* - * Configures appropriate weight based on stomp type. - */ -static void ath9k_btcoex_bt_stomp(struct ath_softc *sc, - enum ath_stomp_type stomp_type) -{ - struct ath_hw *ah = sc->sc_ah; - - switch (stomp_type) { - case ATH_BTCOEX_STOMP_ALL: - ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, - AR_STOMP_ALL_WLAN_WGHT); - break; - case ATH_BTCOEX_STOMP_LOW: - ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, - AR_STOMP_LOW_WLAN_WGHT); - break; - case ATH_BTCOEX_STOMP_NONE: - ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, - AR_STOMP_NONE_WLAN_WGHT); - break; - default: - ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX, - "Invalid Stomptype\n"); - break; - } - - ath9k_hw_btcoex_enable(ah); -} - -static void ath9k_gen_timer_start(struct ath_hw *ah, - struct ath_gen_timer *timer, - u32 timer_next, - u32 timer_period) -{ - struct ath_common *common = ath9k_hw_common(ah); - struct ath_softc *sc = (struct ath_softc *) common->priv; - - ath9k_hw_gen_timer_start(ah, timer, timer_next, timer_period); - - if ((sc->imask & ATH9K_INT_GENTIMER) == 0) { - ath9k_hw_set_interrupts(ah, 0); - sc->imask |= ATH9K_INT_GENTIMER; - ath9k_hw_set_interrupts(ah, sc->imask); - } -} - -static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer) -{ - struct ath_common *common = ath9k_hw_common(ah); - struct ath_softc *sc = (struct ath_softc *) common->priv; - struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; - - ath9k_hw_gen_timer_stop(ah, timer); - - /* if no timer is enabled, turn off interrupt mask */ - if (timer_table->timer_mask.val == 0) { - ath9k_hw_set_interrupts(ah, 0); - sc->imask &= ~ATH9K_INT_GENTIMER; - ath9k_hw_set_interrupts(ah, sc->imask); - } -} - -/* - * This is the master bt coex timer which runs for every - * 45ms, bt traffic will be given priority during 55% of this - * period while wlan gets remaining 45% - */ -static void ath_btcoex_period_timer(unsigned long data) -{ - struct ath_softc *sc = (struct ath_softc *) data; - struct ath_hw *ah = sc->sc_ah; - struct ath_btcoex *btcoex = &sc->btcoex; - u32 timer_period; - bool is_btscan; - - ath_detect_bt_priority(sc); - - is_btscan = sc->sc_flags & SC_OP_BT_SCAN; - - spin_lock_bh(&btcoex->btcoex_lock); - - ath9k_btcoex_bt_stomp(sc, is_btscan ? ATH_BTCOEX_STOMP_ALL : - btcoex->bt_stomp_type); - - spin_unlock_bh(&btcoex->btcoex_lock); - - if (btcoex->btcoex_period != btcoex->btcoex_no_stomp) { - if (btcoex->hw_timer_enabled) - ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer); - - timer_period = is_btscan ? btcoex->btscan_no_stomp : - btcoex->btcoex_no_stomp; - ath9k_gen_timer_start(ah, - btcoex->no_stomp_timer, - (ath9k_hw_gettsf32(ah) + - timer_period), timer_period * 10); - btcoex->hw_timer_enabled = true; - } - - mod_timer(&btcoex->period_timer, jiffies + - msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD)); -} - -/* - * Generic tsf based hw timer which configures weight - * registers to time slice between wlan and bt traffic - */ -static void ath_btcoex_no_stomp_timer(void *arg) -{ - struct ath_softc *sc = (struct ath_softc *)arg; - struct ath_hw *ah = sc->sc_ah; - struct ath_btcoex *btcoex = &sc->btcoex; - bool is_btscan = sc->sc_flags & SC_OP_BT_SCAN; - - ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX, - "no stomp timer running \n"); - - spin_lock_bh(&btcoex->btcoex_lock); - - if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || is_btscan) - ath9k_btcoex_bt_stomp(sc, ATH_BTCOEX_STOMP_NONE); - else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL) - ath9k_btcoex_bt_stomp(sc, ATH_BTCOEX_STOMP_LOW); - - spin_unlock_bh(&btcoex->btcoex_lock); -} - -int ath_init_btcoex_timer(struct ath_softc *sc) -{ - struct ath_btcoex *btcoex = &sc->btcoex; - - btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD * 1000; - btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) * - btcoex->btcoex_period / 100; - btcoex->btscan_no_stomp = (100 - ATH_BTCOEX_BTSCAN_DUTY_CYCLE) * - btcoex->btcoex_period / 100; - - setup_timer(&btcoex->period_timer, ath_btcoex_period_timer, - (unsigned long) sc); - - spin_lock_init(&btcoex->btcoex_lock); - - btcoex->no_stomp_timer = ath_gen_timer_alloc(sc->sc_ah, - ath_btcoex_no_stomp_timer, - ath_btcoex_no_stomp_timer, - (void *) sc, AR_FIRST_NDP_TIMER); - - if (!btcoex->no_stomp_timer) - return -ENOMEM; - - return 0; -} - -/* - * (Re)start btcoex timers - */ -void ath9k_btcoex_timer_resume(struct ath_softc *sc) -{ - struct ath_btcoex *btcoex = &sc->btcoex; - struct ath_hw *ah = sc->sc_ah; - - ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX, - "Starting btcoex timers"); - - /* make sure duty cycle timer is also stopped when resuming */ - if (btcoex->hw_timer_enabled) - ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer); - - btcoex->bt_priority_cnt = 0; - btcoex->bt_priority_time = jiffies; - sc->sc_flags &= ~(SC_OP_BT_PRIORITY_DETECTED | SC_OP_BT_SCAN); - - mod_timer(&btcoex->period_timer, jiffies); -} - - -/* - * Pause btcoex timer and bt duty cycle timer - */ -void ath9k_btcoex_timer_pause(struct ath_softc *sc) -{ - struct ath_btcoex *btcoex = &sc->btcoex; - struct ath_hw *ah = sc->sc_ah; - - del_timer_sync(&btcoex->period_timer); - - if (btcoex->hw_timer_enabled) - ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer); - - btcoex->hw_timer_enabled = false; -} diff --git a/trunk/drivers/net/wireless/ath/ath9k/hw.c b/trunk/drivers/net/wireless/ath/ath9k/hw.c index f00f5c744f48..ae371448b5a0 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/hw.c +++ b/trunk/drivers/net/wireless/ath/ath9k/hw.c @@ -52,6 +52,28 @@ module_exit(ath9k_exit); /* Helper Functions */ /********************/ +static u32 ath9k_hw_mac_usec(struct ath_hw *ah, u32 clks) +{ + struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; + + if (!ah->curchan) /* should really check for CCK instead */ + return clks / ATH9K_CLOCK_RATE_CCK; + if (conf->channel->band == IEEE80211_BAND_2GHZ) + return clks / ATH9K_CLOCK_RATE_2GHZ_OFDM; + + return clks / ATH9K_CLOCK_RATE_5GHZ_OFDM; +} + +static u32 ath9k_hw_mac_to_usec(struct ath_hw *ah, u32 clks) +{ + struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; + + if (conf_is_ht40(conf)) + return ath9k_hw_mac_usec(ah, clks) / 2; + else + return ath9k_hw_mac_usec(ah, clks); +} + static u32 ath9k_hw_mac_clks(struct ath_hw *ah, u32 usecs) { struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; @@ -321,6 +343,30 @@ static bool ath9k_hw_chip_test(struct ath_hw *ah) return true; } +static const char *ath9k_hw_devname(u16 devid) +{ + switch (devid) { + case AR5416_DEVID_PCI: + return "Atheros 5416"; + case AR5416_DEVID_PCIE: + return "Atheros 5418"; + case AR9160_DEVID_PCI: + return "Atheros 9160"; + case AR5416_AR9100_DEVID: + return "Atheros 9100"; + case AR9280_DEVID_PCI: + case AR9280_DEVID_PCIE: + return "Atheros 9280"; + case AR9285_DEVID_PCIE: + return "Atheros 9285"; + case AR5416_DEVID_AR9287_PCI: + case AR5416_DEVID_AR9287_PCIE: + return "Atheros 9287"; + } + + return NULL; +} + static void ath9k_hw_init_config(struct ath_hw *ah) { int i; @@ -334,6 +380,7 @@ static void ath9k_hw_init_config(struct ath_hw *ah) ah->config.pcie_clock_req = 0; ah->config.pcie_waen = 0; ah->config.analog_shiftreg = 1; + ah->config.ht_enable = 1; ah->config.ofdm_trig_low = 200; ah->config.ofdm_trig_high = 500; ah->config.cck_trig_high = 200; @@ -345,12 +392,7 @@ static void ath9k_hw_init_config(struct ath_hw *ah) ah->config.spurchans[i][1] = AR_NO_SPUR; } - if (ah->hw_version.devid != AR2427_DEVID_PCIE) - ah->config.ht_enable = 1; - else - ah->config.ht_enable = 0; - - ah->config.rx_intr_mitigation = true; + ah->config.intr_mitigation = true; /* * We need this for PCI devices only (Cardbus, PCI, miniPCI) @@ -395,6 +437,8 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah) ah->beacon_interval = 100; ah->enable_32kHz_clock = DONT_USE_32KHZ; ah->slottime = (u32) -1; + ah->acktimeout = (u32) -1; + ah->ctstimeout = (u32) -1; ah->globaltxtimeout = (u32) -1; ah->power_mode = ATH9K_PM_UNDEFINED; } @@ -546,7 +590,6 @@ static bool ath9k_hw_devid_supported(u16 devid) case AR5416_DEVID_AR9287_PCI: case AR5416_DEVID_AR9287_PCIE: case AR9271_USB: - case AR2427_DEVID_PCIE: return true; default: break; @@ -1140,7 +1183,7 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah, AR_IMR_RXORN | AR_IMR_BCNMISC; - if (ah->config.rx_intr_mitigation) + if (ah->config.intr_mitigation) ah->mask_reg |= AR_IMR_RXINTM | AR_IMR_RXMINTR; else ah->mask_reg |= AR_IMR_RXOK; @@ -1160,25 +1203,34 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah, } } -static void ath9k_hw_setslottime(struct ath_hw *ah, u32 us) +static bool ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us) { - u32 val = ath9k_hw_mac_to_clks(ah, us); - val = min(val, (u32) 0xFFFF); - REG_WRITE(ah, AR_D_GBL_IFS_SLOT, val); -} - -static void ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us) -{ - u32 val = ath9k_hw_mac_to_clks(ah, us); - val = min(val, (u32) MS(0xFFFFFFFF, AR_TIME_OUT_ACK)); - REG_RMW_FIELD(ah, AR_TIME_OUT, AR_TIME_OUT_ACK, val); + if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) { + ath_print(ath9k_hw_common(ah), ATH_DBG_RESET, + "bad ack timeout %u\n", us); + ah->acktimeout = (u32) -1; + return false; + } else { + REG_RMW_FIELD(ah, AR_TIME_OUT, + AR_TIME_OUT_ACK, ath9k_hw_mac_to_clks(ah, us)); + ah->acktimeout = us; + return true; + } } -static void ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us) +static bool ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us) { - u32 val = ath9k_hw_mac_to_clks(ah, us); - val = min(val, (u32) MS(0xFFFFFFFF, AR_TIME_OUT_CTS)); - REG_RMW_FIELD(ah, AR_TIME_OUT, AR_TIME_OUT_CTS, val); + if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) { + ath_print(ath9k_hw_common(ah), ATH_DBG_RESET, + "bad cts timeout %u\n", us); + ah->ctstimeout = (u32) -1; + return false; + } else { + REG_RMW_FIELD(ah, AR_TIME_OUT, + AR_TIME_OUT_CTS, ath9k_hw_mac_to_clks(ah, us)); + ah->ctstimeout = us; + return true; + } } static bool ath9k_hw_set_global_txtimeout(struct ath_hw *ah, u32 tu) @@ -1195,48 +1247,31 @@ static bool ath9k_hw_set_global_txtimeout(struct ath_hw *ah, u32 tu) } } -void ath9k_hw_init_global_settings(struct ath_hw *ah) +static void ath9k_hw_init_user_settings(struct ath_hw *ah) { - struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; - int acktimeout; - int slottime; - int sifstime; - ath_print(ath9k_hw_common(ah), ATH_DBG_RESET, "ah->misc_mode 0x%x\n", ah->misc_mode); if (ah->misc_mode != 0) REG_WRITE(ah, AR_PCU_MISC, REG_READ(ah, AR_PCU_MISC) | ah->misc_mode); - - if (conf->channel && conf->channel->band == IEEE80211_BAND_5GHZ) - sifstime = 16; - else - sifstime = 10; - - /* As defined by IEEE 802.11-2007 17.3.8.6 */ - slottime = ah->slottime + 3 * ah->coverage_class; - acktimeout = slottime + sifstime; - - /* - * Workaround for early ACK timeouts, add an offset to match the - * initval's 64us ack timeout value. - * This was initially only meant to work around an issue with delayed - * BA frames in some implementations, but it has been found to fix ACK - * timeout issues in other cases as well. - */ - if (conf->channel && conf->channel->band == IEEE80211_BAND_2GHZ) - acktimeout += 64 - sifstime - ah->slottime; - - ath9k_hw_setslottime(ah, slottime); - ath9k_hw_set_ack_timeout(ah, acktimeout); - ath9k_hw_set_cts_timeout(ah, acktimeout); + if (ah->slottime != (u32) -1) + ath9k_hw_setslottime(ah, ah->slottime); + if (ah->acktimeout != (u32) -1) + ath9k_hw_set_ack_timeout(ah, ah->acktimeout); + if (ah->ctstimeout != (u32) -1) + ath9k_hw_set_cts_timeout(ah, ah->ctstimeout); if (ah->globaltxtimeout != (u32) -1) ath9k_hw_set_global_txtimeout(ah, ah->globaltxtimeout); } -EXPORT_SYMBOL(ath9k_hw_init_global_settings); -void ath9k_hw_deinit(struct ath_hw *ah) +const char *ath9k_hw_probe(u16 vendorid, u16 devid) +{ + return vendorid == ATHEROS_VENDOR_ID ? + ath9k_hw_devname(devid) : NULL; +} + +void ath9k_hw_detach(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); @@ -1254,7 +1289,7 @@ void ath9k_hw_deinit(struct ath_hw *ah) kfree(ah); ah = NULL; } -EXPORT_SYMBOL(ath9k_hw_deinit); +EXPORT_SYMBOL(ath9k_hw_detach); /*******/ /* INI */ @@ -2055,7 +2090,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, if (ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) ath9k_enable_rfkill(ah); - ath9k_hw_init_global_settings(ah); + ath9k_hw_init_user_settings(ah); if (AR_SREV_9287_12_OR_LATER(ah)) { REG_WRITE(ah, AR_D_GBL_IFS_SIFS, @@ -2085,7 +2120,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, REG_WRITE(ah, AR_OBS, 8); - if (ah->config.rx_intr_mitigation) { + if (ah->config.intr_mitigation) { REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, 500); REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, 2000); } @@ -2745,7 +2780,7 @@ bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked) *masked = isr & ATH9K_INT_COMMON; - if (ah->config.rx_intr_mitigation) { + if (ah->config.intr_mitigation) { if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM)) *masked |= ATH9K_INT_RX; } @@ -2878,7 +2913,7 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints) } if (ints & ATH9K_INT_RX) { mask |= AR_IMR_RXERR; - if (ah->config.rx_intr_mitigation) + if (ah->config.intr_mitigation) mask |= AR_IMR_RXMINTR | AR_IMR_RXINTM; else mask |= AR_IMR_RXOK | AR_IMR_RXDESC; @@ -3652,6 +3687,21 @@ u64 ath9k_hw_extend_tsf(struct ath_hw *ah, u32 rstamp) } EXPORT_SYMBOL(ath9k_hw_extend_tsf); +bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us) +{ + if (us < ATH9K_SLOT_TIME_9 || us > ath9k_hw_mac_to_usec(ah, 0xffff)) { + ath_print(ath9k_hw_common(ah), ATH_DBG_RESET, + "bad slot time %u\n", us); + ah->slottime = (u32) -1; + return false; + } else { + REG_WRITE(ah, AR_D_GBL_IFS_SLOT, ath9k_hw_mac_to_clks(ah, us)); + ah->slottime = us; + return true; + } +} +EXPORT_SYMBOL(ath9k_hw_setslottime); + void ath9k_hw_set11nmac2040(struct ath_hw *ah) { struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; diff --git a/trunk/drivers/net/wireless/ath/ath9k/hw.h b/trunk/drivers/net/wireless/ath/ath9k/hw.h index dbbf7ca5f97d..e2b0c73a616f 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/hw.h +++ b/trunk/drivers/net/wireless/ath/ath9k/hw.h @@ -40,7 +40,6 @@ #define AR9280_DEVID_PCI 0x0029 #define AR9280_DEVID_PCIE 0x002a #define AR9285_DEVID_PCIE 0x002b -#define AR2427_DEVID_PCIE 0x002c #define AR5416_AR9100_DEVID 0x000b @@ -213,7 +212,7 @@ struct ath9k_ops_config { u32 cck_trig_low; u32 enable_ani; int serialize_regmode; - bool rx_intr_mitigation; + bool intr_mitigation; #define SPUR_DISABLE 0 #define SPUR_ENABLE_IOCTL 1 #define SPUR_ENABLE_EEPROM 2 @@ -552,9 +551,10 @@ struct ath_hw { u32 *bank6Temp; int16_t txpower_indexoffset; - int coverage_class; u32 beacon_interval; u32 slottime; + u32 acktimeout; + u32 ctstimeout; u32 globaltxtimeout; /* ANI */ @@ -616,7 +616,7 @@ static inline struct ath_regulatory *ath9k_hw_regulatory(struct ath_hw *ah) /* Initialization, Detach, Reset */ const char *ath9k_hw_probe(u16 vendorid, u16 devid); -void ath9k_hw_deinit(struct ath_hw *ah); +void ath9k_hw_detach(struct ath_hw *ah); int ath9k_hw_init(struct ath_hw *ah); int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, bool bChannelChange); @@ -668,7 +668,7 @@ void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64); void ath9k_hw_reset_tsf(struct ath_hw *ah); void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting); u64 ath9k_hw_extend_tsf(struct ath_hw *ah, u32 rstamp); -void ath9k_hw_init_global_settings(struct ath_hw *ah); +bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us); void ath9k_hw_set11nmac2040(struct ath_hw *ah); void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period); void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, diff --git a/trunk/drivers/net/wireless/ath/ath9k/init.c b/trunk/drivers/net/wireless/ath/ath9k/init.c deleted file mode 100644 index 623c2f884987..000000000000 --- a/trunk/drivers/net/wireless/ath/ath9k/init.c +++ /dev/null @@ -1,863 +0,0 @@ -/* - * Copyright (c) 2008-2009 Atheros Communications Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "ath9k.h" - -static char *dev_info = "ath9k"; - -MODULE_AUTHOR("Atheros Communications"); -MODULE_DESCRIPTION("Support for Atheros 802.11n wireless LAN cards."); -MODULE_SUPPORTED_DEVICE("Atheros 802.11n WLAN cards"); -MODULE_LICENSE("Dual BSD/GPL"); - -static unsigned int ath9k_debug = ATH_DBG_DEFAULT; -module_param_named(debug, ath9k_debug, uint, 0); -MODULE_PARM_DESC(debug, "Debugging mask"); - -int modparam_nohwcrypt; -module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444); -MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption"); - -/* We use the hw_value as an index into our private channel structure */ - -#define CHAN2G(_freq, _idx) { \ - .center_freq = (_freq), \ - .hw_value = (_idx), \ - .max_power = 20, \ -} - -#define CHAN5G(_freq, _idx) { \ - .band = IEEE80211_BAND_5GHZ, \ - .center_freq = (_freq), \ - .hw_value = (_idx), \ - .max_power = 20, \ -} - -/* Some 2 GHz radios are actually tunable on 2312-2732 - * on 5 MHz steps, we support the channels which we know - * we have calibration data for all cards though to make - * this static */ -static struct ieee80211_channel ath9k_2ghz_chantable[] = { - CHAN2G(2412, 0), /* Channel 1 */ - CHAN2G(2417, 1), /* Channel 2 */ - CHAN2G(2422, 2), /* Channel 3 */ - CHAN2G(2427, 3), /* Channel 4 */ - CHAN2G(2432, 4), /* Channel 5 */ - CHAN2G(2437, 5), /* Channel 6 */ - CHAN2G(2442, 6), /* Channel 7 */ - CHAN2G(2447, 7), /* Channel 8 */ - CHAN2G(2452, 8), /* Channel 9 */ - CHAN2G(2457, 9), /* Channel 10 */ - CHAN2G(2462, 10), /* Channel 11 */ - CHAN2G(2467, 11), /* Channel 12 */ - CHAN2G(2472, 12), /* Channel 13 */ - CHAN2G(2484, 13), /* Channel 14 */ -}; - -/* Some 5 GHz radios are actually tunable on XXXX-YYYY - * on 5 MHz steps, we support the channels which we know - * we have calibration data for all cards though to make - * this static */ -static struct ieee80211_channel ath9k_5ghz_chantable[] = { - /* _We_ call this UNII 1 */ - CHAN5G(5180, 14), /* Channel 36 */ - CHAN5G(5200, 15), /* Channel 40 */ - CHAN5G(5220, 16), /* Channel 44 */ - CHAN5G(5240, 17), /* Channel 48 */ - /* _We_ call this UNII 2 */ - CHAN5G(5260, 18), /* Channel 52 */ - CHAN5G(5280, 19), /* Channel 56 */ - CHAN5G(5300, 20), /* Channel 60 */ - CHAN5G(5320, 21), /* Channel 64 */ - /* _We_ call this "Middle band" */ - CHAN5G(5500, 22), /* Channel 100 */ - CHAN5G(5520, 23), /* Channel 104 */ - CHAN5G(5540, 24), /* Channel 108 */ - CHAN5G(5560, 25), /* Channel 112 */ - CHAN5G(5580, 26), /* Channel 116 */ - CHAN5G(5600, 27), /* Channel 120 */ - CHAN5G(5620, 28), /* Channel 124 */ - CHAN5G(5640, 29), /* Channel 128 */ - CHAN5G(5660, 30), /* Channel 132 */ - CHAN5G(5680, 31), /* Channel 136 */ - CHAN5G(5700, 32), /* Channel 140 */ - /* _We_ call this UNII 3 */ - CHAN5G(5745, 33), /* Channel 149 */ - CHAN5G(5765, 34), /* Channel 153 */ - CHAN5G(5785, 35), /* Channel 157 */ - CHAN5G(5805, 36), /* Channel 161 */ - CHAN5G(5825, 37), /* Channel 165 */ -}; - -/* Atheros hardware rate code addition for short premble */ -#define SHPCHECK(__hw_rate, __flags) \ - ((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04 ) : 0) - -#define RATE(_bitrate, _hw_rate, _flags) { \ - .bitrate = (_bitrate), \ - .flags = (_flags), \ - .hw_value = (_hw_rate), \ - .hw_value_short = (SHPCHECK(_hw_rate, _flags)) \ -} - -static struct ieee80211_rate ath9k_legacy_rates[] = { - RATE(10, 0x1b, 0), - RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE), - RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE), - RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE), - RATE(60, 0x0b, 0), - RATE(90, 0x0f, 0), - RATE(120, 0x0a, 0), - RATE(180, 0x0e, 0), - RATE(240, 0x09, 0), - RATE(360, 0x0d, 0), - RATE(480, 0x08, 0), - RATE(540, 0x0c, 0), -}; - -static void ath9k_deinit_softc(struct ath_softc *sc); - -/* - * Read and write, they both share the same lock. We do this to serialize - * reads and writes on Atheros 802.11n PCI devices only. This is required - * as the FIFO on these devices can only accept sanely 2 requests. - */ - -static void ath9k_iowrite32(void *hw_priv, u32 val, u32 reg_offset) -{ - struct ath_hw *ah = (struct ath_hw *) hw_priv; - struct ath_common *common = ath9k_hw_common(ah); - struct ath_softc *sc = (struct ath_softc *) common->priv; - - if (ah->config.serialize_regmode == SER_REG_MODE_ON) { - unsigned long flags; - spin_lock_irqsave(&sc->sc_serial_rw, flags); - iowrite32(val, sc->mem + reg_offset); - spin_unlock_irqrestore(&sc->sc_serial_rw, flags); - } else - iowrite32(val, sc->mem + reg_offset); -} - -static unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset) -{ - struct ath_hw *ah = (struct ath_hw *) hw_priv; - struct ath_common *common = ath9k_hw_common(ah); - struct ath_softc *sc = (struct ath_softc *) common->priv; - u32 val; - - if (ah->config.serialize_regmode == SER_REG_MODE_ON) { - unsigned long flags; - spin_lock_irqsave(&sc->sc_serial_rw, flags); - val = ioread32(sc->mem + reg_offset); - spin_unlock_irqrestore(&sc->sc_serial_rw, flags); - } else - val = ioread32(sc->mem + reg_offset); - return val; -} - -static const struct ath_ops ath9k_common_ops = { - .read = ath9k_ioread32, - .write = ath9k_iowrite32, -}; - -/**************************/ -/* Initialization */ -/**************************/ - -static void setup_ht_cap(struct ath_softc *sc, - struct ieee80211_sta_ht_cap *ht_info) -{ - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - u8 tx_streams, rx_streams; - - ht_info->ht_supported = true; - ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | - IEEE80211_HT_CAP_SM_PS | - IEEE80211_HT_CAP_SGI_40 | - IEEE80211_HT_CAP_DSSSCCK40; - - ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; - ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8; - - /* set up supported mcs set */ - memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); - tx_streams = !(common->tx_chainmask & (common->tx_chainmask - 1)) ? - 1 : 2; - rx_streams = !(common->rx_chainmask & (common->rx_chainmask - 1)) ? - 1 : 2; - - if (tx_streams != rx_streams) { - ath_print(common, ATH_DBG_CONFIG, - "TX streams %d, RX streams: %d\n", - tx_streams, rx_streams); - ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; - ht_info->mcs.tx_params |= ((tx_streams - 1) << - IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); - } - - ht_info->mcs.rx_mask[0] = 0xff; - if (rx_streams >= 2) - ht_info->mcs.rx_mask[1] = 0xff; - - ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED; -} - -static int ath9k_reg_notifier(struct wiphy *wiphy, - struct regulatory_request *request) -{ - struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - struct ath_regulatory *reg = ath9k_hw_regulatory(sc->sc_ah); - - return ath_reg_notifier_apply(wiphy, request, reg); -} - -/* - * This function will allocate both the DMA descriptor structure, and the - * buffers it contains. These are used to contain the descriptors used - * by the system. -*/ -int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, - struct list_head *head, const char *name, - int nbuf, int ndesc) -{ -#define DS2PHYS(_dd, _ds) \ - ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc)) -#define ATH_DESC_4KB_BOUND_CHECK(_daddr) ((((_daddr) & 0xFFF) > 0xF7F) ? 1 : 0) -#define ATH_DESC_4KB_BOUND_NUM_SKIPPED(_len) ((_len) / 4096) - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ath_desc *ds; - struct ath_buf *bf; - int i, bsize, error; - - ath_print(common, ATH_DBG_CONFIG, "%s DMA: %u buffers %u desc/buf\n", - name, nbuf, ndesc); - - INIT_LIST_HEAD(head); - /* ath_desc must be a multiple of DWORDs */ - if ((sizeof(struct ath_desc) % 4) != 0) { - ath_print(common, ATH_DBG_FATAL, - "ath_desc not DWORD aligned\n"); - BUG_ON((sizeof(struct ath_desc) % 4) != 0); - error = -ENOMEM; - goto fail; - } - - dd->dd_desc_len = sizeof(struct ath_desc) * nbuf * ndesc; - - /* - * Need additional DMA memory because we can't use - * descriptors that cross the 4K page boundary. Assume - * one skipped descriptor per 4K page. - */ - if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_4KB_SPLITTRANS)) { - u32 ndesc_skipped = - ATH_DESC_4KB_BOUND_NUM_SKIPPED(dd->dd_desc_len); - u32 dma_len; - - while (ndesc_skipped) { - dma_len = ndesc_skipped * sizeof(struct ath_desc); - dd->dd_desc_len += dma_len; - - ndesc_skipped = ATH_DESC_4KB_BOUND_NUM_SKIPPED(dma_len); - }; - } - - /* allocate descriptors */ - dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len, - &dd->dd_desc_paddr, GFP_KERNEL); - if (dd->dd_desc == NULL) { - error = -ENOMEM; - goto fail; - } - ds = dd->dd_desc; - ath_print(common, ATH_DBG_CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n", - name, ds, (u32) dd->dd_desc_len, - ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len); - - /* allocate buffers */ - bsize = sizeof(struct ath_buf) * nbuf; - bf = kzalloc(bsize, GFP_KERNEL); - if (bf == NULL) { - error = -ENOMEM; - goto fail2; - } - dd->dd_bufptr = bf; - - for (i = 0; i < nbuf; i++, bf++, ds += ndesc) { - bf->bf_desc = ds; - bf->bf_daddr = DS2PHYS(dd, ds); - - if (!(sc->sc_ah->caps.hw_caps & - ATH9K_HW_CAP_4KB_SPLITTRANS)) { - /* - * Skip descriptor addresses which can cause 4KB - * boundary crossing (addr + length) with a 32 dword - * descriptor fetch. - */ - while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) { - BUG_ON((caddr_t) bf->bf_desc >= - ((caddr_t) dd->dd_desc + - dd->dd_desc_len)); - - ds += ndesc; - bf->bf_desc = ds; - bf->bf_daddr = DS2PHYS(dd, ds); - } - } - list_add_tail(&bf->list, head); - } - return 0; -fail2: - dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc, - dd->dd_desc_paddr); -fail: - memset(dd, 0, sizeof(*dd)); - return error; -#undef ATH_DESC_4KB_BOUND_CHECK -#undef ATH_DESC_4KB_BOUND_NUM_SKIPPED -#undef DS2PHYS -} - -static void ath9k_init_crypto(struct ath_softc *sc) -{ - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - int i = 0; - - /* Get the hardware key cache size. */ - common->keymax = sc->sc_ah->caps.keycache_size; - if (common->keymax > ATH_KEYMAX) { - ath_print(common, ATH_DBG_ANY, - "Warning, using only %u entries in %u key cache\n", - ATH_KEYMAX, common->keymax); - common->keymax = ATH_KEYMAX; - } - - /* - * Reset the key cache since some parts do not - * reset the contents on initial power up. - */ - for (i = 0; i < common->keymax; i++) - ath9k_hw_keyreset(sc->sc_ah, (u16) i); - - if (ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_CIPHER, - ATH9K_CIPHER_TKIP, NULL)) { - /* - * Whether we should enable h/w TKIP MIC. - * XXX: if we don't support WME TKIP MIC, then we wouldn't - * report WMM capable, so it's always safe to turn on - * TKIP MIC in this case. - */ - ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_TKIP_MIC, 0, 1, NULL); - } - - /* - * Check whether the separate key cache entries - * are required to handle both tx+rx MIC keys. - * With split mic keys the number of stations is limited - * to 27 otherwise 59. - */ - if (ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_CIPHER, - ATH9K_CIPHER_TKIP, NULL) - && ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_CIPHER, - ATH9K_CIPHER_MIC, NULL) - && ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_TKIP_SPLIT, - 0, NULL)) - common->splitmic = 1; - - /* turn on mcast key search if possible */ - if (!ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL)) - (void)ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_MCAST_KEYSRCH, - 1, 1, NULL); - -} - -static int ath9k_init_btcoex(struct ath_softc *sc) -{ - int r, qnum; - - switch (sc->sc_ah->btcoex_hw.scheme) { - case ATH_BTCOEX_CFG_NONE: - break; - case ATH_BTCOEX_CFG_2WIRE: - ath9k_hw_btcoex_init_2wire(sc->sc_ah); - break; - case ATH_BTCOEX_CFG_3WIRE: - ath9k_hw_btcoex_init_3wire(sc->sc_ah); - r = ath_init_btcoex_timer(sc); - if (r) - return -1; - qnum = ath_tx_get_qnum(sc, ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE); - ath9k_hw_init_btcoex_hw(sc->sc_ah, qnum); - sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW; - break; - default: - WARN_ON(1); - break; - } - - return 0; -} - -static int ath9k_init_queues(struct ath_softc *sc) -{ - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - int i = 0; - - for (i = 0; i < ARRAY_SIZE(sc->tx.hwq_map); i++) - sc->tx.hwq_map[i] = -1; - - sc->beacon.beaconq = ath9k_hw_beaconq_setup(sc->sc_ah); - if (sc->beacon.beaconq == -1) { - ath_print(common, ATH_DBG_FATAL, - "Unable to setup a beacon xmit queue\n"); - goto err; - } - - sc->beacon.cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0); - if (sc->beacon.cabq == NULL) { - ath_print(common, ATH_DBG_FATAL, - "Unable to setup CAB xmit queue\n"); - goto err; - } - - sc->config.cabqReadytime = ATH_CABQ_READY_TIME; - ath_cabq_update(sc); - - if (!ath_tx_setup(sc, ATH9K_WME_AC_BK)) { - ath_print(common, ATH_DBG_FATAL, - "Unable to setup xmit queue for BK traffic\n"); - goto err; - } - - if (!ath_tx_setup(sc, ATH9K_WME_AC_BE)) { - ath_print(common, ATH_DBG_FATAL, - "Unable to setup xmit queue for BE traffic\n"); - goto err; - } - if (!ath_tx_setup(sc, ATH9K_WME_AC_VI)) { - ath_print(common, ATH_DBG_FATAL, - "Unable to setup xmit queue for VI traffic\n"); - goto err; - } - if (!ath_tx_setup(sc, ATH9K_WME_AC_VO)) { - ath_print(common, ATH_DBG_FATAL, - "Unable to setup xmit queue for VO traffic\n"); - goto err; - } - - return 0; - -err: - for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) - if (ATH_TXQ_SETUP(sc, i)) - ath_tx_cleanupq(sc, &sc->tx.txq[i]); - - return -EIO; -} - -static void ath9k_init_channels_rates(struct ath_softc *sc) -{ - if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes)) { - sc->sbands[IEEE80211_BAND_2GHZ].channels = ath9k_2ghz_chantable; - sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; - sc->sbands[IEEE80211_BAND_2GHZ].n_channels = - ARRAY_SIZE(ath9k_2ghz_chantable); - sc->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates; - sc->sbands[IEEE80211_BAND_2GHZ].n_bitrates = - ARRAY_SIZE(ath9k_legacy_rates); - } - - if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) { - sc->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_chantable; - sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ; - sc->sbands[IEEE80211_BAND_5GHZ].n_channels = - ARRAY_SIZE(ath9k_5ghz_chantable); - sc->sbands[IEEE80211_BAND_5GHZ].bitrates = - ath9k_legacy_rates + 4; - sc->sbands[IEEE80211_BAND_5GHZ].n_bitrates = - ARRAY_SIZE(ath9k_legacy_rates) - 4; - } -} - -static void ath9k_init_misc(struct ath_softc *sc) -{ - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - int i = 0; - - common->ani.noise_floor = ATH_DEFAULT_NOISE_FLOOR; - setup_timer(&common->ani.timer, ath_ani_calibrate, (unsigned long)sc); - - sc->config.txpowlimit = ATH_TXPOWER_MAX; - - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { - sc->sc_flags |= SC_OP_TXAGGR; - sc->sc_flags |= SC_OP_RXAGGR; - } - - common->tx_chainmask = sc->sc_ah->caps.tx_chainmask; - common->rx_chainmask = sc->sc_ah->caps.rx_chainmask; - - ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_DIVERSITY, 1, true, NULL); - sc->rx.defant = ath9k_hw_getdefantenna(sc->sc_ah); - - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) - memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN); - - sc->beacon.slottime = ATH9K_SLOT_TIME_9; - - for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) { - sc->beacon.bslot[i] = NULL; - sc->beacon.bslot_aphy[i] = NULL; - } -} - -static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, - const struct ath_bus_ops *bus_ops) -{ - struct ath_hw *ah = NULL; - struct ath_common *common; - int ret = 0, i; - int csz = 0; - - ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL); - if (!ah) - return -ENOMEM; - - ah->hw_version.devid = devid; - ah->hw_version.subsysid = subsysid; - sc->sc_ah = ah; - - common = ath9k_hw_common(ah); - common->ops = &ath9k_common_ops; - common->bus_ops = bus_ops; - common->ah = ah; - common->hw = sc->hw; - common->priv = sc; - common->debug_mask = ath9k_debug; - - spin_lock_init(&sc->wiphy_lock); - spin_lock_init(&sc->sc_resetlock); - spin_lock_init(&sc->sc_serial_rw); - spin_lock_init(&sc->sc_pm_lock); - mutex_init(&sc->mutex); - tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); - tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet, - (unsigned long)sc); - - /* - * Cache line size is used to size and align various - * structures used to communicate with the hardware. - */ - ath_read_cachesize(common, &csz); - common->cachelsz = csz << 2; /* convert to bytes */ - - ret = ath9k_hw_init(ah); - if (ret) { - ath_print(common, ATH_DBG_FATAL, - "Unable to initialize hardware; " - "initialization status: %d\n", ret); - goto err_hw; - } - - ret = ath9k_init_debug(ah); - if (ret) { - ath_print(common, ATH_DBG_FATAL, - "Unable to create debugfs files\n"); - goto err_debug; - } - - ret = ath9k_init_queues(sc); - if (ret) - goto err_queues; - - ret = ath9k_init_btcoex(sc); - if (ret) - goto err_btcoex; - - ath9k_init_crypto(sc); - ath9k_init_channels_rates(sc); - ath9k_init_misc(sc); - - return 0; - -err_btcoex: - for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) - if (ATH_TXQ_SETUP(sc, i)) - ath_tx_cleanupq(sc, &sc->tx.txq[i]); -err_queues: - ath9k_exit_debug(ah); -err_debug: - ath9k_hw_deinit(ah); -err_hw: - tasklet_kill(&sc->intr_tq); - tasklet_kill(&sc->bcon_tasklet); - - kfree(ah); - sc->sc_ah = NULL; - - return ret; -} - -void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) -{ - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - - hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_SUPPORTS_PS | - IEEE80211_HW_PS_NULLFUNC_STACK | - IEEE80211_HW_SPECTRUM_MGMT | - IEEE80211_HW_REPORTS_TX_ACK_STATUS; - - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) - hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION; - - if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || modparam_nohwcrypt) - hw->flags |= IEEE80211_HW_MFP_CAPABLE; - - hw->wiphy->interface_modes = - BIT(NL80211_IFTYPE_AP) | - BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC) | - BIT(NL80211_IFTYPE_MESH_POINT); - - hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; - - hw->queues = 4; - hw->max_rates = 4; - hw->channel_change_time = 5000; - hw->max_listen_interval = 10; - hw->max_rate_tries = 10; - hw->sta_data_size = sizeof(struct ath_node); - hw->vif_data_size = sizeof(struct ath_vif); - - hw->rate_control_algorithm = "ath9k_rate_control"; - - if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes)) - hw->wiphy->bands[IEEE80211_BAND_2GHZ] = - &sc->sbands[IEEE80211_BAND_2GHZ]; - if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) - hw->wiphy->bands[IEEE80211_BAND_5GHZ] = - &sc->sbands[IEEE80211_BAND_5GHZ]; - - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { - if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes)) - setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); - if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) - setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap); - } - - SET_IEEE80211_PERM_ADDR(hw, common->macaddr); -} - -int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, - const struct ath_bus_ops *bus_ops) -{ - struct ieee80211_hw *hw = sc->hw; - struct ath_common *common; - struct ath_hw *ah; - int error = 0; - struct ath_regulatory *reg; - - /* Bring up device */ - error = ath9k_init_softc(devid, sc, subsysid, bus_ops); - if (error != 0) - goto error_init; - - ah = sc->sc_ah; - common = ath9k_hw_common(ah); - ath9k_set_hw_capab(sc, hw); - - /* Initialize regulatory */ - error = ath_regd_init(&common->regulatory, sc->hw->wiphy, - ath9k_reg_notifier); - if (error) - goto error_regd; - - reg = &common->regulatory; - - /* Setup TX DMA */ - error = ath_tx_init(sc, ATH_TXBUF); - if (error != 0) - goto error_tx; - - /* Setup RX DMA */ - error = ath_rx_init(sc, ATH_RXBUF); - if (error != 0) - goto error_rx; - - /* Register with mac80211 */ - error = ieee80211_register_hw(hw); - if (error) - goto error_register; - - /* Handle world regulatory */ - if (!ath_is_world_regd(reg)) { - error = regulatory_hint(hw->wiphy, reg->alpha2); - if (error) - goto error_world; - } - - INIT_WORK(&sc->chan_work, ath9k_wiphy_chan_work); - INIT_DELAYED_WORK(&sc->wiphy_work, ath9k_wiphy_work); - sc->wiphy_scheduler_int = msecs_to_jiffies(500); - - ath_init_leds(sc); - ath_start_rfkill_poll(sc); - - return 0; - -error_world: - ieee80211_unregister_hw(hw); -error_register: - ath_rx_cleanup(sc); -error_rx: - ath_tx_cleanup(sc); -error_tx: - /* Nothing */ -error_regd: - ath9k_deinit_softc(sc); -error_init: - return error; -} - -/*****************************/ -/* De-Initialization */ -/*****************************/ - -static void ath9k_deinit_softc(struct ath_softc *sc) -{ - int i = 0; - - if ((sc->btcoex.no_stomp_timer) && - sc->sc_ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) - ath_gen_timer_free(sc->sc_ah, sc->btcoex.no_stomp_timer); - - for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) - if (ATH_TXQ_SETUP(sc, i)) - ath_tx_cleanupq(sc, &sc->tx.txq[i]); - - ath9k_exit_debug(sc->sc_ah); - ath9k_hw_deinit(sc->sc_ah); - - tasklet_kill(&sc->intr_tq); - tasklet_kill(&sc->bcon_tasklet); -} - -void ath9k_deinit_device(struct ath_softc *sc) -{ - struct ieee80211_hw *hw = sc->hw; - int i = 0; - - ath9k_ps_wakeup(sc); - - wiphy_rfkill_stop_polling(sc->hw->wiphy); - ath_deinit_leds(sc); - - for (i = 0; i < sc->num_sec_wiphy; i++) { - struct ath_wiphy *aphy = sc->sec_wiphy[i]; - if (aphy == NULL) - continue; - sc->sec_wiphy[i] = NULL; - ieee80211_unregister_hw(aphy->hw); - ieee80211_free_hw(aphy->hw); - } - kfree(sc->sec_wiphy); - - ieee80211_unregister_hw(hw); - ath_rx_cleanup(sc); - ath_tx_cleanup(sc); - ath9k_deinit_softc(sc); -} - -void ath_descdma_cleanup(struct ath_softc *sc, - struct ath_descdma *dd, - struct list_head *head) -{ - dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc, - dd->dd_desc_paddr); - - INIT_LIST_HEAD(head); - kfree(dd->dd_bufptr); - memset(dd, 0, sizeof(*dd)); -} - -/************************/ -/* Module Hooks */ -/************************/ - -static int __init ath9k_init(void) -{ - int error; - - /* Register rate control algorithm */ - error = ath_rate_control_register(); - if (error != 0) { - printk(KERN_ERR - "ath9k: Unable to register rate control " - "algorithm: %d\n", - error); - goto err_out; - } - - error = ath9k_debug_create_root(); - if (error) { - printk(KERN_ERR - "ath9k: Unable to create debugfs root: %d\n", - error); - goto err_rate_unregister; - } - - error = ath_pci_init(); - if (error < 0) { - printk(KERN_ERR - "ath9k: No PCI devices found, driver not installed.\n"); - error = -ENODEV; - goto err_remove_root; - } - - error = ath_ahb_init(); - if (error < 0) { - error = -ENODEV; - goto err_pci_exit; - } - - return 0; - - err_pci_exit: - ath_pci_exit(); - - err_remove_root: - ath9k_debug_remove_root(); - err_rate_unregister: - ath_rate_control_unregister(); - err_out: - return error; -} -module_init(ath9k_init); - -static void __exit ath9k_exit(void) -{ - ath_ahb_exit(); - ath_pci_exit(); - ath9k_debug_remove_root(); - ath_rate_control_unregister(); - printk(KERN_INFO "%s: Driver unloaded\n", dev_info); -} -module_exit(ath9k_exit); diff --git a/trunk/drivers/net/wireless/ath/ath9k/mac.h b/trunk/drivers/net/wireless/ath/ath9k/mac.h index 29851e6376a9..e185479e295e 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/mac.h +++ b/trunk/drivers/net/wireless/ath/ath9k/mac.h @@ -167,40 +167,6 @@ struct ath_rx_status { #define ATH9K_RXKEYIX_INVALID ((u8)-1) #define ATH9K_TXKEYIX_INVALID ((u32)-1) -enum ath9k_phyerr { - ATH9K_PHYERR_UNDERRUN = 0, /* Transmit underrun */ - ATH9K_PHYERR_TIMING = 1, /* Timing error */ - ATH9K_PHYERR_PARITY = 2, /* Illegal parity */ - ATH9K_PHYERR_RATE = 3, /* Illegal rate */ - ATH9K_PHYERR_LENGTH = 4, /* Illegal length */ - ATH9K_PHYERR_RADAR = 5, /* Radar detect */ - ATH9K_PHYERR_SERVICE = 6, /* Illegal service */ - ATH9K_PHYERR_TOR = 7, /* Transmit override receive */ - - ATH9K_PHYERR_OFDM_TIMING = 17, - ATH9K_PHYERR_OFDM_SIGNAL_PARITY = 18, - ATH9K_PHYERR_OFDM_RATE_ILLEGAL = 19, - ATH9K_PHYERR_OFDM_LENGTH_ILLEGAL = 20, - ATH9K_PHYERR_OFDM_POWER_DROP = 21, - ATH9K_PHYERR_OFDM_SERVICE = 22, - ATH9K_PHYERR_OFDM_RESTART = 23, - ATH9K_PHYERR_FALSE_RADAR_EXT = 24, - - ATH9K_PHYERR_CCK_TIMING = 25, - ATH9K_PHYERR_CCK_HEADER_CRC = 26, - ATH9K_PHYERR_CCK_RATE_ILLEGAL = 27, - ATH9K_PHYERR_CCK_SERVICE = 30, - ATH9K_PHYERR_CCK_RESTART = 31, - ATH9K_PHYERR_CCK_LENGTH_ILLEGAL = 32, - ATH9K_PHYERR_CCK_POWER_DROP = 33, - - ATH9K_PHYERR_HT_CRC_ERROR = 34, - ATH9K_PHYERR_HT_LENGTH_ILLEGAL = 35, - ATH9K_PHYERR_HT_RATE_ILLEGAL = 36, - - ATH9K_PHYERR_MAX = 37, -}; - struct ath_desc { u32 ds_link; u32 ds_data; diff --git a/trunk/drivers/net/wireless/ath/ath9k/main.c b/trunk/drivers/net/wireless/ath/ath9k/main.c index 67ca4e5a6017..643bea35686f 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/main.c +++ b/trunk/drivers/net/wireless/ath/ath9k/main.c @@ -18,6 +18,118 @@ #include "ath9k.h" #include "btcoex.h" +static char *dev_info = "ath9k"; + +MODULE_AUTHOR("Atheros Communications"); +MODULE_DESCRIPTION("Support for Atheros 802.11n wireless LAN cards."); +MODULE_SUPPORTED_DEVICE("Atheros 802.11n WLAN cards"); +MODULE_LICENSE("Dual BSD/GPL"); + +static int modparam_nohwcrypt; +module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444); +MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption"); + +static unsigned int ath9k_debug = ATH_DBG_DEFAULT; +module_param_named(debug, ath9k_debug, uint, 0); +MODULE_PARM_DESC(debug, "Debugging mask"); + +/* We use the hw_value as an index into our private channel structure */ + +#define CHAN2G(_freq, _idx) { \ + .center_freq = (_freq), \ + .hw_value = (_idx), \ + .max_power = 20, \ +} + +#define CHAN5G(_freq, _idx) { \ + .band = IEEE80211_BAND_5GHZ, \ + .center_freq = (_freq), \ + .hw_value = (_idx), \ + .max_power = 20, \ +} + +/* Some 2 GHz radios are actually tunable on 2312-2732 + * on 5 MHz steps, we support the channels which we know + * we have calibration data for all cards though to make + * this static */ +static struct ieee80211_channel ath9k_2ghz_chantable[] = { + CHAN2G(2412, 0), /* Channel 1 */ + CHAN2G(2417, 1), /* Channel 2 */ + CHAN2G(2422, 2), /* Channel 3 */ + CHAN2G(2427, 3), /* Channel 4 */ + CHAN2G(2432, 4), /* Channel 5 */ + CHAN2G(2437, 5), /* Channel 6 */ + CHAN2G(2442, 6), /* Channel 7 */ + CHAN2G(2447, 7), /* Channel 8 */ + CHAN2G(2452, 8), /* Channel 9 */ + CHAN2G(2457, 9), /* Channel 10 */ + CHAN2G(2462, 10), /* Channel 11 */ + CHAN2G(2467, 11), /* Channel 12 */ + CHAN2G(2472, 12), /* Channel 13 */ + CHAN2G(2484, 13), /* Channel 14 */ +}; + +/* Some 5 GHz radios are actually tunable on XXXX-YYYY + * on 5 MHz steps, we support the channels which we know + * we have calibration data for all cards though to make + * this static */ +static struct ieee80211_channel ath9k_5ghz_chantable[] = { + /* _We_ call this UNII 1 */ + CHAN5G(5180, 14), /* Channel 36 */ + CHAN5G(5200, 15), /* Channel 40 */ + CHAN5G(5220, 16), /* Channel 44 */ + CHAN5G(5240, 17), /* Channel 48 */ + /* _We_ call this UNII 2 */ + CHAN5G(5260, 18), /* Channel 52 */ + CHAN5G(5280, 19), /* Channel 56 */ + CHAN5G(5300, 20), /* Channel 60 */ + CHAN5G(5320, 21), /* Channel 64 */ + /* _We_ call this "Middle band" */ + CHAN5G(5500, 22), /* Channel 100 */ + CHAN5G(5520, 23), /* Channel 104 */ + CHAN5G(5540, 24), /* Channel 108 */ + CHAN5G(5560, 25), /* Channel 112 */ + CHAN5G(5580, 26), /* Channel 116 */ + CHAN5G(5600, 27), /* Channel 120 */ + CHAN5G(5620, 28), /* Channel 124 */ + CHAN5G(5640, 29), /* Channel 128 */ + CHAN5G(5660, 30), /* Channel 132 */ + CHAN5G(5680, 31), /* Channel 136 */ + CHAN5G(5700, 32), /* Channel 140 */ + /* _We_ call this UNII 3 */ + CHAN5G(5745, 33), /* Channel 149 */ + CHAN5G(5765, 34), /* Channel 153 */ + CHAN5G(5785, 35), /* Channel 157 */ + CHAN5G(5805, 36), /* Channel 161 */ + CHAN5G(5825, 37), /* Channel 165 */ +}; + +/* Atheros hardware rate code addition for short premble */ +#define SHPCHECK(__hw_rate, __flags) \ + ((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04 ) : 0) + +#define RATE(_bitrate, _hw_rate, _flags) { \ + .bitrate = (_bitrate), \ + .flags = (_flags), \ + .hw_value = (_hw_rate), \ + .hw_value_short = (SHPCHECK(_hw_rate, _flags)) \ +} + +static struct ieee80211_rate ath9k_legacy_rates[] = { + RATE(10, 0x1b, 0), + RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE), + RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE), + RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE), + RATE(60, 0x0b, 0), + RATE(90, 0x0f, 0), + RATE(120, 0x0a, 0), + RATE(180, 0x0e, 0), + RATE(240, 0x09, 0), + RATE(360, 0x0d, 0), + RATE(480, 0x08, 0), + RATE(540, 0x0c, 0), +}; + static void ath_cache_conf_rate(struct ath_softc *sc, struct ieee80211_conf *conf) { @@ -109,7 +221,7 @@ static struct ath9k_channel *ath_get_curchannel(struct ath_softc *sc, return channel; } -bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode) +static bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode) { unsigned long flags; bool ret; @@ -143,13 +255,11 @@ void ath9k_ps_restore(struct ath_softc *sc) if (--sc->ps_usecount != 0) goto unlock; - if (sc->ps_idle) - ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP); - else if (sc->ps_enabled && - !(sc->ps_flags & (PS_WAIT_FOR_BEACON | - PS_WAIT_FOR_CAB | - PS_WAIT_FOR_PSPOLL_DATA | - PS_WAIT_FOR_TX_ACK))) + if (sc->ps_enabled && + !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | + SC_OP_WAIT_FOR_CAB | + SC_OP_WAIT_FOR_PSPOLL_DATA | + SC_OP_WAIT_FOR_TX_ACK))) ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP); unlock: @@ -206,7 +316,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, r = ath9k_hw_reset(ah, hchan, fastcc); if (r) { ath_print(common, ATH_DBG_FATAL, - "Unable to reset channel (%u MHz), " + "Unable to reset channel (%u Mhz) " "reset status %d\n", channel->center_freq, r); spin_unlock_bh(&sc->sc_resetlock); @@ -239,7 +349,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, * When the task is complete, it reschedules itself depending on the * appropriate interval that was calculated. */ -void ath_ani_calibrate(unsigned long data) +static void ath_ani_calibrate(unsigned long data) { struct ath_softc *sc = (struct ath_softc *)data; struct ath_hw *ah = sc->sc_ah; @@ -253,6 +363,14 @@ void ath_ani_calibrate(unsigned long data) short_cal_interval = (ah->opmode == NL80211_IFTYPE_AP) ? ATH_AP_SHORT_CALINTERVAL : ATH_STA_SHORT_CALINTERVAL; + /* + * don't calibrate when we're scanning. + * we are most likely not on our home channel. + */ + spin_lock(&sc->ani_lock); + if (sc->sc_flags & SC_OP_SCANNING) + goto set_timer; + /* Only calibrate if awake */ if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) goto set_timer; @@ -319,6 +437,7 @@ void ath_ani_calibrate(unsigned long data) ath9k_ps_restore(sc); set_timer: + spin_unlock(&sc->ani_lock); /* * Set timer interval based on previous results. * The interval must be the shortest necessary to satisfy ANI, @@ -394,7 +513,7 @@ static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) ath_tx_node_cleanup(sc, an); } -void ath9k_tasklet(unsigned long data) +static void ath9k_tasklet(unsigned long data) { struct ath_softc *sc = (struct ath_softc *)data; struct ath_hw *ah = sc->sc_ah; @@ -426,7 +545,7 @@ void ath9k_tasklet(unsigned long data) */ ath_print(common, ATH_DBG_PS, "TSFOOR - Sync with next Beacon\n"); - sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC; + sc->sc_flags |= SC_OP_WAIT_FOR_BEACON | SC_OP_BEACON_SYNC; } if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) @@ -527,7 +646,7 @@ irqreturn_t ath_isr(int irq, void *dev) * receive frames */ ath9k_setpower(sc, ATH9K_PM_AWAKE); ath9k_hw_setrxabort(sc->sc_ah, 0); - sc->ps_flags |= PS_WAIT_FOR_BEACON; + sc->sc_flags |= SC_OP_WAIT_FOR_BEACON; } chip_reset: @@ -809,12 +928,49 @@ static void ath_key_delete(struct ath_common *common, struct ieee80211_key_conf clear_bit(key->hw_key_idx + 64, common->keymap); if (common->splitmic) { - ath9k_hw_keyreset(ah, key->hw_key_idx + 32); clear_bit(key->hw_key_idx + 32, common->keymap); clear_bit(key->hw_key_idx + 64 + 32, common->keymap); } } +static void setup_ht_cap(struct ath_softc *sc, + struct ieee80211_sta_ht_cap *ht_info) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + u8 tx_streams, rx_streams; + + ht_info->ht_supported = true; + ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | + IEEE80211_HT_CAP_SM_PS | + IEEE80211_HT_CAP_SGI_40 | + IEEE80211_HT_CAP_DSSSCCK40; + + ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; + ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8; + + /* set up supported mcs set */ + memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); + tx_streams = !(common->tx_chainmask & (common->tx_chainmask - 1)) ? + 1 : 2; + rx_streams = !(common->rx_chainmask & (common->rx_chainmask - 1)) ? + 1 : 2; + + if (tx_streams != rx_streams) { + ath_print(common, ATH_DBG_CONFIG, + "TX streams %d, RX streams: %d\n", + tx_streams, rx_streams); + ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; + ht_info->mcs.tx_params |= ((tx_streams - 1) << + IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); + } + + ht_info->mcs.rx_mask[0] = 0xff; + if (rx_streams >= 2) + ht_info->mcs.rx_mask[1] = 0xff; + + ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED; +} + static void ath9k_bss_assoc_info(struct ath_softc *sc, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf) @@ -836,7 +992,7 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, * on the receipt of the first Beacon frame (i.e., * after time sync with the AP). */ - sc->ps_flags |= PS_BEACON_SYNC; + sc->sc_flags |= SC_OP_BEACON_SYNC; /* Configure the beacon */ ath_beacon_config(sc, vif); @@ -853,6 +1009,174 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, } } +/********************************/ +/* LED functions */ +/********************************/ + +static void ath_led_blink_work(struct work_struct *work) +{ + struct ath_softc *sc = container_of(work, struct ath_softc, + ath_led_blink_work.work); + + if (!(sc->sc_flags & SC_OP_LED_ASSOCIATED)) + return; + + if ((sc->led_on_duration == ATH_LED_ON_DURATION_IDLE) || + (sc->led_off_duration == ATH_LED_OFF_DURATION_IDLE)) + ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0); + else + ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, + (sc->sc_flags & SC_OP_LED_ON) ? 1 : 0); + + ieee80211_queue_delayed_work(sc->hw, + &sc->ath_led_blink_work, + (sc->sc_flags & SC_OP_LED_ON) ? + msecs_to_jiffies(sc->led_off_duration) : + msecs_to_jiffies(sc->led_on_duration)); + + sc->led_on_duration = sc->led_on_cnt ? + max((ATH_LED_ON_DURATION_IDLE - sc->led_on_cnt), 25) : + ATH_LED_ON_DURATION_IDLE; + sc->led_off_duration = sc->led_off_cnt ? + max((ATH_LED_OFF_DURATION_IDLE - sc->led_off_cnt), 10) : + ATH_LED_OFF_DURATION_IDLE; + sc->led_on_cnt = sc->led_off_cnt = 0; + if (sc->sc_flags & SC_OP_LED_ON) + sc->sc_flags &= ~SC_OP_LED_ON; + else + sc->sc_flags |= SC_OP_LED_ON; +} + +static void ath_led_brightness(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev); + struct ath_softc *sc = led->sc; + + switch (brightness) { + case LED_OFF: + if (led->led_type == ATH_LED_ASSOC || + led->led_type == ATH_LED_RADIO) { + ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, + (led->led_type == ATH_LED_RADIO)); + sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; + if (led->led_type == ATH_LED_RADIO) + sc->sc_flags &= ~SC_OP_LED_ON; + } else { + sc->led_off_cnt++; + } + break; + case LED_FULL: + if (led->led_type == ATH_LED_ASSOC) { + sc->sc_flags |= SC_OP_LED_ASSOCIATED; + ieee80211_queue_delayed_work(sc->hw, + &sc->ath_led_blink_work, 0); + } else if (led->led_type == ATH_LED_RADIO) { + ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0); + sc->sc_flags |= SC_OP_LED_ON; + } else { + sc->led_on_cnt++; + } + break; + default: + break; + } +} + +static int ath_register_led(struct ath_softc *sc, struct ath_led *led, + char *trigger) +{ + int ret; + + led->sc = sc; + led->led_cdev.name = led->name; + led->led_cdev.default_trigger = trigger; + led->led_cdev.brightness_set = ath_led_brightness; + + ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->led_cdev); + if (ret) + ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL, + "Failed to register led:%s", led->name); + else + led->registered = 1; + return ret; +} + +static void ath_unregister_led(struct ath_led *led) +{ + if (led->registered) { + led_classdev_unregister(&led->led_cdev); + led->registered = 0; + } +} + +static void ath_deinit_leds(struct ath_softc *sc) +{ + ath_unregister_led(&sc->assoc_led); + sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; + ath_unregister_led(&sc->tx_led); + ath_unregister_led(&sc->rx_led); + ath_unregister_led(&sc->radio_led); + ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); +} + +static void ath_init_leds(struct ath_softc *sc) +{ + char *trigger; + int ret; + + if (AR_SREV_9287(sc->sc_ah)) + sc->sc_ah->led_pin = ATH_LED_PIN_9287; + else + sc->sc_ah->led_pin = ATH_LED_PIN_DEF; + + /* Configure gpio 1 for output */ + ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin, + AR_GPIO_OUTPUT_MUX_AS_OUTPUT); + /* LED off, active low */ + ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); + + INIT_DELAYED_WORK(&sc->ath_led_blink_work, ath_led_blink_work); + + trigger = ieee80211_get_radio_led_name(sc->hw); + snprintf(sc->radio_led.name, sizeof(sc->radio_led.name), + "ath9k-%s::radio", wiphy_name(sc->hw->wiphy)); + ret = ath_register_led(sc, &sc->radio_led, trigger); + sc->radio_led.led_type = ATH_LED_RADIO; + if (ret) + goto fail; + + trigger = ieee80211_get_assoc_led_name(sc->hw); + snprintf(sc->assoc_led.name, sizeof(sc->assoc_led.name), + "ath9k-%s::assoc", wiphy_name(sc->hw->wiphy)); + ret = ath_register_led(sc, &sc->assoc_led, trigger); + sc->assoc_led.led_type = ATH_LED_ASSOC; + if (ret) + goto fail; + + trigger = ieee80211_get_tx_led_name(sc->hw); + snprintf(sc->tx_led.name, sizeof(sc->tx_led.name), + "ath9k-%s::tx", wiphy_name(sc->hw->wiphy)); + ret = ath_register_led(sc, &sc->tx_led, trigger); + sc->tx_led.led_type = ATH_LED_TX; + if (ret) + goto fail; + + trigger = ieee80211_get_rx_led_name(sc->hw); + snprintf(sc->rx_led.name, sizeof(sc->rx_led.name), + "ath9k-%s::rx", wiphy_name(sc->hw->wiphy)); + ret = ath_register_led(sc, &sc->rx_led, trigger); + sc->rx_led.led_type = ATH_LED_RX; + if (ret) + goto fail; + + return; + +fail: + cancel_delayed_work_sync(&sc->ath_led_blink_work); + ath_deinit_leds(sc); +} + void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) { struct ath_hw *ah = sc->sc_ah; @@ -870,7 +1194,7 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) r = ath9k_hw_reset(ah, ah->curchan, false); if (r) { ath_print(common, ATH_DBG_FATAL, - "Unable to reset channel (%u MHz), " + "Unable to reset channel %u (%uMhz) ", "reset status %d\n", channel->center_freq, r); } @@ -925,7 +1249,7 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw) r = ath9k_hw_reset(ah, ah->curchan, false); if (r) { ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL, - "Unable to reset channel (%u MHz), " + "Unable to reset channel %u (%uMhz) " "reset status %d\n", channel->center_freq, r); } @@ -937,6 +1261,711 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw) ath9k_setpower(sc, ATH9K_PM_FULL_SLEEP); } +/*******************/ +/* Rfkill */ +/*******************/ + +static bool ath_is_rfkill_set(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + + return ath9k_hw_gpio_get(ah, ah->rfkill_gpio) == + ah->rfkill_polarity; +} + +static void ath9k_rfkill_poll_state(struct ieee80211_hw *hw) +{ + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + bool blocked = !!ath_is_rfkill_set(sc); + + wiphy_rfkill_set_hw_state(hw->wiphy, blocked); +} + +static void ath_start_rfkill_poll(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + + if (ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) + wiphy_rfkill_start_polling(sc->hw->wiphy); +} + +static void ath9k_uninit_hw(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + + BUG_ON(!ah); + + ath9k_exit_debug(ah); + ath9k_hw_detach(ah); + sc->sc_ah = NULL; +} + +static void ath_clean_core(struct ath_softc *sc) +{ + struct ieee80211_hw *hw = sc->hw; + struct ath_hw *ah = sc->sc_ah; + int i = 0; + + ath9k_ps_wakeup(sc); + + dev_dbg(sc->dev, "Detach ATH hw\n"); + + ath_deinit_leds(sc); + wiphy_rfkill_stop_polling(sc->hw->wiphy); + + for (i = 0; i < sc->num_sec_wiphy; i++) { + struct ath_wiphy *aphy = sc->sec_wiphy[i]; + if (aphy == NULL) + continue; + sc->sec_wiphy[i] = NULL; + ieee80211_unregister_hw(aphy->hw); + ieee80211_free_hw(aphy->hw); + } + ieee80211_unregister_hw(hw); + ath_rx_cleanup(sc); + ath_tx_cleanup(sc); + + tasklet_kill(&sc->intr_tq); + tasklet_kill(&sc->bcon_tasklet); + + if (!(sc->sc_flags & SC_OP_INVALID)) + ath9k_setpower(sc, ATH9K_PM_AWAKE); + + /* cleanup tx queues */ + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) + if (ATH_TXQ_SETUP(sc, i)) + ath_tx_cleanupq(sc, &sc->tx.txq[i]); + + if ((sc->btcoex.no_stomp_timer) && + ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) + ath_gen_timer_free(ah, sc->btcoex.no_stomp_timer); +} + +void ath_detach(struct ath_softc *sc) +{ + ath_clean_core(sc); + ath9k_uninit_hw(sc); +} + +void ath_cleanup(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + + ath_clean_core(sc); + free_irq(sc->irq, sc); + ath_bus_cleanup(common); + kfree(sc->sec_wiphy); + ieee80211_free_hw(sc->hw); + + ath9k_uninit_hw(sc); +} + +static int ath9k_reg_notifier(struct wiphy *wiphy, + struct regulatory_request *request) +{ + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + struct ath_regulatory *reg = ath9k_hw_regulatory(sc->sc_ah); + + return ath_reg_notifier_apply(wiphy, request, reg); +} + +/* + * Detects if there is any priority bt traffic + */ +static void ath_detect_bt_priority(struct ath_softc *sc) +{ + struct ath_btcoex *btcoex = &sc->btcoex; + struct ath_hw *ah = sc->sc_ah; + + if (ath9k_hw_gpio_get(sc->sc_ah, ah->btcoex_hw.btpriority_gpio)) + btcoex->bt_priority_cnt++; + + if (time_after(jiffies, btcoex->bt_priority_time + + msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) { + if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) { + ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_BTCOEX, + "BT priority traffic detected"); + sc->sc_flags |= SC_OP_BT_PRIORITY_DETECTED; + } else { + sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED; + } + + btcoex->bt_priority_cnt = 0; + btcoex->bt_priority_time = jiffies; + } +} + +/* + * Configures appropriate weight based on stomp type. + */ +static void ath9k_btcoex_bt_stomp(struct ath_softc *sc, + enum ath_stomp_type stomp_type) +{ + struct ath_hw *ah = sc->sc_ah; + + switch (stomp_type) { + case ATH_BTCOEX_STOMP_ALL: + ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, + AR_STOMP_ALL_WLAN_WGHT); + break; + case ATH_BTCOEX_STOMP_LOW: + ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, + AR_STOMP_LOW_WLAN_WGHT); + break; + case ATH_BTCOEX_STOMP_NONE: + ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, + AR_STOMP_NONE_WLAN_WGHT); + break; + default: + ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX, + "Invalid Stomptype\n"); + break; + } + + ath9k_hw_btcoex_enable(ah); +} + +static void ath9k_gen_timer_start(struct ath_hw *ah, + struct ath_gen_timer *timer, + u32 timer_next, + u32 timer_period) +{ + struct ath_common *common = ath9k_hw_common(ah); + struct ath_softc *sc = (struct ath_softc *) common->priv; + + ath9k_hw_gen_timer_start(ah, timer, timer_next, timer_period); + + if ((sc->imask & ATH9K_INT_GENTIMER) == 0) { + ath9k_hw_set_interrupts(ah, 0); + sc->imask |= ATH9K_INT_GENTIMER; + ath9k_hw_set_interrupts(ah, sc->imask); + } +} + +static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer) +{ + struct ath_common *common = ath9k_hw_common(ah); + struct ath_softc *sc = (struct ath_softc *) common->priv; + struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; + + ath9k_hw_gen_timer_stop(ah, timer); + + /* if no timer is enabled, turn off interrupt mask */ + if (timer_table->timer_mask.val == 0) { + ath9k_hw_set_interrupts(ah, 0); + sc->imask &= ~ATH9K_INT_GENTIMER; + ath9k_hw_set_interrupts(ah, sc->imask); + } +} + +/* + * This is the master bt coex timer which runs for every + * 45ms, bt traffic will be given priority during 55% of this + * period while wlan gets remaining 45% + */ +static void ath_btcoex_period_timer(unsigned long data) +{ + struct ath_softc *sc = (struct ath_softc *) data; + struct ath_hw *ah = sc->sc_ah; + struct ath_btcoex *btcoex = &sc->btcoex; + + ath_detect_bt_priority(sc); + + spin_lock_bh(&btcoex->btcoex_lock); + + ath9k_btcoex_bt_stomp(sc, btcoex->bt_stomp_type); + + spin_unlock_bh(&btcoex->btcoex_lock); + + if (btcoex->btcoex_period != btcoex->btcoex_no_stomp) { + if (btcoex->hw_timer_enabled) + ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer); + + ath9k_gen_timer_start(ah, + btcoex->no_stomp_timer, + (ath9k_hw_gettsf32(ah) + + btcoex->btcoex_no_stomp), + btcoex->btcoex_no_stomp * 10); + btcoex->hw_timer_enabled = true; + } + + mod_timer(&btcoex->period_timer, jiffies + + msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD)); +} + +/* + * Generic tsf based hw timer which configures weight + * registers to time slice between wlan and bt traffic + */ +static void ath_btcoex_no_stomp_timer(void *arg) +{ + struct ath_softc *sc = (struct ath_softc *)arg; + struct ath_hw *ah = sc->sc_ah; + struct ath_btcoex *btcoex = &sc->btcoex; + + ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX, + "no stomp timer running \n"); + + spin_lock_bh(&btcoex->btcoex_lock); + + if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW) + ath9k_btcoex_bt_stomp(sc, ATH_BTCOEX_STOMP_NONE); + else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL) + ath9k_btcoex_bt_stomp(sc, ATH_BTCOEX_STOMP_LOW); + + spin_unlock_bh(&btcoex->btcoex_lock); +} + +static int ath_init_btcoex_timer(struct ath_softc *sc) +{ + struct ath_btcoex *btcoex = &sc->btcoex; + + btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD * 1000; + btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) * + btcoex->btcoex_period / 100; + + setup_timer(&btcoex->period_timer, ath_btcoex_period_timer, + (unsigned long) sc); + + spin_lock_init(&btcoex->btcoex_lock); + + btcoex->no_stomp_timer = ath_gen_timer_alloc(sc->sc_ah, + ath_btcoex_no_stomp_timer, + ath_btcoex_no_stomp_timer, + (void *) sc, AR_FIRST_NDP_TIMER); + + if (!btcoex->no_stomp_timer) + return -ENOMEM; + + return 0; +} + +/* + * Read and write, they both share the same lock. We do this to serialize + * reads and writes on Atheros 802.11n PCI devices only. This is required + * as the FIFO on these devices can only accept sanely 2 requests. After + * that the device goes bananas. Serializing the reads/writes prevents this + * from happening. + */ + +static void ath9k_iowrite32(void *hw_priv, u32 val, u32 reg_offset) +{ + struct ath_hw *ah = (struct ath_hw *) hw_priv; + struct ath_common *common = ath9k_hw_common(ah); + struct ath_softc *sc = (struct ath_softc *) common->priv; + + if (ah->config.serialize_regmode == SER_REG_MODE_ON) { + unsigned long flags; + spin_lock_irqsave(&sc->sc_serial_rw, flags); + iowrite32(val, sc->mem + reg_offset); + spin_unlock_irqrestore(&sc->sc_serial_rw, flags); + } else + iowrite32(val, sc->mem + reg_offset); +} + +static unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset) +{ + struct ath_hw *ah = (struct ath_hw *) hw_priv; + struct ath_common *common = ath9k_hw_common(ah); + struct ath_softc *sc = (struct ath_softc *) common->priv; + u32 val; + + if (ah->config.serialize_regmode == SER_REG_MODE_ON) { + unsigned long flags; + spin_lock_irqsave(&sc->sc_serial_rw, flags); + val = ioread32(sc->mem + reg_offset); + spin_unlock_irqrestore(&sc->sc_serial_rw, flags); + } else + val = ioread32(sc->mem + reg_offset); + return val; +} + +static const struct ath_ops ath9k_common_ops = { + .read = ath9k_ioread32, + .write = ath9k_iowrite32, +}; + +/* + * Initialize and fill ath_softc, ath_sofct is the + * "Software Carrier" struct. Historically it has existed + * to allow the separation between hardware specific + * variables (now in ath_hw) and driver specific variables. + */ +static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, + const struct ath_bus_ops *bus_ops) +{ + struct ath_hw *ah = NULL; + struct ath_common *common; + int r = 0, i; + int csz = 0; + int qnum; + + /* XXX: hardware will not be ready until ath_open() being called */ + sc->sc_flags |= SC_OP_INVALID; + + spin_lock_init(&sc->wiphy_lock); + spin_lock_init(&sc->sc_resetlock); + spin_lock_init(&sc->sc_serial_rw); + spin_lock_init(&sc->ani_lock); + spin_lock_init(&sc->sc_pm_lock); + mutex_init(&sc->mutex); + tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); + tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet, + (unsigned long)sc); + + ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL); + if (!ah) + return -ENOMEM; + + ah->hw_version.devid = devid; + ah->hw_version.subsysid = subsysid; + sc->sc_ah = ah; + + common = ath9k_hw_common(ah); + common->ops = &ath9k_common_ops; + common->bus_ops = bus_ops; + common->ah = ah; + common->hw = sc->hw; + common->priv = sc; + common->debug_mask = ath9k_debug; + + /* + * Cache line size is used to size and align various + * structures used to communicate with the hardware. + */ + ath_read_cachesize(common, &csz); + /* XXX assert csz is non-zero */ + common->cachelsz = csz << 2; /* convert to bytes */ + + r = ath9k_hw_init(ah); + if (r) { + ath_print(common, ATH_DBG_FATAL, + "Unable to initialize hardware; " + "initialization status: %d\n", r); + goto bad_free_hw; + } + + if (ath9k_init_debug(ah) < 0) { + ath_print(common, ATH_DBG_FATAL, + "Unable to create debugfs files\n"); + goto bad_free_hw; + } + + /* Get the hardware key cache size. */ + common->keymax = ah->caps.keycache_size; + if (common->keymax > ATH_KEYMAX) { + ath_print(common, ATH_DBG_ANY, + "Warning, using only %u entries in %u key cache\n", + ATH_KEYMAX, common->keymax); + common->keymax = ATH_KEYMAX; + } + + /* + * Reset the key cache since some parts do not + * reset the contents on initial power up. + */ + for (i = 0; i < common->keymax; i++) + ath9k_hw_keyreset(ah, (u16) i); + + /* default to MONITOR mode */ + sc->sc_ah->opmode = NL80211_IFTYPE_MONITOR; + + /* + * Allocate hardware transmit queues: one queue for + * beacon frames and one data queue for each QoS + * priority. Note that the hal handles reseting + * these queues at the needed time. + */ + sc->beacon.beaconq = ath9k_hw_beaconq_setup(ah); + if (sc->beacon.beaconq == -1) { + ath_print(common, ATH_DBG_FATAL, + "Unable to setup a beacon xmit queue\n"); + r = -EIO; + goto bad2; + } + sc->beacon.cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0); + if (sc->beacon.cabq == NULL) { + ath_print(common, ATH_DBG_FATAL, + "Unable to setup CAB xmit queue\n"); + r = -EIO; + goto bad2; + } + + sc->config.cabqReadytime = ATH_CABQ_READY_TIME; + ath_cabq_update(sc); + + for (i = 0; i < ARRAY_SIZE(sc->tx.hwq_map); i++) + sc->tx.hwq_map[i] = -1; + + /* Setup data queues */ + /* NB: ensure BK queue is the lowest priority h/w queue */ + if (!ath_tx_setup(sc, ATH9K_WME_AC_BK)) { + ath_print(common, ATH_DBG_FATAL, + "Unable to setup xmit queue for BK traffic\n"); + r = -EIO; + goto bad2; + } + + if (!ath_tx_setup(sc, ATH9K_WME_AC_BE)) { + ath_print(common, ATH_DBG_FATAL, + "Unable to setup xmit queue for BE traffic\n"); + r = -EIO; + goto bad2; + } + if (!ath_tx_setup(sc, ATH9K_WME_AC_VI)) { + ath_print(common, ATH_DBG_FATAL, + "Unable to setup xmit queue for VI traffic\n"); + r = -EIO; + goto bad2; + } + if (!ath_tx_setup(sc, ATH9K_WME_AC_VO)) { + ath_print(common, ATH_DBG_FATAL, + "Unable to setup xmit queue for VO traffic\n"); + r = -EIO; + goto bad2; + } + + /* Initializes the noise floor to a reasonable default value. + * Later on this will be updated during ANI processing. */ + + common->ani.noise_floor = ATH_DEFAULT_NOISE_FLOOR; + setup_timer(&common->ani.timer, ath_ani_calibrate, (unsigned long)sc); + + if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, + ATH9K_CIPHER_TKIP, NULL)) { + /* + * Whether we should enable h/w TKIP MIC. + * XXX: if we don't support WME TKIP MIC, then we wouldn't + * report WMM capable, so it's always safe to turn on + * TKIP MIC in this case. + */ + ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_TKIP_MIC, + 0, 1, NULL); + } + + /* + * Check whether the separate key cache entries + * are required to handle both tx+rx MIC keys. + * With split mic keys the number of stations is limited + * to 27 otherwise 59. + */ + if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, + ATH9K_CIPHER_TKIP, NULL) + && ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, + ATH9K_CIPHER_MIC, NULL) + && ath9k_hw_getcapability(ah, ATH9K_CAP_TKIP_SPLIT, + 0, NULL)) + common->splitmic = 1; + + /* turn on mcast key search if possible */ + if (!ath9k_hw_getcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL)) + (void)ath9k_hw_setcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 1, + 1, NULL); + + sc->config.txpowlimit = ATH_TXPOWER_MAX; + + /* 11n Capabilities */ + if (ah->caps.hw_caps & ATH9K_HW_CAP_HT) { + sc->sc_flags |= SC_OP_TXAGGR; + sc->sc_flags |= SC_OP_RXAGGR; + } + + common->tx_chainmask = ah->caps.tx_chainmask; + common->rx_chainmask = ah->caps.rx_chainmask; + + ath9k_hw_setcapability(ah, ATH9K_CAP_DIVERSITY, 1, true, NULL); + sc->rx.defant = ath9k_hw_getdefantenna(ah); + + if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) + memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN); + + sc->beacon.slottime = ATH9K_SLOT_TIME_9; /* default to short slot time */ + + /* initialize beacon slots */ + for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) { + sc->beacon.bslot[i] = NULL; + sc->beacon.bslot_aphy[i] = NULL; + } + + /* setup channels and rates */ + + if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes)) { + sc->sbands[IEEE80211_BAND_2GHZ].channels = ath9k_2ghz_chantable; + sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; + sc->sbands[IEEE80211_BAND_2GHZ].n_channels = + ARRAY_SIZE(ath9k_2ghz_chantable); + sc->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates; + sc->sbands[IEEE80211_BAND_2GHZ].n_bitrates = + ARRAY_SIZE(ath9k_legacy_rates); + } + + if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) { + sc->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_chantable; + sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ; + sc->sbands[IEEE80211_BAND_5GHZ].n_channels = + ARRAY_SIZE(ath9k_5ghz_chantable); + sc->sbands[IEEE80211_BAND_5GHZ].bitrates = + ath9k_legacy_rates + 4; + sc->sbands[IEEE80211_BAND_5GHZ].n_bitrates = + ARRAY_SIZE(ath9k_legacy_rates) - 4; + } + + switch (ah->btcoex_hw.scheme) { + case ATH_BTCOEX_CFG_NONE: + break; + case ATH_BTCOEX_CFG_2WIRE: + ath9k_hw_btcoex_init_2wire(ah); + break; + case ATH_BTCOEX_CFG_3WIRE: + ath9k_hw_btcoex_init_3wire(ah); + r = ath_init_btcoex_timer(sc); + if (r) + goto bad2; + qnum = ath_tx_get_qnum(sc, ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE); + ath9k_hw_init_btcoex_hw(ah, qnum); + sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW; + break; + default: + WARN_ON(1); + break; + } + + return 0; +bad2: + /* cleanup tx queues */ + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) + if (ATH_TXQ_SETUP(sc, i)) + ath_tx_cleanupq(sc, &sc->tx.txq[i]); + +bad_free_hw: + ath9k_uninit_hw(sc); + return r; +} + +void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) +{ + hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_AMPDU_AGGREGATION | + IEEE80211_HW_SUPPORTS_PS | + IEEE80211_HW_PS_NULLFUNC_STACK | + IEEE80211_HW_SPECTRUM_MGMT; + + if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || modparam_nohwcrypt) + hw->flags |= IEEE80211_HW_MFP_CAPABLE; + + hw->wiphy->interface_modes = + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC) | + BIT(NL80211_IFTYPE_MESH_POINT); + + hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; + + hw->queues = 4; + hw->max_rates = 4; + hw->channel_change_time = 5000; + hw->max_listen_interval = 10; + /* Hardware supports 10 but we use 4 */ + hw->max_rate_tries = 4; + hw->sta_data_size = sizeof(struct ath_node); + hw->vif_data_size = sizeof(struct ath_vif); + + hw->rate_control_algorithm = "ath9k_rate_control"; + + if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes)) + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = + &sc->sbands[IEEE80211_BAND_2GHZ]; + if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) + hw->wiphy->bands[IEEE80211_BAND_5GHZ] = + &sc->sbands[IEEE80211_BAND_5GHZ]; +} + +/* Device driver core initialization */ +int ath_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, + const struct ath_bus_ops *bus_ops) +{ + struct ieee80211_hw *hw = sc->hw; + struct ath_common *common; + struct ath_hw *ah; + int error = 0, i; + struct ath_regulatory *reg; + + dev_dbg(sc->dev, "Attach ATH hw\n"); + + error = ath_init_softc(devid, sc, subsysid, bus_ops); + if (error != 0) + return error; + + ah = sc->sc_ah; + common = ath9k_hw_common(ah); + + /* get mac address from hardware and set in mac80211 */ + + SET_IEEE80211_PERM_ADDR(hw, common->macaddr); + + ath_set_hw_capab(sc, hw); + + error = ath_regd_init(&common->regulatory, sc->hw->wiphy, + ath9k_reg_notifier); + if (error) + return error; + + reg = &common->regulatory; + + if (ah->caps.hw_caps & ATH9K_HW_CAP_HT) { + if (test_bit(ATH9K_MODE_11G, ah->caps.wireless_modes)) + setup_ht_cap(sc, + &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); + if (test_bit(ATH9K_MODE_11A, ah->caps.wireless_modes)) + setup_ht_cap(sc, + &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap); + } + + /* initialize tx/rx engine */ + error = ath_tx_init(sc, ATH_TXBUF); + if (error != 0) + goto error_attach; + + error = ath_rx_init(sc, ATH_RXBUF); + if (error != 0) + goto error_attach; + + INIT_WORK(&sc->chan_work, ath9k_wiphy_chan_work); + INIT_DELAYED_WORK(&sc->wiphy_work, ath9k_wiphy_work); + sc->wiphy_scheduler_int = msecs_to_jiffies(500); + + error = ieee80211_register_hw(hw); + + if (!ath_is_world_regd(reg)) { + error = regulatory_hint(hw->wiphy, reg->alpha2); + if (error) + goto error_attach; + } + + /* Initialize LED control */ + ath_init_leds(sc); + + ath_start_rfkill_poll(sc); + + return 0; + +error_attach: + /* cleanup tx queues */ + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) + if (ATH_TXQ_SETUP(sc, i)) + ath_tx_cleanupq(sc, &sc->tx.txq[i]); + + ath9k_uninit_hw(sc); + + return error; +} + int ath_reset(struct ath_softc *sc, bool retry_tx) { struct ath_hw *ah = sc->sc_ah; @@ -947,8 +1976,6 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) /* Stop ANI */ del_timer_sync(&common->ani.timer); - ieee80211_stop_queues(hw); - ath9k_hw_set_interrupts(ah, 0); ath_drain_all_txq(sc, retry_tx); ath_stoprecv(sc); @@ -990,14 +2017,131 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) } } - ieee80211_wake_queues(hw); - /* Start ANI */ ath_start_ani(common); return r; } +/* + * This function will allocate both the DMA descriptor structure, and the + * buffers it contains. These are used to contain the descriptors used + * by the system. +*/ +int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, + struct list_head *head, const char *name, + int nbuf, int ndesc) +{ +#define DS2PHYS(_dd, _ds) \ + ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc)) +#define ATH_DESC_4KB_BOUND_CHECK(_daddr) ((((_daddr) & 0xFFF) > 0xF7F) ? 1 : 0) +#define ATH_DESC_4KB_BOUND_NUM_SKIPPED(_len) ((_len) / 4096) + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_desc *ds; + struct ath_buf *bf; + int i, bsize, error; + + ath_print(common, ATH_DBG_CONFIG, "%s DMA: %u buffers %u desc/buf\n", + name, nbuf, ndesc); + + INIT_LIST_HEAD(head); + /* ath_desc must be a multiple of DWORDs */ + if ((sizeof(struct ath_desc) % 4) != 0) { + ath_print(common, ATH_DBG_FATAL, + "ath_desc not DWORD aligned\n"); + BUG_ON((sizeof(struct ath_desc) % 4) != 0); + error = -ENOMEM; + goto fail; + } + + dd->dd_desc_len = sizeof(struct ath_desc) * nbuf * ndesc; + + /* + * Need additional DMA memory because we can't use + * descriptors that cross the 4K page boundary. Assume + * one skipped descriptor per 4K page. + */ + if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_4KB_SPLITTRANS)) { + u32 ndesc_skipped = + ATH_DESC_4KB_BOUND_NUM_SKIPPED(dd->dd_desc_len); + u32 dma_len; + + while (ndesc_skipped) { + dma_len = ndesc_skipped * sizeof(struct ath_desc); + dd->dd_desc_len += dma_len; + + ndesc_skipped = ATH_DESC_4KB_BOUND_NUM_SKIPPED(dma_len); + }; + } + + /* allocate descriptors */ + dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len, + &dd->dd_desc_paddr, GFP_KERNEL); + if (dd->dd_desc == NULL) { + error = -ENOMEM; + goto fail; + } + ds = dd->dd_desc; + ath_print(common, ATH_DBG_CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n", + name, ds, (u32) dd->dd_desc_len, + ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len); + + /* allocate buffers */ + bsize = sizeof(struct ath_buf) * nbuf; + bf = kzalloc(bsize, GFP_KERNEL); + if (bf == NULL) { + error = -ENOMEM; + goto fail2; + } + dd->dd_bufptr = bf; + + for (i = 0; i < nbuf; i++, bf++, ds += ndesc) { + bf->bf_desc = ds; + bf->bf_daddr = DS2PHYS(dd, ds); + + if (!(sc->sc_ah->caps.hw_caps & + ATH9K_HW_CAP_4KB_SPLITTRANS)) { + /* + * Skip descriptor addresses which can cause 4KB + * boundary crossing (addr + length) with a 32 dword + * descriptor fetch. + */ + while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) { + BUG_ON((caddr_t) bf->bf_desc >= + ((caddr_t) dd->dd_desc + + dd->dd_desc_len)); + + ds += ndesc; + bf->bf_desc = ds; + bf->bf_daddr = DS2PHYS(dd, ds); + } + } + list_add_tail(&bf->list, head); + } + return 0; +fail2: + dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc, + dd->dd_desc_paddr); +fail: + memset(dd, 0, sizeof(*dd)); + return error; +#undef ATH_DESC_4KB_BOUND_CHECK +#undef ATH_DESC_4KB_BOUND_NUM_SKIPPED +#undef DS2PHYS +} + +void ath_descdma_cleanup(struct ath_softc *sc, + struct ath_descdma *dd, + struct list_head *head) +{ + dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc, + dd->dd_desc_paddr); + + INIT_LIST_HEAD(head); + kfree(dd->dd_bufptr); + memset(dd, 0, sizeof(*dd)); +} + int ath_get_hal_qnum(u16 queue, struct ath_softc *sc) { int qnum; @@ -1076,6 +2220,28 @@ void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw, /* mac80211 callbacks */ /**********************/ +/* + * (Re)start btcoex timers + */ +static void ath9k_btcoex_timer_resume(struct ath_softc *sc) +{ + struct ath_btcoex *btcoex = &sc->btcoex; + struct ath_hw *ah = sc->sc_ah; + + ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX, + "Starting btcoex timers"); + + /* make sure duty cycle timer is also stopped when resuming */ + if (btcoex->hw_timer_enabled) + ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer); + + btcoex->bt_priority_cnt = 0; + btcoex->bt_priority_time = jiffies; + sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED; + + mod_timer(&btcoex->period_timer, jiffies); +} + static int ath9k_start(struct ieee80211_hw *hw) { struct ath_wiphy *aphy = hw->priv; @@ -1245,11 +2411,11 @@ static int ath9k_tx(struct ieee80211_hw *hw, if (ieee80211_is_pspoll(hdr->frame_control)) { ath_print(common, ATH_DBG_PS, "Sending PS-Poll to pick a buffered frame\n"); - sc->ps_flags |= PS_WAIT_FOR_PSPOLL_DATA; + sc->sc_flags |= SC_OP_WAIT_FOR_PSPOLL_DATA; } else { ath_print(common, ATH_DBG_PS, "Wake up to complete TX\n"); - sc->ps_flags |= PS_WAIT_FOR_TX_ACK; + sc->sc_flags |= SC_OP_WAIT_FOR_TX_ACK; } /* * The actual restore operation will happen only after @@ -1302,6 +2468,22 @@ static int ath9k_tx(struct ieee80211_hw *hw, return 0; } +/* + * Pause btcoex timer and bt duty cycle timer + */ +static void ath9k_btcoex_timer_pause(struct ath_softc *sc) +{ + struct ath_btcoex *btcoex = &sc->btcoex; + struct ath_hw *ah = sc->sc_ah; + + del_timer_sync(&btcoex->period_timer); + + if (btcoex->hw_timer_enabled) + ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer); + + btcoex->hw_timer_enabled = false; +} + static void ath9k_stop(struct ieee80211_hw *hw) { struct ath_wiphy *aphy = hw->priv; @@ -1368,12 +2550,12 @@ static void ath9k_stop(struct ieee80211_hw *hw) } static int ath9k_add_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) + struct ieee80211_if_init_conf *conf) { struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ath_vif *avp = (void *)vif->drv_priv; + struct ath_vif *avp = (void *)conf->vif->drv_priv; enum nl80211_iftype ic_opmode = NL80211_IFTYPE_UNSPECIFIED; int ret = 0; @@ -1385,7 +2567,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, goto out; } - switch (vif->type) { + switch (conf->type) { case NL80211_IFTYPE_STATION: ic_opmode = NL80211_IFTYPE_STATION; break; @@ -1396,11 +2578,11 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, ret = -ENOBUFS; goto out; } - ic_opmode = vif->type; + ic_opmode = conf->type; break; default: ath_print(common, ATH_DBG_FATAL, - "Interface type %d not yet supported\n", vif->type); + "Interface type %d not yet supported\n", conf->type); ret = -EOPNOTSUPP; goto out; } @@ -1432,18 +2614,18 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, * Enable MIB interrupts when there are hardware phy counters. * Note we only do this (at the moment) for station mode. */ - if ((vif->type == NL80211_IFTYPE_STATION) || - (vif->type == NL80211_IFTYPE_ADHOC) || - (vif->type == NL80211_IFTYPE_MESH_POINT)) { + if ((conf->type == NL80211_IFTYPE_STATION) || + (conf->type == NL80211_IFTYPE_ADHOC) || + (conf->type == NL80211_IFTYPE_MESH_POINT)) { sc->imask |= ATH9K_INT_MIB; sc->imask |= ATH9K_INT_TSFOOR; } ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); - if (vif->type == NL80211_IFTYPE_AP || - vif->type == NL80211_IFTYPE_ADHOC || - vif->type == NL80211_IFTYPE_MONITOR) + if (conf->type == NL80211_IFTYPE_AP || + conf->type == NL80211_IFTYPE_ADHOC || + conf->type == NL80211_IFTYPE_MONITOR) ath_start_ani(common); out: @@ -1452,12 +2634,12 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, } static void ath9k_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) + struct ieee80211_if_init_conf *conf) { struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ath_vif *avp = (void *)vif->drv_priv; + struct ath_vif *avp = (void *)conf->vif->drv_priv; int i; ath_print(common, ATH_DBG_CONFIG, "Detach Interface\n"); @@ -1480,7 +2662,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, sc->sc_flags &= ~SC_OP_BEACONS; for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) { - if (sc->beacon.bslot[i] == vif) { + if (sc->beacon.bslot[i] == conf->vif) { printk(KERN_DEBUG "%s: vif had allocated beacon " "slot\n", __func__); sc->beacon.bslot[i] = NULL; @@ -1493,19 +2675,6 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, mutex_unlock(&sc->mutex); } -void ath9k_enable_ps(struct ath_softc *sc) -{ - sc->ps_enabled = true; - if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { - if ((sc->imask & ATH9K_INT_TIM_TIMER) == 0) { - sc->imask |= ATH9K_INT_TIM_TIMER; - ath9k_hw_set_interrupts(sc->sc_ah, - sc->imask); - } - } - ath9k_hw_setrxabort(sc->sc_ah, 1); -} - static int ath9k_config(struct ieee80211_hw *hw, u32 changed) { struct ath_wiphy *aphy = hw->priv; @@ -1544,7 +2713,6 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) spin_unlock_bh(&sc->wiphy_lock); if (enable_radio) { - sc->ps_idle = false; ath_radio_enable(sc, hw); ath_print(common, ATH_DBG_CONFIG, "not-idle: enabling radio\n"); @@ -1559,27 +2727,36 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) */ if (changed & IEEE80211_CONF_CHANGE_PS) { if (conf->flags & IEEE80211_CONF_PS) { - sc->ps_flags |= PS_ENABLED; + sc->sc_flags |= SC_OP_PS_ENABLED; + if (!(ah->caps.hw_caps & + ATH9K_HW_CAP_AUTOSLEEP)) { + if ((sc->imask & ATH9K_INT_TIM_TIMER) == 0) { + sc->imask |= ATH9K_INT_TIM_TIMER; + ath9k_hw_set_interrupts(sc->sc_ah, + sc->imask); + } + } /* * At this point we know hardware has received an ACK * of a previously sent null data frame. */ - if ((sc->ps_flags & PS_NULLFUNC_COMPLETED)) { - sc->ps_flags &= ~PS_NULLFUNC_COMPLETED; - ath9k_enable_ps(sc); + if ((sc->sc_flags & SC_OP_NULLFUNC_COMPLETED)) { + sc->sc_flags &= ~SC_OP_NULLFUNC_COMPLETED; + sc->ps_enabled = true; + ath9k_hw_setrxabort(sc->sc_ah, 1); } } else { sc->ps_enabled = false; - sc->ps_flags &= ~(PS_ENABLED | - PS_NULLFUNC_COMPLETED); + sc->sc_flags &= ~(SC_OP_PS_ENABLED | + SC_OP_NULLFUNC_COMPLETED); ath9k_setpower(sc, ATH9K_PM_AWAKE); if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { ath9k_hw_setrxabort(sc->sc_ah, 0); - sc->ps_flags &= ~(PS_WAIT_FOR_BEACON | - PS_WAIT_FOR_CAB | - PS_WAIT_FOR_PSPOLL_DATA | - PS_WAIT_FOR_TX_ACK); + sc->sc_flags &= ~(SC_OP_WAIT_FOR_BEACON | + SC_OP_WAIT_FOR_CAB | + SC_OP_WAIT_FOR_PSPOLL_DATA | + SC_OP_WAIT_FOR_TX_ACK); if (sc->imask & ATH9K_INT_TIM_TIMER) { sc->imask &= ~ATH9K_INT_TIM_TIMER; ath9k_hw_set_interrupts(sc->sc_ah, @@ -1589,14 +2766,6 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) } } - if (changed & IEEE80211_CONF_CHANGE_MONITOR) { - if (conf->flags & IEEE80211_CONF_MONITOR) { - ath_print(common, ATH_DBG_CONFIG, - "HW opmode set to Monitor mode\n"); - sc->sc_ah->opmode = NL80211_IFTYPE_MONITOR; - } - } - if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { struct ieee80211_channel *curchan = hw->conf.channel; int pos = curchan->hw_value; @@ -1632,10 +2801,8 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) } skip_chan_change: - if (changed & IEEE80211_CONF_CHANGE_POWER) { + if (changed & IEEE80211_CONF_CHANGE_POWER) sc->config.txpowlimit = 2 * conf->power_level; - ath_update_txpow(sc); - } spin_lock_bh(&sc->wiphy_lock); disable_radio = ath9k_all_wiphys_idle(sc); @@ -1643,7 +2810,6 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) if (disable_radio) { ath_print(common, ATH_DBG_CONFIG, "idle: disabling radio\n"); - sc->ps_idle = true; ath_radio_disable(sc, hw); } @@ -1684,28 +2850,24 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw, "Set HW RX filter: 0x%x\n", rfilt); } -static int ath9k_sta_add(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) +static void ath9k_sta_notify(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum sta_notify_cmd cmd, + struct ieee80211_sta *sta) { struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; - ath_node_attach(sc, sta); - - return 0; -} - -static int ath9k_sta_remove(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) -{ - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - - ath_node_detach(sc, sta); - - return 0; + switch (cmd) { + case STA_NOTIFY_ADD: + ath_node_attach(sc, sta); + break; + case STA_NOTIFY_REMOVE: + ath_node_detach(sc, sta); + break; + default: + break; + } } static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue, @@ -1804,7 +2966,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ath_vif *avp = (void *)vif->drv_priv; - int slottime; int error; mutex_lock(&sc->mutex); @@ -1840,25 +3001,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, ath_beacon_config(sc, vif); } - if (changed & BSS_CHANGED_ERP_SLOT) { - if (bss_conf->use_short_slot) - slottime = 9; - else - slottime = 20; - if (vif->type == NL80211_IFTYPE_AP) { - /* - * Defer update, so that connected stations can adjust - * their settings at the same time. - * See beacon.c for more details - */ - sc->beacon.slottime = slottime; - sc->beacon.updateslot = UPDATE; - } else { - ah->slottime = slottime; - ath9k_hw_init_global_settings(ah); - } - } - /* Disable transmission of beacons */ if ((changed & BSS_CHANGED_BEACON_ENABLED) && !bss_conf->enable_beacon) ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); @@ -1991,7 +3133,6 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw) { struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; - struct ath_common *common = ath9k_hw_common(sc->sc_ah); mutex_lock(&sc->mutex); if (ath9k_wiphy_scanning(sc)) { @@ -2007,9 +3148,10 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw) aphy->state = ATH_WIPHY_SCAN; ath9k_wiphy_pause_all_forced(sc, aphy); + + spin_lock_bh(&sc->ani_lock); sc->sc_flags |= SC_OP_SCANNING; - del_timer_sync(&common->ani.timer); - cancel_delayed_work_sync(&sc->tx_complete_work); + spin_unlock_bh(&sc->ani_lock); mutex_unlock(&sc->mutex); } @@ -2017,30 +3159,17 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) { struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; - struct ath_common *common = ath9k_hw_common(sc->sc_ah); mutex_lock(&sc->mutex); + spin_lock_bh(&sc->ani_lock); aphy->state = ATH_WIPHY_ACTIVE; sc->sc_flags &= ~SC_OP_SCANNING; sc->sc_flags |= SC_OP_FULL_RESET; - ath_start_ani(common); - ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); + spin_unlock_bh(&sc->ani_lock); ath_beacon_config(sc, NULL); mutex_unlock(&sc->mutex); } -static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class) -{ - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - struct ath_hw *ah = sc->sc_ah; - - mutex_lock(&sc->mutex); - ah->coverage_class = coverage_class; - ath9k_hw_init_global_settings(ah); - mutex_unlock(&sc->mutex); -} - struct ieee80211_ops ath9k_ops = { .tx = ath9k_tx, .start = ath9k_start, @@ -2049,8 +3178,7 @@ struct ieee80211_ops ath9k_ops = { .remove_interface = ath9k_remove_interface, .config = ath9k_config, .configure_filter = ath9k_configure_filter, - .sta_add = ath9k_sta_add, - .sta_remove = ath9k_sta_remove, + .sta_notify = ath9k_sta_notify, .conf_tx = ath9k_conf_tx, .bss_info_changed = ath9k_bss_info_changed, .set_key = ath9k_set_key, @@ -2061,5 +3189,64 @@ struct ieee80211_ops ath9k_ops = { .sw_scan_start = ath9k_sw_scan_start, .sw_scan_complete = ath9k_sw_scan_complete, .rfkill_poll = ath9k_rfkill_poll_state, - .set_coverage_class = ath9k_set_coverage_class, }; + +static int __init ath9k_init(void) +{ + int error; + + /* Register rate control algorithm */ + error = ath_rate_control_register(); + if (error != 0) { + printk(KERN_ERR + "ath9k: Unable to register rate control " + "algorithm: %d\n", + error); + goto err_out; + } + + error = ath9k_debug_create_root(); + if (error) { + printk(KERN_ERR + "ath9k: Unable to create debugfs root: %d\n", + error); + goto err_rate_unregister; + } + + error = ath_pci_init(); + if (error < 0) { + printk(KERN_ERR + "ath9k: No PCI devices found, driver not installed.\n"); + error = -ENODEV; + goto err_remove_root; + } + + error = ath_ahb_init(); + if (error < 0) { + error = -ENODEV; + goto err_pci_exit; + } + + return 0; + + err_pci_exit: + ath_pci_exit(); + + err_remove_root: + ath9k_debug_remove_root(); + err_rate_unregister: + ath_rate_control_unregister(); + err_out: + return error; +} +module_init(ath9k_init); + +static void __exit ath9k_exit(void) +{ + ath_ahb_exit(); + ath_pci_exit(); + ath9k_debug_remove_root(); + ath_rate_control_unregister(); + printk(KERN_INFO "%s: Driver unloaded\n", dev_info); +} +module_exit(ath9k_exit); diff --git a/trunk/drivers/net/wireless/ath/ath9k/pci.c b/trunk/drivers/net/wireless/ath/ath9k/pci.c index f318b3b1abe9..f7af5ea54753 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/pci.c +++ b/trunk/drivers/net/wireless/ath/ath9k/pci.c @@ -25,7 +25,6 @@ static struct pci_device_id ath_pci_id_table[] __devinitdata = { { PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI */ { PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */ { PCI_VDEVICE(ATHEROS, 0x002B) }, /* PCI-E */ - { PCI_VDEVICE(ATHEROS, 0x002C) }, /* PCI-E 802.11n bonded out */ { PCI_VDEVICE(ATHEROS, 0x002D) }, /* PCI */ { PCI_VDEVICE(ATHEROS, 0x002E) }, /* PCI-E */ { 0 } @@ -50,6 +49,16 @@ static void ath_pci_read_cachesize(struct ath_common *common, int *csz) *csz = DEFAULT_CACHELINE >> 2; /* Use the default size */ } +static void ath_pci_cleanup(struct ath_common *common) +{ + struct ath_softc *sc = (struct ath_softc *) common->priv; + struct pci_dev *pdev = to_pci_dev(sc->dev); + + pci_iounmap(pdev, sc->mem); + pci_disable_device(pdev); + pci_release_region(pdev, 0); +} + static bool ath_pci_eeprom_read(struct ath_common *common, u32 off, u16 *data) { struct ath_hw *ah = (struct ath_hw *) common->ah; @@ -89,6 +98,7 @@ static void ath_pci_bt_coex_prep(struct ath_common *common) static const struct ath_bus_ops ath_pci_bus_ops = { .read_cachesize = ath_pci_read_cachesize, + .cleanup = ath_pci_cleanup, .eeprom_read = ath_pci_eeprom_read, .bt_coex_prep = ath_pci_bt_coex_prep, }; @@ -103,22 +113,25 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) u16 subsysid; u32 val; int ret = 0; + struct ath_hw *ah; char hw_name[64]; if (pci_enable_device(pdev)) return -EIO; ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (ret) { printk(KERN_ERR "ath9k: 32-bit DMA not available\n"); - goto err_dma; + goto bad; } ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); + if (ret) { printk(KERN_ERR "ath9k: 32-bit DMA consistent " "DMA enable failed\n"); - goto err_dma; + goto bad; } /* @@ -158,22 +171,22 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (ret) { dev_err(&pdev->dev, "PCI memory region reserve error\n"); ret = -ENODEV; - goto err_region; + goto bad; } mem = pci_iomap(pdev, 0, 0); if (!mem) { printk(KERN_ERR "PCI memory map error\n") ; ret = -EIO; - goto err_iomap; + goto bad1; } hw = ieee80211_alloc_hw(sizeof(struct ath_wiphy) + sizeof(struct ath_softc), &ath9k_ops); if (!hw) { - dev_err(&pdev->dev, "No memory for ieee80211_hw\n"); + dev_err(&pdev->dev, "no memory for ieee80211_hw\n"); ret = -ENOMEM; - goto err_alloc_hw; + goto bad2; } SET_IEEE80211_DEV(hw, &pdev->dev); @@ -188,25 +201,25 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) sc->dev = &pdev->dev; sc->mem = mem; - /* Will be cleared in ath9k_start() */ - sc->sc_flags |= SC_OP_INVALID; + pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsysid); + ret = ath_init_device(id->device, sc, subsysid, &ath_pci_bus_ops); + if (ret) { + dev_err(&pdev->dev, "failed to initialize device\n"); + goto bad3; + } + + /* setup interrupt service routine */ ret = request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath9k", sc); if (ret) { dev_err(&pdev->dev, "request_irq failed\n"); - goto err_irq; + goto bad4; } sc->irq = pdev->irq; - pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsysid); - ret = ath9k_init_device(id->device, sc, subsysid, &ath_pci_bus_ops); - if (ret) { - dev_err(&pdev->dev, "Failed to initialize device\n"); - goto err_init; - } - - ath9k_hw_name(sc->sc_ah, hw_name, sizeof(hw_name)); + ah = sc->sc_ah; + ath9k_hw_name(ah, hw_name, sizeof(hw_name)); printk(KERN_INFO "%s: %s mem=0x%lx, irq=%d\n", wiphy_name(hw->wiphy), @@ -214,18 +227,15 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) (unsigned long)mem, pdev->irq); return 0; - -err_init: - free_irq(sc->irq, sc); -err_irq: +bad4: + ath_detach(sc); +bad3: ieee80211_free_hw(hw); -err_alloc_hw: +bad2: pci_iounmap(pdev, mem); -err_iomap: +bad1: pci_release_region(pdev, 0); -err_region: - /* Nothing */ -err_dma: +bad: pci_disable_device(pdev); return ret; } @@ -235,15 +245,8 @@ static void ath_pci_remove(struct pci_dev *pdev) struct ieee80211_hw *hw = pci_get_drvdata(pdev); struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; - void __iomem *mem = sc->mem; - - ath9k_deinit_device(sc); - free_irq(sc->irq, sc); - ieee80211_free_hw(sc->hw); - pci_iounmap(pdev, mem); - pci_disable_device(pdev); - pci_release_region(pdev, 0); + ath_cleanup(sc); } #ifdef CONFIG_PM diff --git a/trunk/drivers/net/wireless/ath/ath9k/rc.c b/trunk/drivers/net/wireless/ath/ath9k/rc.c index 2880507f9d3f..c915954d4d5b 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/rc.c +++ b/trunk/drivers/net/wireless/ath/ath9k/rc.c @@ -668,7 +668,7 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, struct ieee80211_tx_rate *rates = tx_info->control.rates; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; __le16 fc = hdr->frame_control; - u8 try_per_rate, i = 0, rix; + u8 try_per_rate, i = 0, rix, nrix; int is_probe = 0; if (rate_control_send_low(sta, priv_sta, txrc)) @@ -678,47 +678,48 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, * For Multi Rate Retry we use a different number of * retry attempt counts. This ends up looking like this: * - * MRR[0] = 4 - * MRR[1] = 4 - * MRR[2] = 4 - * MRR[3] = 8 + * MRR[0] = 2 + * MRR[1] = 2 + * MRR[2] = 2 + * MRR[3] = 4 * */ - try_per_rate = 4; + try_per_rate = sc->hw->max_rate_tries; rate_table = sc->cur_rate_table; rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table, &is_probe); + nrix = rix; if (is_probe) { /* set one try for probe rates. For the * probes don't enable rts */ ath_rc_rate_set_series(rate_table, &rates[i++], txrc, - 1, rix, 0); + 1, nrix, 0); /* Get the next tried/allowed rate. No RTS for the next series * after the probe rate */ - ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &rix); + ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &nrix); ath_rc_rate_set_series(rate_table, &rates[i++], txrc, - try_per_rate, rix, 0); + try_per_rate, nrix, 0); tx_info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; } else { /* Set the choosen rate. No RTS for first series entry. */ ath_rc_rate_set_series(rate_table, &rates[i++], txrc, - try_per_rate, rix, 0); + try_per_rate, nrix, 0); } /* Fill in the other rates for multirate retry */ for ( ; i < 4; i++) { /* Use twice the number of tries for the last MRR segment. */ if (i + 1 == 4) - try_per_rate = 8; + try_per_rate = 4; - ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &rix); + ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &nrix); /* All other rates in the series have RTS enabled */ ath_rc_rate_set_series(rate_table, &rates[i], txrc, - try_per_rate, rix, 1); + try_per_rate, nrix, 1); } /* diff --git a/trunk/drivers/net/wireless/ath/ath9k/rc.h b/trunk/drivers/net/wireless/ath/ath9k/rc.h index 4f6d6fd442f4..9eb96f506998 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/rc.h +++ b/trunk/drivers/net/wireless/ath/ath9k/rc.h @@ -57,10 +57,6 @@ enum { || (_phy == WLAN_RC_PHY_HT_40_DS) \ || (_phy == WLAN_RC_PHY_HT_20_DS_HGI) \ || (_phy == WLAN_RC_PHY_HT_40_DS_HGI)) -#define WLAN_RC_PHY_20(_phy) ((_phy == WLAN_RC_PHY_HT_20_SS) \ - || (_phy == WLAN_RC_PHY_HT_20_DS) \ - || (_phy == WLAN_RC_PHY_HT_20_SS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_20_DS_HGI)) #define WLAN_RC_PHY_40(_phy) ((_phy == WLAN_RC_PHY_HT_40_SS) \ || (_phy == WLAN_RC_PHY_HT_40_DS) \ || (_phy == WLAN_RC_PHY_HT_40_SS_HGI) \ diff --git a/trunk/drivers/net/wireless/ath/ath9k/recv.c b/trunk/drivers/net/wireless/ath/ath9k/recv.c index 1ca42e5148c8..477365e5ae69 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/recv.c +++ b/trunk/drivers/net/wireless/ath/ath9k/recv.c @@ -364,10 +364,10 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) if (memcmp(common->curbssid, mgmt->bssid, ETH_ALEN) != 0) return; /* not from our current AP */ - sc->ps_flags &= ~PS_WAIT_FOR_BEACON; + sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON; - if (sc->ps_flags & PS_BEACON_SYNC) { - sc->ps_flags &= ~PS_BEACON_SYNC; + if (sc->sc_flags & SC_OP_BEACON_SYNC) { + sc->sc_flags &= ~SC_OP_BEACON_SYNC; ath_print(common, ATH_DBG_PS, "Reconfigure Beacon timers based on " "timestamp from the AP\n"); @@ -384,17 +384,17 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) */ ath_print(common, ATH_DBG_PS, "Received DTIM beacon indicating " "buffered broadcast/multicast frame(s)\n"); - sc->ps_flags |= PS_WAIT_FOR_CAB | PS_WAIT_FOR_BEACON; + sc->sc_flags |= SC_OP_WAIT_FOR_CAB | SC_OP_WAIT_FOR_BEACON; return; } - if (sc->ps_flags & PS_WAIT_FOR_CAB) { + if (sc->sc_flags & SC_OP_WAIT_FOR_CAB) { /* * This can happen if a broadcast frame is dropped or the AP * fails to send a frame indicating that all CAB frames have * been delivered. */ - sc->ps_flags &= ~PS_WAIT_FOR_CAB; + sc->sc_flags &= ~SC_OP_WAIT_FOR_CAB; ath_print(common, ATH_DBG_PS, "PS wait for CAB frames timed out\n"); } @@ -408,10 +408,10 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb) hdr = (struct ieee80211_hdr *)skb->data; /* Process Beacon and CAB receive in PS state */ - if ((sc->ps_flags & PS_WAIT_FOR_BEACON) && + if ((sc->sc_flags & SC_OP_WAIT_FOR_BEACON) && ieee80211_is_beacon(hdr->frame_control)) ath_rx_ps_beacon(sc, skb); - else if ((sc->ps_flags & PS_WAIT_FOR_CAB) && + else if ((sc->sc_flags & SC_OP_WAIT_FOR_CAB) && (ieee80211_is_data(hdr->frame_control) || ieee80211_is_action(hdr->frame_control)) && is_multicast_ether_addr(hdr->addr1) && @@ -420,20 +420,20 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb) * No more broadcast/multicast frames to be received at this * point. */ - sc->ps_flags &= ~PS_WAIT_FOR_CAB; + sc->sc_flags &= ~SC_OP_WAIT_FOR_CAB; ath_print(common, ATH_DBG_PS, "All PS CAB frames received, back to sleep\n"); - } else if ((sc->ps_flags & PS_WAIT_FOR_PSPOLL_DATA) && + } else if ((sc->sc_flags & SC_OP_WAIT_FOR_PSPOLL_DATA) && !is_multicast_ether_addr(hdr->addr1) && !ieee80211_has_morefrags(hdr->frame_control)) { - sc->ps_flags &= ~PS_WAIT_FOR_PSPOLL_DATA; + sc->sc_flags &= ~SC_OP_WAIT_FOR_PSPOLL_DATA; ath_print(common, ATH_DBG_PS, "Going back to sleep after having received " - "PS-Poll data (0x%lx)\n", - sc->ps_flags & (PS_WAIT_FOR_BEACON | - PS_WAIT_FOR_CAB | - PS_WAIT_FOR_PSPOLL_DATA | - PS_WAIT_FOR_TX_ACK)); + "PS-Poll data (0x%x)\n", + sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | + SC_OP_WAIT_FOR_CAB | + SC_OP_WAIT_FOR_PSPOLL_DATA | + SC_OP_WAIT_FOR_TX_ACK)); } } @@ -571,8 +571,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) hw = ath_get_virt_hw(sc, hdr); rx_stats = &ds->ds_rxstat; - ath_debug_stat_rx(sc, bf); - /* * If we're asked to flush receive queue, directly * chain it back at the queue without processing it. @@ -633,9 +631,9 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) sc->rx.rxotherant = 0; } - if (unlikely(sc->ps_flags & (PS_WAIT_FOR_BEACON | - PS_WAIT_FOR_CAB | - PS_WAIT_FOR_PSPOLL_DATA))) + if (unlikely(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | + SC_OP_WAIT_FOR_CAB | + SC_OP_WAIT_FOR_PSPOLL_DATA))) ath_rx_ps(sc, skb); ath_rx_send_to_mac80211(hw, sc, skb, rxs); diff --git a/trunk/drivers/net/wireless/ath/ath9k/reg.h b/trunk/drivers/net/wireless/ath/ath9k/reg.h index 72cfa8ebd9ae..8e653fb937a1 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/reg.h +++ b/trunk/drivers/net/wireless/ath/ath9k/reg.h @@ -1547,9 +1547,9 @@ enum { #define AR_BT_COEX_WEIGHT 0x8174 #define AR_BT_COEX_WGHT 0xff55 -#define AR_STOMP_ALL_WLAN_WGHT 0xfcfc -#define AR_STOMP_LOW_WLAN_WGHT 0xa8a8 -#define AR_STOMP_NONE_WLAN_WGHT 0x0000 +#define AR_STOMP_ALL_WLAN_WGHT 0xffcc +#define AR_STOMP_LOW_WLAN_WGHT 0xaaa8 +#define AR_STOMP_NONE_WLAN_WGHT 0xaa00 #define AR_BTCOEX_BT_WGHT 0x0000ffff #define AR_BTCOEX_BT_WGHT_S 0 #define AR_BTCOEX_WL_WGHT 0xffff0000 diff --git a/trunk/drivers/net/wireless/ath/ath9k/virtual.c b/trunk/drivers/net/wireless/ath/ath9k/virtual.c index a43fbf84dab9..cd26caaf44e7 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/virtual.c +++ b/trunk/drivers/net/wireless/ath/ath9k/virtual.c @@ -152,7 +152,7 @@ int ath9k_wiphy_add(struct ath_softc *sc) SET_IEEE80211_PERM_ADDR(hw, addr); - ath9k_set_hw_capab(sc, hw); + ath_set_hw_capab(sc, hw); error = ieee80211_register_hw(hw); diff --git a/trunk/drivers/net/wireless/ath/ath9k/xmit.c b/trunk/drivers/net/wireless/ath/ath9k/xmit.c index 47294f90bbe5..29bf33692f71 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/xmit.c +++ b/trunk/drivers/net/wireless/ath/ath9k/xmit.c @@ -1498,6 +1498,26 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) if (sc->sc_flags & SC_OP_PREAMBLE_SHORT) ctsrate |= rate->hw_value_short; + /* + * ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive. + * Check the first rate in the series to decide whether RTS/CTS + * or CTS-to-self has to be used. + */ + if (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) + flags = ATH9K_TXDESC_CTSENA; + else if (rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) + flags = ATH9K_TXDESC_RTSENA; + + /* FIXME: Handle aggregation protection */ + if (sc->config.ath_aggr_prot && + (!bf_isaggr(bf) || (bf_isaggr(bf) && bf->bf_al < 8192))) { + flags = ATH9K_TXDESC_RTSENA; + } + + /* For AR5416 - RTS cannot be followed by a frame larger than 8K */ + if (bf_isaggr(bf) && (bf->bf_al > sc->sc_ah->caps.rts_aggr_limit)) + flags &= ~(ATH9K_TXDESC_RTSENA); + for (i = 0; i < 4; i++) { bool is_40, is_sgi, is_sp; int phy; @@ -1509,15 +1529,8 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) series[i].Tries = rates[i].count; series[i].ChSel = common->tx_chainmask; - if ((sc->config.ath_aggr_prot && bf_isaggr(bf)) || - (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS)) { + if (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS) series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS; - flags |= ATH9K_TXDESC_RTSENA; - } else if (rates[i].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { - series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS; - flags |= ATH9K_TXDESC_CTSENA; - } - if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) series[i].RateFlags |= ATH9K_RATESERIES_2040; if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI) @@ -1555,14 +1568,6 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) phy, rate->bitrate * 100, bf->bf_frmlen, rix, is_sp); } - /* For AR5416 - RTS cannot be followed by a frame larger than 8K */ - if (bf_isaggr(bf) && (bf->bf_al > sc->sc_ah->caps.rts_aggr_limit)) - flags &= ~ATH9K_TXDESC_RTSENA; - - /* ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive. */ - if (flags & ATH9K_TXDESC_RTSENA) - flags &= ~ATH9K_TXDESC_CTSENA; - /* set dur_update_en for l-sig computation except for PS-Poll frames */ ath9k_hw_set11n_ratescenario(sc->sc_ah, bf->bf_desc, bf->bf_lastbf->bf_desc, @@ -1643,7 +1648,7 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf, /* tag if this is a nullfunc frame to enable PS when AP acks it */ if (ieee80211_is_nullfunc(fc) && ieee80211_has_pm(fc)) { bf->bf_isnullfunc = true; - sc->ps_flags &= ~PS_NULLFUNC_COMPLETED; + sc->sc_flags &= ~SC_OP_NULLFUNC_COMPLETED; } else bf->bf_isnullfunc = false; @@ -1853,15 +1858,15 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, skb_pull(skb, padsize); } - if (sc->ps_flags & PS_WAIT_FOR_TX_ACK) { - sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK; + if (sc->sc_flags & SC_OP_WAIT_FOR_TX_ACK) { + sc->sc_flags &= ~SC_OP_WAIT_FOR_TX_ACK; ath_print(common, ATH_DBG_PS, "Going back to sleep after having " - "received TX status (0x%lx)\n", - sc->ps_flags & (PS_WAIT_FOR_BEACON | - PS_WAIT_FOR_CAB | - PS_WAIT_FOR_PSPOLL_DATA | - PS_WAIT_FOR_TX_ACK)); + "received TX status (0x%x)\n", + sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | + SC_OP_WAIT_FOR_CAB | + SC_OP_WAIT_FOR_PSPOLL_DATA | + SC_OP_WAIT_FOR_TX_ACK)); } if (unlikely(tx_info->pad[0] & ATH_TX_INFO_FRAME_TYPE_INTERNAL)) @@ -2048,10 +2053,11 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) */ if (bf->bf_isnullfunc && (ds->ds_txstat.ts_status & ATH9K_TX_ACKED)) { - if ((sc->ps_flags & PS_ENABLED)) - ath9k_enable_ps(sc); - else - sc->ps_flags |= PS_NULLFUNC_COMPLETED; + if ((sc->sc_flags & SC_OP_PS_ENABLED)) { + sc->ps_enabled = true; + ath9k_hw_setrxabort(sc->sc_ah, 1); + } else + sc->sc_flags |= SC_OP_NULLFUNC_COMPLETED; } /* diff --git a/trunk/drivers/net/wireless/ath/debug.h b/trunk/drivers/net/wireless/ath/debug.h index 8263633c003c..d6b685a06c5e 100644 --- a/trunk/drivers/net/wireless/ath/debug.h +++ b/trunk/drivers/net/wireless/ath/debug.h @@ -65,11 +65,11 @@ enum ATH_DEBUG { #define ATH_DBG_DEFAULT (ATH_DBG_FATAL) #ifdef CONFIG_ATH_DEBUG -void ath_print(struct ath_common *common, int dbg_mask, const char *fmt, ...) - __attribute__ ((format (printf, 3, 4))); +void ath_print(struct ath_common *common, int dbg_mask, const char *fmt, ...); #else -static inline void __attribute__ ((format (printf, 3, 4))) -ath_print(struct ath_common *common, int dbg_mask, const char *fmt, ...) +static inline void ath_print(struct ath_common *common, + int dbg_mask, + const char *fmt, ...) { } #endif /* CONFIG_ATH_DEBUG */ diff --git a/trunk/drivers/net/wireless/ath/regd.c b/trunk/drivers/net/wireless/ath/regd.c index 04abd1f556b7..039ac490465c 100644 --- a/trunk/drivers/net/wireless/ath/regd.c +++ b/trunk/drivers/net/wireless/ath/regd.c @@ -110,9 +110,8 @@ static const struct ieee80211_regdomain ath_world_regdom_67_68_6A = { static inline bool is_wwr_sku(u16 regd) { - return ((regd & COUNTRY_ERD_FLAG) != COUNTRY_ERD_FLAG) && - (((regd & WORLD_SKU_MASK) == WORLD_SKU_PREFIX) || - (regd == WORLD)); + return ((regd & WORLD_SKU_MASK) == WORLD_SKU_PREFIX) || + (regd == WORLD); } static u16 ath_regd_get_eepromRD(struct ath_regulatory *reg) diff --git a/trunk/drivers/net/wireless/b43/Kconfig b/trunk/drivers/net/wireless/b43/Kconfig index 073be566d05e..64c12e1bced3 100644 --- a/trunk/drivers/net/wireless/b43/Kconfig +++ b/trunk/drivers/net/wireless/b43/Kconfig @@ -3,7 +3,6 @@ config B43 depends on SSB_POSSIBLE && MAC80211 && HAS_DMA select SSB select FW_LOADER - select SSB_BLOCKIO ---help--- b43 is a driver for the Broadcom 43xx series wireless devices. @@ -79,6 +78,14 @@ config B43_SDIO If unsure, say N. +# Data transfers to the device via PIO +# This is only needed on PCMCIA and SDIO devices. All others can do DMA properly. +config B43_PIO + bool + depends on B43 && (B43_SDIO || B43_PCMCIA || B43_FORCE_PIO) + select SSB_BLOCKIO + default y + config B43_NPHY bool "Pre IEEE 802.11n support (BROKEN)" depends on B43 && EXPERIMENTAL && BROKEN @@ -130,4 +137,12 @@ config B43_DEBUG for production use. Only say Y, if you are debugging a problem in the b43 driver sourcecode. +config B43_FORCE_PIO + bool "Force usage of PIO instead of DMA" + depends on B43 && B43_DEBUG + ---help--- + This will disable DMA and always enable PIO instead. + Say N! + This is only for debugging the PIO engine code. You do + _NOT_ want to enable this. diff --git a/trunk/drivers/net/wireless/b43/Makefile b/trunk/drivers/net/wireless/b43/Makefile index 5e83b6f0a3a0..84772a2542dc 100644 --- a/trunk/drivers/net/wireless/b43/Makefile +++ b/trunk/drivers/net/wireless/b43/Makefile @@ -12,7 +12,7 @@ b43-y += xmit.o b43-y += lo.o b43-y += wa.o b43-y += dma.o -b43-y += pio.o +b43-$(CONFIG_B43_PIO) += pio.o b43-y += rfkill.o b43-$(CONFIG_B43_LEDS) += leds.o b43-$(CONFIG_B43_PCMCIA) += pcmcia.o diff --git a/trunk/drivers/net/wireless/b43/b43.h b/trunk/drivers/net/wireless/b43/b43.h index 6a6ab0f630e5..c484cc253892 100644 --- a/trunk/drivers/net/wireless/b43/b43.h +++ b/trunk/drivers/net/wireless/b43/b43.h @@ -254,14 +254,6 @@ enum { #define B43_SHM_SH_MAXBFRAMES 0x0080 /* Maximum number of frames in a burst */ #define B43_SHM_SH_SPUWKUP 0x0094 /* pre-wakeup for synth PU in us */ #define B43_SHM_SH_PRETBTT 0x0096 /* pre-TBTT in us */ -/* SHM_SHARED tx iq workarounds */ -#define B43_SHM_SH_NPHY_TXIQW0 0x0700 -#define B43_SHM_SH_NPHY_TXIQW1 0x0702 -#define B43_SHM_SH_NPHY_TXIQW2 0x0704 -#define B43_SHM_SH_NPHY_TXIQW3 0x0706 -/* SHM_SHARED tx pwr ctrl */ -#define B43_SHM_SH_NPHY_TXPWR_INDX0 0x0708 -#define B43_SHM_SH_NPHY_TXPWR_INDX1 0x070E /* SHM_SCRATCH offsets */ #define B43_SHM_SC_MINCONT 0x0003 /* Minimum contention window */ @@ -830,9 +822,11 @@ struct b43_wl { /* The device LEDs. */ struct b43_leds leds; +#ifdef CONFIG_B43_PIO /* Kmalloc'ed scratch space for PIO TX/RX. Protected by wl->mutex. */ u8 pio_scratchspace[110] __attribute__((__aligned__(8))); u8 pio_tailspace[4] __attribute__((__aligned__(8))); +#endif /* CONFIG_B43_PIO */ }; static inline struct b43_wl *hw_to_b43_wl(struct ieee80211_hw *hw) @@ -883,9 +877,20 @@ static inline void b43_write32(struct b43_wldev *dev, u16 offset, u32 value) static inline bool b43_using_pio_transfers(struct b43_wldev *dev) { +#ifdef CONFIG_B43_PIO return dev->__using_pio_transfers; +#else + return 0; +#endif } +#ifdef CONFIG_B43_FORCE_PIO +# define B43_FORCE_PIO 1 +#else +# define B43_FORCE_PIO 0 +#endif + + /* Message printing */ void b43info(struct b43_wl *wl, const char *fmt, ...) __attribute__ ((format(printf, 2, 3))); diff --git a/trunk/drivers/net/wireless/b43/dma.c b/trunk/drivers/net/wireless/b43/dma.c index be7abf8916ad..88d1fd02d40a 100644 --- a/trunk/drivers/net/wireless/b43/dma.c +++ b/trunk/drivers/net/wireless/b43/dma.c @@ -1369,6 +1369,7 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) b43err(dev->wl, "DMA tx mapping failure\n"); goto out; } + ring->nr_tx_packets++; if ((free_slots(ring) < TX_SLOTS_PER_FRAME) || should_inject_overflow(ring)) { /* This TX ring is full. */ @@ -1499,6 +1500,22 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, } } +void b43_dma_get_tx_stats(struct b43_wldev *dev, + struct ieee80211_tx_queue_stats *stats) +{ + const int nr_queues = dev->wl->hw->queues; + struct b43_dmaring *ring; + int i; + + for (i = 0; i < nr_queues; i++) { + ring = select_ring_by_priority(dev, i); + + stats[i].len = ring->used_slots / TX_SLOTS_PER_FRAME; + stats[i].limit = ring->nr_slots / TX_SLOTS_PER_FRAME; + stats[i].count = ring->nr_tx_packets; + } +} + static void dma_rx(struct b43_dmaring *ring, int *slot) { const struct b43_dma_ops *ops = ring->ops; @@ -1636,6 +1653,7 @@ void b43_dma_tx_resume(struct b43_wldev *dev) b43_power_saving_ctl_bits(dev, 0); } +#ifdef CONFIG_B43_PIO static void direct_fifo_rx(struct b43_wldev *dev, enum b43_dmatype type, u16 mmio_base, bool enable) { @@ -1669,3 +1687,4 @@ void b43_dma_direct_fifo_rx(struct b43_wldev *dev, mmio_base = b43_dmacontroller_base(type, engine_index); direct_fifo_rx(dev, type, mmio_base, enable); } +#endif /* CONFIG_B43_PIO */ diff --git a/trunk/drivers/net/wireless/b43/dma.h b/trunk/drivers/net/wireless/b43/dma.h index dc91944d6022..f7ab37c4cdbc 100644 --- a/trunk/drivers/net/wireless/b43/dma.h +++ b/trunk/drivers/net/wireless/b43/dma.h @@ -228,6 +228,8 @@ struct b43_dmaring { int used_slots; /* Currently used slot in the ring. */ int current_slot; + /* Total number of packets sent. Statistics only. */ + unsigned int nr_tx_packets; /* Frameoffset in octets. */ u32 frameoffset; /* Descriptor buffer size. */ @@ -276,6 +278,9 @@ void b43_dma_free(struct b43_wldev *dev); void b43_dma_tx_suspend(struct b43_wldev *dev); void b43_dma_tx_resume(struct b43_wldev *dev); +void b43_dma_get_tx_stats(struct b43_wldev *dev, + struct ieee80211_tx_queue_stats *stats); + int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb); void b43_dma_handle_txstatus(struct b43_wldev *dev, diff --git a/trunk/drivers/net/wireless/b43/main.c b/trunk/drivers/net/wireless/b43/main.c index 8f7a8c0ec27d..fcbf0e27d9f3 100644 --- a/trunk/drivers/net/wireless/b43/main.c +++ b/trunk/drivers/net/wireless/b43/main.c @@ -67,12 +67,7 @@ MODULE_AUTHOR("Gábor Stefanik"); MODULE_LICENSE("GPL"); MODULE_FIRMWARE(B43_SUPPORTED_FIRMWARE_ID); -MODULE_FIRMWARE("b43/ucode11.fw"); -MODULE_FIRMWARE("b43/ucode13.fw"); -MODULE_FIRMWARE("b43/ucode14.fw"); -MODULE_FIRMWARE("b43/ucode15.fw"); -MODULE_FIRMWARE("b43/ucode5.fw"); -MODULE_FIRMWARE("b43/ucode9.fw"); + static int modparam_bad_frames_preempt; module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444); @@ -107,9 +102,6 @@ int b43_modparam_verbose = B43_VERBOSITY_DEFAULT; module_param_named(verbose, b43_modparam_verbose, int, 0644); MODULE_PARM_DESC(verbose, "Log message verbosity: 0=error, 1=warn, 2=info(default), 3=debug"); -static int modparam_pio; -module_param_named(pio, modparam_pio, int, 0444); -MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode"); static const struct ssb_device_id b43_ssb_tbl[] = { SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 5), @@ -118,7 +110,6 @@ static const struct ssb_device_id b43_ssb_tbl[] = { SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 9), SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 10), SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 11), - SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 12), SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 13), SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 15), SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 16), @@ -851,10 +842,8 @@ static void rx_tkip_phase1_write(struct b43_wldev *dev, u8 index, u32 iv32, } static void b43_op_update_tkip_key(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_key_conf *keyconf, - struct ieee80211_sta *sta, - u32 iv32, u16 *phase1key) + struct ieee80211_key_conf *keyconf, const u8 *addr, + u32 iv32, u16 *phase1key) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev; @@ -863,19 +852,19 @@ static void b43_op_update_tkip_key(struct ieee80211_hw *hw, if (B43_WARN_ON(!modparam_hwtkip)) return; - /* This is only called from the RX path through mac80211, where - * our mutex is already locked. */ - B43_WARN_ON(!mutex_is_locked(&wl->mutex)); + mutex_lock(&wl->mutex); + dev = wl->current_dev; - B43_WARN_ON(!dev || b43_status(dev) < B43_STAT_INITIALIZED); + if (!dev || b43_status(dev) < B43_STAT_INITIALIZED) + goto out_unlock; keymac_write(dev, index, NULL); /* First zero out mac to avoid race */ rx_tkip_phase1_write(dev, index, iv32, phase1key); - /* only pairwise TKIP keys are supported right now */ - if (WARN_ON(!sta)) - return; - keymac_write(dev, index, sta->addr); + keymac_write(dev, index, addr); + +out_unlock: + mutex_unlock(&wl->mutex); } static void do_key_write(struct b43_wldev *dev, @@ -1804,8 +1793,8 @@ static void b43_do_interrupt_thread(struct b43_wldev *dev) dma_reason[4], dma_reason[5]); b43err(dev->wl, "This device does not support DMA " "on your system. Please use PIO instead.\n"); - b43err(dev->wl, "Unload the b43 module and reload " - "with 'pio=1'\n"); + b43err(dev->wl, "CONFIG_B43_FORCE_PIO must be set in " + "your kernel configuration.\n"); return; } if (merged_dma_reason & B43_DMAIRQ_NONFATALMASK) { @@ -3356,6 +3345,27 @@ static int b43_op_conf_tx(struct ieee80211_hw *hw, u16 _queue, return err; } +static int b43_op_get_tx_stats(struct ieee80211_hw *hw, + struct ieee80211_tx_queue_stats *stats) +{ + struct b43_wl *wl = hw_to_b43_wl(hw); + struct b43_wldev *dev; + int err = -ENODEV; + + mutex_lock(&wl->mutex); + dev = wl->current_dev; + if (dev && b43_status(dev) >= B43_STAT_STARTED) { + if (b43_using_pio_transfers(dev)) + b43_pio_get_tx_stats(dev, stats); + else + b43_dma_get_tx_stats(dev, stats); + err = 0; + } + mutex_unlock(&wl->mutex); + + return err; +} + static int b43_op_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats) { @@ -3559,12 +3569,6 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) dev = wl->current_dev; phy = &dev->phy; - if (conf_is_ht(conf)) - phy->is_40mhz = - (conf_is_ht40_minus(conf) || conf_is_ht40_plus(conf)); - else - phy->is_40mhz = false; - b43_mac_suspend(dev); if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) @@ -3966,7 +3970,6 @@ static int b43_wireless_core_start(struct b43_wldev *dev) } /* We are ready to run. */ - ieee80211_wake_queues(dev->wl->hw); b43_set_status(dev, B43_STAT_STARTED); /* Start data flow (TX/RX). */ @@ -4357,7 +4360,7 @@ static int b43_wireless_core_init(struct b43_wldev *dev) if ((dev->dev->bus->bustype == SSB_BUSTYPE_PCMCIA) || (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) || - modparam_pio) { + B43_FORCE_PIO) { dev->__using_pio_transfers = 1; err = b43_pio_init(dev); } else { @@ -4376,6 +4379,8 @@ static int b43_wireless_core_init(struct b43_wldev *dev) ieee80211_wake_queues(dev->wl->hw); + ieee80211_wake_queues(dev->wl->hw); + b43_set_status(dev, B43_STAT_INITIALIZED); out: @@ -4390,7 +4395,7 @@ static int b43_wireless_core_init(struct b43_wldev *dev) } static int b43_op_add_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) + struct ieee80211_if_init_conf *conf) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev; @@ -4398,24 +4403,24 @@ static int b43_op_add_interface(struct ieee80211_hw *hw, /* TODO: allow WDS/AP devices to coexist */ - if (vif->type != NL80211_IFTYPE_AP && - vif->type != NL80211_IFTYPE_MESH_POINT && - vif->type != NL80211_IFTYPE_STATION && - vif->type != NL80211_IFTYPE_WDS && - vif->type != NL80211_IFTYPE_ADHOC) + if (conf->type != NL80211_IFTYPE_AP && + conf->type != NL80211_IFTYPE_MESH_POINT && + conf->type != NL80211_IFTYPE_STATION && + conf->type != NL80211_IFTYPE_WDS && + conf->type != NL80211_IFTYPE_ADHOC) return -EOPNOTSUPP; mutex_lock(&wl->mutex); if (wl->operating) goto out_mutex_unlock; - b43dbg(wl, "Adding Interface type %d\n", vif->type); + b43dbg(wl, "Adding Interface type %d\n", conf->type); dev = wl->current_dev; wl->operating = 1; - wl->vif = vif; - wl->if_type = vif->type; - memcpy(wl->mac_addr, vif->addr, ETH_ALEN); + wl->vif = conf->vif; + wl->if_type = conf->type; + memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN); b43_adjust_opmode(dev); b43_set_pretbtt(dev); @@ -4430,17 +4435,17 @@ static int b43_op_add_interface(struct ieee80211_hw *hw, } static void b43_op_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) + struct ieee80211_if_init_conf *conf) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev = wl->current_dev; - b43dbg(wl, "Removing Interface type %d\n", vif->type); + b43dbg(wl, "Removing Interface type %d\n", conf->type); mutex_lock(&wl->mutex); B43_WARN_ON(!wl->operating); - B43_WARN_ON(wl->vif != vif); + B43_WARN_ON(wl->vif != conf->vif); wl->vif = NULL; wl->operating = 0; @@ -4581,6 +4586,7 @@ static const struct ieee80211_ops b43_hw_ops = { .set_key = b43_op_set_key, .update_tkip_key = b43_op_update_tkip_key, .get_stats = b43_op_get_stats, + .get_tx_stats = b43_op_get_tx_stats, .get_tsf = b43_op_get_tsf, .set_tsf = b43_op_set_tsf, .start = b43_op_start, diff --git a/trunk/drivers/net/wireless/b43/phy_common.c b/trunk/drivers/net/wireless/b43/phy_common.c index 8f7d7eff2d80..75b26e175e8f 100644 --- a/trunk/drivers/net/wireless/b43/phy_common.c +++ b/trunk/drivers/net/wireless/b43/phy_common.c @@ -421,48 +421,3 @@ void b43_phyop_switch_analog_generic(struct b43_wldev *dev, bool on) { b43_write16(dev, B43_MMIO_PHY0, on ? 0 : 0xF4); } - -/* http://bcm-v4.sipsolutions.net/802.11/PHY/Cordic */ -struct b43_c32 b43_cordic(int theta) -{ - u32 arctg[] = { 2949120, 1740967, 919879, 466945, 234379, 117304, - 58666, 29335, 14668, 7334, 3667, 1833, 917, 458, - 229, 115, 57, 29, }; - u8 i; - s32 tmp; - s8 signx = 1; - u32 angle = 0; - struct b43_c32 ret = { .i = 39797, .q = 0, }; - - while (theta > (180 << 16)) - theta -= (360 << 16); - while (theta < -(180 << 16)) - theta += (360 << 16); - - if (theta > (90 << 16)) { - theta -= (180 << 16); - signx = -1; - } else if (theta < -(90 << 16)) { - theta += (180 << 16); - signx = -1; - } - - for (i = 0; i <= 17; i++) { - if (theta > angle) { - tmp = ret.i - (ret.q >> i); - ret.q += ret.i >> i; - ret.i = tmp; - angle += arctg[i]; - } else { - tmp = ret.i + (ret.q >> i); - ret.q -= ret.i >> i; - ret.i = tmp; - angle -= arctg[i]; - } - } - - ret.i *= signx; - ret.q *= signx; - - return ret; -} diff --git a/trunk/drivers/net/wireless/b43/phy_common.h b/trunk/drivers/net/wireless/b43/phy_common.h index bd480b481bfc..9edd4e8e0c85 100644 --- a/trunk/drivers/net/wireless/b43/phy_common.h +++ b/trunk/drivers/net/wireless/b43/phy_common.h @@ -5,12 +5,6 @@ struct b43_wldev; -/* Complex number using 2 32-bit signed integers */ -struct b43_c32 { s32 i, q; }; - -#define CORDIC_CONVERT(value) (((value) >= 0) ? \ - ((((value) >> 15) + 1) >> 1) : \ - -((((-(value)) >> 15) + 1) >> 1)) /* PHY register routing bits */ #define B43_PHYROUTE 0x0C00 /* PHY register routing bits mask */ @@ -218,9 +212,6 @@ struct b43_phy { bool supports_2ghz; bool supports_5ghz; - /* HT info */ - bool is_40mhz; - /* GMODE bit enabled? */ bool gmode; @@ -427,6 +418,5 @@ int b43_phy_shm_tssi_read(struct b43_wldev *dev, u16 shm_offset); */ void b43_phyop_switch_analog_generic(struct b43_wldev *dev, bool on); -struct b43_c32 b43_cordic(int theta); #endif /* LINUX_B43_PHY_COMMON_H_ */ diff --git a/trunk/drivers/net/wireless/b43/phy_lp.c b/trunk/drivers/net/wireless/b43/phy_lp.c index 185219e0a552..3e046ec1ff86 100644 --- a/trunk/drivers/net/wireless/b43/phy_lp.c +++ b/trunk/drivers/net/wireless/b43/phy_lp.c @@ -80,7 +80,6 @@ static void b43_lpphy_op_free(struct b43_wldev *dev) dev->phy.lp = NULL; } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/LP/ReadBandSrom */ static void lpphy_read_band_sprom(struct b43_wldev *dev) { struct b43_phy_lp *lpphy = dev->phy.lp; @@ -102,12 +101,6 @@ static void lpphy_read_band_sprom(struct b43_wldev *dev) maxpwr = bus->sprom.maxpwr_bg; lpphy->max_tx_pwr_med_band = maxpwr; cckpo = bus->sprom.cck2gpo; - /* - * We don't read SPROM's opo as specs say. On rev8 SPROMs - * opo == ofdm2gpo and we don't know any SSB with LP-PHY - * and SPROM rev below 8. - */ - B43_WARN_ON(bus->sprom.revision < 8); ofdmpo = bus->sprom.ofdm2gpo; if (cckpo) { for (i = 0; i < 4; i++) { @@ -1710,6 +1703,19 @@ static const struct lpphy_rx_iq_comp lpphy_rev2plus_iq_comp = { .c0 = 0, }; +static u8 lpphy_nbits(s32 val) +{ + u32 tmp = abs(val); + u8 nbits = 0; + + while (tmp != 0) { + nbits++; + tmp >>= 1; + } + + return nbits; +} + static int lpphy_calc_rx_iq_comp(struct b43_wldev *dev, u16 samples) { struct lpphy_iq_est iq_est; @@ -1736,8 +1742,8 @@ static int lpphy_calc_rx_iq_comp(struct b43_wldev *dev, u16 samples) goto out; } - prod_msb = fls(abs(prod)); - q_msb = fls(abs(qpwr)); + prod_msb = lpphy_nbits(prod); + q_msb = lpphy_nbits(qpwr); tmp1 = prod_msb - 20; if (tmp1 >= 0) { @@ -1767,6 +1773,47 @@ static int lpphy_calc_rx_iq_comp(struct b43_wldev *dev, u16 samples) return ret; } +/* Complex number using 2 32-bit signed integers */ +typedef struct {s32 i, q;} lpphy_c32; + +static lpphy_c32 lpphy_cordic(int theta) +{ + u32 arctg[] = { 2949120, 1740967, 919879, 466945, 234379, 117304, + 58666, 29335, 14668, 7334, 3667, 1833, 917, 458, + 229, 115, 57, 29, }; + int i, tmp, signx = 1, angle = 0; + lpphy_c32 ret = { .i = 39797, .q = 0, }; + + theta = clamp_t(int, theta, -180, 180); + + if (theta > 90) { + theta -= 180; + signx = -1; + } else if (theta < -90) { + theta += 180; + signx = -1; + } + + for (i = 0; i <= 17; i++) { + if (theta > angle) { + tmp = ret.i - (ret.q >> i); + ret.q += ret.i >> i; + ret.i = tmp; + angle += arctg[i]; + } else { + tmp = ret.i + (ret.q >> i); + ret.q -= ret.i >> i; + ret.i = tmp; + angle -= arctg[i]; + } + } + + ret.i *= signx; + ret.q *= signx; + + return ret; +} + static void lpphy_run_samples(struct b43_wldev *dev, u16 samples, u16 loops, u16 wait) { @@ -1784,9 +1831,8 @@ static void lpphy_start_tx_tone(struct b43_wldev *dev, s32 freq, u16 max) { struct b43_phy_lp *lpphy = dev->phy.lp; u16 buf[64]; - int i, samples = 0, angle = 0; - int rotation = (((36 * freq) / 20) << 16) / 100; - struct b43_c32 sample; + int i, samples = 0, angle = 0, rotation = (9 * freq) / 500; + lpphy_c32 sample; lpphy->tx_tone_freq = freq; @@ -1802,10 +1848,10 @@ static void lpphy_start_tx_tone(struct b43_wldev *dev, s32 freq, u16 max) } for (i = 0; i < samples; i++) { - sample = b43_cordic(angle); + sample = lpphy_cordic(angle); angle += rotation; - buf[i] = CORDIC_CONVERT((sample.i * max) & 0xFF) << 8; - buf[i] |= CORDIC_CONVERT((sample.q * max) & 0xFF); + buf[i] = ((sample.i * max) & 0xFF) << 8; + buf[i] |= (sample.q * max) & 0xFF; } b43_lptab_write_bulk(dev, B43_LPTAB16(5, 0), samples, buf); diff --git a/trunk/drivers/net/wireless/b43/phy_n.c b/trunk/drivers/net/wireless/b43/phy_n.c index 795bb1e3345d..992318a78077 100644 --- a/trunk/drivers/net/wireless/b43/phy_n.c +++ b/trunk/drivers/net/wireless/b43/phy_n.c @@ -28,50 +28,7 @@ #include "b43.h" #include "phy_n.h" #include "tables_nphy.h" -#include "main.h" -struct nphy_txgains { - u16 txgm[2]; - u16 pga[2]; - u16 pad[2]; - u16 ipa[2]; -}; - -struct nphy_iqcal_params { - u16 txgm; - u16 pga; - u16 pad; - u16 ipa; - u16 cal_gain; - u16 ncorr[5]; -}; - -struct nphy_iq_est { - s32 iq0_prod; - u32 i0_pwr; - u32 q0_pwr; - s32 iq1_prod; - u32 i1_pwr; - u32 q1_pwr; -}; - -enum b43_nphy_rf_sequence { - B43_RFSEQ_RX2TX, - B43_RFSEQ_TX2RX, - B43_RFSEQ_RESET2RX, - B43_RFSEQ_UPDATE_GAINH, - B43_RFSEQ_UPDATE_GAINL, - B43_RFSEQ_UPDATE_GAINU, -}; - -static void b43_nphy_set_rf_sequence(struct b43_wldev *dev, u8 cmd, - u8 *events, u8 *delays, u8 length); -static void b43_nphy_force_rf_sequence(struct b43_wldev *dev, - enum b43_nphy_rf_sequence seq); -static void b43_nphy_rf_control_override(struct b43_wldev *dev, u16 field, - u16 value, u8 core, bool off); -static void b43_nphy_rf_control_intc_override(struct b43_wldev *dev, u8 field, - u16 value, u8 core); void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna) {//TODO @@ -240,2915 +197,295 @@ void b43_nphy_radio_turn_off(struct b43_wldev *dev) ~B43_NPHY_RFCTL_CMD_EN); } -/* - * Upload the N-PHY tables. - * http://bcm-v4.sipsolutions.net/802.11/PHY/N/InitTables - */ +#define ntab_upload(dev, offset, data) do { \ + unsigned int i; \ + for (i = 0; i < (offset##_SIZE); i++) \ + b43_ntab_write(dev, (offset) + i, (data)[i]); \ + } while (0) + +/* Upload the N-PHY tables. */ static void b43_nphy_tables_init(struct b43_wldev *dev) { - if (dev->phy.rev < 3) - b43_nphy_rev0_1_2_tables_init(dev); - else - b43_nphy_rev3plus_tables_init(dev); + /* Static tables */ + ntab_upload(dev, B43_NTAB_FRAMESTRUCT, b43_ntab_framestruct); + ntab_upload(dev, B43_NTAB_FRAMELT, b43_ntab_framelookup); + ntab_upload(dev, B43_NTAB_TMAP, b43_ntab_tmap); + ntab_upload(dev, B43_NTAB_TDTRN, b43_ntab_tdtrn); + ntab_upload(dev, B43_NTAB_INTLEVEL, b43_ntab_intlevel); + ntab_upload(dev, B43_NTAB_PILOT, b43_ntab_pilot); + ntab_upload(dev, B43_NTAB_PILOTLT, b43_ntab_pilotlt); + ntab_upload(dev, B43_NTAB_TDI20A0, b43_ntab_tdi20a0); + ntab_upload(dev, B43_NTAB_TDI20A1, b43_ntab_tdi20a1); + ntab_upload(dev, B43_NTAB_TDI40A0, b43_ntab_tdi40a0); + ntab_upload(dev, B43_NTAB_TDI40A1, b43_ntab_tdi40a1); + ntab_upload(dev, B43_NTAB_BDI, b43_ntab_bdi); + ntab_upload(dev, B43_NTAB_CHANEST, b43_ntab_channelest); + ntab_upload(dev, B43_NTAB_MCS, b43_ntab_mcs); + + /* Volatile tables */ + ntab_upload(dev, B43_NTAB_NOISEVAR10, b43_ntab_noisevar10); + ntab_upload(dev, B43_NTAB_NOISEVAR11, b43_ntab_noisevar11); + ntab_upload(dev, B43_NTAB_C0_ESTPLT, b43_ntab_estimatepowerlt0); + ntab_upload(dev, B43_NTAB_C1_ESTPLT, b43_ntab_estimatepowerlt1); + ntab_upload(dev, B43_NTAB_C0_ADJPLT, b43_ntab_adjustpower0); + ntab_upload(dev, B43_NTAB_C1_ADJPLT, b43_ntab_adjustpower1); + ntab_upload(dev, B43_NTAB_C0_GAINCTL, b43_ntab_gainctl0); + ntab_upload(dev, B43_NTAB_C1_GAINCTL, b43_ntab_gainctl1); + ntab_upload(dev, B43_NTAB_C0_IQLT, b43_ntab_iqlt0); + ntab_upload(dev, B43_NTAB_C1_IQLT, b43_ntab_iqlt1); + ntab_upload(dev, B43_NTAB_C0_LOFEEDTH, b43_ntab_loftlt0); + ntab_upload(dev, B43_NTAB_C1_LOFEEDTH, b43_ntab_loftlt1); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/PA%20override */ -static void b43_nphy_pa_override(struct b43_wldev *dev, bool enable) +static void b43_nphy_workarounds(struct b43_wldev *dev) { - struct b43_phy_n *nphy = dev->phy.n; - enum ieee80211_band band; - u16 tmp; + struct b43_phy *phy = &dev->phy; + unsigned int i; - if (!enable) { - nphy->rfctrl_intc1_save = b43_phy_read(dev, - B43_NPHY_RFCTL_INTC1); - nphy->rfctrl_intc2_save = b43_phy_read(dev, - B43_NPHY_RFCTL_INTC2); - band = b43_current_band(dev->wl); - if (dev->phy.rev >= 3) { - if (band == IEEE80211_BAND_5GHZ) - tmp = 0x600; - else - tmp = 0x480; - } else { - if (band == IEEE80211_BAND_5GHZ) - tmp = 0x180; - else - tmp = 0x120; - } - b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, tmp); - b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, tmp); - } else { - b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, - nphy->rfctrl_intc1_save); - b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, - nphy->rfctrl_intc2_save); - } -} + b43_phy_set(dev, B43_NPHY_IQFLIP, + B43_NPHY_IQFLIP_ADC1 | B43_NPHY_IQFLIP_ADC2); + if (1 /* FIXME band is 2.4GHz */) { + b43_phy_set(dev, B43_NPHY_CLASSCTL, + B43_NPHY_CLASSCTL_CCKEN); + } else { + b43_phy_mask(dev, B43_NPHY_CLASSCTL, + ~B43_NPHY_CLASSCTL_CCKEN); + } + b43_radio_set(dev, B2055_C1_TX_RF_SPARE, 0x8); + b43_phy_write(dev, B43_NPHY_TXFRAMEDELAY, 8); + + /* Fixup some tables */ + b43_ntab_write(dev, B43_NTAB16(8, 0x00), 0xA); + b43_ntab_write(dev, B43_NTAB16(8, 0x10), 0xA); + b43_ntab_write(dev, B43_NTAB16(8, 0x02), 0xCDAA); + b43_ntab_write(dev, B43_NTAB16(8, 0x12), 0xCDAA); + b43_ntab_write(dev, B43_NTAB16(8, 0x08), 0); + b43_ntab_write(dev, B43_NTAB16(8, 0x18), 0); + b43_ntab_write(dev, B43_NTAB16(8, 0x07), 0x7AAB); + b43_ntab_write(dev, B43_NTAB16(8, 0x17), 0x7AAB); + b43_ntab_write(dev, B43_NTAB16(8, 0x06), 0x800); + b43_ntab_write(dev, B43_NTAB16(8, 0x16), 0x800); + + b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO1, 0x2D8); + b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP1, 0x301); + b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO2, 0x2D8); + b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, 0x301); + + //TODO set RF sequence + + /* Set narrowband clip threshold */ + b43_phy_write(dev, B43_NPHY_C1_NBCLIPTHRES, 66); + b43_phy_write(dev, B43_NPHY_C2_NBCLIPTHRES, 66); + + /* Set wideband clip 2 threshold */ + b43_phy_maskset(dev, B43_NPHY_C1_CLIPWBTHRES, + ~B43_NPHY_C1_CLIPWBTHRES_CLIP2, + 21 << B43_NPHY_C1_CLIPWBTHRES_CLIP2_SHIFT); + b43_phy_maskset(dev, B43_NPHY_C2_CLIPWBTHRES, + ~B43_NPHY_C2_CLIPWBTHRES_CLIP2, + 21 << B43_NPHY_C2_CLIPWBTHRES_CLIP2_SHIFT); + + /* Set Clip 2 detect */ + b43_phy_set(dev, B43_NPHY_C1_CGAINI, + B43_NPHY_C1_CGAINI_CL2DETECT); + b43_phy_set(dev, B43_NPHY_C2_CGAINI, + B43_NPHY_C2_CGAINI_CL2DETECT); + + if (0 /*FIXME*/) { + /* Set dwell lengths */ + b43_phy_write(dev, B43_NPHY_CLIP1_NBDWELL_LEN, 43); + b43_phy_write(dev, B43_NPHY_CLIP2_NBDWELL_LEN, 43); + b43_phy_write(dev, B43_NPHY_W1CLIP1_DWELL_LEN, 9); + b43_phy_write(dev, B43_NPHY_W1CLIP2_DWELL_LEN, 9); + + /* Set gain backoff */ + b43_phy_maskset(dev, B43_NPHY_C1_CGAINI, + ~B43_NPHY_C1_CGAINI_GAINBKOFF, + 1 << B43_NPHY_C1_CGAINI_GAINBKOFF_SHIFT); + b43_phy_maskset(dev, B43_NPHY_C2_CGAINI, + ~B43_NPHY_C2_CGAINI_GAINBKOFF, + 1 << B43_NPHY_C2_CGAINI_GAINBKOFF_SHIFT); -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxLpFbw */ -static void b43_nphy_tx_lp_fbw(struct b43_wldev *dev) -{ - struct b43_phy_n *nphy = dev->phy.n; - u16 tmp; - enum ieee80211_band band = b43_current_band(dev->wl); - bool ipa = (nphy->ipa2g_on && band == IEEE80211_BAND_2GHZ) || - (nphy->ipa5g_on && band == IEEE80211_BAND_5GHZ); - - if (dev->phy.rev >= 3) { - if (ipa) { - tmp = 4; - b43_phy_write(dev, B43_NPHY_TXF_40CO_B32S2, - (((((tmp << 3) | tmp) << 3) | tmp) << 3) | tmp); - } + /* Set HPVGA2 index */ + b43_phy_maskset(dev, B43_NPHY_C1_INITGAIN, + ~B43_NPHY_C1_INITGAIN_HPVGA2, + 6 << B43_NPHY_C1_INITGAIN_HPVGA2_SHIFT); + b43_phy_maskset(dev, B43_NPHY_C2_INITGAIN, + ~B43_NPHY_C2_INITGAIN_HPVGA2, + 6 << B43_NPHY_C2_INITGAIN_HPVGA2_SHIFT); - tmp = 1; - b43_phy_write(dev, B43_NPHY_TXF_40CO_B1S2, - (((((tmp << 3) | tmp) << 3) | tmp) << 3) | tmp); + //FIXME verify that the specs really mean to use autoinc here. + for (i = 0; i < 3; i++) + b43_ntab_write(dev, B43_NTAB16(7, 0x106) + i, 0x673); } -} -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/BmacPhyClkFgc */ -static void b43_nphy_bmac_clock_fgc(struct b43_wldev *dev, bool force) -{ - u32 tmslow; + /* Set minimum gain value */ + b43_phy_maskset(dev, B43_NPHY_C1_MINMAX_GAIN, + ~B43_NPHY_C1_MINGAIN, + 23 << B43_NPHY_C1_MINGAIN_SHIFT); + b43_phy_maskset(dev, B43_NPHY_C2_MINMAX_GAIN, + ~B43_NPHY_C2_MINGAIN, + 23 << B43_NPHY_C2_MINGAIN_SHIFT); - if (dev->phy.type != B43_PHYTYPE_N) - return; + if (phy->rev < 2) { + b43_phy_mask(dev, B43_NPHY_SCRAM_SIGCTL, + ~B43_NPHY_SCRAM_SIGCTL_SCM); + } - tmslow = ssb_read32(dev->dev, SSB_TMSLOW); - if (force) - tmslow |= SSB_TMSLOW_FGC; - else - tmslow &= ~SSB_TMSLOW_FGC; - ssb_write32(dev->dev, SSB_TMSLOW, tmslow); + /* Set phase track alpha and beta */ + b43_phy_write(dev, B43_NPHY_PHASETR_A0, 0x125); + b43_phy_write(dev, B43_NPHY_PHASETR_A1, 0x1B3); + b43_phy_write(dev, B43_NPHY_PHASETR_A2, 0x105); + b43_phy_write(dev, B43_NPHY_PHASETR_B0, 0x16E); + b43_phy_write(dev, B43_NPHY_PHASETR_B1, 0xCD); + b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x20); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CCA */ static void b43_nphy_reset_cca(struct b43_wldev *dev) { u16 bbcfg; - b43_nphy_bmac_clock_fgc(dev, 1); + ssb_write32(dev->dev, SSB_TMSLOW, + ssb_read32(dev->dev, SSB_TMSLOW) | SSB_TMSLOW_FGC); bbcfg = b43_phy_read(dev, B43_NPHY_BBCFG); - b43_phy_write(dev, B43_NPHY_BBCFG, bbcfg | B43_NPHY_BBCFG_RSTCCA); - udelay(1); - b43_phy_write(dev, B43_NPHY_BBCFG, bbcfg & ~B43_NPHY_BBCFG_RSTCCA); - b43_nphy_bmac_clock_fgc(dev, 0); - b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX); -} - -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/MIMOConfig */ -static void b43_nphy_update_mimo_config(struct b43_wldev *dev, s32 preamble) -{ - u16 mimocfg = b43_phy_read(dev, B43_NPHY_MIMOCFG); - - mimocfg |= B43_NPHY_MIMOCFG_AUTO; - if (preamble == 1) - mimocfg |= B43_NPHY_MIMOCFG_GFMIX; - else - mimocfg &= ~B43_NPHY_MIMOCFG_GFMIX; - - b43_phy_write(dev, B43_NPHY_MIMOCFG, mimocfg); + b43_phy_set(dev, B43_NPHY_BBCFG, B43_NPHY_BBCFG_RSTCCA); + b43_phy_write(dev, B43_NPHY_BBCFG, + bbcfg & ~B43_NPHY_BBCFG_RSTCCA); + ssb_write32(dev->dev, SSB_TMSLOW, + ssb_read32(dev->dev, SSB_TMSLOW) & ~SSB_TMSLOW_FGC); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/Chains */ -static void b43_nphy_update_txrx_chain(struct b43_wldev *dev) -{ - struct b43_phy_n *nphy = dev->phy.n; - - bool override = false; - u16 chain = 0x33; - - if (nphy->txrx_chain == 0) { - chain = 0x11; - override = true; - } else if (nphy->txrx_chain == 1) { - chain = 0x22; - override = true; - } - - b43_phy_maskset(dev, B43_NPHY_RFSEQCA, - ~(B43_NPHY_RFSEQCA_TXEN | B43_NPHY_RFSEQCA_RXEN), - chain); - - if (override) - b43_phy_set(dev, B43_NPHY_RFSEQMODE, - B43_NPHY_RFSEQMODE_CAOVER); - else - b43_phy_mask(dev, B43_NPHY_RFSEQMODE, - ~B43_NPHY_RFSEQMODE_CAOVER); -} +enum b43_nphy_rf_sequence { + B43_RFSEQ_RX2TX, + B43_RFSEQ_TX2RX, + B43_RFSEQ_RESET2RX, + B43_RFSEQ_UPDATE_GAINH, + B43_RFSEQ_UPDATE_GAINL, + B43_RFSEQ_UPDATE_GAINU, +}; -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxIqEst */ -static void b43_nphy_rx_iq_est(struct b43_wldev *dev, struct nphy_iq_est *est, - u16 samps, u8 time, bool wait) +static void b43_nphy_force_rf_sequence(struct b43_wldev *dev, + enum b43_nphy_rf_sequence seq) { + static const u16 trigger[] = { + [B43_RFSEQ_RX2TX] = B43_NPHY_RFSEQTR_RX2TX, + [B43_RFSEQ_TX2RX] = B43_NPHY_RFSEQTR_TX2RX, + [B43_RFSEQ_RESET2RX] = B43_NPHY_RFSEQTR_RST2RX, + [B43_RFSEQ_UPDATE_GAINH] = B43_NPHY_RFSEQTR_UPGH, + [B43_RFSEQ_UPDATE_GAINL] = B43_NPHY_RFSEQTR_UPGL, + [B43_RFSEQ_UPDATE_GAINU] = B43_NPHY_RFSEQTR_UPGU, + }; int i; - u16 tmp; - - b43_phy_write(dev, B43_NPHY_IQEST_SAMCNT, samps); - b43_phy_maskset(dev, B43_NPHY_IQEST_WT, ~B43_NPHY_IQEST_WT_VAL, time); - if (wait) - b43_phy_set(dev, B43_NPHY_IQEST_CMD, B43_NPHY_IQEST_CMD_MODE); - else - b43_phy_mask(dev, B43_NPHY_IQEST_CMD, ~B43_NPHY_IQEST_CMD_MODE); - - b43_phy_set(dev, B43_NPHY_IQEST_CMD, B43_NPHY_IQEST_CMD_START); - - for (i = 1000; i; i--) { - tmp = b43_phy_read(dev, B43_NPHY_IQEST_CMD); - if (!(tmp & B43_NPHY_IQEST_CMD_START)) { - est->i0_pwr = (b43_phy_read(dev, B43_NPHY_IQEST_IPACC_HI0) << 16) | - b43_phy_read(dev, B43_NPHY_IQEST_IPACC_LO0); - est->q0_pwr = (b43_phy_read(dev, B43_NPHY_IQEST_QPACC_HI0) << 16) | - b43_phy_read(dev, B43_NPHY_IQEST_QPACC_LO0); - est->iq0_prod = (b43_phy_read(dev, B43_NPHY_IQEST_IQACC_HI0) << 16) | - b43_phy_read(dev, B43_NPHY_IQEST_IQACC_LO0); - - est->i1_pwr = (b43_phy_read(dev, B43_NPHY_IQEST_IPACC_HI1) << 16) | - b43_phy_read(dev, B43_NPHY_IQEST_IPACC_LO1); - est->q1_pwr = (b43_phy_read(dev, B43_NPHY_IQEST_QPACC_HI1) << 16) | - b43_phy_read(dev, B43_NPHY_IQEST_QPACC_LO1); - est->iq1_prod = (b43_phy_read(dev, B43_NPHY_IQEST_IQACC_HI1) << 16) | - b43_phy_read(dev, B43_NPHY_IQEST_IQACC_LO1); - return; - } - udelay(10); - } - memset(est, 0, sizeof(*est)); -} - -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxIqCoeffs */ -static void b43_nphy_rx_iq_coeffs(struct b43_wldev *dev, bool write, - struct b43_phy_n_iq_comp *pcomp) -{ - if (write) { - b43_phy_write(dev, B43_NPHY_C1_RXIQ_COMPA0, pcomp->a0); - b43_phy_write(dev, B43_NPHY_C1_RXIQ_COMPB0, pcomp->b0); - b43_phy_write(dev, B43_NPHY_C2_RXIQ_COMPA1, pcomp->a1); - b43_phy_write(dev, B43_NPHY_C2_RXIQ_COMPB1, pcomp->b1); - } else { - pcomp->a0 = b43_phy_read(dev, B43_NPHY_C1_RXIQ_COMPA0); - pcomp->b0 = b43_phy_read(dev, B43_NPHY_C1_RXIQ_COMPB0); - pcomp->a1 = b43_phy_read(dev, B43_NPHY_C2_RXIQ_COMPA1); - pcomp->b1 = b43_phy_read(dev, B43_NPHY_C2_RXIQ_COMPB1); - } -} -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxCalPhyCleanup */ -static void b43_nphy_rx_cal_phy_cleanup(struct b43_wldev *dev, u8 core) -{ - u16 *regs = dev->phy.n->tx_rx_cal_phy_saveregs; + B43_WARN_ON(seq >= ARRAY_SIZE(trigger)); - b43_phy_write(dev, B43_NPHY_RFSEQCA, regs[0]); - if (core == 0) { - b43_phy_write(dev, B43_NPHY_AFECTL_C1, regs[1]); - b43_phy_write(dev, B43_NPHY_AFECTL_OVER1, regs[2]); - } else { - b43_phy_write(dev, B43_NPHY_AFECTL_C2, regs[1]); - b43_phy_write(dev, B43_NPHY_AFECTL_OVER, regs[2]); + b43_phy_set(dev, B43_NPHY_RFSEQMODE, + B43_NPHY_RFSEQMODE_CAOVER | B43_NPHY_RFSEQMODE_TROVER); + b43_phy_set(dev, B43_NPHY_RFSEQTR, trigger[seq]); + for (i = 0; i < 200; i++) { + if (!(b43_phy_read(dev, B43_NPHY_RFSEQST) & trigger[seq])) + goto ok; + msleep(1); } - b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, regs[3]); - b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, regs[4]); - b43_phy_write(dev, B43_NPHY_RFCTL_RSSIO1, regs[5]); - b43_phy_write(dev, B43_NPHY_RFCTL_RSSIO2, regs[6]); - b43_phy_write(dev, B43_NPHY_TXF_40CO_B1S1, regs[7]); - b43_phy_write(dev, B43_NPHY_RFCTL_OVER, regs[8]); - b43_phy_write(dev, B43_NPHY_PAPD_EN0, regs[9]); - b43_phy_write(dev, B43_NPHY_PAPD_EN1, regs[10]); + b43err(dev->wl, "RF sequence status timeout\n"); +ok: + b43_phy_mask(dev, B43_NPHY_RFSEQMODE, + ~(B43_NPHY_RFSEQMODE_CAOVER | B43_NPHY_RFSEQMODE_TROVER)); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxCalPhySetup */ -static void b43_nphy_rx_cal_phy_setup(struct b43_wldev *dev, u8 core) +static void b43_nphy_bphy_init(struct b43_wldev *dev) { - u8 rxval, txval; - u16 *regs = dev->phy.n->tx_rx_cal_phy_saveregs; - - regs[0] = b43_phy_read(dev, B43_NPHY_RFSEQCA); - if (core == 0) { - regs[1] = b43_phy_read(dev, B43_NPHY_AFECTL_C1); - regs[2] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER1); - } else { - regs[1] = b43_phy_read(dev, B43_NPHY_AFECTL_C2); - regs[2] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER); - } - regs[3] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC1); - regs[4] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC2); - regs[5] = b43_phy_read(dev, B43_NPHY_RFCTL_RSSIO1); - regs[6] = b43_phy_read(dev, B43_NPHY_RFCTL_RSSIO2); - regs[7] = b43_phy_read(dev, B43_NPHY_TXF_40CO_B1S1); - regs[8] = b43_phy_read(dev, B43_NPHY_RFCTL_OVER); - regs[9] = b43_phy_read(dev, B43_NPHY_PAPD_EN0); - regs[10] = b43_phy_read(dev, B43_NPHY_PAPD_EN1); - - b43_phy_mask(dev, B43_NPHY_PAPD_EN0, ~0x0001); - b43_phy_mask(dev, B43_NPHY_PAPD_EN1, ~0x0001); - - b43_phy_maskset(dev, B43_NPHY_RFSEQCA, (u16)~B43_NPHY_RFSEQCA_RXDIS, - ((1 - core) << B43_NPHY_RFSEQCA_RXDIS_SHIFT)); - b43_phy_maskset(dev, B43_NPHY_RFSEQCA, ~B43_NPHY_RFSEQCA_TXEN, - ((1 - core) << B43_NPHY_RFSEQCA_TXEN_SHIFT)); - b43_phy_maskset(dev, B43_NPHY_RFSEQCA, ~B43_NPHY_RFSEQCA_RXEN, - (core << B43_NPHY_RFSEQCA_RXEN_SHIFT)); - b43_phy_maskset(dev, B43_NPHY_RFSEQCA, ~B43_NPHY_RFSEQCA_TXDIS, - (core << B43_NPHY_RFSEQCA_TXDIS_SHIFT)); - - if (core == 0) { - b43_phy_mask(dev, B43_NPHY_AFECTL_C1, ~0x0007); - b43_phy_set(dev, B43_NPHY_AFECTL_OVER1, 0x0007); - } else { - b43_phy_mask(dev, B43_NPHY_AFECTL_C2, ~0x0007); - b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x0007); - } - - b43_nphy_rf_control_intc_override(dev, 2, 0, 3); - b43_nphy_rf_control_override(dev, 8, 0, 3, false); - b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RX2TX); + unsigned int i; + u16 val; - if (core == 0) { - rxval = 1; - txval = 8; - } else { - rxval = 4; - txval = 2; + val = 0x1E1F; + for (i = 0; i < 14; i++) { + b43_phy_write(dev, B43_PHY_N_BMODE(0x88 + i), val); + val -= 0x202; } - b43_nphy_rf_control_intc_override(dev, 1, rxval, (core + 1)); - b43_nphy_rf_control_intc_override(dev, 1, txval, (2 - core)); -} - -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CalcRxIqComp */ -static void b43_nphy_calc_rx_iq_comp(struct b43_wldev *dev, u8 mask) -{ - int i; - s32 iq; - u32 ii; - u32 qq; - int iq_nbits, qq_nbits; - int arsh, brsh; - u16 tmp, a, b; - - struct nphy_iq_est est; - struct b43_phy_n_iq_comp old; - struct b43_phy_n_iq_comp new = { }; - bool error = false; - - if (mask == 0) - return; - - b43_nphy_rx_iq_coeffs(dev, false, &old); - b43_nphy_rx_iq_coeffs(dev, true, &new); - b43_nphy_rx_iq_est(dev, &est, 0x4000, 32, false); - new = old; - - for (i = 0; i < 2; i++) { - if (i == 0 && (mask & 1)) { - iq = est.iq0_prod; - ii = est.i0_pwr; - qq = est.q0_pwr; - } else if (i == 1 && (mask & 2)) { - iq = est.iq1_prod; - ii = est.i1_pwr; - qq = est.q1_pwr; - } else { - B43_WARN_ON(1); - continue; - } - - if (ii + qq < 2) { - error = true; - break; - } - - iq_nbits = fls(abs(iq)); - qq_nbits = fls(qq); - - arsh = iq_nbits - 20; - if (arsh >= 0) { - a = -((iq << (30 - iq_nbits)) + (ii >> (1 + arsh))); - tmp = ii >> arsh; - } else { - a = -((iq << (30 - iq_nbits)) + (ii << (-1 - arsh))); - tmp = ii << -arsh; - } - if (tmp == 0) { - error = true; - break; - } - a /= tmp; - - brsh = qq_nbits - 11; - if (brsh >= 0) { - b = (qq << (31 - qq_nbits)); - tmp = ii >> brsh; - } else { - b = (qq << (31 - qq_nbits)); - tmp = ii << -brsh; - } - if (tmp == 0) { - error = true; - break; - } - b = int_sqrt(b / tmp - a * a) - (1 << 10); - - if (i == 0 && (mask & 0x1)) { - if (dev->phy.rev >= 3) { - new.a0 = a & 0x3FF; - new.b0 = b & 0x3FF; - } else { - new.a0 = b & 0x3FF; - new.b0 = a & 0x3FF; - } - } else if (i == 1 && (mask & 0x2)) { - if (dev->phy.rev >= 3) { - new.a1 = a & 0x3FF; - new.b1 = b & 0x3FF; - } else { - new.a1 = b & 0x3FF; - new.b1 = a & 0x3FF; - } - } + val = 0x3E3F; + for (i = 0; i < 16; i++) { + b43_phy_write(dev, B43_PHY_N_BMODE(0x97 + i), val); + val -= 0x202; } - - if (error) - new = old; - - b43_nphy_rx_iq_coeffs(dev, true, &new); -} - -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxIqWar */ -static void b43_nphy_tx_iq_workaround(struct b43_wldev *dev) -{ - u16 array[4]; - int i; - - b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x3C50); - for (i = 0; i < 4; i++) - array[i] = b43_phy_read(dev, B43_NPHY_TABLE_DATALO); - - b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_NPHY_TXIQW0, array[0]); - b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_NPHY_TXIQW1, array[1]); - b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_NPHY_TXIQW2, array[2]); - b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_NPHY_TXIQW3, array[3]); -} - -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/clip-detection */ -static void b43_nphy_write_clip_detection(struct b43_wldev *dev, u16 *clip_st) -{ - b43_phy_write(dev, B43_NPHY_C1_CLIP1THRES, clip_st[0]); - b43_phy_write(dev, B43_NPHY_C2_CLIP1THRES, clip_st[1]); -} - -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/clip-detection */ -static void b43_nphy_read_clip_detection(struct b43_wldev *dev, u16 *clip_st) -{ - clip_st[0] = b43_phy_read(dev, B43_NPHY_C1_CLIP1THRES); - clip_st[1] = b43_phy_read(dev, B43_NPHY_C2_CLIP1THRES); + b43_phy_write(dev, B43_PHY_N_BMODE(0x38), 0x668); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/classifier */ -static u16 b43_nphy_classifier(struct b43_wldev *dev, u16 mask, u16 val) +/* RSSI Calibration */ +static void b43_nphy_rssi_cal(struct b43_wldev *dev, u8 type) { - u16 tmp; - - if (dev->dev->id.revision == 16) - b43_mac_suspend(dev); - - tmp = b43_phy_read(dev, B43_NPHY_CLASSCTL); - tmp &= (B43_NPHY_CLASSCTL_CCKEN | B43_NPHY_CLASSCTL_OFDMEN | - B43_NPHY_CLASSCTL_WAITEDEN); - tmp &= ~mask; - tmp |= (val & mask); - b43_phy_maskset(dev, B43_NPHY_CLASSCTL, 0xFFF8, tmp); - - if (dev->dev->id.revision == 16) - b43_mac_enable(dev); - - return tmp; + //TODO } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/carriersearch */ -static void b43_nphy_stay_in_carrier_search(struct b43_wldev *dev, bool enable) +int b43_phy_initn(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; - struct b43_phy_n *nphy = phy->n; - - if (enable) { - u16 clip[] = { 0xFFFF, 0xFFFF }; - if (nphy->deaf_count++ == 0) { - nphy->classifier_state = b43_nphy_classifier(dev, 0, 0); - b43_nphy_classifier(dev, 0x7, 0); - b43_nphy_read_clip_detection(dev, nphy->clip_state); - b43_nphy_write_clip_detection(dev, clip); - } - b43_nphy_reset_cca(dev); - } else { - if (--nphy->deaf_count == 0) { - b43_nphy_classifier(dev, 0x7, nphy->classifier_state); - b43_nphy_write_clip_detection(dev, nphy->clip_state); - } - } -} - -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/stop-playback */ -static void b43_nphy_stop_playback(struct b43_wldev *dev) -{ - struct b43_phy_n *nphy = dev->phy.n; u16 tmp; - if (nphy->hang_avoid) - b43_nphy_stay_in_carrier_search(dev, 1); - - tmp = b43_phy_read(dev, B43_NPHY_SAMP_STAT); - if (tmp & 0x1) - b43_phy_set(dev, B43_NPHY_SAMP_CMD, B43_NPHY_SAMP_CMD_STOP); - else if (tmp & 0x2) - b43_phy_mask(dev, B43_NPHY_IQLOCAL_CMDGCTL, (u16)~0x8000); - - b43_phy_mask(dev, B43_NPHY_SAMP_CMD, ~0x0004); - - if (nphy->bb_mult_save & 0x80000000) { - tmp = nphy->bb_mult_save & 0xFFFF; - b43_ntab_write(dev, B43_NTAB16(15, 87), tmp); - nphy->bb_mult_save = 0; - } - - if (nphy->hang_avoid) - b43_nphy_stay_in_carrier_search(dev, 0); -} - -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SpurWar */ -static void b43_nphy_spur_workaround(struct b43_wldev *dev) -{ - struct b43_phy_n *nphy = dev->phy.n; - - unsigned int channel; - int tone[2] = { 57, 58 }; - u32 noise[2] = { 0x3FF, 0x3FF }; - - B43_WARN_ON(dev->phy.rev < 3); - - if (nphy->hang_avoid) - b43_nphy_stay_in_carrier_search(dev, 1); - - /* FIXME: channel = radio_chanspec */ - - if (nphy->gband_spurwar_en) { - /* TODO: N PHY Adjust Analog Pfbw (7) */ - if (channel == 11 && dev->phy.is_40mhz) - ; /* TODO: N PHY Adjust Min Noise Var(2, tone, noise)*/ - else - ; /* TODO: N PHY Adjust Min Noise Var(0, NULL, NULL)*/ - /* TODO: N PHY Adjust CRS Min Power (0x1E) */ - } - - if (nphy->aband_spurwar_en) { - if (channel == 54) { - tone[0] = 0x20; - noise[0] = 0x25F; - } else if (channel == 38 || channel == 102 || channel == 118) { - if (0 /* FIXME */) { - tone[0] = 0x20; - noise[0] = 0x21F; - } else { - tone[0] = 0; - noise[0] = 0; - } - } else if (channel == 134) { - tone[0] = 0x20; - noise[0] = 0x21F; - } else if (channel == 151) { - tone[0] = 0x10; - noise[0] = 0x23F; - } else if (channel == 153 || channel == 161) { - tone[0] = 0x30; - noise[0] = 0x23F; - } else { - tone[0] = 0; - noise[0] = 0; - } - - if (!tone[0] && !noise[0]) - ; /* TODO: N PHY Adjust Min Noise Var(1, tone, noise)*/ - else - ; /* TODO: N PHY Adjust Min Noise Var(0, NULL, NULL)*/ - } - - if (nphy->hang_avoid) - b43_nphy_stay_in_carrier_search(dev, 0); -} - -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/WorkaroundsGainCtrl */ -static void b43_nphy_gain_crtl_workarounds(struct b43_wldev *dev) -{ - struct b43_phy_n *nphy = dev->phy.n; - u8 i, j; - u8 code; - - /* TODO: for PHY >= 3 - s8 *lna1_gain, *lna2_gain; - u8 *gain_db, *gain_bits; - u16 *rfseq_init; - u8 lpf_gain[6] = { 0x00, 0x06, 0x0C, 0x12, 0x12, 0x12 }; - u8 lpf_bits[6] = { 0, 1, 2, 3, 3, 3 }; - */ - - u8 rfseq_events[3] = { 6, 8, 7 }; - u8 rfseq_delays[3] = { 10, 30, 1 }; - - if (dev->phy.rev >= 3) { - /* TODO */ - } else { - /* Set Clip 2 detect */ - b43_phy_set(dev, B43_NPHY_C1_CGAINI, - B43_NPHY_C1_CGAINI_CL2DETECT); - b43_phy_set(dev, B43_NPHY_C2_CGAINI, - B43_NPHY_C2_CGAINI_CL2DETECT); - - /* Set narrowband clip threshold */ - b43_phy_set(dev, B43_NPHY_C1_NBCLIPTHRES, 0x84); - b43_phy_set(dev, B43_NPHY_C2_NBCLIPTHRES, 0x84); - - if (!dev->phy.is_40mhz) { - /* Set dwell lengths */ - b43_phy_set(dev, B43_NPHY_CLIP1_NBDWELL_LEN, 0x002B); - b43_phy_set(dev, B43_NPHY_CLIP2_NBDWELL_LEN, 0x002B); - b43_phy_set(dev, B43_NPHY_W1CLIP1_DWELL_LEN, 0x0009); - b43_phy_set(dev, B43_NPHY_W1CLIP2_DWELL_LEN, 0x0009); - } - - /* Set wideband clip 2 threshold */ - b43_phy_maskset(dev, B43_NPHY_C1_CLIPWBTHRES, - ~B43_NPHY_C1_CLIPWBTHRES_CLIP2, - 21); - b43_phy_maskset(dev, B43_NPHY_C2_CLIPWBTHRES, - ~B43_NPHY_C2_CLIPWBTHRES_CLIP2, - 21); - - if (!dev->phy.is_40mhz) { - b43_phy_maskset(dev, B43_NPHY_C1_CGAINI, - ~B43_NPHY_C1_CGAINI_GAINBKOFF, 0x1); - b43_phy_maskset(dev, B43_NPHY_C2_CGAINI, - ~B43_NPHY_C2_CGAINI_GAINBKOFF, 0x1); - b43_phy_maskset(dev, B43_NPHY_C1_CCK_CGAINI, - ~B43_NPHY_C1_CCK_CGAINI_GAINBKOFF, 0x1); - b43_phy_maskset(dev, B43_NPHY_C2_CCK_CGAINI, - ~B43_NPHY_C2_CCK_CGAINI_GAINBKOFF, 0x1); - } - - b43_phy_set(dev, B43_NPHY_CCK_SHIFTB_REF, 0x809C); - - if (nphy->gain_boost) { - if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ && - dev->phy.is_40mhz) - code = 4; - else - code = 5; - } else { - code = dev->phy.is_40mhz ? 6 : 7; - } - - /* Set HPVGA2 index */ - b43_phy_maskset(dev, B43_NPHY_C1_INITGAIN, - ~B43_NPHY_C1_INITGAIN_HPVGA2, - code << B43_NPHY_C1_INITGAIN_HPVGA2_SHIFT); - b43_phy_maskset(dev, B43_NPHY_C2_INITGAIN, - ~B43_NPHY_C2_INITGAIN_HPVGA2, - code << B43_NPHY_C2_INITGAIN_HPVGA2_SHIFT); - - b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x1D06); - b43_phy_write(dev, B43_NPHY_TABLE_DATALO, - (code << 8 | 0x7C)); - b43_phy_write(dev, B43_NPHY_TABLE_DATALO, - (code << 8 | 0x7C)); - - /* TODO: b43_nphy_adjust_lna_gain_table(dev); */ - - if (nphy->elna_gain_config) { - b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x0808); - b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x0); - b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1); - b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1); - b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1); - - b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x0C08); - b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x0); - b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1); - b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1); - b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1); - - b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x1D06); - b43_phy_write(dev, B43_NPHY_TABLE_DATALO, - (code << 8 | 0x74)); - b43_phy_write(dev, B43_NPHY_TABLE_DATALO, - (code << 8 | 0x74)); - } - - if (dev->phy.rev == 2) { - for (i = 0; i < 4; i++) { - b43_phy_write(dev, B43_NPHY_TABLE_ADDR, - (0x0400 * i) + 0x0020); - for (j = 0; j < 21; j++) - b43_phy_write(dev, - B43_NPHY_TABLE_DATALO, 3 * j); - } - - b43_nphy_set_rf_sequence(dev, 5, - rfseq_events, rfseq_delays, 3); - b43_phy_maskset(dev, B43_NPHY_OVER_DGAIN1, - (u16)~B43_NPHY_OVER_DGAIN_CCKDGECV, - 0x5A << B43_NPHY_OVER_DGAIN_CCKDGECV_SHIFT); - - if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) - b43_phy_maskset(dev, B43_PHY_N(0xC5D), - 0xFF80, 4); - } - } -} - -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/Workarounds */ -static void b43_nphy_workarounds(struct b43_wldev *dev) -{ - struct ssb_bus *bus = dev->dev->bus; - struct b43_phy *phy = &dev->phy; - struct b43_phy_n *nphy = phy->n; - - u8 events1[7] = { 0x0, 0x1, 0x2, 0x8, 0x4, 0x5, 0x3 }; - u8 delays1[7] = { 0x8, 0x6, 0x6, 0x2, 0x4, 0x3C, 0x1 }; - - u8 events2[7] = { 0x0, 0x3, 0x5, 0x4, 0x2, 0x1, 0x8 }; - u8 delays2[7] = { 0x8, 0x6, 0x2, 0x4, 0x4, 0x6, 0x1 }; - - if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) - b43_nphy_classifier(dev, 1, 0); - else - b43_nphy_classifier(dev, 1, 1); - - if (nphy->hang_avoid) - b43_nphy_stay_in_carrier_search(dev, 1); - - b43_phy_set(dev, B43_NPHY_IQFLIP, - B43_NPHY_IQFLIP_ADC1 | B43_NPHY_IQFLIP_ADC2); - - if (dev->phy.rev >= 3) { - /* TODO */ - } else { - if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ && - nphy->band5g_pwrgain) { - b43_radio_mask(dev, B2055_C1_TX_RF_SPARE, ~0x8); - b43_radio_mask(dev, B2055_C2_TX_RF_SPARE, ~0x8); - } else { - b43_radio_set(dev, B2055_C1_TX_RF_SPARE, 0x8); - b43_radio_set(dev, B2055_C2_TX_RF_SPARE, 0x8); - } - - /* TODO: convert to b43_ntab_write? */ - b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2000); - b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x000A); - b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2010); - b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x000A); - b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2002); - b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0xCDAA); - b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2012); - b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0xCDAA); - - if (dev->phy.rev < 2) { - b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2008); - b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x0000); - b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2018); - b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x0000); - b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2007); - b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x7AAB); - b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2017); - b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x7AAB); - b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2006); - b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x0800); - b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2016); - b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x0800); - } - - b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO1, 0x2D8); - b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP1, 0x301); - b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO2, 0x2D8); - b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, 0x301); - - if (bus->sprom.boardflags2_lo & 0x100 && - bus->boardinfo.type == 0x8B) { - delays1[0] = 0x1; - delays1[5] = 0x14; - } - b43_nphy_set_rf_sequence(dev, 0, events1, delays1, 7); - b43_nphy_set_rf_sequence(dev, 1, events2, delays2, 7); - - b43_nphy_gain_crtl_workarounds(dev); + //TODO: Spectral management + b43_nphy_tables_init(dev); - if (dev->phy.rev < 2) { - if (b43_phy_read(dev, B43_NPHY_RXCTL) & 0x2) - ; /*TODO: b43_mhf(dev, 2, 0x0010, 0x0010, 3);*/ - } else if (dev->phy.rev == 2) { - b43_phy_write(dev, B43_NPHY_CRSCHECK2, 0); - b43_phy_write(dev, B43_NPHY_CRSCHECK3, 0); - } + /* Clear all overrides */ + b43_phy_write(dev, B43_NPHY_RFCTL_OVER, 0); + b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, 0); + b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, 0); + b43_phy_write(dev, B43_NPHY_RFCTL_INTC3, 0); + b43_phy_write(dev, B43_NPHY_RFCTL_INTC4, 0); + b43_phy_mask(dev, B43_NPHY_RFSEQMODE, + ~(B43_NPHY_RFSEQMODE_CAOVER | + B43_NPHY_RFSEQMODE_TROVER)); + b43_phy_write(dev, B43_NPHY_AFECTL_OVER, 0); - if (dev->phy.rev < 2) - b43_phy_mask(dev, B43_NPHY_SCRAM_SIGCTL, - ~B43_NPHY_SCRAM_SIGCTL_SCM); - - /* Set phase track alpha and beta */ - b43_phy_write(dev, B43_NPHY_PHASETR_A0, 0x125); - b43_phy_write(dev, B43_NPHY_PHASETR_A1, 0x1B3); - b43_phy_write(dev, B43_NPHY_PHASETR_A2, 0x105); - b43_phy_write(dev, B43_NPHY_PHASETR_B0, 0x16E); - b43_phy_write(dev, B43_NPHY_PHASETR_B1, 0xCD); - b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x20); - - b43_phy_mask(dev, B43_NPHY_PIL_DW1, - (u16)~B43_NPHY_PIL_DW_64QAM); - b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B1, 0xB5); - b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B2, 0xA4); - b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B3, 0x00); - - if (dev->phy.rev == 2) - b43_phy_set(dev, B43_NPHY_FINERX2_CGC, - B43_NPHY_FINERX2_CGC_DECGC); - } + tmp = (phy->rev < 2) ? 64 : 59; + b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3, + ~B43_NPHY_BPHY_CTL3_SCALE, + tmp << B43_NPHY_BPHY_CTL3_SCALE_SHIFT); - if (nphy->hang_avoid) - b43_nphy_stay_in_carrier_search(dev, 0); -} + b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_20M, 0x20); + b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_40M, 0x20); -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/LoadSampleTable */ -static int b43_nphy_load_samples(struct b43_wldev *dev, - struct b43_c32 *samples, u16 len) { - struct b43_phy_n *nphy = dev->phy.n; - u16 i; - u32 *data; + b43_phy_write(dev, B43_NPHY_TXREALFD, 184); + b43_phy_write(dev, B43_NPHY_MIMO_CRSTXEXT, 200); + b43_phy_write(dev, B43_NPHY_PLOAD_CSENSE_EXTLEN, 80); + b43_phy_write(dev, B43_NPHY_C2_BCLIPBKOFF, 511); - data = kzalloc(len * sizeof(u32), GFP_KERNEL); - if (!data) { - b43err(dev->wl, "allocation for samples loading failed\n"); - return -ENOMEM; - } - if (nphy->hang_avoid) - b43_nphy_stay_in_carrier_search(dev, 1); + //TODO MIMO-Config + //TODO Update TX/RX chain - for (i = 0; i < len; i++) { - data[i] = (samples[i].i & 0x3FF << 10); - data[i] |= samples[i].q & 0x3FF; + if (phy->rev < 2) { + b43_phy_write(dev, B43_NPHY_DUP40_GFBL, 0xAA8); + b43_phy_write(dev, B43_NPHY_DUP40_BL, 0x9A4); } - b43_ntab_write_bulk(dev, B43_NTAB32(17, 0), len, data); - - kfree(data); - if (nphy->hang_avoid) - b43_nphy_stay_in_carrier_search(dev, 0); - return 0; -} - -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/GenLoadSamples */ -static u16 b43_nphy_gen_load_samples(struct b43_wldev *dev, u32 freq, u16 max, - bool test) -{ - int i; - u16 bw, len, rot, angle; - struct b43_c32 *samples; - + b43_nphy_workarounds(dev); + b43_nphy_reset_cca(dev); - bw = (dev->phy.is_40mhz) ? 40 : 20; - len = bw << 3; - - if (test) { - if (b43_phy_read(dev, B43_NPHY_BBCFG) & B43_NPHY_BBCFG_RSTRX) - bw = 82; - else - bw = 80; - - if (dev->phy.is_40mhz) - bw <<= 1; - - len = bw << 1; - } - - samples = kzalloc(len * sizeof(struct b43_c32), GFP_KERNEL); - if (!samples) { - b43err(dev->wl, "allocation for samples generation failed\n"); - return 0; - } - rot = (((freq * 36) / bw) << 16) / 100; - angle = 0; - - for (i = 0; i < len; i++) { - samples[i] = b43_cordic(angle); - angle += rot; - samples[i].q = CORDIC_CONVERT(samples[i].q * max); - samples[i].i = CORDIC_CONVERT(samples[i].i * max); - } - - i = b43_nphy_load_samples(dev, samples, len); - kfree(samples); - return (i < 0) ? 0 : len; -} - -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RunSamples */ -static void b43_nphy_run_samples(struct b43_wldev *dev, u16 samps, u16 loops, - u16 wait, bool iqmode, bool dac_test) -{ - struct b43_phy_n *nphy = dev->phy.n; - int i; - u16 seq_mode; - u32 tmp; - - if (nphy->hang_avoid) - b43_nphy_stay_in_carrier_search(dev, true); - - if ((nphy->bb_mult_save & 0x80000000) == 0) { - tmp = b43_ntab_read(dev, B43_NTAB16(15, 87)); - nphy->bb_mult_save = (tmp & 0xFFFF) | 0x80000000; - } - - if (!dev->phy.is_40mhz) - tmp = 0x6464; - else - tmp = 0x4747; - b43_ntab_write(dev, B43_NTAB16(15, 87), tmp); - - if (nphy->hang_avoid) - b43_nphy_stay_in_carrier_search(dev, false); - - b43_phy_write(dev, B43_NPHY_SAMP_DEPCNT, (samps - 1)); - - if (loops != 0xFFFF) - b43_phy_write(dev, B43_NPHY_SAMP_LOOPCNT, (loops - 1)); - else - b43_phy_write(dev, B43_NPHY_SAMP_LOOPCNT, loops); - - b43_phy_write(dev, B43_NPHY_SAMP_WAITCNT, wait); - - seq_mode = b43_phy_read(dev, B43_NPHY_RFSEQMODE); - - b43_phy_set(dev, B43_NPHY_RFSEQMODE, B43_NPHY_RFSEQMODE_CAOVER); - if (iqmode) { - b43_phy_mask(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x7FFF); - b43_phy_set(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x8000); - } else { - if (dac_test) - b43_phy_write(dev, B43_NPHY_SAMP_CMD, 5); - else - b43_phy_write(dev, B43_NPHY_SAMP_CMD, 1); - } - for (i = 0; i < 100; i++) { - if (b43_phy_read(dev, B43_NPHY_RFSEQST) & 1) { - i = 0; - break; - } - udelay(10); - } - if (i) - b43err(dev->wl, "run samples timeout\n"); - - b43_phy_write(dev, B43_NPHY_RFSEQMODE, seq_mode); -} - -/* - * Transmits a known value for LO calibration - * http://bcm-v4.sipsolutions.net/802.11/PHY/N/TXTone - */ -static int b43_nphy_tx_tone(struct b43_wldev *dev, u32 freq, u16 max_val, - bool iqmode, bool dac_test) -{ - u16 samp = b43_nphy_gen_load_samples(dev, freq, max_val, dac_test); - if (samp == 0) - return -1; - b43_nphy_run_samples(dev, samp, 0xFFFF, 0, iqmode, dac_test); - return 0; -} - -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlCoefSetup */ -static void b43_nphy_tx_pwr_ctrl_coef_setup(struct b43_wldev *dev) -{ - struct b43_phy_n *nphy = dev->phy.n; - int i, j; - u32 tmp; - u32 cur_real, cur_imag, real_part, imag_part; - - u16 buffer[7]; - - if (nphy->hang_avoid) - b43_nphy_stay_in_carrier_search(dev, true); - - b43_ntab_read_bulk(dev, B43_NTAB16(15, 80), 7, buffer); - - for (i = 0; i < 2; i++) { - tmp = ((buffer[i * 2] & 0x3FF) << 10) | - (buffer[i * 2 + 1] & 0x3FF); - b43_phy_write(dev, B43_NPHY_TABLE_ADDR, - (((i + 26) << 10) | 320)); - for (j = 0; j < 128; j++) { - b43_phy_write(dev, B43_NPHY_TABLE_DATAHI, - ((tmp >> 16) & 0xFFFF)); - b43_phy_write(dev, B43_NPHY_TABLE_DATALO, - (tmp & 0xFFFF)); - } - } - - for (i = 0; i < 2; i++) { - tmp = buffer[5 + i]; - real_part = (tmp >> 8) & 0xFF; - imag_part = (tmp & 0xFF); - b43_phy_write(dev, B43_NPHY_TABLE_ADDR, - (((i + 26) << 10) | 448)); - - if (dev->phy.rev >= 3) { - cur_real = real_part; - cur_imag = imag_part; - tmp = ((cur_real & 0xFF) << 8) | (cur_imag & 0xFF); - } - - for (j = 0; j < 128; j++) { - if (dev->phy.rev < 3) { - cur_real = (real_part * loscale[j] + 128) >> 8; - cur_imag = (imag_part * loscale[j] + 128) >> 8; - tmp = ((cur_real & 0xFF) << 8) | - (cur_imag & 0xFF); - } - b43_phy_write(dev, B43_NPHY_TABLE_DATAHI, - ((tmp >> 16) & 0xFFFF)); - b43_phy_write(dev, B43_NPHY_TABLE_DATALO, - (tmp & 0xFFFF)); - } - } - - if (dev->phy.rev >= 3) { - b43_shm_write16(dev, B43_SHM_SHARED, - B43_SHM_SH_NPHY_TXPWR_INDX0, 0xFFFF); - b43_shm_write16(dev, B43_SHM_SHARED, - B43_SHM_SH_NPHY_TXPWR_INDX1, 0xFFFF); - } - - if (nphy->hang_avoid) - b43_nphy_stay_in_carrier_search(dev, false); -} - -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SetRfSeq */ -static void b43_nphy_set_rf_sequence(struct b43_wldev *dev, u8 cmd, - u8 *events, u8 *delays, u8 length) -{ - struct b43_phy_n *nphy = dev->phy.n; - u8 i; - u8 end = (dev->phy.rev >= 3) ? 0x1F : 0x0F; - u16 offset1 = cmd << 4; - u16 offset2 = offset1 + 0x80; - - if (nphy->hang_avoid) - b43_nphy_stay_in_carrier_search(dev, true); - - b43_ntab_write_bulk(dev, B43_NTAB8(7, offset1), length, events); - b43_ntab_write_bulk(dev, B43_NTAB8(7, offset2), length, delays); - - for (i = length; i < 16; i++) { - b43_ntab_write(dev, B43_NTAB8(7, offset1 + i), end); - b43_ntab_write(dev, B43_NTAB8(7, offset2 + i), 1); - } - - if (nphy->hang_avoid) - b43_nphy_stay_in_carrier_search(dev, false); -} - -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ForceRFSeq */ -static void b43_nphy_force_rf_sequence(struct b43_wldev *dev, - enum b43_nphy_rf_sequence seq) -{ - static const u16 trigger[] = { - [B43_RFSEQ_RX2TX] = B43_NPHY_RFSEQTR_RX2TX, - [B43_RFSEQ_TX2RX] = B43_NPHY_RFSEQTR_TX2RX, - [B43_RFSEQ_RESET2RX] = B43_NPHY_RFSEQTR_RST2RX, - [B43_RFSEQ_UPDATE_GAINH] = B43_NPHY_RFSEQTR_UPGH, - [B43_RFSEQ_UPDATE_GAINL] = B43_NPHY_RFSEQTR_UPGL, - [B43_RFSEQ_UPDATE_GAINU] = B43_NPHY_RFSEQTR_UPGU, - }; - int i; - u16 seq_mode = b43_phy_read(dev, B43_NPHY_RFSEQMODE); - - B43_WARN_ON(seq >= ARRAY_SIZE(trigger)); - - b43_phy_set(dev, B43_NPHY_RFSEQMODE, - B43_NPHY_RFSEQMODE_CAOVER | B43_NPHY_RFSEQMODE_TROVER); - b43_phy_set(dev, B43_NPHY_RFSEQTR, trigger[seq]); - for (i = 0; i < 200; i++) { - if (!(b43_phy_read(dev, B43_NPHY_RFSEQST) & trigger[seq])) - goto ok; - msleep(1); - } - b43err(dev->wl, "RF sequence status timeout\n"); -ok: - b43_phy_write(dev, B43_NPHY_RFSEQMODE, seq_mode); -} - -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlOverride */ -static void b43_nphy_rf_control_override(struct b43_wldev *dev, u16 field, - u16 value, u8 core, bool off) -{ - int i; - u8 index = fls(field); - u8 addr, en_addr, val_addr; - /* we expect only one bit set */ - B43_WARN_ON(field & (~(1 << (index - 1)))); - - if (dev->phy.rev >= 3) { - const struct nphy_rf_control_override_rev3 *rf_ctrl; - for (i = 0; i < 2; i++) { - if (index == 0 || index == 16) { - b43err(dev->wl, - "Unsupported RF Ctrl Override call\n"); - return; - } - - rf_ctrl = &tbl_rf_control_override_rev3[index - 1]; - en_addr = B43_PHY_N((i == 0) ? - rf_ctrl->en_addr0 : rf_ctrl->en_addr1); - val_addr = B43_PHY_N((i == 0) ? - rf_ctrl->val_addr0 : rf_ctrl->val_addr1); - - if (off) { - b43_phy_mask(dev, en_addr, ~(field)); - b43_phy_mask(dev, val_addr, - ~(rf_ctrl->val_mask)); - } else { - if (core == 0 || ((1 << core) & i) != 0) { - b43_phy_set(dev, en_addr, field); - b43_phy_maskset(dev, val_addr, - ~(rf_ctrl->val_mask), - (value << rf_ctrl->val_shift)); - } - } - } - } else { - const struct nphy_rf_control_override_rev2 *rf_ctrl; - if (off) { - b43_phy_mask(dev, B43_NPHY_RFCTL_OVER, ~(field)); - value = 0; - } else { - b43_phy_set(dev, B43_NPHY_RFCTL_OVER, field); - } - - for (i = 0; i < 2; i++) { - if (index <= 1 || index == 16) { - b43err(dev->wl, - "Unsupported RF Ctrl Override call\n"); - return; - } - - if (index == 2 || index == 10 || - (index >= 13 && index <= 15)) { - core = 1; - } - - rf_ctrl = &tbl_rf_control_override_rev2[index - 2]; - addr = B43_PHY_N((i == 0) ? - rf_ctrl->addr0 : rf_ctrl->addr1); - - if ((core & (1 << i)) != 0) - b43_phy_maskset(dev, addr, ~(rf_ctrl->bmask), - (value << rf_ctrl->shift)); - - b43_phy_set(dev, B43_NPHY_RFCTL_OVER, 0x1); - b43_phy_set(dev, B43_NPHY_RFCTL_CMD, - B43_NPHY_RFCTL_CMD_START); - udelay(1); - b43_phy_mask(dev, B43_NPHY_RFCTL_OVER, 0xFFFE); - } - } -} - -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlIntcOverride */ -static void b43_nphy_rf_control_intc_override(struct b43_wldev *dev, u8 field, - u16 value, u8 core) -{ - u8 i, j; - u16 reg, tmp, val; - - B43_WARN_ON(dev->phy.rev < 3); - B43_WARN_ON(field > 4); - - for (i = 0; i < 2; i++) { - if ((core == 1 && i == 1) || (core == 2 && !i)) - continue; - - reg = (i == 0) ? - B43_NPHY_RFCTL_INTC1 : B43_NPHY_RFCTL_INTC2; - b43_phy_mask(dev, reg, 0xFBFF); - - switch (field) { - case 0: - b43_phy_write(dev, reg, 0); - b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX); - break; - case 1: - if (!i) { - b43_phy_maskset(dev, B43_NPHY_RFCTL_INTC1, - 0xFC3F, (value << 6)); - b43_phy_maskset(dev, B43_NPHY_TXF_40CO_B1S1, - 0xFFFE, 1); - b43_phy_set(dev, B43_NPHY_RFCTL_CMD, - B43_NPHY_RFCTL_CMD_START); - for (j = 0; j < 100; j++) { - if (b43_phy_read(dev, B43_NPHY_RFCTL_CMD) & B43_NPHY_RFCTL_CMD_START) { - j = 0; - break; - } - udelay(10); - } - if (j) - b43err(dev->wl, - "intc override timeout\n"); - b43_phy_mask(dev, B43_NPHY_TXF_40CO_B1S1, - 0xFFFE); - } else { - b43_phy_maskset(dev, B43_NPHY_RFCTL_INTC2, - 0xFC3F, (value << 6)); - b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER, - 0xFFFE, 1); - b43_phy_set(dev, B43_NPHY_RFCTL_CMD, - B43_NPHY_RFCTL_CMD_RXTX); - for (j = 0; j < 100; j++) { - if (b43_phy_read(dev, B43_NPHY_RFCTL_CMD) & B43_NPHY_RFCTL_CMD_RXTX) { - j = 0; - break; - } - udelay(10); - } - if (j) - b43err(dev->wl, - "intc override timeout\n"); - b43_phy_mask(dev, B43_NPHY_RFCTL_OVER, - 0xFFFE); - } - break; - case 2: - if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) { - tmp = 0x0020; - val = value << 5; - } else { - tmp = 0x0010; - val = value << 4; - } - b43_phy_maskset(dev, reg, ~tmp, val); - break; - case 3: - if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) { - tmp = 0x0001; - val = value; - } else { - tmp = 0x0004; - val = value << 2; - } - b43_phy_maskset(dev, reg, ~tmp, val); - break; - case 4: - if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) { - tmp = 0x0002; - val = value << 1; - } else { - tmp = 0x0008; - val = value << 3; - } - b43_phy_maskset(dev, reg, ~tmp, val); - break; - } - } -} - -static void b43_nphy_bphy_init(struct b43_wldev *dev) -{ - unsigned int i; - u16 val; - - val = 0x1E1F; - for (i = 0; i < 14; i++) { - b43_phy_write(dev, B43_PHY_N_BMODE(0x88 + i), val); - val -= 0x202; - } - val = 0x3E3F; - for (i = 0; i < 16; i++) { - b43_phy_write(dev, B43_PHY_N_BMODE(0x97 + i), val); - val -= 0x202; - } - b43_phy_write(dev, B43_PHY_N_BMODE(0x38), 0x668); -} - -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ScaleOffsetRssi */ -static void b43_nphy_scale_offset_rssi(struct b43_wldev *dev, u16 scale, - s8 offset, u8 core, u8 rail, u8 type) -{ - u16 tmp; - bool core1or5 = (core == 1) || (core == 5); - bool core2or5 = (core == 2) || (core == 5); - - offset = clamp_val(offset, -32, 31); - tmp = ((scale & 0x3F) << 8) | (offset & 0x3F); - - if (core1or5 && (rail == 0) && (type == 2)) - b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_Z, tmp); - if (core1or5 && (rail == 1) && (type == 2)) - b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_Z, tmp); - if (core2or5 && (rail == 0) && (type == 2)) - b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_Z, tmp); - if (core2or5 && (rail == 1) && (type == 2)) - b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_Z, tmp); - if (core1or5 && (rail == 0) && (type == 0)) - b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_X, tmp); - if (core1or5 && (rail == 1) && (type == 0)) - b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_X, tmp); - if (core2or5 && (rail == 0) && (type == 0)) - b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_X, tmp); - if (core2or5 && (rail == 1) && (type == 0)) - b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_X, tmp); - if (core1or5 && (rail == 0) && (type == 1)) - b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_Y, tmp); - if (core1or5 && (rail == 1) && (type == 1)) - b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_Y, tmp); - if (core2or5 && (rail == 0) && (type == 1)) - b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_Y, tmp); - if (core2or5 && (rail == 1) && (type == 1)) - b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_Y, tmp); - if (core1or5 && (rail == 0) && (type == 6)) - b43_phy_write(dev, B43_NPHY_RSSIMC_0I_TBD, tmp); - if (core1or5 && (rail == 1) && (type == 6)) - b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_TBD, tmp); - if (core2or5 && (rail == 0) && (type == 6)) - b43_phy_write(dev, B43_NPHY_RSSIMC_1I_TBD, tmp); - if (core2or5 && (rail == 1) && (type == 6)) - b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_TBD, tmp); - if (core1or5 && (rail == 0) && (type == 3)) - b43_phy_write(dev, B43_NPHY_RSSIMC_0I_PWRDET, tmp); - if (core1or5 && (rail == 1) && (type == 3)) - b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_PWRDET, tmp); - if (core2or5 && (rail == 0) && (type == 3)) - b43_phy_write(dev, B43_NPHY_RSSIMC_1I_PWRDET, tmp); - if (core2or5 && (rail == 1) && (type == 3)) - b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_PWRDET, tmp); - if (core1or5 && (type == 4)) - b43_phy_write(dev, B43_NPHY_RSSIMC_0I_TSSI, tmp); - if (core2or5 && (type == 4)) - b43_phy_write(dev, B43_NPHY_RSSIMC_1I_TSSI, tmp); - if (core1or5 && (type == 5)) - b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_TSSI, tmp); - if (core2or5 && (type == 5)) - b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_TSSI, tmp); -} - -static void b43_nphy_rev2_rssi_select(struct b43_wldev *dev, u8 code, u8 type) -{ - u16 val; - - if (type < 3) - val = 0; - else if (type == 6) - val = 1; - else if (type == 3) - val = 2; - else - val = 3; - - val = (val << 12) | (val << 14); - b43_phy_maskset(dev, B43_NPHY_AFECTL_C1, 0x0FFF, val); - b43_phy_maskset(dev, B43_NPHY_AFECTL_C2, 0x0FFF, val); - - if (type < 3) { - b43_phy_maskset(dev, B43_NPHY_RFCTL_RSSIO1, 0xFFCF, - (type + 1) << 4); - b43_phy_maskset(dev, B43_NPHY_RFCTL_RSSIO2, 0xFFCF, - (type + 1) << 4); - } - - /* TODO use some definitions */ - if (code == 0) { - b43_phy_maskset(dev, B43_NPHY_AFECTL_OVER, 0xCFFF, 0); - if (type < 3) { - b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD, 0xFEC7, 0); - b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER, 0xEFDC, 0); - b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD, 0xFFFE, 0); - udelay(20); - b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER, 0xFFFE, 0); - } - } else { - b43_phy_maskset(dev, B43_NPHY_AFECTL_OVER, 0xCFFF, - 0x3000); - if (type < 3) { - b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD, - 0xFEC7, 0x0180); - b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER, - 0xEFDC, (code << 1 | 0x1021)); - b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD, 0xFFFE, 0x1); - udelay(20); - b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER, 0xFFFE, 0); - } - } -} - -static void b43_nphy_rev3_rssi_select(struct b43_wldev *dev, u8 code, u8 type) -{ - struct b43_phy_n *nphy = dev->phy.n; - u8 i; - u16 reg, val; - - if (code == 0) { - b43_phy_mask(dev, B43_NPHY_AFECTL_OVER1, 0xFDFF); - b43_phy_mask(dev, B43_NPHY_AFECTL_OVER, 0xFDFF); - b43_phy_mask(dev, B43_NPHY_AFECTL_C1, 0xFCFF); - b43_phy_mask(dev, B43_NPHY_AFECTL_C2, 0xFCFF); - b43_phy_mask(dev, B43_NPHY_TXF_40CO_B1S0, 0xFFDF); - b43_phy_mask(dev, B43_NPHY_TXF_40CO_B32S1, 0xFFDF); - b43_phy_mask(dev, B43_NPHY_RFCTL_LUT_TRSW_UP1, 0xFFC3); - b43_phy_mask(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, 0xFFC3); - } else { - for (i = 0; i < 2; i++) { - if ((code == 1 && i == 1) || (code == 2 && !i)) - continue; - - reg = (i == 0) ? - B43_NPHY_AFECTL_OVER1 : B43_NPHY_AFECTL_OVER; - b43_phy_maskset(dev, reg, 0xFDFF, 0x0200); - - if (type < 3) { - reg = (i == 0) ? - B43_NPHY_AFECTL_C1 : - B43_NPHY_AFECTL_C2; - b43_phy_maskset(dev, reg, 0xFCFF, 0); - - reg = (i == 0) ? - B43_NPHY_RFCTL_LUT_TRSW_UP1 : - B43_NPHY_RFCTL_LUT_TRSW_UP2; - b43_phy_maskset(dev, reg, 0xFFC3, 0); - - if (type == 0) - val = (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) ? 4 : 8; - else if (type == 1) - val = 16; - else - val = 32; - b43_phy_set(dev, reg, val); - - reg = (i == 0) ? - B43_NPHY_TXF_40CO_B1S0 : - B43_NPHY_TXF_40CO_B32S1; - b43_phy_set(dev, reg, 0x0020); - } else { - if (type == 6) - val = 0x0100; - else if (type == 3) - val = 0x0200; - else - val = 0x0300; - - reg = (i == 0) ? - B43_NPHY_AFECTL_C1 : - B43_NPHY_AFECTL_C2; - - b43_phy_maskset(dev, reg, 0xFCFF, val); - b43_phy_maskset(dev, reg, 0xF3FF, val << 2); - - if (type != 3 && type != 6) { - enum ieee80211_band band = - b43_current_band(dev->wl); - - if ((nphy->ipa2g_on && - band == IEEE80211_BAND_2GHZ) || - (nphy->ipa5g_on && - band == IEEE80211_BAND_5GHZ)) - val = (band == IEEE80211_BAND_5GHZ) ? 0xC : 0xE; - else - val = 0x11; - reg = (i == 0) ? 0x2000 : 0x3000; - reg |= B2055_PADDRV; - b43_radio_write16(dev, reg, val); - - reg = (i == 0) ? - B43_NPHY_AFECTL_OVER1 : - B43_NPHY_AFECTL_OVER; - b43_phy_set(dev, reg, 0x0200); - } - } - } - } -} - -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSISel */ -static void b43_nphy_rssi_select(struct b43_wldev *dev, u8 code, u8 type) -{ - if (dev->phy.rev >= 3) - b43_nphy_rev3_rssi_select(dev, code, type); - else - b43_nphy_rev2_rssi_select(dev, code, type); -} - -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SetRssi2055Vcm */ -static void b43_nphy_set_rssi_2055_vcm(struct b43_wldev *dev, u8 type, u8 *buf) -{ - int i; - for (i = 0; i < 2; i++) { - if (type == 2) { - if (i == 0) { - b43_radio_maskset(dev, B2055_C1_B0NB_RSSIVCM, - 0xFC, buf[0]); - b43_radio_maskset(dev, B2055_C1_RX_BB_RSSICTL5, - 0xFC, buf[1]); - } else { - b43_radio_maskset(dev, B2055_C2_B0NB_RSSIVCM, - 0xFC, buf[2 * i]); - b43_radio_maskset(dev, B2055_C2_RX_BB_RSSICTL5, - 0xFC, buf[2 * i + 1]); - } - } else { - if (i == 0) - b43_radio_maskset(dev, B2055_C1_RX_BB_RSSICTL5, - 0xF3, buf[0] << 2); - else - b43_radio_maskset(dev, B2055_C2_RX_BB_RSSICTL5, - 0xF3, buf[2 * i + 1] << 2); - } - } -} - -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/PollRssi */ -static int b43_nphy_poll_rssi(struct b43_wldev *dev, u8 type, s32 *buf, - u8 nsamp) -{ - int i; - int out; - u16 save_regs_phy[9]; - u16 s[2]; - - if (dev->phy.rev >= 3) { - save_regs_phy[0] = b43_phy_read(dev, - B43_NPHY_RFCTL_LUT_TRSW_UP1); - save_regs_phy[1] = b43_phy_read(dev, - B43_NPHY_RFCTL_LUT_TRSW_UP2); - save_regs_phy[2] = b43_phy_read(dev, B43_NPHY_AFECTL_C1); - save_regs_phy[3] = b43_phy_read(dev, B43_NPHY_AFECTL_C2); - save_regs_phy[4] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER1); - save_regs_phy[5] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER); - save_regs_phy[6] = b43_phy_read(dev, B43_NPHY_TXF_40CO_B1S0); - save_regs_phy[7] = b43_phy_read(dev, B43_NPHY_TXF_40CO_B32S1); - } - - b43_nphy_rssi_select(dev, 5, type); - - if (dev->phy.rev < 2) { - save_regs_phy[8] = b43_phy_read(dev, B43_NPHY_GPIO_SEL); - b43_phy_write(dev, B43_NPHY_GPIO_SEL, 5); - } - - for (i = 0; i < 4; i++) - buf[i] = 0; - - for (i = 0; i < nsamp; i++) { - if (dev->phy.rev < 2) { - s[0] = b43_phy_read(dev, B43_NPHY_GPIO_LOOUT); - s[1] = b43_phy_read(dev, B43_NPHY_GPIO_HIOUT); - } else { - s[0] = b43_phy_read(dev, B43_NPHY_RSSI1); - s[1] = b43_phy_read(dev, B43_NPHY_RSSI2); - } - - buf[0] += ((s8)((s[0] & 0x3F) << 2)) >> 2; - buf[1] += ((s8)(((s[0] >> 8) & 0x3F) << 2)) >> 2; - buf[2] += ((s8)((s[1] & 0x3F) << 2)) >> 2; - buf[3] += ((s8)(((s[1] >> 8) & 0x3F) << 2)) >> 2; - } - out = (buf[0] & 0xFF) << 24 | (buf[1] & 0xFF) << 16 | - (buf[2] & 0xFF) << 8 | (buf[3] & 0xFF); - - if (dev->phy.rev < 2) - b43_phy_write(dev, B43_NPHY_GPIO_SEL, save_regs_phy[8]); - - if (dev->phy.rev >= 3) { - b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP1, - save_regs_phy[0]); - b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, - save_regs_phy[1]); - b43_phy_write(dev, B43_NPHY_AFECTL_C1, save_regs_phy[2]); - b43_phy_write(dev, B43_NPHY_AFECTL_C2, save_regs_phy[3]); - b43_phy_write(dev, B43_NPHY_AFECTL_OVER1, save_regs_phy[4]); - b43_phy_write(dev, B43_NPHY_AFECTL_OVER, save_regs_phy[5]); - b43_phy_write(dev, B43_NPHY_TXF_40CO_B1S0, save_regs_phy[6]); - b43_phy_write(dev, B43_NPHY_TXF_40CO_B32S1, save_regs_phy[7]); - } - - return out; -} - -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICal */ -static void b43_nphy_rev2_rssi_cal(struct b43_wldev *dev, u8 type) -{ - int i, j; - u8 state[4]; - u8 code, val; - u16 class, override; - u8 regs_save_radio[2]; - u16 regs_save_phy[2]; - s8 offset[4]; - - u16 clip_state[2]; - u16 clip_off[2] = { 0xFFFF, 0xFFFF }; - s32 results_min[4] = { }; - u8 vcm_final[4] = { }; - s32 results[4][4] = { }; - s32 miniq[4][2] = { }; - - if (type == 2) { - code = 0; - val = 6; - } else if (type < 2) { - code = 25; - val = 4; - } else { - B43_WARN_ON(1); - return; - } - - class = b43_nphy_classifier(dev, 0, 0); - b43_nphy_classifier(dev, 7, 4); - b43_nphy_read_clip_detection(dev, clip_state); - b43_nphy_write_clip_detection(dev, clip_off); - - if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) - override = 0x140; - else - override = 0x110; - - regs_save_phy[0] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC1); - regs_save_radio[0] = b43_radio_read16(dev, B2055_C1_PD_RXTX); - b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, override); - b43_radio_write16(dev, B2055_C1_PD_RXTX, val); - - regs_save_phy[1] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC2); - regs_save_radio[1] = b43_radio_read16(dev, B2055_C2_PD_RXTX); - b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, override); - b43_radio_write16(dev, B2055_C2_PD_RXTX, val); - - state[0] = b43_radio_read16(dev, B2055_C1_PD_RSSIMISC) & 0x07; - state[1] = b43_radio_read16(dev, B2055_C2_PD_RSSIMISC) & 0x07; - b43_radio_mask(dev, B2055_C1_PD_RSSIMISC, 0xF8); - b43_radio_mask(dev, B2055_C2_PD_RSSIMISC, 0xF8); - state[2] = b43_radio_read16(dev, B2055_C1_SP_RSSI) & 0x07; - state[3] = b43_radio_read16(dev, B2055_C2_SP_RSSI) & 0x07; - - b43_nphy_rssi_select(dev, 5, type); - b43_nphy_scale_offset_rssi(dev, 0, 0, 5, 0, type); - b43_nphy_scale_offset_rssi(dev, 0, 0, 5, 1, type); - - for (i = 0; i < 4; i++) { - u8 tmp[4]; - for (j = 0; j < 4; j++) - tmp[j] = i; - if (type != 1) - b43_nphy_set_rssi_2055_vcm(dev, type, tmp); - b43_nphy_poll_rssi(dev, type, results[i], 8); - if (type < 2) - for (j = 0; j < 2; j++) - miniq[i][j] = min(results[i][2 * j], - results[i][2 * j + 1]); - } - - for (i = 0; i < 4; i++) { - s32 mind = 40; - u8 minvcm = 0; - s32 minpoll = 249; - s32 curr; - for (j = 0; j < 4; j++) { - if (type == 2) - curr = abs(results[j][i]); - else - curr = abs(miniq[j][i / 2] - code * 8); - - if (curr < mind) { - mind = curr; - minvcm = j; - } - - if (results[j][i] < minpoll) - minpoll = results[j][i]; - } - results_min[i] = minpoll; - vcm_final[i] = minvcm; - } - - if (type != 1) - b43_nphy_set_rssi_2055_vcm(dev, type, vcm_final); - - for (i = 0; i < 4; i++) { - offset[i] = (code * 8) - results[vcm_final[i]][i]; - - if (offset[i] < 0) - offset[i] = -((abs(offset[i]) + 4) / 8); - else - offset[i] = (offset[i] + 4) / 8; - - if (results_min[i] == 248) - offset[i] = code - 32; - - if (i % 2 == 0) - b43_nphy_scale_offset_rssi(dev, 0, offset[i], 1, 0, - type); - else - b43_nphy_scale_offset_rssi(dev, 0, offset[i], 2, 1, - type); - } - - b43_radio_maskset(dev, B2055_C1_PD_RSSIMISC, 0xF8, state[0]); - b43_radio_maskset(dev, B2055_C1_PD_RSSIMISC, 0xF8, state[1]); - - switch (state[2]) { - case 1: - b43_nphy_rssi_select(dev, 1, 2); - break; - case 4: - b43_nphy_rssi_select(dev, 1, 0); - break; - case 2: - b43_nphy_rssi_select(dev, 1, 1); - break; - default: - b43_nphy_rssi_select(dev, 1, 1); - break; - } - - switch (state[3]) { - case 1: - b43_nphy_rssi_select(dev, 2, 2); - break; - case 4: - b43_nphy_rssi_select(dev, 2, 0); - break; - default: - b43_nphy_rssi_select(dev, 2, 1); - break; - } - - b43_nphy_rssi_select(dev, 0, type); - - b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, regs_save_phy[0]); - b43_radio_write16(dev, B2055_C1_PD_RXTX, regs_save_radio[0]); - b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, regs_save_phy[1]); - b43_radio_write16(dev, B2055_C2_PD_RXTX, regs_save_radio[1]); - - b43_nphy_classifier(dev, 7, class); - b43_nphy_write_clip_detection(dev, clip_state); -} - -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICalRev3 */ -static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev) -{ - /* TODO */ -} - -/* - * RSSI Calibration - * http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICal - */ -static void b43_nphy_rssi_cal(struct b43_wldev *dev) -{ - if (dev->phy.rev >= 3) { - b43_nphy_rev3_rssi_cal(dev); - } else { - b43_nphy_rev2_rssi_cal(dev, 2); - b43_nphy_rev2_rssi_cal(dev, 0); - b43_nphy_rev2_rssi_cal(dev, 1); - } -} - -/* - * Restore RSSI Calibration - * http://bcm-v4.sipsolutions.net/802.11/PHY/N/RestoreRssiCal - */ -static void b43_nphy_restore_rssi_cal(struct b43_wldev *dev) -{ - struct b43_phy_n *nphy = dev->phy.n; - - u16 *rssical_radio_regs = NULL; - u16 *rssical_phy_regs = NULL; - - if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { - if (!nphy->rssical_chanspec_2G) - return; - rssical_radio_regs = nphy->rssical_cache.rssical_radio_regs_2G; - rssical_phy_regs = nphy->rssical_cache.rssical_phy_regs_2G; - } else { - if (!nphy->rssical_chanspec_5G) - return; - rssical_radio_regs = nphy->rssical_cache.rssical_radio_regs_5G; - rssical_phy_regs = nphy->rssical_cache.rssical_phy_regs_5G; - } - - /* TODO use some definitions */ - b43_radio_maskset(dev, 0x602B, 0xE3, rssical_radio_regs[0]); - b43_radio_maskset(dev, 0x702B, 0xE3, rssical_radio_regs[1]); - - b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_Z, rssical_phy_regs[0]); - b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_Z, rssical_phy_regs[1]); - b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_Z, rssical_phy_regs[2]); - b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_Z, rssical_phy_regs[3]); - - b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_X, rssical_phy_regs[4]); - b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_X, rssical_phy_regs[5]); - b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_X, rssical_phy_regs[6]); - b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_X, rssical_phy_regs[7]); - - b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_Y, rssical_phy_regs[8]); - b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_Y, rssical_phy_regs[9]); - b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_Y, rssical_phy_regs[10]); - b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_Y, rssical_phy_regs[11]); -} - -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/GetIpaGainTbl */ -static const u32 *b43_nphy_get_ipa_gain_table(struct b43_wldev *dev) -{ - if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { - if (dev->phy.rev >= 6) { - /* TODO If the chip is 47162 - return txpwrctrl_tx_gain_ipa_rev5 */ - return txpwrctrl_tx_gain_ipa_rev6; - } else if (dev->phy.rev >= 5) { - return txpwrctrl_tx_gain_ipa_rev5; - } else { - return txpwrctrl_tx_gain_ipa; - } - } else { - return txpwrctrl_tx_gain_ipa_5g; - } -} - -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxCalRadioSetup */ -static void b43_nphy_tx_cal_radio_setup(struct b43_wldev *dev) -{ - struct b43_phy_n *nphy = dev->phy.n; - u16 *save = nphy->tx_rx_cal_radio_saveregs; - u16 tmp; - u8 offset, i; - - if (dev->phy.rev >= 3) { - for (i = 0; i < 2; i++) { - tmp = (i == 0) ? 0x2000 : 0x3000; - offset = i * 11; - - save[offset + 0] = b43_radio_read16(dev, B2055_CAL_RVARCTL); - save[offset + 1] = b43_radio_read16(dev, B2055_CAL_LPOCTL); - save[offset + 2] = b43_radio_read16(dev, B2055_CAL_TS); - save[offset + 3] = b43_radio_read16(dev, B2055_CAL_RCCALRTS); - save[offset + 4] = b43_radio_read16(dev, B2055_CAL_RCALRTS); - save[offset + 5] = b43_radio_read16(dev, B2055_PADDRV); - save[offset + 6] = b43_radio_read16(dev, B2055_XOCTL1); - save[offset + 7] = b43_radio_read16(dev, B2055_XOCTL2); - save[offset + 8] = b43_radio_read16(dev, B2055_XOREGUL); - save[offset + 9] = b43_radio_read16(dev, B2055_XOMISC); - save[offset + 10] = b43_radio_read16(dev, B2055_PLL_LFC1); - - if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) { - b43_radio_write16(dev, tmp | B2055_CAL_RVARCTL, 0x0A); - b43_radio_write16(dev, tmp | B2055_CAL_LPOCTL, 0x40); - b43_radio_write16(dev, tmp | B2055_CAL_TS, 0x55); - b43_radio_write16(dev, tmp | B2055_CAL_RCCALRTS, 0); - b43_radio_write16(dev, tmp | B2055_CAL_RCALRTS, 0); - if (nphy->ipa5g_on) { - b43_radio_write16(dev, tmp | B2055_PADDRV, 4); - b43_radio_write16(dev, tmp | B2055_XOCTL1, 1); - } else { - b43_radio_write16(dev, tmp | B2055_PADDRV, 0); - b43_radio_write16(dev, tmp | B2055_XOCTL1, 0x2F); - } - b43_radio_write16(dev, tmp | B2055_XOCTL2, 0); - } else { - b43_radio_write16(dev, tmp | B2055_CAL_RVARCTL, 0x06); - b43_radio_write16(dev, tmp | B2055_CAL_LPOCTL, 0x40); - b43_radio_write16(dev, tmp | B2055_CAL_TS, 0x55); - b43_radio_write16(dev, tmp | B2055_CAL_RCCALRTS, 0); - b43_radio_write16(dev, tmp | B2055_CAL_RCALRTS, 0); - b43_radio_write16(dev, tmp | B2055_XOCTL1, 0); - if (nphy->ipa2g_on) { - b43_radio_write16(dev, tmp | B2055_PADDRV, 6); - b43_radio_write16(dev, tmp | B2055_XOCTL2, - (dev->phy.rev < 5) ? 0x11 : 0x01); - } else { - b43_radio_write16(dev, tmp | B2055_PADDRV, 0); - b43_radio_write16(dev, tmp | B2055_XOCTL2, 0); - } - } - b43_radio_write16(dev, tmp | B2055_XOREGUL, 0); - b43_radio_write16(dev, tmp | B2055_XOMISC, 0); - b43_radio_write16(dev, tmp | B2055_PLL_LFC1, 0); - } - } else { - save[0] = b43_radio_read16(dev, B2055_C1_TX_RF_IQCAL1); - b43_radio_write16(dev, B2055_C1_TX_RF_IQCAL1, 0x29); - - save[1] = b43_radio_read16(dev, B2055_C1_TX_RF_IQCAL2); - b43_radio_write16(dev, B2055_C1_TX_RF_IQCAL2, 0x54); - - save[2] = b43_radio_read16(dev, B2055_C2_TX_RF_IQCAL1); - b43_radio_write16(dev, B2055_C2_TX_RF_IQCAL1, 0x29); - - save[3] = b43_radio_read16(dev, B2055_C2_TX_RF_IQCAL2); - b43_radio_write16(dev, B2055_C2_TX_RF_IQCAL2, 0x54); - - save[3] = b43_radio_read16(dev, B2055_C1_PWRDET_RXTX); - save[4] = b43_radio_read16(dev, B2055_C2_PWRDET_RXTX); - - if (!(b43_phy_read(dev, B43_NPHY_BANDCTL) & - B43_NPHY_BANDCTL_5GHZ)) { - b43_radio_write16(dev, B2055_C1_PWRDET_RXTX, 0x04); - b43_radio_write16(dev, B2055_C2_PWRDET_RXTX, 0x04); - } else { - b43_radio_write16(dev, B2055_C1_PWRDET_RXTX, 0x20); - b43_radio_write16(dev, B2055_C2_PWRDET_RXTX, 0x20); - } - - if (dev->phy.rev < 2) { - b43_radio_set(dev, B2055_C1_TX_BB_MXGM, 0x20); - b43_radio_set(dev, B2055_C2_TX_BB_MXGM, 0x20); - } else { - b43_radio_mask(dev, B2055_C1_TX_BB_MXGM, ~0x20); - b43_radio_mask(dev, B2055_C2_TX_BB_MXGM, ~0x20); - } - } -} - -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/IqCalGainParams */ -static void b43_nphy_iq_cal_gain_params(struct b43_wldev *dev, u16 core, - struct nphy_txgains target, - struct nphy_iqcal_params *params) -{ - int i, j, indx; - u16 gain; - - if (dev->phy.rev >= 3) { - params->txgm = target.txgm[core]; - params->pga = target.pga[core]; - params->pad = target.pad[core]; - params->ipa = target.ipa[core]; - params->cal_gain = (params->txgm << 12) | (params->pga << 8) | - (params->pad << 4) | (params->ipa); - for (j = 0; j < 5; j++) - params->ncorr[j] = 0x79; - } else { - gain = (target.pad[core]) | (target.pga[core] << 4) | - (target.txgm[core] << 8); - - indx = (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) ? - 1 : 0; - for (i = 0; i < 9; i++) - if (tbl_iqcal_gainparams[indx][i][0] == gain) - break; - i = min(i, 8); - - params->txgm = tbl_iqcal_gainparams[indx][i][1]; - params->pga = tbl_iqcal_gainparams[indx][i][2]; - params->pad = tbl_iqcal_gainparams[indx][i][3]; - params->cal_gain = (params->txgm << 7) | (params->pga << 4) | - (params->pad << 2); - for (j = 0; j < 4; j++) - params->ncorr[j] = tbl_iqcal_gainparams[indx][i][4 + j]; - } -} - -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/UpdateTxCalLadder */ -static void b43_nphy_update_tx_cal_ladder(struct b43_wldev *dev, u16 core) -{ - struct b43_phy_n *nphy = dev->phy.n; - int i; - u16 scale, entry; - - u16 tmp = nphy->txcal_bbmult; - if (core == 0) - tmp >>= 8; - tmp &= 0xff; - - for (i = 0; i < 18; i++) { - scale = (ladder_lo[i].percent * tmp) / 100; - entry = ((scale & 0xFF) << 8) | ladder_lo[i].g_env; - b43_ntab_write(dev, B43_NTAB16(15, i), entry); - - scale = (ladder_iq[i].percent * tmp) / 100; - entry = ((scale & 0xFF) << 8) | ladder_iq[i].g_env; - b43_ntab_write(dev, B43_NTAB16(15, i + 32), entry); - } -} - -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ExtPaSetTxDigiFilts */ -static void b43_nphy_ext_pa_set_tx_dig_filters(struct b43_wldev *dev) -{ - int i; - for (i = 0; i < 15; i++) - b43_phy_write(dev, B43_PHY_N(0x2C5 + i), - tbl_tx_filter_coef_rev4[2][i]); -} - -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/IpaSetTxDigiFilts */ -static void b43_nphy_int_pa_set_tx_dig_filters(struct b43_wldev *dev) -{ - int i, j; - /* B43_NPHY_TXF_20CO_S0A1, B43_NPHY_TXF_40CO_S0A1, unknown */ - u16 offset[] = { 0x186, 0x195, 0x2C5 }; - - for (i = 0; i < 3; i++) - for (j = 0; j < 15; j++) - b43_phy_write(dev, B43_PHY_N(offset[i] + j), - tbl_tx_filter_coef_rev4[i][j]); - - if (dev->phy.is_40mhz) { - for (j = 0; j < 15; j++) - b43_phy_write(dev, B43_PHY_N(offset[0] + j), - tbl_tx_filter_coef_rev4[3][j]); - } else if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) { - for (j = 0; j < 15; j++) - b43_phy_write(dev, B43_PHY_N(offset[0] + j), - tbl_tx_filter_coef_rev4[5][j]); - } - - if (dev->phy.channel == 14) - for (j = 0; j < 15; j++) - b43_phy_write(dev, B43_PHY_N(offset[0] + j), - tbl_tx_filter_coef_rev4[6][j]); -} - -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/GetTxGain */ -static struct nphy_txgains b43_nphy_get_tx_gains(struct b43_wldev *dev) -{ - struct b43_phy_n *nphy = dev->phy.n; - - u16 curr_gain[2]; - struct nphy_txgains target; - const u32 *table = NULL; - - if (nphy->txpwrctrl == 0) { - int i; - - if (nphy->hang_avoid) - b43_nphy_stay_in_carrier_search(dev, true); - b43_ntab_read_bulk(dev, B43_NTAB16(7, 0x110), 2, curr_gain); - if (nphy->hang_avoid) - b43_nphy_stay_in_carrier_search(dev, false); - - for (i = 0; i < 2; ++i) { - if (dev->phy.rev >= 3) { - target.ipa[i] = curr_gain[i] & 0x000F; - target.pad[i] = (curr_gain[i] & 0x00F0) >> 4; - target.pga[i] = (curr_gain[i] & 0x0F00) >> 8; - target.txgm[i] = (curr_gain[i] & 0x7000) >> 12; - } else { - target.ipa[i] = curr_gain[i] & 0x0003; - target.pad[i] = (curr_gain[i] & 0x000C) >> 2; - target.pga[i] = (curr_gain[i] & 0x0070) >> 4; - target.txgm[i] = (curr_gain[i] & 0x0380) >> 7; - } - } - } else { - int i; - u16 index[2]; - index[0] = (b43_phy_read(dev, B43_NPHY_C1_TXPCTL_STAT) & - B43_NPHY_TXPCTL_STAT_BIDX) >> - B43_NPHY_TXPCTL_STAT_BIDX_SHIFT; - index[1] = (b43_phy_read(dev, B43_NPHY_C2_TXPCTL_STAT) & - B43_NPHY_TXPCTL_STAT_BIDX) >> - B43_NPHY_TXPCTL_STAT_BIDX_SHIFT; - - for (i = 0; i < 2; ++i) { - if (dev->phy.rev >= 3) { - enum ieee80211_band band = - b43_current_band(dev->wl); - - if ((nphy->ipa2g_on && - band == IEEE80211_BAND_2GHZ) || - (nphy->ipa5g_on && - band == IEEE80211_BAND_5GHZ)) { - table = b43_nphy_get_ipa_gain_table(dev); - } else { - if (band == IEEE80211_BAND_5GHZ) { - if (dev->phy.rev == 3) - table = b43_ntab_tx_gain_rev3_5ghz; - else if (dev->phy.rev == 4) - table = b43_ntab_tx_gain_rev4_5ghz; - else - table = b43_ntab_tx_gain_rev5plus_5ghz; - } else { - table = b43_ntab_tx_gain_rev3plus_2ghz; - } - } - - target.ipa[i] = (table[index[i]] >> 16) & 0xF; - target.pad[i] = (table[index[i]] >> 20) & 0xF; - target.pga[i] = (table[index[i]] >> 24) & 0xF; - target.txgm[i] = (table[index[i]] >> 28) & 0xF; - } else { - table = b43_ntab_tx_gain_rev0_1_2; - - target.ipa[i] = (table[index[i]] >> 16) & 0x3; - target.pad[i] = (table[index[i]] >> 18) & 0x3; - target.pga[i] = (table[index[i]] >> 20) & 0x7; - target.txgm[i] = (table[index[i]] >> 23) & 0x7; - } - } - } - - return target; -} - -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxCalPhyCleanup */ -static void b43_nphy_tx_cal_phy_cleanup(struct b43_wldev *dev) -{ - u16 *regs = dev->phy.n->tx_rx_cal_phy_saveregs; - - if (dev->phy.rev >= 3) { - b43_phy_write(dev, B43_NPHY_AFECTL_C1, regs[0]); - b43_phy_write(dev, B43_NPHY_AFECTL_C2, regs[1]); - b43_phy_write(dev, B43_NPHY_AFECTL_OVER1, regs[2]); - b43_phy_write(dev, B43_NPHY_AFECTL_OVER, regs[3]); - b43_phy_write(dev, B43_NPHY_BBCFG, regs[4]); - b43_ntab_write(dev, B43_NTAB16(8, 3), regs[5]); - b43_ntab_write(dev, B43_NTAB16(8, 19), regs[6]); - b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, regs[7]); - b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, regs[8]); - b43_phy_write(dev, B43_NPHY_PAPD_EN0, regs[9]); - b43_phy_write(dev, B43_NPHY_PAPD_EN1, regs[10]); - b43_nphy_reset_cca(dev); - } else { - b43_phy_maskset(dev, B43_NPHY_AFECTL_C1, 0x0FFF, regs[0]); - b43_phy_maskset(dev, B43_NPHY_AFECTL_C2, 0x0FFF, regs[1]); - b43_phy_write(dev, B43_NPHY_AFECTL_OVER, regs[2]); - b43_ntab_write(dev, B43_NTAB16(8, 2), regs[3]); - b43_ntab_write(dev, B43_NTAB16(8, 18), regs[4]); - b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, regs[5]); - b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, regs[6]); - } -} - -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxCalPhySetup */ -static void b43_nphy_tx_cal_phy_setup(struct b43_wldev *dev) -{ - u16 *regs = dev->phy.n->tx_rx_cal_phy_saveregs; - u16 tmp; - - regs[0] = b43_phy_read(dev, B43_NPHY_AFECTL_C1); - regs[1] = b43_phy_read(dev, B43_NPHY_AFECTL_C2); - if (dev->phy.rev >= 3) { - b43_phy_maskset(dev, B43_NPHY_AFECTL_C1, 0xF0FF, 0x0A00); - b43_phy_maskset(dev, B43_NPHY_AFECTL_C2, 0xF0FF, 0x0A00); - - tmp = b43_phy_read(dev, B43_NPHY_AFECTL_OVER1); - regs[2] = tmp; - b43_phy_write(dev, B43_NPHY_AFECTL_OVER1, tmp | 0x0600); - - tmp = b43_phy_read(dev, B43_NPHY_AFECTL_OVER); - regs[3] = tmp; - b43_phy_write(dev, B43_NPHY_AFECTL_OVER, tmp | 0x0600); - - regs[4] = b43_phy_read(dev, B43_NPHY_BBCFG); - b43_phy_mask(dev, B43_NPHY_BBCFG, (u16)~B43_NPHY_BBCFG_RSTRX); - - tmp = b43_ntab_read(dev, B43_NTAB16(8, 3)); - regs[5] = tmp; - b43_ntab_write(dev, B43_NTAB16(8, 3), 0); - - tmp = b43_ntab_read(dev, B43_NTAB16(8, 19)); - regs[6] = tmp; - b43_ntab_write(dev, B43_NTAB16(8, 19), 0); - regs[7] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC1); - regs[8] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC2); - - b43_nphy_rf_control_intc_override(dev, 2, 1, 3); - b43_nphy_rf_control_intc_override(dev, 1, 2, 1); - b43_nphy_rf_control_intc_override(dev, 1, 8, 2); - - regs[9] = b43_phy_read(dev, B43_NPHY_PAPD_EN0); - regs[10] = b43_phy_read(dev, B43_NPHY_PAPD_EN1); - b43_phy_mask(dev, B43_NPHY_PAPD_EN0, ~0x0001); - b43_phy_mask(dev, B43_NPHY_PAPD_EN1, ~0x0001); - } else { - b43_phy_maskset(dev, B43_NPHY_AFECTL_C1, 0x0FFF, 0xA000); - b43_phy_maskset(dev, B43_NPHY_AFECTL_C2, 0x0FFF, 0xA000); - tmp = b43_phy_read(dev, B43_NPHY_AFECTL_OVER); - regs[2] = tmp; - b43_phy_write(dev, B43_NPHY_AFECTL_OVER, tmp | 0x3000); - tmp = b43_ntab_read(dev, B43_NTAB16(8, 2)); - regs[3] = tmp; - tmp |= 0x2000; - b43_ntab_write(dev, B43_NTAB16(8, 2), tmp); - tmp = b43_ntab_read(dev, B43_NTAB16(8, 18)); - regs[4] = tmp; - tmp |= 0x2000; - b43_ntab_write(dev, B43_NTAB16(8, 18), tmp); - regs[5] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC1); - regs[6] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC2); - if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) - tmp = 0x0180; - else - tmp = 0x0120; - b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, tmp); - b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, tmp); - } -} - -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SaveCal */ -static void b43_nphy_save_cal(struct b43_wldev *dev) -{ - struct b43_phy_n *nphy = dev->phy.n; - - struct b43_phy_n_iq_comp *rxcal_coeffs = NULL; - u16 *txcal_radio_regs = NULL; - u8 *iqcal_chanspec; - u16 *table = NULL; - - if (nphy->hang_avoid) - b43_nphy_stay_in_carrier_search(dev, 1); - - if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { - rxcal_coeffs = &nphy->cal_cache.rxcal_coeffs_2G; - txcal_radio_regs = nphy->cal_cache.txcal_radio_regs_2G; - iqcal_chanspec = &nphy->iqcal_chanspec_2G; - table = nphy->cal_cache.txcal_coeffs_2G; - } else { - rxcal_coeffs = &nphy->cal_cache.rxcal_coeffs_5G; - txcal_radio_regs = nphy->cal_cache.txcal_radio_regs_5G; - iqcal_chanspec = &nphy->iqcal_chanspec_5G; - table = nphy->cal_cache.txcal_coeffs_5G; - } - - b43_nphy_rx_iq_coeffs(dev, false, rxcal_coeffs); - /* TODO use some definitions */ - if (dev->phy.rev >= 3) { - txcal_radio_regs[0] = b43_radio_read(dev, 0x2021); - txcal_radio_regs[1] = b43_radio_read(dev, 0x2022); - txcal_radio_regs[2] = b43_radio_read(dev, 0x3021); - txcal_radio_regs[3] = b43_radio_read(dev, 0x3022); - txcal_radio_regs[4] = b43_radio_read(dev, 0x2023); - txcal_radio_regs[5] = b43_radio_read(dev, 0x2024); - txcal_radio_regs[6] = b43_radio_read(dev, 0x3023); - txcal_radio_regs[7] = b43_radio_read(dev, 0x3024); - } else { - txcal_radio_regs[0] = b43_radio_read(dev, 0x8B); - txcal_radio_regs[1] = b43_radio_read(dev, 0xBA); - txcal_radio_regs[2] = b43_radio_read(dev, 0x8D); - txcal_radio_regs[3] = b43_radio_read(dev, 0xBC); - } - *iqcal_chanspec = nphy->radio_chanspec; - b43_ntab_write_bulk(dev, B43_NTAB16(15, 80), 8, table); - - if (nphy->hang_avoid) - b43_nphy_stay_in_carrier_search(dev, 0); -} - -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RestoreCal */ -static void b43_nphy_restore_cal(struct b43_wldev *dev) -{ - struct b43_phy_n *nphy = dev->phy.n; - - u16 coef[4]; - u16 *loft = NULL; - u16 *table = NULL; - - int i; - u16 *txcal_radio_regs = NULL; - struct b43_phy_n_iq_comp *rxcal_coeffs = NULL; - - if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { - if (nphy->iqcal_chanspec_2G == 0) - return; - table = nphy->cal_cache.txcal_coeffs_2G; - loft = &nphy->cal_cache.txcal_coeffs_2G[5]; - } else { - if (nphy->iqcal_chanspec_5G == 0) - return; - table = nphy->cal_cache.txcal_coeffs_5G; - loft = &nphy->cal_cache.txcal_coeffs_5G[5]; - } - - b43_ntab_write_bulk(dev, B43_NTAB16(15, 80), 4, table); - - for (i = 0; i < 4; i++) { - if (dev->phy.rev >= 3) - table[i] = coef[i]; - else - coef[i] = 0; - } - - b43_ntab_write_bulk(dev, B43_NTAB16(15, 88), 4, coef); - b43_ntab_write_bulk(dev, B43_NTAB16(15, 85), 2, loft); - b43_ntab_write_bulk(dev, B43_NTAB16(15, 93), 2, loft); - - if (dev->phy.rev < 2) - b43_nphy_tx_iq_workaround(dev); - - if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { - txcal_radio_regs = nphy->cal_cache.txcal_radio_regs_2G; - rxcal_coeffs = &nphy->cal_cache.rxcal_coeffs_2G; - } else { - txcal_radio_regs = nphy->cal_cache.txcal_radio_regs_5G; - rxcal_coeffs = &nphy->cal_cache.rxcal_coeffs_5G; - } - - /* TODO use some definitions */ - if (dev->phy.rev >= 3) { - b43_radio_write(dev, 0x2021, txcal_radio_regs[0]); - b43_radio_write(dev, 0x2022, txcal_radio_regs[1]); - b43_radio_write(dev, 0x3021, txcal_radio_regs[2]); - b43_radio_write(dev, 0x3022, txcal_radio_regs[3]); - b43_radio_write(dev, 0x2023, txcal_radio_regs[4]); - b43_radio_write(dev, 0x2024, txcal_radio_regs[5]); - b43_radio_write(dev, 0x3023, txcal_radio_regs[6]); - b43_radio_write(dev, 0x3024, txcal_radio_regs[7]); - } else { - b43_radio_write(dev, 0x8B, txcal_radio_regs[0]); - b43_radio_write(dev, 0xBA, txcal_radio_regs[1]); - b43_radio_write(dev, 0x8D, txcal_radio_regs[2]); - b43_radio_write(dev, 0xBC, txcal_radio_regs[3]); - } - b43_nphy_rx_iq_coeffs(dev, true, rxcal_coeffs); -} - -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CalTxIqlo */ -static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev, - struct nphy_txgains target, - bool full, bool mphase) -{ - struct b43_phy_n *nphy = dev->phy.n; - int i; - int error = 0; - int freq; - bool avoid = false; - u8 length; - u16 tmp, core, type, count, max, numb, last, cmd; - const u16 *table; - bool phy6or5x; - - u16 buffer[11]; - u16 diq_start = 0; - u16 save[2]; - u16 gain[2]; - struct nphy_iqcal_params params[2]; - bool updated[2] = { }; - - b43_nphy_stay_in_carrier_search(dev, true); - - if (dev->phy.rev >= 4) { - avoid = nphy->hang_avoid; - nphy->hang_avoid = 0; - } - - b43_ntab_read_bulk(dev, B43_NTAB16(7, 0x110), 2, save); - - for (i = 0; i < 2; i++) { - b43_nphy_iq_cal_gain_params(dev, i, target, ¶ms[i]); - gain[i] = params[i].cal_gain; - } - - b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x110), 2, gain); - - b43_nphy_tx_cal_radio_setup(dev); - b43_nphy_tx_cal_phy_setup(dev); - - phy6or5x = dev->phy.rev >= 6 || - (dev->phy.rev == 5 && nphy->ipa2g_on && - b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ); - if (phy6or5x) { - if (dev->phy.is_40mhz) { - b43_ntab_write_bulk(dev, B43_NTAB16(15, 0), 18, - tbl_tx_iqlo_cal_loft_ladder_40); - b43_ntab_write_bulk(dev, B43_NTAB16(15, 32), 18, - tbl_tx_iqlo_cal_iqimb_ladder_40); - } else { - b43_ntab_write_bulk(dev, B43_NTAB16(15, 0), 18, - tbl_tx_iqlo_cal_loft_ladder_20); - b43_ntab_write_bulk(dev, B43_NTAB16(15, 32), 18, - tbl_tx_iqlo_cal_iqimb_ladder_20); - } - } - - b43_phy_write(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x8AA9); - - if (!dev->phy.is_40mhz) - freq = 2500; - else - freq = 5000; - - if (nphy->mphase_cal_phase_id > 2) - b43_nphy_run_samples(dev, (dev->phy.is_40mhz ? 40 : 20) * 8, - 0xFFFF, 0, true, false); - else - error = b43_nphy_tx_tone(dev, freq, 250, true, false); - - if (error == 0) { - if (nphy->mphase_cal_phase_id > 2) { - table = nphy->mphase_txcal_bestcoeffs; - length = 11; - if (dev->phy.rev < 3) - length -= 2; - } else { - if (!full && nphy->txiqlocal_coeffsvalid) { - table = nphy->txiqlocal_bestc; - length = 11; - if (dev->phy.rev < 3) - length -= 2; - } else { - full = true; - if (dev->phy.rev >= 3) { - table = tbl_tx_iqlo_cal_startcoefs_nphyrev3; - length = B43_NTAB_TX_IQLO_CAL_STARTCOEFS_REV3; - } else { - table = tbl_tx_iqlo_cal_startcoefs; - length = B43_NTAB_TX_IQLO_CAL_STARTCOEFS; - } - } - } - - b43_ntab_write_bulk(dev, B43_NTAB16(15, 64), length, table); - - if (full) { - if (dev->phy.rev >= 3) - max = B43_NTAB_TX_IQLO_CAL_CMDS_FULLCAL_REV3; - else - max = B43_NTAB_TX_IQLO_CAL_CMDS_FULLCAL; - } else { - if (dev->phy.rev >= 3) - max = B43_NTAB_TX_IQLO_CAL_CMDS_RECAL_REV3; - else - max = B43_NTAB_TX_IQLO_CAL_CMDS_RECAL; - } - - if (mphase) { - count = nphy->mphase_txcal_cmdidx; - numb = min(max, - (u16)(count + nphy->mphase_txcal_numcmds)); - } else { - count = 0; - numb = max; - } - - for (; count < numb; count++) { - if (full) { - if (dev->phy.rev >= 3) - cmd = tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3[count]; - else - cmd = tbl_tx_iqlo_cal_cmds_fullcal[count]; - } else { - if (dev->phy.rev >= 3) - cmd = tbl_tx_iqlo_cal_cmds_recal_nphyrev3[count]; - else - cmd = tbl_tx_iqlo_cal_cmds_recal[count]; - } - - core = (cmd & 0x3000) >> 12; - type = (cmd & 0x0F00) >> 8; - - if (phy6or5x && updated[core] == 0) { - b43_nphy_update_tx_cal_ladder(dev, core); - updated[core] = 1; - } - - tmp = (params[core].ncorr[type] << 8) | 0x66; - b43_phy_write(dev, B43_NPHY_IQLOCAL_CMDNNUM, tmp); - - if (type == 1 || type == 3 || type == 4) { - buffer[0] = b43_ntab_read(dev, - B43_NTAB16(15, 69 + core)); - diq_start = buffer[0]; - buffer[0] = 0; - b43_ntab_write(dev, B43_NTAB16(15, 69 + core), - 0); - } - - b43_phy_write(dev, B43_NPHY_IQLOCAL_CMD, cmd); - for (i = 0; i < 2000; i++) { - tmp = b43_phy_read(dev, B43_NPHY_IQLOCAL_CMD); - if (tmp & 0xC000) - break; - udelay(10); - } - - b43_ntab_read_bulk(dev, B43_NTAB16(15, 96), length, - buffer); - b43_ntab_write_bulk(dev, B43_NTAB16(15, 64), length, - buffer); - - if (type == 1 || type == 3 || type == 4) - buffer[0] = diq_start; - } - - if (mphase) - nphy->mphase_txcal_cmdidx = (numb >= max) ? 0 : numb; - - last = (dev->phy.rev < 3) ? 6 : 7; - - if (!mphase || nphy->mphase_cal_phase_id == last) { - b43_ntab_write_bulk(dev, B43_NTAB16(15, 96), 4, buffer); - b43_ntab_read_bulk(dev, B43_NTAB16(15, 80), 4, buffer); - if (dev->phy.rev < 3) { - buffer[0] = 0; - buffer[1] = 0; - buffer[2] = 0; - buffer[3] = 0; - } - b43_ntab_write_bulk(dev, B43_NTAB16(15, 88), 4, - buffer); - b43_ntab_write_bulk(dev, B43_NTAB16(15, 101), 2, - buffer); - b43_ntab_write_bulk(dev, B43_NTAB16(15, 85), 2, - buffer); - b43_ntab_write_bulk(dev, B43_NTAB16(15, 93), 2, - buffer); - length = 11; - if (dev->phy.rev < 3) - length -= 2; - b43_ntab_read_bulk(dev, B43_NTAB16(15, 96), length, - nphy->txiqlocal_bestc); - nphy->txiqlocal_coeffsvalid = true; - /* TODO: Set nphy->txiqlocal_chanspec to - the current channel */ - } else { - length = 11; - if (dev->phy.rev < 3) - length -= 2; - b43_ntab_read_bulk(dev, B43_NTAB16(15, 96), length, - nphy->mphase_txcal_bestcoeffs); - } - - b43_nphy_stop_playback(dev); - b43_phy_write(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0); - } - - b43_nphy_tx_cal_phy_cleanup(dev); - b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x110), 2, save); - - if (dev->phy.rev < 2 && (!mphase || nphy->mphase_cal_phase_id == last)) - b43_nphy_tx_iq_workaround(dev); - - if (dev->phy.rev >= 4) - nphy->hang_avoid = avoid; - - b43_nphy_stay_in_carrier_search(dev, false); - - return error; -} - -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ReapplyTxCalCoeffs */ -static void b43_nphy_reapply_tx_cal_coeffs(struct b43_wldev *dev) -{ - struct b43_phy_n *nphy = dev->phy.n; - u8 i; - u16 buffer[7]; - bool equal = true; - - if (!nphy->txiqlocal_coeffsvalid || 1 /* FIXME */) - return; - - b43_ntab_read_bulk(dev, B43_NTAB16(15, 80), 7, buffer); - for (i = 0; i < 4; i++) { - if (buffer[i] != nphy->txiqlocal_bestc[i]) { - equal = false; - break; - } - } - - if (!equal) { - b43_ntab_write_bulk(dev, B43_NTAB16(15, 80), 4, - nphy->txiqlocal_bestc); - for (i = 0; i < 4; i++) - buffer[i] = 0; - b43_ntab_write_bulk(dev, B43_NTAB16(15, 88), 4, - buffer); - b43_ntab_write_bulk(dev, B43_NTAB16(15, 85), 2, - &nphy->txiqlocal_bestc[5]); - b43_ntab_write_bulk(dev, B43_NTAB16(15, 93), 2, - &nphy->txiqlocal_bestc[5]); - } -} - -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CalRxIqRev2 */ -static int b43_nphy_rev2_cal_rx_iq(struct b43_wldev *dev, - struct nphy_txgains target, u8 type, bool debug) -{ - struct b43_phy_n *nphy = dev->phy.n; - int i, j, index; - u8 rfctl[2]; - u8 afectl_core; - u16 tmp[6]; - u16 cur_hpf1, cur_hpf2, cur_lna; - u32 real, imag; - enum ieee80211_band band; - - u8 use; - u16 cur_hpf; - u16 lna[3] = { 3, 3, 1 }; - u16 hpf1[3] = { 7, 2, 0 }; - u16 hpf2[3] = { 2, 0, 0 }; - u32 power[3] = { }; - u16 gain_save[2]; - u16 cal_gain[2]; - struct nphy_iqcal_params cal_params[2]; - struct nphy_iq_est est; - int ret = 0; - bool playtone = true; - int desired = 13; - - b43_nphy_stay_in_carrier_search(dev, 1); - - if (dev->phy.rev < 2) - b43_nphy_reapply_tx_cal_coeffs(dev); - b43_ntab_read_bulk(dev, B43_NTAB16(7, 0x110), 2, gain_save); - for (i = 0; i < 2; i++) { - b43_nphy_iq_cal_gain_params(dev, i, target, &cal_params[i]); - cal_gain[i] = cal_params[i].cal_gain; - } - b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x110), 2, cal_gain); - - for (i = 0; i < 2; i++) { - if (i == 0) { - rfctl[0] = B43_NPHY_RFCTL_INTC1; - rfctl[1] = B43_NPHY_RFCTL_INTC2; - afectl_core = B43_NPHY_AFECTL_C1; - } else { - rfctl[0] = B43_NPHY_RFCTL_INTC2; - rfctl[1] = B43_NPHY_RFCTL_INTC1; - afectl_core = B43_NPHY_AFECTL_C2; - } - - tmp[1] = b43_phy_read(dev, B43_NPHY_RFSEQCA); - tmp[2] = b43_phy_read(dev, afectl_core); - tmp[3] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER); - tmp[4] = b43_phy_read(dev, rfctl[0]); - tmp[5] = b43_phy_read(dev, rfctl[1]); - - b43_phy_maskset(dev, B43_NPHY_RFSEQCA, - (u16)~B43_NPHY_RFSEQCA_RXDIS, - ((1 - i) << B43_NPHY_RFSEQCA_RXDIS_SHIFT)); - b43_phy_maskset(dev, B43_NPHY_RFSEQCA, ~B43_NPHY_RFSEQCA_TXEN, - (1 - i)); - b43_phy_set(dev, afectl_core, 0x0006); - b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x0006); - - band = b43_current_band(dev->wl); - - if (nphy->rxcalparams & 0xFF000000) { - if (band == IEEE80211_BAND_5GHZ) - b43_phy_write(dev, rfctl[0], 0x140); - else - b43_phy_write(dev, rfctl[0], 0x110); - } else { - if (band == IEEE80211_BAND_5GHZ) - b43_phy_write(dev, rfctl[0], 0x180); - else - b43_phy_write(dev, rfctl[0], 0x120); - } - - if (band == IEEE80211_BAND_5GHZ) - b43_phy_write(dev, rfctl[1], 0x148); - else - b43_phy_write(dev, rfctl[1], 0x114); - - if (nphy->rxcalparams & 0x10000) { - b43_radio_maskset(dev, B2055_C1_GENSPARE2, 0xFC, - (i + 1)); - b43_radio_maskset(dev, B2055_C2_GENSPARE2, 0xFC, - (2 - i)); - } - - for (j = 0; i < 4; j++) { - if (j < 3) { - cur_lna = lna[j]; - cur_hpf1 = hpf1[j]; - cur_hpf2 = hpf2[j]; - } else { - if (power[1] > 10000) { - use = 1; - cur_hpf = cur_hpf1; - index = 2; - } else { - if (power[0] > 10000) { - use = 1; - cur_hpf = cur_hpf1; - index = 1; - } else { - index = 0; - use = 2; - cur_hpf = cur_hpf2; - } - } - cur_lna = lna[index]; - cur_hpf1 = hpf1[index]; - cur_hpf2 = hpf2[index]; - cur_hpf += desired - hweight32(power[index]); - cur_hpf = clamp_val(cur_hpf, 0, 10); - if (use == 1) - cur_hpf1 = cur_hpf; - else - cur_hpf2 = cur_hpf; - } - - tmp[0] = ((cur_hpf2 << 8) | (cur_hpf1 << 4) | - (cur_lna << 2)); - b43_nphy_rf_control_override(dev, 0x400, tmp[0], 3, - false); - b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX); - b43_nphy_stop_playback(dev); - - if (playtone) { - ret = b43_nphy_tx_tone(dev, 4000, - (nphy->rxcalparams & 0xFFFF), - false, false); - playtone = false; - } else { - b43_nphy_run_samples(dev, 160, 0xFFFF, 0, - false, false); - } - - if (ret == 0) { - if (j < 3) { - b43_nphy_rx_iq_est(dev, &est, 1024, 32, - false); - if (i == 0) { - real = est.i0_pwr; - imag = est.q0_pwr; - } else { - real = est.i1_pwr; - imag = est.q1_pwr; - } - power[i] = ((real + imag) / 1024) + 1; - } else { - b43_nphy_calc_rx_iq_comp(dev, 1 << i); - } - b43_nphy_stop_playback(dev); - } - - if (ret != 0) - break; - } - - b43_radio_mask(dev, B2055_C1_GENSPARE2, 0xFC); - b43_radio_mask(dev, B2055_C2_GENSPARE2, 0xFC); - b43_phy_write(dev, rfctl[1], tmp[5]); - b43_phy_write(dev, rfctl[0], tmp[4]); - b43_phy_write(dev, B43_NPHY_AFECTL_OVER, tmp[3]); - b43_phy_write(dev, afectl_core, tmp[2]); - b43_phy_write(dev, B43_NPHY_RFSEQCA, tmp[1]); - - if (ret != 0) - break; - } - - b43_nphy_rf_control_override(dev, 0x400, 0, 3, true); - b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX); - b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x110), 2, gain_save); - - b43_nphy_stay_in_carrier_search(dev, 0); - - return ret; -} - -static int b43_nphy_rev3_cal_rx_iq(struct b43_wldev *dev, - struct nphy_txgains target, u8 type, bool debug) -{ - return -1; -} - -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CalRxIq */ -static int b43_nphy_cal_rx_iq(struct b43_wldev *dev, - struct nphy_txgains target, u8 type, bool debug) -{ - if (dev->phy.rev >= 3) - return b43_nphy_rev3_cal_rx_iq(dev, target, type, debug); - else - return b43_nphy_rev2_cal_rx_iq(dev, target, type, debug); -} - -/* - * Init N-PHY - * http://bcm-v4.sipsolutions.net/802.11/PHY/Init/N - */ -int b43_phy_initn(struct b43_wldev *dev) -{ - struct ssb_bus *bus = dev->dev->bus; - struct b43_phy *phy = &dev->phy; - struct b43_phy_n *nphy = phy->n; - u8 tx_pwr_state; - struct nphy_txgains target; - u16 tmp; - enum ieee80211_band tmp2; - bool do_rssi_cal; - - u16 clip[2]; - bool do_cal = false; - - if ((dev->phy.rev >= 3) && - (bus->sprom.boardflags_lo & B43_BFL_EXTLNA) && - (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)) { - chipco_set32(&dev->dev->bus->chipco, SSB_CHIPCO_CHIPCTL, 0x40); - } - nphy->deaf_count = 0; - b43_nphy_tables_init(dev); - nphy->crsminpwr_adjusted = false; - nphy->noisevars_adjusted = false; - - /* Clear all overrides */ - if (dev->phy.rev >= 3) { - b43_phy_write(dev, B43_NPHY_TXF_40CO_B1S1, 0); - b43_phy_write(dev, B43_NPHY_RFCTL_OVER, 0); - b43_phy_write(dev, B43_NPHY_TXF_40CO_B1S0, 0); - b43_phy_write(dev, B43_NPHY_TXF_40CO_B32S1, 0); - } else { - b43_phy_write(dev, B43_NPHY_RFCTL_OVER, 0); - } - b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, 0); - b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, 0); - if (dev->phy.rev < 6) { - b43_phy_write(dev, B43_NPHY_RFCTL_INTC3, 0); - b43_phy_write(dev, B43_NPHY_RFCTL_INTC4, 0); - } - b43_phy_mask(dev, B43_NPHY_RFSEQMODE, - ~(B43_NPHY_RFSEQMODE_CAOVER | - B43_NPHY_RFSEQMODE_TROVER)); - if (dev->phy.rev >= 3) - b43_phy_write(dev, B43_NPHY_AFECTL_OVER1, 0); - b43_phy_write(dev, B43_NPHY_AFECTL_OVER, 0); - - if (dev->phy.rev <= 2) { - tmp = (dev->phy.rev == 2) ? 0x3B : 0x40; - b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3, - ~B43_NPHY_BPHY_CTL3_SCALE, - tmp << B43_NPHY_BPHY_CTL3_SCALE_SHIFT); - } - b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_20M, 0x20); - b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_40M, 0x20); - - if (bus->sprom.boardflags2_lo & 0x100 || - (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE && - bus->boardinfo.type == 0x8B)) - b43_phy_write(dev, B43_NPHY_TXREALFD, 0xA0); - else - b43_phy_write(dev, B43_NPHY_TXREALFD, 0xB8); - b43_phy_write(dev, B43_NPHY_MIMO_CRSTXEXT, 0xC8); - b43_phy_write(dev, B43_NPHY_PLOAD_CSENSE_EXTLEN, 0x50); - b43_phy_write(dev, B43_NPHY_TXRIFS_FRDEL, 0x30); - - b43_nphy_update_mimo_config(dev, nphy->preamble_override); - b43_nphy_update_txrx_chain(dev); - - if (phy->rev < 2) { - b43_phy_write(dev, B43_NPHY_DUP40_GFBL, 0xAA8); - b43_phy_write(dev, B43_NPHY_DUP40_BL, 0x9A4); - } - - tmp2 = b43_current_band(dev->wl); - if ((nphy->ipa2g_on && tmp2 == IEEE80211_BAND_2GHZ) || - (nphy->ipa5g_on && tmp2 == IEEE80211_BAND_5GHZ)) { - b43_phy_set(dev, B43_NPHY_PAPD_EN0, 0x1); - b43_phy_maskset(dev, B43_NPHY_EPS_TABLE_ADJ0, 0x007F, - nphy->papd_epsilon_offset[0] << 7); - b43_phy_set(dev, B43_NPHY_PAPD_EN1, 0x1); - b43_phy_maskset(dev, B43_NPHY_EPS_TABLE_ADJ1, 0x007F, - nphy->papd_epsilon_offset[1] << 7); - b43_nphy_int_pa_set_tx_dig_filters(dev); - } else if (phy->rev >= 5) { - b43_nphy_ext_pa_set_tx_dig_filters(dev); - } - - b43_nphy_workarounds(dev); - - /* Reset CCA, in init code it differs a little from standard way */ - b43_nphy_bmac_clock_fgc(dev, 1); - tmp = b43_phy_read(dev, B43_NPHY_BBCFG); - b43_phy_write(dev, B43_NPHY_BBCFG, tmp | B43_NPHY_BBCFG_RSTCCA); - b43_phy_write(dev, B43_NPHY_BBCFG, tmp & ~B43_NPHY_BBCFG_RSTCCA); - b43_nphy_bmac_clock_fgc(dev, 0); - - /* TODO N PHY MAC PHY Clock Set with argument 1 */ - - b43_nphy_pa_override(dev, false); + ssb_write32(dev->dev, SSB_TMSLOW, + ssb_read32(dev->dev, SSB_TMSLOW) | B43_TMSLOW_MACPHYCLKEN); b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RX2TX); b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX); - b43_nphy_pa_override(dev, true); - - b43_nphy_classifier(dev, 0, 0); - b43_nphy_read_clip_detection(dev, clip); - tx_pwr_state = nphy->txpwrctrl; - /* TODO N PHY TX power control with argument 0 - (turning off power control) */ - /* TODO Fix the TX Power Settings */ - /* TODO N PHY TX Power Control Idle TSSI */ - /* TODO N PHY TX Power Control Setup */ - - if (phy->rev >= 3) { - /* TODO */ - } else { - b43_ntab_write_bulk(dev, B43_NTAB32(26, 192), 128, - b43_ntab_tx_gain_rev0_1_2); - b43_ntab_write_bulk(dev, B43_NTAB32(27, 192), 128, - b43_ntab_tx_gain_rev0_1_2); - } - - if (nphy->phyrxchain != 3) - ;/* TODO N PHY RX Core Set State with phyrxchain as argument */ - if (nphy->mphase_cal_phase_id > 0) - ;/* TODO PHY Periodic Calibration Multi-Phase Restart */ - - do_rssi_cal = false; - if (phy->rev >= 3) { - if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) - do_rssi_cal = (nphy->rssical_chanspec_2G == 0); - else - do_rssi_cal = (nphy->rssical_chanspec_5G == 0); - - if (do_rssi_cal) - b43_nphy_rssi_cal(dev); - else - b43_nphy_restore_rssi_cal(dev); - } else { - b43_nphy_rssi_cal(dev); - } - - if (!((nphy->measure_hold & 0x6) != 0)) { - if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) - do_cal = (nphy->iqcal_chanspec_2G == 0); - else - do_cal = (nphy->iqcal_chanspec_5G == 0); - - if (nphy->mute) - do_cal = false; - - if (do_cal) { - target = b43_nphy_get_tx_gains(dev); - - if (nphy->antsel_type == 2) - ;/*TODO NPHY Superswitch Init with argument 1*/ - if (nphy->perical != 2) { - b43_nphy_rssi_cal(dev); - if (phy->rev >= 3) { - nphy->cal_orig_pwr_idx[0] = - nphy->txpwrindex[0].index_internal; - nphy->cal_orig_pwr_idx[1] = - nphy->txpwrindex[1].index_internal; - /* TODO N PHY Pre Calibrate TX Gain */ - target = b43_nphy_get_tx_gains(dev); - } - } - } - } - - if (!b43_nphy_cal_tx_iq_lo(dev, target, true, false)) { - if (b43_nphy_cal_rx_iq(dev, target, 2, 0) == 0) - b43_nphy_save_cal(dev); - else if (nphy->mphase_cal_phase_id == 0) - ;/* N PHY Periodic Calibration with argument 3 */ - } else { - b43_nphy_restore_cal(dev); - } - b43_nphy_tx_pwr_ctrl_coef_setup(dev); - /* TODO N PHY TX Power Control Enable with argument tx_pwr_state */ - b43_phy_write(dev, B43_NPHY_TXMACIF_HOLDOFF, 0x0015); - b43_phy_write(dev, B43_NPHY_TXMACDELAY, 0x0320); - if (phy->rev >= 3 && phy->rev <= 6) - b43_phy_write(dev, B43_NPHY_PLOAD_CSENSE_EXTLEN, 0x0014); - b43_nphy_tx_lp_fbw(dev); - if (phy->rev >= 3) - b43_nphy_spur_workaround(dev); + b43_phy_read(dev, B43_NPHY_CLASSCTL); /* dummy read */ + //TODO read core1/2 clip1 thres regs + + if (1 /* FIXME Band is 2.4GHz */) + b43_nphy_bphy_init(dev); + //TODO disable TX power control + //TODO Fix the TX power settings + //TODO Init periodic calibration with reason 3 + b43_nphy_rssi_cal(dev, 2); + b43_nphy_rssi_cal(dev, 0); + b43_nphy_rssi_cal(dev, 1); + //TODO get TX gain + //TODO init superswitch + //TODO calibrate LO + //TODO idle TSSI TX pctl + //TODO TX power control power setup + //TODO table writes + //TODO TX power control coefficients + //TODO enable TX power control + //TODO control antenna selection + //TODO init radar detection + //TODO reset channel if changed b43err(dev->wl, "IEEE 802.11n devices are not supported, yet.\n"); return 0; diff --git a/trunk/drivers/net/wireless/b43/phy_n.h b/trunk/drivers/net/wireless/b43/phy_n.h index 403aad3f894f..1749aef4147d 100644 --- a/trunk/drivers/net/wireless/b43/phy_n.h +++ b/trunk/drivers/net/wireless/b43/phy_n.h @@ -231,7 +231,6 @@ #define B43_NPHY_C2_TXIQ_COMP_OFF B43_PHY_N(0x088) /* Core 2 TX I/Q comp offset */ #define B43_NPHY_C1_TXCTL B43_PHY_N(0x08B) /* Core 1 TX control */ #define B43_NPHY_C2_TXCTL B43_PHY_N(0x08C) /* Core 2 TX control */ -#define B43_NPHY_AFECTL_OVER1 B43_PHY_N(0x08F) /* AFE control override 1 */ #define B43_NPHY_SCRAM_SIGCTL B43_PHY_N(0x090) /* Scram signal control */ #define B43_NPHY_SCRAM_SIGCTL_INITST 0x007F /* Initial state value */ #define B43_NPHY_SCRAM_SIGCTL_INITST_SHIFT 0 @@ -706,10 +705,6 @@ #define B43_NPHY_TXPCTL_INIT B43_PHY_N(0x222) /* TX power controll init */ #define B43_NPHY_TXPCTL_INIT_PIDXI1 0x00FF /* Power index init 1 */ #define B43_NPHY_TXPCTL_INIT_PIDXI1_SHIFT 0 -#define B43_NPHY_PAPD_EN0 B43_PHY_N(0x297) /* PAPD Enable0 TBD */ -#define B43_NPHY_EPS_TABLE_ADJ0 B43_PHY_N(0x298) /* EPS Table Adj0 TBD */ -#define B43_NPHY_PAPD_EN1 B43_PHY_N(0x29B) /* PAPD Enable1 TBD */ -#define B43_NPHY_EPS_TABLE_ADJ1 B43_PHY_N(0x29C) /* EPS Table Adj1 TBD */ @@ -924,99 +919,8 @@ struct b43_wldev; -struct b43_phy_n_iq_comp { - s16 a0; - s16 b0; - s16 a1; - s16 b1; -}; - -struct b43_phy_n_rssical_cache { - u16 rssical_radio_regs_2G[2]; - u16 rssical_phy_regs_2G[12]; - - u16 rssical_radio_regs_5G[2]; - u16 rssical_phy_regs_5G[12]; -}; - -struct b43_phy_n_cal_cache { - u16 txcal_radio_regs_2G[8]; - u16 txcal_coeffs_2G[8]; - struct b43_phy_n_iq_comp rxcal_coeffs_2G; - - u16 txcal_radio_regs_5G[8]; - u16 txcal_coeffs_5G[8]; - struct b43_phy_n_iq_comp rxcal_coeffs_5G; -}; - -struct b43_phy_n_txpwrindex { - s8 index; - s8 index_internal; - s8 index_internal_save; - u16 AfectrlOverride; - u16 AfeCtrlDacGain; - u16 rad_gain; - u8 bbmult; - u16 iqcomp_a; - u16 iqcomp_b; - u16 locomp; -}; - struct b43_phy_n { - u8 antsel_type; - u8 cal_orig_pwr_idx[2]; - u8 measure_hold; - u8 phyrxchain; - u8 perical; - u32 deaf_count; - u32 rxcalparams; - bool hang_avoid; - bool mute; - u16 papd_epsilon_offset[2]; - s32 preamble_override; - u32 bb_mult_save; - u16 radio_chanspec; - - bool gain_boost; - bool elna_gain_config; - bool band5g_pwrgain; - - u8 mphase_cal_phase_id; - u16 mphase_txcal_cmdidx; - u16 mphase_txcal_numcmds; - u16 mphase_txcal_bestcoeffs[11]; - - u8 txpwrctrl; - u16 txcal_bbmult; - u16 txiqlocal_bestc[11]; - bool txiqlocal_coeffsvalid; - struct b43_phy_n_txpwrindex txpwrindex[2]; - - u8 txrx_chain; - u16 tx_rx_cal_phy_saveregs[11]; - u16 tx_rx_cal_radio_saveregs[22]; - - u16 rfctrl_intc1_save; - u16 rfctrl_intc2_save; - - u16 classifier_state; - u16 clip_state[2]; - - bool aband_spurwar_en; - bool gband_spurwar_en; - - bool ipa2g_on; - u8 iqcal_chanspec_2G; - u8 rssical_chanspec_2G; - - bool ipa5g_on; - u8 iqcal_chanspec_5G; - u8 rssical_chanspec_5G; - - struct b43_phy_n_rssical_cache rssical_cache; - struct b43_phy_n_cal_cache cal_cache; - bool crsminpwr_adjusted; - bool noisevars_adjusted; + //TODO lots of missing stuff }; diff --git a/trunk/drivers/net/wireless/b43/pio.c b/trunk/drivers/net/wireless/b43/pio.c index a6062c3e89a5..c01b8e02412f 100644 --- a/trunk/drivers/net/wireless/b43/pio.c +++ b/trunk/drivers/net/wireless/b43/pio.c @@ -559,6 +559,7 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) b43err(dev->wl, "PIO transmission failure\n"); goto out; } + q->nr_tx_packets++; B43_WARN_ON(q->buffer_used > q->buffer_size); if (((q->buffer_size - q->buffer_used) < roundup(2 + 2 + 6, 4)) || @@ -604,6 +605,22 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev, } } +void b43_pio_get_tx_stats(struct b43_wldev *dev, + struct ieee80211_tx_queue_stats *stats) +{ + const int nr_queues = dev->wl->hw->queues; + struct b43_pio_txqueue *q; + int i; + + for (i = 0; i < nr_queues; i++) { + q = select_queue_by_priority(dev, i); + + stats[i].len = B43_PIO_MAX_NR_TXPACKETS - q->free_packet_slots; + stats[i].limit = B43_PIO_MAX_NR_TXPACKETS; + stats[i].count = q->nr_tx_packets; + } +} + /* Returns whether we should fetch another frame. */ static bool pio_rx_frame(struct b43_pio_rxqueue *q) { diff --git a/trunk/drivers/net/wireless/b43/pio.h b/trunk/drivers/net/wireless/b43/pio.h index 1e516147424f..7dd649c9ddad 100644 --- a/trunk/drivers/net/wireless/b43/pio.h +++ b/trunk/drivers/net/wireless/b43/pio.h @@ -55,6 +55,8 @@ #define B43_PIO_MAX_NR_TXPACKETS 32 +#ifdef CONFIG_B43_PIO + struct b43_pio_txpacket { /* Pointer to the TX queue we belong to. */ struct b43_pio_txqueue *queue; @@ -90,6 +92,9 @@ struct b43_pio_txqueue { struct b43_pio_txpacket packets[B43_PIO_MAX_NR_TXPACKETS]; struct list_head packets_list; + /* Total number of transmitted packets. */ + unsigned int nr_tx_packets; + /* Shortcut to the 802.11 core revision. This is to * avoid horrible pointer dereferencing in the fastpaths. */ u8 rev; @@ -157,9 +162,49 @@ void b43_pio_free(struct b43_wldev *dev); int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb); void b43_pio_handle_txstatus(struct b43_wldev *dev, const struct b43_txstatus *status); +void b43_pio_get_tx_stats(struct b43_wldev *dev, + struct ieee80211_tx_queue_stats *stats); void b43_pio_rx(struct b43_pio_rxqueue *q); void b43_pio_tx_suspend(struct b43_wldev *dev); void b43_pio_tx_resume(struct b43_wldev *dev); + +#else /* CONFIG_B43_PIO */ + + +static inline int b43_pio_init(struct b43_wldev *dev) +{ + return 0; +} +static inline void b43_pio_free(struct b43_wldev *dev) +{ +} +static inline void b43_pio_stop(struct b43_wldev *dev) +{ +} +static inline int b43_pio_tx(struct b43_wldev *dev, + struct sk_buff *skb) +{ + return 0; +} +static inline void b43_pio_handle_txstatus(struct b43_wldev *dev, + const struct b43_txstatus *status) +{ +} +static inline void b43_pio_get_tx_stats(struct b43_wldev *dev, + struct ieee80211_tx_queue_stats *stats) +{ +} +static inline void b43_pio_rx(struct b43_pio_rxqueue *q) +{ +} +static inline void b43_pio_tx_suspend(struct b43_wldev *dev) +{ +} +static inline void b43_pio_tx_resume(struct b43_wldev *dev) +{ +} + +#endif /* CONFIG_B43_PIO */ #endif /* B43_PIO_H_ */ diff --git a/trunk/drivers/net/wireless/b43/tables_nphy.c b/trunk/drivers/net/wireless/b43/tables_nphy.c index a00d509150f7..4e2336315545 100644 --- a/trunk/drivers/net/wireless/b43/tables_nphy.c +++ b/trunk/drivers/net/wireless/b43/tables_nphy.c @@ -1336,7 +1336,7 @@ b43_nphy_get_chantabent(struct b43_wldev *dev, u8 channel) } -static const u8 b43_ntab_adjustpower0[] = { +const u8 b43_ntab_adjustpower0[] = { 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, @@ -1355,7 +1355,7 @@ static const u8 b43_ntab_adjustpower0[] = { 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F, }; -static const u8 b43_ntab_adjustpower1[] = { +const u8 b43_ntab_adjustpower1[] = { 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, @@ -1374,11 +1374,11 @@ static const u8 b43_ntab_adjustpower1[] = { 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F, }; -static const u16 b43_ntab_bdi[] = { +const u16 b43_ntab_bdi[] = { 0x0070, 0x0126, 0x012C, 0x0246, 0x048D, 0x04D2, }; -static const u32 b43_ntab_channelest[] = { +const u32 b43_ntab_channelest[] = { 0x44444444, 0x44444444, 0x44444444, 0x44444444, 0x44444444, 0x44444444, 0x44444444, 0x44444444, 0x10101010, 0x10101010, 0x10101010, 0x10101010, @@ -1405,7 +1405,7 @@ static const u32 b43_ntab_channelest[] = { 0x10101010, 0x10101010, 0x10101010, 0x10101010, }; -static const u8 b43_ntab_estimatepowerlt0[] = { +const u8 b43_ntab_estimatepowerlt0[] = { 0x50, 0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49, 0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40, 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, @@ -1416,7 +1416,7 @@ static const u8 b43_ntab_estimatepowerlt0[] = { 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, }; -static const u8 b43_ntab_estimatepowerlt1[] = { +const u8 b43_ntab_estimatepowerlt1[] = { 0x50, 0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49, 0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40, 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, @@ -1427,14 +1427,14 @@ static const u8 b43_ntab_estimatepowerlt1[] = { 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, }; -static const u8 b43_ntab_framelookup[] = { +const u8 b43_ntab_framelookup[] = { 0x02, 0x04, 0x14, 0x14, 0x03, 0x05, 0x16, 0x16, 0x0A, 0x0C, 0x1C, 0x1C, 0x0B, 0x0D, 0x1E, 0x1E, 0x06, 0x08, 0x18, 0x18, 0x07, 0x09, 0x1A, 0x1A, 0x0E, 0x10, 0x20, 0x28, 0x0F, 0x11, 0x22, 0x2A, }; -static const u32 b43_ntab_framestruct[] = { +const u32 b43_ntab_framestruct[] = { 0x08004A04, 0x00100000, 0x01000A05, 0x00100020, 0x09804506, 0x00100030, 0x09804507, 0x00100030, 0x00000000, 0x00000000, 0x00000000, 0x00000000, @@ -1645,7 +1645,7 @@ static const u32 b43_ntab_framestruct[] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000, }; -static const u32 b43_ntab_gainctl0[] = { +const u32 b43_ntab_gainctl0[] = { 0x007F003F, 0x007E013F, 0x007D023E, 0x007C033E, 0x007B043D, 0x007A053D, 0x0079063C, 0x0078073C, 0x0077083B, 0x0076093B, 0x00750A3A, 0x00740B3A, @@ -1680,7 +1680,7 @@ static const u32 b43_ntab_gainctl0[] = { 0x00030C01, 0x00020D01, 0x00010E00, 0x00000F00, }; -static const u32 b43_ntab_gainctl1[] = { +const u32 b43_ntab_gainctl1[] = { 0x007F003F, 0x007E013F, 0x007D023E, 0x007C033E, 0x007B043D, 0x007A053D, 0x0079063C, 0x0078073C, 0x0077083B, 0x0076093B, 0x00750A3A, 0x00740B3A, @@ -1715,12 +1715,12 @@ static const u32 b43_ntab_gainctl1[] = { 0x00030C01, 0x00020D01, 0x00010E00, 0x00000F00, }; -static const u32 b43_ntab_intlevel[] = { +const u32 b43_ntab_intlevel[] = { 0x00802070, 0x0671188D, 0x0A60192C, 0x0A300E46, 0x00C1188D, 0x080024D2, 0x00000070, }; -static const u32 b43_ntab_iqlt0[] = { +const u32 b43_ntab_iqlt0[] = { 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, @@ -1755,7 +1755,7 @@ static const u32 b43_ntab_iqlt0[] = { 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, }; -static const u32 b43_ntab_iqlt1[] = { +const u32 b43_ntab_iqlt1[] = { 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, @@ -1790,7 +1790,7 @@ static const u32 b43_ntab_iqlt1[] = { 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, }; -static const u16 b43_ntab_loftlt0[] = { +const u16 b43_ntab_loftlt0[] = { 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, @@ -1815,7 +1815,7 @@ static const u16 b43_ntab_loftlt0[] = { 0x0002, 0x0103, }; -static const u16 b43_ntab_loftlt1[] = { +const u16 b43_ntab_loftlt1[] = { 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, @@ -1840,7 +1840,7 @@ static const u16 b43_ntab_loftlt1[] = { 0x0002, 0x0103, }; -static const u8 b43_ntab_mcs[] = { +const u8 b43_ntab_mcs[] = { 0x00, 0x08, 0x0A, 0x10, 0x12, 0x19, 0x1A, 0x1C, 0x40, 0x48, 0x4A, 0x50, 0x52, 0x59, 0x5A, 0x5C, 0x80, 0x88, 0x8A, 0x90, 0x92, 0x99, 0x9A, 0x9C, @@ -1859,7 +1859,7 @@ static const u8 b43_ntab_mcs[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; -static const u32 b43_ntab_noisevar10[] = { +const u32 b43_ntab_noisevar10[] = { 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, @@ -1926,7 +1926,7 @@ static const u32 b43_ntab_noisevar10[] = { 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, }; -static const u32 b43_ntab_noisevar11[] = { +const u32 b43_ntab_noisevar11[] = { 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, @@ -1993,7 +1993,7 @@ static const u32 b43_ntab_noisevar11[] = { 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, }; -static const u16 b43_ntab_pilot[] = { +const u16 b43_ntab_pilot[] = { 0xFF08, 0xFF08, 0xFF08, 0xFF08, 0xFF08, 0xFF08, 0xFF08, 0xFF08, 0x80D5, 0x80D5, 0x80D5, 0x80D5, 0x80D5, 0x80D5, 0x80D5, 0x80D5, 0xFF0A, 0xFF82, @@ -2011,12 +2011,12 @@ static const u16 b43_ntab_pilot[] = { 0xF0A0, 0xF028, 0xFFFF, 0xFFFF, }; -static const u32 b43_ntab_pilotlt[] = { +const u32 b43_ntab_pilotlt[] = { 0x76540123, 0x62407351, 0x76543201, 0x76540213, 0x76540123, 0x76430521, }; -static const u32 b43_ntab_tdi20a0[] = { +const u32 b43_ntab_tdi20a0[] = { 0x00091226, 0x000A1429, 0x000B56AD, 0x000C58B0, 0x000D5AB3, 0x000E9CB6, 0x000F9EBA, 0x0000C13D, 0x00020301, 0x00030504, 0x00040708, 0x0005090B, @@ -2033,7 +2033,7 @@ static const u32 b43_ntab_tdi20a0[] = { 0x00000000, 0x00000000, 0x00000000, }; -static const u32 b43_ntab_tdi20a1[] = { +const u32 b43_ntab_tdi20a1[] = { 0x00014B26, 0x00028D29, 0x000393AD, 0x00049630, 0x0005D833, 0x0006DA36, 0x00099C3A, 0x000A9E3D, 0x000BC081, 0x000CC284, 0x000DC488, 0x000F068B, @@ -2050,7 +2050,7 @@ static const u32 b43_ntab_tdi20a1[] = { 0x00000000, 0x00000000, 0x00000000, }; -static const u32 b43_ntab_tdi40a0[] = { +const u32 b43_ntab_tdi40a0[] = { 0x0011A346, 0x00136CCF, 0x0014F5D9, 0x001641E2, 0x0017CB6B, 0x00195475, 0x001B2383, 0x001CAD0C, 0x001E7616, 0x0000821F, 0x00020BA8, 0x0003D4B2, @@ -2081,7 +2081,7 @@ static const u32 b43_ntab_tdi40a0[] = { 0x00000000, 0x00000000, }; -static const u32 b43_ntab_tdi40a1[] = { +const u32 b43_ntab_tdi40a1[] = { 0x001EDB36, 0x000129CA, 0x0002B353, 0x00047CDD, 0x0005C8E6, 0x000791EF, 0x00091BF9, 0x000AAA07, 0x000C3391, 0x000DFD1A, 0x00120923, 0x0013D22D, @@ -2112,7 +2112,7 @@ static const u32 b43_ntab_tdi40a1[] = { 0x00000000, 0x00000000, }; -static const u32 b43_ntab_tdtrn[] = { +const u32 b43_ntab_tdtrn[] = { 0x061C061C, 0x0050EE68, 0xF592FE36, 0xFE5212F6, 0x00000C38, 0xFE5212F6, 0xF592FE36, 0x0050EE68, 0x061C061C, 0xEE680050, 0xFE36F592, 0x12F6FE52, @@ -2291,7 +2291,7 @@ static const u32 b43_ntab_tdtrn[] = { 0xFA58FC00, 0x0B64FC7E, 0x0800F7B6, 0x00F006BE, }; -static const u32 b43_ntab_tmap[] = { +const u32 b43_ntab_tmap[] = { 0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00000888, 0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8, 0xF1111110, 0x11111111, 0x11F11111, 0x00000111, @@ -2406,544 +2406,6 @@ static const u32 b43_ntab_tmap[] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000, }; -const u32 b43_ntab_tx_gain_rev0_1_2[] = { - 0x03cc2b44, 0x03cc2b42, 0x03cc2a44, 0x03cc2a42, - 0x03cc2944, 0x03c82b44, 0x03c82b42, 0x03c82a44, - 0x03c82a42, 0x03c82944, 0x03c82942, 0x03c82844, - 0x03c82842, 0x03c42b44, 0x03c42b42, 0x03c42a44, - 0x03c42a42, 0x03c42944, 0x03c42942, 0x03c42844, - 0x03c42842, 0x03c42744, 0x03c42742, 0x03c42644, - 0x03c42642, 0x03c42544, 0x03c42542, 0x03c42444, - 0x03c42442, 0x03c02b44, 0x03c02b42, 0x03c02a44, - 0x03c02a42, 0x03c02944, 0x03c02942, 0x03c02844, - 0x03c02842, 0x03c02744, 0x03c02742, 0x03b02b44, - 0x03b02b42, 0x03b02a44, 0x03b02a42, 0x03b02944, - 0x03b02942, 0x03b02844, 0x03b02842, 0x03b02744, - 0x03b02742, 0x03b02644, 0x03b02642, 0x03b02544, - 0x03b02542, 0x03a02b44, 0x03a02b42, 0x03a02a44, - 0x03a02a42, 0x03a02944, 0x03a02942, 0x03a02844, - 0x03a02842, 0x03a02744, 0x03a02742, 0x03902b44, - 0x03902b42, 0x03902a44, 0x03902a42, 0x03902944, - 0x03902942, 0x03902844, 0x03902842, 0x03902744, - 0x03902742, 0x03902644, 0x03902642, 0x03902544, - 0x03902542, 0x03802b44, 0x03802b42, 0x03802a44, - 0x03802a42, 0x03802944, 0x03802942, 0x03802844, - 0x03802842, 0x03802744, 0x03802742, 0x03802644, - 0x03802642, 0x03802544, 0x03802542, 0x03802444, - 0x03802442, 0x03802344, 0x03802342, 0x03802244, - 0x03802242, 0x03802144, 0x03802142, 0x03802044, - 0x03802042, 0x03801f44, 0x03801f42, 0x03801e44, - 0x03801e42, 0x03801d44, 0x03801d42, 0x03801c44, - 0x03801c42, 0x03801b44, 0x03801b42, 0x03801a44, - 0x03801a42, 0x03801944, 0x03801942, 0x03801844, - 0x03801842, 0x03801744, 0x03801742, 0x03801644, - 0x03801642, 0x03801544, 0x03801542, 0x03801444, - 0x03801442, 0x03801344, 0x03801342, 0x00002b00, -}; - -const u32 b43_ntab_tx_gain_rev3plus_2ghz[] = { - 0x1f410044, 0x1f410042, 0x1f410040, 0x1f41003e, - 0x1f41003c, 0x1f41003b, 0x1f410039, 0x1f410037, - 0x1e410044, 0x1e410042, 0x1e410040, 0x1e41003e, - 0x1e41003c, 0x1e41003b, 0x1e410039, 0x1e410037, - 0x1d410044, 0x1d410042, 0x1d410040, 0x1d41003e, - 0x1d41003c, 0x1d41003b, 0x1d410039, 0x1d410037, - 0x1c410044, 0x1c410042, 0x1c410040, 0x1c41003e, - 0x1c41003c, 0x1c41003b, 0x1c410039, 0x1c410037, - 0x1b410044, 0x1b410042, 0x1b410040, 0x1b41003e, - 0x1b41003c, 0x1b41003b, 0x1b410039, 0x1b410037, - 0x1a410044, 0x1a410042, 0x1a410040, 0x1a41003e, - 0x1a41003c, 0x1a41003b, 0x1a410039, 0x1a410037, - 0x19410044, 0x19410042, 0x19410040, 0x1941003e, - 0x1941003c, 0x1941003b, 0x19410039, 0x19410037, - 0x18410044, 0x18410042, 0x18410040, 0x1841003e, - 0x1841003c, 0x1841003b, 0x18410039, 0x18410037, - 0x17410044, 0x17410042, 0x17410040, 0x1741003e, - 0x1741003c, 0x1741003b, 0x17410039, 0x17410037, - 0x16410044, 0x16410042, 0x16410040, 0x1641003e, - 0x1641003c, 0x1641003b, 0x16410039, 0x16410037, - 0x15410044, 0x15410042, 0x15410040, 0x1541003e, - 0x1541003c, 0x1541003b, 0x15410039, 0x15410037, - 0x14410044, 0x14410042, 0x14410040, 0x1441003e, - 0x1441003c, 0x1441003b, 0x14410039, 0x14410037, - 0x13410044, 0x13410042, 0x13410040, 0x1341003e, - 0x1341003c, 0x1341003b, 0x13410039, 0x13410037, - 0x12410044, 0x12410042, 0x12410040, 0x1241003e, - 0x1241003c, 0x1241003b, 0x12410039, 0x12410037, - 0x11410044, 0x11410042, 0x11410040, 0x1141003e, - 0x1141003c, 0x1141003b, 0x11410039, 0x11410037, - 0x10410044, 0x10410042, 0x10410040, 0x1041003e, - 0x1041003c, 0x1041003b, 0x10410039, 0x10410037, -}; - -const u32 b43_ntab_tx_gain_rev3_5ghz[] = { - 0xcff70044, 0xcff70042, 0xcff70040, 0xcff7003e, - 0xcff7003c, 0xcff7003b, 0xcff70039, 0xcff70037, - 0xcef70044, 0xcef70042, 0xcef70040, 0xcef7003e, - 0xcef7003c, 0xcef7003b, 0xcef70039, 0xcef70037, - 0xcdf70044, 0xcdf70042, 0xcdf70040, 0xcdf7003e, - 0xcdf7003c, 0xcdf7003b, 0xcdf70039, 0xcdf70037, - 0xccf70044, 0xccf70042, 0xccf70040, 0xccf7003e, - 0xccf7003c, 0xccf7003b, 0xccf70039, 0xccf70037, - 0xcbf70044, 0xcbf70042, 0xcbf70040, 0xcbf7003e, - 0xcbf7003c, 0xcbf7003b, 0xcbf70039, 0xcbf70037, - 0xcaf70044, 0xcaf70042, 0xcaf70040, 0xcaf7003e, - 0xcaf7003c, 0xcaf7003b, 0xcaf70039, 0xcaf70037, - 0xc9f70044, 0xc9f70042, 0xc9f70040, 0xc9f7003e, - 0xc9f7003c, 0xc9f7003b, 0xc9f70039, 0xc9f70037, - 0xc8f70044, 0xc8f70042, 0xc8f70040, 0xc8f7003e, - 0xc8f7003c, 0xc8f7003b, 0xc8f70039, 0xc8f70037, - 0xc7f70044, 0xc7f70042, 0xc7f70040, 0xc7f7003e, - 0xc7f7003c, 0xc7f7003b, 0xc7f70039, 0xc7f70037, - 0xc6f70044, 0xc6f70042, 0xc6f70040, 0xc6f7003e, - 0xc6f7003c, 0xc6f7003b, 0xc6f70039, 0xc6f70037, - 0xc5f70044, 0xc5f70042, 0xc5f70040, 0xc5f7003e, - 0xc5f7003c, 0xc5f7003b, 0xc5f70039, 0xc5f70037, - 0xc4f70044, 0xc4f70042, 0xc4f70040, 0xc4f7003e, - 0xc4f7003c, 0xc4f7003b, 0xc4f70039, 0xc4f70037, - 0xc3f70044, 0xc3f70042, 0xc3f70040, 0xc3f7003e, - 0xc3f7003c, 0xc3f7003b, 0xc3f70039, 0xc3f70037, - 0xc2f70044, 0xc2f70042, 0xc2f70040, 0xc2f7003e, - 0xc2f7003c, 0xc2f7003b, 0xc2f70039, 0xc2f70037, - 0xc1f70044, 0xc1f70042, 0xc1f70040, 0xc1f7003e, - 0xc1f7003c, 0xc1f7003b, 0xc1f70039, 0xc1f70037, - 0xc0f70044, 0xc0f70042, 0xc0f70040, 0xc0f7003e, - 0xc0f7003c, 0xc0f7003b, 0xc0f70039, 0xc0f70037, -}; - -const u32 b43_ntab_tx_gain_rev4_5ghz[] = { - 0x2ff20044, 0x2ff20042, 0x2ff20040, 0x2ff2003e, - 0x2ff2003c, 0x2ff2003b, 0x2ff20039, 0x2ff20037, - 0x2ef20044, 0x2ef20042, 0x2ef20040, 0x2ef2003e, - 0x2ef2003c, 0x2ef2003b, 0x2ef20039, 0x2ef20037, - 0x2df20044, 0x2df20042, 0x2df20040, 0x2df2003e, - 0x2df2003c, 0x2df2003b, 0x2df20039, 0x2df20037, - 0x2cf20044, 0x2cf20042, 0x2cf20040, 0x2cf2003e, - 0x2cf2003c, 0x2cf2003b, 0x2cf20039, 0x2cf20037, - 0x2bf20044, 0x2bf20042, 0x2bf20040, 0x2bf2003e, - 0x2bf2003c, 0x2bf2003b, 0x2bf20039, 0x2bf20037, - 0x2af20044, 0x2af20042, 0x2af20040, 0x2af2003e, - 0x2af2003c, 0x2af2003b, 0x2af20039, 0x2af20037, - 0x29f20044, 0x29f20042, 0x29f20040, 0x29f2003e, - 0x29f2003c, 0x29f2003b, 0x29f20039, 0x29f20037, - 0x28f20044, 0x28f20042, 0x28f20040, 0x28f2003e, - 0x28f2003c, 0x28f2003b, 0x28f20039, 0x28f20037, - 0x27f20044, 0x27f20042, 0x27f20040, 0x27f2003e, - 0x27f2003c, 0x27f2003b, 0x27f20039, 0x27f20037, - 0x26f20044, 0x26f20042, 0x26f20040, 0x26f2003e, - 0x26f2003c, 0x26f2003b, 0x26f20039, 0x26f20037, - 0x25f20044, 0x25f20042, 0x25f20040, 0x25f2003e, - 0x25f2003c, 0x25f2003b, 0x25f20039, 0x25f20037, - 0x24f20044, 0x24f20042, 0x24f20040, 0x24f2003e, - 0x24f2003c, 0x24f2003b, 0x24f20039, 0x24f20038, - 0x23f20041, 0x23f20040, 0x23f2003f, 0x23f2003e, - 0x23f2003c, 0x23f2003b, 0x23f20039, 0x23f20037, - 0x22f20044, 0x22f20042, 0x22f20040, 0x22f2003e, - 0x22f2003c, 0x22f2003b, 0x22f20039, 0x22f20037, - 0x21f20044, 0x21f20042, 0x21f20040, 0x21f2003e, - 0x21f2003c, 0x21f2003b, 0x21f20039, 0x21f20037, - 0x20d20043, 0x20d20041, 0x20d2003e, 0x20d2003c, - 0x20d2003a, 0x20d20038, 0x20d20036, 0x20d20034, -}; - -const u32 b43_ntab_tx_gain_rev5plus_5ghz[] = { - 0x0f62004a, 0x0f620048, 0x0f620046, 0x0f620044, - 0x0f620042, 0x0f620040, 0x0f62003e, 0x0f62003c, - 0x0e620044, 0x0e620042, 0x0e620040, 0x0e62003e, - 0x0e62003c, 0x0e62003d, 0x0e62003b, 0x0e62003a, - 0x0d620043, 0x0d620041, 0x0d620040, 0x0d62003e, - 0x0d62003d, 0x0d62003c, 0x0d62003b, 0x0d62003a, - 0x0c620041, 0x0c620040, 0x0c62003f, 0x0c62003e, - 0x0c62003c, 0x0c62003b, 0x0c620039, 0x0c620037, - 0x0b620046, 0x0b620044, 0x0b620042, 0x0b620040, - 0x0b62003e, 0x0b62003c, 0x0b62003b, 0x0b62003a, - 0x0a620041, 0x0a620040, 0x0a62003e, 0x0a62003c, - 0x0a62003b, 0x0a62003a, 0x0a620039, 0x0a620038, - 0x0962003e, 0x0962003d, 0x0962003c, 0x0962003b, - 0x09620039, 0x09620037, 0x09620035, 0x09620033, - 0x08620044, 0x08620042, 0x08620040, 0x0862003e, - 0x0862003c, 0x0862003b, 0x0862003a, 0x08620039, - 0x07620043, 0x07620042, 0x07620040, 0x0762003f, - 0x0762003d, 0x0762003b, 0x0762003a, 0x07620039, - 0x0662003e, 0x0662003d, 0x0662003c, 0x0662003b, - 0x06620039, 0x06620037, 0x06620035, 0x06620033, - 0x05620046, 0x05620044, 0x05620042, 0x05620040, - 0x0562003e, 0x0562003c, 0x0562003b, 0x05620039, - 0x04620044, 0x04620042, 0x04620040, 0x0462003e, - 0x0462003c, 0x0462003b, 0x04620039, 0x04620038, - 0x0362003c, 0x0362003b, 0x0362003a, 0x03620039, - 0x03620038, 0x03620037, 0x03620035, 0x03620033, - 0x0262004c, 0x0262004a, 0x02620048, 0x02620047, - 0x02620046, 0x02620044, 0x02620043, 0x02620042, - 0x0162004a, 0x01620048, 0x01620046, 0x01620044, - 0x01620043, 0x01620042, 0x01620041, 0x01620040, - 0x00620042, 0x00620040, 0x0062003e, 0x0062003c, - 0x0062003b, 0x00620039, 0x00620037, 0x00620035, -}; - -const u32 txpwrctrl_tx_gain_ipa[] = { - 0x5ff7002d, 0x5ff7002b, 0x5ff7002a, 0x5ff70029, - 0x5ff70028, 0x5ff70027, 0x5ff70026, 0x5ff70025, - 0x5ef7002d, 0x5ef7002b, 0x5ef7002a, 0x5ef70029, - 0x5ef70028, 0x5ef70027, 0x5ef70026, 0x5ef70025, - 0x5df7002d, 0x5df7002b, 0x5df7002a, 0x5df70029, - 0x5df70028, 0x5df70027, 0x5df70026, 0x5df70025, - 0x5cf7002d, 0x5cf7002b, 0x5cf7002a, 0x5cf70029, - 0x5cf70028, 0x5cf70027, 0x5cf70026, 0x5cf70025, - 0x5bf7002d, 0x5bf7002b, 0x5bf7002a, 0x5bf70029, - 0x5bf70028, 0x5bf70027, 0x5bf70026, 0x5bf70025, - 0x5af7002d, 0x5af7002b, 0x5af7002a, 0x5af70029, - 0x5af70028, 0x5af70027, 0x5af70026, 0x5af70025, - 0x59f7002d, 0x59f7002b, 0x59f7002a, 0x59f70029, - 0x59f70028, 0x59f70027, 0x59f70026, 0x59f70025, - 0x58f7002d, 0x58f7002b, 0x58f7002a, 0x58f70029, - 0x58f70028, 0x58f70027, 0x58f70026, 0x58f70025, - 0x57f7002d, 0x57f7002b, 0x57f7002a, 0x57f70029, - 0x57f70028, 0x57f70027, 0x57f70026, 0x57f70025, - 0x56f7002d, 0x56f7002b, 0x56f7002a, 0x56f70029, - 0x56f70028, 0x56f70027, 0x56f70026, 0x56f70025, - 0x55f7002d, 0x55f7002b, 0x55f7002a, 0x55f70029, - 0x55f70028, 0x55f70027, 0x55f70026, 0x55f70025, - 0x54f7002d, 0x54f7002b, 0x54f7002a, 0x54f70029, - 0x54f70028, 0x54f70027, 0x54f70026, 0x54f70025, - 0x53f7002d, 0x53f7002b, 0x53f7002a, 0x53f70029, - 0x53f70028, 0x53f70027, 0x53f70026, 0x53f70025, - 0x52f7002d, 0x52f7002b, 0x52f7002a, 0x52f70029, - 0x52f70028, 0x52f70027, 0x52f70026, 0x52f70025, - 0x51f7002d, 0x51f7002b, 0x51f7002a, 0x51f70029, - 0x51f70028, 0x51f70027, 0x51f70026, 0x51f70025, - 0x50f7002d, 0x50f7002b, 0x50f7002a, 0x50f70029, - 0x50f70028, 0x50f70027, 0x50f70026, 0x50f70025, -}; - -const u32 txpwrctrl_tx_gain_ipa_rev5[] = { - 0x1ff7002d, 0x1ff7002b, 0x1ff7002a, 0x1ff70029, - 0x1ff70028, 0x1ff70027, 0x1ff70026, 0x1ff70025, - 0x1ef7002d, 0x1ef7002b, 0x1ef7002a, 0x1ef70029, - 0x1ef70028, 0x1ef70027, 0x1ef70026, 0x1ef70025, - 0x1df7002d, 0x1df7002b, 0x1df7002a, 0x1df70029, - 0x1df70028, 0x1df70027, 0x1df70026, 0x1df70025, - 0x1cf7002d, 0x1cf7002b, 0x1cf7002a, 0x1cf70029, - 0x1cf70028, 0x1cf70027, 0x1cf70026, 0x1cf70025, - 0x1bf7002d, 0x1bf7002b, 0x1bf7002a, 0x1bf70029, - 0x1bf70028, 0x1bf70027, 0x1bf70026, 0x1bf70025, - 0x1af7002d, 0x1af7002b, 0x1af7002a, 0x1af70029, - 0x1af70028, 0x1af70027, 0x1af70026, 0x1af70025, - 0x19f7002d, 0x19f7002b, 0x19f7002a, 0x19f70029, - 0x19f70028, 0x19f70027, 0x19f70026, 0x19f70025, - 0x18f7002d, 0x18f7002b, 0x18f7002a, 0x18f70029, - 0x18f70028, 0x18f70027, 0x18f70026, 0x18f70025, - 0x17f7002d, 0x17f7002b, 0x17f7002a, 0x17f70029, - 0x17f70028, 0x17f70027, 0x17f70026, 0x17f70025, - 0x16f7002d, 0x16f7002b, 0x16f7002a, 0x16f70029, - 0x16f70028, 0x16f70027, 0x16f70026, 0x16f70025, - 0x15f7002d, 0x15f7002b, 0x15f7002a, 0x15f70029, - 0x15f70028, 0x15f70027, 0x15f70026, 0x15f70025, - 0x14f7002d, 0x14f7002b, 0x14f7002a, 0x14f70029, - 0x14f70028, 0x14f70027, 0x14f70026, 0x14f70025, - 0x13f7002d, 0x13f7002b, 0x13f7002a, 0x13f70029, - 0x13f70028, 0x13f70027, 0x13f70026, 0x13f70025, - 0x12f7002d, 0x12f7002b, 0x12f7002a, 0x12f70029, - 0x12f70028, 0x12f70027, 0x12f70026, 0x12f70025, - 0x11f7002d, 0x11f7002b, 0x11f7002a, 0x11f70029, - 0x11f70028, 0x11f70027, 0x11f70026, 0x11f70025, - 0x10f7002d, 0x10f7002b, 0x10f7002a, 0x10f70029, - 0x10f70028, 0x10f70027, 0x10f70026, 0x10f70025, -}; - -const u32 txpwrctrl_tx_gain_ipa_rev6[] = { - 0x0ff7002d, 0x0ff7002b, 0x0ff7002a, 0x0ff70029, - 0x0ff70028, 0x0ff70027, 0x0ff70026, 0x0ff70025, - 0x0ef7002d, 0x0ef7002b, 0x0ef7002a, 0x0ef70029, - 0x0ef70028, 0x0ef70027, 0x0ef70026, 0x0ef70025, - 0x0df7002d, 0x0df7002b, 0x0df7002a, 0x0df70029, - 0x0df70028, 0x0df70027, 0x0df70026, 0x0df70025, - 0x0cf7002d, 0x0cf7002b, 0x0cf7002a, 0x0cf70029, - 0x0cf70028, 0x0cf70027, 0x0cf70026, 0x0cf70025, - 0x0bf7002d, 0x0bf7002b, 0x0bf7002a, 0x0bf70029, - 0x0bf70028, 0x0bf70027, 0x0bf70026, 0x0bf70025, - 0x0af7002d, 0x0af7002b, 0x0af7002a, 0x0af70029, - 0x0af70028, 0x0af70027, 0x0af70026, 0x0af70025, - 0x09f7002d, 0x09f7002b, 0x09f7002a, 0x09f70029, - 0x09f70028, 0x09f70027, 0x09f70026, 0x09f70025, - 0x08f7002d, 0x08f7002b, 0x08f7002a, 0x08f70029, - 0x08f70028, 0x08f70027, 0x08f70026, 0x08f70025, - 0x07f7002d, 0x07f7002b, 0x07f7002a, 0x07f70029, - 0x07f70028, 0x07f70027, 0x07f70026, 0x07f70025, - 0x06f7002d, 0x06f7002b, 0x06f7002a, 0x06f70029, - 0x06f70028, 0x06f70027, 0x06f70026, 0x06f70025, - 0x05f7002d, 0x05f7002b, 0x05f7002a, 0x05f70029, - 0x05f70028, 0x05f70027, 0x05f70026, 0x05f70025, - 0x04f7002d, 0x04f7002b, 0x04f7002a, 0x04f70029, - 0x04f70028, 0x04f70027, 0x04f70026, 0x04f70025, - 0x03f7002d, 0x03f7002b, 0x03f7002a, 0x03f70029, - 0x03f70028, 0x03f70027, 0x03f70026, 0x03f70025, - 0x02f7002d, 0x02f7002b, 0x02f7002a, 0x02f70029, - 0x02f70028, 0x02f70027, 0x02f70026, 0x02f70025, - 0x01f7002d, 0x01f7002b, 0x01f7002a, 0x01f70029, - 0x01f70028, 0x01f70027, 0x01f70026, 0x01f70025, - 0x00f7002d, 0x00f7002b, 0x00f7002a, 0x00f70029, - 0x00f70028, 0x00f70027, 0x00f70026, 0x00f70025, -}; - -const u32 txpwrctrl_tx_gain_ipa_5g[] = { - 0x7ff70035, 0x7ff70033, 0x7ff70032, 0x7ff70031, - 0x7ff7002f, 0x7ff7002e, 0x7ff7002d, 0x7ff7002b, - 0x7ff7002a, 0x7ff70029, 0x7ff70028, 0x7ff70027, - 0x7ff70026, 0x7ff70024, 0x7ff70023, 0x7ff70022, - 0x7ef70028, 0x7ef70027, 0x7ef70026, 0x7ef70025, - 0x7ef70024, 0x7ef70023, 0x7df70028, 0x7df70027, - 0x7df70026, 0x7df70025, 0x7df70024, 0x7df70023, - 0x7df70022, 0x7cf70029, 0x7cf70028, 0x7cf70027, - 0x7cf70026, 0x7cf70025, 0x7cf70023, 0x7cf70022, - 0x7bf70029, 0x7bf70028, 0x7bf70026, 0x7bf70025, - 0x7bf70024, 0x7bf70023, 0x7bf70022, 0x7bf70021, - 0x7af70029, 0x7af70028, 0x7af70027, 0x7af70026, - 0x7af70025, 0x7af70024, 0x7af70023, 0x7af70022, - 0x79f70029, 0x79f70028, 0x79f70027, 0x79f70026, - 0x79f70025, 0x79f70024, 0x79f70023, 0x79f70022, - 0x78f70029, 0x78f70028, 0x78f70027, 0x78f70026, - 0x78f70025, 0x78f70024, 0x78f70023, 0x78f70022, - 0x77f70029, 0x77f70028, 0x77f70027, 0x77f70026, - 0x77f70025, 0x77f70024, 0x77f70023, 0x77f70022, - 0x76f70029, 0x76f70028, 0x76f70027, 0x76f70026, - 0x76f70024, 0x76f70023, 0x76f70022, 0x76f70021, - 0x75f70029, 0x75f70028, 0x75f70027, 0x75f70026, - 0x75f70025, 0x75f70024, 0x75f70023, 0x74f70029, - 0x74f70028, 0x74f70026, 0x74f70025, 0x74f70024, - 0x74f70023, 0x74f70022, 0x73f70029, 0x73f70027, - 0x73f70026, 0x73f70025, 0x73f70024, 0x73f70023, - 0x73f70022, 0x72f70028, 0x72f70027, 0x72f70026, - 0x72f70025, 0x72f70024, 0x72f70023, 0x72f70022, - 0x71f70028, 0x71f70027, 0x71f70026, 0x71f70025, - 0x71f70024, 0x71f70023, 0x70f70028, 0x70f70027, - 0x70f70026, 0x70f70024, 0x70f70023, 0x70f70022, - 0x70f70021, 0x70f70020, 0x70f70020, 0x70f7001f, -}; - -const u16 tbl_iqcal_gainparams[2][9][8] = { - { - { 0x000, 0, 0, 2, 0x69, 0x69, 0x69, 0x69 }, - { 0x700, 7, 0, 0, 0x69, 0x69, 0x69, 0x69 }, - { 0x710, 7, 1, 0, 0x68, 0x68, 0x68, 0x68 }, - { 0x720, 7, 2, 0, 0x67, 0x67, 0x67, 0x67 }, - { 0x730, 7, 3, 0, 0x66, 0x66, 0x66, 0x66 }, - { 0x740, 7, 4, 0, 0x65, 0x65, 0x65, 0x65 }, - { 0x741, 7, 4, 1, 0x65, 0x65, 0x65, 0x65 }, - { 0x742, 7, 4, 2, 0x65, 0x65, 0x65, 0x65 }, - { 0x743, 7, 4, 3, 0x65, 0x65, 0x65, 0x65 } - }, - { - { 0x000, 7, 0, 0, 0x79, 0x79, 0x79, 0x79 }, - { 0x700, 7, 0, 0, 0x79, 0x79, 0x79, 0x79 }, - { 0x710, 7, 1, 0, 0x79, 0x79, 0x79, 0x79 }, - { 0x720, 7, 2, 0, 0x78, 0x78, 0x78, 0x78 }, - { 0x730, 7, 3, 0, 0x78, 0x78, 0x78, 0x78 }, - { 0x740, 7, 4, 0, 0x78, 0x78, 0x78, 0x78 }, - { 0x741, 7, 4, 1, 0x78, 0x78, 0x78, 0x78 }, - { 0x742, 7, 4, 2, 0x78, 0x78, 0x78, 0x78 }, - { 0x743, 7, 4, 3, 0x78, 0x78, 0x78, 0x78 } - } -}; - -const struct nphy_txiqcal_ladder ladder_lo[] = { - { 3, 0 }, - { 4, 0 }, - { 6, 0 }, - { 9, 0 }, - { 13, 0 }, - { 18, 0 }, - { 25, 0 }, - { 25, 1 }, - { 25, 2 }, - { 25, 3 }, - { 25, 4 }, - { 25, 5 }, - { 25, 6 }, - { 25, 7 }, - { 35, 7 }, - { 50, 7 }, - { 71, 7 }, - { 100, 7 } -}; - -const struct nphy_txiqcal_ladder ladder_iq[] = { - { 3, 0 }, - { 4, 0 }, - { 6, 0 }, - { 9, 0 }, - { 13, 0 }, - { 18, 0 }, - { 25, 0 }, - { 35, 0 }, - { 50, 0 }, - { 71, 0 }, - { 100, 0 }, - { 100, 1 }, - { 100, 2 }, - { 100, 3 }, - { 100, 4 }, - { 100, 5 }, - { 100, 6 }, - { 100, 7 } -}; - -const u16 loscale[] = { - 256, 256, 271, 271, - 287, 256, 256, 271, - 271, 287, 287, 304, - 304, 256, 256, 271, - 271, 287, 287, 304, - 304, 322, 322, 341, - 341, 362, 362, 383, - 383, 256, 256, 271, - 271, 287, 287, 304, - 304, 322, 322, 256, - 256, 271, 271, 287, - 287, 304, 304, 322, - 322, 341, 341, 362, - 362, 256, 256, 271, - 271, 287, 287, 304, - 304, 322, 322, 256, - 256, 271, 271, 287, - 287, 304, 304, 322, - 322, 341, 341, 362, - 362, 256, 256, 271, - 271, 287, 287, 304, - 304, 322, 322, 341, - 341, 362, 362, 383, - 383, 406, 406, 430, - 430, 455, 455, 482, - 482, 511, 511, 541, - 541, 573, 573, 607, - 607, 643, 643, 681, - 681, 722, 722, 764, - 764, 810, 810, 858, - 858, 908, 908, 962, - 962, 1019, 1019, 256 -}; - -const u16 tbl_tx_iqlo_cal_loft_ladder_40[] = { - 0x0200, 0x0300, 0x0400, 0x0700, - 0x0900, 0x0c00, 0x1200, 0x1201, - 0x1202, 0x1203, 0x1204, 0x1205, - 0x1206, 0x1207, 0x1907, 0x2307, - 0x3207, 0x4707 -}; - -const u16 tbl_tx_iqlo_cal_loft_ladder_20[] = { - 0x0300, 0x0500, 0x0700, 0x0900, - 0x0d00, 0x1100, 0x1900, 0x1901, - 0x1902, 0x1903, 0x1904, 0x1905, - 0x1906, 0x1907, 0x2407, 0x3207, - 0x4607, 0x6407 -}; - -const u16 tbl_tx_iqlo_cal_iqimb_ladder_40[] = { - 0x0100, 0x0200, 0x0400, 0x0700, - 0x0900, 0x0c00, 0x1200, 0x1900, - 0x2300, 0x3200, 0x4700, 0x4701, - 0x4702, 0x4703, 0x4704, 0x4705, - 0x4706, 0x4707 -}; - -const u16 tbl_tx_iqlo_cal_iqimb_ladder_20[] = { - 0x0200, 0x0300, 0x0600, 0x0900, - 0x0d00, 0x1100, 0x1900, 0x2400, - 0x3200, 0x4600, 0x6400, 0x6401, - 0x6402, 0x6403, 0x6404, 0x6405, - 0x6406, 0x6407 -}; - -const u16 tbl_tx_iqlo_cal_startcoefs_nphyrev3[B43_NTAB_TX_IQLO_CAL_STARTCOEFS_REV3] = { }; - -const u16 tbl_tx_iqlo_cal_startcoefs[B43_NTAB_TX_IQLO_CAL_STARTCOEFS] = { }; - -const u16 tbl_tx_iqlo_cal_cmds_recal_nphyrev3[] = { - 0x8423, 0x8323, 0x8073, 0x8256, - 0x8045, 0x8223, 0x9423, 0x9323, - 0x9073, 0x9256, 0x9045, 0x9223 -}; - -const u16 tbl_tx_iqlo_cal_cmds_recal[] = { - 0x8101, 0x8253, 0x8053, 0x8234, - 0x8034, 0x9101, 0x9253, 0x9053, - 0x9234, 0x9034 -}; - -const u16 tbl_tx_iqlo_cal_cmds_fullcal[] = { - 0x8123, 0x8264, 0x8086, 0x8245, - 0x8056, 0x9123, 0x9264, 0x9086, - 0x9245, 0x9056 -}; - -const u16 tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3[] = { - 0x8434, 0x8334, 0x8084, 0x8267, - 0x8056, 0x8234, 0x9434, 0x9334, - 0x9084, 0x9267, 0x9056, 0x9234 -}; - -const s16 tbl_tx_filter_coef_rev4[7][15] = { - { -377, 137, -407, 208, -1527, - 956, 93, 186, 93, 230, - -44, 230, 20, -191, 201 }, - { -77, 20, -98, 49, -93, - 60, 56, 111, 56, 26, - -5, 26, 34, -32, 34 }, - { -360, 164, -376, 164, -1533, - 576, 308, -314, 308, 121, - -73, 121, 91, 124, 91 }, - { -295, 200, -363, 142, -1391, - 826, 151, 301, 151, 151, - 301, 151, 602, -752, 602 }, - { -92, 58, -96, 49, -104, - 44, 17, 35, 17, 12, - 25, 12, 13, 27, 13 }, - { -375, 136, -399, 209, -1479, - 949, 130, 260, 130, 230, - -44, 230, 201, -191, 201 }, - { 0xed9, 0xc8, 0xe95, 0x8e, 0xa91, - 0x33a, 0x97, 0x12d, 0x97, 0x97, - 0x12d, 0x97, 0x25a, 0xd10, 0x25a } -}; - -/* addr0, addr1, bmask, shift */ -const struct nphy_rf_control_override_rev2 tbl_rf_control_override_rev2[] = { - { 0x78, 0x78, 0x0038, 3 }, /* for field == 0x0002 (fls == 2) */ - { 0x7A, 0x7D, 0x0001, 0 }, /* for field == 0x0004 (fls == 3) */ - { 0x7A, 0x7D, 0x0002, 1 }, /* for field == 0x0008 (fls == 4) */ - { 0x7A, 0x7D, 0x0004, 2 }, /* for field == 0x0010 (fls == 5) */ - { 0x7A, 0x7D, 0x0030, 4 }, /* for field == 0x0020 (fls == 6) */ - { 0x7A, 0x7D, 0x00C0, 6 }, /* for field == 0x0040 (fls == 7) */ - { 0x7A, 0x7D, 0x0100, 8 }, /* for field == 0x0080 (fls == 8) */ - { 0x7A, 0x7D, 0x0200, 9 }, /* for field == 0x0100 (fls == 9) */ - { 0x78, 0x78, 0x0004, 2 }, /* for field == 0x0200 (fls == 10) */ - { 0x7B, 0x7E, 0x01FF, 0 }, /* for field == 0x0400 (fls == 11) */ - { 0x7C, 0x7F, 0x01FF, 0 }, /* for field == 0x0800 (fls == 12) */ - { 0x78, 0x78, 0x0100, 8 }, /* for field == 0x1000 (fls == 13) */ - { 0x78, 0x78, 0x0200, 9 }, /* for field == 0x2000 (fls == 14) */ - { 0x78, 0x78, 0xF000, 12 } /* for field == 0x4000 (fls == 15) */ -}; - -/* val_mask, val_shift, en_addr0, val_addr0, en_addr1, val_addr1 */ -const struct nphy_rf_control_override_rev3 tbl_rf_control_override_rev3[] = { - { 0x8000, 15, 0xE5, 0xF9, 0xE6, 0xFB }, /* field == 0x0001 (fls 1) */ - { 0x0001, 0, 0xE7, 0x7A, 0xEC, 0x7D }, /* field == 0x0002 (fls 2) */ - { 0x0002, 1, 0xE7, 0x7A, 0xEC, 0x7D }, /* field == 0x0004 (fls 3) */ - { 0x0004, 2, 0xE7, 0x7A, 0xEC, 0x7D }, /* field == 0x0008 (fls 4) */ - { 0x0016, 4, 0xE7, 0x7A, 0xEC, 0x7D }, /* field == 0x0010 (fls 5) */ - { 0x0020, 5, 0xE7, 0x7A, 0xEC, 0x7D }, /* field == 0x0020 (fls 6) */ - { 0x0040, 6, 0xE7, 0x7A, 0xEC, 0x7D }, /* field == 0x0040 (fls 7) */ - { 0x0080, 6, 0xE7, 0x7A, 0xEC, 0x7D }, /* field == 0x0080 (fls 8) */ - { 0x0100, 7, 0xE7, 0x7A, 0xEC, 0x7D }, /* field == 0x0100 (fls 9) */ - { 0x0007, 0, 0xE7, 0xF8, 0xEC, 0xFA }, /* field == 0x0200 (fls 10) */ - { 0x0070, 4, 0xE7, 0xF8, 0xEC, 0xFA }, /* field == 0x0400 (fls 11) */ - { 0xE000, 13, 0xE7, 0x7A, 0xEC, 0x7D }, /* field == 0x0800 (fls 12) */ - { 0xFFFF, 0, 0xE7, 0x7B, 0xEC, 0x7E }, /* field == 0x1000 (fls 13) */ - { 0xFFFF, 0, 0xE7, 0x7C, 0xEC, 0x7F }, /* field == 0x2000 (fls 14) */ - { 0x00C0, 6, 0xE7, 0xF9, 0xEC, 0xFB } /* field == 0x4000 (fls 15) */ -}; - static inline void assert_ntab_array_sizes(void) { #undef check @@ -2980,72 +2442,6 @@ static inline void assert_ntab_array_sizes(void) #undef check } -u32 b43_ntab_read(struct b43_wldev *dev, u32 offset) -{ - u32 type, value; - - type = offset & B43_NTAB_TYPEMASK; - offset &= ~B43_NTAB_TYPEMASK; - B43_WARN_ON(offset > 0xFFFF); - - switch (type) { - case B43_NTAB_8BIT: - b43_phy_write(dev, B43_NPHY_TABLE_ADDR, offset); - value = b43_phy_read(dev, B43_NPHY_TABLE_DATALO) & 0xFF; - break; - case B43_NTAB_16BIT: - b43_phy_write(dev, B43_NPHY_TABLE_ADDR, offset); - value = b43_phy_read(dev, B43_NPHY_TABLE_DATALO); - break; - case B43_NTAB_32BIT: - b43_phy_write(dev, B43_NPHY_TABLE_ADDR, offset); - value = b43_phy_read(dev, B43_NPHY_TABLE_DATAHI); - value <<= 16; - value |= b43_phy_read(dev, B43_NPHY_TABLE_DATALO); - break; - default: - B43_WARN_ON(1); - value = 0; - } - - return value; -} - -void b43_ntab_read_bulk(struct b43_wldev *dev, u32 offset, - unsigned int nr_elements, void *_data) -{ - u32 type; - u8 *data = _data; - unsigned int i; - - type = offset & B43_NTAB_TYPEMASK; - offset &= ~B43_NTAB_TYPEMASK; - B43_WARN_ON(offset > 0xFFFF); - - b43_phy_write(dev, B43_NPHY_TABLE_ADDR, offset); - - for (i = 0; i < nr_elements; i++) { - switch (type) { - case B43_NTAB_8BIT: - *data = b43_phy_read(dev, B43_NPHY_TABLE_DATALO) & 0xFF; - data++; - break; - case B43_NTAB_16BIT: - *((u16 *)data) = b43_phy_read(dev, B43_NPHY_TABLE_DATALO); - data += 2; - break; - case B43_NTAB_32BIT: - *((u32 *)data) = b43_phy_read(dev, B43_NPHY_TABLE_DATAHI); - *((u32 *)data) <<= 16; - *((u32 *)data) |= b43_phy_read(dev, B43_NPHY_TABLE_DATALO); - data += 4; - break; - default: - B43_WARN_ON(1); - } - } -} - void b43_ntab_write(struct b43_wldev *dev, u32 offset, u32 value) { u32 type; @@ -3078,91 +2474,3 @@ void b43_ntab_write(struct b43_wldev *dev, u32 offset, u32 value) /* Some compiletime assertions... */ assert_ntab_array_sizes(); } - -void b43_ntab_write_bulk(struct b43_wldev *dev, u32 offset, - unsigned int nr_elements, const void *_data) -{ - u32 type, value; - const u8 *data = _data; - unsigned int i; - - type = offset & B43_NTAB_TYPEMASK; - offset &= ~B43_NTAB_TYPEMASK; - B43_WARN_ON(offset > 0xFFFF); - - b43_phy_write(dev, B43_NPHY_TABLE_ADDR, offset); - - for (i = 0; i < nr_elements; i++) { - switch (type) { - case B43_NTAB_8BIT: - value = *data; - data++; - B43_WARN_ON(value & ~0xFF); - b43_phy_write(dev, B43_NPHY_TABLE_DATALO, value); - break; - case B43_NTAB_16BIT: - value = *((u16 *)data); - data += 2; - B43_WARN_ON(value & ~0xFFFF); - b43_phy_write(dev, B43_NPHY_TABLE_DATALO, value); - break; - case B43_NTAB_32BIT: - value = *((u32 *)data); - data += 4; - b43_phy_write(dev, B43_NPHY_TABLE_DATAHI, value >> 16); - b43_phy_write(dev, B43_NPHY_TABLE_DATALO, - value & 0xFFFF); - break; - default: - B43_WARN_ON(1); - } - } -} - -#define ntab_upload(dev, offset, data) do { \ - unsigned int i; \ - for (i = 0; i < (offset##_SIZE); i++) \ - b43_ntab_write(dev, (offset) + i, (data)[i]); \ - } while (0) - -void b43_nphy_rev0_1_2_tables_init(struct b43_wldev *dev) -{ - /* Static tables */ - ntab_upload(dev, B43_NTAB_FRAMESTRUCT, b43_ntab_framestruct); - ntab_upload(dev, B43_NTAB_FRAMELT, b43_ntab_framelookup); - ntab_upload(dev, B43_NTAB_TMAP, b43_ntab_tmap); - ntab_upload(dev, B43_NTAB_TDTRN, b43_ntab_tdtrn); - ntab_upload(dev, B43_NTAB_INTLEVEL, b43_ntab_intlevel); - ntab_upload(dev, B43_NTAB_PILOT, b43_ntab_pilot); - ntab_upload(dev, B43_NTAB_PILOTLT, b43_ntab_pilotlt); - ntab_upload(dev, B43_NTAB_TDI20A0, b43_ntab_tdi20a0); - ntab_upload(dev, B43_NTAB_TDI20A1, b43_ntab_tdi20a1); - ntab_upload(dev, B43_NTAB_TDI40A0, b43_ntab_tdi40a0); - ntab_upload(dev, B43_NTAB_TDI40A1, b43_ntab_tdi40a1); - ntab_upload(dev, B43_NTAB_BDI, b43_ntab_bdi); - ntab_upload(dev, B43_NTAB_CHANEST, b43_ntab_channelest); - ntab_upload(dev, B43_NTAB_MCS, b43_ntab_mcs); - - /* Volatile tables */ - ntab_upload(dev, B43_NTAB_NOISEVAR10, b43_ntab_noisevar10); - ntab_upload(dev, B43_NTAB_NOISEVAR11, b43_ntab_noisevar11); - ntab_upload(dev, B43_NTAB_C0_ESTPLT, b43_ntab_estimatepowerlt0); - ntab_upload(dev, B43_NTAB_C1_ESTPLT, b43_ntab_estimatepowerlt1); - ntab_upload(dev, B43_NTAB_C0_ADJPLT, b43_ntab_adjustpower0); - ntab_upload(dev, B43_NTAB_C1_ADJPLT, b43_ntab_adjustpower1); - ntab_upload(dev, B43_NTAB_C0_GAINCTL, b43_ntab_gainctl0); - ntab_upload(dev, B43_NTAB_C1_GAINCTL, b43_ntab_gainctl1); - ntab_upload(dev, B43_NTAB_C0_IQLT, b43_ntab_iqlt0); - ntab_upload(dev, B43_NTAB_C1_IQLT, b43_ntab_iqlt1); - ntab_upload(dev, B43_NTAB_C0_LOFEEDTH, b43_ntab_loftlt0); - ntab_upload(dev, B43_NTAB_C1_LOFEEDTH, b43_ntab_loftlt1); -} - -void b43_nphy_rev3plus_tables_init(struct b43_wldev *dev) -{ - /* Static tables */ - /* TODO */ - - /* Volatile tables */ - /* TODO */ -} diff --git a/trunk/drivers/net/wireless/b43/tables_nphy.h b/trunk/drivers/net/wireless/b43/tables_nphy.h index 9c1c6ecd3672..4d498b053ec7 100644 --- a/trunk/drivers/net/wireless/b43/tables_nphy.h +++ b/trunk/drivers/net/wireless/b43/tables_nphy.h @@ -46,27 +46,6 @@ struct b43_nphy_channeltab_entry { struct b43_wldev; -struct nphy_txiqcal_ladder { - u8 percent; - u8 g_env; -}; - -struct nphy_rf_control_override_rev2 { - u8 addr0; - u8 addr1; - u16 bmask; - u8 shift; -}; - -struct nphy_rf_control_override_rev3 { - u16 val_mask; - u8 val_shift; - u8 en_addr0; - u8 val_addr0; - u8 en_addr1; - u8 val_addr1; -}; - /* Upload the default register value table. * If "ghz5" is true, we upload the 5Ghz table. Otherwise the 2.4Ghz * table is uploaded. If "ignore_uploadflag" is true, we upload any value @@ -147,57 +126,34 @@ b43_nphy_get_chantabent(struct b43_wldev *dev, u8 channel); #define B43_NTAB_C1_LOFEEDTH B43_NTAB16(0x1B, 0x1C0) /* Local Oscillator Feed Through Lookup Table Core 1 */ #define B43_NTAB_C1_LOFEEDTH_SIZE 128 -#define B43_NTAB_TX_IQLO_CAL_LOFT_LADDER_40_SIZE 18 -#define B43_NTAB_TX_IQLO_CAL_LOFT_LADDER_20_SIZE 18 -#define B43_NTAB_TX_IQLO_CAL_IQIMB_LADDER_40_SIZE 18 -#define B43_NTAB_TX_IQLO_CAL_IQIMB_LADDER_20_SIZE 18 -#define B43_NTAB_TX_IQLO_CAL_STARTCOEFS_REV3 11 -#define B43_NTAB_TX_IQLO_CAL_STARTCOEFS 9 -#define B43_NTAB_TX_IQLO_CAL_CMDS_RECAL_REV3 12 -#define B43_NTAB_TX_IQLO_CAL_CMDS_RECAL 10 -#define B43_NTAB_TX_IQLO_CAL_CMDS_FULLCAL 10 -#define B43_NTAB_TX_IQLO_CAL_CMDS_FULLCAL_REV3 12 - -u32 b43_ntab_read(struct b43_wldev *dev, u32 offset); -void b43_ntab_read_bulk(struct b43_wldev *dev, u32 offset, - unsigned int nr_elements, void *_data); void b43_ntab_write(struct b43_wldev *dev, u32 offset, u32 value); -void b43_ntab_write_bulk(struct b43_wldev *dev, u32 offset, - unsigned int nr_elements, const void *_data); - -void b43_nphy_rev0_1_2_tables_init(struct b43_wldev *dev); -void b43_nphy_rev3plus_tables_init(struct b43_wldev *dev); - -extern const u32 b43_ntab_tx_gain_rev0_1_2[]; -extern const u32 b43_ntab_tx_gain_rev3plus_2ghz[]; -extern const u32 b43_ntab_tx_gain_rev3_5ghz[]; -extern const u32 b43_ntab_tx_gain_rev4_5ghz[]; -extern const u32 b43_ntab_tx_gain_rev5plus_5ghz[]; - -extern const u32 txpwrctrl_tx_gain_ipa[]; -extern const u32 txpwrctrl_tx_gain_ipa_rev5[]; -extern const u32 txpwrctrl_tx_gain_ipa_rev6[]; -extern const u32 txpwrctrl_tx_gain_ipa_5g[]; -extern const u16 tbl_iqcal_gainparams[2][9][8]; -extern const struct nphy_txiqcal_ladder ladder_lo[]; -extern const struct nphy_txiqcal_ladder ladder_iq[]; -extern const u16 loscale[]; - -extern const u16 tbl_tx_iqlo_cal_loft_ladder_40[]; -extern const u16 tbl_tx_iqlo_cal_loft_ladder_20[]; -extern const u16 tbl_tx_iqlo_cal_iqimb_ladder_40[]; -extern const u16 tbl_tx_iqlo_cal_iqimb_ladder_20[]; -extern const u16 tbl_tx_iqlo_cal_startcoefs_nphyrev3[]; -extern const u16 tbl_tx_iqlo_cal_startcoefs[]; -extern const u16 tbl_tx_iqlo_cal_cmds_recal_nphyrev3[]; -extern const u16 tbl_tx_iqlo_cal_cmds_recal[]; -extern const u16 tbl_tx_iqlo_cal_cmds_fullcal[]; -extern const u16 tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3[]; -extern const s16 tbl_tx_filter_coef_rev4[7][15]; - -extern const struct nphy_rf_control_override_rev2 - tbl_rf_control_override_rev2[]; -extern const struct nphy_rf_control_override_rev3 - tbl_rf_control_override_rev3[]; + +extern const u8 b43_ntab_adjustpower0[]; +extern const u8 b43_ntab_adjustpower1[]; +extern const u16 b43_ntab_bdi[]; +extern const u32 b43_ntab_channelest[]; +extern const u8 b43_ntab_estimatepowerlt0[]; +extern const u8 b43_ntab_estimatepowerlt1[]; +extern const u8 b43_ntab_framelookup[]; +extern const u32 b43_ntab_framestruct[]; +extern const u32 b43_ntab_gainctl0[]; +extern const u32 b43_ntab_gainctl1[]; +extern const u32 b43_ntab_intlevel[]; +extern const u32 b43_ntab_iqlt0[]; +extern const u32 b43_ntab_iqlt1[]; +extern const u16 b43_ntab_loftlt0[]; +extern const u16 b43_ntab_loftlt1[]; +extern const u8 b43_ntab_mcs[]; +extern const u32 b43_ntab_noisevar10[]; +extern const u32 b43_ntab_noisevar11[]; +extern const u16 b43_ntab_pilot[]; +extern const u32 b43_ntab_pilotlt[]; +extern const u32 b43_ntab_tdi20a0[]; +extern const u32 b43_ntab_tdi20a1[]; +extern const u32 b43_ntab_tdi40a0[]; +extern const u32 b43_ntab_tdi40a1[]; +extern const u32 b43_ntab_tdtrn[]; +extern const u32 b43_ntab_tmap[]; + #endif /* B43_TABLES_NPHY_H_ */ diff --git a/trunk/drivers/net/wireless/b43legacy/dma.c b/trunk/drivers/net/wireless/b43legacy/dma.c index 8b9387c6ff36..0a86bdf53154 100644 --- a/trunk/drivers/net/wireless/b43legacy/dma.c +++ b/trunk/drivers/net/wireless/b43legacy/dma.c @@ -1411,6 +1411,7 @@ int b43legacy_dma_tx(struct b43legacy_wldev *dev, b43legacyerr(dev->wl, "DMA tx mapping failure\n"); goto out_unlock; } + ring->nr_tx_packets++; if ((free_slots(ring) < SLOTS_PER_PACKET) || should_inject_overflow(ring)) { /* This TX ring is full. */ @@ -1526,6 +1527,25 @@ void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev, spin_unlock(&ring->lock); } +void b43legacy_dma_get_tx_stats(struct b43legacy_wldev *dev, + struct ieee80211_tx_queue_stats *stats) +{ + const int nr_queues = dev->wl->hw->queues; + struct b43legacy_dmaring *ring; + unsigned long flags; + int i; + + for (i = 0; i < nr_queues; i++) { + ring = priority_to_txring(dev, i); + + spin_lock_irqsave(&ring->lock, flags); + stats[i].len = ring->used_slots / SLOTS_PER_PACKET; + stats[i].limit = ring->nr_slots / SLOTS_PER_PACKET; + stats[i].count = ring->nr_tx_packets; + spin_unlock_irqrestore(&ring->lock, flags); + } +} + static void dma_rx(struct b43legacy_dmaring *ring, int *slot) { diff --git a/trunk/drivers/net/wireless/b43legacy/dma.h b/trunk/drivers/net/wireless/b43legacy/dma.h index f9681041c2d8..2f186003c31e 100644 --- a/trunk/drivers/net/wireless/b43legacy/dma.h +++ b/trunk/drivers/net/wireless/b43legacy/dma.h @@ -243,6 +243,8 @@ struct b43legacy_dmaring { int used_slots; /* Currently used slot in the ring. */ int current_slot; + /* Total number of packets sent. Statistics only. */ + unsigned int nr_tx_packets; /* Frameoffset in octets. */ u32 frameoffset; /* Descriptor buffer size. */ @@ -290,6 +292,9 @@ void b43legacy_dma_free(struct b43legacy_wldev *dev); void b43legacy_dma_tx_suspend(struct b43legacy_wldev *dev); void b43legacy_dma_tx_resume(struct b43legacy_wldev *dev); +void b43legacy_dma_get_tx_stats(struct b43legacy_wldev *dev, + struct ieee80211_tx_queue_stats *stats); + int b43legacy_dma_tx(struct b43legacy_wldev *dev, struct sk_buff *skb); void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev, @@ -310,6 +315,11 @@ void b43legacy_dma_free(struct b43legacy_wldev *dev) { } static inline +void b43legacy_dma_get_tx_stats(struct b43legacy_wldev *dev, + struct ieee80211_tx_queue_stats *stats) +{ +} +static inline int b43legacy_dma_tx(struct b43legacy_wldev *dev, struct sk_buff *skb) { diff --git a/trunk/drivers/net/wireless/b43legacy/leds.h b/trunk/drivers/net/wireless/b43legacy/leds.h index 9ff6750dc57f..82167a90088f 100644 --- a/trunk/drivers/net/wireless/b43legacy/leds.h +++ b/trunk/drivers/net/wireless/b43legacy/leds.h @@ -45,7 +45,7 @@ enum b43legacy_led_behaviour { void b43legacy_leds_init(struct b43legacy_wldev *dev); void b43legacy_leds_exit(struct b43legacy_wldev *dev); -#else /* CONFIG_B43LEGACY_LEDS */ +#else /* CONFIG_B43EGACY_LEDS */ /* LED support disabled */ struct b43legacy_led { diff --git a/trunk/drivers/net/wireless/b43legacy/main.c b/trunk/drivers/net/wireless/b43legacy/main.c index 08523a45e23b..ab6a18c2e9d9 100644 --- a/trunk/drivers/net/wireless/b43legacy/main.c +++ b/trunk/drivers/net/wireless/b43legacy/main.c @@ -61,8 +61,6 @@ MODULE_AUTHOR("Michael Buesch"); MODULE_LICENSE("GPL"); MODULE_FIRMWARE(B43legacy_SUPPORTED_FIRMWARE_ID); -MODULE_FIRMWARE("b43legacy/ucode2.fw"); -MODULE_FIRMWARE("b43legacy/ucode4.fw"); #if defined(CONFIG_B43LEGACY_DMA) && defined(CONFIG_B43LEGACY_PIO) static int modparam_pio; @@ -2446,6 +2444,29 @@ static int b43legacy_op_conf_tx(struct ieee80211_hw *hw, u16 queue, return 0; } +static int b43legacy_op_get_tx_stats(struct ieee80211_hw *hw, + struct ieee80211_tx_queue_stats *stats) +{ + struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); + struct b43legacy_wldev *dev = wl->current_dev; + unsigned long flags; + int err = -ENODEV; + + if (!dev) + goto out; + spin_lock_irqsave(&wl->irq_lock, flags); + if (likely(b43legacy_status(dev) >= B43legacy_STAT_STARTED)) { + if (b43legacy_using_pio(dev)) + b43legacy_pio_get_tx_stats(dev, stats); + else + b43legacy_dma_get_tx_stats(dev, stats); + err = 0; + } + spin_unlock_irqrestore(&wl->irq_lock, flags); +out: + return err; +} + static int b43legacy_op_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats) { @@ -2900,7 +2921,6 @@ static int b43legacy_wireless_core_start(struct b43legacy_wldev *dev) goto out; } /* We are ready to run. */ - ieee80211_wake_queues(dev->wl->hw); b43legacy_set_status(dev, B43legacy_STAT_STARTED); /* Start data flow (TX/RX) */ @@ -3321,7 +3341,6 @@ static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev) b43legacy_security_init(dev); b43legacy_rng_init(wl); - ieee80211_wake_queues(dev->wl->hw); b43legacy_set_status(dev, B43legacy_STAT_INITIALIZED); b43legacy_leds_init(dev); @@ -3342,7 +3361,7 @@ static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev) } static int b43legacy_op_add_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) + struct ieee80211_if_init_conf *conf) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev; @@ -3351,23 +3370,23 @@ static int b43legacy_op_add_interface(struct ieee80211_hw *hw, /* TODO: allow WDS/AP devices to coexist */ - if (vif->type != NL80211_IFTYPE_AP && - vif->type != NL80211_IFTYPE_STATION && - vif->type != NL80211_IFTYPE_WDS && - vif->type != NL80211_IFTYPE_ADHOC) + if (conf->type != NL80211_IFTYPE_AP && + conf->type != NL80211_IFTYPE_STATION && + conf->type != NL80211_IFTYPE_WDS && + conf->type != NL80211_IFTYPE_ADHOC) return -EOPNOTSUPP; mutex_lock(&wl->mutex); if (wl->operating) goto out_mutex_unlock; - b43legacydbg(wl, "Adding Interface type %d\n", vif->type); + b43legacydbg(wl, "Adding Interface type %d\n", conf->type); dev = wl->current_dev; wl->operating = 1; - wl->vif = vif; - wl->if_type = vif->type; - memcpy(wl->mac_addr, vif->addr, ETH_ALEN); + wl->vif = conf->vif; + wl->if_type = conf->type; + memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN); spin_lock_irqsave(&wl->irq_lock, flags); b43legacy_adjust_opmode(dev); @@ -3384,18 +3403,18 @@ static int b43legacy_op_add_interface(struct ieee80211_hw *hw, } static void b43legacy_op_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) + struct ieee80211_if_init_conf *conf) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev = wl->current_dev; unsigned long flags; - b43legacydbg(wl, "Removing Interface type %d\n", vif->type); + b43legacydbg(wl, "Removing Interface type %d\n", conf->type); mutex_lock(&wl->mutex); B43legacy_WARN_ON(!wl->operating); - B43legacy_WARN_ON(wl->vif != vif); + B43legacy_WARN_ON(wl->vif != conf->vif); wl->vif = NULL; wl->operating = 0; @@ -3490,6 +3509,7 @@ static const struct ieee80211_ops b43legacy_hw_ops = { .bss_info_changed = b43legacy_op_bss_info_changed, .configure_filter = b43legacy_op_configure_filter, .get_stats = b43legacy_op_get_stats, + .get_tx_stats = b43legacy_op_get_tx_stats, .start = b43legacy_op_start, .stop = b43legacy_op_stop, .set_tim = b43legacy_op_beacon_set_tim, @@ -3940,7 +3960,7 @@ static struct ssb_driver b43legacy_ssb_driver = { static void b43legacy_print_driverinfo(void) { - const char *feat_pci = "", *feat_leds = "", + const char *feat_pci = "", *feat_leds = "", *feat_rfkill = "", *feat_pio = "", *feat_dma = ""; #ifdef CONFIG_B43LEGACY_PCI_AUTOSELECT @@ -3949,6 +3969,9 @@ static void b43legacy_print_driverinfo(void) #ifdef CONFIG_B43LEGACY_LEDS feat_leds = "L"; #endif +#ifdef CONFIG_B43LEGACY_RFKILL + feat_rfkill = "R"; +#endif #ifdef CONFIG_B43LEGACY_PIO feat_pio = "I"; #endif @@ -3956,9 +3979,9 @@ static void b43legacy_print_driverinfo(void) feat_dma = "D"; #endif printk(KERN_INFO "Broadcom 43xx-legacy driver loaded " - "[ Features: %s%s%s%s, Firmware-ID: " + "[ Features: %s%s%s%s%s, Firmware-ID: " B43legacy_SUPPORTED_FIRMWARE_ID " ]\n", - feat_pci, feat_leds, feat_pio, feat_dma); + feat_pci, feat_leds, feat_rfkill, feat_pio, feat_dma); } static int __init b43legacy_init(void) diff --git a/trunk/drivers/net/wireless/b43legacy/pio.c b/trunk/drivers/net/wireless/b43legacy/pio.c index 017c0e9c37ef..51866c9a2769 100644 --- a/trunk/drivers/net/wireless/b43legacy/pio.c +++ b/trunk/drivers/net/wireless/b43legacy/pio.c @@ -477,6 +477,7 @@ int b43legacy_pio_tx(struct b43legacy_wldev *dev, list_move_tail(&packet->list, &queue->txqueue); queue->nr_txfree--; + queue->nr_tx_packets++; B43legacy_WARN_ON(queue->nr_txfree >= B43legacy_PIO_MAXTXPACKETS); tasklet_schedule(&queue->txtask); @@ -545,6 +546,18 @@ void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev, tasklet_schedule(&queue->txtask); } +void b43legacy_pio_get_tx_stats(struct b43legacy_wldev *dev, + struct ieee80211_tx_queue_stats *stats) +{ + struct b43legacy_pio *pio = &dev->pio; + struct b43legacy_pioqueue *queue; + + queue = pio->queue1; + stats[0].len = B43legacy_PIO_MAXTXPACKETS - queue->nr_txfree; + stats[0].limit = B43legacy_PIO_MAXTXPACKETS; + stats[0].count = queue->nr_tx_packets; +} + static void pio_rx_error(struct b43legacy_pioqueue *queue, int clear_buffers, const char *error) diff --git a/trunk/drivers/net/wireless/b43legacy/pio.h b/trunk/drivers/net/wireless/b43legacy/pio.h index 8e6773ea6e75..464fec05a06d 100644 --- a/trunk/drivers/net/wireless/b43legacy/pio.h +++ b/trunk/drivers/net/wireless/b43legacy/pio.h @@ -74,6 +74,10 @@ struct b43legacy_pioqueue { * posted to the device. We are waiting for the txstatus. */ struct list_head txrunning; + /* Total number or packets sent. + * (This counter can obviously wrap). + */ + unsigned int nr_tx_packets; struct tasklet_struct txtask; struct b43legacy_pio_txpacket tx_packets_cache[B43legacy_PIO_MAXTXPACKETS]; @@ -102,6 +106,8 @@ int b43legacy_pio_tx(struct b43legacy_wldev *dev, struct sk_buff *skb); void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev, const struct b43legacy_txstatus *status); +void b43legacy_pio_get_tx_stats(struct b43legacy_wldev *dev, + struct ieee80211_tx_queue_stats *stats); void b43legacy_pio_rx(struct b43legacy_pioqueue *queue); /* Suspend TX queue in hardware. */ @@ -134,6 +140,11 @@ void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev, { } static inline +void b43legacy_pio_get_tx_stats(struct b43legacy_wldev *dev, + struct ieee80211_tx_queue_stats *stats) +{ +} +static inline void b43legacy_pio_rx(struct b43legacy_pioqueue *queue) { } diff --git a/trunk/drivers/net/wireless/hostap/hostap_cs.c b/trunk/drivers/net/wireless/hostap/hostap_cs.c index d19748d90aaf..c9640a3e02c9 100644 --- a/trunk/drivers/net/wireless/hostap/hostap_cs.c +++ b/trunk/drivers/net/wireless/hostap/hostap_cs.c @@ -793,6 +793,13 @@ static struct pcmcia_device_id hostap_cs_ids[] = { 0x4b801a17), PCMCIA_MFC_DEVICE_PROD_ID12(0, "SanDisk", "ConnectPlus", 0x7a954bd9, 0x74be00c6), + PCMCIA_DEVICE_PROD_ID123( + "Intersil", "PRISM 2_5 PCMCIA ADAPTER", "ISL37300P", + 0x4b801a17, 0x6345a0bf, 0xc9049a39), + /* D-Link DWL-650 Rev. P1; manfid 0x000b, 0x7110 */ + PCMCIA_DEVICE_PROD_ID123( + "D-Link", "DWL-650 Wireless PC Card RevP", "ISL37101P-10", + 0x1a424a1c, 0x6ea57632, 0xdd97a26b), PCMCIA_DEVICE_PROD_ID123( "Addtron", "AWP-100 Wireless PCMCIA", "Version 01.02", 0xe6ec52ce, 0x08649af2, 0x4b74baa0), @@ -826,13 +833,15 @@ static struct pcmcia_device_id hostap_cs_ids[] = { "Allied Telesyn", "AT-WCL452 Wireless PCMCIA Radio", "Ver. 1.00", 0x5cd01705, 0x4271660f, 0x9d08ee12), + PCMCIA_DEVICE_PROD_ID123( + "corega", "WL PCCL-11", "ISL37300P", + 0xa21501a, 0x59868926, 0xc9049a39), + PCMCIA_DEVICE_PROD_ID123( + "The Linksys Group, Inc.", "Wireless Network CF Card", "ISL37300P", + 0xa5f472c2, 0x9c05598d, 0xc9049a39), PCMCIA_DEVICE_PROD_ID123( "Wireless LAN" , "11Mbps PC Card", "Version 01.02", 0x4b8870ff, 0x70e946d1, 0x4b74baa0), - PCMCIA_DEVICE_PROD_ID3("HFA3863", 0x355cb092), - PCMCIA_DEVICE_PROD_ID3("ISL37100P", 0x630d52b2), - PCMCIA_DEVICE_PROD_ID3("ISL37101P-10", 0xdd97a26b), - PCMCIA_DEVICE_PROD_ID3("ISL37300P", 0xc9049a39), PCMCIA_DEVICE_NULL }; MODULE_DEVICE_TABLE(pcmcia, hostap_cs_ids); diff --git a/trunk/drivers/net/wireless/hostap/hostap_hw.c b/trunk/drivers/net/wireless/hostap/hostap_hw.c index d70732819423..ff9b5c882184 100644 --- a/trunk/drivers/net/wireless/hostap/hostap_hw.c +++ b/trunk/drivers/net/wireless/hostap/hostap_hw.c @@ -2618,15 +2618,6 @@ static irqreturn_t prism2_interrupt(int irq, void *dev_id) int events = 0; u16 ev; - /* Detect early interrupt before driver is fully configued */ - if (!dev->base_addr) { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: Interrupt, but dev not configured\n", - dev->name); - } - return IRQ_HANDLED; - } - iface = netdev_priv(dev); local = iface->local; diff --git a/trunk/drivers/net/wireless/iwlwifi/Kconfig b/trunk/drivers/net/wireless/iwlwifi/Kconfig index dc8ed1527666..b16b06c2031f 100644 --- a/trunk/drivers/net/wireless/iwlwifi/Kconfig +++ b/trunk/drivers/net/wireless/iwlwifi/Kconfig @@ -1,8 +1,14 @@ config IWLWIFI tristate "Intel Wireless Wifi" - depends on PCI && MAC80211 + depends on PCI && MAC80211 && EXPERIMENTAL select FW_LOADER +config IWLWIFI_SPECTRUM_MEASUREMENT + bool "Enable Spectrum Measurement in iwlagn driver" + depends on IWLWIFI + ---help--- + This option will enable spectrum measurement for the iwlagn driver. + config IWLWIFI_DEBUG bool "Enable full debugging output in iwlagn and iwl3945 drivers" depends on IWLWIFI @@ -114,3 +120,9 @@ config IWL3945 inserted in and removed from the running kernel whenever you want), say M here and read . The module will be called iwl3945. + +config IWL3945_SPECTRUM_MEASUREMENT + bool "Enable Spectrum Measurement in iwl3945 driver" + depends on IWL3945 + ---help--- + This option will enable spectrum measurement for the iwl3945 driver. diff --git a/trunk/drivers/net/wireless/iwlwifi/Makefile b/trunk/drivers/net/wireless/iwlwifi/Makefile index 4e378faee650..7f82044af242 100644 --- a/trunk/drivers/net/wireless/iwlwifi/Makefile +++ b/trunk/drivers/net/wireless/iwlwifi/Makefile @@ -3,6 +3,7 @@ iwlcore-objs := iwl-core.o iwl-eeprom.o iwl-hcmd.o iwl-power.o iwlcore-objs += iwl-rx.o iwl-tx.o iwl-sta.o iwl-calib.o iwlcore-objs += iwl-scan.o iwl-led.o iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o +iwlcore-$(CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT) += iwl-spectrum.o iwlcore-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o CFLAGS_iwl-devtrace.o := -I$(src) @@ -19,5 +20,3 @@ iwlagn-$(CONFIG_IWL5000) += iwl-1000.o # 3945 obj-$(CONFIG_IWL3945) += iwl3945.o iwl3945-objs := iwl3945-base.o iwl-3945.o iwl-3945-rs.o iwl-3945-led.o - -ccflags-y += -D__CHECK_ENDIAN__ diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-1000.c b/trunk/drivers/net/wireless/iwlwifi/iwl-1000.c index 3bf2e6e9b2d9..8414178bcff4 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008-2009 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -89,78 +89,8 @@ static void iwl1000_nic_config(struct iwl_priv *priv) ~APMG_SVR_VOLTAGE_CONFIG_BIT_MSK); } -static struct iwl_sensitivity_ranges iwl1000_sensitivity = { - .min_nrg_cck = 95, - .max_nrg_cck = 0, /* not used, set to 0 */ - .auto_corr_min_ofdm = 90, - .auto_corr_min_ofdm_mrc = 170, - .auto_corr_min_ofdm_x1 = 120, - .auto_corr_min_ofdm_mrc_x1 = 240, - - .auto_corr_max_ofdm = 120, - .auto_corr_max_ofdm_mrc = 210, - .auto_corr_max_ofdm_x1 = 155, - .auto_corr_max_ofdm_mrc_x1 = 290, - - .auto_corr_min_cck = 125, - .auto_corr_max_cck = 200, - .auto_corr_min_cck_mrc = 170, - .auto_corr_max_cck_mrc = 400, - .nrg_th_cck = 95, - .nrg_th_ofdm = 95, - - .barker_corr_th_min = 190, - .barker_corr_th_min_mrc = 390, - .nrg_th_cca = 62, -}; - -static int iwl1000_hw_set_hw_params(struct iwl_priv *priv) -{ - if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES && - priv->cfg->mod_params->num_of_queues <= IWL50_NUM_QUEUES) - priv->cfg->num_of_queues = - priv->cfg->mod_params->num_of_queues; - - priv->hw_params.max_txq_num = priv->cfg->num_of_queues; - priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM; - priv->hw_params.scd_bc_tbls_size = - priv->cfg->num_of_queues * - sizeof(struct iwl5000_scd_bc_tbl); - priv->hw_params.tfd_size = sizeof(struct iwl_tfd); - priv->hw_params.max_stations = IWL5000_STATION_COUNT; - priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID; - - priv->hw_params.max_data_size = IWL50_RTC_DATA_SIZE; - priv->hw_params.max_inst_size = IWL50_RTC_INST_SIZE; - - priv->hw_params.max_bsm_size = 0; - priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | - BIT(IEEE80211_BAND_5GHZ); - priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; - - priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant); - priv->hw_params.rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant); - priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant; - priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant; - - if (priv->cfg->ops->lib->temp_ops.set_ct_kill) - priv->cfg->ops->lib->temp_ops.set_ct_kill(priv); - - /* Set initial sensitivity parameters */ - /* Set initial calibration set */ - priv->hw_params.sens = &iwl1000_sensitivity; - priv->hw_params.calib_init_cfg = - BIT(IWL_CALIB_XTAL) | - BIT(IWL_CALIB_LO) | - BIT(IWL_CALIB_TX_IQ) | - BIT(IWL_CALIB_TX_IQ_PERD) | - BIT(IWL_CALIB_BASE_BAND); - - return 0; -} - static struct iwl_lib_ops iwl1000_lib = { - .set_hw_params = iwl1000_hw_set_hw_params, + .set_hw_params = iwl5000_hw_set_hw_params, .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, .txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl, .txq_set_sched = iwl5000_txq_set_sched, @@ -175,8 +105,6 @@ static struct iwl_lib_ops iwl1000_lib = { .load_ucode = iwl5000_load_ucode, .dump_nic_event_log = iwl_dump_nic_event_log, .dump_nic_error_log = iwl_dump_nic_error_log, - .dump_csr = iwl_dump_csr, - .dump_fh = iwl_dump_fh, .init_alive_start = iwl5000_init_alive_start, .alive_notify = iwl5000_alive_notify, .send_tx_power = iwl5000_send_tx_power, @@ -210,10 +138,9 @@ static struct iwl_lib_ops iwl1000_lib = { .temperature = iwl5000_temperature, .set_ct_kill = iwl1000_set_ct_threshold, }, - .add_bcast_station = iwl_add_bcast_station, }; -static const struct iwl_ops iwl1000_ops = { +static struct iwl_ops iwl1000_ops = { .ucode = &iwl5000_ucode, .lib = &iwl1000_lib, .hcmd = &iwl5000_hcmd, @@ -246,8 +173,7 @@ struct iwl_cfg iwl1000_bgn_cfg = { .use_rts_for_ht = true, /* use rts/cts protection */ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .support_ct_kill_exit = true, - .plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF, - .chain_noise_scale = 1000, + .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED, }; struct iwl_cfg iwl1000_bg_cfg = { @@ -274,8 +200,6 @@ struct iwl_cfg iwl1000_bg_cfg = { .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .support_ct_kill_exit = true, - .plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF, - .chain_noise_scale = 1000, }; MODULE_FIRMWARE(IWL1000_MODULE_FIRMWARE(IWL1000_UCODE_API_MAX)); diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-3945-fh.h b/trunk/drivers/net/wireless/iwlwifi/iwl-3945-fh.h index 042f6bc0df13..08ce259a0e60 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-3945-fh.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-3945-fh.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/trunk/drivers/net/wireless/iwlwifi/iwl-3945-hw.h index 3a876a8ece38..6fd10d443ba3 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-3945-hw.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-3945-hw.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-3945-led.c b/trunk/drivers/net/wireless/iwlwifi/iwl-3945-led.c index abe2b739c4dc..a871d09d598f 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-3945-led.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-3945-led.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-3945-led.h b/trunk/drivers/net/wireless/iwlwifi/iwl-3945-led.h index ce990adc51e7..5a1033ca7aaa 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-3945-led.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-3945-led.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/trunk/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index 47909f94271e..d4b49883b30e 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-3945.c b/trunk/drivers/net/wireless/iwlwifi/iwl-3945.c index 521584b99fd1..234891d8cc10 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -45,8 +45,8 @@ #include "iwl-sta.h" #include "iwl-3945.h" #include "iwl-eeprom.h" -#include "iwl-core.h" #include "iwl-helpers.h" +#include "iwl-core.h" #include "iwl-led.h" #include "iwl-3945-led.h" @@ -1951,7 +1951,11 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv) } /* Add the broadcast address so we can send broadcast frames */ - priv->cfg->ops->lib->add_bcast_station(priv); + if (iwl_add_station(priv, iwl_bcast_addr, false, CMD_SYNC, NULL) == + IWL_INVALID_STATION) { + IWL_ERR(priv, "Error adding BROADCAST address for transmit.\n"); + return -EIO; + } /* If we have set the ASSOC_MSK and we are in BSS mode then * add the IWL_AP_ID to the station rate table */ @@ -2470,9 +2474,11 @@ int iwl3945_hw_set_hw_params(struct iwl_priv *priv) memset((void *)&priv->hw_params, 0, sizeof(struct iwl_hw_params)); - priv->shared_virt = dma_alloc_coherent(&priv->pci_dev->dev, - sizeof(struct iwl3945_shared), - &priv->shared_phys, GFP_KERNEL); + priv->shared_virt = + pci_alloc_consistent(priv->pci_dev, + sizeof(struct iwl3945_shared), + &priv->shared_phys); + if (!priv->shared_virt) { IWL_ERR(priv, "failed to allocate pci memory\n"); mutex_unlock(&priv->mutex); @@ -2790,7 +2796,6 @@ static struct iwl_lib_ops iwl3945_lib = { .post_associate = iwl3945_post_associate, .isr = iwl_isr_legacy, .config_ap = iwl3945_config_ap, - .add_bcast_station = iwl3945_add_bcast_station, }; static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = { @@ -2799,7 +2804,7 @@ static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = { .rts_tx_cmd_flag = iwlcore_rts_tx_cmd_flag, }; -static const struct iwl_ops iwl3945_ops = { +static struct iwl_ops iwl3945_ops = { .ucode = &iwl3945_ucode, .lib = &iwl3945_lib, .hcmd = &iwl3945_hcmd, @@ -2825,7 +2830,6 @@ static struct iwl_cfg iwl3945_bg_cfg = { .ht_greenfield_support = false, .led_compensation = 64, .broken_powersave = true, - .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, }; static struct iwl_cfg iwl3945_abg_cfg = { @@ -2843,7 +2847,6 @@ static struct iwl_cfg iwl3945_abg_cfg = { .ht_greenfield_support = false, .led_compensation = 64, .broken_powersave = true, - .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, }; struct pci_device_id iwl3945_hw_card_ids[] = { diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-3945.h b/trunk/drivers/net/wireless/iwlwifi/iwl-3945.h index ae94babe595b..531fa125f5a6 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -171,6 +171,24 @@ struct iwl3945_frame { #define SCAN_INTERVAL 100 +#define STATUS_HCMD_ACTIVE 0 /* host command in progress */ +#define STATUS_HCMD_SYNC_ACTIVE 1 /* sync host command in progress */ +#define STATUS_INT_ENABLED 2 +#define STATUS_RF_KILL_HW 3 +#define STATUS_INIT 5 +#define STATUS_ALIVE 6 +#define STATUS_READY 7 +#define STATUS_TEMPERATURE 8 +#define STATUS_GEO_CONFIGURED 9 +#define STATUS_EXIT_PENDING 10 +#define STATUS_STATISTICS 12 +#define STATUS_SCANNING 13 +#define STATUS_SCAN_ABORTING 14 +#define STATUS_SCAN_HW 15 +#define STATUS_POWER_PMI 16 +#define STATUS_FW_ERROR 17 +#define STATUS_CONF_PENDING 18 + #define MAX_TID_COUNT 9 #define IWL_INVALID_RATE 0xFF @@ -208,8 +226,7 @@ extern void iwl3945_rx_replenish(void *data); extern void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq); extern unsigned int iwl3945_fill_beacon_frame(struct iwl_priv *priv, struct ieee80211_hdr *hdr,int left); -extern int iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log, - char **buf, bool display); +extern void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log); extern void iwl3945_dump_nic_error_log(struct iwl_priv *priv); /* diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/trunk/drivers/net/wireless/iwlwifi/iwl-4965-hw.h index 67ef562e8db1..c606366b582c 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-4965-hw.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-4965-hw.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-4965.c b/trunk/drivers/net/wireless/iwlwifi/iwl-4965.c index 1bd2cd836026..31462813bac0 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -581,13 +581,6 @@ static int iwl4965_alive_notify(struct iwl_priv *priv) iwl4965_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0); - /* make sure all queue are not stopped */ - memset(&priv->queue_stopped[0], 0, sizeof(priv->queue_stopped)); - for (i = 0; i < 4; i++) - atomic_set(&priv->queue_stop_count[i], 0); - - /* reset to 0 to enable all the queue first */ - priv->txq_ctx_active_msk = 0; /* Map each Tx/cmd queue to its corresponding fifo */ for (i = 0; i < ARRAY_SIZE(default_queue_to_tx_fifo); i++) { int ac = default_queue_to_tx_fifo[i]; @@ -2213,10 +2206,9 @@ static struct iwl_lib_ops iwl4965_lib = { .temperature = iwl4965_temperature_calib, .set_ct_kill = iwl4965_set_ct_threshold, }, - .add_bcast_station = iwl_add_bcast_station, }; -static const struct iwl_ops iwl4965_ops = { +static struct iwl_ops iwl4965_ops = { .ucode = &iwl4965_ucode, .lib = &iwl4965_lib, .hcmd = &iwl4965_hcmd, @@ -2247,7 +2239,7 @@ struct iwl_cfg iwl4965_agn_cfg = { .broken_powersave = true, .led_compensation = 61, .chain_noise_num_beacons = IWL4965_CAL_NUM_BEACONS, - .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, + .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED, }; /* Module firmware */ diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-5000-hw.h b/trunk/drivers/net/wireless/iwlwifi/iwl-5000-hw.h index 714e032f6217..bc056e9ab85f 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-5000-hw.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-5000-hw.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-5000.c b/trunk/drivers/net/wireless/iwlwifi/iwl-5000.c index e476acb53aa7..cffaae772d51 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -179,24 +179,14 @@ static void iwl5000_gain_computation(struct iwl_priv *priv, data->delta_gain_code[i] = 0; continue; } - - delta_g = (priv->cfg->chain_noise_scale * - ((s32)average_noise[default_chain] - + delta_g = (1000 * ((s32)average_noise[default_chain] - (s32)average_noise[i])) / 1500; - /* bound gain by 2 bits value max, 3rd bit is sign */ data->delta_gain_code[i] = min(abs(delta_g), (long) CHAIN_NOISE_MAX_DELTA_GAIN_CODE); if (delta_g < 0) - /* - * set negative sign ... - * note to Intel developers: This is uCode API format, - * not the format of any internal device registers. - * Do not change this format for e.g. 6050 or similar - * devices. Change format only if more resolution - * (i.e. more than 2 bits magnitude) is needed. - */ + /* set negative sign */ data->delta_gain_code[i] |= (1 << 2); } @@ -273,8 +263,8 @@ static struct iwl_sensitivity_ranges iwl5000_sensitivity = { .auto_corr_max_ofdm = 120, .auto_corr_max_ofdm_mrc = 210, - .auto_corr_max_ofdm_x1 = 120, - .auto_corr_max_ofdm_mrc_x1 = 240, + .auto_corr_max_ofdm_x1 = 155, + .auto_corr_max_ofdm_mrc_x1 = 290, .auto_corr_min_cck = 125, .auto_corr_max_cck = 200, @@ -422,14 +412,12 @@ static void iwl5000_rx_calib_complete(struct iwl_priv *priv, /* * ucode */ -static int iwl5000_load_section(struct iwl_priv *priv, const char *name, - struct fw_desc *image, u32 dst_addr) +static int iwl5000_load_section(struct iwl_priv *priv, + struct fw_desc *image, + u32 dst_addr) { dma_addr_t phy_addr = image->p_addr; u32 byte_cnt = image->len; - int ret; - - priv->ucode_write_complete = 0; iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL), @@ -459,20 +447,6 @@ static int iwl5000_load_section(struct iwl_priv *priv, const char *name, FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE | FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD); - IWL_DEBUG_INFO(priv, "%s uCode section being loaded...\n", name); - ret = wait_event_interruptible_timeout(priv->wait_command_queue, - priv->ucode_write_complete, 5 * HZ); - if (ret == -ERESTARTSYS) { - IWL_ERR(priv, "Could not load the %s uCode section due " - "to interrupt\n", name); - return ret; - } - if (!ret) { - IWL_ERR(priv, "Could not load the %s uCode section\n", - name); - return -ETIMEDOUT; - } - return 0; } @@ -482,13 +456,48 @@ static int iwl5000_load_given_ucode(struct iwl_priv *priv, { int ret = 0; - ret = iwl5000_load_section(priv, "INST", inst_image, + ret = iwl5000_load_section(priv, inst_image, IWL50_RTC_INST_LOWER_BOUND); if (ret) return ret; - return iwl5000_load_section(priv, "DATA", data_image, - IWL50_RTC_DATA_LOWER_BOUND); + IWL_DEBUG_INFO(priv, "INST uCode section being loaded...\n"); + ret = wait_event_interruptible_timeout(priv->wait_command_queue, + priv->ucode_write_complete, 5 * HZ); + if (ret == -ERESTARTSYS) { + IWL_ERR(priv, "Could not load the INST uCode section due " + "to interrupt\n"); + return ret; + } + if (!ret) { + IWL_ERR(priv, "Could not load the INST uCode section\n"); + return -ETIMEDOUT; + } + + priv->ucode_write_complete = 0; + + ret = iwl5000_load_section( + priv, data_image, IWL50_RTC_DATA_LOWER_BOUND); + if (ret) + return ret; + + IWL_DEBUG_INFO(priv, "DATA uCode section being loaded...\n"); + + ret = wait_event_interruptible_timeout(priv->wait_command_queue, + priv->ucode_write_complete, 5 * HZ); + if (ret == -ERESTARTSYS) { + IWL_ERR(priv, "Could not load the INST uCode section due " + "to interrupt\n"); + return ret; + } else if (!ret) { + IWL_ERR(priv, "Could not load the DATA uCode section\n"); + return -ETIMEDOUT; + } else + ret = 0; + + priv->ucode_write_complete = 0; + + return ret; } int iwl5000_load_ucode(struct iwl_priv *priv) @@ -648,13 +657,6 @@ int iwl5000_alive_notify(struct iwl_priv *priv) iwl5000_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0); - /* make sure all queue are not stopped */ - memset(&priv->queue_stopped[0], 0, sizeof(priv->queue_stopped)); - for (i = 0; i < 4; i++) - atomic_set(&priv->queue_stop_count[i], 0); - - /* reset to 0 to enable all the queue first */ - priv->txq_ctx_active_msk = 0; /* map qos queues to fifos one-to-one */ for (i = 0; i < ARRAY_SIZE(iwl5000_default_queue_to_tx_fifo); i++) { int ac = iwl5000_default_queue_to_tx_fifo[i]; @@ -779,7 +781,7 @@ void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv, scd_bc_tbl[txq_id].tfd_offset[write_ptr] = bc_ent; - if (write_ptr < TFD_QUEUE_SIZE_BC_DUP) + if (txq->q.write_ptr < TFD_QUEUE_SIZE_BC_DUP) scd_bc_tbl[txq_id]. tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent; } @@ -798,12 +800,12 @@ void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv, if (txq_id != IWL_CMD_QUEUE_NUM) sta_id = txq->cmd[read_ptr]->cmd.tx.sta_id; - bc_ent = cpu_to_le16(1 | (sta_id << 12)); + bc_ent = cpu_to_le16(1 | (sta_id << 12)); scd_bc_tbl[txq_id].tfd_offset[read_ptr] = bc_ent; - if (read_ptr < TFD_QUEUE_SIZE_BC_DUP) + if (txq->q.write_ptr < TFD_QUEUE_SIZE_BC_DUP) scd_bc_tbl[txq_id]. - tfd_offset[TFD_QUEUE_SIZE_MAX + read_ptr] = bc_ent; + tfd_offset[TFD_QUEUE_SIZE_MAX + read_ptr] = bc_ent; } static int iwl5000_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid, @@ -1462,8 +1464,6 @@ struct iwl_lib_ops iwl5000_lib = { .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr, .dump_nic_event_log = iwl_dump_nic_event_log, .dump_nic_error_log = iwl_dump_nic_error_log, - .dump_csr = iwl_dump_csr, - .dump_fh = iwl_dump_fh, .load_ucode = iwl5000_load_ucode, .init_alive_start = iwl5000_init_alive_start, .alive_notify = iwl5000_alive_notify, @@ -1499,7 +1499,6 @@ struct iwl_lib_ops iwl5000_lib = { .temperature = iwl5000_temperature, .set_ct_kill = iwl5000_set_ct_threshold, }, - .add_bcast_station = iwl_add_bcast_station, }; static struct iwl_lib_ops iwl5150_lib = { @@ -1517,7 +1516,6 @@ static struct iwl_lib_ops iwl5150_lib = { .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr, .dump_nic_event_log = iwl_dump_nic_event_log, .dump_nic_error_log = iwl_dump_nic_error_log, - .dump_csr = iwl_dump_csr, .load_ucode = iwl5000_load_ucode, .init_alive_start = iwl5000_init_alive_start, .alive_notify = iwl5000_alive_notify, @@ -1553,10 +1551,9 @@ static struct iwl_lib_ops iwl5150_lib = { .temperature = iwl5150_temperature, .set_ct_kill = iwl5150_set_ct_threshold, }, - .add_bcast_station = iwl_add_bcast_station, }; -static const struct iwl_ops iwl5000_ops = { +static struct iwl_ops iwl5000_ops = { .ucode = &iwl5000_ucode, .lib = &iwl5000_lib, .hcmd = &iwl5000_hcmd, @@ -1564,7 +1561,7 @@ static const struct iwl_ops iwl5000_ops = { .led = &iwlagn_led_ops, }; -static const struct iwl_ops iwl5150_ops = { +static struct iwl_ops iwl5150_ops = { .ucode = &iwl5000_ucode, .lib = &iwl5150_lib, .hcmd = &iwl5000_hcmd, @@ -1601,8 +1598,7 @@ struct iwl_cfg iwl5300_agn_cfg = { .led_compensation = 51, .use_rts_for_ht = true, /* use rts/cts protection */ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, - .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, - .chain_noise_scale = 1000, + .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED, }; struct iwl_cfg iwl5100_bgn_cfg = { @@ -1627,8 +1623,6 @@ struct iwl_cfg iwl5100_bgn_cfg = { .led_compensation = 51, .use_rts_for_ht = true, /* use rts/cts protection */ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, - .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, - .chain_noise_scale = 1000, }; struct iwl_cfg iwl5100_abg_cfg = { @@ -1651,8 +1645,6 @@ struct iwl_cfg iwl5100_abg_cfg = { .use_bsm = false, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, - .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, - .chain_noise_scale = 1000, }; struct iwl_cfg iwl5100_agn_cfg = { @@ -1677,8 +1669,7 @@ struct iwl_cfg iwl5100_agn_cfg = { .led_compensation = 51, .use_rts_for_ht = true, /* use rts/cts protection */ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, - .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, - .chain_noise_scale = 1000, + .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED, }; struct iwl_cfg iwl5350_agn_cfg = { @@ -1703,8 +1694,7 @@ struct iwl_cfg iwl5350_agn_cfg = { .led_compensation = 51, .use_rts_for_ht = true, /* use rts/cts protection */ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, - .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, - .chain_noise_scale = 1000, + .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED, }; struct iwl_cfg iwl5150_agn_cfg = { @@ -1729,8 +1719,7 @@ struct iwl_cfg iwl5150_agn_cfg = { .led_compensation = 51, .use_rts_for_ht = true, /* use rts/cts protection */ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, - .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, - .chain_noise_scale = 1000, + .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED, }; struct iwl_cfg iwl5150_abg_cfg = { @@ -1753,8 +1742,6 @@ struct iwl_cfg iwl5150_abg_cfg = { .use_bsm = false, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, - .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, - .chain_noise_scale = 1000, }; MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX)); diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-6000-hw.h b/trunk/drivers/net/wireless/iwlwifi/iwl-6000-hw.h index ddba39999997..90185777d98b 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-6000-hw.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-6000-hw.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-6000.c b/trunk/drivers/net/wireless/iwlwifi/iwl-6000.c index c4844adff92a..74e571049273 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008-2009 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -70,14 +70,6 @@ static void iwl6000_set_ct_threshold(struct iwl_priv *priv) priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD; } -/* Indicate calibration version to uCode. */ -static void iwl6050_set_calib_version(struct iwl_priv *priv) -{ - if (priv->cfg->ops->lib->eeprom_ops.calib_version(priv) >= 6) - iwl_set_bit(priv, CSR_GP_DRIVER_REG, - CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6); -} - /* NIC configuration for 6000 series */ static void iwl6000_nic_config(struct iwl_priv *priv) { @@ -104,8 +96,6 @@ static void iwl6000_nic_config(struct iwl_priv *priv) CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA); } /* else do nothing, uCode configured */ - if (priv->cfg->ops->lib->temp_ops.set_calib_version) - priv->cfg->ops->lib->temp_ops.set_calib_version(priv); } static struct iwl_sensitivity_ranges iwl6000_sensitivity = { @@ -118,7 +108,7 @@ static struct iwl_sensitivity_ranges iwl6000_sensitivity = { .auto_corr_max_ofdm = 145, .auto_corr_max_ofdm_mrc = 232, - .auto_corr_max_ofdm_x1 = 110, + .auto_corr_max_ofdm_x1 = 145, .auto_corr_max_ofdm_mrc_x1 = 232, .auto_corr_min_cck = 125, @@ -168,25 +158,11 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv) /* Set initial sensitivity parameters */ /* Set initial calibration set */ priv->hw_params.sens = &iwl6000_sensitivity; - switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { - case CSR_HW_REV_TYPE_6x50: - priv->hw_params.calib_init_cfg = - BIT(IWL_CALIB_XTAL) | - BIT(IWL_CALIB_DC) | - BIT(IWL_CALIB_LO) | - BIT(IWL_CALIB_TX_IQ) | - BIT(IWL_CALIB_BASE_BAND); - - break; - default: - priv->hw_params.calib_init_cfg = + priv->hw_params.calib_init_cfg = BIT(IWL_CALIB_XTAL) | BIT(IWL_CALIB_LO) | BIT(IWL_CALIB_TX_IQ) | BIT(IWL_CALIB_BASE_BAND); - break; - } - return 0; } @@ -239,8 +215,6 @@ static struct iwl_lib_ops iwl6000_lib = { .load_ucode = iwl5000_load_ucode, .dump_nic_event_log = iwl_dump_nic_event_log, .dump_nic_error_log = iwl_dump_nic_error_log, - .dump_csr = iwl_dump_csr, - .dump_fh = iwl_dump_fh, .init_alive_start = iwl5000_init_alive_start, .alive_notify = iwl5000_alive_notify, .send_tx_power = iwl5000_send_tx_power, @@ -276,10 +250,9 @@ static struct iwl_lib_ops iwl6000_lib = { .temperature = iwl5000_temperature, .set_ct_kill = iwl6000_set_ct_threshold, }, - .add_bcast_station = iwl_add_bcast_station, }; -static const struct iwl_ops iwl6000_ops = { +static struct iwl_ops iwl6000_ops = { .ucode = &iwl5000_ucode, .lib = &iwl6000_lib, .hcmd = &iwl5000_hcmd, @@ -287,68 +260,18 @@ static const struct iwl_ops iwl6000_ops = { .led = &iwlagn_led_ops, }; -static struct iwl_lib_ops iwl6050_lib = { - .set_hw_params = iwl6000_hw_set_hw_params, - .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, - .txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl, - .txq_set_sched = iwl5000_txq_set_sched, - .txq_agg_enable = iwl5000_txq_agg_enable, - .txq_agg_disable = iwl5000_txq_agg_disable, - .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, - .txq_free_tfd = iwl_hw_txq_free_tfd, - .txq_init = iwl_hw_tx_queue_init, - .rx_handler_setup = iwl5000_rx_handler_setup, - .setup_deferred_work = iwl5000_setup_deferred_work, - .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr, - .load_ucode = iwl5000_load_ucode, - .dump_nic_event_log = iwl_dump_nic_event_log, - .dump_nic_error_log = iwl_dump_nic_error_log, - .dump_csr = iwl_dump_csr, - .dump_fh = iwl_dump_fh, - .init_alive_start = iwl5000_init_alive_start, - .alive_notify = iwl5000_alive_notify, - .send_tx_power = iwl5000_send_tx_power, - .update_chain_flags = iwl_update_chain_flags, - .set_channel_switch = iwl6000_hw_channel_switch, - .apm_ops = { - .init = iwl_apm_init, - .stop = iwl_apm_stop, - .config = iwl6000_nic_config, - .set_pwr_src = iwl_set_pwr_src, - }, - .eeprom_ops = { - .regulatory_bands = { - EEPROM_5000_REG_BAND_1_CHANNELS, - EEPROM_5000_REG_BAND_2_CHANNELS, - EEPROM_5000_REG_BAND_3_CHANNELS, - EEPROM_5000_REG_BAND_4_CHANNELS, - EEPROM_5000_REG_BAND_5_CHANNELS, - EEPROM_5000_REG_BAND_24_HT40_CHANNELS, - EEPROM_5000_REG_BAND_52_HT40_CHANNELS - }, - .verify_signature = iwlcore_eeprom_verify_signature, - .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, - .release_semaphore = iwlcore_eeprom_release_semaphore, - .calib_version = iwl5000_eeprom_calib_version, - .query_addr = iwl5000_eeprom_query_addr, - .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower, - }, - .post_associate = iwl_post_associate, - .isr = iwl_isr_ict, - .config_ap = iwl_config_ap, - .temp_ops = { - .temperature = iwl5000_temperature, - .set_ct_kill = iwl6000_set_ct_threshold, - .set_calib_version = iwl6050_set_calib_version, - }, - .add_bcast_station = iwl_add_bcast_station, +static struct iwl_hcmd_utils_ops iwl6050_hcmd_utils = { + .get_hcmd_size = iwl5000_get_hcmd_size, + .build_addsta_hcmd = iwl5000_build_addsta_hcmd, + .rts_tx_cmd_flag = iwl5000_rts_tx_cmd_flag, + .calc_rssi = iwl5000_calc_rssi, }; -static const struct iwl_ops iwl6050_ops = { +static struct iwl_ops iwl6050_ops = { .ucode = &iwl5000_ucode, - .lib = &iwl6050_lib, + .lib = &iwl6000_lib, .hcmd = &iwl5000_hcmd, - .utils = &iwl5000_hcmd_utils, + .utils = &iwl6050_hcmd_utils, .led = &iwlagn_led_ops, }; @@ -383,8 +306,7 @@ struct iwl_cfg iwl6000i_2agn_cfg = { .supports_idle = true, .adv_thermal_throttle = true, .support_ct_kill_exit = true, - .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, - .chain_noise_scale = 1000, + .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED, }; struct iwl_cfg iwl6000i_2abg_cfg = { @@ -414,8 +336,6 @@ struct iwl_cfg iwl6000i_2abg_cfg = { .supports_idle = true, .adv_thermal_throttle = true, .support_ct_kill_exit = true, - .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, - .chain_noise_scale = 1000, }; struct iwl_cfg iwl6000i_2bg_cfg = { @@ -445,8 +365,6 @@ struct iwl_cfg iwl6000i_2bg_cfg = { .supports_idle = true, .adv_thermal_throttle = true, .support_ct_kill_exit = true, - .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, - .chain_noise_scale = 1000, }; struct iwl_cfg iwl6050_2agn_cfg = { @@ -477,8 +395,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { .supports_idle = true, .adv_thermal_throttle = true, .support_ct_kill_exit = true, - .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, - .chain_noise_scale = 1500, + .sm_ps_mode = WLAN_HT_CAP_SM_PS_DYNAMIC, }; struct iwl_cfg iwl6050_2abg_cfg = { @@ -508,8 +425,6 @@ struct iwl_cfg iwl6050_2abg_cfg = { .supports_idle = true, .adv_thermal_throttle = true, .support_ct_kill_exit = true, - .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, - .chain_noise_scale = 1500, }; struct iwl_cfg iwl6000_3agn_cfg = { @@ -540,8 +455,7 @@ struct iwl_cfg iwl6000_3agn_cfg = { .supports_idle = true, .adv_thermal_throttle = true, .support_ct_kill_exit = true, - .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, - .chain_noise_scale = 1000, + .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED, }; MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-agn-led.c b/trunk/drivers/net/wireless/iwlwifi/iwl-agn-led.c index 1a24946bc203..3bccba20f6da 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-agn-led.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-agn-led.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-agn-led.h b/trunk/drivers/net/wireless/iwlwifi/iwl-agn-led.h index a594e4fdc6b8..ab55f92a161d 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-agn-led.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-agn-led.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/trunk/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 8bf7c20b9d39..b93e49158196 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -298,23 +298,10 @@ static void rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv, struct iwl_lq_sta *lq_data, u8 tid, struct ieee80211_sta *sta) { - int ret; - if (rs_tl_get_load(lq_data, tid) > IWL_AGG_LOAD_THRESHOLD) { IWL_DEBUG_HT(priv, "Starting Tx agg: STA: %pM tid: %d\n", sta->addr, tid); - ret = ieee80211_start_tx_ba_session(sta, tid); - if (ret == -EAGAIN) { - /* - * driver and mac80211 is out of sync - * this might be cause by reloading firmware - * stop the tx ba session here - */ - IWL_DEBUG_HT(priv, "Fail start Tx agg on tid: %d\n", - tid); - ret = ieee80211_stop_tx_ba_session(sta, tid, - WLAN_BACK_INITIATOR); - } + ieee80211_start_tx_ba_session(sta, tid); } } diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/trunk/drivers/net/wireless/iwlwifi/iwl-agn-rs.h index e71923961e69..affc0c5a2f2c 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-agn-rs.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-agn-rs.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -191,7 +191,7 @@ enum { IWL_RATE_2M_MASK) #define IWL_CCK_RATES_MASK \ - (IWL_CCK_BASIC_RATES_MASK | \ + (IWL_BASIC_RATES_MASK | \ IWL_RATE_5M_MASK | \ IWL_RATE_11M_MASK) diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-agn.c b/trunk/drivers/net/wireless/iwlwifi/iwl-agn.c index c5b724eaf306..1c9866daf815 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -73,7 +73,13 @@ #define VD #endif -#define DRV_VERSION IWLWIFI_VERSION VD +#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT +#define VS "s" +#else +#define VS +#endif + +#define DRV_VERSION IWLWIFI_VERSION VD VS MODULE_DESCRIPTION(DRV_DESCRIPTION); @@ -197,8 +203,7 @@ int iwl_commit_rxon(struct iwl_priv *priv) priv->start_calib = 0; /* Add the broadcast address so we can send broadcast frames */ - priv->cfg->ops->lib->add_bcast_station(priv); - + iwl_add_bcast_station(priv); /* If we have set the ASSOC_MSK and we are in BSS mode then * add the IWL_AP_ID to the station rate table */ @@ -652,131 +657,6 @@ static void iwl_bg_statistics_periodic(unsigned long data) iwl_send_statistics_request(priv, CMD_ASYNC, false); } - -static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base, - u32 start_idx, u32 num_events, - u32 mode) -{ - u32 i; - u32 ptr; /* SRAM byte address of log data */ - u32 ev, time, data; /* event log data */ - unsigned long reg_flags; - - if (mode == 0) - ptr = base + (4 * sizeof(u32)) + (start_idx * 2 * sizeof(u32)); - else - ptr = base + (4 * sizeof(u32)) + (start_idx * 3 * sizeof(u32)); - - /* Make sure device is powered up for SRAM reads */ - spin_lock_irqsave(&priv->reg_lock, reg_flags); - if (iwl_grab_nic_access(priv)) { - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); - return; - } - - /* Set starting address; reads will auto-increment */ - _iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, ptr); - rmb(); - - /* - * "time" is actually "data" for mode 0 (no timestamp). - * place event id # at far right for easier visual parsing. - */ - for (i = 0; i < num_events; i++) { - ev = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); - time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); - if (mode == 0) { - trace_iwlwifi_dev_ucode_cont_event(priv, - 0, time, ev); - } else { - data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); - trace_iwlwifi_dev_ucode_cont_event(priv, - time, data, ev); - } - } - /* Allow device to power down */ - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); -} - -static void iwl_continuous_event_trace(struct iwl_priv *priv) -{ - u32 capacity; /* event log capacity in # entries */ - u32 base; /* SRAM byte address of event log header */ - u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */ - u32 num_wraps; /* # times uCode wrapped to top of log */ - u32 next_entry; /* index of next entry to be written by uCode */ - - if (priv->ucode_type == UCODE_INIT) - base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr); - else - base = le32_to_cpu(priv->card_alive.log_event_table_ptr); - if (priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { - capacity = iwl_read_targ_mem(priv, base); - num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32))); - mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32))); - next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32))); - } else - return; - - if (num_wraps == priv->event_log.num_wraps) { - iwl_print_cont_event_trace(priv, - base, priv->event_log.next_entry, - next_entry - priv->event_log.next_entry, - mode); - priv->event_log.non_wraps_count++; - } else { - if ((num_wraps - priv->event_log.num_wraps) > 1) - priv->event_log.wraps_more_count++; - else - priv->event_log.wraps_once_count++; - trace_iwlwifi_dev_ucode_wrap_event(priv, - num_wraps - priv->event_log.num_wraps, - next_entry, priv->event_log.next_entry); - if (next_entry < priv->event_log.next_entry) { - iwl_print_cont_event_trace(priv, base, - priv->event_log.next_entry, - capacity - priv->event_log.next_entry, - mode); - - iwl_print_cont_event_trace(priv, base, 0, - next_entry, mode); - } else { - iwl_print_cont_event_trace(priv, base, - next_entry, capacity - next_entry, - mode); - - iwl_print_cont_event_trace(priv, base, 0, - next_entry, mode); - } - } - priv->event_log.num_wraps = num_wraps; - priv->event_log.next_entry = next_entry; -} - -/** - * iwl_bg_ucode_trace - Timer callback to log ucode event - * - * The timer is continually set to execute every - * UCODE_TRACE_PERIOD milliseconds after the last timer expired - * this function is to perform continuous uCode event logging operation - * if enabled - */ -static void iwl_bg_ucode_trace(unsigned long data) -{ - struct iwl_priv *priv = (struct iwl_priv *)data; - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - if (priv->event_log.ucode_trace) { - iwl_continuous_event_trace(priv); - /* Reschedule the timer to occur in UCODE_TRACE_PERIOD */ - mod_timer(&priv->ucode_trace, - jiffies + msecs_to_jiffies(UCODE_TRACE_PERIOD)); - } -} - static void iwl_rx_beacon_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { @@ -809,14 +689,12 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv, u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags); unsigned long status = priv->status; - IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s CT:%s\n", + IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s\n", (flags & HW_CARD_DISABLED) ? "Kill" : "On", - (flags & SW_CARD_DISABLED) ? "Kill" : "On", - (flags & CT_CARD_DISABLED) ? - "Reached" : "Not reached"); + (flags & SW_CARD_DISABLED) ? "Kill" : "On"); if (flags & (SW_CARD_DISABLED | HW_CARD_DISABLED | - CT_CARD_DISABLED)) { + RF_CARD_DISABLED)) { iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); @@ -830,10 +708,10 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv, iwl_write_direct32(priv, HBUS_TARG_MBX_C, HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); } - if (flags & CT_CARD_DISABLED) + if (flags & RF_CARD_DISABLED) iwl_tt_enter_ct_kill(priv); } - if (!(flags & CT_CARD_DISABLED)) + if (!(flags & RF_CARD_DISABLED)) iwl_tt_exit_ct_kill(priv); if (flags & HW_CARD_DISABLED) @@ -883,8 +761,6 @@ static void iwl_setup_rx_handlers(struct iwl_priv *priv) priv->rx_handlers[REPLY_ALIVE] = iwl_rx_reply_alive; priv->rx_handlers[REPLY_ERROR] = iwl_rx_reply_error; priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa; - priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] = - iwl_rx_spectrum_measure_notif; priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl_rx_pm_sleep_notif; priv->rx_handlers[PM_DEBUG_STATISTIC_NOTIFIC] = iwl_rx_pm_debug_statistics_notif; @@ -898,6 +774,7 @@ static void iwl_setup_rx_handlers(struct iwl_priv *priv) priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl_reply_statistics; priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl_rx_statistics; + iwl_setup_spectrum_handlers(priv); iwl_setup_rx_scan_handlers(priv); /* status change handler */ @@ -1757,7 +1634,7 @@ static const char *desc_lookup_text[] = { "DEBUG_1", "DEBUG_2", "DEBUG_3", - "ADVANCED SYSASSERT" + "UNKNOWN" }; static const char *desc_lookup(int i) @@ -1828,9 +1705,8 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) * iwl_print_event_log - Dump error event log to syslog * */ -static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, - u32 num_events, u32 mode, - int pos, char **buf, size_t bufsz) +static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, + u32 num_events, u32 mode) { u32 i; u32 base; /* SRAM byte address of event log header */ @@ -1840,7 +1716,7 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, unsigned long reg_flags; if (num_events == 0) - return pos; + return; if (priv->ucode_type == UCODE_INIT) base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); else @@ -1868,44 +1744,27 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); if (mode == 0) { /* data, ev */ - if (bufsz) { - pos += scnprintf(*buf + pos, bufsz - pos, - "EVT_LOG:0x%08x:%04u\n", - time, ev); - } else { - trace_iwlwifi_dev_ucode_event(priv, 0, - time, ev); - IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n", - time, ev); - } + trace_iwlwifi_dev_ucode_event(priv, 0, time, ev); + IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n", time, ev); } else { data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); - if (bufsz) { - pos += scnprintf(*buf + pos, bufsz - pos, - "EVT_LOGT:%010u:0x%08x:%04u\n", - time, data, ev); - } else { - IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n", + IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n", time, data, ev); - trace_iwlwifi_dev_ucode_event(priv, time, - data, ev); - } + trace_iwlwifi_dev_ucode_event(priv, time, data, ev); } } /* Allow device to power down */ iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->reg_lock, reg_flags); - return pos; } /** * iwl_print_last_event_logs - Dump the newest # of event log to syslog */ -static int iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity, - u32 num_wraps, u32 next_entry, - u32 size, u32 mode, - int pos, char **buf, size_t bufsz) +static void iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity, + u32 num_wraps, u32 next_entry, + u32 size, u32 mode) { /* * display the newest DEFAULT_LOG_ENTRIES entries @@ -1913,26 +1772,21 @@ static int iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity, */ if (num_wraps) { if (next_entry < size) { - pos = iwl_print_event_log(priv, - capacity - (size - next_entry), - size - next_entry, mode, - pos, buf, bufsz); - pos = iwl_print_event_log(priv, 0, - next_entry, mode, - pos, buf, bufsz); + iwl_print_event_log(priv, + capacity - (size - next_entry), + size - next_entry, mode); + iwl_print_event_log(priv, 0, + next_entry, mode); } else - pos = iwl_print_event_log(priv, next_entry - size, - size, mode, pos, buf, bufsz); + iwl_print_event_log(priv, next_entry - size, + size, mode); } else { - if (next_entry < size) { - pos = iwl_print_event_log(priv, 0, next_entry, - mode, pos, buf, bufsz); - } else { - pos = iwl_print_event_log(priv, next_entry - size, - size, mode, pos, buf, bufsz); - } + if (next_entry < size) + iwl_print_event_log(priv, 0, next_entry, mode); + else + iwl_print_event_log(priv, next_entry - size, + size, mode); } - return pos; } /* For sanity check only. Actual size is determined by uCode, typ. 512 */ @@ -1940,8 +1794,7 @@ static int iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity, #define DEFAULT_DUMP_EVENT_LOG_ENTRIES (20) -int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log, - char **buf, bool display) +void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log) { u32 base; /* SRAM byte address of event log header */ u32 capacity; /* event log capacity in # entries */ @@ -1949,8 +1802,6 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log, u32 num_wraps; /* # times uCode wrapped to top of log */ u32 next_entry; /* index of next entry to be written by uCode */ u32 size; /* # entries that we'll print */ - int pos = 0; - size_t bufsz = 0; if (priv->ucode_type == UCODE_INIT) base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); @@ -1961,7 +1812,7 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log, IWL_ERR(priv, "Invalid event log pointer 0x%08X for %s uCode\n", base, (priv->ucode_type == UCODE_INIT) ? "Init" : "RT"); - return -EINVAL; + return; } /* event log header */ @@ -1987,7 +1838,7 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log, /* bail out if nothing in log */ if (size == 0) { IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n"); - return pos; + return; } #ifdef CONFIG_IWLWIFI_DEBUG @@ -2002,15 +1853,6 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log, size); #ifdef CONFIG_IWLWIFI_DEBUG - if (display) { - if (full_log) - bufsz = capacity * 48; - else - bufsz = size * 48; - *buf = kmalloc(bufsz, GFP_KERNEL); - if (!*buf) - return -ENOMEM; - } if ((iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) || full_log) { /* * if uCode has wrapped back to top of log, @@ -2018,22 +1860,17 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log, * i.e the next one that uCode would fill. */ if (num_wraps) - pos = iwl_print_event_log(priv, next_entry, - capacity - next_entry, mode, - pos, buf, bufsz); + iwl_print_event_log(priv, next_entry, + capacity - next_entry, mode); /* (then/else) start at top of log */ - pos = iwl_print_event_log(priv, 0, - next_entry, mode, pos, buf, bufsz); + iwl_print_event_log(priv, 0, next_entry, mode); } else - pos = iwl_print_last_event_logs(priv, capacity, num_wraps, - next_entry, size, mode, - pos, buf, bufsz); + iwl_print_last_event_logs(priv, capacity, num_wraps, + next_entry, size, mode); #else - pos = iwl_print_last_event_logs(priv, capacity, num_wraps, - next_entry, size, mode, - pos, buf, bufsz); + iwl_print_last_event_logs(priv, capacity, num_wraps, + next_entry, size, mode); #endif - return pos; } /** @@ -2439,6 +2276,18 @@ static void iwl_bg_run_time_calib_work(struct work_struct *work) return; } +static void iwl_bg_up(struct work_struct *data) +{ + struct iwl_priv *priv = container_of(data, struct iwl_priv, up); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + __iwl_up(priv); + mutex_unlock(&priv->mutex); +} + static void iwl_bg_restart(struct work_struct *data) { struct iwl_priv *priv = container_of(data, struct iwl_priv, restart); @@ -2455,13 +2304,7 @@ static void iwl_bg_restart(struct work_struct *data) ieee80211_restart_hw(priv->hw); } else { iwl_down(priv); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - mutex_lock(&priv->mutex); - __iwl_up(priv); - mutex_unlock(&priv->mutex); + queue_work(priv->workqueue, &priv->up); } } @@ -2597,7 +2440,7 @@ void iwl_post_associate(struct iwl_priv *priv) * Not a mac80211 entry point function, but it fits in with all the * other mac80211 functions grouped here. */ -static int iwl_mac_setup_register(struct iwl_priv *priv) +static int iwl_setup_mac(struct iwl_priv *priv) { int ret; struct ieee80211_hw *hw = priv->hw; @@ -2613,10 +2456,6 @@ static int iwl_mac_setup_register(struct iwl_priv *priv) hw->flags |= IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_SUPPORTS_DYNAMIC_PS; - if (priv->cfg->sku & IWL_SKU_N) - hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | - IEEE80211_HW_SUPPORTS_STATIC_SMPS; - hw->sta_data_size = sizeof(struct iwl_station_priv); hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | @@ -2631,7 +2470,7 @@ static int iwl_mac_setup_register(struct iwl_priv *priv) */ hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; - hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX + 1; + hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX; /* we create the 802.11 header and a zero-length SSID element */ hw->wiphy->max_scan_ie_len = IWL_MAX_PROBE_REQUEST - 24 - 2; @@ -2829,18 +2668,14 @@ void iwl_config_ap(struct iwl_priv *priv) } static void iwl_mac_update_tkip_key(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_key_conf *keyconf, - struct ieee80211_sta *sta, - u32 iv32, u16 *phase1key) + struct ieee80211_key_conf *keyconf, const u8 *addr, + u32 iv32, u16 *phase1key) { struct iwl_priv *priv = hw->priv; IWL_DEBUG_MAC80211(priv, "enter\n"); - iwl_update_tkip_key(priv, keyconf, - sta ? sta->addr : iwl_bcast_addr, - iv32, phase1key); + iwl_update_tkip_key(priv, keyconf, addr, iv32, phase1key); IWL_DEBUG_MAC80211(priv, "leave\n"); } @@ -2941,28 +2776,14 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw, return ret; case IEEE80211_AMPDU_TX_START: IWL_DEBUG_HT(priv, "start Tx\n"); - ret = iwl_tx_agg_start(priv, sta->addr, tid, ssn); - if (ret == 0) { - priv->agg_tids_count++; - IWL_DEBUG_HT(priv, "priv->agg_tids_count = %u\n", - priv->agg_tids_count); - } - return ret; + return iwl_tx_agg_start(priv, sta->addr, tid, ssn); case IEEE80211_AMPDU_TX_STOP: IWL_DEBUG_HT(priv, "stop Tx\n"); ret = iwl_tx_agg_stop(priv, sta->addr, tid); - if ((ret == 0) && (priv->agg_tids_count > 0)) { - priv->agg_tids_count--; - IWL_DEBUG_HT(priv, "priv->agg_tids_count = %u\n", - priv->agg_tids_count); - } if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return 0; else return ret; - case IEEE80211_AMPDU_TX_OPERATIONAL: - /* do nothing */ - return -EOPNOTSUPP; default: IWL_DEBUG_HT(priv, "unknown\n"); return -EINVAL; @@ -3012,8 +2833,6 @@ static void iwl_mac_sta_notify(struct ieee80211_hw *hw, break; case STA_NOTIFY_AWAKE: WARN_ON(!sta_priv->client); - if (!sta_priv->asleep) - break; sta_priv->asleep = false; sta_id = iwl_find_station(priv, sta->addr); if (sta_id != IWL_INVALID_STATION) @@ -3290,6 +3109,7 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) init_waitqueue_head(&priv->wait_command_queue); + INIT_WORK(&priv->up, iwl_bg_up); INIT_WORK(&priv->restart, iwl_bg_restart); INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish); INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update); @@ -3306,10 +3126,6 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) priv->statistics_periodic.data = (unsigned long)priv; priv->statistics_periodic.function = iwl_bg_statistics_periodic; - init_timer(&priv->ucode_trace); - priv->ucode_trace.data = (unsigned long)priv; - priv->ucode_trace.function = iwl_bg_ucode_trace; - if (!priv->cfg->use_isr_legacy) tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) iwl_irq_tasklet, (unsigned long)priv); @@ -3328,7 +3144,6 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv) cancel_delayed_work(&priv->alive_start); cancel_work_sync(&priv->beacon_update); del_timer_sync(&priv->statistics_periodic); - del_timer_sync(&priv->ucode_trace); } static void iwl_init_hw_rates(struct iwl_priv *priv, @@ -3364,7 +3179,6 @@ static int iwl_init_drv(struct iwl_priv *priv) INIT_LIST_HEAD(&priv->free_frames); mutex_init(&priv->mutex); - mutex_init(&priv->sync_cmd_mutex); /* Clear the driver's (not device's) station table */ iwl_clear_stations_table(priv); @@ -3374,15 +3188,6 @@ static int iwl_init_drv(struct iwl_priv *priv) priv->band = IEEE80211_BAND_2GHZ; priv->iw_mode = NL80211_IFTYPE_STATION; - priv->current_ht_config.smps = IEEE80211_SMPS_STATIC; - priv->missed_beacon_threshold = IWL_MISSED_BEACON_THRESHOLD_DEF; - priv->agg_tids_count = 0; - - /* initialize force reset */ - priv->force_reset[IWL_RF_RESET].reset_duration = - IWL_DELAY_NEXT_FORCE_RF_RESET; - priv->force_reset[IWL_FW_RESET].reset_duration = - IWL_DELAY_NEXT_FORCE_FW_RELOAD; /* Choose which receivers/antennas to use */ if (priv->cfg->ops->hcmd->set_rxon_chain) @@ -3459,6 +3264,7 @@ static struct ieee80211_ops iwl_hw_ops = { .set_key = iwl_mac_set_key, .update_tkip_key = iwl_mac_update_tkip_key, .get_stats = iwl_mac_get_stats, + .get_tx_stats = iwl_mac_get_tx_stats, .conf_tx = iwl_mac_conf_tx, .reset_tsf = iwl_mac_reset_tsf, .bss_info_changed = iwl_bss_info_changed, @@ -3559,14 +3365,6 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) */ spin_lock_init(&priv->reg_lock); spin_lock_init(&priv->lock); - - /* - * stop and reset the on-board processor just in case it is in a - * strange state ... like being left stranded by a primary kernel - * and this is now the kdump kernel trying to start up - */ - iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); - iwl_hw_detect(priv); IWL_INFO(priv, "Detected Intel Wireless WiFi Link %s REV=0x%X\n", priv->cfg->name, priv->hw_rev); @@ -3641,9 +3439,9 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) iwl_setup_deferred_work(priv); iwl_setup_rx_handlers(priv); - /********************************************* - * 8. Enable interrupts and read RFKILL state - *********************************************/ + /********************************** + * 8. Setup and register mac80211 + **********************************/ /* enable interrupts if needed: hw bug w/a */ pci_read_config_word(priv->pci_dev, PCI_COMMAND, &pci_cmd); @@ -3654,6 +3452,14 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) iwl_enable_interrupts(priv); + err = iwl_setup_mac(priv); + if (err) + goto out_remove_sysfs; + + err = iwl_dbgfs_register(priv, DRV_NAME); + if (err) + IWL_ERR(priv, "failed to create debugfs files. Ignoring error: %d\n", err); + /* If platform's RF_KILL switch is NOT set to KILL */ if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) clear_bit(STATUS_RF_KILL_HW, &priv->status); @@ -3665,18 +3471,6 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) iwl_power_initialize(priv); iwl_tt_initialize(priv); - - /************************************************** - * 9. Setup and register with mac80211 and debugfs - **************************************************/ - err = iwl_mac_setup_register(priv); - if (err) - goto out_remove_sysfs; - - err = iwl_dbgfs_register(priv, DRV_NAME); - if (err) - IWL_ERR(priv, "failed to create debugfs files. Ignoring error: %d\n", err); - return 0; out_remove_sysfs: diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-calib.c b/trunk/drivers/net/wireless/iwlwifi/iwl-calib.c index 845831ac053e..95a57b36a7ea 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-calib.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-calib.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2009 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -414,6 +414,7 @@ static int iwl_sens_auto_corr_ofdm(struct iwl_priv *priv, /* Prepare a SENSITIVITY_CMD, send to uCode if values have changed */ static int iwl_sensitivity_write(struct iwl_priv *priv) { + int ret = 0; struct iwl_sensitivity_cmd cmd ; struct iwl_sensitivity_data *data = NULL; struct iwl_host_cmd cmd_out = { @@ -476,7 +477,11 @@ static int iwl_sensitivity_write(struct iwl_priv *priv) memcpy(&(priv->sensitivity_tbl[0]), &(cmd.table[0]), sizeof(u16)*HD_TABLE_SIZE); - return iwl_send_cmd(priv, &cmd_out); + ret = iwl_send_cmd(priv, &cmd_out); + if (ret) + IWL_ERR(priv, "SENSITIVITY_CMD failed\n"); + + return ret; } void iwl_init_sensitivity(struct iwl_priv *priv) diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-calib.h b/trunk/drivers/net/wireless/iwlwifi/iwl-calib.h index 2b7b1df83ba0..b6cef989a796 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-calib.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-calib.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2009 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-commands.h b/trunk/drivers/net/wireless/iwlwifi/iwl-commands.h index ab3c77b92cc8..cfd6c8423113 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -120,6 +120,7 @@ enum { CALIBRATION_COMPLETE_NOTIFICATION = 0x67, /* 802.11h related */ + RADAR_NOTIFICATION = 0x70, /* not used */ REPLY_QUIET_CMD = 0x71, /* not used */ REPLY_CHANNEL_SWITCH = 0x72, CHANNEL_SWITCH_NOTIFICATION = 0x73, @@ -2247,22 +2248,10 @@ struct iwl_link_quality_cmd { __le32 reserved2; } __attribute__ ((packed)); -/* - * BT configuration enable flags: - * bit 0 - 1: BT channel announcement enabled - * 0: disable - * bit 1 - 1: priority of BT device enabled - * 0: disable - * bit 2 - 1: BT 2 wire support enabled - * 0: disable - */ -#define BT_COEX_DISABLE (0x0) -#define BT_ENABLE_CHANNEL_ANNOUNCE BIT(0) -#define BT_ENABLE_PRIORITY BIT(1) -#define BT_ENABLE_2_WIRE BIT(2) - #define BT_COEX_DISABLE (0x0) -#define BT_COEX_ENABLE (BT_ENABLE_CHANNEL_ANNOUNCE | BT_ENABLE_PRIORITY) +#define BT_COEX_MODE_2W (0x1) +#define BT_COEX_MODE_3W (0x2) +#define BT_COEX_MODE_4W (0x3) #define BT_LEAD_TIME_MIN (0x0) #define BT_LEAD_TIME_DEF (0x1E) @@ -2521,7 +2510,7 @@ struct iwl_card_state_notif { #define HW_CARD_DISABLED 0x01 #define SW_CARD_DISABLED 0x02 -#define CT_CARD_DISABLED 0x04 +#define RF_CARD_DISABLED 0x04 #define RXON_CARD_DISABLED 0x10 struct iwl_ct_kill_config { @@ -2623,6 +2612,7 @@ struct iwl_ssid_ie { #define TX_CMD_LIFE_TIME_INFINITE cpu_to_le32(0xFFFFFFFF) #define IWL_GOOD_CRC_TH cpu_to_le16(1) #define IWL_MAX_SCAN_SIZE 1024 +#define IWL_MAX_CMD_SIZE 4096 #define IWL_MAX_PROBE_REQUEST 200 /* @@ -2995,7 +2985,7 @@ struct statistics_rx_ht_phy { __le32 agg_crc32_good; __le32 agg_mpdu_cnt; __le32 agg_cnt; - __le32 unsupport_mcs; + __le32 reserved2; } __attribute__ ((packed)); #define INTERFERENCE_DATA_AVAILABLE cpu_to_le32(1) @@ -3098,8 +3088,8 @@ struct statistics_div { } __attribute__ ((packed)); struct statistics_general { - __le32 temperature; /* radio temperature */ - __le32 temperature_m; /* for 5000 and up, this is radio voltage */ + __le32 temperature; + __le32 temperature_m; struct statistics_dbg dbg; __le32 sleep_time; __le32 slots_out; @@ -3107,12 +3097,7 @@ struct statistics_general { __le32 ttl_timestamp; struct statistics_div div; __le32 rx_enable_counter; - /* - * num_of_sos_states: - * count the number of times we have to re-tune - * in order to get out of bad PHY status - */ - __le32 num_of_sos_states; + __le32 reserved1; __le32 reserved2; __le32 reserved3; } __attribute__ ((packed)); @@ -3177,30 +3162,13 @@ struct iwl_notif_statistics { /* * MISSED_BEACONS_NOTIFICATION = 0xa2 (notification only, not a command) - * - * uCode send MISSED_BEACONS_NOTIFICATION to driver when detect beacon missed - * in regardless of how many missed beacons, which mean when driver receive the - * notification, inside the command, it can find all the beacons information - * which include number of total missed beacons, number of consecutive missed - * beacons, number of beacons received and number of beacons expected to - * receive. - * - * If uCode detected consecutive_missed_beacons > 5, it will reset the radio - * in order to bring the radio/PHY back to working state; which has no relation - * to when driver will perform sensitivity calibration. - * - * Driver should set it own missed_beacon_threshold to decide when to perform - * sensitivity calibration based on number of consecutive missed beacons in - * order to improve overall performance, especially in noisy environment. - * */ - -#define IWL_MISSED_BEACON_THRESHOLD_MIN (1) -#define IWL_MISSED_BEACON_THRESHOLD_DEF (5) -#define IWL_MISSED_BEACON_THRESHOLD_MAX IWL_MISSED_BEACON_THRESHOLD_DEF +/* if ucode missed CONSECUTIVE_MISSED_BCONS_TH beacons in a row, + * then this notification will be sent. */ +#define CONSECUTIVE_MISSED_BCONS_TH 20 struct iwl_missed_beacon_notif { - __le32 consecutive_missed_beacons; + __le32 consequtive_missed_beacons; __le32 total_missed_becons; __le32 num_expected_beacons; __le32 num_recvd_beacons; @@ -3470,7 +3438,11 @@ enum { IWL_PHY_CALIBRATE_DIFF_GAIN_CMD = 7, IWL_PHY_CALIBRATE_DC_CMD = 8, IWL_PHY_CALIBRATE_LO_CMD = 9, + IWL_PHY_CALIBRATE_RX_BB_CMD = 10, IWL_PHY_CALIBRATE_TX_IQ_CMD = 11, + IWL_PHY_CALIBRATE_RX_IQ_CMD = 12, + IWL_PHY_CALIBRATION_NOISE_CMD = 13, + IWL_PHY_CALIBRATE_AGC_TABLE_CMD = 14, IWL_PHY_CALIBRATE_CRYSTAL_FRQ_CMD = 15, IWL_PHY_CALIBRATE_BASE_BAND_CMD = 16, IWL_PHY_CALIBRATE_TX_IQ_PERD_CMD = 17, diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-core.c b/trunk/drivers/net/wireless/iwlwifi/iwl-core.c index 112149e9b31e..f36f804804fc 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2009 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -47,26 +47,6 @@ MODULE_VERSION(IWLWIFI_VERSION); MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); MODULE_LICENSE("GPL"); -/* - * set bt_coex_active to true, uCode will do kill/defer - * every time the priority line is asserted (BT is sending signals on the - * priority line in the PCIx). - * set bt_coex_active to false, uCode will ignore the BT activity and - * perform the normal operation - * - * User might experience transmit issue on some platform due to WiFi/BT - * co-exist problem. The possible behaviors are: - * Able to scan and finding all the available AP - * Not able to associate with any AP - * On those platforms, WiFi communication can be restored by set - * "bt_coex_active" module parameter to "false" - * - * default: bt_coex_active = true (BT_COEX_ENABLE) - */ -static bool bt_coex_active = true; -module_param(bt_coex_active, bool, S_IRUGO); -MODULE_PARM_DESC(bt_coex_active, "enable wifi/bluetooth co-exist\n"); - static struct iwl_wimax_coex_event_entry cu_priorities[COEX_NUM_OF_EVENTS] = { {COEX_CU_UNASSOC_IDLE_RP, COEX_CU_UNASSOC_IDLE_WP, 0, COEX_UNASSOC_IDLE_FLAGS}, @@ -277,8 +257,8 @@ int iwl_hw_nic_init(struct iwl_priv *priv) spin_lock_irqsave(&priv->lock, flags); priv->cfg->ops->lib->apm_ops.init(priv); - /* Set interrupt coalescing calibration timer to default (512 usecs) */ - iwl_write8(priv, CSR_INT_COALESCING, IWL_HOST_INT_CALIB_TIMEOUT_DEF); + /* Set interrupt coalescing timer to 512 usecs */ + iwl_write8(priv, CSR_INT_COALESCING, 512 / 32); spin_unlock_irqrestore(&priv->lock, flags); @@ -470,6 +450,8 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, if (priv->cfg->ht_greenfield_support) ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD; ht_info->cap |= IEEE80211_HT_CAP_SGI_20; + ht_info->cap |= (IEEE80211_HT_CAP_SM_PS & + (priv->cfg->sm_ps_mode << 2)); max_bit_rate = MAX_BIT_RATE_20_MHZ; if (priv->hw_params.ht40_channel & BIT(band)) { ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; @@ -654,7 +636,7 @@ EXPORT_SYMBOL(iwlcore_rts_tx_cmd_flag); static bool is_single_rx_stream(struct iwl_priv *priv) { - return priv->current_ht_config.smps == IEEE80211_SMPS_STATIC || + return !priv->current_ht_config.is_ht || priv->current_ht_config.single_chain_sufficient; } @@ -1021,18 +1003,28 @@ static int iwl_get_active_rx_chain_count(struct iwl_priv *priv) */ static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt) { - /* # Rx chains when idling, depending on SMPS mode */ - switch (priv->current_ht_config.smps) { - case IEEE80211_SMPS_STATIC: - case IEEE80211_SMPS_DYNAMIC: - return IWL_NUM_IDLE_CHAINS_SINGLE; - case IEEE80211_SMPS_OFF: - return active_cnt; + int idle_cnt = active_cnt; + bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status); + + /* # Rx chains when idling and maybe trying to save power */ + switch (priv->cfg->sm_ps_mode) { + case WLAN_HT_CAP_SM_PS_STATIC: + idle_cnt = (is_cam) ? active_cnt : IWL_NUM_IDLE_CHAINS_SINGLE; + break; + case WLAN_HT_CAP_SM_PS_DYNAMIC: + idle_cnt = (is_cam) ? IWL_NUM_IDLE_CHAINS_DUAL : + IWL_NUM_IDLE_CHAINS_SINGLE; + break; + case WLAN_HT_CAP_SM_PS_DISABLED: + break; + case WLAN_HT_CAP_SM_PS_INVALID: default: - WARN(1, "invalid SMPS mode %d", - priv->current_ht_config.smps); - return active_cnt; + IWL_ERR(priv, "invalid sm_ps mode %u\n", + priv->cfg->sm_ps_mode); + WARN_ON(1); + break; } + return idle_cnt; } /* up to 4 chains */ @@ -1371,11 +1363,7 @@ void iwl_irq_handle_error(struct iwl_priv *priv) clear_bit(STATUS_HCMD_ACTIVE, &priv->status); priv->cfg->ops->lib->dump_nic_error_log(priv); - if (priv->cfg->ops->lib->dump_csr) - priv->cfg->ops->lib->dump_csr(priv); - if (priv->cfg->ops->lib->dump_fh) - priv->cfg->ops->lib->dump_fh(priv, NULL, false); - priv->cfg->ops->lib->dump_nic_event_log(priv, false, NULL, false); + priv->cfg->ops->lib->dump_nic_event_log(priv, false); #ifdef CONFIG_IWLWIFI_DEBUG if (iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) iwl_print_rx_config_cmd(priv); @@ -1670,9 +1658,9 @@ EXPORT_SYMBOL(iwl_set_tx_power); void iwl_free_isr_ict(struct iwl_priv *priv) { if (priv->ict_tbl_vir) { - dma_free_coherent(&priv->pci_dev->dev, - (sizeof(u32) * ICT_COUNT) + PAGE_SIZE, - priv->ict_tbl_vir, priv->ict_tbl_dma); + pci_free_consistent(priv->pci_dev, (sizeof(u32) * ICT_COUNT) + + PAGE_SIZE, priv->ict_tbl_vir, + priv->ict_tbl_dma); priv->ict_tbl_vir = NULL; } } @@ -1688,9 +1676,9 @@ int iwl_alloc_isr_ict(struct iwl_priv *priv) if (priv->cfg->use_isr_legacy) return 0; /* allocate shrared data table */ - priv->ict_tbl_vir = dma_alloc_coherent(&priv->pci_dev->dev, - (sizeof(u32) * ICT_COUNT) + PAGE_SIZE, - &priv->ict_tbl_dma, GFP_KERNEL); + priv->ict_tbl_vir = pci_alloc_consistent(priv->pci_dev, (sizeof(u32) * + ICT_COUNT) + PAGE_SIZE, + &priv->ict_tbl_dma); if (!priv->ict_tbl_vir) return -ENOMEM; @@ -1825,16 +1813,6 @@ irqreturn_t iwl_isr_ict(int irq, void *data) if (val == 0xffffffff) val = 0; - /* - * this is a w/a for a h/w bug. the h/w bug may cause the Rx bit - * (bit 15 before shifting it to 31) to clear when using interrupt - * coalescing. fortunately, bits 18 and 19 stay set when this happens - * so we use them to decide on the real state of the Rx bit. - * In order words, bit 15 is set if bit 18 or bit 19 are set. - */ - if (val & 0xC0000) - val |= 0x8000; - inta = (0xff & val) | ((0xff00 & val) << 16); IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x ict 0x%08x\n", inta, inta_mask, val); @@ -1997,20 +1975,13 @@ EXPORT_SYMBOL(iwl_isr_legacy); int iwl_send_bt_config(struct iwl_priv *priv) { struct iwl_bt_cmd bt_cmd = { + .flags = BT_COEX_MODE_4W, .lead_time = BT_LEAD_TIME_DEF, .max_kill = BT_MAX_KILL_DEF, .kill_ack_mask = 0, .kill_cts_mask = 0, }; - if (!bt_coex_active) - bt_cmd.flags = BT_COEX_DISABLE; - else - bt_cmd.flags = BT_COEX_ENABLE; - - IWL_DEBUG_INFO(priv, "BT coex %s\n", - (bt_cmd.flags == BT_COEX_DISABLE) ? "disable" : "active"); - return iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG, sizeof(struct iwl_bt_cmd), &bt_cmd); } @@ -2628,43 +2599,44 @@ int iwl_set_mode(struct iwl_priv *priv, int mode) EXPORT_SYMBOL(iwl_set_mode); int iwl_mac_add_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) + struct ieee80211_if_init_conf *conf) { struct iwl_priv *priv = hw->priv; - int err = 0; - - IWL_DEBUG_MAC80211(priv, "enter: type %d\n", vif->type); + unsigned long flags; - mutex_lock(&priv->mutex); + IWL_DEBUG_MAC80211(priv, "enter: type %d\n", conf->type); if (priv->vif) { IWL_DEBUG_MAC80211(priv, "leave - vif != NULL\n"); - err = -EOPNOTSUPP; - goto out; + return -EOPNOTSUPP; } - priv->vif = vif; - priv->iw_mode = vif->type; + spin_lock_irqsave(&priv->lock, flags); + priv->vif = conf->vif; + priv->iw_mode = conf->type; + + spin_unlock_irqrestore(&priv->lock, flags); + + mutex_lock(&priv->mutex); - if (vif->addr) { - IWL_DEBUG_MAC80211(priv, "Set %pM\n", vif->addr); - memcpy(priv->mac_addr, vif->addr, ETH_ALEN); + if (conf->mac_addr) { + IWL_DEBUG_MAC80211(priv, "Set %pM\n", conf->mac_addr); + memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); } - if (iwl_set_mode(priv, vif->type) == -EAGAIN) + if (iwl_set_mode(priv, conf->type) == -EAGAIN) /* we are not ready, will run again when ready */ set_bit(STATUS_MODE_PENDING, &priv->status); - out: mutex_unlock(&priv->mutex); IWL_DEBUG_MAC80211(priv, "leave\n"); - return err; + return 0; } EXPORT_SYMBOL(iwl_mac_add_interface); void iwl_mac_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) + struct ieee80211_if_init_conf *conf) { struct iwl_priv *priv = hw->priv; @@ -2677,7 +2649,7 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw, priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; iwlcore_commit_rxon(priv); } - if (priv->vif == vif) { + if (priv->vif == conf->vif) { priv->vif = NULL; memset(priv->bssid, 0, ETH_ALEN); } @@ -2717,21 +2689,6 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) IWL_DEBUG_MAC80211(priv, "leave - scanning\n"); } - if (changed & (IEEE80211_CONF_CHANGE_SMPS | - IEEE80211_CONF_CHANGE_CHANNEL)) { - /* mac80211 uses static for non-HT which is what we want */ - priv->current_ht_config.smps = conf->smps_mode; - - /* - * Recalculate chain counts. - * - * If monitor mode is enabled then mac80211 will - * set up the SM PS mode to OFF if an HT channel is - * configured. - */ - if (priv->cfg->ops->hcmd->set_rxon_chain) - priv->cfg->ops->hcmd->set_rxon_chain(priv); - } /* during scanning mac80211 will delay channel setting until * scan finish with changed = 0 @@ -2829,6 +2786,10 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) iwl_set_tx_power(priv, conf->power_level, false); } + /* call to ensure that 4965 rx_chain is set properly in monitor mode */ + if (priv->cfg->ops->hcmd->set_rxon_chain) + priv->cfg->ops->hcmd->set_rxon_chain(priv); + if (!iwl_is_ready(priv)) { IWL_DEBUG_MAC80211(priv, "leave - not ready\n"); goto out; @@ -2851,6 +2812,42 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) } EXPORT_SYMBOL(iwl_mac_config); +int iwl_mac_get_tx_stats(struct ieee80211_hw *hw, + struct ieee80211_tx_queue_stats *stats) +{ + struct iwl_priv *priv = hw->priv; + int i, avail; + struct iwl_tx_queue *txq; + struct iwl_queue *q; + unsigned long flags; + + IWL_DEBUG_MAC80211(priv, "enter\n"); + + if (!iwl_is_ready_rf(priv)) { + IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n"); + return -EIO; + } + + spin_lock_irqsave(&priv->lock, flags); + + for (i = 0; i < AC_NUM; i++) { + txq = &priv->txq[i]; + q = &txq->q; + avail = iwl_queue_space(q); + + stats[i].len = q->n_window - avail; + stats[i].limit = q->n_window - q->high_mark; + stats[i].count = q->n_window; + + } + spin_unlock_irqrestore(&priv->lock, flags); + + IWL_DEBUG_MAC80211(priv, "leave\n"); + + return 0; +} +EXPORT_SYMBOL(iwl_mac_get_tx_stats); + void iwl_mac_reset_tsf(struct ieee80211_hw *hw) { struct iwl_priv *priv = hw->priv; @@ -3200,207 +3197,6 @@ void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len) EXPORT_SYMBOL(iwl_update_stats); #endif -const static char *get_csr_string(int cmd) -{ - switch (cmd) { - IWL_CMD(CSR_HW_IF_CONFIG_REG); - IWL_CMD(CSR_INT_COALESCING); - IWL_CMD(CSR_INT); - IWL_CMD(CSR_INT_MASK); - IWL_CMD(CSR_FH_INT_STATUS); - IWL_CMD(CSR_GPIO_IN); - IWL_CMD(CSR_RESET); - IWL_CMD(CSR_GP_CNTRL); - IWL_CMD(CSR_HW_REV); - IWL_CMD(CSR_EEPROM_REG); - IWL_CMD(CSR_EEPROM_GP); - IWL_CMD(CSR_OTP_GP_REG); - IWL_CMD(CSR_GIO_REG); - IWL_CMD(CSR_GP_UCODE_REG); - IWL_CMD(CSR_GP_DRIVER_REG); - IWL_CMD(CSR_UCODE_DRV_GP1); - IWL_CMD(CSR_UCODE_DRV_GP2); - IWL_CMD(CSR_LED_REG); - IWL_CMD(CSR_DRAM_INT_TBL_REG); - IWL_CMD(CSR_GIO_CHICKEN_BITS); - IWL_CMD(CSR_ANA_PLL_CFG); - IWL_CMD(CSR_HW_REV_WA_REG); - IWL_CMD(CSR_DBG_HPET_MEM_REG); - default: - return "UNKNOWN"; - - } -} - -void iwl_dump_csr(struct iwl_priv *priv) -{ - int i; - u32 csr_tbl[] = { - CSR_HW_IF_CONFIG_REG, - CSR_INT_COALESCING, - CSR_INT, - CSR_INT_MASK, - CSR_FH_INT_STATUS, - CSR_GPIO_IN, - CSR_RESET, - CSR_GP_CNTRL, - CSR_HW_REV, - CSR_EEPROM_REG, - CSR_EEPROM_GP, - CSR_OTP_GP_REG, - CSR_GIO_REG, - CSR_GP_UCODE_REG, - CSR_GP_DRIVER_REG, - CSR_UCODE_DRV_GP1, - CSR_UCODE_DRV_GP2, - CSR_LED_REG, - CSR_DRAM_INT_TBL_REG, - CSR_GIO_CHICKEN_BITS, - CSR_ANA_PLL_CFG, - CSR_HW_REV_WA_REG, - CSR_DBG_HPET_MEM_REG - }; - IWL_ERR(priv, "CSR values:\n"); - IWL_ERR(priv, "(2nd byte of CSR_INT_COALESCING is " - "CSR_INT_PERIODIC_REG)\n"); - for (i = 0; i < ARRAY_SIZE(csr_tbl); i++) { - IWL_ERR(priv, " %25s: 0X%08x\n", - get_csr_string(csr_tbl[i]), - iwl_read32(priv, csr_tbl[i])); - } -} -EXPORT_SYMBOL(iwl_dump_csr); - -const static char *get_fh_string(int cmd) -{ - switch (cmd) { - IWL_CMD(FH_RSCSR_CHNL0_STTS_WPTR_REG); - IWL_CMD(FH_RSCSR_CHNL0_RBDCB_BASE_REG); - IWL_CMD(FH_RSCSR_CHNL0_WPTR); - IWL_CMD(FH_MEM_RCSR_CHNL0_CONFIG_REG); - IWL_CMD(FH_MEM_RSSR_SHARED_CTRL_REG); - IWL_CMD(FH_MEM_RSSR_RX_STATUS_REG); - IWL_CMD(FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV); - IWL_CMD(FH_TSSR_TX_STATUS_REG); - IWL_CMD(FH_TSSR_TX_ERROR_REG); - default: - return "UNKNOWN"; - - } -} - -int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display) -{ - int i; -#ifdef CONFIG_IWLWIFI_DEBUG - int pos = 0; - size_t bufsz = 0; -#endif - u32 fh_tbl[] = { - FH_RSCSR_CHNL0_STTS_WPTR_REG, - FH_RSCSR_CHNL0_RBDCB_BASE_REG, - FH_RSCSR_CHNL0_WPTR, - FH_MEM_RCSR_CHNL0_CONFIG_REG, - FH_MEM_RSSR_SHARED_CTRL_REG, - FH_MEM_RSSR_RX_STATUS_REG, - FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV, - FH_TSSR_TX_STATUS_REG, - FH_TSSR_TX_ERROR_REG - }; -#ifdef CONFIG_IWLWIFI_DEBUG - if (display) { - bufsz = ARRAY_SIZE(fh_tbl) * 48 + 40; - *buf = kmalloc(bufsz, GFP_KERNEL); - if (!*buf) - return -ENOMEM; - pos += scnprintf(*buf + pos, bufsz - pos, - "FH register values:\n"); - for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) { - pos += scnprintf(*buf + pos, bufsz - pos, - " %34s: 0X%08x\n", - get_fh_string(fh_tbl[i]), - iwl_read_direct32(priv, fh_tbl[i])); - } - return pos; - } -#endif - IWL_ERR(priv, "FH register values:\n"); - for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) { - IWL_ERR(priv, " %34s: 0X%08x\n", - get_fh_string(fh_tbl[i]), - iwl_read_direct32(priv, fh_tbl[i])); - } - return 0; -} -EXPORT_SYMBOL(iwl_dump_fh); - -static void iwl_force_rf_reset(struct iwl_priv *priv) -{ - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - if (!iwl_is_associated(priv)) { - IWL_DEBUG_SCAN(priv, "force reset rejected: not associated\n"); - return; - } - /* - * There is no easy and better way to force reset the radio, - * the only known method is switching channel which will force to - * reset and tune the radio. - * Use internal short scan (single channel) operation to should - * achieve this objective. - * Driver should reset the radio when number of consecutive missed - * beacon, or any other uCode error condition detected. - */ - IWL_DEBUG_INFO(priv, "perform radio reset.\n"); - iwl_internal_short_hw_scan(priv); - return; -} - - -int iwl_force_reset(struct iwl_priv *priv, int mode) -{ - struct iwl_force_reset *force_reset; - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return -EINVAL; - - if (mode >= IWL_MAX_FORCE_RESET) { - IWL_DEBUG_INFO(priv, "invalid reset request.\n"); - return -EINVAL; - } - force_reset = &priv->force_reset[mode]; - force_reset->reset_request_count++; - if (force_reset->last_force_reset_jiffies && - time_after(force_reset->last_force_reset_jiffies + - force_reset->reset_duration, jiffies)) { - IWL_DEBUG_INFO(priv, "force reset rejected\n"); - force_reset->reset_reject_count++; - return -EAGAIN; - } - force_reset->reset_success_count++; - force_reset->last_force_reset_jiffies = jiffies; - IWL_DEBUG_INFO(priv, "perform force reset (%d)\n", mode); - switch (mode) { - case IWL_RF_RESET: - iwl_force_rf_reset(priv); - break; - case IWL_FW_RESET: - IWL_ERR(priv, "On demand firmware reload\n"); - /* Set the FW error flag -- cleared on iwl_down */ - set_bit(STATUS_FW_ERROR, &priv->status); - wake_up_interruptible(&priv->wait_command_queue); - /* - * Keep the restart process from trying to send host - * commands by clearing the INIT status bit - */ - clear_bit(STATUS_READY, &priv->status); - queue_work(priv->workqueue, &priv->restart); - break; - } - return 0; -} - #ifdef CONFIG_PM int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state) diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-core.h b/trunk/drivers/net/wireless/iwlwifi/iwl-core.h index 4ef7739f9e8e..fe37d6a6bf97 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-core.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2009 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -63,6 +63,8 @@ #ifndef __iwl_core_h__ #define __iwl_core_h__ +#include + /************************ * forward declarations * ************************/ @@ -70,8 +72,8 @@ struct iwl_host_cmd; struct iwl_cmd; -#define IWLWIFI_VERSION "in-tree:" -#define DRV_COPYRIGHT "Copyright(c) 2003-2010 Intel Corporation" +#define IWLWIFI_VERSION UTS_RELEASE "-k" +#define DRV_COPYRIGHT "Copyright(c) 2003-2009 Intel Corporation" #define DRV_AUTHOR "" #define IWL_PCI_DEVICE(dev, subdev, cfg) \ @@ -117,7 +119,6 @@ struct iwl_apm_ops { struct iwl_temp_ops { void (*temperature)(struct iwl_priv *priv); void (*set_ct_kill)(struct iwl_priv *priv); - void (*set_calib_version)(struct iwl_priv *priv); }; struct iwl_ucode_ops { @@ -168,11 +169,8 @@ struct iwl_lib_ops { int (*is_valid_rtc_data_addr)(u32 addr); /* 1st ucode load */ int (*load_ucode)(struct iwl_priv *priv); - int (*dump_nic_event_log)(struct iwl_priv *priv, - bool full_log, char **buf, bool display); + void (*dump_nic_event_log)(struct iwl_priv *priv, bool full_log); void (*dump_nic_error_log)(struct iwl_priv *priv); - void (*dump_csr)(struct iwl_priv *priv); - int (*dump_fh)(struct iwl_priv *priv, char **buf, bool display); int (*set_channel_switch)(struct iwl_priv *priv, u16 channel); /* power management */ struct iwl_apm_ops apm_ops; @@ -189,8 +187,6 @@ struct iwl_lib_ops { /* temperature */ struct iwl_temp_ops temp_ops; - /* station management */ - void (*add_bcast_station)(struct iwl_priv *priv); }; struct iwl_led_ops { @@ -234,9 +230,8 @@ struct iwl_mod_params { * @chain_noise_num_beacons: number of beacons used to compute chain noise * @adv_thermal_throttle: support advance thermal throttle * @support_ct_kill_exit: support ct kill exit condition + * @sm_ps_mode: spatial multiplexing power save mode * @support_wimax_coexist: support wimax/wifi co-exist - * @plcp_delta_threshold: plcp error rate threshold used to trigger - * radio tuning when there is a high receiving plcp error rate * * We enable the driver to be backward compatible wrt API version. The * driver specifies which APIs it supports (with @ucode_api_max being the @@ -292,9 +287,8 @@ struct iwl_cfg { const bool supports_idle; bool adv_thermal_throttle; bool support_ct_kill_exit; + u8 sm_ps_mode; const bool support_wimax_coexist; - u8 plcp_delta_threshold; - s32 chain_noise_scale; }; /*************************** @@ -338,11 +332,13 @@ int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb); int iwl_commit_rxon(struct iwl_priv *priv); int iwl_set_mode(struct iwl_priv *priv, int mode); int iwl_mac_add_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif); + struct ieee80211_if_init_conf *conf); void iwl_mac_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif); + struct ieee80211_if_init_conf *conf); int iwl_mac_config(struct ieee80211_hw *hw, u32 changed); void iwl_config_ap(struct iwl_priv *priv); +int iwl_mac_get_tx_stats(struct ieee80211_hw *hw, + struct ieee80211_tx_queue_stats *stats); void iwl_mac_reset_tsf(struct ieee80211_hw *hw); int iwl_alloc_txq_mem(struct iwl_priv *priv); void iwl_free_txq_mem(struct iwl_priv *priv); @@ -415,13 +411,13 @@ void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq); void iwl_cmd_queue_free(struct iwl_priv *priv); int iwl_rx_queue_alloc(struct iwl_priv *priv); void iwl_rx_handle(struct iwl_priv *priv); -void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, +int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q); void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq); void iwl_rx_replenish(struct iwl_priv *priv); void iwl_rx_replenish_now(struct iwl_priv *priv); int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq); -void iwl_rx_queue_restock(struct iwl_priv *priv); +int iwl_rx_queue_restock(struct iwl_priv *priv); int iwl_rx_queue_space(const struct iwl_rx_queue *q); void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority); void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); @@ -429,8 +425,6 @@ int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index); /* Handlers */ void iwl_rx_missed_beacon_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); -void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb); void iwl_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); void iwl_reply_statistics(struct iwl_priv *priv, @@ -451,9 +445,9 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb); void iwl_hw_txq_ctx_free(struct iwl_priv *priv); int iwl_hw_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq); +int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq); void iwl_free_tfds_in_queue(struct iwl_priv *priv, int sta_id, int tid, int freed); -void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq); int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq, int slots_num, u32 txq_id); void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id); @@ -503,8 +497,6 @@ void iwl_init_scan_params(struct iwl_priv *priv); int iwl_scan_cancel(struct iwl_priv *priv); int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms); int iwl_mac_hw_scan(struct ieee80211_hw *hw, struct cfg80211_scan_request *req); -int iwl_internal_short_hw_scan(struct iwl_priv *priv); -int iwl_force_reset(struct iwl_priv *priv, int mode); u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame, const u8 *ie, int ie_len, int left); void iwl_setup_rx_scan_handlers(struct iwl_priv *priv); @@ -535,6 +527,14 @@ int iwl_send_calib_results(struct iwl_priv *priv); int iwl_calib_set(struct iwl_calib_result *res, const u8 *buf, int len); void iwl_calib_free_results(struct iwl_priv *priv); +/******************************************************************************* + * Spectrum Measureemtns in iwl-spectrum.c + ******************************************************************************/ +#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT +void iwl_setup_spectrum_handlers(struct iwl_priv *priv); +#else +static inline void iwl_setup_spectrum_handlers(struct iwl_priv *priv) {} +#endif /***************************************************** * S e n d i n g H o s t C o m m a n d s * *****************************************************/ @@ -583,10 +583,7 @@ int iwl_pci_resume(struct pci_dev *pdev); * Error Handling Debugging ******************************************************/ void iwl_dump_nic_error_log(struct iwl_priv *priv); -int iwl_dump_nic_event_log(struct iwl_priv *priv, - bool full_log, char **buf, bool display); -void iwl_dump_csr(struct iwl_priv *priv); -int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display); +void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log); #ifdef CONFIG_IWLWIFI_DEBUG void iwl_print_rx_config_cmd(struct iwl_priv *priv); #else @@ -606,7 +603,7 @@ void iwlcore_free_geos(struct iwl_priv *priv); /*************** DRIVER STATUS FUNCTIONS *****/ #define STATUS_HCMD_ACTIVE 0 /* host command in progress */ -/* 1 is unused (used to be STATUS_HCMD_SYNC_ACTIVE) */ +#define STATUS_HCMD_SYNC_ACTIVE 1 /* sync host command in progress */ #define STATUS_INT_ENABLED 2 #define STATUS_RF_KILL_HW 3 #define STATUS_CT_KILL 4 diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-csr.h b/trunk/drivers/net/wireless/iwlwifi/iwl-csr.h index 808b7146bead..1ec8cb4d5eae 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -369,7 +369,7 @@ #define CSR_GP_DRIVER_REG_BIT_RADIO_SKU_3x3_HYB (0x00000000) #define CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_HYB (0x00000001) #define CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA (0x00000002) -#define CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6 (0x00000004) + /* GIO Chicken Bits (PCI Express bus link power management) */ #define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX (0x00800000) diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-debug.h b/trunk/drivers/net/wireless/iwlwifi/iwl-debug.h index 1c7b53d511c7..d61293ab67c9 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project. * @@ -67,6 +67,57 @@ do { \ DUMP_PREFIX_OFFSET, 16, 1, p, len, 1); \ } while (0) +#ifdef CONFIG_IWLWIFI_DEBUGFS +struct iwl_debugfs { + const char *name; + struct dentry *dir_drv; + struct dentry *dir_data; + struct dentry *dir_debug; + struct dentry *dir_rf; + struct dir_data_files { + struct dentry *file_sram; + struct dentry *file_nvm; + struct dentry *file_stations; + struct dentry *file_log_event; + struct dentry *file_channels; + struct dentry *file_status; + struct dentry *file_interrupt; + struct dentry *file_qos; + struct dentry *file_thermal_throttling; + struct dentry *file_led; + struct dentry *file_disable_ht40; + struct dentry *file_sleep_level_override; + struct dentry *file_current_sleep_command; + } dbgfs_data_files; + struct dir_rf_files { + struct dentry *file_disable_sensitivity; + struct dentry *file_disable_chain_noise; + struct dentry *file_disable_tx_power; + } dbgfs_rf_files; + struct dir_debug_files { + struct dentry *file_rx_statistics; + struct dentry *file_tx_statistics; + struct dentry *file_traffic_log; + struct dentry *file_rx_queue; + struct dentry *file_tx_queue; + struct dentry *file_ucode_rx_stats; + struct dentry *file_ucode_tx_stats; + struct dentry *file_ucode_general_stats; + struct dentry *file_sensitivity; + struct dentry *file_chain_noise; + struct dentry *file_tx_power; + struct dentry *file_power_save_status; + struct dentry *file_clear_ucode_statistics; + struct dentry *file_clear_traffic_statistics; + } dbgfs_debug_files; + u32 sram_offset; + u32 sram_len; +}; + +int iwl_dbgfs_register(struct iwl_priv *priv, const char *name); +void iwl_dbgfs_unregister(struct iwl_priv *priv); +#endif + #else #define IWL_DEBUG(__priv, level, fmt, args...) #define IWL_DEBUG_LIMIT(__priv, level, fmt, args...) @@ -75,10 +126,9 @@ static inline void iwl_print_hex_dump(struct iwl_priv *priv, int level, {} #endif /* CONFIG_IWLWIFI_DEBUG */ -#ifdef CONFIG_IWLWIFI_DEBUGFS -int iwl_dbgfs_register(struct iwl_priv *priv, const char *name); -void iwl_dbgfs_unregister(struct iwl_priv *priv); -#else + + +#ifndef CONFIG_IWLWIFI_DEBUGFS static inline int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) { return 0; diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/trunk/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 7bf44f146799..21e0f6699daf 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2009 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -41,28 +41,43 @@ #include "iwl-calib.h" /* create and remove of files */ -#define DEBUGFS_ADD_FILE(name, parent, mode) do { \ - if (!debugfs_create_file(#name, mode, parent, priv, \ - &iwl_dbgfs_##name##_ops)) \ - goto err; \ +#define DEBUGFS_ADD_DIR(name, parent) do { \ + dbgfs->dir_##name = debugfs_create_dir(#name, parent); \ + if (!(dbgfs->dir_##name)) \ + goto err; \ } while (0) -#define DEBUGFS_ADD_BOOL(name, parent, ptr) do { \ - struct dentry *__tmp; \ - __tmp = debugfs_create_bool(#name, S_IWUSR | S_IRUSR, \ - parent, ptr); \ - if (IS_ERR(__tmp) || !__tmp) \ - goto err; \ +#define DEBUGFS_ADD_FILE(name, parent, mode) do { \ + dbgfs->dbgfs_##parent##_files.file_##name = \ + debugfs_create_file(#name, mode, \ + dbgfs->dir_##parent, priv, \ + &iwl_dbgfs_##name##_ops); \ + if (!(dbgfs->dbgfs_##parent##_files.file_##name)) \ + goto err; \ } while (0) -#define DEBUGFS_ADD_X32(name, parent, ptr) do { \ - struct dentry *__tmp; \ - __tmp = debugfs_create_x32(#name, S_IWUSR | S_IRUSR, \ - parent, ptr); \ - if (IS_ERR(__tmp) || !__tmp) \ - goto err; \ +#define DEBUGFS_ADD_BOOL(name, parent, ptr) do { \ + dbgfs->dbgfs_##parent##_files.file_##name = \ + debugfs_create_bool(#name, S_IWUSR | S_IRUSR, \ + dbgfs->dir_##parent, ptr); \ + if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name) \ + || !dbgfs->dbgfs_##parent##_files.file_##name) \ + goto err; \ } while (0) +#define DEBUGFS_ADD_X32(name, parent, ptr) do { \ + dbgfs->dbgfs_##parent##_files.file_##name = \ + debugfs_create_x32(#name, S_IRUSR, dbgfs->dir_##parent, ptr); \ + if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name) \ + || !dbgfs->dbgfs_##parent##_files.file_##name) \ + goto err; \ +} while (0) + +#define DEBUGFS_REMOVE(name) do { \ + debugfs_remove(name); \ + name = NULL; \ +} while (0); + /* file operation */ #define DEBUGFS_READ_FUNC(name) \ static ssize_t iwl_dbgfs_##name##_read(struct file *file, \ @@ -110,7 +125,7 @@ static ssize_t iwl_dbgfs_tx_statistics_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct iwl_priv *priv = file->private_data; + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; char *buf; int pos = 0; @@ -169,7 +184,7 @@ static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct iwl_priv *priv = file->private_data; + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; char *buf; int pos = 0; int cnt; @@ -217,28 +232,28 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, ssize_t ret; int i; int pos = 0; - struct iwl_priv *priv = file->private_data; + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; size_t bufsz; /* default is to dump the entire data segment */ - if (!priv->dbgfs_sram_offset && !priv->dbgfs_sram_len) { - priv->dbgfs_sram_offset = 0x800000; + if (!priv->dbgfs->sram_offset && !priv->dbgfs->sram_len) { + priv->dbgfs->sram_offset = 0x800000; if (priv->ucode_type == UCODE_INIT) - priv->dbgfs_sram_len = priv->ucode_init_data.len; + priv->dbgfs->sram_len = priv->ucode_init_data.len; else - priv->dbgfs_sram_len = priv->ucode_data.len; + priv->dbgfs->sram_len = priv->ucode_data.len; } - bufsz = 30 + priv->dbgfs_sram_len * sizeof(char) * 10; + bufsz = 30 + priv->dbgfs->sram_len * sizeof(char) * 10; buf = kmalloc(bufsz, GFP_KERNEL); if (!buf) return -ENOMEM; pos += scnprintf(buf + pos, bufsz - pos, "sram_len: 0x%x\n", - priv->dbgfs_sram_len); + priv->dbgfs->sram_len); pos += scnprintf(buf + pos, bufsz - pos, "sram_offset: 0x%x\n", - priv->dbgfs_sram_offset); - for (i = priv->dbgfs_sram_len; i > 0; i -= 4) { - val = iwl_read_targ_mem(priv, priv->dbgfs_sram_offset + \ - priv->dbgfs_sram_len - i); + priv->dbgfs->sram_offset); + for (i = priv->dbgfs->sram_len; i > 0; i -= 4) { + val = iwl_read_targ_mem(priv, priv->dbgfs->sram_offset + \ + priv->dbgfs->sram_len - i); if (i < 4) { switch (i) { case 1: @@ -278,11 +293,11 @@ static ssize_t iwl_dbgfs_sram_write(struct file *file, return -EFAULT; if (sscanf(buf, "%x,%x", &offset, &len) == 2) { - priv->dbgfs_sram_offset = offset; - priv->dbgfs_sram_len = len; + priv->dbgfs->sram_offset = offset; + priv->dbgfs->sram_len = len; } else { - priv->dbgfs_sram_offset = 0; - priv->dbgfs_sram_len = 0; + priv->dbgfs->sram_offset = 0; + priv->dbgfs->sram_len = 0; } return count; @@ -291,7 +306,7 @@ static ssize_t iwl_dbgfs_sram_write(struct file *file, static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct iwl_priv *priv = file->private_data; + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; struct iwl_station_entry *station; int max_sta = priv->hw_params.max_stations; char *buf; @@ -361,7 +376,7 @@ static ssize_t iwl_dbgfs_nvm_read(struct file *file, loff_t *ppos) { ssize_t ret; - struct iwl_priv *priv = file->private_data; + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; int pos = 0, ofs = 0, buf_size = 0; const u8 *ptr; char *buf; @@ -405,24 +420,6 @@ static ssize_t iwl_dbgfs_nvm_read(struct file *file, return ret; } -static ssize_t iwl_dbgfs_log_event_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_priv *priv = file->private_data; - char *buf; - int pos = 0; - ssize_t ret = -ENOMEM; - - ret = pos = priv->cfg->ops->lib->dump_nic_event_log( - priv, true, &buf, true); - if (buf) { - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - kfree(buf); - } - return ret; -} - static ssize_t iwl_dbgfs_log_event_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) @@ -439,8 +436,7 @@ static ssize_t iwl_dbgfs_log_event_write(struct file *file, if (sscanf(buf, "%d", &event_log_flag) != 1) return -EFAULT; if (event_log_flag == 1) - priv->cfg->ops->lib->dump_nic_event_log(priv, true, - NULL, false); + priv->cfg->ops->lib->dump_nic_event_log(priv, true); return count; } @@ -450,7 +446,7 @@ static ssize_t iwl_dbgfs_log_event_write(struct file *file, static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct iwl_priv *priv = file->private_data; + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; struct ieee80211_channel *channels = NULL; const struct ieee80211_supported_band *supp_band = NULL; int pos = 0, i, bufsz = PAGE_SIZE; @@ -523,13 +519,15 @@ static ssize_t iwl_dbgfs_status_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct iwl_priv *priv = file->private_data; + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; char buf[512]; int pos = 0; const size_t bufsz = sizeof(buf); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_HCMD_ACTIVE:\t %d\n", test_bit(STATUS_HCMD_ACTIVE, &priv->status)); + pos += scnprintf(buf + pos, bufsz - pos, "STATUS_HCMD_SYNC_ACTIVE: %d\n", + test_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_INT_ENABLED:\t %d\n", test_bit(STATUS_INT_ENABLED, &priv->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_RF_KILL_HW:\t %d\n", @@ -569,7 +567,7 @@ static ssize_t iwl_dbgfs_interrupt_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct iwl_priv *priv = file->private_data; + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; int pos = 0; int cnt = 0; char *buf; @@ -656,7 +654,7 @@ static ssize_t iwl_dbgfs_interrupt_write(struct file *file, static ssize_t iwl_dbgfs_qos_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct iwl_priv *priv = file->private_data; + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; int pos = 0, i; char buf[256]; const size_t bufsz = sizeof(buf); @@ -679,7 +677,7 @@ static ssize_t iwl_dbgfs_qos_read(struct file *file, char __user *user_buf, static ssize_t iwl_dbgfs_led_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct iwl_priv *priv = file->private_data; + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; int pos = 0; char buf[256]; const size_t bufsz = sizeof(buf); @@ -705,7 +703,7 @@ static ssize_t iwl_dbgfs_thermal_throttling_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct iwl_priv *priv = file->private_data; + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; struct iwl_tt_mgmt *tt = &priv->thermal_throttle; struct iwl_tt_restriction *restriction; char buf[100]; @@ -765,7 +763,7 @@ static ssize_t iwl_dbgfs_disable_ht40_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct iwl_priv *priv = file->private_data; + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; char buf[100]; int pos = 0; const size_t bufsz = sizeof(buf); @@ -813,9 +811,7 @@ static ssize_t iwl_dbgfs_sleep_level_override_write(struct file *file, priv->power_data.debug_sleep_level_override = value; - mutex_lock(&priv->mutex); iwl_power_update_mode(priv, true); - mutex_unlock(&priv->mutex); return count; } @@ -824,7 +820,7 @@ static ssize_t iwl_dbgfs_sleep_level_override_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct iwl_priv *priv = file->private_data; + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; char buf[10]; int pos, value; const size_t bufsz = sizeof(buf); @@ -842,7 +838,7 @@ static ssize_t iwl_dbgfs_current_sleep_command_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct iwl_priv *priv = file->private_data; + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; char buf[200]; int pos = 0, i; const size_t bufsz = sizeof(buf); @@ -863,7 +859,7 @@ static ssize_t iwl_dbgfs_current_sleep_command_read(struct file *file, } DEBUGFS_READ_WRITE_FILE_OPS(sram); -DEBUGFS_READ_WRITE_FILE_OPS(log_event); +DEBUGFS_WRITE_FILE_OPS(log_event); DEBUGFS_READ_FILE_OPS(nvm); DEBUGFS_READ_FILE_OPS(stations); DEBUGFS_READ_FILE_OPS(channels); @@ -980,7 +976,7 @@ static ssize_t iwl_dbgfs_tx_queue_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct iwl_priv *priv = file->private_data; + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; struct iwl_tx_queue *txq; struct iwl_queue *q; char *buf; @@ -1026,7 +1022,7 @@ static ssize_t iwl_dbgfs_rx_queue_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct iwl_priv *priv = file->private_data; + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; struct iwl_rx_queue *rxq = &priv->rxq; char buf[256]; int pos = 0; @@ -1067,33 +1063,36 @@ static int iwl_dbgfs_statistics_flag(struct iwl_priv *priv, char *buf, return p; } -static const char ucode_stats_header[] = - "%-32s current acumulative delta max\n"; -static const char ucode_stats_short_format[] = - " %-30s %10u\n"; -static const char ucode_stats_format[] = - " %-30s %10u %10u %10u %10u\n"; static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct iwl_priv *priv = file->private_data; + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; int pos = 0; char *buf; - int bufsz = sizeof(struct statistics_rx_phy) * 40 + - sizeof(struct statistics_rx_non_phy) * 40 + - sizeof(struct statistics_rx_ht_phy) * 40 + 400; + int bufsz = sizeof(struct statistics_rx_phy) * 20 + + sizeof(struct statistics_rx_non_phy) * 20 + + sizeof(struct statistics_rx_ht_phy) * 20 + 400; ssize_t ret; - struct statistics_rx_phy *ofdm, *accum_ofdm, *delta_ofdm, *max_ofdm; - struct statistics_rx_phy *cck, *accum_cck, *delta_cck, *max_cck; + struct statistics_rx_phy *ofdm, *accum_ofdm; + struct statistics_rx_phy *cck, *accum_cck; struct statistics_rx_non_phy *general, *accum_general; - struct statistics_rx_non_phy *delta_general, *max_general; - struct statistics_rx_ht_phy *ht, *accum_ht, *delta_ht, *max_ht; + struct statistics_rx_ht_phy *ht, *accum_ht; if (!iwl_is_alive(priv)) return -EAGAIN; + /* make request to uCode to retrieve statistics information */ + mutex_lock(&priv->mutex); + ret = iwl_send_statistics_request(priv, CMD_SYNC, false); + mutex_unlock(&priv->mutex); + + if (ret) { + IWL_ERR(priv, + "Error sending statistics request: %zd\n", ret); + return -EAGAIN; + } buf = kzalloc(bufsz, GFP_KERNEL); if (!buf) { IWL_ERR(priv, "Can not allocate Buffer\n"); @@ -1112,401 +1111,264 @@ static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file, accum_cck = &priv->accum_statistics.rx.cck; accum_general = &priv->accum_statistics.rx.general; accum_ht = &priv->accum_statistics.rx.ofdm_ht; - delta_ofdm = &priv->delta_statistics.rx.ofdm; - delta_cck = &priv->delta_statistics.rx.cck; - delta_general = &priv->delta_statistics.rx.general; - delta_ht = &priv->delta_statistics.rx.ofdm_ht; - max_ofdm = &priv->max_delta.rx.ofdm; - max_cck = &priv->max_delta.rx.cck; - max_general = &priv->max_delta.rx.general; - max_ht = &priv->max_delta.rx.ofdm_ht; - pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_header, - "Statistics_Rx - OFDM:"); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "ina_cnt:", le32_to_cpu(ofdm->ina_cnt), - accum_ofdm->ina_cnt, - delta_ofdm->ina_cnt, max_ofdm->ina_cnt); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "fina_cnt:", - le32_to_cpu(ofdm->fina_cnt), accum_ofdm->fina_cnt, - delta_ofdm->fina_cnt, max_ofdm->fina_cnt); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "plcp_err:", - le32_to_cpu(ofdm->plcp_err), accum_ofdm->plcp_err, - delta_ofdm->plcp_err, max_ofdm->plcp_err); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "crc32_err:", - le32_to_cpu(ofdm->crc32_err), accum_ofdm->crc32_err, - delta_ofdm->crc32_err, max_ofdm->crc32_err); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "overrun_err:", + pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - OFDM:\n"); + pos += scnprintf(buf + pos, bufsz - pos, + "\t\t\tcurrent\t\t\taccumulative\n"); + pos += scnprintf(buf + pos, bufsz - pos, "ina_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(ofdm->ina_cnt), accum_ofdm->ina_cnt); + pos += scnprintf(buf + pos, bufsz - pos, "fina_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(ofdm->fina_cnt), accum_ofdm->fina_cnt); + pos += scnprintf(buf + pos, bufsz - pos, "plcp_err:\t\t%u\t\t\t%u\n", + le32_to_cpu(ofdm->plcp_err), accum_ofdm->plcp_err); + pos += scnprintf(buf + pos, bufsz - pos, "crc32_err:\t\t%u\t\t\t%u\n", + le32_to_cpu(ofdm->crc32_err), accum_ofdm->crc32_err); + pos += scnprintf(buf + pos, bufsz - pos, + "overrun_err:\t\t%u\t\t\t%u\n", le32_to_cpu(ofdm->overrun_err), - accum_ofdm->overrun_err, - delta_ofdm->overrun_err, max_ofdm->overrun_err); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "early_overrun_err:", + accum_ofdm->overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, + "early_overrun_err:\t%u\t\t\t%u\n", le32_to_cpu(ofdm->early_overrun_err), - accum_ofdm->early_overrun_err, - delta_ofdm->early_overrun_err, - max_ofdm->early_overrun_err); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "crc32_good:", + accum_ofdm->early_overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, "crc32_good:\t\t%u\t\t\t%u\n", le32_to_cpu(ofdm->crc32_good), - accum_ofdm->crc32_good, - delta_ofdm->crc32_good, max_ofdm->crc32_good); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "false_alarm_cnt:", + accum_ofdm->crc32_good); + pos += scnprintf(buf + pos, bufsz - pos, + "false_alarm_cnt:\t%u\t\t\t%u\n", le32_to_cpu(ofdm->false_alarm_cnt), - accum_ofdm->false_alarm_cnt, - delta_ofdm->false_alarm_cnt, - max_ofdm->false_alarm_cnt); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "fina_sync_err_cnt:", + accum_ofdm->false_alarm_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "fina_sync_err_cnt:\t%u\t\t\t%u\n", le32_to_cpu(ofdm->fina_sync_err_cnt), - accum_ofdm->fina_sync_err_cnt, - delta_ofdm->fina_sync_err_cnt, - max_ofdm->fina_sync_err_cnt); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "sfd_timeout:", + accum_ofdm->fina_sync_err_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "sfd_timeout:\t\t%u\t\t\t%u\n", le32_to_cpu(ofdm->sfd_timeout), - accum_ofdm->sfd_timeout, - delta_ofdm->sfd_timeout, - max_ofdm->sfd_timeout); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "fina_timeout:", + accum_ofdm->sfd_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + "fina_timeout:\t\t%u\t\t\t%u\n", le32_to_cpu(ofdm->fina_timeout), - accum_ofdm->fina_timeout, - delta_ofdm->fina_timeout, - max_ofdm->fina_timeout); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "unresponded_rts:", + accum_ofdm->fina_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + "unresponded_rts:\t%u\t\t\t%u\n", le32_to_cpu(ofdm->unresponded_rts), - accum_ofdm->unresponded_rts, - delta_ofdm->unresponded_rts, - max_ofdm->unresponded_rts); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "rxe_frame_lmt_ovrun:", + accum_ofdm->unresponded_rts); + pos += scnprintf(buf + pos, bufsz - pos, + "rxe_frame_lmt_ovrun:\t%u\t\t\t%u\n", le32_to_cpu(ofdm->rxe_frame_limit_overrun), - accum_ofdm->rxe_frame_limit_overrun, - delta_ofdm->rxe_frame_limit_overrun, - max_ofdm->rxe_frame_limit_overrun); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "sent_ack_cnt:", + accum_ofdm->rxe_frame_limit_overrun); + pos += scnprintf(buf + pos, bufsz - pos, + "sent_ack_cnt:\t\t%u\t\t\t%u\n", le32_to_cpu(ofdm->sent_ack_cnt), - accum_ofdm->sent_ack_cnt, - delta_ofdm->sent_ack_cnt, - max_ofdm->sent_ack_cnt); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "sent_cts_cnt:", + accum_ofdm->sent_ack_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "sent_cts_cnt:\t\t%u\t\t\t%u\n", le32_to_cpu(ofdm->sent_cts_cnt), - accum_ofdm->sent_cts_cnt, - delta_ofdm->sent_cts_cnt, max_ofdm->sent_cts_cnt); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "sent_ba_rsp_cnt:", + accum_ofdm->sent_cts_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "sent_ba_rsp_cnt:\t%u\t\t\t%u\n", le32_to_cpu(ofdm->sent_ba_rsp_cnt), - accum_ofdm->sent_ba_rsp_cnt, - delta_ofdm->sent_ba_rsp_cnt, - max_ofdm->sent_ba_rsp_cnt); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "dsp_self_kill:", + accum_ofdm->sent_ba_rsp_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "dsp_self_kill:\t\t%u\t\t\t%u\n", le32_to_cpu(ofdm->dsp_self_kill), - accum_ofdm->dsp_self_kill, - delta_ofdm->dsp_self_kill, - max_ofdm->dsp_self_kill); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "mh_format_err:", + accum_ofdm->dsp_self_kill); + pos += scnprintf(buf + pos, bufsz - pos, + "mh_format_err:\t\t%u\t\t\t%u\n", le32_to_cpu(ofdm->mh_format_err), - accum_ofdm->mh_format_err, - delta_ofdm->mh_format_err, - max_ofdm->mh_format_err); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "re_acq_main_rssi_sum:", + accum_ofdm->mh_format_err); + pos += scnprintf(buf + pos, bufsz - pos, + "re_acq_main_rssi_sum:\t%u\t\t\t%u\n", le32_to_cpu(ofdm->re_acq_main_rssi_sum), - accum_ofdm->re_acq_main_rssi_sum, - delta_ofdm->re_acq_main_rssi_sum, - max_ofdm->re_acq_main_rssi_sum); - - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_header, - "Statistics_Rx - CCK:"); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "ina_cnt:", - le32_to_cpu(cck->ina_cnt), accum_cck->ina_cnt, - delta_cck->ina_cnt, max_cck->ina_cnt); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "fina_cnt:", - le32_to_cpu(cck->fina_cnt), accum_cck->fina_cnt, - delta_cck->fina_cnt, max_cck->fina_cnt); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "plcp_err:", - le32_to_cpu(cck->plcp_err), accum_cck->plcp_err, - delta_cck->plcp_err, max_cck->plcp_err); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "crc32_err:", - le32_to_cpu(cck->crc32_err), accum_cck->crc32_err, - delta_cck->crc32_err, max_cck->crc32_err); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "overrun_err:", + accum_ofdm->re_acq_main_rssi_sum); + + pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - CCK:\n"); + pos += scnprintf(buf + pos, bufsz - pos, + "\t\t\tcurrent\t\t\taccumulative\n"); + pos += scnprintf(buf + pos, bufsz - pos, "ina_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(cck->ina_cnt), accum_cck->ina_cnt); + pos += scnprintf(buf + pos, bufsz - pos, "fina_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(cck->fina_cnt), accum_cck->fina_cnt); + pos += scnprintf(buf + pos, bufsz - pos, "plcp_err:\t\t%u\t\t\t%u\n", + le32_to_cpu(cck->plcp_err), accum_cck->plcp_err); + pos += scnprintf(buf + pos, bufsz - pos, "crc32_err:\t\t%u\t\t\t%u\n", + le32_to_cpu(cck->crc32_err), accum_cck->crc32_err); + pos += scnprintf(buf + pos, bufsz - pos, + "overrun_err:\t\t%u\t\t\t%u\n", le32_to_cpu(cck->overrun_err), - accum_cck->overrun_err, - delta_cck->overrun_err, max_cck->overrun_err); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "early_overrun_err:", + accum_cck->overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, + "early_overrun_err:\t%u\t\t\t%u\n", le32_to_cpu(cck->early_overrun_err), - accum_cck->early_overrun_err, - delta_cck->early_overrun_err, - max_cck->early_overrun_err); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "crc32_good:", - le32_to_cpu(cck->crc32_good), accum_cck->crc32_good, - delta_cck->crc32_good, - max_cck->crc32_good); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "false_alarm_cnt:", + accum_cck->early_overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, "crc32_good:\t\t%u\t\t\t%u\n", + le32_to_cpu(cck->crc32_good), accum_cck->crc32_good); + pos += scnprintf(buf + pos, bufsz - pos, + "false_alarm_cnt:\t%u\t\t\t%u\n", le32_to_cpu(cck->false_alarm_cnt), - accum_cck->false_alarm_cnt, - delta_cck->false_alarm_cnt, max_cck->false_alarm_cnt); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "fina_sync_err_cnt:", + accum_cck->false_alarm_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "fina_sync_err_cnt:\t%u\t\t\t%u\n", le32_to_cpu(cck->fina_sync_err_cnt), - accum_cck->fina_sync_err_cnt, - delta_cck->fina_sync_err_cnt, - max_cck->fina_sync_err_cnt); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "sfd_timeout:", + accum_cck->fina_sync_err_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "sfd_timeout:\t\t%u\t\t\t%u\n", le32_to_cpu(cck->sfd_timeout), - accum_cck->sfd_timeout, - delta_cck->sfd_timeout, max_cck->sfd_timeout); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "fina_timeout:", + accum_cck->sfd_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + "fina_timeout:\t\t%u\t\t\t%u\n", le32_to_cpu(cck->fina_timeout), - accum_cck->fina_timeout, - delta_cck->fina_timeout, max_cck->fina_timeout); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "unresponded_rts:", + accum_cck->fina_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + "unresponded_rts:\t%u\t\t\t%u\n", le32_to_cpu(cck->unresponded_rts), - accum_cck->unresponded_rts, - delta_cck->unresponded_rts, - max_cck->unresponded_rts); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "rxe_frame_lmt_ovrun:", + accum_cck->unresponded_rts); + pos += scnprintf(buf + pos, bufsz - pos, + "rxe_frame_lmt_ovrun:\t%u\t\t\t%u\n", le32_to_cpu(cck->rxe_frame_limit_overrun), - accum_cck->rxe_frame_limit_overrun, - delta_cck->rxe_frame_limit_overrun, - max_cck->rxe_frame_limit_overrun); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "sent_ack_cnt:", + accum_cck->rxe_frame_limit_overrun); + pos += scnprintf(buf + pos, bufsz - pos, + "sent_ack_cnt:\t\t%u\t\t\t%u\n", le32_to_cpu(cck->sent_ack_cnt), - accum_cck->sent_ack_cnt, - delta_cck->sent_ack_cnt, - max_cck->sent_ack_cnt); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "sent_cts_cnt:", + accum_cck->sent_ack_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "sent_cts_cnt:\t\t%u\t\t\t%u\n", le32_to_cpu(cck->sent_cts_cnt), - accum_cck->sent_cts_cnt, - delta_cck->sent_cts_cnt, - max_cck->sent_cts_cnt); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "sent_ba_rsp_cnt:", + accum_cck->sent_cts_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "sent_ba_rsp_cnt:\t%u\t\t\t%u\n", le32_to_cpu(cck->sent_ba_rsp_cnt), - accum_cck->sent_ba_rsp_cnt, - delta_cck->sent_ba_rsp_cnt, - max_cck->sent_ba_rsp_cnt); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "dsp_self_kill:", + accum_cck->sent_ba_rsp_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "dsp_self_kill:\t\t%u\t\t\t%u\n", le32_to_cpu(cck->dsp_self_kill), - accum_cck->dsp_self_kill, - delta_cck->dsp_self_kill, - max_cck->dsp_self_kill); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "mh_format_err:", + accum_cck->dsp_self_kill); + pos += scnprintf(buf + pos, bufsz - pos, + "mh_format_err:\t\t%u\t\t\t%u\n", le32_to_cpu(cck->mh_format_err), - accum_cck->mh_format_err, - delta_cck->mh_format_err, max_cck->mh_format_err); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "re_acq_main_rssi_sum:", + accum_cck->mh_format_err); + pos += scnprintf(buf + pos, bufsz - pos, + "re_acq_main_rssi_sum:\t%u\t\t\t%u\n", le32_to_cpu(cck->re_acq_main_rssi_sum), - accum_cck->re_acq_main_rssi_sum, - delta_cck->re_acq_main_rssi_sum, - max_cck->re_acq_main_rssi_sum); - - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_header, - "Statistics_Rx - GENERAL:"); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "bogus_cts:", + accum_cck->re_acq_main_rssi_sum); + + pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - GENERAL:\n"); + pos += scnprintf(buf + pos, bufsz - pos, + "\t\t\tcurrent\t\t\taccumulative\n"); + pos += scnprintf(buf + pos, bufsz - pos, "bogus_cts:\t\t%u\t\t\t%u\n", le32_to_cpu(general->bogus_cts), - accum_general->bogus_cts, - delta_general->bogus_cts, max_general->bogus_cts); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "bogus_ack:", + accum_general->bogus_cts); + pos += scnprintf(buf + pos, bufsz - pos, "bogus_ack:\t\t%u\t\t\t%u\n", le32_to_cpu(general->bogus_ack), - accum_general->bogus_ack, - delta_general->bogus_ack, max_general->bogus_ack); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "non_bssid_frames:", + accum_general->bogus_ack); + pos += scnprintf(buf + pos, bufsz - pos, + "non_bssid_frames:\t%u\t\t\t%u\n", le32_to_cpu(general->non_bssid_frames), - accum_general->non_bssid_frames, - delta_general->non_bssid_frames, - max_general->non_bssid_frames); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "filtered_frames:", + accum_general->non_bssid_frames); + pos += scnprintf(buf + pos, bufsz - pos, + "filtered_frames:\t%u\t\t\t%u\n", le32_to_cpu(general->filtered_frames), - accum_general->filtered_frames, - delta_general->filtered_frames, - max_general->filtered_frames); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "non_channel_beacons:", + accum_general->filtered_frames); + pos += scnprintf(buf + pos, bufsz - pos, + "non_channel_beacons:\t%u\t\t\t%u\n", le32_to_cpu(general->non_channel_beacons), - accum_general->non_channel_beacons, - delta_general->non_channel_beacons, - max_general->non_channel_beacons); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "channel_beacons:", + accum_general->non_channel_beacons); + pos += scnprintf(buf + pos, bufsz - pos, + "channel_beacons:\t%u\t\t\t%u\n", le32_to_cpu(general->channel_beacons), - accum_general->channel_beacons, - delta_general->channel_beacons, - max_general->channel_beacons); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "num_missed_bcon:", + accum_general->channel_beacons); + pos += scnprintf(buf + pos, bufsz - pos, + "num_missed_bcon:\t%u\t\t\t%u\n", le32_to_cpu(general->num_missed_bcon), - accum_general->num_missed_bcon, - delta_general->num_missed_bcon, - max_general->num_missed_bcon); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "adc_rx_saturation_time:", + accum_general->num_missed_bcon); + pos += scnprintf(buf + pos, bufsz - pos, + "adc_rx_saturation_time:\t%u\t\t\t%u\n", le32_to_cpu(general->adc_rx_saturation_time), - accum_general->adc_rx_saturation_time, - delta_general->adc_rx_saturation_time, - max_general->adc_rx_saturation_time); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "ina_detect_search_tm:", + accum_general->adc_rx_saturation_time); + pos += scnprintf(buf + pos, bufsz - pos, + "ina_detect_search_tm:\t%u\t\t\t%u\n", le32_to_cpu(general->ina_detection_search_time), - accum_general->ina_detection_search_time, - delta_general->ina_detection_search_time, - max_general->ina_detection_search_time); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "beacon_silence_rssi_a:", + accum_general->ina_detection_search_time); + pos += scnprintf(buf + pos, bufsz - pos, + "beacon_silence_rssi_a:\t%u\t\t\t%u\n", le32_to_cpu(general->beacon_silence_rssi_a), - accum_general->beacon_silence_rssi_a, - delta_general->beacon_silence_rssi_a, - max_general->beacon_silence_rssi_a); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "beacon_silence_rssi_b:", + accum_general->beacon_silence_rssi_a); + pos += scnprintf(buf + pos, bufsz - pos, + "beacon_silence_rssi_b:\t%u\t\t\t%u\n", le32_to_cpu(general->beacon_silence_rssi_b), - accum_general->beacon_silence_rssi_b, - delta_general->beacon_silence_rssi_b, - max_general->beacon_silence_rssi_b); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "beacon_silence_rssi_c:", + accum_general->beacon_silence_rssi_b); + pos += scnprintf(buf + pos, bufsz - pos, + "beacon_silence_rssi_c:\t%u\t\t\t%u\n", le32_to_cpu(general->beacon_silence_rssi_c), - accum_general->beacon_silence_rssi_c, - delta_general->beacon_silence_rssi_c, - max_general->beacon_silence_rssi_c); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "interference_data_flag:", + accum_general->beacon_silence_rssi_c); + pos += scnprintf(buf + pos, bufsz - pos, + "interference_data_flag:\t%u\t\t\t%u\n", le32_to_cpu(general->interference_data_flag), - accum_general->interference_data_flag, - delta_general->interference_data_flag, - max_general->interference_data_flag); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "channel_load:", + accum_general->interference_data_flag); + pos += scnprintf(buf + pos, bufsz - pos, + "channel_load:\t\t%u\t\t\t%u\n", le32_to_cpu(general->channel_load), - accum_general->channel_load, - delta_general->channel_load, - max_general->channel_load); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "dsp_false_alarms:", + accum_general->channel_load); + pos += scnprintf(buf + pos, bufsz - pos, + "dsp_false_alarms:\t%u\t\t\t%u\n", le32_to_cpu(general->dsp_false_alarms), - accum_general->dsp_false_alarms, - delta_general->dsp_false_alarms, - max_general->dsp_false_alarms); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "beacon_rssi_a:", + accum_general->dsp_false_alarms); + pos += scnprintf(buf + pos, bufsz - pos, + "beacon_rssi_a:\t\t%u\t\t\t%u\n", le32_to_cpu(general->beacon_rssi_a), - accum_general->beacon_rssi_a, - delta_general->beacon_rssi_a, - max_general->beacon_rssi_a); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "beacon_rssi_b:", + accum_general->beacon_rssi_a); + pos += scnprintf(buf + pos, bufsz - pos, + "beacon_rssi_b:\t\t%u\t\t\t%u\n", le32_to_cpu(general->beacon_rssi_b), - accum_general->beacon_rssi_b, - delta_general->beacon_rssi_b, - max_general->beacon_rssi_b); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "beacon_rssi_c:", + accum_general->beacon_rssi_b); + pos += scnprintf(buf + pos, bufsz - pos, + "beacon_rssi_c:\t\t%u\t\t\t%u\n", le32_to_cpu(general->beacon_rssi_c), - accum_general->beacon_rssi_c, - delta_general->beacon_rssi_c, - max_general->beacon_rssi_c); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "beacon_energy_a:", + accum_general->beacon_rssi_c); + pos += scnprintf(buf + pos, bufsz - pos, + "beacon_energy_a:\t%u\t\t\t%u\n", le32_to_cpu(general->beacon_energy_a), - accum_general->beacon_energy_a, - delta_general->beacon_energy_a, - max_general->beacon_energy_a); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "beacon_energy_b:", + accum_general->beacon_energy_a); + pos += scnprintf(buf + pos, bufsz - pos, + "beacon_energy_b:\t%u\t\t\t%u\n", le32_to_cpu(general->beacon_energy_b), - accum_general->beacon_energy_b, - delta_general->beacon_energy_b, - max_general->beacon_energy_b); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "beacon_energy_c:", + accum_general->beacon_energy_b); + pos += scnprintf(buf + pos, bufsz - pos, + "beacon_energy_c:\t%u\t\t\t%u\n", le32_to_cpu(general->beacon_energy_c), - accum_general->beacon_energy_c, - delta_general->beacon_energy_c, - max_general->beacon_energy_c); + accum_general->beacon_energy_c); pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - OFDM_HT:\n"); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_header, - "Statistics_Rx - OFDM_HT:"); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "plcp_err:", - le32_to_cpu(ht->plcp_err), accum_ht->plcp_err, - delta_ht->plcp_err, max_ht->plcp_err); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "overrun_err:", - le32_to_cpu(ht->overrun_err), accum_ht->overrun_err, - delta_ht->overrun_err, max_ht->overrun_err); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "early_overrun_err:", + pos += scnprintf(buf + pos, bufsz - pos, + "\t\t\tcurrent\t\t\taccumulative\n"); + pos += scnprintf(buf + pos, bufsz - pos, "plcp_err:\t\t%u\t\t\t%u\n", + le32_to_cpu(ht->plcp_err), accum_ht->plcp_err); + pos += scnprintf(buf + pos, bufsz - pos, + "overrun_err:\t\t%u\t\t\t%u\n", + le32_to_cpu(ht->overrun_err), accum_ht->overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, + "early_overrun_err:\t%u\t\t\t%u\n", le32_to_cpu(ht->early_overrun_err), - accum_ht->early_overrun_err, - delta_ht->early_overrun_err, - max_ht->early_overrun_err); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "crc32_good:", - le32_to_cpu(ht->crc32_good), accum_ht->crc32_good, - delta_ht->crc32_good, max_ht->crc32_good); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "crc32_err:", - le32_to_cpu(ht->crc32_err), accum_ht->crc32_err, - delta_ht->crc32_err, max_ht->crc32_err); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "mh_format_err:", + accum_ht->early_overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, "crc32_good:\t\t%u\t\t\t%u\n", + le32_to_cpu(ht->crc32_good), accum_ht->crc32_good); + pos += scnprintf(buf + pos, bufsz - pos, "crc32_err:\t\t%u\t\t\t%u\n", + le32_to_cpu(ht->crc32_err), accum_ht->crc32_err); + pos += scnprintf(buf + pos, bufsz - pos, + "mh_format_err:\t\t%u\t\t\t%u\n", le32_to_cpu(ht->mh_format_err), - accum_ht->mh_format_err, - delta_ht->mh_format_err, max_ht->mh_format_err); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "agg_crc32_good:", + accum_ht->mh_format_err); + pos += scnprintf(buf + pos, bufsz - pos, + "agg_crc32_good:\t\t%u\t\t\t%u\n", le32_to_cpu(ht->agg_crc32_good), - accum_ht->agg_crc32_good, - delta_ht->agg_crc32_good, max_ht->agg_crc32_good); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "agg_mpdu_cnt:", + accum_ht->agg_crc32_good); + pos += scnprintf(buf + pos, bufsz - pos, + "agg_mpdu_cnt:\t\t%u\t\t\t%u\n", le32_to_cpu(ht->agg_mpdu_cnt), - accum_ht->agg_mpdu_cnt, - delta_ht->agg_mpdu_cnt, max_ht->agg_mpdu_cnt); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "agg_cnt:", - le32_to_cpu(ht->agg_cnt), accum_ht->agg_cnt, - delta_ht->agg_cnt, max_ht->agg_cnt); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "unsupport_mcs:", - le32_to_cpu(ht->unsupport_mcs), - accum_ht->unsupport_mcs, - delta_ht->unsupport_mcs, max_ht->unsupport_mcs); + accum_ht->agg_mpdu_cnt); + pos += scnprintf(buf + pos, bufsz - pos, "agg_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(ht->agg_cnt), accum_ht->agg_cnt); ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); kfree(buf); @@ -1517,16 +1379,26 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct iwl_priv *priv = file->private_data; + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; int pos = 0; char *buf; - int bufsz = (sizeof(struct statistics_tx) * 48) + 250; + int bufsz = (sizeof(struct statistics_tx) * 24) + 250; ssize_t ret; - struct statistics_tx *tx, *accum_tx, *delta_tx, *max_tx; + struct statistics_tx *tx, *accum_tx; if (!iwl_is_alive(priv)) return -EAGAIN; + /* make request to uCode to retrieve statistics information */ + mutex_lock(&priv->mutex); + ret = iwl_send_statistics_request(priv, CMD_SYNC, false); + mutex_unlock(&priv->mutex); + + if (ret) { + IWL_ERR(priv, + "Error sending statistics request: %zd\n", ret); + return -EAGAIN; + } buf = kzalloc(bufsz, GFP_KERNEL); if (!buf) { IWL_ERR(priv, "Can not allocate Buffer\n"); @@ -1539,148 +1411,106 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file, */ tx = &priv->statistics.tx; accum_tx = &priv->accum_statistics.tx; - delta_tx = &priv->delta_statistics.tx; - max_tx = &priv->max_delta.tx; pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_header, - "Statistics_Tx:"); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "preamble:", + pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Tx:\n"); + pos += scnprintf(buf + pos, bufsz - pos, + "\t\t\tcurrent\t\t\taccumulative\n"); + pos += scnprintf(buf + pos, bufsz - pos, "preamble:\t\t\t%u\t\t\t%u\n", le32_to_cpu(tx->preamble_cnt), - accum_tx->preamble_cnt, - delta_tx->preamble_cnt, max_tx->preamble_cnt); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "rx_detected_cnt:", + accum_tx->preamble_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "rx_detected_cnt:\t\t%u\t\t\t%u\n", le32_to_cpu(tx->rx_detected_cnt), - accum_tx->rx_detected_cnt, - delta_tx->rx_detected_cnt, max_tx->rx_detected_cnt); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "bt_prio_defer_cnt:", + accum_tx->rx_detected_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "bt_prio_defer_cnt:\t\t%u\t\t\t%u\n", le32_to_cpu(tx->bt_prio_defer_cnt), - accum_tx->bt_prio_defer_cnt, - delta_tx->bt_prio_defer_cnt, - max_tx->bt_prio_defer_cnt); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "bt_prio_kill_cnt:", + accum_tx->bt_prio_defer_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "bt_prio_kill_cnt:\t\t%u\t\t\t%u\n", le32_to_cpu(tx->bt_prio_kill_cnt), - accum_tx->bt_prio_kill_cnt, - delta_tx->bt_prio_kill_cnt, - max_tx->bt_prio_kill_cnt); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "few_bytes_cnt:", + accum_tx->bt_prio_kill_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "few_bytes_cnt:\t\t\t%u\t\t\t%u\n", le32_to_cpu(tx->few_bytes_cnt), - accum_tx->few_bytes_cnt, - delta_tx->few_bytes_cnt, max_tx->few_bytes_cnt); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "cts_timeout:", - le32_to_cpu(tx->cts_timeout), accum_tx->cts_timeout, - delta_tx->cts_timeout, max_tx->cts_timeout); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "ack_timeout:", + accum_tx->few_bytes_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "cts_timeout:\t\t\t%u\t\t\t%u\n", + le32_to_cpu(tx->cts_timeout), accum_tx->cts_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + "ack_timeout:\t\t\t%u\t\t\t%u\n", le32_to_cpu(tx->ack_timeout), - accum_tx->ack_timeout, - delta_tx->ack_timeout, max_tx->ack_timeout); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "expected_ack_cnt:", + accum_tx->ack_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + "expected_ack_cnt:\t\t%u\t\t\t%u\n", le32_to_cpu(tx->expected_ack_cnt), - accum_tx->expected_ack_cnt, - delta_tx->expected_ack_cnt, - max_tx->expected_ack_cnt); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "actual_ack_cnt:", + accum_tx->expected_ack_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "actual_ack_cnt:\t\t\t%u\t\t\t%u\n", le32_to_cpu(tx->actual_ack_cnt), - accum_tx->actual_ack_cnt, - delta_tx->actual_ack_cnt, - max_tx->actual_ack_cnt); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "dump_msdu_cnt:", + accum_tx->actual_ack_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "dump_msdu_cnt:\t\t\t%u\t\t\t%u\n", le32_to_cpu(tx->dump_msdu_cnt), - accum_tx->dump_msdu_cnt, - delta_tx->dump_msdu_cnt, - max_tx->dump_msdu_cnt); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "abort_nxt_frame_mismatch:", + accum_tx->dump_msdu_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "abort_nxt_frame_mismatch:" + "\t%u\t\t\t%u\n", le32_to_cpu(tx->burst_abort_next_frame_mismatch_cnt), - accum_tx->burst_abort_next_frame_mismatch_cnt, - delta_tx->burst_abort_next_frame_mismatch_cnt, - max_tx->burst_abort_next_frame_mismatch_cnt); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "abort_missing_nxt_frame:", + accum_tx->burst_abort_next_frame_mismatch_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "abort_missing_nxt_frame:" + "\t%u\t\t\t%u\n", le32_to_cpu(tx->burst_abort_missing_next_frame_cnt), - accum_tx->burst_abort_missing_next_frame_cnt, - delta_tx->burst_abort_missing_next_frame_cnt, - max_tx->burst_abort_missing_next_frame_cnt); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "cts_timeout_collision:", + accum_tx->burst_abort_missing_next_frame_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "cts_timeout_collision:\t\t%u\t\t\t%u\n", le32_to_cpu(tx->cts_timeout_collision), - accum_tx->cts_timeout_collision, - delta_tx->cts_timeout_collision, - max_tx->cts_timeout_collision); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "ack_ba_timeout_collision:", + accum_tx->cts_timeout_collision); + pos += scnprintf(buf + pos, bufsz - pos, + "ack_ba_timeout_collision:\t%u\t\t\t%u\n", le32_to_cpu(tx->ack_or_ba_timeout_collision), - accum_tx->ack_or_ba_timeout_collision, - delta_tx->ack_or_ba_timeout_collision, - max_tx->ack_or_ba_timeout_collision); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "agg ba_timeout:", + accum_tx->ack_or_ba_timeout_collision); + pos += scnprintf(buf + pos, bufsz - pos, + "agg ba_timeout:\t\t\t%u\t\t\t%u\n", le32_to_cpu(tx->agg.ba_timeout), - accum_tx->agg.ba_timeout, - delta_tx->agg.ba_timeout, - max_tx->agg.ba_timeout); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "agg ba_resched_frames:", + accum_tx->agg.ba_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + "agg ba_resched_frames:\t\t%u\t\t\t%u\n", le32_to_cpu(tx->agg.ba_reschedule_frames), - accum_tx->agg.ba_reschedule_frames, - delta_tx->agg.ba_reschedule_frames, - max_tx->agg.ba_reschedule_frames); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "agg scd_query_agg_frame:", + accum_tx->agg.ba_reschedule_frames); + pos += scnprintf(buf + pos, bufsz - pos, + "agg scd_query_agg_frame:\t%u\t\t\t%u\n", le32_to_cpu(tx->agg.scd_query_agg_frame_cnt), - accum_tx->agg.scd_query_agg_frame_cnt, - delta_tx->agg.scd_query_agg_frame_cnt, - max_tx->agg.scd_query_agg_frame_cnt); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "agg scd_query_no_agg:", + accum_tx->agg.scd_query_agg_frame_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "agg scd_query_no_agg:\t\t%u\t\t\t%u\n", le32_to_cpu(tx->agg.scd_query_no_agg), - accum_tx->agg.scd_query_no_agg, - delta_tx->agg.scd_query_no_agg, - max_tx->agg.scd_query_no_agg); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "agg scd_query_agg:", + accum_tx->agg.scd_query_no_agg); + pos += scnprintf(buf + pos, bufsz - pos, + "agg scd_query_agg:\t\t%u\t\t\t%u\n", le32_to_cpu(tx->agg.scd_query_agg), - accum_tx->agg.scd_query_agg, - delta_tx->agg.scd_query_agg, - max_tx->agg.scd_query_agg); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "agg scd_query_mismatch:", + accum_tx->agg.scd_query_agg); + pos += scnprintf(buf + pos, bufsz - pos, + "agg scd_query_mismatch:\t\t%u\t\t\t%u\n", le32_to_cpu(tx->agg.scd_query_mismatch), - accum_tx->agg.scd_query_mismatch, - delta_tx->agg.scd_query_mismatch, - max_tx->agg.scd_query_mismatch); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "agg frame_not_ready:", + accum_tx->agg.scd_query_mismatch); + pos += scnprintf(buf + pos, bufsz - pos, + "agg frame_not_ready:\t\t%u\t\t\t%u\n", le32_to_cpu(tx->agg.frame_not_ready), - accum_tx->agg.frame_not_ready, - delta_tx->agg.frame_not_ready, - max_tx->agg.frame_not_ready); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "agg underrun:", + accum_tx->agg.frame_not_ready); + pos += scnprintf(buf + pos, bufsz - pos, + "agg underrun:\t\t\t%u\t\t\t%u\n", le32_to_cpu(tx->agg.underrun), - accum_tx->agg.underrun, - delta_tx->agg.underrun, max_tx->agg.underrun); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "agg bt_prio_kill:", + accum_tx->agg.underrun); + pos += scnprintf(buf + pos, bufsz - pos, + "agg bt_prio_kill:\t\t%u\t\t\t%u\n", le32_to_cpu(tx->agg.bt_prio_kill), - accum_tx->agg.bt_prio_kill, - delta_tx->agg.bt_prio_kill, - max_tx->agg.bt_prio_kill); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "agg rx_ba_rsp_cnt:", + accum_tx->agg.bt_prio_kill); + pos += scnprintf(buf + pos, bufsz - pos, + "agg rx_ba_rsp_cnt:\t\t%u\t\t\t%u\n", le32_to_cpu(tx->agg.rx_ba_rsp_cnt), - accum_tx->agg.rx_ba_rsp_cnt, - delta_tx->agg.rx_ba_rsp_cnt, - max_tx->agg.rx_ba_rsp_cnt); + accum_tx->agg.rx_ba_rsp_cnt); ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); kfree(buf); @@ -1691,19 +1521,28 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct iwl_priv *priv = file->private_data; + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; int pos = 0; char *buf; - int bufsz = sizeof(struct statistics_general) * 10 + 300; + int bufsz = sizeof(struct statistics_general) * 4 + 250; ssize_t ret; struct statistics_general *general, *accum_general; - struct statistics_general *delta_general, *max_general; - struct statistics_dbg *dbg, *accum_dbg, *delta_dbg, *max_dbg; - struct statistics_div *div, *accum_div, *delta_div, *max_div; + struct statistics_dbg *dbg, *accum_dbg; + struct statistics_div *div, *accum_div; if (!iwl_is_alive(priv)) return -EAGAIN; + /* make request to uCode to retrieve statistics information */ + mutex_lock(&priv->mutex); + ret = iwl_send_statistics_request(priv, CMD_SYNC, false); + mutex_unlock(&priv->mutex); + + if (ret) { + IWL_ERR(priv, + "Error sending statistics request: %zd\n", ret); + return -EAGAIN; + } buf = kzalloc(bufsz, GFP_KERNEL); if (!buf) { IWL_ERR(priv, "Can not allocate Buffer\n"); @@ -1718,78 +1557,52 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file, dbg = &priv->statistics.general.dbg; div = &priv->statistics.general.div; accum_general = &priv->accum_statistics.general; - delta_general = &priv->delta_statistics.general; - max_general = &priv->max_delta.general; accum_dbg = &priv->accum_statistics.general.dbg; - delta_dbg = &priv->delta_statistics.general.dbg; - max_dbg = &priv->max_delta.general.dbg; accum_div = &priv->accum_statistics.general.div; - delta_div = &priv->delta_statistics.general.div; - max_div = &priv->max_delta.general.div; pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_header, - "Statistics_General:"); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_short_format, - "temperature:", + pos += scnprintf(buf + pos, bufsz - pos, "Statistics_General:\n"); + pos += scnprintf(buf + pos, bufsz - pos, + "\t\t\tcurrent\t\t\taccumulative\n"); + pos += scnprintf(buf + pos, bufsz - pos, "temperature:\t\t\t%u\n", le32_to_cpu(general->temperature)); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_short_format, - "temperature_m:", + pos += scnprintf(buf + pos, bufsz - pos, "temperature_m:\t\t\t%u\n", le32_to_cpu(general->temperature_m)); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "burst_check:", + pos += scnprintf(buf + pos, bufsz - pos, + "burst_check:\t\t\t%u\t\t\t%u\n", le32_to_cpu(dbg->burst_check), - accum_dbg->burst_check, - delta_dbg->burst_check, max_dbg->burst_check); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "burst_count:", + accum_dbg->burst_check); + pos += scnprintf(buf + pos, bufsz - pos, + "burst_count:\t\t\t%u\t\t\t%u\n", le32_to_cpu(dbg->burst_count), - accum_dbg->burst_count, - delta_dbg->burst_count, max_dbg->burst_count); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "sleep_time:", + accum_dbg->burst_count); + pos += scnprintf(buf + pos, bufsz - pos, + "sleep_time:\t\t\t%u\t\t\t%u\n", le32_to_cpu(general->sleep_time), - accum_general->sleep_time, - delta_general->sleep_time, max_general->sleep_time); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "slots_out:", + accum_general->sleep_time); + pos += scnprintf(buf + pos, bufsz - pos, + "slots_out:\t\t\t%u\t\t\t%u\n", le32_to_cpu(general->slots_out), - accum_general->slots_out, - delta_general->slots_out, max_general->slots_out); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "slots_idle:", + accum_general->slots_out); + pos += scnprintf(buf + pos, bufsz - pos, + "slots_idle:\t\t\t%u\t\t\t%u\n", le32_to_cpu(general->slots_idle), - accum_general->slots_idle, - delta_general->slots_idle, max_general->slots_idle); + accum_general->slots_idle); pos += scnprintf(buf + pos, bufsz - pos, "ttl_timestamp:\t\t\t%u\n", le32_to_cpu(general->ttl_timestamp)); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "tx_on_a:", - le32_to_cpu(div->tx_on_a), accum_div->tx_on_a, - delta_div->tx_on_a, max_div->tx_on_a); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "tx_on_b:", - le32_to_cpu(div->tx_on_b), accum_div->tx_on_b, - delta_div->tx_on_b, max_div->tx_on_b); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "exec_time:", - le32_to_cpu(div->exec_time), accum_div->exec_time, - delta_div->exec_time, max_div->exec_time); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "probe_time:", - le32_to_cpu(div->probe_time), accum_div->probe_time, - delta_div->probe_time, max_div->probe_time); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "rx_enable_counter:", + pos += scnprintf(buf + pos, bufsz - pos, "tx_on_a:\t\t\t%u\t\t\t%u\n", + le32_to_cpu(div->tx_on_a), accum_div->tx_on_a); + pos += scnprintf(buf + pos, bufsz - pos, "tx_on_b:\t\t\t%u\t\t\t%u\n", + le32_to_cpu(div->tx_on_b), accum_div->tx_on_b); + pos += scnprintf(buf + pos, bufsz - pos, + "exec_time:\t\t\t%u\t\t\t%u\n", + le32_to_cpu(div->exec_time), accum_div->exec_time); + pos += scnprintf(buf + pos, bufsz - pos, + "probe_time:\t\t\t%u\t\t\t%u\n", + le32_to_cpu(div->probe_time), accum_div->probe_time); + pos += scnprintf(buf + pos, bufsz - pos, + "rx_enable_counter:\t\t%u\t\t\t%u\n", le32_to_cpu(general->rx_enable_counter), - accum_general->rx_enable_counter, - delta_general->rx_enable_counter, - max_general->rx_enable_counter); - pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format, - "num_of_sos_states:", - le32_to_cpu(general->num_of_sos_states), - accum_general->num_of_sos_states, - delta_general->num_of_sos_states, - max_general->num_of_sos_states); + accum_general->rx_enable_counter); ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); kfree(buf); return ret; @@ -1799,7 +1612,7 @@ static ssize_t iwl_dbgfs_sensitivity_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct iwl_priv *priv = file->private_data; + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; int pos = 0; int cnt = 0; char *buf; @@ -1880,7 +1693,7 @@ static ssize_t iwl_dbgfs_chain_noise_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct iwl_priv *priv = file->private_data; + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; int pos = 0; int cnt = 0; char *buf; @@ -1938,15 +1751,26 @@ static ssize_t iwl_dbgfs_tx_power_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct iwl_priv *priv = file->private_data; + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; char buf[128]; int pos = 0; + ssize_t ret; const size_t bufsz = sizeof(buf); struct statistics_tx *tx; if (!iwl_is_alive(priv)) pos += scnprintf(buf + pos, bufsz - pos, "N/A\n"); else { + /* make request to uCode to retrieve statistics information */ + mutex_lock(&priv->mutex); + ret = iwl_send_statistics_request(priv, CMD_SYNC, false); + mutex_unlock(&priv->mutex); + + if (ret) { + IWL_ERR(priv, "Error sending statistics request: %zd\n", + ret); + return -EAGAIN; + } tx = &priv->statistics.tx; if (tx->tx_power.ant_a || tx->tx_power.ant_b || @@ -1978,7 +1802,7 @@ static ssize_t iwl_dbgfs_power_save_status_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct iwl_priv *priv = file->private_data; + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; char buf[60]; int pos = 0; const size_t bufsz = sizeof(buf); @@ -2021,262 +1845,6 @@ static ssize_t iwl_dbgfs_clear_ucode_statistics_write(struct file *file, return count; } -static ssize_t iwl_dbgfs_csr_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_priv *priv = file->private_data; - char buf[8]; - int buf_size; - int csr; - - memset(buf, 0, sizeof(buf)); - buf_size = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, buf_size)) - return -EFAULT; - if (sscanf(buf, "%d", &csr) != 1) - return -EFAULT; - - if (priv->cfg->ops->lib->dump_csr) - priv->cfg->ops->lib->dump_csr(priv); - - return count; -} - -static ssize_t iwl_dbgfs_ucode_tracing_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) { - - struct iwl_priv *priv = (struct iwl_priv *)file->private_data; - int pos = 0; - char buf[128]; - const size_t bufsz = sizeof(buf); - ssize_t ret; - - pos += scnprintf(buf + pos, bufsz - pos, "ucode trace timer is %s\n", - priv->event_log.ucode_trace ? "On" : "Off"); - pos += scnprintf(buf + pos, bufsz - pos, "non_wraps_count:\t\t %u\n", - priv->event_log.non_wraps_count); - pos += scnprintf(buf + pos, bufsz - pos, "wraps_once_count:\t\t %u\n", - priv->event_log.wraps_once_count); - pos += scnprintf(buf + pos, bufsz - pos, "wraps_more_count:\t\t %u\n", - priv->event_log.wraps_more_count); - - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - return ret; -} - -static ssize_t iwl_dbgfs_ucode_tracing_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_priv *priv = file->private_data; - char buf[8]; - int buf_size; - int trace; - - memset(buf, 0, sizeof(buf)); - buf_size = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, buf_size)) - return -EFAULT; - if (sscanf(buf, "%d", &trace) != 1) - return -EFAULT; - - if (trace) { - priv->event_log.ucode_trace = true; - /* schedule the ucode timer to occur in UCODE_TRACE_PERIOD */ - mod_timer(&priv->ucode_trace, - jiffies + msecs_to_jiffies(UCODE_TRACE_PERIOD)); - } else { - priv->event_log.ucode_trace = false; - del_timer_sync(&priv->ucode_trace); - } - - return count; -} - -static ssize_t iwl_dbgfs_fh_reg_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_priv *priv = (struct iwl_priv *)file->private_data; - char *buf; - int pos = 0; - ssize_t ret = -EFAULT; - - if (priv->cfg->ops->lib->dump_fh) { - ret = pos = priv->cfg->ops->lib->dump_fh(priv, &buf, true); - if (buf) { - ret = simple_read_from_buffer(user_buf, - count, ppos, buf, pos); - kfree(buf); - } - } - - return ret; -} - -static ssize_t iwl_dbgfs_missed_beacon_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) { - - struct iwl_priv *priv = file->private_data; - int pos = 0; - char buf[12]; - const size_t bufsz = sizeof(buf); - ssize_t ret; - - pos += scnprintf(buf + pos, bufsz - pos, "%d\n", - priv->missed_beacon_threshold); - - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - return ret; -} - -static ssize_t iwl_dbgfs_missed_beacon_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_priv *priv = file->private_data; - char buf[8]; - int buf_size; - int missed; - - memset(buf, 0, sizeof(buf)); - buf_size = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, buf_size)) - return -EFAULT; - if (sscanf(buf, "%d", &missed) != 1) - return -EINVAL; - - if (missed < IWL_MISSED_BEACON_THRESHOLD_MIN || - missed > IWL_MISSED_BEACON_THRESHOLD_MAX) - priv->missed_beacon_threshold = - IWL_MISSED_BEACON_THRESHOLD_DEF; - else - priv->missed_beacon_threshold = missed; - - return count; -} - -static ssize_t iwl_dbgfs_internal_scan_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_priv *priv = file->private_data; - char buf[8]; - int buf_size; - int scan; - - memset(buf, 0, sizeof(buf)); - buf_size = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, buf_size)) - return -EFAULT; - if (sscanf(buf, "%d", &scan) != 1) - return -EINVAL; - - iwl_internal_short_hw_scan(priv); - - return count; -} - -static ssize_t iwl_dbgfs_plcp_delta_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) { - - struct iwl_priv *priv = (struct iwl_priv *)file->private_data; - int pos = 0; - char buf[12]; - const size_t bufsz = sizeof(buf); - ssize_t ret; - - pos += scnprintf(buf + pos, bufsz - pos, "%u\n", - priv->cfg->plcp_delta_threshold); - - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - return ret; -} - -static ssize_t iwl_dbgfs_plcp_delta_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) { - - struct iwl_priv *priv = file->private_data; - char buf[8]; - int buf_size; - int plcp; - - memset(buf, 0, sizeof(buf)); - buf_size = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, buf_size)) - return -EFAULT; - if (sscanf(buf, "%d", &plcp) != 1) - return -EINVAL; - if ((plcp <= IWL_MAX_PLCP_ERR_THRESHOLD_MIN) || - (plcp > IWL_MAX_PLCP_ERR_THRESHOLD_MAX)) - priv->cfg->plcp_delta_threshold = - IWL_MAX_PLCP_ERR_THRESHOLD_DEF; - else - priv->cfg->plcp_delta_threshold = plcp; - return count; -} - -static ssize_t iwl_dbgfs_force_reset_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) { - - struct iwl_priv *priv = file->private_data; - int i, pos = 0; - char buf[300]; - const size_t bufsz = sizeof(buf); - struct iwl_force_reset *force_reset; - - for (i = 0; i < IWL_MAX_FORCE_RESET; i++) { - force_reset = &priv->force_reset[i]; - pos += scnprintf(buf + pos, bufsz - pos, - "Force reset method %d\n", i); - pos += scnprintf(buf + pos, bufsz - pos, - "\tnumber of reset request: %d\n", - force_reset->reset_request_count); - pos += scnprintf(buf + pos, bufsz - pos, - "\tnumber of reset request success: %d\n", - force_reset->reset_success_count); - pos += scnprintf(buf + pos, bufsz - pos, - "\tnumber of reset request reject: %d\n", - force_reset->reset_reject_count); - pos += scnprintf(buf + pos, bufsz - pos, - "\treset duration: %lu\n", - force_reset->reset_duration); - } - return simple_read_from_buffer(user_buf, count, ppos, buf, pos); -} - -static ssize_t iwl_dbgfs_force_reset_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) { - - struct iwl_priv *priv = file->private_data; - char buf[8]; - int buf_size; - int reset, ret; - - memset(buf, 0, sizeof(buf)); - buf_size = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, buf_size)) - return -EFAULT; - if (sscanf(buf, "%d", &reset) != 1) - return -EINVAL; - switch (reset) { - case IWL_RF_RESET: - case IWL_FW_RESET: - ret = iwl_force_reset(priv, reset); - break; - default: - return -EINVAL; - } - return ret ? ret : count; -} - DEBUGFS_READ_FILE_OPS(rx_statistics); DEBUGFS_READ_FILE_OPS(tx_statistics); DEBUGFS_READ_WRITE_FILE_OPS(traffic_log); @@ -2291,13 +1859,6 @@ DEBUGFS_READ_FILE_OPS(tx_power); DEBUGFS_READ_FILE_OPS(power_save_status); DEBUGFS_WRITE_FILE_OPS(clear_ucode_statistics); DEBUGFS_WRITE_FILE_OPS(clear_traffic_statistics); -DEBUGFS_WRITE_FILE_OPS(csr); -DEBUGFS_READ_WRITE_FILE_OPS(ucode_tracing); -DEBUGFS_READ_FILE_OPS(fh_reg); -DEBUGFS_READ_WRITE_FILE_OPS(missed_beacon); -DEBUGFS_WRITE_FILE_OPS(internal_scan); -DEBUGFS_READ_WRITE_FILE_OPS(plcp_delta); -DEBUGFS_READ_WRITE_FILE_OPS(force_reset); /* * Create the debugfs files and directories @@ -2305,74 +1866,69 @@ DEBUGFS_READ_WRITE_FILE_OPS(force_reset); */ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) { + struct iwl_debugfs *dbgfs; struct dentry *phyd = priv->hw->wiphy->debugfsdir; - struct dentry *dir_drv, *dir_data, *dir_rf, *dir_debug; - - dir_drv = debugfs_create_dir(name, phyd); - if (!dir_drv) - return -ENOMEM; - - priv->debugfs_dir = dir_drv; + int ret = 0; - dir_data = debugfs_create_dir("data", dir_drv); - if (!dir_data) - goto err; - dir_rf = debugfs_create_dir("rf", dir_drv); - if (!dir_rf) + dbgfs = kzalloc(sizeof(struct iwl_debugfs), GFP_KERNEL); + if (!dbgfs) { + ret = -ENOMEM; goto err; - dir_debug = debugfs_create_dir("debug", dir_drv); - if (!dir_debug) + } + + priv->dbgfs = dbgfs; + dbgfs->name = name; + dbgfs->dir_drv = debugfs_create_dir(name, phyd); + if (!dbgfs->dir_drv || IS_ERR(dbgfs->dir_drv)) { + ret = -ENOENT; goto err; + } - DEBUGFS_ADD_FILE(nvm, dir_data, S_IRUSR); - DEBUGFS_ADD_FILE(sram, dir_data, S_IWUSR | S_IRUSR); - DEBUGFS_ADD_FILE(log_event, dir_data, S_IWUSR | S_IRUSR); - DEBUGFS_ADD_FILE(stations, dir_data, S_IRUSR); - DEBUGFS_ADD_FILE(channels, dir_data, S_IRUSR); - DEBUGFS_ADD_FILE(status, dir_data, S_IRUSR); - DEBUGFS_ADD_FILE(interrupt, dir_data, S_IWUSR | S_IRUSR); - DEBUGFS_ADD_FILE(qos, dir_data, S_IRUSR); - DEBUGFS_ADD_FILE(led, dir_data, S_IRUSR); - DEBUGFS_ADD_FILE(sleep_level_override, dir_data, S_IWUSR | S_IRUSR); - DEBUGFS_ADD_FILE(current_sleep_command, dir_data, S_IRUSR); - DEBUGFS_ADD_FILE(thermal_throttling, dir_data, S_IRUSR); - DEBUGFS_ADD_FILE(disable_ht40, dir_data, S_IWUSR | S_IRUSR); - DEBUGFS_ADD_FILE(rx_statistics, dir_debug, S_IRUSR); - DEBUGFS_ADD_FILE(tx_statistics, dir_debug, S_IRUSR); - DEBUGFS_ADD_FILE(traffic_log, dir_debug, S_IWUSR | S_IRUSR); - DEBUGFS_ADD_FILE(rx_queue, dir_debug, S_IRUSR); - DEBUGFS_ADD_FILE(tx_queue, dir_debug, S_IRUSR); - DEBUGFS_ADD_FILE(tx_power, dir_debug, S_IRUSR); - DEBUGFS_ADD_FILE(power_save_status, dir_debug, S_IRUSR); - DEBUGFS_ADD_FILE(clear_ucode_statistics, dir_debug, S_IWUSR); - DEBUGFS_ADD_FILE(clear_traffic_statistics, dir_debug, S_IWUSR); - DEBUGFS_ADD_FILE(csr, dir_debug, S_IWUSR); - DEBUGFS_ADD_FILE(fh_reg, dir_debug, S_IRUSR); - DEBUGFS_ADD_FILE(missed_beacon, dir_debug, S_IWUSR); - DEBUGFS_ADD_FILE(internal_scan, dir_debug, S_IWUSR); - DEBUGFS_ADD_FILE(plcp_delta, dir_debug, S_IWUSR | S_IRUSR); - DEBUGFS_ADD_FILE(force_reset, dir_debug, S_IWUSR | S_IRUSR); + DEBUGFS_ADD_DIR(data, dbgfs->dir_drv); + DEBUGFS_ADD_DIR(rf, dbgfs->dir_drv); + DEBUGFS_ADD_DIR(debug, dbgfs->dir_drv); + DEBUGFS_ADD_FILE(nvm, data, S_IRUSR); + DEBUGFS_ADD_FILE(sram, data, S_IWUSR | S_IRUSR); + DEBUGFS_ADD_FILE(log_event, data, S_IWUSR); + DEBUGFS_ADD_FILE(stations, data, S_IRUSR); + DEBUGFS_ADD_FILE(channels, data, S_IRUSR); + DEBUGFS_ADD_FILE(status, data, S_IRUSR); + DEBUGFS_ADD_FILE(interrupt, data, S_IWUSR | S_IRUSR); + DEBUGFS_ADD_FILE(qos, data, S_IRUSR); + DEBUGFS_ADD_FILE(led, data, S_IRUSR); + DEBUGFS_ADD_FILE(sleep_level_override, data, S_IWUSR | S_IRUSR); + DEBUGFS_ADD_FILE(current_sleep_command, data, S_IRUSR); + DEBUGFS_ADD_FILE(thermal_throttling, data, S_IRUSR); + DEBUGFS_ADD_FILE(disable_ht40, data, S_IWUSR | S_IRUSR); + DEBUGFS_ADD_FILE(rx_statistics, debug, S_IRUSR); + DEBUGFS_ADD_FILE(tx_statistics, debug, S_IRUSR); + DEBUGFS_ADD_FILE(traffic_log, debug, S_IWUSR | S_IRUSR); + DEBUGFS_ADD_FILE(rx_queue, debug, S_IRUSR); + DEBUGFS_ADD_FILE(tx_queue, debug, S_IRUSR); + DEBUGFS_ADD_FILE(tx_power, debug, S_IRUSR); + DEBUGFS_ADD_FILE(power_save_status, debug, S_IRUSR); + DEBUGFS_ADD_FILE(clear_ucode_statistics, debug, S_IWUSR); + DEBUGFS_ADD_FILE(clear_traffic_statistics, debug, S_IWUSR); if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) { - DEBUGFS_ADD_FILE(ucode_rx_stats, dir_debug, S_IRUSR); - DEBUGFS_ADD_FILE(ucode_tx_stats, dir_debug, S_IRUSR); - DEBUGFS_ADD_FILE(ucode_general_stats, dir_debug, S_IRUSR); - DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR); - DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR); - DEBUGFS_ADD_FILE(ucode_tracing, dir_debug, S_IWUSR | S_IRUSR); + DEBUGFS_ADD_FILE(ucode_rx_stats, debug, S_IRUSR); + DEBUGFS_ADD_FILE(ucode_tx_stats, debug, S_IRUSR); + DEBUGFS_ADD_FILE(ucode_general_stats, debug, S_IRUSR); + DEBUGFS_ADD_FILE(sensitivity, debug, S_IRUSR); + DEBUGFS_ADD_FILE(chain_noise, debug, S_IRUSR); } - DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf, &priv->disable_sens_cal); - DEBUGFS_ADD_BOOL(disable_chain_noise, dir_rf, + DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal); + DEBUGFS_ADD_BOOL(disable_chain_noise, rf, &priv->disable_chain_noise_cal); if (((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) || ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_3945)) - DEBUGFS_ADD_BOOL(disable_tx_power, dir_rf, + DEBUGFS_ADD_BOOL(disable_tx_power, rf, &priv->disable_tx_power_cal); return 0; err: - IWL_ERR(priv, "Can't create the debugfs directory\n"); + IWL_ERR(priv, "Can't open the debugfs directory\n"); iwl_dbgfs_unregister(priv); - return -ENOMEM; + return ret; } EXPORT_SYMBOL(iwl_dbgfs_register); @@ -2382,11 +1938,56 @@ EXPORT_SYMBOL(iwl_dbgfs_register); */ void iwl_dbgfs_unregister(struct iwl_priv *priv) { - if (!priv->debugfs_dir) + if (!priv->dbgfs) return; - debugfs_remove_recursive(priv->debugfs_dir); - priv->debugfs_dir = NULL; + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sleep_level_override); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_current_sleep_command); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_nvm); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sram); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_log_event); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_stations); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_channels); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_status); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_interrupt); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_qos); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_led); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_thermal_throttling); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_disable_ht40); + DEBUGFS_REMOVE(priv->dbgfs->dir_data); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_rx_statistics); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_statistics); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_traffic_log); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_rx_queue); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_queue); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_power); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_power_save_status); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. + file_clear_ucode_statistics); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. + file_clear_traffic_statistics); + if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) { + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. + file_ucode_rx_stats); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. + file_ucode_tx_stats); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. + file_ucode_general_stats); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. + file_sensitivity); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. + file_chain_noise); + } + DEBUGFS_REMOVE(priv->dbgfs->dir_debug); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise); + if (((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) || + ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_3945)) + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_tx_power); + DEBUGFS_REMOVE(priv->dbgfs->dir_rf); + DEBUGFS_REMOVE(priv->dbgfs->dir_drv); + kfree(priv->dbgfs); + priv->dbgfs = NULL; } EXPORT_SYMBOL(iwl_dbgfs_unregister); diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-dev.h b/trunk/drivers/net/wireless/iwlwifi/iwl-dev.h index 7914d65a5a55..3822cf53e368 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -512,7 +512,6 @@ struct iwl_ht_config { bool is_ht; bool is_40mhz; bool single_chain_sufficient; - enum ieee80211_smps_mode smps; /* current smps mode */ /* BSS related data */ u8 extension_chan_offset; u8 ht_protection; @@ -985,74 +984,6 @@ struct iwl_switch_rxon { __le16 channel; }; -/* - * schedule the timer to wake up every UCODE_TRACE_PERIOD milliseconds - * to perform continuous uCode event logging operation if enabled - */ -#define UCODE_TRACE_PERIOD (100) - -/* - * iwl_event_log: current uCode event log position - * - * @ucode_trace: enable/disable ucode continuous trace timer - * @num_wraps: how many times the event buffer wraps - * @next_entry: the entry just before the next one that uCode would fill - * @non_wraps_count: counter for no wrap detected when dump ucode events - * @wraps_once_count: counter for wrap once detected when dump ucode events - * @wraps_more_count: counter for wrap more than once detected - * when dump ucode events - */ -struct iwl_event_log { - bool ucode_trace; - u32 num_wraps; - u32 next_entry; - int non_wraps_count; - int wraps_once_count; - int wraps_more_count; -}; - -/* - * host interrupt timeout value - * used with setting interrupt coalescing timer - * the CSR_INT_COALESCING is an 8 bit register in 32-usec unit - * - * default interrupt coalescing timer is 64 x 32 = 2048 usecs - * default interrupt coalescing calibration timer is 16 x 32 = 512 usecs - */ -#define IWL_HOST_INT_TIMEOUT_MAX (0xFF) -#define IWL_HOST_INT_TIMEOUT_DEF (0x40) -#define IWL_HOST_INT_TIMEOUT_MIN (0x0) -#define IWL_HOST_INT_CALIB_TIMEOUT_MAX (0xFF) -#define IWL_HOST_INT_CALIB_TIMEOUT_DEF (0x10) -#define IWL_HOST_INT_CALIB_TIMEOUT_MIN (0x0) - -/* - * This is the threshold value of plcp error rate per 100mSecs. It is - * used to set and check for the validity of plcp_delta. - */ -#define IWL_MAX_PLCP_ERR_THRESHOLD_MIN (0) -#define IWL_MAX_PLCP_ERR_THRESHOLD_DEF (50) -#define IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF (100) -#define IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF (200) -#define IWL_MAX_PLCP_ERR_THRESHOLD_MAX (255) - -#define IWL_DELAY_NEXT_FORCE_RF_RESET (HZ*3) -#define IWL_DELAY_NEXT_FORCE_FW_RELOAD (HZ*5) - -enum iwl_reset { - IWL_RF_RESET = 0, - IWL_FW_RESET, - IWL_MAX_FORCE_RESET, -}; - -struct iwl_force_reset { - int reset_request_count; - int reset_success_count; - int reset_reject_count; - unsigned long reset_duration; - unsigned long last_force_reset_jiffies; -}; - struct iwl_priv { /* ieee device used by generic ieee processing code */ @@ -1073,22 +1004,13 @@ struct iwl_priv { struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS]; +#if defined(CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT) || defined(CONFIG_IWL3945_SPECTRUM_MEASUREMENT) /* spectrum measurement report caching */ struct iwl_spectrum_notification measure_report; u8 measurement_status; - +#endif /* ucode beacon time */ u32 ucode_beacon_time; - int missed_beacon_threshold; - - /* storing the jiffies when the plcp error rate is received */ - unsigned long plcp_jiffies; - - /* reporting the number of tids has AGG on. 0 means no AGGREGATION */ - u8 agg_tids_count; - - /* force reset */ - struct iwl_force_reset force_reset[IWL_MAX_FORCE_RESET]; /* we allocate array of iwl4965_channel_info for NIC's valid channels. * Access via channel # using indirect index array */ @@ -1107,6 +1029,7 @@ struct iwl_priv { struct iwl_calib_result calib_results[IWL_CALIB_MAX]; /* Scan related variables */ + unsigned long last_scan_jiffies; unsigned long next_scan_jiffies; unsigned long scan_start; unsigned long scan_pass_start; @@ -1114,7 +1037,6 @@ struct iwl_priv { void *scan; int scan_bands; struct cfg80211_scan_request *scan_request; - bool is_internal_short_scan; u8 scan_tx_ant[IEEE80211_NUM_BANDS]; u8 mgmt_tx_ant; @@ -1123,7 +1045,6 @@ struct iwl_priv { spinlock_t hcmd_lock; /* protect hcmd */ spinlock_t reg_lock; /* protect hw register access */ struct mutex mutex; - struct mutex sync_cmd_mutex; /* enable serialization of sync commands */ /* basic pci-network driver stuff */ struct pci_dev *pci_dev; @@ -1214,8 +1135,6 @@ struct iwl_priv { struct iwl_notif_statistics statistics; #ifdef CONFIG_IWLWIFI_DEBUG struct iwl_notif_statistics accum_statistics; - struct iwl_notif_statistics delta_statistics; - struct iwl_notif_statistics max_delta; #endif /* context information */ @@ -1288,10 +1207,15 @@ struct iwl_priv { struct workqueue_struct *workqueue; + struct work_struct up; struct work_struct restart; + struct work_struct calibrated_work; struct work_struct scan_completed; struct work_struct rx_replenish; struct work_struct abort_scan; + struct work_struct update_link_led; + struct work_struct auth_work; + struct work_struct report_work; struct work_struct request_scan; struct work_struct beacon_update; struct work_struct tt_work; @@ -1327,8 +1251,7 @@ struct iwl_priv { u16 rx_traffic_idx; u8 *tx_traffic; u8 *rx_traffic; - struct dentry *debugfs_dir; - u32 dbgfs_sram_offset, dbgfs_sram_len; + struct iwl_debugfs *dbgfs; #endif /* CONFIG_IWLWIFI_DEBUGFS */ #endif /* CONFIG_IWLWIFI_DEBUG */ @@ -1338,7 +1261,6 @@ struct iwl_priv { u32 disable_tx_power_cal; struct work_struct run_time_calib_work; struct timer_list statistics_periodic; - struct timer_list ucode_trace; bool hw_ready; /*For 3945*/ #define IWL_DEFAULT_TX_POWER 0x0F @@ -1346,8 +1268,6 @@ struct iwl_priv { struct iwl3945_notif_statistics statistics_39; u32 sta_supp_rates; - - struct iwl_event_log event_log; }; /*iwl_priv */ static inline void iwl_txq_ctx_activate(struct iwl_priv *priv, int txq_id) diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-devtrace.c b/trunk/drivers/net/wireless/iwlwifi/iwl-devtrace.c index 36580d8d8b8d..83cc4e500a96 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-devtrace.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-devtrace.c @@ -37,6 +37,4 @@ EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_iowrite32); EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_rx); EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_event); EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_error); -EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_cont_event); -EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_wrap_event); #endif diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/trunk/drivers/net/wireless/iwlwifi/iwl-devtrace.h index ff4d012ce260..d9c7363b1bbb 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-devtrace.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-devtrace.h @@ -90,50 +90,6 @@ TRACE_EVENT(iwlwifi_dev_iowrite32, TP_printk("[%p] write io[%#x] = %#x)", __entry->priv, __entry->offs, __entry->val) ); -#undef TRACE_SYSTEM -#define TRACE_SYSTEM iwlwifi_ucode - -TRACE_EVENT(iwlwifi_dev_ucode_cont_event, - TP_PROTO(struct iwl_priv *priv, u32 time, u32 data, u32 ev), - TP_ARGS(priv, time, data, ev), - TP_STRUCT__entry( - PRIV_ENTRY - - __field(u32, time) - __field(u32, data) - __field(u32, ev) - ), - TP_fast_assign( - PRIV_ASSIGN; - __entry->time = time; - __entry->data = data; - __entry->ev = ev; - ), - TP_printk("[%p] EVT_LOGT:%010u:0x%08x:%04u", - __entry->priv, __entry->time, __entry->data, __entry->ev) -); - -TRACE_EVENT(iwlwifi_dev_ucode_wrap_event, - TP_PROTO(struct iwl_priv *priv, u32 wraps, u32 n_entry, u32 p_entry), - TP_ARGS(priv, wraps, n_entry, p_entry), - TP_STRUCT__entry( - PRIV_ENTRY - - __field(u32, wraps) - __field(u32, n_entry) - __field(u32, p_entry) - ), - TP_fast_assign( - PRIV_ASSIGN; - __entry->wraps = wraps; - __entry->n_entry = n_entry; - __entry->p_entry = p_entry; - ), - TP_printk("[%p] wraps=#%02d n=0x%X p=0x%X", - __entry->priv, __entry->wraps, __entry->n_entry, - __entry->p_entry) -); - #undef TRACE_SYSTEM #define TRACE_SYSTEM iwlwifi diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/trunk/drivers/net/wireless/iwlwifi/iwl-eeprom.c index fd37152abae3..4a30969689ff 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2009 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/trunk/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 4e1ba824dc50..0cd9c02ee044 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2009 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-fh.h b/trunk/drivers/net/wireless/iwlwifi/iwl-fh.h index 113c3669b9ce..65fa8a69fd5a 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-fh.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-fh.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -379,25 +379,6 @@ #define FH_TSSR_TX_STATUS_REG (FH_TSSR_LOWER_BOUND + 0x010) -/** - * Bit fields for TSSR(Tx Shared Status & Control) error status register: - * 31: Indicates an address error when accessed to internal memory - * uCode/driver must write "1" in order to clear this flag - * 30: Indicates that Host did not send the expected number of dwords to FH - * uCode/driver must write "1" in order to clear this flag - * 16-9:Each status bit is for one channel. Indicates that an (Error) ActDMA - * command was received from the scheduler while the TRB was already full - * with previous command - * uCode/driver must write "1" in order to clear this flag - * 7-0: Each status bit indicates a channel's TxCredit error. When an error - * bit is set, it indicates that the FH has received a full indication - * from the RTC TxFIFO and the current value of the TxCredit counter was - * not equal to zero. This mean that the credit mechanism was not - * synchronized to the TxFIFO status - * uCode/driver must write "1" in order to clear this flag - */ -#define FH_TSSR_TX_ERROR_REG (FH_TSSR_LOWER_BOUND + 0x018) - #define FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) ((1 << (_chnl)) << 24) #define FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl) ((1 << (_chnl)) << 16) diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/trunk/drivers/net/wireless/iwlwifi/iwl-hcmd.c index 73681c4fefe7..30e9ea6d54ec 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2009 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -58,6 +58,7 @@ const char *get_cmd_string(u8 cmd) IWL_CMD(COEX_PRIORITY_TABLE_CMD); IWL_CMD(COEX_MEDIUM_NOTIFICATION); IWL_CMD(COEX_EVENT_CMD); + IWL_CMD(RADAR_NOTIFICATION); IWL_CMD(REPLY_QUIET_CMD); IWL_CMD(REPLY_CHANNEL_SWITCH); IWL_CMD(CHANNEL_SWITCH_NOTIFICATION); @@ -164,13 +165,15 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) /* A synchronous command can not have a callback set. */ BUG_ON(cmd->callback); - IWL_DEBUG_INFO(priv, "Attempting to send sync command %s\n", + if (test_and_set_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status)) { + IWL_ERR(priv, + "Error sending %s: Already sending a host command\n", get_cmd_string(cmd->id)); - mutex_lock(&priv->sync_cmd_mutex); + ret = -EBUSY; + goto out; + } set_bit(STATUS_HCMD_ACTIVE, &priv->status); - IWL_DEBUG_INFO(priv, "Setting HCMD_ACTIVE for command %s \n", - get_cmd_string(cmd->id)); cmd_idx = iwl_enqueue_hcmd(priv, cmd); if (cmd_idx < 0) { @@ -191,8 +194,6 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) jiffies_to_msecs(HOST_COMPLETE_TIMEOUT)); clear_bit(STATUS_HCMD_ACTIVE, &priv->status); - IWL_DEBUG_INFO(priv, "Clearing HCMD_ACTIVE for command %s \n", - get_cmd_string(cmd->id)); ret = -ETIMEDOUT; goto cancel; } @@ -237,7 +238,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) cmd->reply_page = 0; } out: - mutex_unlock(&priv->sync_cmd_mutex); + clear_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status); return ret; } EXPORT_SYMBOL(iwl_send_cmd_sync); diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-helpers.h b/trunk/drivers/net/wireless/iwlwifi/iwl-helpers.h index 51a67fb2e185..bd0b12efb5c7 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-helpers.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-helpers.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -80,8 +80,8 @@ static inline void iwl_free_fw_desc(struct pci_dev *pci_dev, struct fw_desc *desc) { if (desc->v_addr) - dma_free_coherent(&pci_dev->dev, desc->len, - desc->v_addr, desc->p_addr); + pci_free_consistent(pci_dev, desc->len, + desc->v_addr, desc->p_addr); desc->v_addr = NULL; desc->len = 0; } @@ -89,8 +89,7 @@ static inline void iwl_free_fw_desc(struct pci_dev *pci_dev, static inline int iwl_alloc_fw_desc(struct pci_dev *pci_dev, struct fw_desc *desc) { - desc->v_addr = dma_alloc_coherent(&pci_dev->dev, desc->len, - &desc->p_addr, GFP_KERNEL); + desc->v_addr = pci_alloc_consistent(pci_dev, desc->len, &desc->p_addr); return (desc->v_addr != NULL) ? 0 : -ENOMEM; } diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-io.h b/trunk/drivers/net/wireless/iwlwifi/iwl-io.h index c719baf2585a..e552d4c4bdbe 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-io.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project. * diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-led.c b/trunk/drivers/net/wireless/iwlwifi/iwl-led.c index a6f9c918aabc..46c7a95b88f0 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-led.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-led.h b/trunk/drivers/net/wireless/iwlwifi/iwl-led.h index 49a70baa3fb6..f47f053f02ea 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-led.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-led.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-power.c b/trunk/drivers/net/wireless/iwlwifi/iwl-power.c index 1a1a9f081cc7..8ccc0bb1d9ed 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-power.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -303,12 +303,13 @@ static int iwl_set_power(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd) sizeof(struct iwl_powertable_cmd), cmd); } -/* priv->mutex must be held */ + int iwl_power_update_mode(struct iwl_priv *priv, bool force) { int ret = 0; struct iwl_tt_mgmt *tt = &priv->thermal_throttle; - bool enabled = priv->hw->conf.flags & IEEE80211_CONF_PS; + bool enabled = (priv->iw_mode == NL80211_IFTYPE_STATION) && + (priv->hw->conf.flags & IEEE80211_CONF_PS); bool update_chains; struct iwl_powertable_cmd cmd; int dtimper; @@ -318,7 +319,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE; if (priv->vif) - dtimper = priv->hw->conf.ps_dtim_period; + dtimper = priv->vif->bss_conf.dtim_period; else dtimper = 1; diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-power.h b/trunk/drivers/net/wireless/iwlwifi/iwl-power.h index 5db91c10dcc8..310c32e8f698 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-power.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-power.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-prph.h b/trunk/drivers/net/wireless/iwlwifi/iwl-prph.h index d2d2a9174900..6d95832db06d 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-rx.c b/trunk/drivers/net/wireless/iwlwifi/iwl-rx.c index 0d09f571e185..2dbce85404aa 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -123,11 +123,12 @@ EXPORT_SYMBOL(iwl_rx_queue_space); /** * iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue */ -void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q) +int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q) { unsigned long flags; u32 rx_wrt_ptr_reg = priv->hw_params.rx_wrt_ptr_reg; u32 reg; + int ret = 0; spin_lock_irqsave(&q->lock, flags); @@ -160,6 +161,7 @@ void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q exit_unlock: spin_unlock_irqrestore(&q->lock, flags); + return ret; } EXPORT_SYMBOL(iwl_rx_queue_update_write_ptr); /** @@ -182,13 +184,14 @@ static inline __le32 iwl_dma_addr2rbd_ptr(struct iwl_priv *priv, * also updates the memory address in the firmware to reference the new * target buffer. */ -void iwl_rx_queue_restock(struct iwl_priv *priv) +int iwl_rx_queue_restock(struct iwl_priv *priv) { struct iwl_rx_queue *rxq = &priv->rxq; struct list_head *element; struct iwl_rx_mem_buffer *rxb; unsigned long flags; int write; + int ret = 0; spin_lock_irqsave(&rxq->lock, flags); write = rxq->write & ~0x7; @@ -217,8 +220,10 @@ void iwl_rx_queue_restock(struct iwl_priv *priv) spin_lock_irqsave(&rxq->lock, flags); rxq->need_update = 1; spin_unlock_irqrestore(&rxq->lock, flags); - iwl_rx_queue_update_write_ptr(priv, rxq); + ret = iwl_rx_queue_update_write_ptr(priv, rxq); } + + return ret; } EXPORT_SYMBOL(iwl_rx_queue_restock); @@ -345,10 +350,10 @@ void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq) } } - dma_free_coherent(&priv->pci_dev->dev, 4 * RX_QUEUE_SIZE, rxq->bd, - rxq->dma_addr); - dma_free_coherent(&priv->pci_dev->dev, sizeof(struct iwl_rb_status), - rxq->rb_stts, rxq->rb_stts_dma); + pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd, + rxq->dma_addr); + pci_free_consistent(priv->pci_dev, sizeof(struct iwl_rb_status), + rxq->rb_stts, rxq->rb_stts_dma); rxq->bd = NULL; rxq->rb_stts = NULL; } @@ -357,7 +362,7 @@ EXPORT_SYMBOL(iwl_rx_queue_free); int iwl_rx_queue_alloc(struct iwl_priv *priv) { struct iwl_rx_queue *rxq = &priv->rxq; - struct device *dev = &priv->pci_dev->dev; + struct pci_dev *dev = priv->pci_dev; int i; spin_lock_init(&rxq->lock); @@ -365,13 +370,12 @@ int iwl_rx_queue_alloc(struct iwl_priv *priv) INIT_LIST_HEAD(&rxq->rx_used); /* Alloc the circular buffer of Read Buffer Descriptors (RBDs) */ - rxq->bd = dma_alloc_coherent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr, - GFP_KERNEL); + rxq->bd = pci_alloc_consistent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr); if (!rxq->bd) goto err_bd; - rxq->rb_stts = dma_alloc_coherent(dev, sizeof(struct iwl_rb_status), - &rxq->rb_stts_dma, GFP_KERNEL); + rxq->rb_stts = pci_alloc_consistent(dev, sizeof(struct iwl_rb_status), + &rxq->rb_stts_dma); if (!rxq->rb_stts) goto err_rb; @@ -388,8 +392,8 @@ int iwl_rx_queue_alloc(struct iwl_priv *priv) return 0; err_rb: - dma_free_coherent(&priv->pci_dev->dev, 4 * RX_QUEUE_SIZE, rxq->bd, - rxq->dma_addr); + pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd, + rxq->dma_addr); err_bd: return -ENOMEM; } @@ -469,8 +473,8 @@ int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) (rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)| (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS)); - /* Set interrupt coalescing timer to default (2048 usecs) */ - iwl_write8(priv, CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF); + /* Set interrupt coalescing timer to 64 x 32 = 2048 usecs */ + iwl_write8(priv, CSR_INT_COALESCING, 0x40); return 0; } @@ -495,10 +499,9 @@ void iwl_rx_missed_beacon_notif(struct iwl_priv *priv, struct iwl_missed_beacon_notif *missed_beacon; missed_beacon = &pkt->u.missed_beacon; - if (le32_to_cpu(missed_beacon->consecutive_missed_beacons) > - priv->missed_beacon_threshold) { + if (le32_to_cpu(missed_beacon->consequtive_missed_beacons) > 5) { IWL_DEBUG_CALIB(priv, "missed bcn cnsq %d totl %d rcd %d expctd %d\n", - le32_to_cpu(missed_beacon->consecutive_missed_beacons), + le32_to_cpu(missed_beacon->consequtive_missed_beacons), le32_to_cpu(missed_beacon->total_missed_becons), le32_to_cpu(missed_beacon->num_recvd_beacons), le32_to_cpu(missed_beacon->num_expected_beacons)); @@ -508,24 +511,6 @@ void iwl_rx_missed_beacon_notif(struct iwl_priv *priv, } EXPORT_SYMBOL(iwl_rx_missed_beacon_notif); -void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif); - - if (!report->state) { - IWL_DEBUG_11H(priv, - "Spectrum Measure Notification: Start\n"); - return; - } - - memcpy(&priv->measure_report, report, sizeof(*report)); - priv->measurement_status |= MEASUREMENT_READY; -} -EXPORT_SYMBOL(iwl_rx_spectrum_measure_notif); - - /* Calculate noise level, based on measurements during network silence just * before arriving beacon. This measurement can be done only if we know @@ -579,24 +564,15 @@ static void iwl_accumulative_statistics(struct iwl_priv *priv, int i; __le32 *prev_stats; u32 *accum_stats; - u32 *delta, *max_delta; prev_stats = (__le32 *)&priv->statistics; accum_stats = (u32 *)&priv->accum_statistics; - delta = (u32 *)&priv->delta_statistics; - max_delta = (u32 *)&priv->max_delta; for (i = sizeof(__le32); i < sizeof(struct iwl_notif_statistics); - i += sizeof(__le32), stats++, prev_stats++, delta++, - max_delta++, accum_stats++) { - if (le32_to_cpu(*stats) > le32_to_cpu(*prev_stats)) { - *delta = (le32_to_cpu(*stats) - + i += sizeof(__le32), stats++, prev_stats++, accum_stats++) + if (le32_to_cpu(*stats) > le32_to_cpu(*prev_stats)) + *accum_stats += (le32_to_cpu(*stats) - le32_to_cpu(*prev_stats)); - *accum_stats += *delta; - if (*delta > *max_delta) - *max_delta = *delta; - } - } /* reset accumulative statistics for "no-counter" type statistics */ priv->accum_statistics.general.temperature = @@ -616,23 +592,11 @@ static void iwl_accumulative_statistics(struct iwl_priv *priv, #define REG_RECALIB_PERIOD (60) -/* the threshold ratio of actual_ack_cnt to expected_ack_cnt in percent */ -#define ACK_CNT_RATIO (50) -#define BA_TIMEOUT_CNT (5) -#define BA_TIMEOUT_MAX (16) - -#define PLCP_MSG "plcp_err exceeded %u, %u, %u, %u, %u, %d, %u mSecs\n" void iwl_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { int change; struct iwl_rx_packet *pkt = rxb_addr(rxb); - int combined_plcp_delta; - unsigned int plcp_msec; - unsigned long plcp_received_jiffies; - int actual_ack_cnt_delta; - int expected_ack_cnt_delta; - int ba_timeout_delta; IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n", (int)sizeof(priv->statistics), @@ -647,94 +611,6 @@ void iwl_rx_statistics(struct iwl_priv *priv, #ifdef CONFIG_IWLWIFI_DEBUG iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats); #endif - actual_ack_cnt_delta = le32_to_cpu(pkt->u.stats.tx.actual_ack_cnt) - - le32_to_cpu(priv->statistics.tx.actual_ack_cnt); - expected_ack_cnt_delta = le32_to_cpu( - pkt->u.stats.tx.expected_ack_cnt) - - le32_to_cpu(priv->statistics.tx.expected_ack_cnt); - ba_timeout_delta = le32_to_cpu( - pkt->u.stats.tx.agg.ba_timeout) - - le32_to_cpu(priv->statistics.tx.agg.ba_timeout); - if ((priv->agg_tids_count > 0) && - (expected_ack_cnt_delta > 0) && - (((actual_ack_cnt_delta * 100) / expected_ack_cnt_delta) < - ACK_CNT_RATIO) && - (ba_timeout_delta > BA_TIMEOUT_CNT)) { - IWL_DEBUG_RADIO(priv, - "actual_ack_cnt delta = %d, expected_ack_cnt = %d\n", - actual_ack_cnt_delta, expected_ack_cnt_delta); - -#ifdef CONFIG_IWLWIFI_DEBUG - IWL_DEBUG_RADIO(priv, "rx_detected_cnt delta = %d\n", - priv->delta_statistics.tx.rx_detected_cnt); - IWL_DEBUG_RADIO(priv, - "ack_or_ba_timeout_collision delta = %d\n", - priv->delta_statistics.tx.ack_or_ba_timeout_collision); -#endif - IWL_DEBUG_RADIO(priv, "agg ba_timeout delta = %d\n", - ba_timeout_delta); - if ((actual_ack_cnt_delta == 0) && - (ba_timeout_delta >= - BA_TIMEOUT_MAX)) { - IWL_DEBUG_RADIO(priv, - "call iwl_force_reset(IWL_FW_RESET)\n"); - iwl_force_reset(priv, IWL_FW_RESET); - } else { - IWL_DEBUG_RADIO(priv, - "call iwl_force_reset(IWL_RF_RESET)\n"); - iwl_force_reset(priv, IWL_RF_RESET); - } - } - /* - * check for plcp_err and trigger radio reset if it exceeds - * the plcp error threshold plcp_delta. - */ - plcp_received_jiffies = jiffies; - plcp_msec = jiffies_to_msecs((long) plcp_received_jiffies - - (long) priv->plcp_jiffies); - priv->plcp_jiffies = plcp_received_jiffies; - /* - * check to make sure plcp_msec is not 0 to prevent division - * by zero. - */ - if (plcp_msec) { - combined_plcp_delta = - (le32_to_cpu(pkt->u.stats.rx.ofdm.plcp_err) - - le32_to_cpu(priv->statistics.rx.ofdm.plcp_err)) + - (le32_to_cpu(pkt->u.stats.rx.ofdm_ht.plcp_err) - - le32_to_cpu(priv->statistics.rx.ofdm_ht.plcp_err)); - - if ((combined_plcp_delta > 0) && - ((combined_plcp_delta * 100) / plcp_msec) > - priv->cfg->plcp_delta_threshold) { - /* - * if plcp_err exceed the threshold, the following - * data is printed in csv format: - * Text: plcp_err exceeded %d, - * Received ofdm.plcp_err, - * Current ofdm.plcp_err, - * Received ofdm_ht.plcp_err, - * Current ofdm_ht.plcp_err, - * combined_plcp_delta, - * plcp_msec - */ - IWL_DEBUG_RADIO(priv, PLCP_MSG, - priv->cfg->plcp_delta_threshold, - le32_to_cpu(pkt->u.stats.rx.ofdm.plcp_err), - le32_to_cpu(priv->statistics.rx.ofdm.plcp_err), - le32_to_cpu(pkt->u.stats.rx.ofdm_ht.plcp_err), - le32_to_cpu( - priv->statistics.rx.ofdm_ht.plcp_err), - combined_plcp_delta, plcp_msec); - - /* - * Reset the RF radio due to the high plcp - * error rate - */ - iwl_force_reset(priv, IWL_RF_RESET); - } - } - memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics)); set_bit(STATUS_STATISTICS, &priv->status); @@ -762,13 +638,11 @@ void iwl_reply_statistics(struct iwl_priv *priv, struct iwl_rx_packet *pkt = rxb_addr(rxb); if (le32_to_cpu(pkt->u.stats.flag) & UCODE_STATISTICS_CLEAR_MSK) { + memset(&priv->statistics, 0, + sizeof(struct iwl_notif_statistics)); #ifdef CONFIG_IWLWIFI_DEBUG memset(&priv->accum_statistics, 0, sizeof(struct iwl_notif_statistics)); - memset(&priv->delta_statistics, 0, - sizeof(struct iwl_notif_statistics)); - memset(&priv->max_delta, 0, - sizeof(struct iwl_notif_statistics)); #endif IWL_DEBUG_RX(priv, "Statistics have been cleared\n"); } diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-scan.c b/trunk/drivers/net/wireless/iwlwifi/iwl-scan.c index dd9ff2ed645a..fa1c89ba6459 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2009 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -192,17 +192,19 @@ static void iwl_rx_scan_results_notif(struct iwl_priv *priv, IWL_DEBUG_SCAN(priv, "Scan ch.res: " "%d [802.11%s] " "(TSF: 0x%08X:%08X) - %d " - "elapsed=%lu usec\n", + "elapsed=%lu usec (%dms since last)\n", notif->channel, notif->band ? "bg" : "a", le32_to_cpu(notif->tsf_high), le32_to_cpu(notif->tsf_low), le32_to_cpu(notif->statistics[0]), - le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf); + le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf, + jiffies_to_msecs(elapsed_jiffies + (priv->last_scan_jiffies, jiffies))); #endif - if (!priv->is_internal_short_scan) - priv->next_scan_jiffies = 0; + priv->last_scan_jiffies = jiffies; + priv->next_scan_jiffies = 0; } /* Service SCAN_COMPLETE_NOTIFICATION (0x84) */ @@ -248,9 +250,8 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv, goto reschedule; } - if (!priv->is_internal_short_scan) - priv->next_scan_jiffies = 0; - + priv->last_scan_jiffies = jiffies; + priv->next_scan_jiffies = 0; IWL_DEBUG_INFO(priv, "Setting scan to off\n"); clear_bit(STATUS_SCANNING, &priv->status); @@ -313,72 +314,6 @@ u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, } EXPORT_SYMBOL(iwl_get_passive_dwell_time); -static int iwl_get_single_channel_for_scan(struct iwl_priv *priv, - enum ieee80211_band band, - struct iwl_scan_channel *scan_ch) -{ - const struct ieee80211_supported_band *sband; - const struct iwl_channel_info *ch_info; - u16 passive_dwell = 0; - u16 active_dwell = 0; - int i, added = 0; - u16 channel = 0; - - sband = iwl_get_hw_mode(priv, band); - if (!sband) { - IWL_ERR(priv, "invalid band\n"); - return added; - } - - active_dwell = iwl_get_active_dwell_time(priv, band, 0); - passive_dwell = iwl_get_passive_dwell_time(priv, band); - - if (passive_dwell <= active_dwell) - passive_dwell = active_dwell + 1; - - /* only scan single channel, good enough to reset the RF */ - /* pick the first valid not in-use channel */ - if (band == IEEE80211_BAND_5GHZ) { - for (i = 14; i < priv->channel_count; i++) { - if (priv->channel_info[i].channel != - le16_to_cpu(priv->staging_rxon.channel)) { - channel = priv->channel_info[i].channel; - ch_info = iwl_get_channel_info(priv, - band, channel); - if (is_channel_valid(ch_info)) - break; - } - } - } else { - for (i = 0; i < 14; i++) { - if (priv->channel_info[i].channel != - le16_to_cpu(priv->staging_rxon.channel)) { - channel = - priv->channel_info[i].channel; - ch_info = iwl_get_channel_info(priv, - band, channel); - if (is_channel_valid(ch_info)) - break; - } - } - } - if (channel) { - scan_ch->channel = cpu_to_le16(channel); - scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE; - scan_ch->active_dwell = cpu_to_le16(active_dwell); - scan_ch->passive_dwell = cpu_to_le16(passive_dwell); - /* Set txpower levels to defaults */ - scan_ch->dsp_atten = 110; - if (band == IEEE80211_BAND_5GHZ) - scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3; - else - scan_ch->tx_gain = ((1 << 5) | (5 << 3)); - added++; - } else - IWL_ERR(priv, "no valid channel found\n"); - return added; -} - static int iwl_get_channels_for_scan(struct iwl_priv *priv, enum ieee80211_band band, u8 is_active, u8 n_probes, @@ -469,9 +404,23 @@ EXPORT_SYMBOL(iwl_init_scan_params); static int iwl_scan_initiate(struct iwl_priv *priv) { + if (!iwl_is_ready_rf(priv)) { + IWL_DEBUG_SCAN(priv, "Aborting scan due to not ready.\n"); + return -EIO; + } + + if (test_bit(STATUS_SCANNING, &priv->status)) { + IWL_DEBUG_SCAN(priv, "Scan already in progress.\n"); + return -EAGAIN; + } + + if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { + IWL_DEBUG_SCAN(priv, "Scan request while abort pending\n"); + return -EAGAIN; + } + IWL_DEBUG_INFO(priv, "Starting scan...\n"); set_bit(STATUS_SCANNING, &priv->status); - priv->is_internal_short_scan = false; priv->scan_start = jiffies; priv->scan_pass_start = priv->scan_start; @@ -500,18 +449,6 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw, goto out_unlock; } - if (test_bit(STATUS_SCANNING, &priv->status)) { - IWL_DEBUG_SCAN(priv, "Scan already in progress.\n"); - ret = -EAGAIN; - goto out_unlock; - } - - if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { - IWL_DEBUG_SCAN(priv, "Scan request while abort pending\n"); - ret = -EAGAIN; - goto out_unlock; - } - /* We don't schedule scan within next_scan_jiffies period. * Avoid scanning during possible EAPOL exchange, return * success immediately. @@ -524,6 +461,15 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw, goto out_unlock; } + /* if we just finished scan ask for delay */ + if (iwl_is_associated(priv) && priv->last_scan_jiffies && + time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN, jiffies)) { + IWL_DEBUG_SCAN(priv, "scan rejected: within previous scan period\n"); + queue_work(priv->workqueue, &priv->scan_completed); + ret = 0; + goto out_unlock; + } + priv->scan_bands = 0; for (i = 0; i < req->n_channels; i++) priv->scan_bands |= BIT(req->channels[i]->band); @@ -542,46 +488,6 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw, } EXPORT_SYMBOL(iwl_mac_hw_scan); -/* - * internal short scan, this function should only been called while associated. - * It will reset and tune the radio to prevent possible RF related problem - */ -int iwl_internal_short_hw_scan(struct iwl_priv *priv) -{ - int ret = 0; - - if (!iwl_is_ready_rf(priv)) { - ret = -EIO; - IWL_DEBUG_SCAN(priv, "not ready or exit pending\n"); - goto out; - } - if (test_bit(STATUS_SCANNING, &priv->status)) { - IWL_DEBUG_SCAN(priv, "Scan already in progress.\n"); - ret = -EAGAIN; - goto out; - } - if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { - IWL_DEBUG_SCAN(priv, "Scan request while abort pending\n"); - ret = -EAGAIN; - goto out; - } - - priv->scan_bands = 0; - if (priv->band == IEEE80211_BAND_5GHZ) - priv->scan_bands |= BIT(IEEE80211_BAND_5GHZ); - else - priv->scan_bands |= BIT(IEEE80211_BAND_2GHZ); - - IWL_DEBUG_SCAN(priv, "Start internal short scan...\n"); - set_bit(STATUS_SCANNING, &priv->status); - priv->is_internal_short_scan = true; - queue_work(priv->workqueue, &priv->request_scan); - -out: - return ret; -} -EXPORT_SYMBOL(iwl_internal_short_hw_scan); - #define IWL_SCAN_CHECK_WATCHDOG (7 * HZ) void iwl_bg_scan_check(struct work_struct *data) @@ -638,26 +544,14 @@ u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame, if (left < 0) return 0; *pos++ = WLAN_EID_SSID; - if (!priv->is_internal_short_scan && - priv->scan_request->n_ssids) { - struct cfg80211_ssid *ssid = - priv->scan_request->ssids; - - /* Broadcast if ssid_len is 0 */ - *pos++ = ssid->ssid_len; - memcpy(pos, ssid->ssid, ssid->ssid_len); - pos += ssid->ssid_len; - len += 2 + ssid->ssid_len; - } else { - *pos++ = 0; - len += 2; - } + *pos++ = 0; + + len += 2; if (WARN_ON(left < ie_len)) return len; - if (ies) - memcpy(pos, ies, ie_len); + memcpy(pos, ies, ie_len); len += ie_len; left -= ie_len; @@ -760,6 +654,7 @@ static void iwl_bg_request_scan(struct work_struct *data) unsigned long flags; IWL_DEBUG_INFO(priv, "Scanning while associated...\n"); + spin_lock_irqsave(&priv->lock, flags); interval = priv->beacon_int; spin_unlock_irqrestore(&priv->lock, flags); @@ -777,29 +672,21 @@ static void iwl_bg_request_scan(struct work_struct *data) scan_suspend_time, interval); } - if (priv->is_internal_short_scan) { - IWL_DEBUG_SCAN(priv, "Start internal passive scan.\n"); - } else if (priv->scan_request->n_ssids) { + if (priv->scan_request->n_ssids) { + int i, p = 0; IWL_DEBUG_SCAN(priv, "Kicking off active scan\n"); - /* - * The first SSID to scan is stuffed into the probe request - * template and the remaining ones are handled through the - * direct_scan array. - */ - if (priv->scan_request->n_ssids > 1) { - int i, p = 0; - for (i = 1; i < priv->scan_request->n_ssids; i++) { - if (!priv->scan_request->ssids[i].ssid_len) - continue; - scan->direct_scan[p].id = WLAN_EID_SSID; - scan->direct_scan[p].len = - priv->scan_request->ssids[i].ssid_len; - memcpy(scan->direct_scan[p].ssid, - priv->scan_request->ssids[i].ssid, - priv->scan_request->ssids[i].ssid_len); - n_probes++; - p++; - } + for (i = 0; i < priv->scan_request->n_ssids; i++) { + /* always does wildcard anyway */ + if (!priv->scan_request->ssids[i].ssid_len) + continue; + scan->direct_scan[p].id = WLAN_EID_SSID; + scan->direct_scan[p].len = + priv->scan_request->ssids[i].ssid_len; + memcpy(scan->direct_scan[p].ssid, + priv->scan_request->ssids[i].ssid, + priv->scan_request->ssids[i].ssid_len); + n_probes++; + p++; } is_active = true; } else @@ -866,38 +753,24 @@ static void iwl_bg_request_scan(struct work_struct *data) rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_SEL_POS; rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS; scan->rx_chain = cpu_to_le16(rx_chain); - if (!priv->is_internal_short_scan) { - cmd_len = iwl_fill_probe_req(priv, - (struct ieee80211_mgmt *)scan->data, - priv->scan_request->ie, - priv->scan_request->ie_len, - IWL_MAX_SCAN_SIZE - sizeof(*scan)); - } else { - cmd_len = iwl_fill_probe_req(priv, - (struct ieee80211_mgmt *)scan->data, - NULL, 0, - IWL_MAX_SCAN_SIZE - sizeof(*scan)); + cmd_len = iwl_fill_probe_req(priv, + (struct ieee80211_mgmt *)scan->data, + priv->scan_request->ie, + priv->scan_request->ie_len, + IWL_MAX_SCAN_SIZE - sizeof(*scan)); - } scan->tx_cmd.len = cpu_to_le16(cmd_len); + if (iwl_is_monitor_mode(priv)) scan->filter_flags = RXON_FILTER_PROMISC_MSK; scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK | RXON_FILTER_BCON_AWARE_MSK); - if (priv->is_internal_short_scan) { - scan->channel_count = - iwl_get_single_channel_for_scan(priv, band, - (void *)&scan->data[le16_to_cpu( - scan->tx_cmd.len)]); - } else { - scan->channel_count = - iwl_get_channels_for_scan(priv, band, - is_active, n_probes, - (void *)&scan->data[le16_to_cpu( - scan->tx_cmd.len)]); - } + scan->channel_count = + iwl_get_channels_for_scan(priv, band, is_active, n_probes, + (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); + if (scan->channel_count == 0) { IWL_DEBUG_SCAN(priv, "channel count %d\n", scan->channel_count); goto done; @@ -958,12 +831,7 @@ void iwl_bg_scan_completed(struct work_struct *work) cancel_delayed_work(&priv->scan_check); - if (!priv->is_internal_short_scan) - ieee80211_scan_completed(priv->hw, false); - else { - priv->is_internal_short_scan = false; - IWL_DEBUG_SCAN(priv, "internal short scan completed\n"); - } + ieee80211_scan_completed(priv->hw, false); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-spectrum.c b/trunk/drivers/net/wireless/iwlwifi/iwl-spectrum.c new file mode 100644 index 000000000000..1ea5cd345fe8 --- /dev/null +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-spectrum.c @@ -0,0 +1,198 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project, as well + * as portions of the ieee80211 subsystem header files. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "iwl-eeprom.h" +#include "iwl-dev.h" +#include "iwl-core.h" +#include "iwl-io.h" +#include "iwl-spectrum.h" + +#define BEACON_TIME_MASK_LOW 0x00FFFFFF +#define BEACON_TIME_MASK_HIGH 0xFF000000 +#define TIME_UNIT 1024 + +/* + * extended beacon time format + * time in usec will be changed into a 32-bit value in 8:24 format + * the high 1 byte is the beacon counts + * the lower 3 bytes is the time in usec within one beacon interval + */ + +/* TOOD: was used in sysfs debug interface need to add to mac */ +#if 0 +static u32 iwl_usecs_to_beacons(u32 usec, u32 beacon_interval) +{ + u32 quot; + u32 rem; + u32 interval = beacon_interval * 1024; + + if (!interval || !usec) + return 0; + + quot = (usec / interval) & (BEACON_TIME_MASK_HIGH >> 24); + rem = (usec % interval) & BEACON_TIME_MASK_LOW; + + return (quot << 24) + rem; +} + +/* base is usually what we get from ucode with each received frame, + * the same as HW timer counter counting down + */ + +static __le32 iwl_add_beacon_time(u32 base, u32 addon, u32 beacon_interval) +{ + u32 base_low = base & BEACON_TIME_MASK_LOW; + u32 addon_low = addon & BEACON_TIME_MASK_LOW; + u32 interval = beacon_interval * TIME_UNIT; + u32 res = (base & BEACON_TIME_MASK_HIGH) + + (addon & BEACON_TIME_MASK_HIGH); + + if (base_low > addon_low) + res += base_low - addon_low; + else if (base_low < addon_low) { + res += interval + base_low - addon_low; + res += (1 << 24); + } else + res += (1 << 24); + + return cpu_to_le32(res); +} +static int iwl_get_measurement(struct iwl_priv *priv, + struct ieee80211_measurement_params *params, + u8 type) +{ + struct iwl4965_spectrum_cmd spectrum; + struct iwl_rx_packet *res; + struct iwl_host_cmd cmd = { + .id = REPLY_SPECTRUM_MEASUREMENT_CMD, + .data = (void *)&spectrum, + .meta.flags = CMD_WANT_SKB, + }; + u32 add_time = le64_to_cpu(params->start_time); + int rc; + int spectrum_resp_status; + int duration = le16_to_cpu(params->duration); + + if (iwl_is_associated(priv)) + add_time = + iwl_usecs_to_beacons( + le64_to_cpu(params->start_time) - priv->last_tsf, + le16_to_cpu(priv->rxon_timing.beacon_interval)); + + memset(&spectrum, 0, sizeof(spectrum)); + + spectrum.channel_count = cpu_to_le16(1); + spectrum.flags = + RXON_FLG_TSF2HOST_MSK | RXON_FLG_ANT_A_MSK | RXON_FLG_DIS_DIV_MSK; + spectrum.filter_flags = MEASUREMENT_FILTER_FLAG; + cmd.len = sizeof(spectrum); + spectrum.len = cpu_to_le16(cmd.len - sizeof(spectrum.len)); + + if (iwl_is_associated(priv)) + spectrum.start_time = + iwl_add_beacon_time(priv->last_beacon_time, + add_time, + le16_to_cpu(priv->rxon_timing.beacon_interval)); + else + spectrum.start_time = 0; + + spectrum.channels[0].duration = cpu_to_le32(duration * TIME_UNIT); + spectrum.channels[0].channel = params->channel; + spectrum.channels[0].type = type; + if (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK) + spectrum.flags |= RXON_FLG_BAND_24G_MSK | + RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK; + + rc = iwl_send_cmd_sync(priv, &cmd); + if (rc) + return rc; + + res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; + if (res->hdr.flags & IWL_CMD_FAILED_MSK) { + IWL_ERR(priv, "Bad return from REPLY_RX_ON_ASSOC command\n"); + rc = -EIO; + } + + spectrum_resp_status = le16_to_cpu(res->u.spectrum.status); + switch (spectrum_resp_status) { + case 0: /* Command will be handled */ + if (res->u.spectrum.id != 0xff) { + IWL_DEBUG_INFO(priv, + "Replaced existing measurement: %d\n", + res->u.spectrum.id); + priv->measurement_status &= ~MEASUREMENT_READY; + } + priv->measurement_status |= MEASUREMENT_ACTIVE; + rc = 0; + break; + + case 1: /* Command will not be handled */ + rc = -EAGAIN; + break; + } + + dev_kfree_skb_any(cmd.meta.u.skb); + + return rc; +} +#endif + +static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif); + + if (!report->state) { + IWL_DEBUG_11H(priv, + "Spectrum Measure Notification: Start\n"); + return; + } + + memcpy(&priv->measure_report, report, sizeof(*report)); + priv->measurement_status |= MEASUREMENT_READY; +} + +void iwl_setup_spectrum_handlers(struct iwl_priv *priv) +{ + priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] = + iwl_rx_spectrum_measure_notif; +} +EXPORT_SYMBOL(iwl_setup_spectrum_handlers); diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-spectrum.h b/trunk/drivers/net/wireless/iwlwifi/iwl-spectrum.h index af6babee2891..a77c1e619062 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-spectrum.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-spectrum.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ieee80211 subsystem header files. * diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-sta.c b/trunk/drivers/net/wireless/iwlwifi/iwl-sta.c index 4a6686fa6b36..90fbdb25399e 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -80,103 +80,46 @@ int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) } EXPORT_SYMBOL(iwl_get_ra_sta_id); -/* priv->sta_lock must be held */ static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id) { + unsigned long flags; + + spin_lock_irqsave(&priv->sta_lock, flags); if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) - IWL_ERR(priv, "ACTIVATE a non DRIVER active station id %u addr %pM\n", - sta_id, priv->stations[sta_id].sta.sta.addr); + IWL_ERR(priv, "ACTIVATE a non DRIVER active station %d\n", + sta_id); - if (priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE) { - IWL_DEBUG_ASSOC(priv, - "STA id %u addr %pM already present in uCode (according to driver)\n", - sta_id, priv->stations[sta_id].sta.sta.addr); - } else { - priv->stations[sta_id].used |= IWL_STA_UCODE_ACTIVE; - IWL_DEBUG_ASSOC(priv, "Added STA id %u addr %pM to uCode\n", - sta_id, priv->stations[sta_id].sta.sta.addr); - } + priv->stations[sta_id].used |= IWL_STA_UCODE_ACTIVE; + IWL_DEBUG_ASSOC(priv, "Added STA to Ucode: %pM\n", + priv->stations[sta_id].sta.sta.addr); + + spin_unlock_irqrestore(&priv->sta_lock, flags); } -static void iwl_process_add_sta_resp(struct iwl_priv *priv, - struct iwl_addsta_cmd *addsta, - struct iwl_rx_packet *pkt, - bool sync) +static void iwl_add_sta_callback(struct iwl_priv *priv, + struct iwl_device_cmd *cmd, + struct iwl_rx_packet *pkt) { + struct iwl_addsta_cmd *addsta = + (struct iwl_addsta_cmd *)cmd->cmd.payload; u8 sta_id = addsta->sta.sta_id; - unsigned long flags; if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n", - pkt->hdr.flags); + pkt->hdr.flags); return; } - IWL_DEBUG_INFO(priv, "Processing response for adding station %u\n", - sta_id); - - spin_lock_irqsave(&priv->sta_lock, flags); - switch (pkt->u.add_sta.status) { case ADD_STA_SUCCESS_MSK: - IWL_DEBUG_INFO(priv, "REPLY_ADD_STA PASSED\n"); iwl_sta_ucode_activate(priv, sta_id); - break; - case ADD_STA_NO_ROOM_IN_TABLE: - IWL_ERR(priv, "Adding station %d failed, no room in table.\n", - sta_id); - break; - case ADD_STA_NO_BLOCK_ACK_RESOURCE: - IWL_ERR(priv, "Adding station %d failed, no block ack resource.\n", - sta_id); - break; - case ADD_STA_MODIFY_NON_EXIST_STA: - IWL_ERR(priv, "Attempting to modify non-existing station %d \n", - sta_id); - break; + /* fall through */ default: - IWL_DEBUG_ASSOC(priv, "Received REPLY_ADD_STA:(0x%08X)\n", - pkt->u.add_sta.status); + IWL_DEBUG_HC(priv, "Received REPLY_ADD_STA:(0x%08X)\n", + pkt->u.add_sta.status); break; } - - IWL_DEBUG_INFO(priv, "%s station id %u addr %pM\n", - priv->stations[sta_id].sta.mode == - STA_CONTROL_MODIFY_MSK ? "Modified" : "Added", - sta_id, priv->stations[sta_id].sta.sta.addr); - - /* - * XXX: The MAC address in the command buffer is often changed from - * the original sent to the device. That is, the MAC address - * written to the command buffer often is not the same MAC adress - * read from the command buffer when the command returns. This - * issue has not yet been resolved and this debugging is left to - * observe the problem. - */ - IWL_DEBUG_INFO(priv, "%s station according to cmd buffer %pM\n", - priv->stations[sta_id].sta.mode == - STA_CONTROL_MODIFY_MSK ? "Modified" : "Added", - addsta->sta.addr); - - /* - * Determine if we wanted to modify or add a station, - * if adding a station succeeded we have some more initialization - * to do when using station notification. TODO - */ - - spin_unlock_irqrestore(&priv->sta_lock, flags); -} - -static void iwl_add_sta_callback(struct iwl_priv *priv, - struct iwl_device_cmd *cmd, - struct iwl_rx_packet *pkt) -{ - struct iwl_addsta_cmd *addsta = - (struct iwl_addsta_cmd *)cmd->cmd.payload; - - iwl_process_add_sta_resp(priv, addsta, pkt, false); - } int iwl_send_add_sta(struct iwl_priv *priv, @@ -202,9 +145,24 @@ int iwl_send_add_sta(struct iwl_priv *priv, if (ret || (flags & CMD_ASYNC)) return ret; + pkt = (struct iwl_rx_packet *)cmd.reply_page; + if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { + IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n", + pkt->hdr.flags); + ret = -EIO; + } + if (ret == 0) { - pkt = (struct iwl_rx_packet *)cmd.reply_page; - iwl_process_add_sta_resp(priv, sta, pkt, true); + switch (pkt->u.add_sta.status) { + case ADD_STA_SUCCESS_MSK: + iwl_sta_ucode_activate(priv, sta->sta.sta_id); + IWL_DEBUG_INFO(priv, "REPLY_ADD_STA PASSED\n"); + break; + default: + ret = -EIO; + IWL_WARN(priv, "REPLY_ADD_STA failed\n"); + break; + } } iwl_free_pages(priv, cmd.reply_page); @@ -1045,19 +1003,24 @@ int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap) struct ieee80211_sta_ht_cap *cur_ht_config = NULL; u8 sta_id; + /* Add station to device's station table */ + /* - * Set HT capabilities. It is ok to set this struct even if not using - * HT config: the priv->current_ht_config.is_ht flag will just be false + * XXX: This check is definitely not correct, if we're an AP + * it'll always be false which is not what we want, but + * it doesn't look like iwlagn is prepared to be an HT + * AP anyway. */ - rcu_read_lock(); - sta = ieee80211_find_sta(priv->vif, addr); - if (sta) { - memcpy(&ht_config, &sta->ht_cap, sizeof(ht_config)); - cur_ht_config = &ht_config; + if (priv->current_ht_config.is_ht) { + rcu_read_lock(); + sta = ieee80211_find_sta(priv->vif, addr); + if (sta) { + memcpy(&ht_config, &sta->ht_cap, sizeof(ht_config)); + cur_ht_config = &ht_config; + } + rcu_read_unlock(); } - rcu_read_unlock(); - /* Add station to device's station table */ sta_id = iwl_add_station(priv, addr, is_ap, CMD_SYNC, cur_ht_config); /* Set up default rate scaling table in device's station table */ @@ -1122,7 +1085,6 @@ static void iwl_sta_init_bcast_lq(struct iwl_priv *priv) */ void iwl_add_bcast_station(struct iwl_priv *priv) { - IWL_DEBUG_INFO(priv, "Adding broadcast station to station table\n"); iwl_add_station(priv, iwl_bcast_addr, false, CMD_SYNC, NULL); /* Set up default rate scaling table in device's station table */ @@ -1130,16 +1092,6 @@ void iwl_add_bcast_station(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_add_bcast_station); -/** - * iwl3945_add_bcast_station - add broadcast station into station table. - */ -void iwl3945_add_bcast_station(struct iwl_priv *priv) -{ - IWL_DEBUG_INFO(priv, "Adding broadcast station to station table\n"); - iwl_add_station(priv, iwl_bcast_addr, false, CMD_SYNC, NULL); -} -EXPORT_SYMBOL(iwl3945_add_bcast_station); - /** * iwl_get_sta_id - Find station's index within station table * diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-sta.h b/trunk/drivers/net/wireless/iwlwifi/iwl-sta.h index 2dc35fe28f56..8d052de2d405 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-sta.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-sta.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -53,7 +53,6 @@ void iwl_update_tkip_key(struct iwl_priv *priv, int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap); void iwl_add_bcast_station(struct iwl_priv *priv); -void iwl3945_add_bcast_station(struct iwl_priv *priv); int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, bool is_ap); void iwl_clear_stations_table(struct iwl_priv *priv); int iwl_get_free_ucode_key_index(struct iwl_priv *priv); diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-tx.c b/trunk/drivers/net/wireless/iwlwifi/iwl-tx.c index 10701b8eef23..066491fc75f2 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -60,8 +60,7 @@ static const u16 default_tid_to_tx_fifo[] = { static inline int iwl_alloc_dma_ptr(struct iwl_priv *priv, struct iwl_dma_ptr *ptr, size_t size) { - ptr->addr = dma_alloc_coherent(&priv->pci_dev->dev, size, &ptr->dma, - GFP_KERNEL); + ptr->addr = pci_alloc_consistent(priv->pci_dev, size, &ptr->dma); if (!ptr->addr) return -ENOMEM; ptr->size = size; @@ -74,20 +73,21 @@ static inline void iwl_free_dma_ptr(struct iwl_priv *priv, if (unlikely(!ptr->addr)) return; - dma_free_coherent(&priv->pci_dev->dev, ptr->size, ptr->addr, ptr->dma); + pci_free_consistent(priv->pci_dev, ptr->size, ptr->addr, ptr->dma); memset(ptr, 0, sizeof(*ptr)); } /** * iwl_txq_update_write_ptr - Send new write index to hardware */ -void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq) +int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq) { u32 reg = 0; + int ret = 0; int txq_id = txq->q.id; if (txq->need_update == 0) - return; + return ret; /* if we're trying to save power */ if (test_bit(STATUS_POWER_PMI, &priv->status)) { @@ -101,7 +101,7 @@ void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq) txq_id, reg); iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - return; + return ret; } iwl_write_direct32(priv, HBUS_TARG_WRPTR, @@ -114,6 +114,8 @@ void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq) txq->q.write_ptr | (txq_id << 8)); txq->need_update = 0; + + return ret; } EXPORT_SYMBOL(iwl_txq_update_write_ptr); @@ -144,7 +146,7 @@ void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id) { struct iwl_tx_queue *txq = &priv->txq[txq_id]; struct iwl_queue *q = &txq->q; - struct device *dev = &priv->pci_dev->dev; + struct pci_dev *dev = priv->pci_dev; int i; if (q->n_bd == 0) @@ -161,8 +163,8 @@ void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id) /* De-alloc circular buffer of TFDs */ if (txq->q.n_bd) - dma_free_coherent(dev, priv->hw_params.tfd_size * - txq->q.n_bd, txq->tfds, txq->q.dma_addr); + pci_free_consistent(dev, priv->hw_params.tfd_size * + txq->q.n_bd, txq->tfds, txq->q.dma_addr); /* De-alloc array of per-TFD driver data */ kfree(txq->txb); @@ -191,7 +193,7 @@ void iwl_cmd_queue_free(struct iwl_priv *priv) { struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM]; struct iwl_queue *q = &txq->q; - struct device *dev = &priv->pci_dev->dev; + struct pci_dev *dev = priv->pci_dev; int i; if (q->n_bd == 0) @@ -203,8 +205,8 @@ void iwl_cmd_queue_free(struct iwl_priv *priv) /* De-alloc circular buffer of TFDs */ if (txq->q.n_bd) - dma_free_coherent(dev, priv->hw_params.tfd_size * txq->q.n_bd, - txq->tfds, txq->q.dma_addr); + pci_free_consistent(dev, priv->hw_params.tfd_size * + txq->q.n_bd, txq->tfds, txq->q.dma_addr); /* deallocate arrays */ kfree(txq->cmd); @@ -295,7 +297,7 @@ static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q, static int iwl_tx_queue_alloc(struct iwl_priv *priv, struct iwl_tx_queue *txq, u32 id) { - struct device *dev = &priv->pci_dev->dev; + struct pci_dev *dev = priv->pci_dev; size_t tfd_sz = priv->hw_params.tfd_size * TFD_QUEUE_SIZE_MAX; /* Driver private data, only for Tx (not command) queues, @@ -314,8 +316,8 @@ static int iwl_tx_queue_alloc(struct iwl_priv *priv, /* Circular buffer of transmit frame descriptors (TFDs), * shared with device */ - txq->tfds = dma_alloc_coherent(dev, tfd_sz, &txq->q.dma_addr, - GFP_KERNEL); + txq->tfds = pci_alloc_consistent(dev, tfd_sz, &txq->q.dma_addr); + if (!txq->tfds) { IWL_ERR(priv, "pci_alloc_consistent(%zd) failed\n", tfd_sz); goto error; @@ -364,7 +366,7 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq, for (i = 0; i < actual_slots; i++) { /* only happens for cmd queue */ if (i == slots_num) - len += IWL_MAX_SCAN_SIZE; + len = IWL_MAX_CMD_SIZE; txq->cmd[i] = kmalloc(len, GFP_KERNEL); if (!txq->cmd[i]) @@ -743,6 +745,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) u8 tid = 0; u8 *qc = NULL; unsigned long flags; + int ret; spin_lock_irqsave(&priv->lock, flags); if (iwl_is_rfkill(priv)) { @@ -817,10 +820,8 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) hdr->seq_ctrl |= cpu_to_le16(seq_number); seq_number += 0x10; /* aggregation is on for this */ - if (info->flags & IEEE80211_TX_CTL_AMPDU && - priv->stations[sta_id].tid[tid].agg.state == IWL_AGG_ON) { + if (info->flags & IEEE80211_TX_CTL_AMPDU) txq_id = priv->stations[sta_id].tid[tid].agg.txq_id; - } } txq = &priv->txq[txq_id]; @@ -962,7 +963,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) /* Tell device the write index *just past* this latest filled TFD */ q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); - iwl_txq_update_write_ptr(priv, txq); + ret = iwl_txq_update_write_ptr(priv, txq); spin_unlock_irqrestore(&priv->lock, flags); /* @@ -976,6 +977,9 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) if (sta_priv && sta_priv->client) atomic_inc(&sta_priv->pending_frames); + if (ret) + return ret; + if ((iwl_queue_space(q) < q->high_mark) && priv->mac80211_registered) { if (wait_write_ptr) { spin_lock_irqsave(&priv->lock, flags); @@ -1014,7 +1018,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) struct iwl_cmd_meta *out_meta; dma_addr_t phys_addr; unsigned long flags; - int len; + int len, ret; u32 idx; u16 fix_size; @@ -1023,9 +1027,12 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) /* If any of the command structures end up being larger than * the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then - * we will need to increase the size of the TFD entries */ + * we will need to increase the size of the TFD entries + * Also, check to see if command buffer should not exceed the size + * of device_cmd and max_cmd_size. */ BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) && !(cmd->flags & CMD_SIZE_HUGE)); + BUG_ON(fix_size > IWL_MAX_CMD_SIZE); if (iwl_is_rfkill(priv) || iwl_is_ctkill(priv)) { IWL_WARN(priv, "Not sending command - %s KILL\n", @@ -1069,8 +1076,8 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) if (cmd->flags & CMD_SIZE_HUGE) out_cmd->hdr.sequence |= SEQ_HUGE_FRAME; len = sizeof(struct iwl_device_cmd); - len += (idx == TFD_CMD_SLOTS) ? IWL_MAX_SCAN_SIZE : 0; - + if (idx == TFD_CMD_SLOTS) + len = IWL_MAX_CMD_SIZE; #ifdef CONFIG_IWLWIFI_DEBUG switch (out_cmd->hdr.cmd) { @@ -1111,10 +1118,10 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) /* Increment and update queue's write index */ q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); - iwl_txq_update_write_ptr(priv, txq); + ret = iwl_txq_update_write_ptr(priv, txq); spin_unlock_irqrestore(&priv->hcmd_lock, flags); - return idx; + return ret ? ret : idx; } static void iwl_tx_status(struct iwl_priv *priv, struct sk_buff *skb) @@ -1256,8 +1263,6 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) if (!(meta->flags & CMD_ASYNC)) { clear_bit(STATUS_HCMD_ACTIVE, &priv->status); - IWL_DEBUG_INFO(priv, "Clearing HCMD_ACTIVE for command %s \n", - get_cmd_string(cmd->hdr.cmd)); wake_up_interruptible(&priv->wait_command_queue); } } @@ -1344,7 +1349,7 @@ int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid) { int tx_fifo_id, txq_id, sta_id, ssn = -1; struct iwl_tid_data *tid_data; - int write_ptr, read_ptr; + int ret, write_ptr, read_ptr; unsigned long flags; if (!ra) { @@ -1396,17 +1401,13 @@ int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid) priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF; spin_lock_irqsave(&priv->lock, flags); - /* - * the only reason this call can fail is queue number out of range, - * which can happen if uCode is reloaded and all the station - * information are lost. if it is outside the range, there is no need - * to deactivate the uCode queue, just return "success" to allow - * mac80211 to clean up it own data. - */ - priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, ssn, + ret = priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, ssn, tx_fifo_id); spin_unlock_irqrestore(&priv->lock, flags); + if (ret) + return ret; + ieee80211_stop_tx_ba_cb_irqsafe(priv->vif, ra, tid); return 0; diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl3945-base.c b/trunk/drivers/net/wireless/iwlwifi/iwl3945-base.c index 54daa38ecba3..f8e4e4b18d02 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -53,10 +53,9 @@ #include "iwl-commands.h" #include "iwl-sta.h" #include "iwl-3945.h" -#include "iwl-core.h" #include "iwl-helpers.h" +#include "iwl-core.h" #include "iwl-dev.h" -#include "iwl-spectrum.h" /* * module name, copyright, version, etc. @@ -71,13 +70,14 @@ #define VD #endif -/* - * add "s" to indicate spectrum measurement included. - * we add it here to be consistent with previous releases in which - * this was configurable. - */ -#define DRV_VERSION IWLWIFI_VERSION VD "s" -#define DRV_COPYRIGHT "Copyright(c) 2003-2010 Intel Corporation" +#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT +#define VS "s" +#else +#define VS +#endif + +#define DRV_VERSION IWLWIFI_VERSION VD VS +#define DRV_COPYRIGHT "Copyright(c) 2003-2009 Intel Corporation" #define DRV_AUTHOR "" MODULE_DESCRIPTION(DRV_DESCRIPTION); @@ -352,10 +352,10 @@ static int iwl3945_send_beacon_cmd(struct iwl_priv *priv) static void iwl3945_unset_hw_params(struct iwl_priv *priv) { if (priv->shared_virt) - dma_free_coherent(&priv->pci_dev->dev, - sizeof(struct iwl3945_shared), - priv->shared_virt, - priv->shared_phys); + pci_free_consistent(priv->pci_dev, + sizeof(struct iwl3945_shared), + priv->shared_virt, + priv->shared_phys); } static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv, @@ -478,6 +478,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) u8 wait_write_ptr = 0; u8 *qc = NULL; unsigned long flags; + int rc; spin_lock_irqsave(&priv->lock, flags); if (iwl_is_rfkill(priv)) { @@ -662,9 +663,12 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) /* Tell device the write index *just past* this latest filled TFD */ q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); - iwl_txq_update_write_ptr(priv, txq); + rc = iwl_txq_update_write_ptr(priv, txq); spin_unlock_irqrestore(&priv->lock, flags); + if (rc) + return rc; + if ((iwl_queue_space(q) < q->high_mark) && priv->mac80211_registered) { if (wait_write_ptr) { @@ -685,6 +689,10 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) return -1; } +#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT + +#include "iwl-spectrum.h" + #define BEACON_TIME_MASK_LOW 0x00FFFFFF #define BEACON_TIME_MASK_HIGH 0xFF000000 #define TIME_UNIT 1024 @@ -811,6 +819,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv, return rc; } +#endif static void iwl3945_rx_reply_alive(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) @@ -953,8 +962,6 @@ static void iwl3945_setup_rx_handlers(struct iwl_priv *priv) priv->rx_handlers[REPLY_ADD_STA] = iwl3945_rx_reply_add_sta; priv->rx_handlers[REPLY_ERROR] = iwl_rx_reply_error; priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa; - priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] = - iwl_rx_spectrum_measure_notif; priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl_rx_pm_sleep_notif; priv->rx_handlers[PM_DEBUG_STATISTIC_NOTIFIC] = iwl_rx_pm_debug_statistics_notif; @@ -968,6 +975,7 @@ static void iwl3945_setup_rx_handlers(struct iwl_priv *priv) priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl3945_hw_rx_statistics; priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl3945_hw_rx_statistics; + iwl_setup_spectrum_handlers(priv); iwl_setup_rx_scan_handlers(priv); priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl3945_rx_card_state_notif; @@ -1059,13 +1067,13 @@ static inline __le32 iwl3945_dma_addr2rbd_ptr(struct iwl_priv *priv, * also updates the memory address in the firmware to reference the new * target buffer. */ -static void iwl3945_rx_queue_restock(struct iwl_priv *priv) +static int iwl3945_rx_queue_restock(struct iwl_priv *priv) { struct iwl_rx_queue *rxq = &priv->rxq; struct list_head *element; struct iwl_rx_mem_buffer *rxb; unsigned long flags; - int write; + int write, rc; spin_lock_irqsave(&rxq->lock, flags); write = rxq->write & ~0x7; @@ -1095,8 +1103,12 @@ static void iwl3945_rx_queue_restock(struct iwl_priv *priv) spin_lock_irqsave(&rxq->lock, flags); rxq->need_update = 1; spin_unlock_irqrestore(&rxq->lock, flags); - iwl_rx_queue_update_write_ptr(priv, rxq); + rc = iwl_rx_queue_update_write_ptr(priv, rxq); + if (rc) + return rc; } + + return 0; } /** @@ -1241,10 +1253,10 @@ static void iwl3945_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rx } } - dma_free_coherent(&priv->pci_dev->dev, 4 * RX_QUEUE_SIZE, rxq->bd, - rxq->dma_addr); - dma_free_coherent(&priv->pci_dev->dev, sizeof(struct iwl_rb_status), - rxq->rb_stts, rxq->rb_stts_dma); + pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd, + rxq->dma_addr); + pci_free_consistent(priv->pci_dev, sizeof(struct iwl_rb_status), + rxq->rb_stts, rxq->rb_stts_dma); rxq->bd = NULL; rxq->rb_stts = NULL; } @@ -1506,9 +1518,8 @@ void iwl3945_dump_nic_error_log(struct iwl_priv *priv) * iwl3945_print_event_log - Dump error event log to syslog * */ -static int iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx, - u32 num_events, u32 mode, - int pos, char **buf, size_t bufsz) +static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx, + u32 num_events, u32 mode) { u32 i; u32 base; /* SRAM byte address of event log header */ @@ -1518,7 +1529,7 @@ static int iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx, unsigned long reg_flags; if (num_events == 0) - return pos; + return; base = le32_to_cpu(priv->card_alive.log_event_table_ptr); @@ -1544,43 +1555,26 @@ static int iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx, time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); if (mode == 0) { /* data, ev */ - if (bufsz) { - pos += scnprintf(*buf + pos, bufsz - pos, - "0x%08x:%04u\n", - time, ev); - } else { - IWL_ERR(priv, "0x%08x\t%04u\n", time, ev); - trace_iwlwifi_dev_ucode_event(priv, 0, - time, ev); - } + IWL_ERR(priv, "0x%08x\t%04u\n", time, ev); + trace_iwlwifi_dev_ucode_event(priv, 0, time, ev); } else { data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); - if (bufsz) { - pos += scnprintf(*buf + pos, bufsz - pos, - "%010u:0x%08x:%04u\n", - time, data, ev); - } else { - IWL_ERR(priv, "%010u\t0x%08x\t%04u\n", - time, data, ev); - trace_iwlwifi_dev_ucode_event(priv, time, - data, ev); - } + IWL_ERR(priv, "%010u\t0x%08x\t%04u\n", time, data, ev); + trace_iwlwifi_dev_ucode_event(priv, time, data, ev); } } /* Allow device to power down */ iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->reg_lock, reg_flags); - return pos; } /** * iwl3945_print_last_event_logs - Dump the newest # of event log to syslog */ -static int iwl3945_print_last_event_logs(struct iwl_priv *priv, u32 capacity, +static void iwl3945_print_last_event_logs(struct iwl_priv *priv, u32 capacity, u32 num_wraps, u32 next_entry, - u32 size, u32 mode, - int pos, char **buf, size_t bufsz) + u32 size, u32 mode) { /* * display the newest DEFAULT_LOG_ENTRIES entries @@ -1588,28 +1582,21 @@ static int iwl3945_print_last_event_logs(struct iwl_priv *priv, u32 capacity, */ if (num_wraps) { if (next_entry < size) { - pos = iwl3945_print_event_log(priv, - capacity - (size - next_entry), - size - next_entry, mode, - pos, buf, bufsz); - pos = iwl3945_print_event_log(priv, 0, - next_entry, mode, - pos, buf, bufsz); + iwl3945_print_event_log(priv, + capacity - (size - next_entry), + size - next_entry, mode); + iwl3945_print_event_log(priv, 0, + next_entry, mode); } else - pos = iwl3945_print_event_log(priv, next_entry - size, - size, mode, - pos, buf, bufsz); + iwl3945_print_event_log(priv, next_entry - size, + size, mode); } else { if (next_entry < size) - pos = iwl3945_print_event_log(priv, 0, - next_entry, mode, - pos, buf, bufsz); + iwl3945_print_event_log(priv, 0, next_entry, mode); else - pos = iwl3945_print_event_log(priv, next_entry - size, - size, mode, - pos, buf, bufsz); + iwl3945_print_event_log(priv, next_entry - size, + size, mode); } - return pos; } /* For sanity check only. Actual size is determined by uCode, typ. 512 */ @@ -1617,8 +1604,7 @@ static int iwl3945_print_last_event_logs(struct iwl_priv *priv, u32 capacity, #define DEFAULT_IWL3945_DUMP_EVENT_LOG_ENTRIES (20) -int iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log, - char **buf, bool display) +void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log) { u32 base; /* SRAM byte address of event log header */ u32 capacity; /* event log capacity in # entries */ @@ -1626,13 +1612,11 @@ int iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log, u32 num_wraps; /* # times uCode wrapped to top of log */ u32 next_entry; /* index of next entry to be written by uCode */ u32 size; /* # entries that we'll print */ - int pos = 0; - size_t bufsz = 0; base = le32_to_cpu(priv->card_alive.log_event_table_ptr); if (!iwl3945_hw_valid_rtc_data_addr(base)) { IWL_ERR(priv, "Invalid event log pointer 0x%08X\n", base); - return -EINVAL; + return; } /* event log header */ @@ -1658,7 +1642,7 @@ int iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log, /* bail out if nothing in log */ if (size == 0) { IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n"); - return pos; + return; } #ifdef CONFIG_IWLWIFI_DEBUG @@ -1674,38 +1658,25 @@ int iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log, size); #ifdef CONFIG_IWLWIFI_DEBUG - if (display) { - if (full_log) - bufsz = capacity * 48; - else - bufsz = size * 48; - *buf = kmalloc(bufsz, GFP_KERNEL); - if (!*buf) - return -ENOMEM; - } if ((iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) || full_log) { /* if uCode has wrapped back to top of log, * start at the oldest entry, * i.e the next one that uCode would fill. */ if (num_wraps) - pos = iwl3945_print_event_log(priv, next_entry, - capacity - next_entry, mode, - pos, buf, bufsz); + iwl3945_print_event_log(priv, next_entry, + capacity - next_entry, mode); /* (then/else) start at top of log */ - pos = iwl3945_print_event_log(priv, 0, next_entry, mode, - pos, buf, bufsz); + iwl3945_print_event_log(priv, 0, next_entry, mode); } else - pos = iwl3945_print_last_event_logs(priv, capacity, num_wraps, - next_entry, size, mode, - pos, buf, bufsz); + iwl3945_print_last_event_logs(priv, capacity, num_wraps, + next_entry, size, mode); #else - pos = iwl3945_print_last_event_logs(priv, capacity, num_wraps, - next_entry, size, mode, - pos, buf, bufsz); + iwl3945_print_last_event_logs(priv, capacity, num_wraps, + next_entry, size, mode); #endif - return pos; + } static void iwl3945_irq_tasklet(struct iwl_priv *priv) @@ -3025,6 +2996,18 @@ static void iwl3945_bg_request_scan(struct work_struct *data) mutex_unlock(&priv->mutex); } +static void iwl3945_bg_up(struct work_struct *data) +{ + struct iwl_priv *priv = container_of(data, struct iwl_priv, up); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + __iwl3945_up(priv); + mutex_unlock(&priv->mutex); +} + static void iwl3945_bg_restart(struct work_struct *data) { struct iwl_priv *priv = container_of(data, struct iwl_priv, restart); @@ -3041,13 +3024,7 @@ static void iwl3945_bg_restart(struct work_struct *data) ieee80211_restart_hw(priv->hw); } else { iwl3945_down(priv); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - mutex_lock(&priv->mutex); - __iwl3945_up(priv); - mutex_unlock(&priv->mutex); + queue_work(priv->workqueue, &priv->up); } } @@ -3551,6 +3528,8 @@ static ssize_t store_filter_flags(struct device *d, static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags, store_filter_flags); +#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT + static ssize_t show_measurement(struct device *d, struct device_attribute *attr, char *buf) { @@ -3620,6 +3599,7 @@ static ssize_t store_measurement(struct device *d, static DEVICE_ATTR(measurement, S_IRUSR | S_IWUSR, show_measurement, store_measurement); +#endif /* CONFIG_IWL3945_SPECTRUM_MEASUREMENT */ static ssize_t store_retry_rate(struct device *d, struct device_attribute *attr, @@ -3768,6 +3748,7 @@ static void iwl3945_setup_deferred_work(struct iwl_priv *priv) init_waitqueue_head(&priv->wait_command_queue); + INIT_WORK(&priv->up, iwl3945_bg_up); INIT_WORK(&priv->restart, iwl3945_bg_restart); INIT_WORK(&priv->rx_replenish, iwl3945_bg_rx_replenish); INIT_WORK(&priv->beacon_update, iwl3945_bg_beacon_update); @@ -3801,7 +3782,9 @@ static struct attribute *iwl3945_sysfs_entries[] = { &dev_attr_dump_errors.attr, &dev_attr_flags.attr, &dev_attr_filter_flags.attr, +#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT &dev_attr_measurement.attr, +#endif &dev_attr_retry_rate.attr, &dev_attr_statistics.attr, &dev_attr_status.attr, @@ -3827,6 +3810,7 @@ static struct ieee80211_ops iwl3945_hw_ops = { .config = iwl_mac_config, .configure_filter = iwl_configure_filter, .set_key = iwl3945_mac_set_key, + .get_tx_stats = iwl_mac_get_tx_stats, .conf_tx = iwl_mac_conf_tx, .reset_tsf = iwl_mac_reset_tsf, .bss_info_changed = iwl_bss_info_changed, @@ -3847,7 +3831,6 @@ static int iwl3945_init_drv(struct iwl_priv *priv) INIT_LIST_HEAD(&priv->free_frames); mutex_init(&priv->mutex); - mutex_init(&priv->sync_cmd_mutex); /* Clear the driver's (not device's) station table */ iwl_clear_stations_table(priv); @@ -3857,7 +3840,6 @@ static int iwl3945_init_drv(struct iwl_priv *priv) priv->band = IEEE80211_BAND_2GHZ; priv->iw_mode = NL80211_IFTYPE_STATION; - priv->missed_beacon_threshold = IWL_MISSED_BEACON_THRESHOLD_DEF; iwl_reset_qos(priv); @@ -4040,13 +4022,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e spin_lock_init(&priv->reg_lock); spin_lock_init(&priv->lock); - /* - * stop and reset the on-board processor just in case it is in a - * strange state ... like being left stranded by a primary kernel - * and this is now the kdump kernel trying to start up - */ - iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); - /*********************** * 4. Read EEPROM * ********************/ diff --git a/trunk/drivers/net/wireless/iwmc3200wifi/iwm.h b/trunk/drivers/net/wireless/iwmc3200wifi/iwm.h index 79ffa3b98d73..842811142bef 100644 --- a/trunk/drivers/net/wireless/iwmc3200wifi/iwm.h +++ b/trunk/drivers/net/wireless/iwmc3200wifi/iwm.h @@ -268,7 +268,7 @@ struct iwm_priv { struct sk_buff_head rx_list; struct list_head rx_tickets; - struct list_head rx_packets[IWM_RX_ID_HASH]; + struct list_head rx_packets[IWM_RX_ID_HASH + 1]; struct workqueue_struct *rx_wq; struct work_struct rx_worker; diff --git a/trunk/drivers/net/wireless/iwmc3200wifi/rx.c b/trunk/drivers/net/wireless/iwmc3200wifi/rx.c index 6b53ae122680..64d16fe37f9a 100644 --- a/trunk/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/trunk/drivers/net/wireless/iwmc3200wifi/rx.c @@ -868,35 +868,36 @@ static int iwm_mlme_mgt_frame(struct iwm_priv *iwm, u8 *buf, struct iwm_umac_notif_mgt_frame *mgt_frame = (struct iwm_umac_notif_mgt_frame *)buf; struct ieee80211_mgmt *mgt = (struct ieee80211_mgmt *)mgt_frame->frame; + u8 *ie; IWM_HEXDUMP(iwm, DBG, MLME, "MGT: ", mgt_frame->frame, le16_to_cpu(mgt_frame->len)); if (ieee80211_is_assoc_req(mgt->frame_control)) { - iwm->req_ie_len = le16_to_cpu(mgt_frame->len) - - offsetof(struct ieee80211_mgmt, - u.assoc_req.variable); + ie = mgt->u.assoc_req.variable;; + iwm->req_ie_len = + le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt); kfree(iwm->req_ie); iwm->req_ie = kmemdup(mgt->u.assoc_req.variable, iwm->req_ie_len, GFP_KERNEL); } else if (ieee80211_is_reassoc_req(mgt->frame_control)) { - iwm->req_ie_len = le16_to_cpu(mgt_frame->len) - - offsetof(struct ieee80211_mgmt, - u.reassoc_req.variable); + ie = mgt->u.reassoc_req.variable;; + iwm->req_ie_len = + le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt); kfree(iwm->req_ie); iwm->req_ie = kmemdup(mgt->u.reassoc_req.variable, iwm->req_ie_len, GFP_KERNEL); } else if (ieee80211_is_assoc_resp(mgt->frame_control)) { - iwm->resp_ie_len = le16_to_cpu(mgt_frame->len) - - offsetof(struct ieee80211_mgmt, - u.assoc_resp.variable); + ie = mgt->u.assoc_resp.variable;; + iwm->resp_ie_len = + le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt); kfree(iwm->resp_ie); iwm->resp_ie = kmemdup(mgt->u.assoc_resp.variable, iwm->resp_ie_len, GFP_KERNEL); } else if (ieee80211_is_reassoc_resp(mgt->frame_control)) { - iwm->resp_ie_len = le16_to_cpu(mgt_frame->len) - - offsetof(struct ieee80211_mgmt, - u.reassoc_resp.variable); + ie = mgt->u.reassoc_resp.variable;; + iwm->resp_ie_len = + le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt); kfree(iwm->resp_ie); iwm->resp_ie = kmemdup(mgt->u.reassoc_resp.variable, iwm->resp_ie_len, GFP_KERNEL); @@ -1533,33 +1534,6 @@ static void classify8023(struct sk_buff *skb) } } -static void iwm_rx_process_amsdu(struct iwm_priv *iwm, struct sk_buff *skb) -{ - struct wireless_dev *wdev = iwm_to_wdev(iwm); - struct net_device *ndev = iwm_to_ndev(iwm); - struct sk_buff_head list; - struct sk_buff *frame; - - IWM_HEXDUMP(iwm, DBG, RX, "A-MSDU: ", skb->data, skb->len); - - __skb_queue_head_init(&list); - ieee80211_amsdu_to_8023s(skb, &list, ndev->dev_addr, wdev->iftype, 0); - - while ((frame = __skb_dequeue(&list))) { - ndev->stats.rx_packets++; - ndev->stats.rx_bytes += frame->len; - - frame->protocol = eth_type_trans(frame, ndev); - frame->ip_summed = CHECKSUM_NONE; - memset(frame->cb, 0, sizeof(frame->cb)); - - if (netif_rx_ni(frame) == NET_RX_DROP) { - IWM_ERR(iwm, "Packet dropped\n"); - ndev->stats.rx_dropped++; - } - } -} - static void iwm_rx_process_packet(struct iwm_priv *iwm, struct iwm_rx_packet *packet, struct iwm_rx_ticket_node *ticket_node) @@ -1574,34 +1548,25 @@ static void iwm_rx_process_packet(struct iwm_priv *iwm, switch (le16_to_cpu(ticket_node->ticket->action)) { case IWM_RX_TICKET_RELEASE: IWM_DBG_RX(iwm, DBG, "RELEASE packet\n"); - - iwm_rx_adjust_packet(iwm, packet, ticket_node); - skb->dev = iwm_to_ndev(iwm); classify8023(skb); - - if (le16_to_cpu(ticket_node->ticket->flags) & - IWM_RX_TICKET_AMSDU_MSK) { - iwm_rx_process_amsdu(iwm, skb); - break; - } - + iwm_rx_adjust_packet(iwm, packet, ticket_node); ret = ieee80211_data_to_8023(skb, ndev->dev_addr, wdev->iftype); if (ret < 0) { IWM_DBG_RX(iwm, DBG, "Couldn't convert 802.11 header - " "%d\n", ret); - kfree_skb(packet->skb); break; } IWM_HEXDUMP(iwm, DBG, RX, "802.3: ", skb->data, skb->len); - ndev->stats.rx_packets++; - ndev->stats.rx_bytes += skb->len; - + skb->dev = iwm_to_ndev(iwm); skb->protocol = eth_type_trans(skb, ndev); skb->ip_summed = CHECKSUM_NONE; memset(skb->cb, 0, sizeof(skb->cb)); + ndev->stats.rx_packets++; + ndev->stats.rx_bytes += skb->len; + if (netif_rx_ni(skb) == NET_RX_DROP) { IWM_ERR(iwm, "Packet dropped\n"); ndev->stats.rx_dropped++; diff --git a/trunk/drivers/net/wireless/libertas/Kconfig b/trunk/drivers/net/wireless/libertas/Kconfig index 0485c9957575..30aa9d48d67e 100644 --- a/trunk/drivers/net/wireless/libertas/Kconfig +++ b/trunk/drivers/net/wireless/libertas/Kconfig @@ -37,9 +37,3 @@ config LIBERTAS_DEBUG depends on LIBERTAS ---help--- Debugging support. - -config LIBERTAS_MESH - bool "Enable mesh support" - depends on LIBERTAS - help - This enables Libertas' MESH support, used by e.g. the OLPC people. diff --git a/trunk/drivers/net/wireless/libertas/Makefile b/trunk/drivers/net/wireless/libertas/Makefile index 45e870e33117..b188cd97a053 100644 --- a/trunk/drivers/net/wireless/libertas/Makefile +++ b/trunk/drivers/net/wireless/libertas/Makefile @@ -5,11 +5,11 @@ libertas-y += cmdresp.o libertas-y += debugfs.o libertas-y += ethtool.o libertas-y += main.o +libertas-y += mesh.o libertas-y += rx.o libertas-y += scan.o libertas-y += tx.o libertas-y += wext.o -libertas-$(CONFIG_LIBERTAS_MESH) += mesh.o usb8xxx-objs += if_usb.o libertas_cs-objs += if_cs.o diff --git a/trunk/drivers/net/wireless/libertas/assoc.c b/trunk/drivers/net/wireless/libertas/assoc.c index f03d5e4e59c3..751067369ba8 100644 --- a/trunk/drivers/net/wireless/libertas/assoc.c +++ b/trunk/drivers/net/wireless/libertas/assoc.c @@ -390,8 +390,10 @@ int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv, cmd.enablehwauto = cpu_to_le16(priv->enablehwauto); cmd.bitmap = lbs_rate_to_fw_bitmap(priv->cur_rate, priv->enablehwauto); ret = lbs_cmd_with_response(priv, CMD_802_11_RATE_ADAPT_RATESET, &cmd); - if (!ret && cmd_action == CMD_ACT_GET) + if (!ret && cmd_action == CMD_ACT_GET) { + priv->ratebitmap = le16_to_cpu(cmd.bitmap); priv->enablehwauto = le16_to_cpu(cmd.enablehwauto); + } lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; @@ -805,7 +807,8 @@ static int lbs_try_associate(struct lbs_private *priv, } /* Use short preamble only when both the BSS and firmware support it */ - if (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE) + if ((priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) && + (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) preamble = RADIO_PREAMBLE_SHORT; ret = lbs_set_radio(priv, preamble, 1); @@ -936,7 +939,8 @@ static int lbs_adhoc_join(struct lbs_private *priv, } /* Use short preamble only when both the BSS and firmware support it */ - if (bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) { + if ((priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) && + (bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) { lbs_deb_join("AdhocJoin: Short preamble\n"); preamble = RADIO_PREAMBLE_SHORT; } @@ -1045,7 +1049,7 @@ static int lbs_adhoc_start(struct lbs_private *priv, struct assoc_request *assoc_req) { struct cmd_ds_802_11_ad_hoc_start cmd; - u8 preamble = RADIO_PREAMBLE_SHORT; + u8 preamble = RADIO_PREAMBLE_LONG; size_t ratesize = 0; u16 tmpcap = 0; int ret = 0; @@ -1053,6 +1057,11 @@ static int lbs_adhoc_start(struct lbs_private *priv, lbs_deb_enter(LBS_DEB_ASSOC); + if (priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) { + lbs_deb_join("ADHOC_START: Will use short preamble\n"); + preamble = RADIO_PREAMBLE_SHORT; + } + ret = lbs_set_radio(priv, preamble, 1); if (ret) goto out; @@ -1160,11 +1169,11 @@ int lbs_adhoc_stop(struct lbs_private *priv) static inline int match_bss_no_security(struct lbs_802_11_security *secinfo, struct bss_descriptor *match_bss) { - if (!secinfo->wep_enabled && - !secinfo->WPAenabled && !secinfo->WPA2enabled && - match_bss->wpa_ie[0] != WLAN_EID_GENERIC && - match_bss->rsn_ie[0] != WLAN_EID_RSN && - !(match_bss->capability & WLAN_CAPABILITY_PRIVACY)) + if (!secinfo->wep_enabled && !secinfo->WPAenabled + && !secinfo->WPA2enabled + && match_bss->wpa_ie[0] != WLAN_EID_GENERIC + && match_bss->rsn_ie[0] != WLAN_EID_RSN + && !(match_bss->capability & WLAN_CAPABILITY_PRIVACY)) return 1; else return 0; @@ -1173,9 +1182,9 @@ static inline int match_bss_no_security(struct lbs_802_11_security *secinfo, static inline int match_bss_static_wep(struct lbs_802_11_security *secinfo, struct bss_descriptor *match_bss) { - if (secinfo->wep_enabled && - !secinfo->WPAenabled && !secinfo->WPA2enabled && - (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) + if (secinfo->wep_enabled && !secinfo->WPAenabled + && !secinfo->WPA2enabled + && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) return 1; else return 0; @@ -1184,8 +1193,8 @@ static inline int match_bss_static_wep(struct lbs_802_11_security *secinfo, static inline int match_bss_wpa(struct lbs_802_11_security *secinfo, struct bss_descriptor *match_bss) { - if (!secinfo->wep_enabled && secinfo->WPAenabled && - (match_bss->wpa_ie[0] == WLAN_EID_GENERIC) + if (!secinfo->wep_enabled && secinfo->WPAenabled + && (match_bss->wpa_ie[0] == WLAN_EID_GENERIC) /* privacy bit may NOT be set in some APs like LinkSys WRT54G && (match_bss->capability & WLAN_CAPABILITY_PRIVACY) */ ) @@ -1210,11 +1219,11 @@ static inline int match_bss_wpa2(struct lbs_802_11_security *secinfo, static inline int match_bss_dynamic_wep(struct lbs_802_11_security *secinfo, struct bss_descriptor *match_bss) { - if (!secinfo->wep_enabled && - !secinfo->WPAenabled && !secinfo->WPA2enabled && - (match_bss->wpa_ie[0] != WLAN_EID_GENERIC) && - (match_bss->rsn_ie[0] != WLAN_EID_RSN) && - (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) + if (!secinfo->wep_enabled && !secinfo->WPAenabled + && !secinfo->WPA2enabled + && (match_bss->wpa_ie[0] != WLAN_EID_GENERIC) + && (match_bss->rsn_ie[0] != WLAN_EID_RSN) + && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) return 1; else return 0; @@ -1525,8 +1534,8 @@ static int assoc_helper_associate(struct lbs_private *priv, /* If we're given and 'any' BSSID, try associating based on SSID */ if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) { - if (compare_ether_addr(bssid_any, assoc_req->bssid) && - compare_ether_addr(bssid_off, assoc_req->bssid)) { + if (compare_ether_addr(bssid_any, assoc_req->bssid) + && compare_ether_addr(bssid_off, assoc_req->bssid)) { ret = assoc_helper_bssid(priv, assoc_req); done = 1; } @@ -1612,9 +1621,11 @@ static int assoc_helper_channel(struct lbs_private *priv, goto restore_mesh; } - if (assoc_req->secinfo.wep_enabled && - (assoc_req->wep_keys[0].len || assoc_req->wep_keys[1].len || - assoc_req->wep_keys[2].len || assoc_req->wep_keys[3].len)) { + if ( assoc_req->secinfo.wep_enabled + && (assoc_req->wep_keys[0].len + || assoc_req->wep_keys[1].len + || assoc_req->wep_keys[2].len + || assoc_req->wep_keys[3].len)) { /* Make sure WEP keys are re-sent to firmware */ set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags); } @@ -1981,14 +1992,14 @@ void lbs_association_worker(struct work_struct *work) assoc_req->secinfo.auth_mode); /* If 'any' SSID was specified, find an SSID to associate with */ - if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags) && - !assoc_req->ssid_len) + if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags) + && !assoc_req->ssid_len) find_any_ssid = 1; /* But don't use 'any' SSID if there's a valid locked BSSID to use */ if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) { - if (compare_ether_addr(assoc_req->bssid, bssid_any) && - compare_ether_addr(assoc_req->bssid, bssid_off)) + if (compare_ether_addr(assoc_req->bssid, bssid_any) + && compare_ether_addr(assoc_req->bssid, bssid_off)) find_any_ssid = 0; } @@ -2050,6 +2061,13 @@ void lbs_association_worker(struct work_struct *work) goto out; } + if ( test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags) + || test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) { + ret = assoc_helper_wep_keys(priv, assoc_req); + if (ret) + goto out; + } + if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) { ret = assoc_helper_secinfo(priv, assoc_req); if (ret) @@ -2062,31 +2080,18 @@ void lbs_association_worker(struct work_struct *work) goto out; } - /* - * v10 FW wants WPA keys to be set/cleared before WEP key operations, - * otherwise it will fail to correctly associate to WEP networks. - * Other firmware versions don't appear to care. - */ - if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags) || - test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) { + if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags) + || test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) { ret = assoc_helper_wpa_keys(priv, assoc_req); if (ret) goto out; } - if (test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags) || - test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) { - ret = assoc_helper_wep_keys(priv, assoc_req); - if (ret) - goto out; - } - - /* SSID/BSSID should be the _last_ config option set, because they * trigger the association attempt. */ - if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags) || - test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) { + if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags) + || test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) { int success = 1; ret = assoc_helper_associate(priv, assoc_req); diff --git a/trunk/drivers/net/wireless/libertas/cmd.c b/trunk/drivers/net/wireless/libertas/cmd.c index 42051f7cad6d..b9b371bfa30f 100644 --- a/trunk/drivers/net/wireless/libertas/cmd.c +++ b/trunk/drivers/net/wireless/libertas/cmd.c @@ -143,6 +143,19 @@ int lbs_update_hw_spec(struct lbs_private *priv) lbs_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n", cmd.hwifversion, cmd.version); + /* Determine mesh_fw_ver from fwrelease and fwcapinfo */ + /* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */ + /* 5.110.22 have mesh command with 0xa3 command id */ + /* 10.0.0.p0 FW brings in mesh config command with different id */ + /* Check FW version MSB and initialize mesh_fw_ver */ + if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5) + priv->mesh_fw_ver = MESH_FW_OLD; + else if ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) && + (priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK)) + priv->mesh_fw_ver = MESH_FW_NEW; + else + priv->mesh_fw_ver = MESH_NONE; + /* Clamp region code to 8-bit since FW spec indicates that it should * only ever be 8-bit, even though the field size is 16-bit. Some firmware * returns non-zero high 8 bits here. @@ -842,6 +855,9 @@ int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on) if (priv->fwrelease < 0x09000000) { switch (preamble) { case RADIO_PREAMBLE_SHORT: + if (!(priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) + goto out; + /* Fall through */ case RADIO_PREAMBLE_AUTO: case RADIO_PREAMBLE_LONG: cmd.control = cpu_to_le16(preamble); @@ -995,8 +1011,6 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, ret = 0; break; -#ifdef CONFIG_LIBERTAS_MESH - case CMD_BT_ACCESS: ret = lbs_cmd_bt_access(cmdptr, cmd_action, pdata_buf); break; @@ -1005,8 +1019,6 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, ret = lbs_cmd_fwt_access(cmdptr, cmd_action, pdata_buf); break; -#endif - case CMD_802_11_BEACON_CTRL: ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action); break; @@ -1305,7 +1317,7 @@ int lbs_execute_next_command(struct lbs_private *priv) if ((priv->psmode != LBS802_11POWERMODECAM) && (priv->psstate == PS_STATE_FULL_POWER) && ((priv->connect_status == LBS_CONNECTED) || - lbs_mesh_connected(priv))) { + (priv->mesh_connect_status == LBS_CONNECTED))) { if (priv->secinfo.WPAenabled || priv->secinfo.WPA2enabled) { /* check for valid WPA group keys */ diff --git a/trunk/drivers/net/wireless/libertas/cmd.h b/trunk/drivers/net/wireless/libertas/cmd.h index cb4138a55fdf..2862748aef70 100644 --- a/trunk/drivers/net/wireless/libertas/cmd.h +++ b/trunk/drivers/net/wireless/libertas/cmd.h @@ -110,6 +110,18 @@ int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val); int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val); +/* Mesh related */ + +int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action, + struct cmd_ds_mesh_access *cmd); + +int lbs_mesh_config_send(struct lbs_private *priv, + struct cmd_ds_mesh_config *cmd, + uint16_t action, uint16_t type); + +int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan); + + /* Commands only used in wext.c, assoc. and scan.c */ int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0, diff --git a/trunk/drivers/net/wireless/libertas/cmdresp.c b/trunk/drivers/net/wireless/libertas/cmdresp.c index e7470442f76b..21d57690c20a 100644 --- a/trunk/drivers/net/wireless/libertas/cmdresp.c +++ b/trunk/drivers/net/wireless/libertas/cmdresp.c @@ -240,6 +240,11 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len) /* Now we got response from FW, cancel the command timer */ del_timer(&priv->command_timer); priv->cmd_timed_out = 0; + if (priv->nr_retries) { + lbs_pr_info("Received result %x to command %x after %d retries\n", + result, curcmd, priv->nr_retries); + priv->nr_retries = 0; + } /* Store the response code to cur_cmd_retcode. */ priv->cur_cmd_retcode = result; @@ -480,8 +485,20 @@ int lbs_process_event(struct lbs_private *priv, u32 event) break; case MACREG_INT_CODE_MESH_AUTO_STARTED: - /* Ignore spurious autostart events */ - lbs_pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n"); + /* Ignore spurious autostart events if autostart is disabled */ + if (!priv->mesh_autostart_enabled) { + lbs_pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n"); + break; + } + lbs_pr_info("EVENT: MESH_AUTO_STARTED\n"); + priv->mesh_connect_status = LBS_CONNECTED; + if (priv->mesh_open) { + netif_carrier_on(priv->mesh_dev); + if (!priv->tx_pending_len) + netif_wake_queue(priv->mesh_dev); + } + priv->mode = IW_MODE_ADHOC; + schedule_work(&priv->sync_channel); break; default: diff --git a/trunk/drivers/net/wireless/libertas/defs.h b/trunk/drivers/net/wireless/libertas/defs.h index ea3f10ef4e00..6b6ea9f7bf5b 100644 --- a/trunk/drivers/net/wireless/libertas/defs.h +++ b/trunk/drivers/net/wireless/libertas/defs.h @@ -397,6 +397,13 @@ enum KEY_INFO_WPA { KEY_INFO_WPA_ENABLED = 0x04 }; +/** mesh_fw_ver */ +enum _mesh_fw_ver { + MESH_NONE = 0, /* MESH is not supported */ + MESH_FW_OLD, /* MESH is supported in FW V5 */ + MESH_FW_NEW, /* MESH is supported in FW V10 and newer */ +}; + /* Default values for fwt commands. */ #define FWT_DEFAULT_METRIC 0 #define FWT_DEFAULT_DIR 1 diff --git a/trunk/drivers/net/wireless/libertas/dev.h b/trunk/drivers/net/wireless/libertas/dev.h index efb2519d9d74..6a8d2b291d8c 100644 --- a/trunk/drivers/net/wireless/libertas/dev.h +++ b/trunk/drivers/net/wireless/libertas/dev.h @@ -39,14 +39,15 @@ struct lbs_private { /* Mesh */ struct net_device *mesh_dev; /* Virtual device */ -#ifdef CONFIG_LIBERTAS_MESH u32 mesh_connect_status; struct lbs_mesh_stats mstats; int mesh_open; + int mesh_fw_ver; + int mesh_autostart_enabled; uint16_t mesh_tlv; u8 mesh_ssid[IEEE80211_MAX_SSID_LEN + 1]; u8 mesh_ssid_len; -#endif + struct work_struct sync_channel; /* Monitor mode */ struct net_device *rtap_net_dev; @@ -109,6 +110,7 @@ struct lbs_private { struct list_head cmdpendingq; /* pending command buffers */ wait_queue_head_t cmd_pending; struct timer_list command_timer; + int nr_retries; int cmd_timed_out; /* Command responses sent from the hardware to the driver */ @@ -174,7 +176,9 @@ struct lbs_private { struct bss_descriptor *networks; struct assoc_request * pending_assoc_req; struct assoc_request * in_progress_assoc_req; + u16 capability; uint16_t enablehwauto; + uint16_t ratebitmap; /* ADHOC */ u16 beacon_period; diff --git a/trunk/drivers/net/wireless/libertas/ethtool.c b/trunk/drivers/net/wireless/libertas/ethtool.c index 3804a58d7f4e..63d020374c2b 100644 --- a/trunk/drivers/net/wireless/libertas/ethtool.c +++ b/trunk/drivers/net/wireless/libertas/ethtool.c @@ -114,11 +114,9 @@ const struct ethtool_ops lbs_ethtool_ops = { .get_drvinfo = lbs_ethtool_get_drvinfo, .get_eeprom = lbs_ethtool_get_eeprom, .get_eeprom_len = lbs_ethtool_get_eeprom_len, -#ifdef CONFIG_LIBERTAS_MESH .get_sset_count = lbs_mesh_ethtool_get_sset_count, .get_ethtool_stats = lbs_mesh_ethtool_get_stats, .get_strings = lbs_mesh_ethtool_get_strings, -#endif .get_wol = lbs_ethtool_get_wol, .set_wol = lbs_ethtool_set_wol, }; diff --git a/trunk/drivers/net/wireless/libertas/if_spi.c b/trunk/drivers/net/wireless/libertas/if_spi.c index 3ea03f259ee7..bf4bfbae6227 100644 --- a/trunk/drivers/net/wireless/libertas/if_spi.c +++ b/trunk/drivers/net/wireless/libertas/if_spi.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include diff --git a/trunk/drivers/net/wireless/libertas/main.c b/trunk/drivers/net/wireless/libertas/main.c index f5d641efd50a..db38a5a719fa 100644 --- a/trunk/drivers/net/wireless/libertas/main.c +++ b/trunk/drivers/net/wireless/libertas/main.c @@ -123,7 +123,7 @@ static ssize_t lbs_rtap_set(struct device *dev, if (priv->monitormode == monitor_mode) return strlen(buf); if (!priv->monitormode) { - if (priv->infra_open || lbs_mesh_open(priv)) + if (priv->infra_open || priv->mesh_open) return -EBUSY; if (priv->mode == IW_MODE_INFRA) lbs_cmd_80211_deauthenticate(priv, @@ -533,14 +533,31 @@ static int lbs_thread(void *data) if (priv->cmd_timed_out && priv->cur_cmd) { struct cmd_ctrl_node *cmdnode = priv->cur_cmd; - lbs_pr_info("Timeout submitting command 0x%04x\n", - le16_to_cpu(cmdnode->cmdbuf->command)); - lbs_complete_command(priv, cmdnode, -ETIMEDOUT); - if (priv->reset_card) - priv->reset_card(priv); + if (++priv->nr_retries > 3) { + lbs_pr_info("Excessive timeouts submitting " + "command 0x%04x\n", + le16_to_cpu(cmdnode->cmdbuf->command)); + lbs_complete_command(priv, cmdnode, -ETIMEDOUT); + priv->nr_retries = 0; + if (priv->reset_card) + priv->reset_card(priv); + } else { + priv->cur_cmd = NULL; + priv->dnld_sent = DNLD_RES_RECEIVED; + lbs_pr_info("requeueing command 0x%04x due " + "to timeout (#%d)\n", + le16_to_cpu(cmdnode->cmdbuf->command), + priv->nr_retries); + + /* Stick it back at the _top_ of the pending queue + for immediate resubmission */ + list_add(&cmdnode->list, &priv->cmdpendingq); + } } priv->cmd_timed_out = 0; + + if (!priv->fw_ready) continue; @@ -602,7 +619,7 @@ static int lbs_thread(void *data) if (priv->connect_status == LBS_CONNECTED) netif_wake_queue(priv->dev); if (priv->mesh_dev && - lbs_mesh_connected(priv)) + priv->mesh_connect_status == LBS_CONNECTED) netif_wake_queue(priv->mesh_dev); } } @@ -712,7 +729,7 @@ static int lbs_setup_firmware(struct lbs_private *priv) * This function handles the timeout of command sending. * It will re-send the same command again. */ -static void lbs_cmd_timeout_handler(unsigned long data) +static void command_timer_fn(unsigned long data) { struct lbs_private *priv = (struct lbs_private *)data; unsigned long flags; @@ -789,6 +806,18 @@ int lbs_exit_auto_deep_sleep(struct lbs_private *priv) return 0; } +static void lbs_sync_channel_worker(struct work_struct *work) +{ + struct lbs_private *priv = container_of(work, struct lbs_private, + sync_channel); + + lbs_deb_enter(LBS_DEB_MAIN); + if (lbs_update_channel(priv)) + lbs_pr_info("Channel synchronization failed."); + lbs_deb_leave(LBS_DEB_MAIN); +} + + static int lbs_init_adapter(struct lbs_private *priv) { size_t bufsize; @@ -816,12 +845,14 @@ static int lbs_init_adapter(struct lbs_private *priv) memset(priv->current_addr, 0xff, ETH_ALEN); priv->connect_status = LBS_DISCONNECTED; + priv->mesh_connect_status = LBS_DISCONNECTED; priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; priv->mode = IW_MODE_INFRA; priv->channel = DEFAULT_AD_HOC_CHANNEL; priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON; priv->radio_on = 1; priv->enablehwauto = 1; + priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE; priv->psmode = LBS802_11POWERMODECAM; priv->psstate = PS_STATE_FULL_POWER; priv->is_deep_sleep = 0; @@ -831,7 +862,7 @@ static int lbs_init_adapter(struct lbs_private *priv) mutex_init(&priv->lock); - setup_timer(&priv->command_timer, lbs_cmd_timeout_handler, + setup_timer(&priv->command_timer, command_timer_fn, (unsigned long)priv); setup_timer(&priv->auto_deepsleep_timer, auto_deepsleep_timer_fn, (unsigned long)priv); @@ -966,6 +997,11 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) INIT_DELAYED_WORK(&priv->assoc_work, lbs_association_worker); INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker); INIT_WORK(&priv->mcast_work, lbs_set_mcast_worker); + INIT_WORK(&priv->sync_channel, lbs_sync_channel_worker); + + priv->mesh_open = 0; + sprintf(priv->mesh_ssid, "mesh"); + priv->mesh_ssid_len = 4; priv->wol_criteria = 0xffffffff; priv->wol_gpio = 0xff; @@ -1039,17 +1075,6 @@ void lbs_remove_card(struct lbs_private *priv) EXPORT_SYMBOL_GPL(lbs_remove_card); -static int lbs_rtap_supported(struct lbs_private *priv) -{ - if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5) - return 1; - - /* newer firmware use a capability mask */ - return ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) && - (priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK)); -} - - int lbs_start_card(struct lbs_private *priv) { struct net_device *dev = priv->dev; @@ -1069,14 +1094,12 @@ int lbs_start_card(struct lbs_private *priv) lbs_update_channel(priv); - lbs_init_mesh(priv); - /* * While rtap isn't related to mesh, only mesh-enabled * firmware implements the rtap functionality via * CMD_802_11_MONITOR_MODE. */ - if (lbs_rtap_supported(priv)) { + if (lbs_init_mesh(priv)) { if (device_create_file(&dev->dev, &dev_attr_lbs_rtap)) lbs_pr_err("cannot register lbs_rtap attribute\n"); } @@ -1110,9 +1133,7 @@ void lbs_stop_card(struct lbs_private *priv) netif_carrier_off(dev); lbs_debugfs_remove_one(priv); - lbs_deinit_mesh(priv); - - if (lbs_rtap_supported(priv)) + if (lbs_deinit_mesh(priv)) device_remove_file(&dev->dev, &dev_attr_lbs_rtap); /* Delete the timeout of the currently processing command */ diff --git a/trunk/drivers/net/wireless/libertas/mesh.c b/trunk/drivers/net/wireless/libertas/mesh.c index 954cd00f7452..2f91c9b808af 100644 --- a/trunk/drivers/net/wireless/libertas/mesh.c +++ b/trunk/drivers/net/wireless/libertas/mesh.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -195,14 +196,7 @@ int lbs_init_mesh(struct lbs_private *priv) lbs_deb_enter(LBS_DEB_MESH); - priv->mesh_connect_status = LBS_DISCONNECTED; - - /* Determine mesh_fw_ver from fwrelease and fwcapinfo */ - /* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */ - /* 5.110.22 have mesh command with 0xa3 command id */ - /* 10.0.0.p0 FW brings in mesh config command with different id */ - /* Check FW version MSB and initialize mesh_fw_ver */ - if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5) { + if (priv->mesh_fw_ver == MESH_FW_OLD) { /* Enable mesh, if supported, and work out which TLV it uses. 0x100 + 291 is an unofficial value used in 5.110.20.pXX 0x100 + 37 is the official value used in 5.110.21.pXX @@ -224,9 +218,7 @@ int lbs_init_mesh(struct lbs_private *priv) priv->channel)) priv->mesh_tlv = 0; } - } else - if ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) && - (priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK)) { + } else if (priv->mesh_fw_ver == MESH_FW_NEW) { /* 10.0.0.pXX new firmwares should succeed with TLV * 0x100+37; Do not invoke command with old TLV. */ @@ -235,12 +227,7 @@ int lbs_init_mesh(struct lbs_private *priv) priv->channel)) priv->mesh_tlv = 0; } - - if (priv->mesh_tlv) { - sprintf(priv->mesh_ssid, "mesh"); - priv->mesh_ssid_len = 4; - lbs_add_mesh(priv); if (device_create_file(&dev->dev, &dev_attr_lbs_mesh)) @@ -429,10 +416,10 @@ struct net_device *lbs_mesh_set_dev(struct lbs_private *priv, struct net_device *dev, struct rxpd *rxpd) { if (priv->mesh_dev) { - if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID) { + if (priv->mesh_fw_ver == MESH_FW_OLD) { if (rxpd->rx_control & RxPD_MESH_FRAME) dev = priv->mesh_dev; - } else if (priv->mesh_tlv == TLV_TYPE_MESH_ID) { + } else if (priv->mesh_fw_ver == MESH_FW_NEW) { if (rxpd->u.bss.bss_num == MESH_IFACE_ID) dev = priv->mesh_dev; } @@ -445,9 +432,9 @@ void lbs_mesh_set_txpd(struct lbs_private *priv, struct net_device *dev, struct txpd *txpd) { if (dev == priv->mesh_dev) { - if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID) + if (priv->mesh_fw_ver == MESH_FW_OLD) txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME); - else if (priv->mesh_tlv == TLV_TYPE_MESH_ID) + else if (priv->mesh_fw_ver == MESH_FW_NEW) txpd->u.bss.bss_num = MESH_IFACE_ID; } } @@ -551,7 +538,7 @@ static int __lbs_mesh_config_send(struct lbs_private *priv, * Command id is 0xac for v10 FW along with mesh interface * id in bits 14-13-12. */ - if (priv->mesh_tlv == TLV_TYPE_MESH_ID) + if (priv->mesh_fw_ver == MESH_FW_NEW) command = CMD_MESH_CONFIG | (MESH_IFACE_ID << MESH_IFACE_BIT_OFFSET); diff --git a/trunk/drivers/net/wireless/libertas/mesh.h b/trunk/drivers/net/wireless/libertas/mesh.h index e2573303a328..fea9b5d005fc 100644 --- a/trunk/drivers/net/wireless/libertas/mesh.h +++ b/trunk/drivers/net/wireless/libertas/mesh.h @@ -9,8 +9,6 @@ #include -#ifdef CONFIG_LIBERTAS_MESH - /* Mesh statistics */ struct lbs_mesh_stats { u32 fwd_bcast_cnt; /* Fwd: Broadcast counter */ @@ -48,20 +46,11 @@ void lbs_mesh_set_txpd(struct lbs_private *priv, /* Command handling */ struct cmd_ds_command; -struct cmd_ds_mesh_access; -struct cmd_ds_mesh_config; int lbs_cmd_bt_access(struct cmd_ds_command *cmd, u16 cmd_action, void *pdata_buf); int lbs_cmd_fwt_access(struct cmd_ds_command *cmd, u16 cmd_action, void *pdata_buf); -int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action, - struct cmd_ds_mesh_access *cmd); -int lbs_mesh_config_send(struct lbs_private *priv, - struct cmd_ds_mesh_config *cmd, - uint16_t action, uint16_t type); -int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan); - /* Persistent configuration */ @@ -86,25 +75,4 @@ void lbs_mesh_ethtool_get_strings(struct net_device *dev, uint32_t stringset, uint8_t *s); -/* Accessors */ - -#define lbs_mesh_open(priv) (priv->mesh_open) -#define lbs_mesh_connected(priv) (priv->mesh_connect_status == LBS_CONNECTED) - -#else - -#define lbs_init_mesh(priv) -#define lbs_deinit_mesh(priv) -#define lbs_add_mesh(priv) -#define lbs_remove_mesh(priv) -#define lbs_mesh_set_dev(priv, dev, rxpd) (dev) -#define lbs_mesh_set_txpd(priv, dev, txpd) -#define lbs_mesh_config(priv, enable, chan) -#define lbs_mesh_open(priv) (0) -#define lbs_mesh_connected(priv) (0) - -#endif - - - #endif diff --git a/trunk/drivers/net/wireless/libertas/scan.c b/trunk/drivers/net/wireless/libertas/scan.c index 220361e69cd3..b0b1c7841500 100644 --- a/trunk/drivers/net/wireless/libertas/scan.c +++ b/trunk/drivers/net/wireless/libertas/scan.c @@ -635,7 +635,7 @@ int lbs_scan_networks(struct lbs_private *priv, int full_scan) if (priv->connect_status == LBS_CONNECTED && !priv->tx_pending_len) netif_wake_queue(priv->dev); - if (priv->mesh_dev && lbs_mesh_connected(priv) && + if (priv->mesh_dev && (priv->mesh_connect_status == LBS_CONNECTED) && !priv->tx_pending_len) netif_wake_queue(priv->mesh_dev); diff --git a/trunk/drivers/net/wireless/libertas/tx.c b/trunk/drivers/net/wireless/libertas/tx.c index 52d244ea3d97..315d1ce286ca 100644 --- a/trunk/drivers/net/wireless/libertas/tx.c +++ b/trunk/drivers/net/wireless/libertas/tx.c @@ -198,7 +198,7 @@ void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count) if (priv->connect_status == LBS_CONNECTED) netif_wake_queue(priv->dev); - if (priv->mesh_dev && lbs_mesh_connected(priv)) + if (priv->mesh_dev && (priv->mesh_connect_status == LBS_CONNECTED)) netif_wake_queue(priv->mesh_dev); } EXPORT_SYMBOL_GPL(lbs_send_tx_feedback); diff --git a/trunk/drivers/net/wireless/libertas/wext.c b/trunk/drivers/net/wireless/libertas/wext.c index 71f88a08e090..4b1aab593a84 100644 --- a/trunk/drivers/net/wireless/libertas/wext.c +++ b/trunk/drivers/net/wireless/libertas/wext.c @@ -192,7 +192,7 @@ static void copy_active_data_rates(struct lbs_private *priv, u8 *rates) lbs_deb_enter(LBS_DEB_WEXT); if ((priv->connect_status != LBS_CONNECTED) && - !lbs_mesh_connected(priv)) + (priv->mesh_connect_status != LBS_CONNECTED)) memcpy(rates, lbs_bg_rates, MAX_RATES); else memcpy(rates, priv->curbssparams.rates, MAX_RATES); @@ -298,7 +298,6 @@ static int lbs_get_nick(struct net_device *dev, struct iw_request_info *info, return 0; } -#ifdef CONFIG_LIBERTAS_MESH static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { @@ -308,7 +307,7 @@ static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info, /* Use nickname to indicate that mesh is on */ - if (lbs_mesh_connected(priv)) { + if (priv->mesh_connect_status == LBS_CONNECTED) { strncpy(extra, "Mesh", 12); extra[12] = '\0'; dwrq->length = strlen(extra); @@ -322,7 +321,6 @@ static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info, lbs_deb_leave(LBS_DEB_WEXT); return 0; } -#endif static int lbs_set_rts(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) @@ -424,7 +422,6 @@ static int lbs_get_mode(struct net_device *dev, return 0; } -#ifdef CONFIG_LIBERTAS_MESH static int mesh_wlan_get_mode(struct net_device *dev, struct iw_request_info *info, u32 * uwrq, char *extra) @@ -436,7 +433,6 @@ static int mesh_wlan_get_mode(struct net_device *dev, lbs_deb_leave(LBS_DEB_WEXT); return 0; } -#endif static int lbs_get_txpow(struct net_device *dev, struct iw_request_info *info, @@ -867,7 +863,7 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev) /* If we're not associated, all quality values are meaningless */ if ((priv->connect_status != LBS_CONNECTED) && - !lbs_mesh_connected(priv)) + (priv->mesh_connect_status != LBS_CONNECTED)) goto out; /* Quality by RSSI */ @@ -1014,7 +1010,6 @@ static int lbs_set_freq(struct net_device *dev, struct iw_request_info *info, return ret; } -#ifdef CONFIG_LIBERTAS_MESH static int lbs_mesh_set_freq(struct net_device *dev, struct iw_request_info *info, struct iw_freq *fwrq, char *extra) @@ -1066,7 +1061,6 @@ static int lbs_mesh_set_freq(struct net_device *dev, lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); return ret; } -#endif static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) @@ -2114,7 +2108,6 @@ static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info, return ret; } -#ifdef CONFIG_LIBERTAS_MESH static int lbs_mesh_get_essid(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) @@ -2168,7 +2161,6 @@ static int lbs_mesh_set_essid(struct net_device *dev, lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); return ret; } -#endif /** * @brief Connect to the AP or Ad-hoc Network with specific bssid @@ -2275,13 +2267,7 @@ static const iw_handler lbs_handler[] = { (iw_handler) lbs_get_encodeext,/* SIOCGIWENCODEEXT */ (iw_handler) NULL, /* SIOCSIWPMKSA */ }; -struct iw_handler_def lbs_handler_def = { - .num_standard = ARRAY_SIZE(lbs_handler), - .standard = (iw_handler *) lbs_handler, - .get_wireless_stats = lbs_get_wireless_stats, -}; -#ifdef CONFIG_LIBERTAS_MESH static const iw_handler mesh_wlan_handler[] = { (iw_handler) NULL, /* SIOCSIWCOMMIT */ (iw_handler) lbs_get_name, /* SIOCGIWNAME */ @@ -2339,10 +2325,14 @@ static const iw_handler mesh_wlan_handler[] = { (iw_handler) lbs_get_encodeext,/* SIOCGIWENCODEEXT */ (iw_handler) NULL, /* SIOCSIWPMKSA */ }; +struct iw_handler_def lbs_handler_def = { + .num_standard = ARRAY_SIZE(lbs_handler), + .standard = (iw_handler *) lbs_handler, + .get_wireless_stats = lbs_get_wireless_stats, +}; struct iw_handler_def mesh_handler_def = { .num_standard = ARRAY_SIZE(mesh_wlan_handler), .standard = (iw_handler *) mesh_wlan_handler, .get_wireless_stats = lbs_get_wireless_stats, }; -#endif diff --git a/trunk/drivers/net/wireless/libertas_tf/main.c b/trunk/drivers/net/wireless/libertas_tf/main.c index 6ab30033c26c..26a1abd5bb03 100644 --- a/trunk/drivers/net/wireless/libertas_tf/main.c +++ b/trunk/drivers/net/wireless/libertas_tf/main.c @@ -318,14 +318,14 @@ static void lbtf_op_stop(struct ieee80211_hw *hw) } static int lbtf_op_add_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) + struct ieee80211_if_init_conf *conf) { struct lbtf_private *priv = hw->priv; if (priv->vif != NULL) return -EOPNOTSUPP; - priv->vif = vif; - switch (vif->type) { + priv->vif = conf->vif; + switch (conf->type) { case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_AP: lbtf_set_mode(priv, LBTF_AP_MODE); @@ -337,12 +337,12 @@ static int lbtf_op_add_interface(struct ieee80211_hw *hw, priv->vif = NULL; return -EOPNOTSUPP; } - lbtf_set_mac_address(priv, (u8 *) vif->addr); + lbtf_set_mac_address(priv, (u8 *) conf->mac_addr); return 0; } static void lbtf_op_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) + struct ieee80211_if_init_conf *conf) { struct lbtf_private *priv = hw->priv; @@ -555,9 +555,6 @@ struct lbtf_private *lbtf_add_card(void *card, struct device *dmdev) priv->band.n_channels = ARRAY_SIZE(lbtf_channels); priv->band.channels = priv->channels; hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; - hw->wiphy->interface_modes = - BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC); skb_queue_head_init(&priv->bc_ps_buf); SET_IEEE80211_DEV(hw, dmdev); diff --git a/trunk/drivers/net/wireless/mac80211_hwsim.c b/trunk/drivers/net/wireless/mac80211_hwsim.c index 6ea77e95277b..88e41176e7fd 100644 --- a/trunk/drivers/net/wireless/mac80211_hwsim.c +++ b/trunk/drivers/net/wireless/mac80211_hwsim.c @@ -32,10 +32,6 @@ static int radios = 2; module_param(radios, int, 0444); MODULE_PARM_DESC(radios, "Number of simulated radios"); -static bool fake_hw_scan; -module_param(fake_hw_scan, bool, 0444); -MODULE_PARM_DESC(fake_hw_scan, "Install fake (no-op) hw-scan handler"); - /** * enum hwsim_regtest - the type of regulatory tests we offer * @@ -285,8 +281,6 @@ struct mac80211_hwsim_data { struct ieee80211_channel channels_5ghz[ARRAY_SIZE(hwsim_channels_5ghz)]; struct ieee80211_rate rates[ARRAY_SIZE(hwsim_rates)]; - struct mac_address addresses[2]; - struct ieee80211_channel *channel; unsigned long beacon_int; /* in jiffies unit */ unsigned int rx_filter; @@ -442,38 +436,6 @@ static bool hwsim_ps_rx_ok(struct mac80211_hwsim_data *data, } -struct mac80211_hwsim_addr_match_data { - bool ret; - const u8 *addr; -}; - -static void mac80211_hwsim_addr_iter(void *data, u8 *mac, - struct ieee80211_vif *vif) -{ - struct mac80211_hwsim_addr_match_data *md = data; - if (memcmp(mac, md->addr, ETH_ALEN) == 0) - md->ret = true; -} - - -static bool mac80211_hwsim_addr_match(struct mac80211_hwsim_data *data, - const u8 *addr) -{ - struct mac80211_hwsim_addr_match_data md; - - if (memcmp(addr, data->hw->wiphy->perm_addr, ETH_ALEN) == 0) - return true; - - md.ret = false; - md.addr = addr; - ieee80211_iterate_active_interfaces_atomic(data->hw, - mac80211_hwsim_addr_iter, - &md); - - return md.ret; -} - - static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, struct sk_buff *skb) { @@ -526,7 +488,8 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, if (nskb == NULL) continue; - if (mac80211_hwsim_addr_match(data2, hdr->addr1)) + if (memcmp(hdr->addr1, data2->hw->wiphy->perm_addr, + ETH_ALEN) == 0) ack = true; memcpy(IEEE80211_SKB_RXCB(nskb), &rx_status, sizeof(rx_status)); ieee80211_rx_irqsafe(data2->hw, nskb); @@ -590,24 +553,24 @@ static void mac80211_hwsim_stop(struct ieee80211_hw *hw) static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) + struct ieee80211_if_init_conf *conf) { printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%pM)\n", - wiphy_name(hw->wiphy), __func__, vif->type, - vif->addr); - hwsim_set_magic(vif); + wiphy_name(hw->wiphy), __func__, conf->type, + conf->mac_addr); + hwsim_set_magic(conf->vif); return 0; } static void mac80211_hwsim_remove_interface( - struct ieee80211_hw *hw, struct ieee80211_vif *vif) + struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%pM)\n", - wiphy_name(hw->wiphy), __func__, vif->type, - vif->addr); - hwsim_check_magic(vif); - hwsim_clear_magic(vif); + wiphy_name(hw->wiphy), __func__, conf->type, + conf->mac_addr); + hwsim_check_magic(conf->vif); + hwsim_clear_magic(conf->vif); } @@ -655,26 +618,12 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed) { struct mac80211_hwsim_data *data = hw->priv; struct ieee80211_conf *conf = &hw->conf; - static const char *chantypes[4] = { - [NL80211_CHAN_NO_HT] = "noht", - [NL80211_CHAN_HT20] = "ht20", - [NL80211_CHAN_HT40MINUS] = "ht40-", - [NL80211_CHAN_HT40PLUS] = "ht40+", - }; - static const char *smps_modes[IEEE80211_SMPS_NUM_MODES] = { - [IEEE80211_SMPS_AUTOMATIC] = "auto", - [IEEE80211_SMPS_OFF] = "off", - [IEEE80211_SMPS_STATIC] = "static", - [IEEE80211_SMPS_DYNAMIC] = "dynamic", - }; - - printk(KERN_DEBUG "%s:%s (freq=%d/%s idle=%d ps=%d smps=%s)\n", + + printk(KERN_DEBUG "%s:%s (freq=%d idle=%d ps=%d)\n", wiphy_name(hw->wiphy), __func__, conf->channel->center_freq, - chantypes[conf->channel_type], !!(conf->flags & IEEE80211_CONF_IDLE), - !!(conf->flags & IEEE80211_CONF_PS), - smps_modes[conf->smps_mode]); + !!(conf->flags & IEEE80211_CONF_PS)); data->idle = !!(conf->flags & IEEE80211_CONF_IDLE); @@ -771,41 +720,23 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw, } } -static int mac80211_hwsim_sta_add(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) -{ - hwsim_check_magic(vif); - hwsim_set_sta_magic(sta); - - return 0; -} - -static int mac80211_hwsim_sta_remove(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) -{ - hwsim_check_magic(vif); - hwsim_clear_sta_magic(sta); - - return 0; -} - static void mac80211_hwsim_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum sta_notify_cmd cmd, struct ieee80211_sta *sta) { hwsim_check_magic(vif); - switch (cmd) { + case STA_NOTIFY_ADD: + hwsim_set_sta_magic(sta); + break; + 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; - default: - WARN(1, "Invalid sta notify: %d\n", cmd); - break; } } @@ -896,77 +827,7 @@ static int mac80211_hwsim_testmode_cmd(struct ieee80211_hw *hw, } #endif -static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn) -{ - switch (action) { - case IEEE80211_AMPDU_TX_START: - ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); - break; - case IEEE80211_AMPDU_TX_STOP: - ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); - break; - case IEEE80211_AMPDU_TX_OPERATIONAL: - break; - case IEEE80211_AMPDU_RX_START: - case IEEE80211_AMPDU_RX_STOP: - break; - default: - return -EOPNOTSUPP; - } - - return 0; -} - -static void mac80211_hwsim_flush(struct ieee80211_hw *hw, bool drop) -{ - /* - * In this special case, there's nothing we need to - * do because hwsim does transmission synchronously. - * In the future, when it does transmissions via - * userspace, we may need to do something. - */ -} - -struct hw_scan_done { - struct delayed_work w; - struct ieee80211_hw *hw; -}; - -static void hw_scan_done(struct work_struct *work) -{ - struct hw_scan_done *hsd = - container_of(work, struct hw_scan_done, w.work); - - ieee80211_scan_completed(hsd->hw, false); - kfree(hsd); -} - -static int mac80211_hwsim_hw_scan(struct ieee80211_hw *hw, - struct cfg80211_scan_request *req) -{ - struct hw_scan_done *hsd = kzalloc(sizeof(*hsd), GFP_KERNEL); - int i; - - if (!hsd) - return -ENOMEM; - - hsd->hw = hw; - INIT_DELAYED_WORK(&hsd->w, hw_scan_done); - - printk(KERN_DEBUG "hwsim scan request\n"); - for (i = 0; i < req->n_channels; i++) - printk(KERN_DEBUG "hwsim scan freq %d\n", - req->channels[i]->center_freq); - - ieee80211_queue_delayed_work(hw, &hsd->w, 2 * HZ); - - return 0; -} - -static struct ieee80211_ops mac80211_hwsim_ops = +static const struct ieee80211_ops mac80211_hwsim_ops = { .tx = mac80211_hwsim_tx, .start = mac80211_hwsim_start, @@ -976,14 +837,10 @@ static struct ieee80211_ops mac80211_hwsim_ops = .config = mac80211_hwsim_config, .configure_filter = mac80211_hwsim_configure_filter, .bss_info_changed = mac80211_hwsim_bss_info_changed, - .sta_add = mac80211_hwsim_sta_add, - .sta_remove = mac80211_hwsim_sta_remove, .sta_notify = mac80211_hwsim_sta_notify, .set_tim = mac80211_hwsim_set_tim, .conf_tx = mac80211_hwsim_conf_tx, CFG80211_TESTMODE_CMD(mac80211_hwsim_testmode_cmd) - .ampdu_action = mac80211_hwsim_ampdu_action, - .flush = mac80211_hwsim_flush, }; @@ -1178,9 +1035,6 @@ static int __init init_mac80211_hwsim(void) if (radios < 1 || radios > 100) return -EINVAL; - if (fake_hw_scan) - mac80211_hwsim_ops.hw_scan = mac80211_hwsim_hw_scan; - spin_lock_init(&hwsim_radio_lock); INIT_LIST_HEAD(&hwsim_radios); @@ -1218,11 +1072,7 @@ static int __init init_mac80211_hwsim(void) SET_IEEE80211_DEV(hw, data->dev); addr[3] = i >> 8; addr[4] = i; - memcpy(data->addresses[0].addr, addr, ETH_ALEN); - memcpy(data->addresses[1].addr, addr, ETH_ALEN); - data->addresses[1].addr[0] |= 0x40; - hw->wiphy->n_addresses = 2; - hw->wiphy->addresses = data->addresses; + SET_IEEE80211_PERM_ADDR(hw, addr); hw->channel_change_time = 1; hw->queues = 4; @@ -1232,9 +1082,7 @@ static int __init init_mac80211_hwsim(void) BIT(NL80211_IFTYPE_MESH_POINT); hw->flags = IEEE80211_HW_MFP_CAPABLE | - IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_SUPPORTS_STATIC_SMPS | - IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS; + IEEE80211_HW_SIGNAL_DBM; /* ask mac80211 to reserve space for magic */ hw->vif_data_size = sizeof(struct hwsim_vif_priv); diff --git a/trunk/drivers/net/wireless/mwl8k.c b/trunk/drivers/net/wireless/mwl8k.c index ac65e13eb0de..59f92105b0c2 100644 --- a/trunk/drivers/net/wireless/mwl8k.c +++ b/trunk/drivers/net/wireless/mwl8k.c @@ -2,7 +2,7 @@ * drivers/net/wireless/mwl8k.c * Driver for Marvell TOPDOG 802.11 Wireless cards * - * Copyright (C) 2008, 2009, 2010 Marvell Semiconductor Inc. + * Copyright (C) 2008-2009 Marvell Semiconductor Inc. * * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any @@ -26,7 +26,7 @@ #define MWL8K_DESC "Marvell TOPDOG(R) 802.11 Wireless Network Driver" #define MWL8K_NAME KBUILD_MODNAME -#define MWL8K_VERSION "0.12" +#define MWL8K_VERSION "0.10" /* Register definitions */ #define MWL8K_HIU_GEN_PTR 0x00000c10 @@ -92,7 +92,8 @@ struct mwl8k_device_info { char *part_name; char *helper_image; char *fw_image; - struct rxd_ops *ap_rxd_ops; + struct rxd_ops *rxd_ops; + u16 modes; }; struct mwl8k_rx_queue { @@ -119,36 +120,34 @@ struct mwl8k_tx_queue { /* sw appends here */ int tail; - unsigned int len; + struct ieee80211_tx_queue_stats stats; struct mwl8k_tx_desc *txd; dma_addr_t txd_dma; struct sk_buff **skb; }; -struct mwl8k_priv { - struct ieee80211_hw *hw; - struct pci_dev *pdev; +/* Pointers to the firmware data and meta information about it. */ +struct mwl8k_firmware { + /* Boot helper code */ + struct firmware *helper; - struct mwl8k_device_info *device_info; + /* Microcode */ + struct firmware *ucode; +}; +struct mwl8k_priv { void __iomem *sram; void __iomem *regs; + struct ieee80211_hw *hw; - /* firmware */ - struct firmware *fw_helper; - struct firmware *fw_ucode; + struct pci_dev *pdev; - /* hardware/firmware parameters */ + struct mwl8k_device_info *device_info; bool ap_fw; struct rxd_ops *rxd_ops; - struct ieee80211_supported_band band_24; - struct ieee80211_channel channels_24[14]; - struct ieee80211_rate rates_24[14]; - struct ieee80211_supported_band band_50; - struct ieee80211_channel channels_50[4]; - struct ieee80211_rate rates_50[9]; - u32 ap_macids_supported; - u32 sta_macids_supported; + + /* firmware files and meta data */ + struct mwl8k_firmware fw; /* firmware access */ struct mutex fw_mutex; @@ -162,9 +161,9 @@ struct mwl8k_priv { /* TX quiesce completion, protected by fw_mutex and tx_lock */ struct completion *tx_wait; - /* List of interfaces. */ - u32 macids_used; - struct list_head vif_list; + struct ieee80211_vif *vif; + + struct ieee80211_channel *current_channel; /* power management status cookie from firmware */ u32 *cookie; @@ -183,6 +182,11 @@ struct mwl8k_priv { struct mwl8k_rx_queue rxq[MWL8K_RX_QUEUES]; struct mwl8k_tx_queue txq[MWL8K_TX_QUEUES]; + /* PHY parameters */ + struct ieee80211_supported_band band; + struct ieee80211_channel channels[14]; + struct ieee80211_rate rates[14]; + bool radio_on; bool radio_short_preamble; bool sniffer_enabled; @@ -201,33 +205,32 @@ struct mwl8k_priv { */ struct work_struct finalize_join_worker; - /* Tasklet to perform TX reclaim. */ - struct tasklet_struct poll_tx_task; - - /* Tasklet to perform RX. */ - struct tasklet_struct poll_rx_task; + /* Tasklet to reclaim TX descriptors and buffers after tx */ + struct tasklet_struct tx_reclaim_task; }; /* Per interface specific private data */ struct mwl8k_vif { - struct list_head list; - struct ieee80211_vif *vif; + /* backpointer to parent config block */ + struct mwl8k_priv *priv; - /* Firmware macid for this vif. */ - int macid; + /* BSS config of AP or IBSS from mac80211*/ + struct ieee80211_bss_conf bss_info; - /* Non AMPDU sequence number assigned by driver. */ - u16 seqno; -}; -#define MWL8K_VIF(_vif) ((struct mwl8k_vif *)&((_vif)->drv_priv)) + /* BSSID of AP or IBSS */ + u8 bssid[ETH_ALEN]; + u8 mac_addr[ETH_ALEN]; + + /* Index into station database.Returned by update_sta_db call */ + u8 peer_id; -struct mwl8k_sta { - /* Index into station database. Returned by UPDATE_STADB. */ - u8 peer_id; + /* Non AMPDU sequence number assigned by driver */ + u16 seqno; }; -#define MWL8K_STA(_sta) ((struct mwl8k_sta *)&((_sta)->drv_priv)) -static const struct ieee80211_channel mwl8k_channels_24[] = { +#define MWL8K_VIF(_vif) ((struct mwl8k_vif *)&((_vif)->drv_priv)) + +static const struct ieee80211_channel mwl8k_channels[] = { { .center_freq = 2412, .hw_value = 1, }, { .center_freq = 2417, .hw_value = 2, }, { .center_freq = 2422, .hw_value = 3, }, @@ -239,12 +242,9 @@ static const struct ieee80211_channel mwl8k_channels_24[] = { { .center_freq = 2452, .hw_value = 9, }, { .center_freq = 2457, .hw_value = 10, }, { .center_freq = 2462, .hw_value = 11, }, - { .center_freq = 2467, .hw_value = 12, }, - { .center_freq = 2472, .hw_value = 13, }, - { .center_freq = 2484, .hw_value = 14, }, }; -static const struct ieee80211_rate mwl8k_rates_24[] = { +static const struct ieee80211_rate mwl8k_rates[] = { { .bitrate = 10, .hw_value = 2, }, { .bitrate = 20, .hw_value = 4, }, { .bitrate = 55, .hw_value = 11, }, @@ -261,23 +261,8 @@ static const struct ieee80211_rate mwl8k_rates_24[] = { { .bitrate = 720, .hw_value = 144, }, }; -static const struct ieee80211_channel mwl8k_channels_50[] = { - { .center_freq = 5180, .hw_value = 36, }, - { .center_freq = 5200, .hw_value = 40, }, - { .center_freq = 5220, .hw_value = 44, }, - { .center_freq = 5240, .hw_value = 48, }, -}; - -static const struct ieee80211_rate mwl8k_rates_50[] = { - { .bitrate = 60, .hw_value = 12, }, - { .bitrate = 90, .hw_value = 18, }, - { .bitrate = 120, .hw_value = 24, }, - { .bitrate = 180, .hw_value = 36, }, - { .bitrate = 240, .hw_value = 48, }, - { .bitrate = 360, .hw_value = 72, }, - { .bitrate = 480, .hw_value = 96, }, - { .bitrate = 540, .hw_value = 108, }, - { .bitrate = 720, .hw_value = 144, }, +static const u8 mwl8k_rateids[12] = { + 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108, }; /* Set or get info from Firmware */ @@ -293,7 +278,6 @@ static const struct ieee80211_rate mwl8k_rates_50[] = { #define MWL8K_CMD_RADIO_CONTROL 0x001c #define MWL8K_CMD_RF_TX_POWER 0x001e #define MWL8K_CMD_RF_ANTENNA 0x0020 -#define MWL8K_CMD_SET_BEACON 0x0100 /* per-vif */ #define MWL8K_CMD_SET_PRE_SCAN 0x0107 #define MWL8K_CMD_SET_POST_SCAN 0x0108 #define MWL8K_CMD_SET_RF_CHANNEL 0x010a @@ -307,10 +291,8 @@ static const struct ieee80211_rate mwl8k_rates_50[] = { #define MWL8K_CMD_MIMO_CONFIG 0x0125 #define MWL8K_CMD_USE_FIXED_RATE 0x0126 #define MWL8K_CMD_ENABLE_SNIFFER 0x0150 -#define MWL8K_CMD_SET_MAC_ADDR 0x0202 /* per-vif */ +#define MWL8K_CMD_SET_MAC_ADDR 0x0202 #define MWL8K_CMD_SET_RATEADAPT_MODE 0x0203 -#define MWL8K_CMD_BSS_START 0x1100 /* per-vif */ -#define MWL8K_CMD_SET_NEW_STN 0x1111 /* per-vif */ #define MWL8K_CMD_UPDATE_STADB 0x1123 static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize) @@ -328,7 +310,6 @@ static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize) MWL8K_CMDNAME(RADIO_CONTROL); MWL8K_CMDNAME(RF_TX_POWER); MWL8K_CMDNAME(RF_ANTENNA); - MWL8K_CMDNAME(SET_BEACON); MWL8K_CMDNAME(SET_PRE_SCAN); MWL8K_CMDNAME(SET_POST_SCAN); MWL8K_CMDNAME(SET_RF_CHANNEL); @@ -344,8 +325,6 @@ static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize) MWL8K_CMDNAME(ENABLE_SNIFFER); MWL8K_CMDNAME(SET_MAC_ADDR); MWL8K_CMDNAME(SET_RATEADAPT_MODE); - MWL8K_CMDNAME(BSS_START); - MWL8K_CMDNAME(SET_NEW_STN); MWL8K_CMDNAME(UPDATE_STADB); default: snprintf(buf, bufsize, "0x%x", cmd); @@ -376,8 +355,8 @@ static void mwl8k_release_fw(struct firmware **fw) static void mwl8k_release_firmware(struct mwl8k_priv *priv) { - mwl8k_release_fw(&priv->fw_ucode); - mwl8k_release_fw(&priv->fw_helper); + mwl8k_release_fw(&priv->fw.ucode); + mwl8k_release_fw(&priv->fw.helper); } /* Request fw image */ @@ -398,7 +377,7 @@ static int mwl8k_request_firmware(struct mwl8k_priv *priv) int rc; if (di->helper_image != NULL) { - rc = mwl8k_request_fw(priv, di->helper_image, &priv->fw_helper); + rc = mwl8k_request_fw(priv, di->helper_image, &priv->fw.helper); if (rc) { printk(KERN_ERR "%s: Error requesting helper " "firmware file %s\n", pci_name(priv->pdev), @@ -407,22 +386,24 @@ static int mwl8k_request_firmware(struct mwl8k_priv *priv) } } - rc = mwl8k_request_fw(priv, di->fw_image, &priv->fw_ucode); + rc = mwl8k_request_fw(priv, di->fw_image, &priv->fw.ucode); if (rc) { printk(KERN_ERR "%s: Error requesting firmware file %s\n", pci_name(priv->pdev), di->fw_image); - mwl8k_release_fw(&priv->fw_helper); + mwl8k_release_fw(&priv->fw.helper); return rc; } return 0; } +MODULE_FIRMWARE("mwl8k/helper_8687.fw"); +MODULE_FIRMWARE("mwl8k/fmimage_8687.fw"); + struct mwl8k_cmd_pkt { __le16 code; __le16 length; - __u8 seq_num; - __u8 macid; + __le16 seq_num; __le16 result; char payload[0]; } __attribute__((packed)); @@ -480,7 +461,6 @@ static int mwl8k_load_fw_image(struct mwl8k_priv *priv, cmd->code = cpu_to_le16(MWL8K_CMD_CODE_DNLD); cmd->seq_num = 0; - cmd->macid = 0; cmd->result = 0; done = 0; @@ -571,12 +551,13 @@ static int mwl8k_feed_fw_image(struct mwl8k_priv *priv, static int mwl8k_load_firmware(struct ieee80211_hw *hw) { struct mwl8k_priv *priv = hw->priv; - struct firmware *fw = priv->fw_ucode; + struct firmware *fw = priv->fw.ucode; + struct mwl8k_device_info *di = priv->device_info; int rc; int loops; if (!memcmp(fw->data, "\x01\x00\x00\x00", 4)) { - struct firmware *helper = priv->fw_helper; + struct firmware *helper = priv->fw.helper; if (helper == NULL) { printk(KERN_ERR "%s: helper image needed but none " @@ -603,7 +584,10 @@ static int mwl8k_load_firmware(struct ieee80211_hw *hw) return rc; } - iowrite32(MWL8K_MODE_STA, priv->regs + MWL8K_HIU_GEN_PTR); + if (di->modes & BIT(NL80211_IFTYPE_AP)) + iowrite32(MWL8K_MODE_AP, priv->regs + MWL8K_HIU_GEN_PTR); + else + iowrite32(MWL8K_MODE_STA, priv->regs + MWL8K_HIU_GEN_PTR); loops = 500000; do { @@ -626,6 +610,91 @@ static int mwl8k_load_firmware(struct ieee80211_hw *hw) } +/* + * Defines shared between transmission and reception. + */ +/* HT control fields for firmware */ +struct ewc_ht_info { + __le16 control1; + __le16 control2; + __le16 control3; +} __attribute__((packed)); + +/* Firmware Station database operations */ +#define MWL8K_STA_DB_ADD_ENTRY 0 +#define MWL8K_STA_DB_MODIFY_ENTRY 1 +#define MWL8K_STA_DB_DEL_ENTRY 2 +#define MWL8K_STA_DB_FLUSH 3 + +/* Peer Entry flags - used to define the type of the peer node */ +#define MWL8K_PEER_TYPE_ACCESSPOINT 2 + +struct peer_capability_info { + /* Peer type - AP vs. STA. */ + __u8 peer_type; + + /* Basic 802.11 capabilities from assoc resp. */ + __le16 basic_caps; + + /* Set if peer supports 802.11n high throughput (HT). */ + __u8 ht_support; + + /* Valid if HT is supported. */ + __le16 ht_caps; + __u8 extended_ht_caps; + struct ewc_ht_info ewc_info; + + /* Legacy rate table. Intersection of our rates and peer rates. */ + __u8 legacy_rates[12]; + + /* HT rate table. Intersection of our rates and peer rates. */ + __u8 ht_rates[16]; + __u8 pad[16]; + + /* If set, interoperability mode, no proprietary extensions. */ + __u8 interop; + __u8 pad2; + __u8 station_id; + __le16 amsdu_enabled; +} __attribute__((packed)); + +/* Inline functions to manipulate QoS field in data descriptor. */ +static inline u16 mwl8k_qos_setbit_eosp(u16 qos) +{ + u16 val_mask = 1 << 4; + + /* End of Service Period Bit 4 */ + return qos | val_mask; +} + +static inline u16 mwl8k_qos_setbit_ack(u16 qos, u8 ack_policy) +{ + u16 val_mask = 0x3; + u8 shift = 5; + u16 qos_mask = ~(val_mask << shift); + + /* Ack Policy Bit 5-6 */ + return (qos & qos_mask) | ((ack_policy & val_mask) << shift); +} + +static inline u16 mwl8k_qos_setbit_amsdu(u16 qos) +{ + u16 val_mask = 1 << 7; + + /* AMSDU present Bit 7 */ + return qos | val_mask; +} + +static inline u16 mwl8k_qos_setbit_qlen(u16 qos, u8 len) +{ + u16 val_mask = 0xff; + u8 shift = 8; + u16 qos_mask = ~(val_mask << shift); + + /* Queue Length Bits 8-15 */ + return (qos & qos_mask) | ((len & val_mask) << shift); +} + /* DMA header used by firmware and hardware. */ struct mwl8k_dma_data { __le16 fwlen; @@ -692,9 +761,9 @@ static inline void mwl8k_add_dma_header(struct sk_buff *skb) /* - * Packet reception for 88w8366 AP firmware. + * Packet reception for 88w8366. */ -struct mwl8k_rxd_8366_ap { +struct mwl8k_rxd_8366 { __le16 pkt_len; __u8 sq2; __u8 rate; @@ -712,23 +781,23 @@ struct mwl8k_rxd_8366_ap { __u8 rx_ctrl; } __attribute__((packed)); -#define MWL8K_8366_AP_RATE_INFO_MCS_FORMAT 0x80 -#define MWL8K_8366_AP_RATE_INFO_40MHZ 0x40 -#define MWL8K_8366_AP_RATE_INFO_RATEID(x) ((x) & 0x3f) +#define MWL8K_8366_RATE_INFO_MCS_FORMAT 0x80 +#define MWL8K_8366_RATE_INFO_40MHZ 0x40 +#define MWL8K_8366_RATE_INFO_RATEID(x) ((x) & 0x3f) -#define MWL8K_8366_AP_RX_CTRL_OWNED_BY_HOST 0x80 +#define MWL8K_8366_RX_CTRL_OWNED_BY_HOST 0x80 -static void mwl8k_rxd_8366_ap_init(void *_rxd, dma_addr_t next_dma_addr) +static void mwl8k_rxd_8366_init(void *_rxd, dma_addr_t next_dma_addr) { - struct mwl8k_rxd_8366_ap *rxd = _rxd; + struct mwl8k_rxd_8366 *rxd = _rxd; rxd->next_rxd_phys_addr = cpu_to_le32(next_dma_addr); - rxd->rx_ctrl = MWL8K_8366_AP_RX_CTRL_OWNED_BY_HOST; + rxd->rx_ctrl = MWL8K_8366_RX_CTRL_OWNED_BY_HOST; } -static void mwl8k_rxd_8366_ap_refill(void *_rxd, dma_addr_t addr, int len) +static void mwl8k_rxd_8366_refill(void *_rxd, dma_addr_t addr, int len) { - struct mwl8k_rxd_8366_ap *rxd = _rxd; + struct mwl8k_rxd_8366 *rxd = _rxd; rxd->pkt_len = cpu_to_le16(len); rxd->pkt_phys_addr = cpu_to_le32(addr); @@ -737,12 +806,12 @@ static void mwl8k_rxd_8366_ap_refill(void *_rxd, dma_addr_t addr, int len) } static int -mwl8k_rxd_8366_ap_process(void *_rxd, struct ieee80211_rx_status *status, - __le16 *qos) +mwl8k_rxd_8366_process(void *_rxd, struct ieee80211_rx_status *status, + __le16 *qos) { - struct mwl8k_rxd_8366_ap *rxd = _rxd; + struct mwl8k_rxd_8366 *rxd = _rxd; - if (!(rxd->rx_ctrl & MWL8K_8366_AP_RX_CTRL_OWNED_BY_HOST)) + if (!(rxd->rx_ctrl & MWL8K_8366_RX_CTRL_OWNED_BY_HOST)) return -1; rmb(); @@ -751,29 +820,23 @@ mwl8k_rxd_8366_ap_process(void *_rxd, struct ieee80211_rx_status *status, status->signal = -rxd->rssi; status->noise = -rxd->noise_floor; - if (rxd->rate & MWL8K_8366_AP_RATE_INFO_MCS_FORMAT) { + if (rxd->rate & MWL8K_8366_RATE_INFO_MCS_FORMAT) { status->flag |= RX_FLAG_HT; - if (rxd->rate & MWL8K_8366_AP_RATE_INFO_40MHZ) + if (rxd->rate & MWL8K_8366_RATE_INFO_40MHZ) status->flag |= RX_FLAG_40MHZ; - status->rate_idx = MWL8K_8366_AP_RATE_INFO_RATEID(rxd->rate); + status->rate_idx = MWL8K_8366_RATE_INFO_RATEID(rxd->rate); } else { int i; - for (i = 0; i < ARRAY_SIZE(mwl8k_rates_24); i++) { - if (mwl8k_rates_24[i].hw_value == rxd->rate) { + for (i = 0; i < ARRAY_SIZE(mwl8k_rates); i++) { + if (mwl8k_rates[i].hw_value == rxd->rate) { status->rate_idx = i; break; } } } - if (rxd->channel > 14) { - status->band = IEEE80211_BAND_5GHZ; - if (!(status->flag & RX_FLAG_HT)) - status->rate_idx -= 5; - } else { - status->band = IEEE80211_BAND_2GHZ; - } + status->band = IEEE80211_BAND_2GHZ; status->freq = ieee80211_channel_to_frequency(rxd->channel); *qos = rxd->qos_control; @@ -781,17 +844,17 @@ mwl8k_rxd_8366_ap_process(void *_rxd, struct ieee80211_rx_status *status, return le16_to_cpu(rxd->pkt_len); } -static struct rxd_ops rxd_8366_ap_ops = { - .rxd_size = sizeof(struct mwl8k_rxd_8366_ap), - .rxd_init = mwl8k_rxd_8366_ap_init, - .rxd_refill = mwl8k_rxd_8366_ap_refill, - .rxd_process = mwl8k_rxd_8366_ap_process, +static struct rxd_ops rxd_8366_ops = { + .rxd_size = sizeof(struct mwl8k_rxd_8366), + .rxd_init = mwl8k_rxd_8366_init, + .rxd_refill = mwl8k_rxd_8366_refill, + .rxd_process = mwl8k_rxd_8366_process, }; /* - * Packet reception for STA firmware. + * Packet reception for 88w8687. */ -struct mwl8k_rxd_sta { +struct mwl8k_rxd_8687 { __le16 pkt_len; __u8 link_quality; __u8 noise_level; @@ -808,26 +871,26 @@ struct mwl8k_rxd_sta { __u8 pad2[2]; } __attribute__((packed)); -#define MWL8K_STA_RATE_INFO_SHORTPRE 0x8000 -#define MWL8K_STA_RATE_INFO_ANTSELECT(x) (((x) >> 11) & 0x3) -#define MWL8K_STA_RATE_INFO_RATEID(x) (((x) >> 3) & 0x3f) -#define MWL8K_STA_RATE_INFO_40MHZ 0x0004 -#define MWL8K_STA_RATE_INFO_SHORTGI 0x0002 -#define MWL8K_STA_RATE_INFO_MCS_FORMAT 0x0001 +#define MWL8K_8687_RATE_INFO_SHORTPRE 0x8000 +#define MWL8K_8687_RATE_INFO_ANTSELECT(x) (((x) >> 11) & 0x3) +#define MWL8K_8687_RATE_INFO_RATEID(x) (((x) >> 3) & 0x3f) +#define MWL8K_8687_RATE_INFO_40MHZ 0x0004 +#define MWL8K_8687_RATE_INFO_SHORTGI 0x0002 +#define MWL8K_8687_RATE_INFO_MCS_FORMAT 0x0001 -#define MWL8K_STA_RX_CTRL_OWNED_BY_HOST 0x02 +#define MWL8K_8687_RX_CTRL_OWNED_BY_HOST 0x02 -static void mwl8k_rxd_sta_init(void *_rxd, dma_addr_t next_dma_addr) +static void mwl8k_rxd_8687_init(void *_rxd, dma_addr_t next_dma_addr) { - struct mwl8k_rxd_sta *rxd = _rxd; + struct mwl8k_rxd_8687 *rxd = _rxd; rxd->next_rxd_phys_addr = cpu_to_le32(next_dma_addr); - rxd->rx_ctrl = MWL8K_STA_RX_CTRL_OWNED_BY_HOST; + rxd->rx_ctrl = MWL8K_8687_RX_CTRL_OWNED_BY_HOST; } -static void mwl8k_rxd_sta_refill(void *_rxd, dma_addr_t addr, int len) +static void mwl8k_rxd_8687_refill(void *_rxd, dma_addr_t addr, int len) { - struct mwl8k_rxd_sta *rxd = _rxd; + struct mwl8k_rxd_8687 *rxd = _rxd; rxd->pkt_len = cpu_to_le16(len); rxd->pkt_phys_addr = cpu_to_le32(addr); @@ -836,13 +899,13 @@ static void mwl8k_rxd_sta_refill(void *_rxd, dma_addr_t addr, int len) } static int -mwl8k_rxd_sta_process(void *_rxd, struct ieee80211_rx_status *status, +mwl8k_rxd_8687_process(void *_rxd, struct ieee80211_rx_status *status, __le16 *qos) { - struct mwl8k_rxd_sta *rxd = _rxd; + struct mwl8k_rxd_8687 *rxd = _rxd; u16 rate_info; - if (!(rxd->rx_ctrl & MWL8K_STA_RX_CTRL_OWNED_BY_HOST)) + if (!(rxd->rx_ctrl & MWL8K_8687_RX_CTRL_OWNED_BY_HOST)) return -1; rmb(); @@ -852,25 +915,19 @@ mwl8k_rxd_sta_process(void *_rxd, struct ieee80211_rx_status *status, status->signal = -rxd->rssi; status->noise = -rxd->noise_level; - status->antenna = MWL8K_STA_RATE_INFO_ANTSELECT(rate_info); - status->rate_idx = MWL8K_STA_RATE_INFO_RATEID(rate_info); + status->antenna = MWL8K_8687_RATE_INFO_ANTSELECT(rate_info); + status->rate_idx = MWL8K_8687_RATE_INFO_RATEID(rate_info); - if (rate_info & MWL8K_STA_RATE_INFO_SHORTPRE) + if (rate_info & MWL8K_8687_RATE_INFO_SHORTPRE) status->flag |= RX_FLAG_SHORTPRE; - if (rate_info & MWL8K_STA_RATE_INFO_40MHZ) + if (rate_info & MWL8K_8687_RATE_INFO_40MHZ) status->flag |= RX_FLAG_40MHZ; - if (rate_info & MWL8K_STA_RATE_INFO_SHORTGI) + if (rate_info & MWL8K_8687_RATE_INFO_SHORTGI) status->flag |= RX_FLAG_SHORT_GI; - if (rate_info & MWL8K_STA_RATE_INFO_MCS_FORMAT) + if (rate_info & MWL8K_8687_RATE_INFO_MCS_FORMAT) status->flag |= RX_FLAG_HT; - if (rxd->channel > 14) { - status->band = IEEE80211_BAND_5GHZ; - if (!(status->flag & RX_FLAG_HT)) - status->rate_idx -= 5; - } else { - status->band = IEEE80211_BAND_2GHZ; - } + status->band = IEEE80211_BAND_2GHZ; status->freq = ieee80211_channel_to_frequency(rxd->channel); *qos = rxd->qos_control; @@ -878,11 +935,11 @@ mwl8k_rxd_sta_process(void *_rxd, struct ieee80211_rx_status *status, return le16_to_cpu(rxd->pkt_len); } -static struct rxd_ops rxd_sta_ops = { - .rxd_size = sizeof(struct mwl8k_rxd_sta), - .rxd_init = mwl8k_rxd_sta_init, - .rxd_refill = mwl8k_rxd_sta_refill, - .rxd_process = mwl8k_rxd_sta_process, +static struct rxd_ops rxd_8687_ops = { + .rxd_size = sizeof(struct mwl8k_rxd_8687), + .rxd_init = mwl8k_rxd_8687_init, + .rxd_refill = mwl8k_rxd_8687_refill, + .rxd_process = mwl8k_rxd_8687_process, }; @@ -1096,18 +1153,16 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit) * Packet transmission. */ +/* Transmit packet ACK policy */ +#define MWL8K_TXD_ACK_POLICY_NORMAL 0 +#define MWL8K_TXD_ACK_POLICY_BLOCKACK 3 + #define MWL8K_TXD_STATUS_OK 0x00000001 #define MWL8K_TXD_STATUS_OK_RETRY 0x00000002 #define MWL8K_TXD_STATUS_OK_MORE_RETRY 0x00000004 #define MWL8K_TXD_STATUS_MULTICAST_TX 0x00000008 #define MWL8K_TXD_STATUS_FW_OWNED 0x80000000 -#define MWL8K_QOS_QLEN_UNSPEC 0xff00 -#define MWL8K_QOS_ACK_POLICY_MASK 0x0060 -#define MWL8K_QOS_ACK_POLICY_NORMAL 0x0000 -#define MWL8K_QOS_ACK_POLICY_BLOCKACK 0x0060 -#define MWL8K_QOS_EOSP 0x0010 - struct mwl8k_tx_desc { __le32 status; __u8 data_rate; @@ -1132,7 +1187,8 @@ static int mwl8k_txq_init(struct ieee80211_hw *hw, int index) int size; int i; - txq->len = 0; + memset(&txq->stats, 0, sizeof(struct ieee80211_tx_queue_stats)); + txq->stats.limit = MWL8K_TX_DESCS; txq->head = 0; txq->tail = 0; @@ -1208,7 +1264,7 @@ static void mwl8k_dump_tx_rings(struct ieee80211_hw *hw) printk(KERN_ERR "%s: txq[%d] len=%d head=%d tail=%d " "fw_owned=%d drv_owned=%d unused=%d\n", wiphy_name(hw->wiphy), i, - txq->len, txq->head, txq->tail, + txq->stats.len, txq->head, txq->tail, fw_owned, drv_owned, unused); } } @@ -1216,7 +1272,7 @@ static void mwl8k_dump_tx_rings(struct ieee80211_hw *hw) /* * Must be called with priv->fw_mutex held and tx queues stopped. */ -#define MWL8K_TX_WAIT_TIMEOUT_MS 5000 +#define MWL8K_TX_WAIT_TIMEOUT_MS 1000 static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) { @@ -1260,8 +1316,8 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) } if (priv->pending_tx_pkts < oldcount) { - printk(KERN_NOTICE "%s: waiting for tx rings " - "to drain (%d -> %d pkts)\n", + printk(KERN_NOTICE "%s: timeout waiting for tx " + "rings to drain (%d -> %d pkts), retrying\n", wiphy_name(hw->wiphy), oldcount, priv->pending_tx_pkts); retry = 1; @@ -1286,15 +1342,13 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) MWL8K_TXD_STATUS_OK_RETRY | \ MWL8K_TXD_STATUS_OK_MORE_RETRY)) -static int -mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) +static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force) { struct mwl8k_priv *priv = hw->priv; struct mwl8k_tx_queue *txq = priv->txq + index; - int processed; + int wake = 0; - processed = 0; - while (txq->len > 0 && limit--) { + while (txq->stats.len > 0) { int tx; struct mwl8k_tx_desc *tx_desc; unsigned long addr; @@ -1316,8 +1370,8 @@ mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) } txq->head = (tx + 1) % MWL8K_TX_DESCS; - BUG_ON(txq->len == 0); - txq->len--; + BUG_ON(txq->stats.len == 0); + txq->stats.len--; priv->pending_tx_pkts--; addr = le32_to_cpu(tx_desc->pkt_phys_addr); @@ -1341,13 +1395,11 @@ mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) ieee80211_tx_status_irqsafe(hw, skb); - processed++; + wake = 1; } - if (processed && priv->radio_on && !mutex_is_locked(&priv->fw_mutex)) + if (wake && priv->radio_on && !mutex_is_locked(&priv->fw_mutex)) ieee80211_wake_queue(hw, index); - - return processed; } /* must be called only when the card's transmit is completely halted */ @@ -1356,7 +1408,7 @@ static void mwl8k_txq_deinit(struct ieee80211_hw *hw, int index) struct mwl8k_priv *priv = hw->priv; struct mwl8k_tx_queue *txq = priv->txq + index; - mwl8k_txq_reclaim(hw, index, INT_MAX, 1); + mwl8k_txq_reclaim(hw, index, 1); kfree(txq->skb); txq->skb = NULL; @@ -1394,9 +1446,11 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) mwl8k_vif = MWL8K_VIF(tx_info->control.vif); if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { + u16 seqno = mwl8k_vif->seqno; + wh->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); - wh->seq_ctrl |= cpu_to_le16(mwl8k_vif->seqno); - mwl8k_vif->seqno += 0x10; + wh->seq_ctrl |= cpu_to_le16(seqno << 4); + mwl8k_vif->seqno = seqno++ % 4096; } /* Setup firmware control bit fields for each frame type. */ @@ -1405,17 +1459,24 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) if (ieee80211_is_mgmt(wh->frame_control) || ieee80211_is_ctl(wh->frame_control)) { txdatarate = 0; - qos |= MWL8K_QOS_QLEN_UNSPEC | MWL8K_QOS_EOSP; + qos = mwl8k_qos_setbit_eosp(qos); + /* Set Queue size to unspecified */ + qos = mwl8k_qos_setbit_qlen(qos, 0xff); } else if (ieee80211_is_data(wh->frame_control)) { txdatarate = 1; if (is_multicast_ether_addr(wh->addr1)) txstatus |= MWL8K_TXD_STATUS_MULTICAST_TX; - qos &= ~MWL8K_QOS_ACK_POLICY_MASK; + /* Send pkt in an aggregate if AMPDU frame. */ if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) - qos |= MWL8K_QOS_ACK_POLICY_BLOCKACK; + qos = mwl8k_qos_setbit_ack(qos, + MWL8K_TXD_ACK_POLICY_BLOCKACK); else - qos |= MWL8K_QOS_ACK_POLICY_NORMAL; + qos = mwl8k_qos_setbit_ack(qos, + MWL8K_TXD_ACK_POLICY_NORMAL); + + if (qos & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT) + qos = mwl8k_qos_setbit_amsdu(qos); } dma = pci_map_single(priv->pdev, skb->data, @@ -1442,14 +1503,12 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) tx->pkt_phys_addr = cpu_to_le32(dma); tx->pkt_len = cpu_to_le16(skb->len); tx->rate_info = 0; - if (!priv->ap_fw && tx_info->control.sta != NULL) - tx->peer_id = MWL8K_STA(tx_info->control.sta)->peer_id; - else - tx->peer_id = 0; + tx->peer_id = mwl8k_vif->peer_id; wmb(); tx->status = cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED | txstatus); - txq->len++; + txq->stats.count++; + txq->stats.len++; priv->pending_tx_pkts++; txq->tail++; @@ -1597,56 +1656,6 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) return rc; } -static int mwl8k_post_pervif_cmd(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct mwl8k_cmd_pkt *cmd) -{ - if (vif != NULL) - cmd->macid = MWL8K_VIF(vif)->macid; - return mwl8k_post_cmd(hw, cmd); -} - -/* - * Setup code shared between STA and AP firmware images. - */ -static void mwl8k_setup_2ghz_band(struct ieee80211_hw *hw) -{ - struct mwl8k_priv *priv = hw->priv; - - BUILD_BUG_ON(sizeof(priv->channels_24) != sizeof(mwl8k_channels_24)); - memcpy(priv->channels_24, mwl8k_channels_24, sizeof(mwl8k_channels_24)); - - BUILD_BUG_ON(sizeof(priv->rates_24) != sizeof(mwl8k_rates_24)); - memcpy(priv->rates_24, mwl8k_rates_24, sizeof(mwl8k_rates_24)); - - priv->band_24.band = IEEE80211_BAND_2GHZ; - priv->band_24.channels = priv->channels_24; - priv->band_24.n_channels = ARRAY_SIZE(mwl8k_channels_24); - priv->band_24.bitrates = priv->rates_24; - priv->band_24.n_bitrates = ARRAY_SIZE(mwl8k_rates_24); - - hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band_24; -} - -static void mwl8k_setup_5ghz_band(struct ieee80211_hw *hw) -{ - struct mwl8k_priv *priv = hw->priv; - - BUILD_BUG_ON(sizeof(priv->channels_50) != sizeof(mwl8k_channels_50)); - memcpy(priv->channels_50, mwl8k_channels_50, sizeof(mwl8k_channels_50)); - - BUILD_BUG_ON(sizeof(priv->rates_50) != sizeof(mwl8k_rates_50)); - memcpy(priv->rates_50, mwl8k_rates_50, sizeof(mwl8k_rates_50)); - - priv->band_50.band = IEEE80211_BAND_5GHZ; - priv->band_50.channels = priv->channels_50; - priv->band_50.n_channels = ARRAY_SIZE(mwl8k_channels_50); - priv->band_50.bitrates = priv->rates_50; - priv->band_50.n_bitrates = ARRAY_SIZE(mwl8k_rates_50); - - hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &priv->band_50; -} - /* * CMD_GET_HW_SPEC (STA version). */ @@ -1669,89 +1678,6 @@ struct mwl8k_cmd_get_hw_spec_sta { __le32 total_rxd; } __attribute__((packed)); -#define MWL8K_CAP_MAX_AMSDU 0x20000000 -#define MWL8K_CAP_GREENFIELD 0x08000000 -#define MWL8K_CAP_AMPDU 0x04000000 -#define MWL8K_CAP_RX_STBC 0x01000000 -#define MWL8K_CAP_TX_STBC 0x00800000 -#define MWL8K_CAP_SHORTGI_40MHZ 0x00400000 -#define MWL8K_CAP_SHORTGI_20MHZ 0x00200000 -#define MWL8K_CAP_RX_ANTENNA_MASK 0x000e0000 -#define MWL8K_CAP_TX_ANTENNA_MASK 0x0001c000 -#define MWL8K_CAP_DELAY_BA 0x00003000 -#define MWL8K_CAP_MIMO 0x00000200 -#define MWL8K_CAP_40MHZ 0x00000100 -#define MWL8K_CAP_BAND_MASK 0x00000007 -#define MWL8K_CAP_5GHZ 0x00000004 -#define MWL8K_CAP_2GHZ4 0x00000001 - -static void -mwl8k_set_ht_caps(struct ieee80211_hw *hw, - struct ieee80211_supported_band *band, u32 cap) -{ - int rx_streams; - int tx_streams; - - band->ht_cap.ht_supported = 1; - - if (cap & MWL8K_CAP_MAX_AMSDU) - band->ht_cap.cap |= IEEE80211_HT_CAP_MAX_AMSDU; - if (cap & MWL8K_CAP_GREENFIELD) - band->ht_cap.cap |= IEEE80211_HT_CAP_GRN_FLD; - if (cap & MWL8K_CAP_AMPDU) { - hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION; - band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; - band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE; - } - if (cap & MWL8K_CAP_RX_STBC) - band->ht_cap.cap |= IEEE80211_HT_CAP_RX_STBC; - if (cap & MWL8K_CAP_TX_STBC) - band->ht_cap.cap |= IEEE80211_HT_CAP_TX_STBC; - if (cap & MWL8K_CAP_SHORTGI_40MHZ) - band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40; - if (cap & MWL8K_CAP_SHORTGI_20MHZ) - band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20; - if (cap & MWL8K_CAP_DELAY_BA) - band->ht_cap.cap |= IEEE80211_HT_CAP_DELAY_BA; - if (cap & MWL8K_CAP_40MHZ) - band->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; - - rx_streams = hweight32(cap & MWL8K_CAP_RX_ANTENNA_MASK); - tx_streams = hweight32(cap & MWL8K_CAP_TX_ANTENNA_MASK); - - band->ht_cap.mcs.rx_mask[0] = 0xff; - if (rx_streams >= 2) - band->ht_cap.mcs.rx_mask[1] = 0xff; - if (rx_streams >= 3) - band->ht_cap.mcs.rx_mask[2] = 0xff; - band->ht_cap.mcs.rx_mask[4] = 0x01; - band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; - - if (rx_streams != tx_streams) { - band->ht_cap.mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; - band->ht_cap.mcs.tx_params |= (tx_streams - 1) << - IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT; - } -} - -static void -mwl8k_set_caps(struct ieee80211_hw *hw, u32 caps) -{ - struct mwl8k_priv *priv = hw->priv; - - if ((caps & MWL8K_CAP_2GHZ4) || !(caps & MWL8K_CAP_BAND_MASK)) { - mwl8k_setup_2ghz_band(hw); - if (caps & MWL8K_CAP_MIMO) - mwl8k_set_ht_caps(hw, &priv->band_24, caps); - } - - if (caps & MWL8K_CAP_5GHZ) { - mwl8k_setup_5ghz_band(hw); - if (caps & MWL8K_CAP_MIMO) - mwl8k_set_ht_caps(hw, &priv->band_50, caps); - } -} - static int mwl8k_cmd_get_hw_spec_sta(struct ieee80211_hw *hw) { struct mwl8k_priv *priv = hw->priv; @@ -1782,9 +1708,6 @@ static int mwl8k_cmd_get_hw_spec_sta(struct ieee80211_hw *hw) priv->num_mcaddrs = le16_to_cpu(cmd->num_mcaddrs); priv->fw_rev = le32_to_cpu(cmd->fw_rev); priv->hw_rev = cmd->hw_rev; - mwl8k_set_caps(hw, le32_to_cpu(cmd->caps)); - priv->ap_macids_supported = 0x00000000; - priv->sta_macids_supported = 0x00000001; } kfree(cmd); @@ -1838,9 +1761,6 @@ static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw) priv->num_mcaddrs = le16_to_cpu(cmd->num_mcaddrs); priv->fw_rev = le32_to_cpu(cmd->fw_rev); priv->hw_rev = cmd->hw_rev; - mwl8k_setup_2ghz_band(hw); - priv->ap_macids_supported = 0x000000ff; - priv->sta_macids_supported = 0x00000000; off = le32_to_cpu(cmd->wcbbase0) & 0xffff; iowrite32(cpu_to_le32(priv->txq[0].txd_dma), priv->sram + off); @@ -1886,9 +1806,7 @@ struct mwl8k_cmd_set_hw_spec { __le32 total_rxd; } __attribute__((packed)); -#define MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT 0x00000080 -#define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP 0x00000020 -#define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON 0x00000010 +#define MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT 0x00000080 static int mwl8k_cmd_set_hw_spec(struct ieee80211_hw *hw) { @@ -1909,9 +1827,7 @@ static int mwl8k_cmd_set_hw_spec(struct ieee80211_hw *hw) cmd->num_tx_queues = cpu_to_le32(MWL8K_TX_QUEUES); for (i = 0; i < MWL8K_TX_QUEUES; i++) cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[i].txd_dma); - cmd->flags = cpu_to_le32(MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT | - MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP | - MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON); + cmd->flags = cpu_to_le32(MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT); cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS); cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS); @@ -1981,9 +1897,9 @@ __mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, int allmulti, } /* - * CMD_GET_STAT. + * CMD_802_11_GET_STAT. */ -struct mwl8k_cmd_get_stat { +struct mwl8k_cmd_802_11_get_stat { struct mwl8k_cmd_pkt header; __le32 stats[64]; } __attribute__((packed)); @@ -1993,10 +1909,10 @@ struct mwl8k_cmd_get_stat { #define MWL8K_STAT_FCS_ERROR 24 #define MWL8K_STAT_RTS_SUCCESS 11 -static int mwl8k_cmd_get_stat(struct ieee80211_hw *hw, - struct ieee80211_low_level_stats *stats) +static int mwl8k_cmd_802_11_get_stat(struct ieee80211_hw *hw, + struct ieee80211_low_level_stats *stats) { - struct mwl8k_cmd_get_stat *cmd; + struct mwl8k_cmd_802_11_get_stat *cmd; int rc; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); @@ -2023,9 +1939,9 @@ static int mwl8k_cmd_get_stat(struct ieee80211_hw *hw, } /* - * CMD_RADIO_CONTROL. + * CMD_802_11_RADIO_CONTROL. */ -struct mwl8k_cmd_radio_control { +struct mwl8k_cmd_802_11_radio_control { struct mwl8k_cmd_pkt header; __le16 action; __le16 control; @@ -2033,10 +1949,10 @@ struct mwl8k_cmd_radio_control { } __attribute__((packed)); static int -mwl8k_cmd_radio_control(struct ieee80211_hw *hw, bool enable, bool force) +mwl8k_cmd_802_11_radio_control(struct ieee80211_hw *hw, bool enable, bool force) { struct mwl8k_priv *priv = hw->priv; - struct mwl8k_cmd_radio_control *cmd; + struct mwl8k_cmd_802_11_radio_control *cmd; int rc; if (enable == priv->radio_on && !force) @@ -2061,32 +1977,36 @@ mwl8k_cmd_radio_control(struct ieee80211_hw *hw, bool enable, bool force) return rc; } -static int mwl8k_cmd_radio_disable(struct ieee80211_hw *hw) +static int mwl8k_cmd_802_11_radio_disable(struct ieee80211_hw *hw) { - return mwl8k_cmd_radio_control(hw, 0, 0); + return mwl8k_cmd_802_11_radio_control(hw, 0, 0); } -static int mwl8k_cmd_radio_enable(struct ieee80211_hw *hw) +static int mwl8k_cmd_802_11_radio_enable(struct ieee80211_hw *hw) { - return mwl8k_cmd_radio_control(hw, 1, 0); + return mwl8k_cmd_802_11_radio_control(hw, 1, 0); } static int mwl8k_set_radio_preamble(struct ieee80211_hw *hw, bool short_preamble) { - struct mwl8k_priv *priv = hw->priv; + struct mwl8k_priv *priv; + + if (hw == NULL || hw->priv == NULL) + return -EINVAL; + priv = hw->priv; priv->radio_short_preamble = short_preamble; - return mwl8k_cmd_radio_control(hw, 1, 1); + return mwl8k_cmd_802_11_radio_control(hw, 1, 1); } /* - * CMD_RF_TX_POWER. + * CMD_802_11_RF_TX_POWER. */ #define MWL8K_TX_POWER_LEVEL_TOTAL 8 -struct mwl8k_cmd_rf_tx_power { +struct mwl8k_cmd_802_11_rf_tx_power { struct mwl8k_cmd_pkt header; __le16 action; __le16 support_level; @@ -2095,9 +2015,9 @@ struct mwl8k_cmd_rf_tx_power { __le16 power_level_list[MWL8K_TX_POWER_LEVEL_TOTAL]; } __attribute__((packed)); -static int mwl8k_cmd_rf_tx_power(struct ieee80211_hw *hw, int dBm) +static int mwl8k_cmd_802_11_rf_tx_power(struct ieee80211_hw *hw, int dBm) { - struct mwl8k_cmd_rf_tx_power *cmd; + struct mwl8k_cmd_802_11_rf_tx_power *cmd; int rc; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); @@ -2148,36 +2068,6 @@ mwl8k_cmd_rf_antenna(struct ieee80211_hw *hw, int antenna, int mask) return rc; } -/* - * CMD_SET_BEACON. - */ -struct mwl8k_cmd_set_beacon { - struct mwl8k_cmd_pkt header; - __le16 beacon_len; - __u8 beacon[0]; -}; - -static int mwl8k_cmd_set_beacon(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, u8 *beacon, int len) -{ - struct mwl8k_cmd_set_beacon *cmd; - int rc; - - cmd = kzalloc(sizeof(*cmd) + len, GFP_KERNEL); - if (cmd == NULL) - return -ENOMEM; - - cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_BEACON); - cmd->header.length = cpu_to_le16(sizeof(*cmd) + len); - cmd->beacon_len = cpu_to_le16(len); - memcpy(cmd->beacon, beacon, len); - - rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); - kfree(cmd); - - return rc; -} - /* * CMD_SET_PRE_SCAN. */ @@ -2213,7 +2103,7 @@ struct mwl8k_cmd_set_post_scan { } __attribute__((packed)); static int -mwl8k_cmd_set_post_scan(struct ieee80211_hw *hw, const __u8 *mac) +mwl8k_cmd_set_post_scan(struct ieee80211_hw *hw, __u8 *mac) { struct mwl8k_cmd_set_post_scan *cmd; int rc; @@ -2244,9 +2134,8 @@ struct mwl8k_cmd_set_rf_channel { } __attribute__((packed)); static int mwl8k_cmd_set_rf_channel(struct ieee80211_hw *hw, - struct ieee80211_conf *conf) + struct ieee80211_channel *channel) { - struct ieee80211_channel *channel = conf->channel; struct mwl8k_cmd_set_rf_channel *cmd; int rc; @@ -2258,19 +2147,10 @@ static int mwl8k_cmd_set_rf_channel(struct ieee80211_hw *hw, cmd->header.length = cpu_to_le16(sizeof(*cmd)); cmd->action = cpu_to_le16(MWL8K_CMD_SET); cmd->current_channel = channel->hw_value; - if (channel->band == IEEE80211_BAND_2GHZ) - cmd->channel_flags |= cpu_to_le32(0x00000001); - else if (channel->band == IEEE80211_BAND_5GHZ) - cmd->channel_flags |= cpu_to_le32(0x00000004); - - if (conf->channel_type == NL80211_CHAN_NO_HT || - conf->channel_type == NL80211_CHAN_HT20) - cmd->channel_flags |= cpu_to_le32(0x00000080); - else if (conf->channel_type == NL80211_CHAN_HT40MINUS) - cmd->channel_flags |= cpu_to_le32(0x000001900); - else if (conf->channel_type == NL80211_CHAN_HT40PLUS) - cmd->channel_flags |= cpu_to_le32(0x000000900); + cmd->channel_flags = cpu_to_le32(0x00000081); + else + cmd->channel_flags = cpu_to_le32(0x00000000); rc = mwl8k_post_cmd(hw, &cmd->header); kfree(cmd); @@ -2279,75 +2159,27 @@ static int mwl8k_cmd_set_rf_channel(struct ieee80211_hw *hw, } /* - * CMD_SET_AID. + * CMD_SET_SLOT. */ -#define MWL8K_FRAME_PROT_DISABLED 0x00 -#define MWL8K_FRAME_PROT_11G 0x07 -#define MWL8K_FRAME_PROT_11N_HT_40MHZ_ONLY 0x02 -#define MWL8K_FRAME_PROT_11N_HT_ALL 0x06 - -struct mwl8k_cmd_update_set_aid { - struct mwl8k_cmd_pkt header; - __le16 aid; - - /* AP's MAC address (BSSID) */ - __u8 bssid[ETH_ALEN]; - __le16 protection_mode; - __u8 supp_rates[14]; +struct mwl8k_cmd_set_slot { + struct mwl8k_cmd_pkt header; + __le16 action; + __u8 short_slot; } __attribute__((packed)); -static void legacy_rate_mask_to_array(u8 *rates, u32 mask) -{ - int i; - int j; - - /* - * Clear nonstandard rates 4 and 13. - */ - mask &= 0x1fef; - - for (i = 0, j = 0; i < 14; i++) { - if (mask & (1 << i)) - rates[j++] = mwl8k_rates_24[i].hw_value; - } -} - -static int -mwl8k_cmd_set_aid(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, u32 legacy_rate_mask) +static int mwl8k_cmd_set_slot(struct ieee80211_hw *hw, bool short_slot_time) { - struct mwl8k_cmd_update_set_aid *cmd; - u16 prot_mode; + struct mwl8k_cmd_set_slot *cmd; int rc; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (cmd == NULL) return -ENOMEM; - cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_AID); + cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_SLOT); cmd->header.length = cpu_to_le16(sizeof(*cmd)); - cmd->aid = cpu_to_le16(vif->bss_conf.aid); - memcpy(cmd->bssid, vif->bss_conf.bssid, ETH_ALEN); - - if (vif->bss_conf.use_cts_prot) { - prot_mode = MWL8K_FRAME_PROT_11G; - } else { - switch (vif->bss_conf.ht_operation_mode & - IEEE80211_HT_OP_MODE_PROTECTION) { - case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: - prot_mode = MWL8K_FRAME_PROT_11N_HT_40MHZ_ONLY; - break; - case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED: - prot_mode = MWL8K_FRAME_PROT_11N_HT_ALL; - break; - default: - prot_mode = MWL8K_FRAME_PROT_DISABLED; - break; - } - } - cmd->protection_mode = cpu_to_le16(prot_mode); - - legacy_rate_mask_to_array(cmd->supp_rates, legacy_rate_mask); + cmd->action = cpu_to_le16(MWL8K_CMD_SET); + cmd->short_slot = short_slot_time; rc = mwl8k_post_cmd(hw, &cmd->header); kfree(cmd); @@ -2356,32 +2188,29 @@ mwl8k_cmd_set_aid(struct ieee80211_hw *hw, } /* - * CMD_SET_RATE. + * CMD_MIMO_CONFIG. */ -struct mwl8k_cmd_set_rate { - struct mwl8k_cmd_pkt header; - __u8 legacy_rates[14]; - - /* Bitmap for supported MCS codes. */ - __u8 mcs_set[16]; - __u8 reserved[16]; +struct mwl8k_cmd_mimo_config { + struct mwl8k_cmd_pkt header; + __le32 action; + __u8 rx_antenna_map; + __u8 tx_antenna_map; } __attribute__((packed)); -static int -mwl8k_cmd_set_rate(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u32 legacy_rate_mask, u8 *mcs_rates) +static int mwl8k_cmd_mimo_config(struct ieee80211_hw *hw, __u8 rx, __u8 tx) { - struct mwl8k_cmd_set_rate *cmd; + struct mwl8k_cmd_mimo_config *cmd; int rc; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (cmd == NULL) return -ENOMEM; - cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_RATE); + cmd->header.code = cpu_to_le16(MWL8K_CMD_MIMO_CONFIG); cmd->header.length = cpu_to_le16(sizeof(*cmd)); - legacy_rate_mask_to_array(cmd->legacy_rates, legacy_rate_mask); - memcpy(cmd->mcs_set, mcs_rates, 16); + cmd->action = cpu_to_le32((u32)MWL8K_CMD_SET); + cmd->rx_antenna_map = rx; + cmd->tx_antenna_map = tx; rc = mwl8k_post_cmd(hw, &cmd->header); kfree(cmd); @@ -2390,39 +2219,64 @@ mwl8k_cmd_set_rate(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } /* - * CMD_FINALIZE_JOIN. + * CMD_ENABLE_SNIFFER. */ -#define MWL8K_FJ_BEACON_MAXLEN 128 - -struct mwl8k_cmd_finalize_join { +struct mwl8k_cmd_enable_sniffer { struct mwl8k_cmd_pkt header; - __le32 sleep_interval; /* Number of beacon periods to sleep */ - __u8 beacon_data[MWL8K_FJ_BEACON_MAXLEN]; + __le32 action; } __attribute__((packed)); -static int mwl8k_cmd_finalize_join(struct ieee80211_hw *hw, void *frame, - int framelen, int dtim) +static int mwl8k_enable_sniffer(struct ieee80211_hw *hw, bool enable) { - struct mwl8k_cmd_finalize_join *cmd; - struct ieee80211_mgmt *payload = frame; - int payload_len; + struct mwl8k_cmd_enable_sniffer *cmd; int rc; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (cmd == NULL) return -ENOMEM; - cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_FINALIZE_JOIN); + cmd->header.code = cpu_to_le16(MWL8K_CMD_ENABLE_SNIFFER); cmd->header.length = cpu_to_le16(sizeof(*cmd)); - cmd->sleep_interval = cpu_to_le32(dtim ? dtim : 1); + cmd->action = cpu_to_le32(!!enable); - payload_len = framelen - ieee80211_hdrlen(payload->frame_control); - if (payload_len < 0) - payload_len = 0; - else if (payload_len > MWL8K_FJ_BEACON_MAXLEN) - payload_len = MWL8K_FJ_BEACON_MAXLEN; + rc = mwl8k_post_cmd(hw, &cmd->header); + kfree(cmd); - memcpy(cmd->beacon_data, &payload->u.beacon, payload_len); + return rc; +} + +/* + * CMD_SET_MAC_ADDR. + */ +struct mwl8k_cmd_set_mac_addr { + struct mwl8k_cmd_pkt header; + union { + struct { + __le16 mac_type; + __u8 mac_addr[ETH_ALEN]; + } mbss; + __u8 mac_addr[ETH_ALEN]; + }; +} __attribute__((packed)); + +static int mwl8k_set_mac_addr(struct ieee80211_hw *hw, u8 *mac) +{ + struct mwl8k_priv *priv = hw->priv; + struct mwl8k_cmd_set_mac_addr *cmd; + int rc; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (cmd == NULL) + return -ENOMEM; + + cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_MAC_ADDR); + cmd->header.length = cpu_to_le16(sizeof(*cmd)); + if (priv->ap_fw) { + cmd->mbss.mac_type = 0; + memcpy(cmd->mbss.mac_addr, mac, ETH_ALEN); + } else { + memcpy(cmd->mac_addr, mac, ETH_ALEN); + } rc = mwl8k_post_cmd(hw, &cmd->header); kfree(cmd); @@ -2430,29 +2284,29 @@ static int mwl8k_cmd_finalize_join(struct ieee80211_hw *hw, void *frame, return rc; } + /* - * CMD_SET_RTS_THRESHOLD. + * CMD_SET_RATEADAPT_MODE. */ -struct mwl8k_cmd_set_rts_threshold { +struct mwl8k_cmd_set_rate_adapt_mode { struct mwl8k_cmd_pkt header; __le16 action; - __le16 threshold; + __le16 mode; } __attribute__((packed)); -static int -mwl8k_cmd_set_rts_threshold(struct ieee80211_hw *hw, int rts_thresh) +static int mwl8k_cmd_setrateadaptmode(struct ieee80211_hw *hw, __u16 mode) { - struct mwl8k_cmd_set_rts_threshold *cmd; + struct mwl8k_cmd_set_rate_adapt_mode *cmd; int rc; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (cmd == NULL) return -ENOMEM; - cmd->header.code = cpu_to_le16(MWL8K_CMD_RTS_THRESHOLD); + cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_RATEADAPT_MODE); cmd->header.length = cpu_to_le16(sizeof(*cmd)); cmd->action = cpu_to_le16(MWL8K_CMD_SET); - cmd->threshold = cpu_to_le16(rts_thresh); + cmd->mode = cpu_to_le16(mode); rc = mwl8k_post_cmd(hw, &cmd->header); kfree(cmd); @@ -2461,27 +2315,59 @@ mwl8k_cmd_set_rts_threshold(struct ieee80211_hw *hw, int rts_thresh) } /* - * CMD_SET_SLOT. + * CMD_SET_WMM_MODE. */ -struct mwl8k_cmd_set_slot { +struct mwl8k_cmd_set_wmm { struct mwl8k_cmd_pkt header; __le16 action; - __u8 short_slot; } __attribute__((packed)); -static int mwl8k_cmd_set_slot(struct ieee80211_hw *hw, bool short_slot_time) +static int mwl8k_set_wmm(struct ieee80211_hw *hw, bool enable) { - struct mwl8k_cmd_set_slot *cmd; + struct mwl8k_priv *priv = hw->priv; + struct mwl8k_cmd_set_wmm *cmd; int rc; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (cmd == NULL) return -ENOMEM; - cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_SLOT); + cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_WMM_MODE); cmd->header.length = cpu_to_le16(sizeof(*cmd)); - cmd->action = cpu_to_le16(MWL8K_CMD_SET); - cmd->short_slot = short_slot_time; + cmd->action = cpu_to_le16(!!enable); + + rc = mwl8k_post_cmd(hw, &cmd->header); + kfree(cmd); + + if (!rc) + priv->wmm_enabled = enable; + + return rc; +} + +/* + * CMD_SET_RTS_THRESHOLD. + */ +struct mwl8k_cmd_rts_threshold { + struct mwl8k_cmd_pkt header; + __le16 action; + __le16 threshold; +} __attribute__((packed)); + +static int mwl8k_rts_threshold(struct ieee80211_hw *hw, + u16 action, u16 threshold) +{ + struct mwl8k_cmd_rts_threshold *cmd; + int rc; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (cmd == NULL) + return -ENOMEM; + + cmd->header.code = cpu_to_le16(MWL8K_CMD_RTS_THRESHOLD); + cmd->header.length = cpu_to_le16(sizeof(*cmd)); + cmd->action = cpu_to_le16(action); + cmd->threshold = cpu_to_le16(threshold); rc = mwl8k_post_cmd(hw, &cmd->header); kfree(cmd); @@ -2540,9 +2426,9 @@ struct mwl8k_cmd_set_edca_params { MWL8K_SET_EDCA_AIFS) static int -mwl8k_cmd_set_edca_params(struct ieee80211_hw *hw, __u8 qnum, - __u16 cw_min, __u16 cw_max, - __u8 aifs, __u16 txop) +mwl8k_set_edca_params(struct ieee80211_hw *hw, __u8 qnum, + __u16 cw_min, __u16 cw_max, + __u8 aifs, __u16 txop) { struct mwl8k_priv *priv = hw->priv; struct mwl8k_cmd_set_edca_params *cmd; @@ -2552,6 +2438,12 @@ mwl8k_cmd_set_edca_params(struct ieee80211_hw *hw, __u8 qnum, if (cmd == NULL) return -ENOMEM; + /* + * Queues 0 (BE) and 1 (BK) are swapped in hardware for + * this call. + */ + qnum ^= !(qnum >> 1); + cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_EDCA_PARAMS); cmd->header.length = cpu_to_le16(sizeof(*cmd)); cmd->action = cpu_to_le16(MWL8K_SET_EDCA_ALL); @@ -2575,102 +2467,39 @@ mwl8k_cmd_set_edca_params(struct ieee80211_hw *hw, __u8 qnum, } /* - * CMD_SET_WMM_MODE. + * CMD_FINALIZE_JOIN. */ -struct mwl8k_cmd_set_wmm_mode { - struct mwl8k_cmd_pkt header; - __le16 action; -} __attribute__((packed)); - -static int mwl8k_cmd_set_wmm_mode(struct ieee80211_hw *hw, bool enable) -{ - struct mwl8k_priv *priv = hw->priv; - struct mwl8k_cmd_set_wmm_mode *cmd; - int rc; - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (cmd == NULL) - return -ENOMEM; - - cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_WMM_MODE); - cmd->header.length = cpu_to_le16(sizeof(*cmd)); - cmd->action = cpu_to_le16(!!enable); - - rc = mwl8k_post_cmd(hw, &cmd->header); - kfree(cmd); - - if (!rc) - priv->wmm_enabled = enable; - - return rc; -} +#define MWL8K_FJ_BEACON_MAXLEN 128 -/* - * CMD_MIMO_CONFIG. - */ -struct mwl8k_cmd_mimo_config { +struct mwl8k_cmd_finalize_join { struct mwl8k_cmd_pkt header; - __le32 action; - __u8 rx_antenna_map; - __u8 tx_antenna_map; + __le32 sleep_interval; /* Number of beacon periods to sleep */ + __u8 beacon_data[MWL8K_FJ_BEACON_MAXLEN]; } __attribute__((packed)); -static int mwl8k_cmd_mimo_config(struct ieee80211_hw *hw, __u8 rx, __u8 tx) +static int mwl8k_finalize_join(struct ieee80211_hw *hw, void *frame, + int framelen, int dtim) { - struct mwl8k_cmd_mimo_config *cmd; + struct mwl8k_cmd_finalize_join *cmd; + struct ieee80211_mgmt *payload = frame; + int payload_len; int rc; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (cmd == NULL) return -ENOMEM; - cmd->header.code = cpu_to_le16(MWL8K_CMD_MIMO_CONFIG); + cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_FINALIZE_JOIN); cmd->header.length = cpu_to_le16(sizeof(*cmd)); - cmd->action = cpu_to_le32((u32)MWL8K_CMD_SET); - cmd->rx_antenna_map = rx; - cmd->tx_antenna_map = tx; - - rc = mwl8k_post_cmd(hw, &cmd->header); - kfree(cmd); - - return rc; -} - -/* - * CMD_USE_FIXED_RATE (STA version). - */ -struct mwl8k_cmd_use_fixed_rate_sta { - struct mwl8k_cmd_pkt header; - __le32 action; - __le32 allow_rate_drop; - __le32 num_rates; - struct { - __le32 is_ht_rate; - __le32 enable_retry; - __le32 rate; - __le32 retry_count; - } rate_entry[8]; - __le32 rate_type; - __le32 reserved1; - __le32 reserved2; -} __attribute__((packed)); - -#define MWL8K_USE_AUTO_RATE 0x0002 -#define MWL8K_UCAST_RATE 0 - -static int mwl8k_cmd_use_fixed_rate_sta(struct ieee80211_hw *hw) -{ - struct mwl8k_cmd_use_fixed_rate_sta *cmd; - int rc; + cmd->sleep_interval = cpu_to_le32(dtim ? dtim : 1); - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (cmd == NULL) - return -ENOMEM; + payload_len = framelen - ieee80211_hdrlen(payload->frame_control); + if (payload_len < 0) + payload_len = 0; + else if (payload_len > MWL8K_FJ_BEACON_MAXLEN) + payload_len = MWL8K_FJ_BEACON_MAXLEN; - cmd->header.code = cpu_to_le16(MWL8K_CMD_USE_FIXED_RATE); - cmd->header.length = cpu_to_le16(sizeof(*cmd)); - cmd->action = cpu_to_le32(MWL8K_USE_AUTO_RATE); - cmd->rate_type = cpu_to_le32(MWL8K_UCAST_RATE); + memcpy(cmd->beacon_data, &payload->u.beacon, payload_len); rc = mwl8k_post_cmd(hw, &cmd->header); kfree(cmd); @@ -2679,412 +2508,246 @@ static int mwl8k_cmd_use_fixed_rate_sta(struct ieee80211_hw *hw) } /* - * CMD_USE_FIXED_RATE (AP version). + * CMD_UPDATE_STADB. */ -struct mwl8k_cmd_use_fixed_rate_ap { +struct mwl8k_cmd_update_sta_db { struct mwl8k_cmd_pkt header; - __le32 action; - __le32 allow_rate_drop; - __le32 num_rates; - struct mwl8k_rate_entry_ap { - __le32 is_ht_rate; - __le32 enable_retry; - __le32 rate; - __le32 retry_count; - } rate_entry[4]; - u8 multicast_rate; - u8 multicast_rate_type; - u8 management_rate; -} __attribute__((packed)); - -static int -mwl8k_cmd_use_fixed_rate_ap(struct ieee80211_hw *hw, int mcast, int mgmt) -{ - struct mwl8k_cmd_use_fixed_rate_ap *cmd; - int rc; - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (cmd == NULL) - return -ENOMEM; - - cmd->header.code = cpu_to_le16(MWL8K_CMD_USE_FIXED_RATE); - cmd->header.length = cpu_to_le16(sizeof(*cmd)); - cmd->action = cpu_to_le32(MWL8K_USE_AUTO_RATE); - cmd->multicast_rate = mcast; - cmd->management_rate = mgmt; + /* See STADB_ACTION_TYPE */ + __le32 action; - rc = mwl8k_post_cmd(hw, &cmd->header); - kfree(cmd); + /* Peer MAC address */ + __u8 peer_addr[ETH_ALEN]; - return rc; -} + __le32 reserved; -/* - * CMD_ENABLE_SNIFFER. - */ -struct mwl8k_cmd_enable_sniffer { - struct mwl8k_cmd_pkt header; - __le32 action; + /* Peer info - valid during add/update. */ + struct peer_capability_info peer_info; } __attribute__((packed)); -static int mwl8k_cmd_enable_sniffer(struct ieee80211_hw *hw, bool enable) +static int mwl8k_cmd_update_sta_db(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, __u32 action) { - struct mwl8k_cmd_enable_sniffer *cmd; + struct mwl8k_vif *mv_vif = MWL8K_VIF(vif); + struct ieee80211_bss_conf *info = &mv_vif->bss_info; + struct mwl8k_cmd_update_sta_db *cmd; + struct peer_capability_info *peer_info; int rc; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (cmd == NULL) return -ENOMEM; - cmd->header.code = cpu_to_le16(MWL8K_CMD_ENABLE_SNIFFER); + cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_STADB); cmd->header.length = cpu_to_le16(sizeof(*cmd)); - cmd->action = cpu_to_le32(!!enable); - - rc = mwl8k_post_cmd(hw, &cmd->header); - kfree(cmd); - - return rc; -} -/* - * CMD_SET_MAC_ADDR. - */ -struct mwl8k_cmd_set_mac_addr { - struct mwl8k_cmd_pkt header; - union { - struct { - __le16 mac_type; - __u8 mac_addr[ETH_ALEN]; - } mbss; - __u8 mac_addr[ETH_ALEN]; - }; -} __attribute__((packed)); - -#define MWL8K_MAC_TYPE_PRIMARY_CLIENT 0 -#define MWL8K_MAC_TYPE_SECONDARY_CLIENT 1 -#define MWL8K_MAC_TYPE_PRIMARY_AP 2 -#define MWL8K_MAC_TYPE_SECONDARY_AP 3 - -static int mwl8k_cmd_set_mac_addr(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, u8 *mac) -{ - struct mwl8k_priv *priv = hw->priv; - struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); - struct mwl8k_cmd_set_mac_addr *cmd; - int mac_type; - int rc; + cmd->action = cpu_to_le32(action); + peer_info = &cmd->peer_info; + memcpy(cmd->peer_addr, mv_vif->bssid, ETH_ALEN); - mac_type = MWL8K_MAC_TYPE_PRIMARY_AP; - if (vif != NULL && vif->type == NL80211_IFTYPE_STATION) { - if (mwl8k_vif->macid + 1 == ffs(priv->sta_macids_supported)) - mac_type = MWL8K_MAC_TYPE_PRIMARY_CLIENT; - else - mac_type = MWL8K_MAC_TYPE_SECONDARY_CLIENT; - } else if (vif != NULL && vif->type == NL80211_IFTYPE_AP) { - if (mwl8k_vif->macid + 1 == ffs(priv->ap_macids_supported)) - mac_type = MWL8K_MAC_TYPE_PRIMARY_AP; - else - mac_type = MWL8K_MAC_TYPE_SECONDARY_AP; - } + switch (action) { + case MWL8K_STA_DB_ADD_ENTRY: + case MWL8K_STA_DB_MODIFY_ENTRY: + /* Build peer_info block */ + peer_info->peer_type = MWL8K_PEER_TYPE_ACCESSPOINT; + peer_info->basic_caps = cpu_to_le16(info->assoc_capability); + memcpy(peer_info->legacy_rates, mwl8k_rateids, + sizeof(mwl8k_rateids)); + peer_info->interop = 1; + peer_info->amsdu_enabled = 0; + + rc = mwl8k_post_cmd(hw, &cmd->header); + if (rc == 0) + mv_vif->peer_id = peer_info->station_id; - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (cmd == NULL) - return -ENOMEM; + break; - cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_MAC_ADDR); - cmd->header.length = cpu_to_le16(sizeof(*cmd)); - if (priv->ap_fw) { - cmd->mbss.mac_type = cpu_to_le16(mac_type); - memcpy(cmd->mbss.mac_addr, mac, ETH_ALEN); - } else { - memcpy(cmd->mac_addr, mac, ETH_ALEN); + case MWL8K_STA_DB_DEL_ENTRY: + case MWL8K_STA_DB_FLUSH: + default: + rc = mwl8k_post_cmd(hw, &cmd->header); + if (rc == 0) + mv_vif->peer_id = 0; + break; } - - rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); kfree(cmd); return rc; } /* - * CMD_SET_RATEADAPT_MODE. + * CMD_SET_AID. */ -struct mwl8k_cmd_set_rate_adapt_mode { - struct mwl8k_cmd_pkt header; - __le16 action; - __le16 mode; -} __attribute__((packed)); - -static int mwl8k_cmd_set_rateadapt_mode(struct ieee80211_hw *hw, __u16 mode) -{ - struct mwl8k_cmd_set_rate_adapt_mode *cmd; - int rc; - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (cmd == NULL) - return -ENOMEM; - - cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_RATEADAPT_MODE); - cmd->header.length = cpu_to_le16(sizeof(*cmd)); - cmd->action = cpu_to_le16(MWL8K_CMD_SET); - cmd->mode = cpu_to_le16(mode); - - rc = mwl8k_post_cmd(hw, &cmd->header); - kfree(cmd); +#define MWL8K_FRAME_PROT_DISABLED 0x00 +#define MWL8K_FRAME_PROT_11G 0x07 +#define MWL8K_FRAME_PROT_11N_HT_40MHZ_ONLY 0x02 +#define MWL8K_FRAME_PROT_11N_HT_ALL 0x06 - return rc; -} +struct mwl8k_cmd_update_set_aid { + struct mwl8k_cmd_pkt header; + __le16 aid; -/* - * CMD_BSS_START. - */ -struct mwl8k_cmd_bss_start { - struct mwl8k_cmd_pkt header; - __le32 enable; + /* AP's MAC address (BSSID) */ + __u8 bssid[ETH_ALEN]; + __le16 protection_mode; + __u8 supp_rates[14]; } __attribute__((packed)); -static int mwl8k_cmd_bss_start(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, int enable) +static int mwl8k_cmd_set_aid(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { - struct mwl8k_cmd_bss_start *cmd; + struct mwl8k_vif *mv_vif = MWL8K_VIF(vif); + struct ieee80211_bss_conf *info = &mv_vif->bss_info; + struct mwl8k_cmd_update_set_aid *cmd; + u16 prot_mode; int rc; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (cmd == NULL) return -ENOMEM; - cmd->header.code = cpu_to_le16(MWL8K_CMD_BSS_START); + cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_AID); cmd->header.length = cpu_to_le16(sizeof(*cmd)); - cmd->enable = cpu_to_le32(enable); - - rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); - kfree(cmd); - - return rc; -} - -/* - * CMD_SET_NEW_STN. - */ -struct mwl8k_cmd_set_new_stn { - struct mwl8k_cmd_pkt header; - __le16 aid; - __u8 mac_addr[6]; - __le16 stn_id; - __le16 action; - __le16 rsvd; - __le32 legacy_rates; - __u8 ht_rates[4]; - __le16 cap_info; - __le16 ht_capabilities_info; - __u8 mac_ht_param_info; - __u8 rev; - __u8 control_channel; - __u8 add_channel; - __le16 op_mode; - __le16 stbc; - __u8 add_qos_info; - __u8 is_qos_sta; - __le32 fw_sta_ptr; -} __attribute__((packed)); + cmd->aid = cpu_to_le16(info->aid); -#define MWL8K_STA_ACTION_ADD 0 -#define MWL8K_STA_ACTION_REMOVE 2 - -static int mwl8k_cmd_set_new_stn_add(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) -{ - struct mwl8k_cmd_set_new_stn *cmd; - u32 rates; - int rc; + memcpy(cmd->bssid, mv_vif->bssid, ETH_ALEN); - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (cmd == NULL) - return -ENOMEM; - - cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_NEW_STN); - cmd->header.length = cpu_to_le16(sizeof(*cmd)); - cmd->aid = cpu_to_le16(sta->aid); - memcpy(cmd->mac_addr, sta->addr, ETH_ALEN); - cmd->stn_id = cpu_to_le16(sta->aid); - cmd->action = cpu_to_le16(MWL8K_STA_ACTION_ADD); - if (hw->conf.channel->band == IEEE80211_BAND_2GHZ) - rates = sta->supp_rates[IEEE80211_BAND_2GHZ]; - else - rates = sta->supp_rates[IEEE80211_BAND_5GHZ] << 5; - cmd->legacy_rates = cpu_to_le32(rates); - if (sta->ht_cap.ht_supported) { - cmd->ht_rates[0] = sta->ht_cap.mcs.rx_mask[0]; - cmd->ht_rates[1] = sta->ht_cap.mcs.rx_mask[1]; - cmd->ht_rates[2] = sta->ht_cap.mcs.rx_mask[2]; - cmd->ht_rates[3] = sta->ht_cap.mcs.rx_mask[3]; - cmd->ht_capabilities_info = cpu_to_le16(sta->ht_cap.cap); - cmd->mac_ht_param_info = (sta->ht_cap.ampdu_factor & 3) | - ((sta->ht_cap.ampdu_density & 7) << 2); - cmd->is_qos_sta = 1; + if (info->use_cts_prot) { + prot_mode = MWL8K_FRAME_PROT_11G; + } else { + switch (info->ht_operation_mode & + IEEE80211_HT_OP_MODE_PROTECTION) { + case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: + prot_mode = MWL8K_FRAME_PROT_11N_HT_40MHZ_ONLY; + break; + case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED: + prot_mode = MWL8K_FRAME_PROT_11N_HT_ALL; + break; + default: + prot_mode = MWL8K_FRAME_PROT_DISABLED; + break; + } } + cmd->protection_mode = cpu_to_le16(prot_mode); - rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); + memcpy(cmd->supp_rates, mwl8k_rateids, sizeof(mwl8k_rateids)); + + rc = mwl8k_post_cmd(hw, &cmd->header); kfree(cmd); return rc; } -static int mwl8k_cmd_set_new_stn_add_self(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct mwl8k_cmd_set_new_stn *cmd; - int rc; - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (cmd == NULL) - return -ENOMEM; - - cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_NEW_STN); - cmd->header.length = cpu_to_le16(sizeof(*cmd)); - memcpy(cmd->mac_addr, vif->addr, ETH_ALEN); - - rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); - kfree(cmd); +/* + * CMD_SET_RATE. + */ +struct mwl8k_cmd_update_rateset { + struct mwl8k_cmd_pkt header; + __u8 legacy_rates[14]; - return rc; -} + /* Bitmap for supported MCS codes. */ + __u8 mcs_set[16]; + __u8 reserved[16]; +} __attribute__((packed)); -static int mwl8k_cmd_set_new_stn_del(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, u8 *addr) +static int mwl8k_update_rateset(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { - struct mwl8k_cmd_set_new_stn *cmd; + struct mwl8k_cmd_update_rateset *cmd; int rc; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (cmd == NULL) return -ENOMEM; - cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_NEW_STN); + cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_RATE); cmd->header.length = cpu_to_le16(sizeof(*cmd)); - memcpy(cmd->mac_addr, addr, ETH_ALEN); - cmd->action = cpu_to_le16(MWL8K_STA_ACTION_REMOVE); + memcpy(cmd->legacy_rates, mwl8k_rateids, sizeof(mwl8k_rateids)); - rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); + rc = mwl8k_post_cmd(hw, &cmd->header); kfree(cmd); return rc; } /* - * CMD_UPDATE_STADB. + * CMD_USE_FIXED_RATE. */ -struct ewc_ht_info { - __le16 control1; - __le16 control2; - __le16 control3; -} __attribute__((packed)); - -struct peer_capability_info { - /* Peer type - AP vs. STA. */ - __u8 peer_type; - - /* Basic 802.11 capabilities from assoc resp. */ - __le16 basic_caps; - - /* Set if peer supports 802.11n high throughput (HT). */ - __u8 ht_support; +#define MWL8K_RATE_TABLE_SIZE 8 +#define MWL8K_UCAST_RATE 0 +#define MWL8K_USE_AUTO_RATE 0x0002 - /* Valid if HT is supported. */ - __le16 ht_caps; - __u8 extended_ht_caps; - struct ewc_ht_info ewc_info; +struct mwl8k_rate_entry { + /* Set to 1 if HT rate, 0 if legacy. */ + __le32 is_ht_rate; - /* Legacy rate table. Intersection of our rates and peer rates. */ - __u8 legacy_rates[12]; + /* Set to 1 to use retry_count field. */ + __le32 enable_retry; - /* HT rate table. Intersection of our rates and peer rates. */ - __u8 ht_rates[16]; - __u8 pad[16]; + /* Specified legacy rate or MCS. */ + __le32 rate; - /* If set, interoperability mode, no proprietary extensions. */ - __u8 interop; - __u8 pad2; - __u8 station_id; - __le16 amsdu_enabled; + /* Number of allowed retries. */ + __le32 retry_count; } __attribute__((packed)); -struct mwl8k_cmd_update_stadb { - struct mwl8k_cmd_pkt header; +struct mwl8k_rate_table { + /* 1 to allow specified rate and below */ + __le32 allow_rate_drop; + __le32 num_rates; + struct mwl8k_rate_entry rate_entry[MWL8K_RATE_TABLE_SIZE]; +} __attribute__((packed)); - /* See STADB_ACTION_TYPE */ +struct mwl8k_cmd_use_fixed_rate { + struct mwl8k_cmd_pkt header; __le32 action; + struct mwl8k_rate_table rate_table; - /* Peer MAC address */ - __u8 peer_addr[ETH_ALEN]; - - __le32 reserved; - - /* Peer info - valid during add/update. */ - struct peer_capability_info peer_info; + /* Unicast, Broadcast or Multicast */ + __le32 rate_type; + __le32 reserved1; + __le32 reserved2; } __attribute__((packed)); -#define MWL8K_STA_DB_MODIFY_ENTRY 1 -#define MWL8K_STA_DB_DEL_ENTRY 2 - -/* Peer Entry flags - used to define the type of the peer node */ -#define MWL8K_PEER_TYPE_ACCESSPOINT 2 - -static int mwl8k_cmd_update_stadb_add(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) +static int mwl8k_cmd_use_fixed_rate(struct ieee80211_hw *hw, + u32 action, u32 rate_type, struct mwl8k_rate_table *rate_table) { - struct mwl8k_cmd_update_stadb *cmd; - struct peer_capability_info *p; - u32 rates; + struct mwl8k_cmd_use_fixed_rate *cmd; + int count; int rc; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (cmd == NULL) return -ENOMEM; - cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_STADB); + cmd->header.code = cpu_to_le16(MWL8K_CMD_USE_FIXED_RATE); cmd->header.length = cpu_to_le16(sizeof(*cmd)); - cmd->action = cpu_to_le32(MWL8K_STA_DB_MODIFY_ENTRY); - memcpy(cmd->peer_addr, sta->addr, ETH_ALEN); - - p = &cmd->peer_info; - p->peer_type = MWL8K_PEER_TYPE_ACCESSPOINT; - p->basic_caps = cpu_to_le16(vif->bss_conf.assoc_capability); - p->ht_support = sta->ht_cap.ht_supported; - p->ht_caps = sta->ht_cap.cap; - p->extended_ht_caps = (sta->ht_cap.ampdu_factor & 3) | - ((sta->ht_cap.ampdu_density & 7) << 2); - if (hw->conf.channel->band == IEEE80211_BAND_2GHZ) - rates = sta->supp_rates[IEEE80211_BAND_2GHZ]; - else - rates = sta->supp_rates[IEEE80211_BAND_5GHZ] << 5; - legacy_rate_mask_to_array(p->legacy_rates, rates); - memcpy(p->ht_rates, sta->ht_cap.mcs.rx_mask, 16); - p->interop = 1; - p->amsdu_enabled = 0; - - rc = mwl8k_post_cmd(hw, &cmd->header); - kfree(cmd); - return rc ? rc : p->station_id; -} + cmd->action = cpu_to_le32(action); + cmd->rate_type = cpu_to_le32(rate_type); -static int mwl8k_cmd_update_stadb_del(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, u8 *addr) -{ - struct mwl8k_cmd_update_stadb *cmd; - int rc; - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (cmd == NULL) - return -ENOMEM; - - cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_STADB); - cmd->header.length = cpu_to_le16(sizeof(*cmd)); - cmd->action = cpu_to_le32(MWL8K_STA_DB_DEL_ENTRY); - memcpy(cmd->peer_addr, addr, ETH_ALEN); + if (rate_table != NULL) { + /* + * Copy over each field manually so that endian + * conversion can be done. + */ + cmd->rate_table.allow_rate_drop = + cpu_to_le32(rate_table->allow_rate_drop); + cmd->rate_table.num_rates = + cpu_to_le32(rate_table->num_rates); + + for (count = 0; count < rate_table->num_rates; count++) { + struct mwl8k_rate_entry *dst = + &cmd->rate_table.rate_entry[count]; + struct mwl8k_rate_entry *src = + &rate_table->rate_entry[count]; + + dst->is_ht_rate = cpu_to_le32(src->is_ht_rate); + dst->enable_retry = cpu_to_le32(src->enable_retry); + dst->rate = cpu_to_le32(src->rate); + dst->retry_count = cpu_to_le32(src->retry_count); + } + } rc = mwl8k_post_cmd(hw, &cmd->header); kfree(cmd); @@ -3103,22 +2766,19 @@ static irqreturn_t mwl8k_interrupt(int irq, void *dev_id) u32 status; status = ioread32(priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); + iowrite32(~status, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); + if (!status) return IRQ_NONE; - if (status & MWL8K_A2H_INT_TX_DONE) { - status &= ~MWL8K_A2H_INT_TX_DONE; - tasklet_schedule(&priv->poll_tx_task); - } + if (status & MWL8K_A2H_INT_TX_DONE) + tasklet_schedule(&priv->tx_reclaim_task); if (status & MWL8K_A2H_INT_RX_READY) { - status &= ~MWL8K_A2H_INT_RX_READY; - tasklet_schedule(&priv->poll_rx_task); + while (rxq_process(hw, 0, 1)) + rxq_refill(hw, 0, 1); } - if (status) - iowrite32(~status, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); - if (status & MWL8K_A2H_INT_OPC_DONE) { if (priv->hostcmd_wait != NULL) complete(priv->hostcmd_wait); @@ -3133,53 +2793,6 @@ static irqreturn_t mwl8k_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static void mwl8k_tx_poll(unsigned long data) -{ - struct ieee80211_hw *hw = (struct ieee80211_hw *)data; - struct mwl8k_priv *priv = hw->priv; - int limit; - int i; - - limit = 32; - - spin_lock_bh(&priv->tx_lock); - - for (i = 0; i < MWL8K_TX_QUEUES; i++) - limit -= mwl8k_txq_reclaim(hw, i, limit, 0); - - if (!priv->pending_tx_pkts && priv->tx_wait != NULL) { - complete(priv->tx_wait); - priv->tx_wait = NULL; - } - - spin_unlock_bh(&priv->tx_lock); - - if (limit) { - writel(~MWL8K_A2H_INT_TX_DONE, - priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); - } else { - tasklet_schedule(&priv->poll_tx_task); - } -} - -static void mwl8k_rx_poll(unsigned long data) -{ - struct ieee80211_hw *hw = (struct ieee80211_hw *)data; - struct mwl8k_priv *priv = hw->priv; - int limit; - - limit = 32; - limit -= rxq_process(hw, 0, limit); - limit -= rxq_refill(hw, 0, limit); - - if (limit) { - writel(~MWL8K_A2H_INT_RX_READY, - priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); - } else { - tasklet_schedule(&priv->poll_rx_task); - } -} - /* * Core driver operations. @@ -3190,7 +2803,7 @@ static int mwl8k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) int index = skb_get_queue_mapping(skb); int rc; - if (!priv->radio_on) { + if (priv->current_channel == NULL) { printk(KERN_DEBUG "%s: dropped TX frame since radio " "disabled\n", wiphy_name(hw->wiphy)); dev_kfree_skb(skb); @@ -3215,20 +2828,19 @@ static int mwl8k_start(struct ieee80211_hw *hw) return -EIO; } - /* Enable TX reclaim and RX tasklets. */ - tasklet_enable(&priv->poll_tx_task); - tasklet_enable(&priv->poll_rx_task); + /* Enable tx reclaim tasklet */ + tasklet_enable(&priv->tx_reclaim_task); /* Enable interrupts */ iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); rc = mwl8k_fw_lock(hw); if (!rc) { - rc = mwl8k_cmd_radio_enable(hw); + rc = mwl8k_cmd_802_11_radio_enable(hw); if (!priv->ap_fw) { if (!rc) - rc = mwl8k_cmd_enable_sniffer(hw, 0); + rc = mwl8k_enable_sniffer(hw, 0); if (!rc) rc = mwl8k_cmd_set_pre_scan(hw); @@ -3239,10 +2851,10 @@ static int mwl8k_start(struct ieee80211_hw *hw) } if (!rc) - rc = mwl8k_cmd_set_rateadapt_mode(hw, 0); + rc = mwl8k_cmd_setrateadaptmode(hw, 0); if (!rc) - rc = mwl8k_cmd_set_wmm_mode(hw, 0); + rc = mwl8k_set_wmm(hw, 0); mwl8k_fw_unlock(hw); } @@ -3250,8 +2862,7 @@ static int mwl8k_start(struct ieee80211_hw *hw) if (rc) { iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); free_irq(priv->pdev->irq, hw); - tasklet_disable(&priv->poll_tx_task); - tasklet_disable(&priv->poll_rx_task); + tasklet_disable(&priv->tx_reclaim_task); } return rc; @@ -3262,7 +2873,7 @@ static void mwl8k_stop(struct ieee80211_hw *hw) struct mwl8k_priv *priv = hw->priv; int i; - mwl8k_cmd_radio_disable(hw); + mwl8k_cmd_802_11_radio_disable(hw); ieee80211_stop_queues(hw); @@ -3275,27 +2886,36 @@ static void mwl8k_stop(struct ieee80211_hw *hw) if (priv->beacon_skb != NULL) dev_kfree_skb(priv->beacon_skb); - /* Stop TX reclaim and RX tasklets. */ - tasklet_disable(&priv->poll_tx_task); - tasklet_disable(&priv->poll_rx_task); + /* Stop tx reclaim tasklet */ + tasklet_disable(&priv->tx_reclaim_task); /* Return all skbs to mac80211 */ for (i = 0; i < MWL8K_TX_QUEUES; i++) - mwl8k_txq_reclaim(hw, i, INT_MAX, 1); + mwl8k_txq_reclaim(hw, i, 1); } static int mwl8k_add_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) + struct ieee80211_if_init_conf *conf) { struct mwl8k_priv *priv = hw->priv; struct mwl8k_vif *mwl8k_vif; - u32 macids_supported; - int macid; + + /* + * We only support one active interface at a time. + */ + if (priv->vif != NULL) + return -EBUSY; + + /* + * We only support managed interfaces for now. + */ + if (conf->type != NL80211_IFTYPE_STATION) + return -EINVAL; /* * Reject interface creation if sniffer mode is active, as * STA operation is mutually exclusive with hardware sniffer - * mode. (Sniffer mode is only used on STA firmware.) + * mode. */ if (priv->sniffer_enabled) { printk(KERN_INFO "%s: unable to create STA " @@ -3304,54 +2924,37 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw, return -EINVAL; } + /* Clean out driver private area */ + mwl8k_vif = MWL8K_VIF(conf->vif); + memset(mwl8k_vif, 0, sizeof(*mwl8k_vif)); - switch (vif->type) { - case NL80211_IFTYPE_AP: - macids_supported = priv->ap_macids_supported; - break; - case NL80211_IFTYPE_STATION: - macids_supported = priv->sta_macids_supported; - break; - default: - return -EINVAL; - } + /* Set and save the mac address */ + mwl8k_set_mac_addr(hw, conf->mac_addr); + memcpy(mwl8k_vif->mac_addr, conf->mac_addr, ETH_ALEN); - macid = ffs(macids_supported & ~priv->macids_used); - if (!macid--) - return -EBUSY; + /* Back pointer to parent config block */ + mwl8k_vif->priv = priv; - /* Setup driver private area. */ - mwl8k_vif = MWL8K_VIF(vif); - memset(mwl8k_vif, 0, sizeof(*mwl8k_vif)); - mwl8k_vif->vif = vif; - mwl8k_vif->macid = macid; + /* Set Initial sequence number to zero */ mwl8k_vif->seqno = 0; - /* Set the mac address. */ - mwl8k_cmd_set_mac_addr(hw, vif, vif->addr); - - if (priv->ap_fw) - mwl8k_cmd_set_new_stn_add_self(hw, vif); - - priv->macids_used |= 1 << mwl8k_vif->macid; - list_add_tail(&mwl8k_vif->list, &priv->vif_list); + priv->vif = conf->vif; + priv->current_channel = NULL; return 0; } static void mwl8k_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) + struct ieee80211_if_init_conf *conf) { struct mwl8k_priv *priv = hw->priv; - struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); - if (priv->ap_fw) - mwl8k_cmd_set_new_stn_del(hw, vif, vif->addr); + if (priv->vif == NULL) + return; - mwl8k_cmd_set_mac_addr(hw, vif, "\x00\x00\x00\x00\x00\x00"); + mwl8k_set_mac_addr(hw, "\x00\x00\x00\x00\x00\x00"); - priv->macids_used &= ~(1 << mwl8k_vif->macid); - list_del(&mwl8k_vif->list); + priv->vif = NULL; } static int mwl8k_config(struct ieee80211_hw *hw, u32 changed) @@ -3361,7 +2964,8 @@ static int mwl8k_config(struct ieee80211_hw *hw, u32 changed) int rc; if (conf->flags & IEEE80211_CONF_IDLE) { - mwl8k_cmd_radio_disable(hw); + mwl8k_cmd_802_11_radio_disable(hw); + priv->current_channel = NULL; return 0; } @@ -3369,17 +2973,19 @@ static int mwl8k_config(struct ieee80211_hw *hw, u32 changed) if (rc) return rc; - rc = mwl8k_cmd_radio_enable(hw); + rc = mwl8k_cmd_802_11_radio_enable(hw); if (rc) goto out; - rc = mwl8k_cmd_set_rf_channel(hw, conf); + rc = mwl8k_cmd_set_rf_channel(hw, conf->channel); if (rc) goto out; + priv->current_channel = conf->channel; + if (conf->power_level > 18) conf->power_level = 18; - rc = mwl8k_cmd_rf_tx_power(hw, conf->power_level); + rc = mwl8k_cmd_802_11_rf_tx_power(hw, conf->power_level); if (rc) goto out; @@ -3397,160 +3003,79 @@ static int mwl8k_config(struct ieee80211_hw *hw, u32 changed) return rc; } -static void -mwl8k_bss_info_changed_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *info, u32 changed) +static void mwl8k_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, + u32 changed) { struct mwl8k_priv *priv = hw->priv; - u32 ap_legacy_rates; - u8 ap_mcs_rates[16]; + struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); int rc; - if (mwl8k_fw_lock(hw)) + if ((changed & BSS_CHANGED_ASSOC) == 0) return; - /* - * No need to capture a beacon if we're no longer associated. - */ - if ((changed & BSS_CHANGED_ASSOC) && !vif->bss_conf.assoc) - priv->capture_beacon = false; - - /* - * Get the AP's legacy and MCS rates. - */ - if (vif->bss_conf.assoc) { - struct ieee80211_sta *ap; + priv->capture_beacon = false; - rcu_read_lock(); + rc = mwl8k_fw_lock(hw); + if (rc) + return; - ap = ieee80211_find_sta(vif, vif->bss_conf.bssid); - if (ap == NULL) { - rcu_read_unlock(); - goto out; - } + if (info->assoc) { + memcpy(&mwl8k_vif->bss_info, info, + sizeof(struct ieee80211_bss_conf)); - if (hw->conf.channel->band == IEEE80211_BAND_2GHZ) { - ap_legacy_rates = ap->supp_rates[IEEE80211_BAND_2GHZ]; - } else { - ap_legacy_rates = - ap->supp_rates[IEEE80211_BAND_5GHZ] << 5; - } - memcpy(ap_mcs_rates, ap->ht_cap.mcs.rx_mask, 16); + memcpy(mwl8k_vif->bssid, info->bssid, ETH_ALEN); - rcu_read_unlock(); - } + /* Install rates */ + rc = mwl8k_update_rateset(hw, vif); + if (rc) + goto out; - if ((changed & BSS_CHANGED_ASSOC) && vif->bss_conf.assoc) { - rc = mwl8k_cmd_set_rate(hw, vif, ap_legacy_rates, ap_mcs_rates); + /* Turn on rate adaptation */ + rc = mwl8k_cmd_use_fixed_rate(hw, MWL8K_USE_AUTO_RATE, + MWL8K_UCAST_RATE, NULL); if (rc) goto out; - rc = mwl8k_cmd_use_fixed_rate_sta(hw); + /* Set radio preamble */ + rc = mwl8k_set_radio_preamble(hw, info->use_short_preamble); if (rc) goto out; - } - if (changed & BSS_CHANGED_ERP_PREAMBLE) { - rc = mwl8k_set_radio_preamble(hw, - vif->bss_conf.use_short_preamble); + /* Set slot time */ + rc = mwl8k_cmd_set_slot(hw, info->use_short_slot); if (rc) goto out; - } - if (changed & BSS_CHANGED_ERP_SLOT) { - rc = mwl8k_cmd_set_slot(hw, vif->bss_conf.use_short_slot); + /* Update peer rate info */ + rc = mwl8k_cmd_update_sta_db(hw, vif, + MWL8K_STA_DB_MODIFY_ENTRY); if (rc) goto out; - } - if (vif->bss_conf.assoc && - (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_ERP_CTS_PROT | - BSS_CHANGED_HT))) { - rc = mwl8k_cmd_set_aid(hw, vif, ap_legacy_rates); + /* Set AID */ + rc = mwl8k_cmd_set_aid(hw, vif); if (rc) goto out; - } - if (vif->bss_conf.assoc && - (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_BEACON_INT))) { /* * Finalize the join. Tell rx handler to process * next beacon from our BSSID. */ - memcpy(priv->capture_bssid, vif->bss_conf.bssid, ETH_ALEN); + memcpy(priv->capture_bssid, mwl8k_vif->bssid, ETH_ALEN); priv->capture_beacon = true; + } else { + rc = mwl8k_cmd_update_sta_db(hw, vif, MWL8K_STA_DB_DEL_ENTRY); + memset(&mwl8k_vif->bss_info, 0, + sizeof(struct ieee80211_bss_conf)); + memset(mwl8k_vif->bssid, 0, ETH_ALEN); } out: mwl8k_fw_unlock(hw); } -static void -mwl8k_bss_info_changed_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *info, u32 changed) -{ - int rc; - - if (mwl8k_fw_lock(hw)) - return; - - if (changed & BSS_CHANGED_ERP_PREAMBLE) { - rc = mwl8k_set_radio_preamble(hw, - vif->bss_conf.use_short_preamble); - if (rc) - goto out; - } - - if (changed & BSS_CHANGED_BASIC_RATES) { - int idx; - int rate; - - /* - * Use lowest supported basic rate for multicasts - * and management frames (such as probe responses -- - * beacons will always go out at 1 Mb/s). - */ - idx = ffs(vif->bss_conf.basic_rates); - if (idx) - idx--; - - if (hw->conf.channel->band == IEEE80211_BAND_2GHZ) - rate = mwl8k_rates_24[idx].hw_value; - else - rate = mwl8k_rates_50[idx].hw_value; - - mwl8k_cmd_use_fixed_rate_ap(hw, rate, rate); - } - - if (changed & (BSS_CHANGED_BEACON_INT | BSS_CHANGED_BEACON)) { - struct sk_buff *skb; - - skb = ieee80211_beacon_get(hw, vif); - if (skb != NULL) { - mwl8k_cmd_set_beacon(hw, vif, skb->data, skb->len); - kfree_skb(skb); - } - } - - if (changed & BSS_CHANGED_BEACON_ENABLED) - mwl8k_cmd_bss_start(hw, vif, info->enable_beacon); - -out: - mwl8k_fw_unlock(hw); -} - -static void -mwl8k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *info, u32 changed) -{ - struct mwl8k_priv *priv = hw->priv; - - if (!priv->ap_fw) - mwl8k_bss_info_changed_sta(hw, vif, info, changed); - else - mwl8k_bss_info_changed_ap(hw, vif, info, changed); -} - static u64 mwl8k_prepare_multicast(struct ieee80211_hw *hw, int mc_count, struct dev_addr_list *mclist) { @@ -3580,7 +3105,7 @@ mwl8k_configure_filter_sniffer(struct ieee80211_hw *hw, * operation, so refuse to enable sniffer mode if a STA * interface is active. */ - if (!list_empty(&priv->vif_list)) { + if (priv->vif != NULL) { if (net_ratelimit()) printk(KERN_INFO "%s: not enabling sniffer " "mode because STA interface is active\n", @@ -3589,7 +3114,7 @@ mwl8k_configure_filter_sniffer(struct ieee80211_hw *hw, } if (!priv->sniffer_enabled) { - if (mwl8k_cmd_enable_sniffer(hw, 1)) + if (mwl8k_enable_sniffer(hw, 1)) return 0; priv->sniffer_enabled = true; } @@ -3601,14 +3126,6 @@ mwl8k_configure_filter_sniffer(struct ieee80211_hw *hw, return 1; } -static struct mwl8k_vif *mwl8k_first_vif(struct mwl8k_priv *priv) -{ - if (!list_empty(&priv->vif_list)) - return list_entry(priv->vif_list.next, struct mwl8k_vif, list); - - return NULL; -} - static void mwl8k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, @@ -3646,7 +3163,7 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw, } if (priv->sniffer_enabled) { - mwl8k_cmd_enable_sniffer(hw, 0); + mwl8k_enable_sniffer(hw, 0); priv->sniffer_enabled = false; } @@ -3657,8 +3174,7 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw, */ mwl8k_cmd_set_pre_scan(hw); } else { - struct mwl8k_vif *mwl8k_vif; - const u8 *bssid; + u8 *bssid; /* * Enable the BSS filter. @@ -3668,11 +3184,9 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw, * (where the OUI part needs to be nonzero for * the BSSID to be accepted by POST_SCAN). */ - mwl8k_vif = mwl8k_first_vif(priv); - if (mwl8k_vif != NULL) - bssid = mwl8k_vif->vif->bss_conf.bssid; - else - bssid = "\x01\x00\x00\x00\x00\x00"; + bssid = "\x01\x00\x00\x00\x00\x00"; + if (priv->vif != NULL) + bssid = MWL8K_VIF(priv->vif)->bssid; mwl8k_cmd_set_post_scan(hw, bssid); } @@ -3699,39 +3213,7 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw, static int mwl8k_set_rts_threshold(struct ieee80211_hw *hw, u32 value) { - return mwl8k_cmd_set_rts_threshold(hw, value); -} - -static int mwl8k_sta_remove(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) -{ - struct mwl8k_priv *priv = hw->priv; - - if (priv->ap_fw) - return mwl8k_cmd_set_new_stn_del(hw, vif, sta->addr); - else - return mwl8k_cmd_update_stadb_del(hw, vif, sta->addr); -} - -static int mwl8k_sta_add(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) -{ - struct mwl8k_priv *priv = hw->priv; - int ret; - - if (!priv->ap_fw) { - ret = mwl8k_cmd_update_stadb_add(hw, vif, sta); - if (ret >= 0) { - MWL8K_STA(sta)->peer_id = ret; - return 0; - } - - return ret; - } - - return mwl8k_cmd_set_new_stn_add(hw, vif, sta); + return mwl8k_rts_threshold(hw, MWL8K_CMD_SET, value); } static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue, @@ -3743,14 +3225,14 @@ static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue, rc = mwl8k_fw_lock(hw); if (!rc) { if (!priv->wmm_enabled) - rc = mwl8k_cmd_set_wmm_mode(hw, 1); + rc = mwl8k_set_wmm(hw, 1); if (!rc) - rc = mwl8k_cmd_set_edca_params(hw, queue, - params->cw_min, - params->cw_max, - params->aifs, - params->txop); + rc = mwl8k_set_edca_params(hw, queue, + params->cw_min, + params->cw_max, + params->aifs, + params->txop); mwl8k_fw_unlock(hw); } @@ -3758,26 +3240,28 @@ static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue, return rc; } -static int mwl8k_get_stats(struct ieee80211_hw *hw, - struct ieee80211_low_level_stats *stats) +static int mwl8k_get_tx_stats(struct ieee80211_hw *hw, + struct ieee80211_tx_queue_stats *stats) { - return mwl8k_cmd_get_stat(hw, stats); + struct mwl8k_priv *priv = hw->priv; + struct mwl8k_tx_queue *txq; + int index; + + spin_lock_bh(&priv->tx_lock); + for (index = 0; index < MWL8K_TX_QUEUES; index++) { + txq = priv->txq + index; + memcpy(&stats[index], &txq->stats, + sizeof(struct ieee80211_tx_queue_stats)); + } + spin_unlock_bh(&priv->tx_lock); + + return 0; } -static int -mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn) +static int mwl8k_get_stats(struct ieee80211_hw *hw, + struct ieee80211_low_level_stats *stats) { - switch (action) { - case IEEE80211_AMPDU_RX_START: - case IEEE80211_AMPDU_RX_STOP: - if (!(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION)) - return -ENOTSUPP; - return 0; - default: - return -ENOTSUPP; - } + return mwl8k_cmd_802_11_get_stat(hw, stats); } static const struct ieee80211_ops mwl8k_ops = { @@ -3791,72 +3275,67 @@ static const struct ieee80211_ops mwl8k_ops = { .prepare_multicast = mwl8k_prepare_multicast, .configure_filter = mwl8k_configure_filter, .set_rts_threshold = mwl8k_set_rts_threshold, - .sta_add = mwl8k_sta_add, - .sta_remove = mwl8k_sta_remove, .conf_tx = mwl8k_conf_tx, + .get_tx_stats = mwl8k_get_tx_stats, .get_stats = mwl8k_get_stats, - .ampdu_action = mwl8k_ampdu_action, }; +static void mwl8k_tx_reclaim_handler(unsigned long data) +{ + int i; + struct ieee80211_hw *hw = (struct ieee80211_hw *) data; + struct mwl8k_priv *priv = hw->priv; + + spin_lock_bh(&priv->tx_lock); + for (i = 0; i < MWL8K_TX_QUEUES; i++) + mwl8k_txq_reclaim(hw, i, 0); + + if (priv->tx_wait != NULL && !priv->pending_tx_pkts) { + complete(priv->tx_wait); + priv->tx_wait = NULL; + } + spin_unlock_bh(&priv->tx_lock); +} + static void mwl8k_finalize_join_worker(struct work_struct *work) { struct mwl8k_priv *priv = container_of(work, struct mwl8k_priv, finalize_join_worker); struct sk_buff *skb = priv->beacon_skb; - struct ieee80211_mgmt *mgmt = (void *)skb->data; - int len = skb->len - offsetof(struct ieee80211_mgmt, u.beacon.variable); - const u8 *tim = cfg80211_find_ie(WLAN_EID_TIM, - mgmt->u.beacon.variable, len); - int dtim_period = 1; - - if (tim && tim[1] >= 2) - dtim_period = tim[3]; - - mwl8k_cmd_finalize_join(priv->hw, skb->data, skb->len, dtim_period); + u8 dtim = MWL8K_VIF(priv->vif)->bss_info.dtim_period; + mwl8k_finalize_join(priv->hw, skb->data, skb->len, dtim); dev_kfree_skb(skb); + priv->beacon_skb = NULL; } enum { - MWL8363 = 0, - MWL8687, + MWL8687 = 0, MWL8366, }; static struct mwl8k_device_info mwl8k_info_tbl[] __devinitdata = { - [MWL8363] = { - .part_name = "88w8363", - .helper_image = "mwl8k/helper_8363.fw", - .fw_image = "mwl8k/fmimage_8363.fw", - }, - [MWL8687] = { + { .part_name = "88w8687", .helper_image = "mwl8k/helper_8687.fw", .fw_image = "mwl8k/fmimage_8687.fw", + .rxd_ops = &rxd_8687_ops, + .modes = BIT(NL80211_IFTYPE_STATION), }, - [MWL8366] = { + { .part_name = "88w8366", .helper_image = "mwl8k/helper_8366.fw", .fw_image = "mwl8k/fmimage_8366.fw", - .ap_rxd_ops = &rxd_8366_ap_ops, + .rxd_ops = &rxd_8366_ops, + .modes = 0, }, }; -MODULE_FIRMWARE("mwl8k/helper_8363.fw"); -MODULE_FIRMWARE("mwl8k/fmimage_8363.fw"); -MODULE_FIRMWARE("mwl8k/helper_8687.fw"); -MODULE_FIRMWARE("mwl8k/fmimage_8687.fw"); -MODULE_FIRMWARE("mwl8k/helper_8366.fw"); -MODULE_FIRMWARE("mwl8k/fmimage_8366.fw"); - static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = { - { PCI_VDEVICE(MARVELL, 0x2a0c), .driver_data = MWL8363, }, - { PCI_VDEVICE(MARVELL, 0x2a24), .driver_data = MWL8363, }, { PCI_VDEVICE(MARVELL, 0x2a2b), .driver_data = MWL8687, }, { PCI_VDEVICE(MARVELL, 0x2a30), .driver_data = MWL8687, }, { PCI_VDEVICE(MARVELL, 0x2a40), .driver_data = MWL8366, }, - { PCI_VDEVICE(MARVELL, 0x2a43), .driver_data = MWL8366, }, { }, }; MODULE_DEVICE_TABLE(pci, mwl8k_pci_id_table); @@ -3875,7 +3354,6 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, printed_version = 1; } - rc = pci_enable_device(pdev); if (rc) { printk(KERN_ERR "%s: Cannot enable new PCI device\n", @@ -3892,7 +3370,6 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, pci_set_master(pdev); - hw = ieee80211_alloc_hw(sizeof(*priv), &mwl8k_ops); if (hw == NULL) { printk(KERN_ERR "%s: ieee80211 alloc failed\n", MWL8K_NAME); @@ -3900,14 +3377,17 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, goto err_free_reg; } - SET_IEEE80211_DEV(hw, &pdev->dev); - pci_set_drvdata(pdev, hw); - priv = hw->priv; priv->hw = hw; priv->pdev = pdev; priv->device_info = &mwl8k_info_tbl[id->driver_data]; + priv->rxd_ops = priv->device_info->rxd_ops; + priv->sniffer_enabled = false; + priv->wmm_enabled = false; + priv->pending_tx_pkts = 0; + SET_IEEE80211_DEV(hw, &pdev->dev); + pci_set_drvdata(pdev, hw); priv->sram = pci_iomap(pdev, 0, 0x10000); if (priv->sram == NULL) { @@ -3930,46 +3410,16 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, } } + memcpy(priv->channels, mwl8k_channels, sizeof(mwl8k_channels)); + priv->band.band = IEEE80211_BAND_2GHZ; + priv->band.channels = priv->channels; + priv->band.n_channels = ARRAY_SIZE(mwl8k_channels); + priv->band.bitrates = priv->rates; + priv->band.n_bitrates = ARRAY_SIZE(mwl8k_rates); + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; - /* Reset firmware and hardware */ - mwl8k_hw_reset(priv); - - /* Ask userland hotplug daemon for the device firmware */ - rc = mwl8k_request_firmware(priv); - if (rc) { - printk(KERN_ERR "%s: Firmware files not found\n", - wiphy_name(hw->wiphy)); - goto err_stop_firmware; - } - - /* Load firmware into hardware */ - rc = mwl8k_load_firmware(hw); - if (rc) { - printk(KERN_ERR "%s: Cannot start firmware\n", - wiphy_name(hw->wiphy)); - goto err_stop_firmware; - } - - /* Reclaim memory once firmware is successfully loaded */ - mwl8k_release_firmware(priv); - - - if (priv->ap_fw) { - priv->rxd_ops = priv->device_info->ap_rxd_ops; - if (priv->rxd_ops == NULL) { - printk(KERN_ERR "%s: Driver does not have AP " - "firmware image support for this hardware\n", - wiphy_name(hw->wiphy)); - goto err_stop_firmware; - } - } else { - priv->rxd_ops = &rxd_sta_ops; - } - - priv->sniffer_enabled = false; - priv->wmm_enabled = false; - priv->pending_tx_pkts = 0; - + BUILD_BUG_ON(sizeof(priv->rates) != sizeof(mwl8k_rates)); + memcpy(priv->rates, mwl8k_rates, sizeof(mwl8k_rates)); /* * Extra headroom is the size of the required DMA header @@ -3982,13 +3432,12 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, hw->queues = MWL8K_TX_QUEUES; + hw->wiphy->interface_modes = priv->device_info->modes; + /* Set rssi and noise values to dBm */ hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; hw->vif_data_size = sizeof(struct mwl8k_vif); - hw->sta_data_size = sizeof(struct mwl8k_sta); - - priv->macids_used = 0; - INIT_LIST_HEAD(&priv->vif_list); + priv->vif = NULL; /* Set default radio state and preamble */ priv->radio_on = 0; @@ -3997,20 +3446,19 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, /* Finalize join worker */ INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker); - /* TX reclaim and RX tasklets. */ - tasklet_init(&priv->poll_tx_task, mwl8k_tx_poll, (unsigned long)hw); - tasklet_disable(&priv->poll_tx_task); - tasklet_init(&priv->poll_rx_task, mwl8k_rx_poll, (unsigned long)hw); - tasklet_disable(&priv->poll_rx_task); + /* TX reclaim tasklet */ + tasklet_init(&priv->tx_reclaim_task, + mwl8k_tx_reclaim_handler, (unsigned long)hw); + tasklet_disable(&priv->tx_reclaim_task); /* Power management cookie */ priv->cookie = pci_alloc_consistent(priv->pdev, 4, &priv->cookie_dma); if (priv->cookie == NULL) - goto err_stop_firmware; + goto err_iounmap; rc = mwl8k_rxq_init(hw, 0); if (rc) - goto err_free_cookie; + goto err_iounmap; rxq_refill(hw, 0, INT_MAX); mutex_init(&priv->fw_mutex); @@ -4030,8 +3478,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); - iowrite32(MWL8K_A2H_INT_TX_DONE | MWL8K_A2H_INT_RX_READY, - priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL); + iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL); iowrite32(0xffffffff, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); rc = request_irq(priv->pdev->irq, mwl8k_interrupt, @@ -4042,9 +3489,31 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, goto err_free_queues; } + /* Reset firmware and hardware */ + mwl8k_hw_reset(priv); + + /* Ask userland hotplug daemon for the device firmware */ + rc = mwl8k_request_firmware(priv); + if (rc) { + printk(KERN_ERR "%s: Firmware files not found\n", + wiphy_name(hw->wiphy)); + goto err_free_irq; + } + + /* Load firmware into hardware */ + rc = mwl8k_load_firmware(hw); + if (rc) { + printk(KERN_ERR "%s: Cannot start firmware\n", + wiphy_name(hw->wiphy)); + goto err_stop_firmware; + } + + /* Reclaim memory once firmware is successfully loaded */ + mwl8k_release_firmware(priv); + /* * Temporarily enable interrupts. Initial firmware host - * commands use interrupts and avoid polling. Disable + * commands use interrupts and avoids polling. Disable * interrupts when done. */ iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); @@ -4060,29 +3529,22 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, if (rc) { printk(KERN_ERR "%s: Cannot initialise firmware\n", wiphy_name(hw->wiphy)); - goto err_free_irq; + goto err_stop_firmware; } - hw->wiphy->interface_modes = 0; - if (priv->ap_macids_supported) - hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP); - if (priv->sta_macids_supported) - hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_STATION); - - /* Turn radio off */ - rc = mwl8k_cmd_radio_disable(hw); + rc = mwl8k_cmd_802_11_radio_disable(hw); if (rc) { printk(KERN_ERR "%s: Cannot disable\n", wiphy_name(hw->wiphy)); - goto err_free_irq; + goto err_stop_firmware; } /* Clear MAC address */ - rc = mwl8k_cmd_set_mac_addr(hw, NULL, "\x00\x00\x00\x00\x00\x00"); + rc = mwl8k_set_mac_addr(hw, "\x00\x00\x00\x00\x00\x00"); if (rc) { printk(KERN_ERR "%s: Cannot clear MAC address\n", wiphy_name(hw->wiphy)); - goto err_free_irq; + goto err_stop_firmware; } /* Disable interrupts */ @@ -4093,7 +3555,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, if (rc) { printk(KERN_ERR "%s: Cannot register device\n", wiphy_name(hw->wiphy)); - goto err_free_queues; + goto err_stop_firmware; } printk(KERN_INFO "%s: %s v%d, %pM, %s firmware %u.%u.%u.%u\n", @@ -4105,6 +3567,10 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, return 0; +err_stop_firmware: + mwl8k_hw_reset(priv); + mwl8k_release_firmware(priv); + err_free_irq: iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); free_irq(priv->pdev->irq, hw); @@ -4114,16 +3580,11 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, mwl8k_txq_deinit(hw, i); mwl8k_rxq_deinit(hw, 0); -err_free_cookie: +err_iounmap: if (priv->cookie != NULL) pci_free_consistent(priv->pdev, 4, priv->cookie, priv->cookie_dma); -err_stop_firmware: - mwl8k_hw_reset(priv); - mwl8k_release_firmware(priv); - -err_iounmap: if (priv->regs != NULL) pci_iounmap(pdev, priv->regs); @@ -4161,16 +3622,15 @@ static void __devexit mwl8k_remove(struct pci_dev *pdev) ieee80211_unregister_hw(hw); - /* Remove TX reclaim and RX tasklets. */ - tasklet_kill(&priv->poll_tx_task); - tasklet_kill(&priv->poll_rx_task); + /* Remove tx reclaim tasklet */ + tasklet_kill(&priv->tx_reclaim_task); /* Stop hardware */ mwl8k_hw_reset(priv); /* Return all skbs to mac80211 */ for (i = 0; i < MWL8K_TX_QUEUES; i++) - mwl8k_txq_reclaim(hw, i, INT_MAX, 1); + mwl8k_txq_reclaim(hw, i, 1); for (i = 0; i < MWL8K_TX_QUEUES; i++) mwl8k_txq_deinit(hw, i); diff --git a/trunk/drivers/net/wireless/orinoco/orinoco_cs.c b/trunk/drivers/net/wireless/orinoco/orinoco_cs.c index 1d4ada188eda..f27bb8367c98 100644 --- a/trunk/drivers/net/wireless/orinoco/orinoco_cs.c +++ b/trunk/drivers/net/wireless/orinoco/orinoco_cs.c @@ -407,6 +407,7 @@ static struct pcmcia_device_id orinoco_cs_ids[] = { PCMCIA_DEVICE_PROD_ID12("3Com", "3CRWE737A AirConnect Wireless LAN PC Card", 0x41240e5b, 0x56010af3), PCMCIA_DEVICE_PROD_ID12("ACTIONTEC", "PRISM Wireless LAN PC Card", 0x393089da, 0xa71e69d5), PCMCIA_DEVICE_PROD_ID12("Addtron", "AWP-100 Wireless PCMCIA", 0xe6ec52ce, 0x08649af2), + PCMCIA_DEVICE_PROD_ID123("AIRVAST", "IEEE 802.11b Wireless PCMCIA Card", "HFA3863", 0xea569531, 0x4bcb9645, 0x355cb092), PCMCIA_DEVICE_PROD_ID12("Allied Telesyn", "AT-WCL452 Wireless PCMCIA Radio", 0x5cd01705, 0x4271660f), PCMCIA_DEVICE_PROD_ID12("ASUS", "802_11b_PC_CARD_25", 0x78fc06ee, 0xdb9aa842), PCMCIA_DEVICE_PROD_ID12("ASUS", "802_11B_CF_CARD_25", 0x78fc06ee, 0x45a50c1e), @@ -416,6 +417,7 @@ static struct pcmcia_device_id orinoco_cs_ids[] = { PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-CF-S11G", 0x2decece3, 0x82067c18), PCMCIA_DEVICE_PROD_ID12("Cabletron", "RoamAbout 802.11 DS", 0x32d445f5, 0xedeffd90), PCMCIA_DEVICE_PROD_ID12("Compaq", "WL200_11Mbps_Wireless_PCI_Card", 0x54f7c49c, 0x15a75e5b), + PCMCIA_DEVICE_PROD_ID123("corega", "WL PCCL-11", "ISL37300P", 0x0a21501a, 0x59868926, 0xc9049a39), PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCC-11", 0x5261440f, 0xa6405584), PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCCA-11", 0x5261440f, 0xdf6115f9), PCMCIA_DEVICE_PROD_ID12("corega_K.K.", "Wireless_LAN_PCCB-11", 0x29e33311, 0xee7a27ae), @@ -430,6 +432,7 @@ static struct pcmcia_device_id orinoco_cs_ids[] = { PCMCIA_DEVICE_PROD_ID12("INTERSIL", "HFA384x/IEEE", 0x74c5e40d, 0xdb472a18), PCMCIA_DEVICE_PROD_ID12("INTERSIL", "I-GATE 11M PC Card / PC Card plus", 0x74c5e40d, 0x8304ff77), PCMCIA_DEVICE_PROD_ID12("Intersil", "PRISM 2_5 PCMCIA ADAPTER", 0x4b801a17, 0x6345a0bf), + PCMCIA_DEVICE_PROD_ID123("Intersil", "PRISM Freedom PCMCIA Adapter", "ISL37100P", 0x4b801a17, 0xf222ec2d, 0x630d52b2), PCMCIA_DEVICE_PROD_ID12("LeArtery", "SYNCBYAIR 11Mbps Wireless LAN PC Card", 0x7e3b326a, 0x49893e92), PCMCIA_DEVICE_PROD_ID12("Linksys", "Wireless CompactFlash Card", 0x0733cc81, 0x0c52f395), PCMCIA_DEVICE_PROD_ID12("Lucent Technologies", "WaveLAN/IEEE", 0x23eb9949, 0xc562e72a), @@ -442,6 +445,7 @@ static struct pcmcia_device_id orinoco_cs_ids[] = { PCMCIA_DEVICE_PROD_ID12("Nortel Networks", "emobility 802.11 Wireless LAN PC Card", 0x2d617ea0, 0x88cd5767), PCMCIA_DEVICE_PROD_ID12("OEM", "PRISM2 IEEE 802.11 PC-Card", 0xfea54c90, 0x48f2bdd6), PCMCIA_DEVICE_PROD_ID12("OTC", "Wireless AirEZY 2411-PCC WLAN Card", 0x4ac44287, 0x235a6bed), + PCMCIA_DEVICE_PROD_ID123("PCMCIA", "11M WLAN Card v2.5", "ISL37300P", 0x281f1c5d, 0x6e440487, 0xc9049a39), PCMCIA_DEVICE_PROD_ID12("PLANEX", "GeoWave/GW-CF110", 0x209f40ab, 0xd9715264), PCMCIA_DEVICE_PROD_ID12("PLANEX", "GeoWave/GW-NS110", 0x209f40ab, 0x46263178), PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PC CARD HARMONY 80211B", 0xc6536a5e, 0x090c3cd9), @@ -450,11 +454,8 @@ static struct pcmcia_device_id orinoco_cs_ids[] = { PCMCIA_DEVICE_PROD_ID12("SMC", "SMC2532W-B EliteConnect Wireless Adapter", 0xc4f8b18b, 0x196bd757), PCMCIA_DEVICE_PROD_ID12("SMC", "SMC2632W", 0xc4f8b18b, 0x474a1f2a), PCMCIA_DEVICE_PROD_ID12("Symbol Technologies", "LA4111 Spectrum24 Wireless LAN PC Card", 0x3f02b4d6, 0x3663cb0e), + PCMCIA_DEVICE_PROD_ID123("The Linksys Group, Inc.", "Instant Wireless Network PC Card", "ISL37300P", 0xa5f472c2, 0x590eb502, 0xc9049a39), PCMCIA_DEVICE_PROD_ID12("ZoomAir 11Mbps High", "Rate wireless Networking", 0x273fe3db, 0x32a1eaee), - PCMCIA_DEVICE_PROD_ID3("HFA3863", 0x355cb092), - PCMCIA_DEVICE_PROD_ID3("ISL37100P", 0x630d52b2), - PCMCIA_DEVICE_PROD_ID3("ISL37101P-10", 0xdd97a26b), - PCMCIA_DEVICE_PROD_ID3("ISL37300P", 0xc9049a39), PCMCIA_DEVICE_NULL, }; MODULE_DEVICE_TABLE(pcmcia, orinoco_cs_ids); diff --git a/trunk/drivers/net/wireless/p54/main.c b/trunk/drivers/net/wireless/p54/main.c index 4f752a21495f..18012dbfb45d 100644 --- a/trunk/drivers/net/wireless/p54/main.c +++ b/trunk/drivers/net/wireless/p54/main.c @@ -33,29 +33,21 @@ MODULE_DESCRIPTION("Softmac Prism54 common code"); MODULE_LICENSE("GPL"); MODULE_ALIAS("prism54common"); -static int p54_sta_add_remove(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) -{ - struct p54_common *priv = hw->priv; - - /* - * Notify the firmware that we don't want or we don't - * need to buffer frames for this station anymore. - */ - - p54_sta_unlock(priv, sta->addr); - - return 0; -} - static void p54_sta_notify(struct ieee80211_hw *dev, struct ieee80211_vif *vif, enum sta_notify_cmd notify_cmd, struct ieee80211_sta *sta) { struct p54_common *priv = dev->priv; - 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(priv, sta->addr); + break; case STA_NOTIFY_AWAKE: /* update the firmware's filter table */ p54_sta_unlock(priv, sta->addr); @@ -224,7 +216,7 @@ static void p54_stop(struct ieee80211_hw *dev) } static int p54_add_interface(struct ieee80211_hw *dev, - struct ieee80211_vif *vif) + struct ieee80211_if_init_conf *conf) { struct p54_common *priv = dev->priv; @@ -234,28 +226,28 @@ static int p54_add_interface(struct ieee80211_hw *dev, return -EOPNOTSUPP; } - priv->vif = vif; + priv->vif = conf->vif; - switch (vif->type) { + switch (conf->type) { case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_AP: case NL80211_IFTYPE_MESH_POINT: - priv->mode = vif->type; + priv->mode = conf->type; break; default: mutex_unlock(&priv->conf_mutex); return -EOPNOTSUPP; } - memcpy(priv->mac_addr, vif->addr, ETH_ALEN); + memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); p54_setup_mac(priv); mutex_unlock(&priv->conf_mutex); return 0; } static void p54_remove_interface(struct ieee80211_hw *dev, - struct ieee80211_vif *vif) + struct ieee80211_if_init_conf *conf) { struct p54_common *priv = dev->priv; @@ -366,6 +358,16 @@ static int p54_get_stats(struct ieee80211_hw *dev, return 0; } +static int p54_get_tx_stats(struct ieee80211_hw *dev, + struct ieee80211_tx_queue_stats *stats) +{ + struct p54_common *priv = dev->priv; + + memcpy(stats, &priv->tx_stats[P54_QUEUE_DATA], + sizeof(stats[0]) * dev->queues); + return 0; +} + static void p54_bss_info_changed(struct ieee80211_hw *dev, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, @@ -514,14 +516,13 @@ static const struct ieee80211_ops p54_ops = { .remove_interface = p54_remove_interface, .set_tim = p54_set_tim, .sta_notify = p54_sta_notify, - .sta_add = p54_sta_add_remove, - .sta_remove = p54_sta_add_remove, .set_key = p54_set_key, .config = p54_config, .bss_info_changed = p54_bss_info_changed, .configure_filter = p54_configure_filter, .conf_tx = p54_conf_tx, .get_stats = p54_get_stats, + .get_tx_stats = p54_get_tx_stats }; struct ieee80211_hw *p54_init_common(size_t priv_data_len) diff --git a/trunk/drivers/net/wireless/p54/p54.h b/trunk/drivers/net/wireless/p54/p54.h index 43a3b2ead81a..1afc39410e85 100644 --- a/trunk/drivers/net/wireless/p54/p54.h +++ b/trunk/drivers/net/wireless/p54/p54.h @@ -157,12 +157,6 @@ struct p54_led_dev { #endif /* CONFIG_P54_LEDS */ -struct p54_tx_queue_stats { - unsigned int len; - unsigned int limit; - unsigned int count; -}; - struct p54_common { struct ieee80211_hw *hw; struct ieee80211_vif *vif; @@ -189,7 +183,7 @@ struct p54_common { /* (e)DCF / QOS state */ bool use_short_slot; spinlock_t tx_stats_lock; - struct p54_tx_queue_stats tx_stats[8]; + struct ieee80211_tx_queue_stats tx_stats[8]; struct p54_edcf_queue_param qos_params[8]; /* Radio data */ diff --git a/trunk/drivers/net/wireless/p54/p54pci.c b/trunk/drivers/net/wireless/p54/p54pci.c index bda29c00f3ef..a72f7c2577de 100644 --- a/trunk/drivers/net/wireless/p54/p54pci.c +++ b/trunk/drivers/net/wireless/p54/p54pci.c @@ -157,14 +157,6 @@ static void p54p_refill_rx_ring(struct ieee80211_hw *dev, skb_tail_pointer(skb), priv->common.rx_mtu + 32, PCI_DMA_FROMDEVICE); - - if (pci_dma_mapping_error(priv->pdev, mapping)) { - dev_kfree_skb_any(skb); - dev_err(&priv->pdev->dev, - "RX DMA Mapping error\n"); - break; - } - desc->host_addr = cpu_to_le32(mapping); desc->device_addr = 0; // FIXME: necessary? desc->len = cpu_to_le16(priv->common.rx_mtu + 32); @@ -234,14 +226,14 @@ static void p54p_check_rx_ring(struct ieee80211_hw *dev, u32 *index, p54p_refill_rx_ring(dev, ring_index, ring, ring_limit, rx_buf); } +/* caller must hold priv->lock */ static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index, int ring_index, struct p54p_desc *ring, u32 ring_limit, - struct sk_buff **tx_buf) + void **tx_buf) { struct p54p_priv *priv = dev->priv; struct p54p_ring_control *ring_control = priv->ring_control; struct p54p_desc *desc; - struct sk_buff *skb; u32 idx, i; i = (*index) % ring_limit; @@ -250,8 +242,9 @@ static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index, while (i != idx) { desc = &ring[i]; - - skb = 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), @@ -262,28 +255,17 @@ static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index, desc->len = 0; desc->flags = 0; - if (skb && FREE_AFTER_TX(skb)) - p54_free_skb(dev, skb); - i++; i %= ring_limit; } } -static void p54p_tasklet(unsigned long dev_id) +static void p54p_rx_tasklet(unsigned long dev_id) { struct ieee80211_hw *dev = (struct ieee80211_hw *)dev_id; struct p54p_priv *priv = dev->priv; struct p54p_ring_control *ring_control = priv->ring_control; - p54p_check_tx_ring(dev, &priv->tx_idx_mgmt, 3, ring_control->tx_mgmt, - ARRAY_SIZE(ring_control->tx_mgmt), - priv->tx_buf_mgmt); - - p54p_check_tx_ring(dev, &priv->tx_idx_data, 1, ring_control->tx_data, - ARRAY_SIZE(ring_control->tx_data), - priv->tx_buf_data); - p54p_check_rx_ring(dev, &priv->rx_idx_mgmt, 2, ring_control->rx_mgmt, ARRAY_SIZE(ring_control->rx_mgmt), priv->rx_buf_mgmt); @@ -298,49 +280,59 @@ static irqreturn_t p54p_interrupt(int irq, void *dev_id) { struct ieee80211_hw *dev = dev_id; struct p54p_priv *priv = dev->priv; + struct p54p_ring_control *ring_control = priv->ring_control; __le32 reg; + spin_lock(&priv->lock); reg = P54P_READ(int_ident); if (unlikely(reg == cpu_to_le32(0xFFFFFFFF))) { - goto out; + spin_unlock(&priv->lock); + return IRQ_HANDLED; } + P54P_WRITE(int_ack, reg); reg &= P54P_READ(int_enable); - if (reg & cpu_to_le32(ISL38XX_INT_IDENT_UPDATE)) - tasklet_schedule(&priv->tasklet); - else if (reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)) + if (reg & cpu_to_le32(ISL38XX_INT_IDENT_UPDATE)) { + p54p_check_tx_ring(dev, &priv->tx_idx_mgmt, + 3, ring_control->tx_mgmt, + ARRAY_SIZE(ring_control->tx_mgmt), + priv->tx_buf_mgmt); + + p54p_check_tx_ring(dev, &priv->tx_idx_data, + 1, ring_control->tx_data, + ARRAY_SIZE(ring_control->tx_data), + priv->tx_buf_data); + + tasklet_schedule(&priv->rx_tasklet); + + } else if (reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)) complete(&priv->boot_comp); -out: + spin_unlock(&priv->lock); + return reg ? IRQ_HANDLED : IRQ_NONE; } static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb) { - unsigned long flags; struct p54p_priv *priv = dev->priv; struct p54p_ring_control *ring_control = priv->ring_control; + unsigned long flags; struct p54p_desc *desc; dma_addr_t mapping; u32 device_idx, idx, i; spin_lock_irqsave(&priv->lock, flags); + device_idx = le32_to_cpu(ring_control->device_idx[1]); idx = le32_to_cpu(ring_control->host_idx[1]); i = idx % ARRAY_SIZE(ring_control->tx_data); + priv->tx_buf_data[i] = skb; mapping = pci_map_single(priv->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); - if (pci_dma_mapping_error(priv->pdev, mapping)) { - spin_unlock_irqrestore(&priv->lock, flags); - p54_free_skb(dev, skb); - dev_err(&priv->pdev->dev, "TX DMA mapping error\n"); - return ; - } - priv->tx_buf_data[i] = skb; - desc = &ring_control->tx_data[i]; desc->host_addr = cpu_to_le32(mapping); desc->device_addr = ((struct p54_hdr *)skb->data)->req_id; @@ -362,14 +354,14 @@ static void p54p_stop(struct ieee80211_hw *dev) unsigned int i; struct p54p_desc *desc; + tasklet_kill(&priv->rx_tasklet); + P54P_WRITE(int_enable, cpu_to_le32(0)); P54P_READ(int_enable); udelay(10); free_irq(priv->pdev->irq, dev); - tasklet_kill(&priv->tasklet); - P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET)); for (i = 0; i < ARRAY_SIZE(priv->rx_buf_data); i++) { @@ -553,7 +545,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev, priv->common.tx = p54p_tx; spin_lock_init(&priv->lock); - tasklet_init(&priv->tasklet, p54p_tasklet, (unsigned long)dev); + tasklet_init(&priv->rx_tasklet, p54p_rx_tasklet, (unsigned long)dev); err = request_firmware(&priv->firmware, "isl3886pci", &priv->pdev->dev); diff --git a/trunk/drivers/net/wireless/p54/p54pci.h b/trunk/drivers/net/wireless/p54/p54pci.h index 2feead617a3b..fbb683953fb2 100644 --- a/trunk/drivers/net/wireless/p54/p54pci.h +++ b/trunk/drivers/net/wireless/p54/p54pci.h @@ -92,7 +92,7 @@ struct p54p_priv { struct p54_common common; struct pci_dev *pdev; struct p54p_csr __iomem *map; - struct tasklet_struct tasklet; + struct tasklet_struct rx_tasklet; const struct firmware *firmware; spinlock_t lock; struct p54p_ring_control *ring_control; @@ -101,8 +101,8 @@ struct p54p_priv { u32 rx_idx_mgmt, tx_idx_mgmt; struct sk_buff *rx_buf_data[8]; struct sk_buff *rx_buf_mgmt[4]; - struct sk_buff *tx_buf_data[32]; - struct sk_buff *tx_buf_mgmt[4]; + void *tx_buf_data[32]; + void *tx_buf_mgmt[4]; struct completion boot_comp; }; diff --git a/trunk/drivers/net/wireless/p54/p54usb.c b/trunk/drivers/net/wireless/p54/p54usb.c index b3c4fbd80d8d..92af9b96bb7a 100644 --- a/trunk/drivers/net/wireless/p54/p54usb.c +++ b/trunk/drivers/net/wireless/p54/p54usb.c @@ -36,7 +36,6 @@ static struct usb_device_id p54u_table[] __devinitdata = { /* Version 1 devices (pci chip + net2280) */ {USB_DEVICE(0x0506, 0x0a11)}, /* 3COM 3CRWE254G72 */ {USB_DEVICE(0x0707, 0xee06)}, /* SMC 2862W-G */ - {USB_DEVICE(0x07aa, 0x001c)}, /* Corega CG-WLUSB2GT */ {USB_DEVICE(0x083a, 0x4501)}, /* Accton 802.11g WN4501 USB */ {USB_DEVICE(0x083a, 0x4502)}, /* Siemens Gigaset USB Adapter */ {USB_DEVICE(0x083a, 0x5501)}, /* Phillips CPWUA054 */ @@ -61,7 +60,6 @@ static struct usb_device_id p54u_table[] __devinitdata = { {USB_DEVICE(0x06b9, 0x0121)}, /* Thomson SpeedTouch 121g */ {USB_DEVICE(0x0707, 0xee13)}, /* SMC 2862W-G version 2 */ {USB_DEVICE(0x083a, 0x4521)}, /* Siemens Gigaset USB Adapter 54 version 2 */ - {USB_DEVICE(0x083a, 0xf503)}, /* Accton FD7050E ver 1010ec */ {USB_DEVICE(0x0846, 0x4240)}, /* Netgear WG111 (v2) */ {USB_DEVICE(0x0915, 0x2000)}, /* Cohiba Proto board */ {USB_DEVICE(0x0915, 0x2002)}, /* Cohiba Proto board */ diff --git a/trunk/drivers/net/wireless/p54/txrx.c b/trunk/drivers/net/wireless/p54/txrx.c index 66057999a93c..b6dda2b27fb5 100644 --- a/trunk/drivers/net/wireless/p54/txrx.c +++ b/trunk/drivers/net/wireless/p54/txrx.c @@ -183,10 +183,10 @@ static int p54_tx_qos_accounting_alloc(struct p54_common *priv, struct sk_buff *skb, const u16 p54_queue) { - struct p54_tx_queue_stats *queue; + struct ieee80211_tx_queue_stats *queue; unsigned long flags; - if (WARN_ON(p54_queue >= P54_QUEUE_NUM)) + if (WARN_ON(p54_queue > P54_QUEUE_NUM)) return -EINVAL; queue = &priv->tx_stats[p54_queue]; diff --git a/trunk/drivers/net/wireless/rndis_wlan.c b/trunk/drivers/net/wireless/rndis_wlan.c index 305c106fdc1c..2ecbedb26e15 100644 --- a/trunk/drivers/net/wireless/rndis_wlan.c +++ b/trunk/drivers/net/wireless/rndis_wlan.c @@ -2594,9 +2594,23 @@ static void rndis_device_poller(struct work_struct *work) /* * driver/device initialization */ -static void rndis_copy_module_params(struct usbnet *usbdev) +static int bcm4320a_early_init(struct usbnet *usbdev) +{ + /* bcm4320a doesn't handle configuration parameters well. Try + * set any and you get partially zeroed mac and broken device. + */ + + return 0; +} + +static int bcm4320b_early_init(struct usbnet *usbdev) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); + char buf[8]; + + /* Early initialization settings, setting these won't have effect + * if called after generic_rndis_bind(). + */ priv->param_country[0] = modparam_country[0]; priv->param_country[1] = modparam_country[1]; @@ -2638,32 +2652,6 @@ static void rndis_copy_module_params(struct usbnet *usbdev) priv->param_workaround_interval = 500; else priv->param_workaround_interval = modparam_workaround_interval; -} - -static int bcm4320a_early_init(struct usbnet *usbdev) -{ - /* copy module parameters for bcm4320a so that iwconfig reports txpower - * and workaround parameter is copied to private structure correctly. - */ - rndis_copy_module_params(usbdev); - - /* bcm4320a doesn't handle configuration parameters well. Try - * set any and you get partially zeroed mac and broken device. - */ - - return 0; -} - -static int bcm4320b_early_init(struct usbnet *usbdev) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - char buf[8]; - - rndis_copy_module_params(usbdev); - - /* Early initialization settings, setting these won't have effect - * if called after generic_rndis_bind(). - */ rndis_set_config_parameter_str(usbdev, "Country", priv->param_country); rndis_set_config_parameter_str(usbdev, "FrameBursting", diff --git a/trunk/drivers/net/wireless/rt2x00/Kconfig b/trunk/drivers/net/wireless/rt2x00/Kconfig index 5239e082cd0f..bf60689aaabb 100644 --- a/trunk/drivers/net/wireless/rt2x00/Kconfig +++ b/trunk/drivers/net/wireless/rt2x00/Kconfig @@ -54,17 +54,17 @@ config RT61PCI When compiled as a module, this driver will be called rt61pci. config RT2800PCI_PCI - boolean + tristate depends on PCI default y config RT2800PCI_SOC - boolean + tristate depends on RALINK_RT288X || RALINK_RT305X default y config RT2800PCI - tristate "Ralink rt28xx/rt30xx/rt35xx (PCI/PCIe/PCMCIA) support (EXPERIMENTAL)" + tristate "Ralink rt2800 (PCI/PCMCIA) support (VERY EXPERIMENTAL)" depends on (RT2800PCI_PCI || RT2800PCI_SOC) && EXPERIMENTAL select RT2800_LIB select RT2X00_LIB_PCI if RT2800PCI_PCI @@ -75,7 +75,7 @@ config RT2800PCI select CRC_CCITT select EEPROM_93CX6 ---help--- - This adds support for rt2800/rt3000/rt3500 wireless chipset family. + This adds support for rt2800 wireless chipset family. Supported chips: RT2760, RT2790, RT2860, RT2880, RT2890 & RT3052 This driver is non-functional at the moment and is intended for @@ -83,32 +83,6 @@ config RT2800PCI When compiled as a module, this driver will be called "rt2800pci.ko". -if RT2800PCI - -config RT2800PCI_RT30XX - bool "rt2800pci - Include support for rt30xx (PCI/PCIe/PCMCIA) devices" - default n - ---help--- - This adds support for rt30xx wireless chipset family to the - rt2800pci driver. - Supported chips: RT3090, RT3091 & RT3092 - - Support for these devices is non-functional at the moment and is - intended for testers and developers. - -config RT2800PCI_RT35XX - bool "rt2800pci - Include support for rt35xx (PCI/PCIe/PCMCIA) devices" - default n - ---help--- - This adds support for rt35xx wireless chipset family to the - rt2800pci driver. - Supported chips: RT3060, RT3062, RT3562, RT3592 - - Support for these devices is non-functional at the moment and is - intended for testers and developers. - -endif - config RT2500USB tristate "Ralink rt2500 (USB) support" depends on USB @@ -152,43 +126,6 @@ config RT2800USB When compiled as a module, this driver will be called "rt2800usb.ko". -if RT2800USB - -config RT2800USB_RT30XX - bool "rt2800usb - Include support for rt30xx (USB) devices" - default n - ---help--- - This adds support for rt30xx wireless chipset family to the - rt2800usb driver. - Supported chips: RT3070, RT3071 & RT3072 - - Support for these devices is non-functional at the moment and is - intended for testers and developers. - -config RT2800USB_RT35XX - bool "rt2800usb - Include support for rt35xx (USB) devices" - default n - ---help--- - This adds support for rt35xx wireless chipset family to the - rt2800usb driver. - Supported chips: RT3572 - - Support for these devices is non-functional at the moment and is - intended for testers and developers. - -config RT2800USB_UNKNOWN - bool "rt2800usb - Include support for unknown (USB) devices" - default n - ---help--- - This adds support for rt2800 family devices that are known to - have a rt2800 family chipset, but for which the exact chipset - is unknown. - - Support status for these devices is unknown, and enabling these - devices may or may not work. - -endif - config RT2800_LIB tristate diff --git a/trunk/drivers/net/wireless/rt2x00/rt2400pci.c b/trunk/drivers/net/wireless/rt2x00/rt2400pci.c index 676814d3a81b..e7f46405a418 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/trunk/drivers/net/wireless/rt2x00/rt2400pci.c @@ -451,7 +451,7 @@ static void rt2400pci_config_channel(struct rt2x00_dev *rt2x00dev, /* * RF2420 chipset don't need any additional actions. */ - if (rt2x00_rf(rt2x00dev, RF2420)) + if (rt2x00_rf(&rt2x00dev->chip, RF2420)) return; /* @@ -1340,10 +1340,11 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev) */ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); rt2x00pci_register_read(rt2x00dev, CSR0, ®); - rt2x00_set_chip(rt2x00dev, RT2460, value, - rt2x00_get_field32(reg, CSR0_REVISION)); + rt2x00_set_chip_rf(rt2x00dev, value, reg); + rt2x00_print_chip(rt2x00dev); - if (!rt2x00_rf(rt2x00dev, RF2420) && !rt2x00_rf(rt2x00dev, RF2421)) { + if (!rt2x00_rf(&rt2x00dev->chip, RF2420) && + !rt2x00_rf(&rt2x00dev->chip, RF2421)) { ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); return -ENODEV; } @@ -1561,6 +1562,7 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = { .get_stats = rt2x00mac_get_stats, .bss_info_changed = rt2x00mac_bss_info_changed, .conf_tx = rt2400pci_conf_tx, + .get_tx_stats = rt2x00mac_get_tx_stats, .get_tsf = rt2400pci_get_tsf, .tx_last_beacon = rt2400pci_tx_last_beacon, .rfkill_poll = rt2x00mac_rfkill_poll, diff --git a/trunk/drivers/net/wireless/rt2x00/rt2400pci.h b/trunk/drivers/net/wireless/rt2x00/rt2400pci.h index 606137738848..6c21ef66dfe0 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2400pci.h +++ b/trunk/drivers/net/wireless/rt2x00/rt2400pci.h @@ -65,7 +65,6 @@ * CSR0: ASIC revision number. */ #define CSR0 0x0000 -#define CSR0_REVISION FIELD32(0x0000ffff) /* * CSR1: System control register. diff --git a/trunk/drivers/net/wireless/rt2x00/rt2500pci.c b/trunk/drivers/net/wireless/rt2x00/rt2500pci.c index c71266142ae9..408fcfc120f5 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/trunk/drivers/net/wireless/rt2x00/rt2500pci.c @@ -440,7 +440,8 @@ static void rt2500pci_config_ant(struct rt2x00_dev *rt2x00dev, /* * RT2525E and RT5222 need to flip TX I/Q */ - if (rt2x00_rf(rt2x00dev, RF2525E) || rt2x00_rf(rt2x00dev, RF5222)) { + if (rt2x00_rf(&rt2x00dev->chip, RF2525E) || + rt2x00_rf(&rt2x00dev->chip, RF5222)) { rt2x00_set_field8(&r2, BBP_R2_TX_IQ_FLIP, 1); rt2x00_set_field32(®, BBPCSR1_CCK_FLIP, 1); rt2x00_set_field32(®, BBPCSR1_OFDM_FLIP, 1); @@ -448,7 +449,7 @@ static void rt2500pci_config_ant(struct rt2x00_dev *rt2x00dev, /* * RT2525E does not need RX I/Q Flip. */ - if (rt2x00_rf(rt2x00dev, RF2525E)) + if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) rt2x00_set_field8(&r14, BBP_R14_RX_IQ_FLIP, 0); } else { rt2x00_set_field32(®, BBPCSR1_CCK_FLIP, 0); @@ -474,14 +475,14 @@ static void rt2500pci_config_channel(struct rt2x00_dev *rt2x00dev, * Switch on tuning bits. * For RT2523 devices we do not need to update the R1 register. */ - if (!rt2x00_rf(rt2x00dev, RF2523)) + if (!rt2x00_rf(&rt2x00dev->chip, RF2523)) rt2x00_set_field32(&rf->rf1, RF1_TUNER, 1); rt2x00_set_field32(&rf->rf3, RF3_TUNER, 1); /* * For RT2525 we should first set the channel to half band higher. */ - if (rt2x00_rf(rt2x00dev, RF2525)) { + if (rt2x00_rf(&rt2x00dev->chip, RF2525)) { static const u32 vals[] = { 0x00080cbe, 0x00080d02, 0x00080d06, 0x00080d0a, 0x00080d0e, 0x00080d12, 0x00080d16, 0x00080d1a, @@ -515,7 +516,7 @@ static void rt2500pci_config_channel(struct rt2x00_dev *rt2x00dev, * Switch off tuning bits. * For RT2523 devices we do not need to update the R1 register. */ - if (!rt2x00_rf(rt2x00dev, RF2523)) { + if (!rt2x00_rf(&rt2x00dev->chip, RF2523)) { rt2x00_set_field32(&rf->rf1, RF1_TUNER, 0); rt2500pci_rf_write(rt2x00dev, 1, rf->rf1); } @@ -639,7 +640,7 @@ static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev, * up to version C the link tuning should halt after 20 * seconds while being associated. */ - if (rt2x00_rev(rt2x00dev) < RT2560_VERSION_D && + if (rt2x00_rev(&rt2x00dev->chip) < RT2560_VERSION_D && rt2x00dev->intf_associated && count > 20) return; @@ -649,7 +650,7 @@ static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev, * should go straight to dynamic CCA tuning when they * are not associated. */ - if (rt2x00_rev(rt2x00dev) < RT2560_VERSION_D || + if (rt2x00_rev(&rt2x00dev->chip) < RT2560_VERSION_D || !rt2x00dev->intf_associated) goto dynamic_cca_tune; @@ -1503,15 +1504,15 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev) */ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); rt2x00pci_register_read(rt2x00dev, CSR0, ®); - rt2x00_set_chip(rt2x00dev, RT2560, value, - rt2x00_get_field32(reg, CSR0_REVISION)); - - if (!rt2x00_rf(rt2x00dev, RF2522) && - !rt2x00_rf(rt2x00dev, RF2523) && - !rt2x00_rf(rt2x00dev, RF2524) && - !rt2x00_rf(rt2x00dev, RF2525) && - !rt2x00_rf(rt2x00dev, RF2525E) && - !rt2x00_rf(rt2x00dev, RF5222)) { + rt2x00_set_chip_rf(rt2x00dev, value, reg); + rt2x00_print_chip(rt2x00dev); + + if (!rt2x00_rf(&rt2x00dev->chip, RF2522) && + !rt2x00_rf(&rt2x00dev->chip, RF2523) && + !rt2x00_rf(&rt2x00dev->chip, RF2524) && + !rt2x00_rf(&rt2x00dev->chip, RF2525) && + !rt2x00_rf(&rt2x00dev->chip, RF2525E) && + !rt2x00_rf(&rt2x00dev->chip, RF5222)) { ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); return -ENODEV; } @@ -1743,22 +1744,22 @@ static int rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) spec->supported_bands = SUPPORT_BAND_2GHZ; spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM; - if (rt2x00_rf(rt2x00dev, RF2522)) { + if (rt2x00_rf(&rt2x00dev->chip, RF2522)) { spec->num_channels = ARRAY_SIZE(rf_vals_bg_2522); spec->channels = rf_vals_bg_2522; - } else if (rt2x00_rf(rt2x00dev, RF2523)) { + } else if (rt2x00_rf(&rt2x00dev->chip, RF2523)) { spec->num_channels = ARRAY_SIZE(rf_vals_bg_2523); spec->channels = rf_vals_bg_2523; - } else if (rt2x00_rf(rt2x00dev, RF2524)) { + } else if (rt2x00_rf(&rt2x00dev->chip, RF2524)) { spec->num_channels = ARRAY_SIZE(rf_vals_bg_2524); spec->channels = rf_vals_bg_2524; - } else if (rt2x00_rf(rt2x00dev, RF2525)) { + } else if (rt2x00_rf(&rt2x00dev->chip, RF2525)) { spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525); spec->channels = rf_vals_bg_2525; - } else if (rt2x00_rf(rt2x00dev, RF2525E)) { + } else if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) { spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525e); spec->channels = rf_vals_bg_2525e; - } else if (rt2x00_rf(rt2x00dev, RF5222)) { + } else if (rt2x00_rf(&rt2x00dev->chip, RF5222)) { spec->supported_bands |= SUPPORT_BAND_5GHZ; spec->num_channels = ARRAY_SIZE(rf_vals_5222); spec->channels = rf_vals_5222; @@ -1859,6 +1860,7 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = { .get_stats = rt2x00mac_get_stats, .bss_info_changed = rt2x00mac_bss_info_changed, .conf_tx = rt2x00mac_conf_tx, + .get_tx_stats = rt2x00mac_get_tx_stats, .get_tsf = rt2500pci_get_tsf, .tx_last_beacon = rt2500pci_tx_last_beacon, .rfkill_poll = rt2x00mac_rfkill_poll, diff --git a/trunk/drivers/net/wireless/rt2x00/rt2500pci.h b/trunk/drivers/net/wireless/rt2x00/rt2500pci.h index 6471f8e74b35..b0075674c09b 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2500pci.h +++ b/trunk/drivers/net/wireless/rt2x00/rt2500pci.h @@ -76,7 +76,6 @@ * CSR0: ASIC revision number. */ #define CSR0 0x0000 -#define CSR0_REVISION FIELD32(0x0000ffff) /* * CSR1: System control register. diff --git a/trunk/drivers/net/wireless/rt2x00/rt2500usb.c b/trunk/drivers/net/wireless/rt2x00/rt2500usb.c index ee34c137e7cd..83f2592c59de 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/trunk/drivers/net/wireless/rt2x00/rt2500usb.c @@ -565,7 +565,8 @@ static void rt2500usb_config_ant(struct rt2x00_dev *rt2x00dev, /* * RT2525E and RT5222 need to flip TX I/Q */ - if (rt2x00_rf(rt2x00dev, RF2525E) || rt2x00_rf(rt2x00dev, RF5222)) { + if (rt2x00_rf(&rt2x00dev->chip, RF2525E) || + rt2x00_rf(&rt2x00dev->chip, RF5222)) { rt2x00_set_field8(&r2, BBP_R2_TX_IQ_FLIP, 1); rt2x00_set_field16(&csr5, PHY_CSR5_CCK_FLIP, 1); rt2x00_set_field16(&csr6, PHY_CSR6_OFDM_FLIP, 1); @@ -573,7 +574,7 @@ static void rt2500usb_config_ant(struct rt2x00_dev *rt2x00dev, /* * RT2525E does not need RX I/Q Flip. */ - if (rt2x00_rf(rt2x00dev, RF2525E)) + if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) rt2x00_set_field8(&r14, BBP_R14_RX_IQ_FLIP, 0); } else { rt2x00_set_field16(&csr5, PHY_CSR5_CCK_FLIP, 0); @@ -597,7 +598,7 @@ static void rt2500usb_config_channel(struct rt2x00_dev *rt2x00dev, /* * For RT2525E we should first set the channel to half band higher. */ - if (rt2x00_rf(rt2x00dev, RF2525E)) { + if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) { static const u32 vals[] = { 0x000008aa, 0x000008ae, 0x000008ae, 0x000008b2, 0x000008b2, 0x000008b6, 0x000008b6, 0x000008ba, @@ -792,7 +793,7 @@ static int rt2500usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field16(®, MAC_CSR1_HOST_READY, 1); rt2500usb_register_write(rt2x00dev, MAC_CSR1, reg); - if (rt2x00_rev(rt2x00dev) >= RT2570_VERSION_C) { + if (rt2x00_rev(&rt2x00dev->chip) >= RT2570_VERSION_C) { rt2500usb_register_read(rt2x00dev, PHY_CSR2, ®); rt2x00_set_field16(®, PHY_CSR2_LNA, 0); } else { @@ -1408,18 +1409,21 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev) value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); rt2500usb_register_read(rt2x00dev, MAC_CSR0, ®); rt2x00_set_chip(rt2x00dev, RT2570, value, reg); + rt2x00_print_chip(rt2x00dev); + + if (!rt2x00_check_rev(&rt2x00dev->chip, 0x000ffff0, 0) || + rt2x00_check_rev(&rt2x00dev->chip, 0x0000000f, 0)) { - if (((reg & 0xfff0) != 0) || ((reg & 0x0000000f) == 0)) { ERROR(rt2x00dev, "Invalid RT chipset detected.\n"); return -ENODEV; } - if (!rt2x00_rf(rt2x00dev, RF2522) && - !rt2x00_rf(rt2x00dev, RF2523) && - !rt2x00_rf(rt2x00dev, RF2524) && - !rt2x00_rf(rt2x00dev, RF2525) && - !rt2x00_rf(rt2x00dev, RF2525E) && - !rt2x00_rf(rt2x00dev, RF5222)) { + if (!rt2x00_rf(&rt2x00dev->chip, RF2522) && + !rt2x00_rf(&rt2x00dev->chip, RF2523) && + !rt2x00_rf(&rt2x00dev->chip, RF2524) && + !rt2x00_rf(&rt2x00dev->chip, RF2525) && + !rt2x00_rf(&rt2x00dev->chip, RF2525E) && + !rt2x00_rf(&rt2x00dev->chip, RF5222)) { ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); return -ENODEV; } @@ -1663,22 +1667,22 @@ static int rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) spec->supported_bands = SUPPORT_BAND_2GHZ; spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM; - if (rt2x00_rf(rt2x00dev, RF2522)) { + if (rt2x00_rf(&rt2x00dev->chip, RF2522)) { spec->num_channels = ARRAY_SIZE(rf_vals_bg_2522); spec->channels = rf_vals_bg_2522; - } else if (rt2x00_rf(rt2x00dev, RF2523)) { + } else if (rt2x00_rf(&rt2x00dev->chip, RF2523)) { spec->num_channels = ARRAY_SIZE(rf_vals_bg_2523); spec->channels = rf_vals_bg_2523; - } else if (rt2x00_rf(rt2x00dev, RF2524)) { + } else if (rt2x00_rf(&rt2x00dev->chip, RF2524)) { spec->num_channels = ARRAY_SIZE(rf_vals_bg_2524); spec->channels = rf_vals_bg_2524; - } else if (rt2x00_rf(rt2x00dev, RF2525)) { + } else if (rt2x00_rf(&rt2x00dev->chip, RF2525)) { spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525); spec->channels = rf_vals_bg_2525; - } else if (rt2x00_rf(rt2x00dev, RF2525E)) { + } else if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) { spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525e); spec->channels = rf_vals_bg_2525e; - } else if (rt2x00_rf(rt2x00dev, RF5222)) { + } else if (rt2x00_rf(&rt2x00dev->chip, RF5222)) { spec->supported_bands |= SUPPORT_BAND_5GHZ; spec->num_channels = ARRAY_SIZE(rf_vals_5222); spec->channels = rf_vals_5222; @@ -1759,6 +1763,7 @@ static const struct ieee80211_ops rt2500usb_mac80211_ops = { .get_stats = rt2x00mac_get_stats, .bss_info_changed = rt2x00mac_bss_info_changed, .conf_tx = rt2x00mac_conf_tx, + .get_tx_stats = rt2x00mac_get_tx_stats, .rfkill_poll = rt2x00mac_rfkill_poll, }; diff --git a/trunk/drivers/net/wireless/rt2x00/rt2800.h b/trunk/drivers/net/wireless/rt2x00/rt2800.h index 74c0433dba37..1a7eae357fef 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2800.h +++ b/trunk/drivers/net/wireless/rt2x00/rt2800.h @@ -60,11 +60,11 @@ /* * Chipset version. */ -#define RT2860C_VERSION 0x0100 -#define RT2860D_VERSION 0x0101 -#define RT2880E_VERSION 0x0200 -#define RT2883_VERSION 0x0300 -#define RT3070_VERSION 0x0200 +#define RT2860C_VERSION 0x28600100 +#define RT2860D_VERSION 0x28600101 +#define RT2880E_VERSION 0x28720200 +#define RT2883_VERSION 0x28830300 +#define RT3070_VERSION 0x30700200 /* * Signal information. @@ -408,8 +408,8 @@ * ASIC_VER: 2860 or 2870 */ #define MAC_CSR0 0x1000 -#define MAC_CSR0_REVISION FIELD32(0x0000ffff) -#define MAC_CSR0_CHIPSET FIELD32(0xffff0000) +#define MAC_CSR0_ASIC_REV FIELD32(0x0000ffff) +#define MAC_CSR0_ASIC_VER FIELD32(0xffff0000) /* * MAC_SYS_CTRL: diff --git a/trunk/drivers/net/wireless/rt2x00/rt2800lib.c b/trunk/drivers/net/wireless/rt2x00/rt2800lib.c index 18d4d8e4ae6b..9deae41cb784 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/trunk/drivers/net/wireless/rt2x00/rt2800lib.c @@ -37,12 +37,9 @@ #include #include "rt2x00.h" -#if defined(CONFIG_RT2X00_LIB_USB) || defined(CONFIG_RT2X00_LIB_USB_MODULE) +#if defined(CONFIG_RT2800USB) || defined(CONFIG_RT2800USB_MODULE) #include "rt2x00usb.h" #endif -#if defined(CONFIG_RT2X00_LIB_PCI) || defined(CONFIG_RT2X00_LIB_PCI_MODULE) -#include "rt2x00pci.h" -#endif #include "rt2800lib.h" #include "rt2800.h" #include "rt2800usb.h" @@ -92,7 +89,7 @@ static void rt2800_bbp_write(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, BBP_CSR_CFG_REGNUM, word); rt2x00_set_field32(®, BBP_CSR_CFG_BUSY, 1); rt2x00_set_field32(®, BBP_CSR_CFG_READ_CONTROL, 0); - if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev)) + if (rt2x00_intf_is_pci(rt2x00dev)) rt2x00_set_field32(®, BBP_CSR_CFG_BBP_RW_MODE, 1); rt2800_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg); @@ -121,7 +118,7 @@ static void rt2800_bbp_read(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, BBP_CSR_CFG_REGNUM, word); rt2x00_set_field32(®, BBP_CSR_CFG_BUSY, 1); rt2x00_set_field32(®, BBP_CSR_CFG_READ_CONTROL, 1); - if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev)) + if (rt2x00_intf_is_pci(rt2x00dev)) rt2x00_set_field32(®, BBP_CSR_CFG_BBP_RW_MODE, 1); rt2800_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg); @@ -221,9 +218,10 @@ void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev, u32 reg; /* - * SOC devices don't support MCU requests. + * RT2880 and RT3052 don't support MCU requests. */ - if (rt2x00_is_soc(rt2x00dev)) + if (rt2x00_rt(&rt2x00dev->chip, RT2880) || + rt2x00_rt(&rt2x00dev->chip, RT3052)) return; mutex_lock(&rt2x00dev->csr_mutex); @@ -248,25 +246,6 @@ void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev, } EXPORT_SYMBOL_GPL(rt2800_mcu_request); -int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev) -{ - unsigned int i; - u32 reg; - - for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); - if (!rt2x00_get_field32(reg, WPDMA_GLO_CFG_TX_DMA_BUSY) && - !rt2x00_get_field32(reg, WPDMA_GLO_CFG_RX_DMA_BUSY)) - return 0; - - msleep(1); - } - - ERROR(rt2x00dev, "WPDMA TX/RX busy, aborting.\n"); - return -EACCES; -} -EXPORT_SYMBOL_GPL(rt2800_wait_wpdma_ready); - #ifdef CONFIG_RT2X00_LIB_DEBUGFS const struct rt2x00debug rt2800_rt2x00debug = { .owner = THIS_MODULE, @@ -369,7 +348,7 @@ static int rt2800_blink_set(struct led_classdev *led_cdev, return 0; } -static void rt2800_init_led(struct rt2x00_dev *rt2x00dev, +void rt2800_init_led(struct rt2x00_dev *rt2x00dev, struct rt2x00_led *led, enum led_type type) { led->rt2x00dev = rt2x00dev; @@ -378,6 +357,7 @@ static void rt2800_init_led(struct rt2x00_dev *rt2x00dev, led->led_dev.blink_set = rt2800_blink_set; led->flags = LED_INITIALIZED; } +EXPORT_SYMBOL_GPL(rt2800_init_led); #endif /* CONFIG_RT2X00_LIB_LEDS */ /* @@ -663,7 +643,7 @@ void rt2800_config_ant(struct rt2x00_dev *rt2x00dev, struct antenna_setup *ant) switch ((int)ant->tx) { case 1: rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 0); - if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev)) + if (rt2x00_intf_is_pci(rt2x00dev)) rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 0); break; case 2: @@ -826,12 +806,12 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, unsigned int tx_pin; u8 bbp; - if ((rt2x00_rt(rt2x00dev, RT3070) || - rt2x00_rt(rt2x00dev, RT3090)) && - (rt2x00_rf(rt2x00dev, RF2020) || - rt2x00_rf(rt2x00dev, RF3020) || - rt2x00_rf(rt2x00dev, RF3021) || - rt2x00_rf(rt2x00dev, RF3022))) + if ((rt2x00_rt(&rt2x00dev->chip, RT3070) || + rt2x00_rt(&rt2x00dev->chip, RT3090)) && + (rt2x00_rf(&rt2x00dev->chip, RF2020) || + rt2x00_rf(&rt2x00dev->chip, RF3020) || + rt2x00_rf(&rt2x00dev->chip, RF3021) || + rt2x00_rf(&rt2x00dev->chip, RF3022))) rt2800_config_channel_rt3x(rt2x00dev, conf, rf, info); else rt2800_config_channel_rt2x(rt2x00dev, conf, rf, info); @@ -898,8 +878,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, rt2x00_set_field8(&bbp, BBP3_HT40_PLUS, conf_is_ht40_plus(conf)); rt2800_bbp_write(rt2x00dev, 3, bbp); - if (rt2x00_rt(rt2x00dev, RT2860) && - (rt2x00_rev(rt2x00dev) == RT2860C_VERSION)) { + if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) { if (conf_is_ht40(conf)) { rt2800_bbp_write(rt2x00dev, 69, 0x1a); rt2800_bbp_write(rt2x00dev, 70, 0x0a); @@ -1061,9 +1040,8 @@ EXPORT_SYMBOL_GPL(rt2800_link_stats); static u8 rt2800_get_default_vgc(struct rt2x00_dev *rt2x00dev) { if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) { - if (rt2x00_is_usb(rt2x00dev) && - rt2x00_rt(rt2x00dev, RT3070) && - (rt2x00_rev(rt2x00dev) == RT3070_VERSION)) + if (rt2x00_intf_is_usb(rt2x00dev) && + rt2x00_rev(&rt2x00dev->chip) == RT3070_VERSION) return 0x1c + (2 * rt2x00dev->lna_gain); else return 0x2e + rt2x00dev->lna_gain; @@ -1094,8 +1072,7 @@ EXPORT_SYMBOL_GPL(rt2800_reset_tuner); void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual, const u32 count) { - if (rt2x00_rt(rt2x00dev, RT2860) && - (rt2x00_rev(rt2x00dev) == RT2860C_VERSION)) + if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) return; /* @@ -1115,7 +1092,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) u32 reg; unsigned int i; - if (rt2x00_is_usb(rt2x00dev)) { + if (rt2x00_intf_is_usb(rt2x00dev)) { /* * Wait until BBP and RF are ready. */ @@ -1134,7 +1111,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, ®); rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, reg & ~0x00002000); - } else if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev)) + } else if (rt2x00_intf_is_pci(rt2x00dev)) rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003); rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); @@ -1142,9 +1119,9 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, MAC_SYS_CTRL_RESET_BBP, 1); rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); - if (rt2x00_is_usb(rt2x00dev)) { + if (rt2x00_intf_is_usb(rt2x00dev)) { rt2800_register_write(rt2x00dev, USB_DMA_CFG, 0x00000000); -#if defined(CONFIG_RT2X00_LIB_USB) || defined(CONFIG_RT2X00_LIB_USB_MODULE) +#if defined(CONFIG_RT2800USB) || defined(CONFIG_RT2800USB_MODULE) rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0, USB_MODE_RESET, REGISTER_TIMEOUT); #endif @@ -1180,9 +1157,8 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, BCN_TIME_CFG_TX_TIME_COMPENSATE, 0); rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); - if (rt2x00_is_usb(rt2x00dev) && - rt2x00_rt(rt2x00dev, RT3070) && - (rt2x00_rev(rt2x00dev) == RT3070_VERSION)) { + if (rt2x00_intf_is_usb(rt2x00dev) && + rt2x00_rev(&rt2x00dev->chip) == RT3070_VERSION) { rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400); rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000); rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000); @@ -1209,14 +1185,8 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2800_register_read(rt2x00dev, MAX_LEN_CFG, ®); rt2x00_set_field32(®, MAX_LEN_CFG_MAX_MPDU, AGGREGATION_SIZE); - if ((rt2x00_rt(rt2x00dev, RT2872) && - (rt2x00_rev(rt2x00dev) >= RT2880E_VERSION)) || - rt2x00_rt(rt2x00dev, RT2880) || - rt2x00_rt(rt2x00dev, RT2883) || - rt2x00_rt(rt2x00dev, RT2890) || - rt2x00_rt(rt2x00dev, RT3052) || - (rt2x00_rt(rt2x00dev, RT3070) && - (rt2x00_rev(rt2x00dev) < RT3070_VERSION))) + if (rt2x00_rev(&rt2x00dev->chip) >= RT2880E_VERSION && + rt2x00_rev(&rt2x00dev->chip) < RT3070_VERSION) rt2x00_set_field32(®, MAX_LEN_CFG_MAX_PSDU, 2); else rt2x00_set_field32(®, MAX_LEN_CFG_MAX_PSDU, 1); @@ -1306,7 +1276,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_GF40, 1); rt2800_register_write(rt2x00dev, GF40_PROT_CFG, reg); - if (rt2x00_is_usb(rt2x00dev)) { + if (rt2x00_intf_is_usb(rt2x00dev)) { rt2800_register_write(rt2x00dev, PBF_CFG, 0xf40006); rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); @@ -1366,7 +1336,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2800_register_write(rt2x00dev, HW_BEACON_BASE6, 0); rt2800_register_write(rt2x00dev, HW_BEACON_BASE7, 0); - if (rt2x00_is_usb(rt2x00dev)) { + if (rt2x00_intf_is_usb(rt2x00dev)) { rt2800_register_read(rt2x00dev, USB_CYC_CFG, ®); rt2x00_set_field32(®, USB_CYC_CFG_CLOCK_CYCLE, 30); rt2800_register_write(rt2x00dev, USB_CYC_CFG, reg); @@ -1495,25 +1465,22 @@ int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) rt2800_bbp_write(rt2x00dev, 103, 0x00); rt2800_bbp_write(rt2x00dev, 105, 0x05); - if (rt2x00_rt(rt2x00dev, RT2860) && - (rt2x00_rev(rt2x00dev) == RT2860C_VERSION)) { + if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) { rt2800_bbp_write(rt2x00dev, 69, 0x16); rt2800_bbp_write(rt2x00dev, 73, 0x12); } - if (rt2x00_rt(rt2x00dev, RT2860) && - (rt2x00_rev(rt2x00dev) > RT2860D_VERSION)) + if (rt2x00_rev(&rt2x00dev->chip) > RT2860D_VERSION) rt2800_bbp_write(rt2x00dev, 84, 0x19); - if (rt2x00_is_usb(rt2x00dev) && - rt2x00_rt(rt2x00dev, RT3070) && - (rt2x00_rev(rt2x00dev) == RT3070_VERSION)) { + if (rt2x00_intf_is_usb(rt2x00dev) && + rt2x00_rev(&rt2x00dev->chip) == RT3070_VERSION) { rt2800_bbp_write(rt2x00dev, 70, 0x0a); rt2800_bbp_write(rt2x00dev, 84, 0x99); rt2800_bbp_write(rt2x00dev, 105, 0x05); } - if (rt2x00_rt(rt2x00dev, RT3052)) { + if (rt2x00_rt(&rt2x00dev->chip, RT3052)) { rt2800_bbp_write(rt2x00dev, 31, 0x08); rt2800_bbp_write(rt2x00dev, 78, 0x0e); rt2800_bbp_write(rt2x00dev, 80, 0x08); @@ -1598,15 +1565,14 @@ int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) u8 rfcsr; u8 bbp; - if (rt2x00_is_usb(rt2x00dev) && - rt2x00_rt(rt2x00dev, RT3070) && - (rt2x00_rev(rt2x00dev) != RT3070_VERSION)) + if (rt2x00_intf_is_usb(rt2x00dev) && + rt2x00_rev(&rt2x00dev->chip) != RT3070_VERSION) return 0; - if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev)) { - if (!rt2x00_rf(rt2x00dev, RF3020) && - !rt2x00_rf(rt2x00dev, RF3021) && - !rt2x00_rf(rt2x00dev, RF3022)) + if (rt2x00_intf_is_pci(rt2x00dev)) { + if (!rt2x00_rf(&rt2x00dev->chip, RF3020) && + !rt2x00_rf(&rt2x00dev->chip, RF3021) && + !rt2x00_rf(&rt2x00dev->chip, RF3022)) return 0; } @@ -1620,7 +1586,7 @@ int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 0); rt2800_rfcsr_write(rt2x00dev, 30, rfcsr); - if (rt2x00_is_usb(rt2x00dev)) { + if (rt2x00_intf_is_usb(rt2x00dev)) { rt2800_rfcsr_write(rt2x00dev, 4, 0x40); rt2800_rfcsr_write(rt2x00dev, 5, 0x03); rt2800_rfcsr_write(rt2x00dev, 6, 0x02); @@ -1641,7 +1607,7 @@ int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) rt2800_rfcsr_write(rt2x00dev, 25, 0x01); rt2800_rfcsr_write(rt2x00dev, 27, 0x03); rt2800_rfcsr_write(rt2x00dev, 29, 0x1f); - } else if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev)) { + } else if (rt2x00_intf_is_pci(rt2x00dev)) { rt2800_rfcsr_write(rt2x00dev, 0, 0x50); rt2800_rfcsr_write(rt2x00dev, 1, 0x01); rt2800_rfcsr_write(rt2x00dev, 2, 0xf7); @@ -1771,12 +1737,7 @@ int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2820); rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word); EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word); - } else if (rt2x00_rt(rt2x00dev, RT2860) || - rt2x00_rt(rt2x00dev, RT2870) || - rt2x00_rt(rt2x00dev, RT2872) || - rt2x00_rt(rt2x00dev, RT2880) || - (rt2x00_rt(rt2x00dev, RT2883) && - (rt2x00_rev(rt2x00dev) < RT2883_VERSION))) { + } else if (rt2x00_rev(&rt2x00dev->chip) < RT2883_VERSION) { /* * There is a max of 2 RX streams for RT28x0 series */ @@ -1875,34 +1836,36 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); rt2800_register_read(rt2x00dev, MAC_CSR0, ®); - rt2x00_set_chip(rt2x00dev, rt2x00_get_field32(reg, MAC_CSR0_CHIPSET), - value, rt2x00_get_field32(reg, MAC_CSR0_REVISION)); - - if (!rt2x00_rt(rt2x00dev, RT2860) && - !rt2x00_rt(rt2x00dev, RT2870) && - !rt2x00_rt(rt2x00dev, RT2872) && - !rt2x00_rt(rt2x00dev, RT2880) && - !rt2x00_rt(rt2x00dev, RT2883) && - !rt2x00_rt(rt2x00dev, RT2890) && - !rt2x00_rt(rt2x00dev, RT3052) && - !rt2x00_rt(rt2x00dev, RT3070) && - !rt2x00_rt(rt2x00dev, RT3071) && - !rt2x00_rt(rt2x00dev, RT3090) && - !rt2x00_rt(rt2x00dev, RT3390) && - !rt2x00_rt(rt2x00dev, RT3572)) { - ERROR(rt2x00dev, "Invalid RT chipset detected.\n"); - return -ENODEV; - } + rt2x00_set_chip_rf(rt2x00dev, value, reg); + + if (rt2x00_intf_is_usb(rt2x00dev)) { + struct rt2x00_chip *chip = &rt2x00dev->chip; - if (!rt2x00_rf(rt2x00dev, RF2820) && - !rt2x00_rf(rt2x00dev, RF2850) && - !rt2x00_rf(rt2x00dev, RF2720) && - !rt2x00_rf(rt2x00dev, RF2750) && - !rt2x00_rf(rt2x00dev, RF3020) && - !rt2x00_rf(rt2x00dev, RF2020) && - !rt2x00_rf(rt2x00dev, RF3021) && - !rt2x00_rf(rt2x00dev, RF3022) && - !rt2x00_rf(rt2x00dev, RF3052)) { + /* + * The check for rt2860 is not a typo, some rt2870 hardware + * identifies itself as rt2860 in the CSR register. + */ + if (rt2x00_check_rev(chip, 0xfff00000, 0x28600000) || + rt2x00_check_rev(chip, 0xfff00000, 0x28700000) || + rt2x00_check_rev(chip, 0xfff00000, 0x28800000)) { + rt2x00_set_chip_rt(rt2x00dev, RT2870); + } else if (rt2x00_check_rev(chip, 0xffff0000, 0x30700000)) { + rt2x00_set_chip_rt(rt2x00dev, RT3070); + } else { + ERROR(rt2x00dev, "Invalid RT chipset detected.\n"); + return -ENODEV; + } + } + rt2x00_print_chip(rt2x00dev); + + if (!rt2x00_rf(&rt2x00dev->chip, RF2820) && + !rt2x00_rf(&rt2x00dev->chip, RF2850) && + !rt2x00_rf(&rt2x00dev->chip, RF2720) && + !rt2x00_rf(&rt2x00dev->chip, RF2750) && + !rt2x00_rf(&rt2x00dev->chip, RF3020) && + !rt2x00_rf(&rt2x00dev->chip, RF2020) && + !rt2x00_rf(&rt2x00dev->chip, RF3021) && + !rt2x00_rf(&rt2x00dev->chip, RF3022)) { ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); return -ENODEV; } @@ -2050,6 +2013,7 @@ static const struct rf_channel rf_vals_302x[] = { int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) { + struct rt2x00_chip *chip = &rt2x00dev->chip; struct hw_mode_spec *spec = &rt2x00dev->spec; struct channel_info *info; char *tx_power1; @@ -2060,7 +2024,7 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) /* * Disable powersaving as default on PCI devices. */ - if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev)) + if (rt2x00_intf_is_pci(rt2x00dev)) rt2x00dev->hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; /* @@ -2085,19 +2049,19 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) spec->supported_bands = SUPPORT_BAND_2GHZ; spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM; - if (rt2x00_rf(rt2x00dev, RF2820) || - rt2x00_rf(rt2x00dev, RF2720) || - rt2x00_rf(rt2x00dev, RF3052)) { + if (rt2x00_rf(chip, RF2820) || + rt2x00_rf(chip, RF2720) || + (rt2x00_intf_is_pci(rt2x00dev) && rt2x00_rf(chip, RF3052))) { spec->num_channels = 14; spec->channels = rf_vals; - } else if (rt2x00_rf(rt2x00dev, RF2850) || rt2x00_rf(rt2x00dev, RF2750)) { + } else if (rt2x00_rf(chip, RF2850) || rt2x00_rf(chip, RF2750)) { spec->supported_bands |= SUPPORT_BAND_5GHZ; spec->num_channels = ARRAY_SIZE(rf_vals); spec->channels = rf_vals; - } else if (rt2x00_rf(rt2x00dev, RF3020) || - rt2x00_rf(rt2x00dev, RF2020) || - rt2x00_rf(rt2x00dev, RF3021) || - rt2x00_rf(rt2x00dev, RF3022)) { + } else if (rt2x00_rf(chip, RF3020) || + rt2x00_rf(chip, RF2020) || + rt2x00_rf(chip, RF3021) || + rt2x00_rf(chip, RF3022)) { spec->num_channels = ARRAY_SIZE(rf_vals_302x); spec->channels = rf_vals_302x; } @@ -2105,7 +2069,7 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) /* * Initialize HT information. */ - if (!rt2x00_rf(rt2x00dev, RF2020)) + if (!rt2x00_rf(chip, RF2020)) spec->ht.ht_supported = true; else spec->ht.ht_supported = false; @@ -2318,6 +2282,7 @@ const struct ieee80211_ops rt2800_mac80211_ops = { .set_rts_threshold = rt2800_set_rts_threshold, .bss_info_changed = rt2x00mac_bss_info_changed, .conf_tx = rt2800_conf_tx, + .get_tx_stats = rt2x00mac_get_tx_stats, .get_tsf = rt2800_get_tsf, .rfkill_poll = rt2x00mac_rfkill_poll, }; diff --git a/trunk/drivers/net/wireless/rt2x00/rt2800lib.h b/trunk/drivers/net/wireless/rt2x00/rt2800lib.h index ebabeae62d1b..535ce22f2ac8 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2800lib.h +++ b/trunk/drivers/net/wireless/rt2x00/rt2800lib.h @@ -114,6 +114,8 @@ void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev, extern const struct rt2x00debug rt2800_rt2x00debug; int rt2800_rfkill_poll(struct rt2x00_dev *rt2x00dev); +void rt2800_init_led(struct rt2x00_dev *rt2x00dev, + struct rt2x00_led *led, enum led_type type); int rt2800_config_shared_key(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_crypto *crypto, struct ieee80211_key_conf *key); @@ -137,7 +139,6 @@ void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual, int rt2800_init_registers(struct rt2x00_dev *rt2x00dev); int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev); int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev); -int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev); int rt2800_efuse_detect(struct rt2x00_dev *rt2x00dev); void rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev); diff --git a/trunk/drivers/net/wireless/rt2x00/rt2800pci.c b/trunk/drivers/net/wireless/rt2x00/rt2800pci.c index 0e4c41766edc..dfc886fcb44d 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/trunk/drivers/net/wireless/rt2x00/rt2800pci.c @@ -48,6 +48,14 @@ #include "rt2800.h" #include "rt2800pci.h" +#ifdef CONFIG_RT2800PCI_PCI_MODULE +#define CONFIG_RT2800PCI_PCI +#endif + +#ifdef CONFIG_RT2800PCI_WISOC_MODULE +#define CONFIG_RT2800PCI_WISOC +#endif + /* * Allow hardware encryption to be disabled. */ @@ -79,7 +87,7 @@ static void rt2800pci_mcu_status(struct rt2x00_dev *rt2x00dev, const u8 token) rt2800_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0); } -#ifdef CONFIG_RT2800PCI_SOC +#ifdef CONFIG_RT2800PCI_WISOC static void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev) { u32 *base_addr = (u32 *) KSEG1ADDR(0x1F040000); /* XXX for RT3052 */ @@ -90,7 +98,7 @@ static void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev) static inline void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev) { } -#endif /* CONFIG_RT2800PCI_SOC */ +#endif /* CONFIG_RT2800PCI_WISOC */ #ifdef CONFIG_RT2800PCI_PCI static void rt2800pci_eepromregister_read(struct eeprom_93cx6 *eeprom) @@ -453,6 +461,24 @@ static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev, rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg); } +static int rt2800pci_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev) +{ + unsigned int i; + u32 reg; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); + if (!rt2x00_get_field32(reg, WPDMA_GLO_CFG_TX_DMA_BUSY) && + !rt2x00_get_field32(reg, WPDMA_GLO_CFG_RX_DMA_BUSY)) + return 0; + + msleep(1); + } + + ERROR(rt2x00dev, "WPDMA TX/RX busy, aborting.\n"); + return -EACCES; +} + static int rt2800pci_enable_radio(struct rt2x00_dev *rt2x00dev) { u32 reg; @@ -461,10 +487,10 @@ static int rt2800pci_enable_radio(struct rt2x00_dev *rt2x00dev) /* * Initialize all registers. */ - if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev) || + if (unlikely(rt2800pci_wait_wpdma_ready(rt2x00dev) || rt2800pci_init_queues(rt2x00dev) || rt2800_init_registers(rt2x00dev) || - rt2800_wait_wpdma_ready(rt2x00dev) || + rt2800pci_wait_wpdma_ready(rt2x00dev) || rt2800_init_bbp(rt2x00dev) || rt2800_init_rfcsr(rt2x00dev))) return -EIO; @@ -544,7 +570,7 @@ static void rt2800pci_disable_radio(struct rt2x00_dev *rt2x00dev) rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00); /* Wait for DMA, ignore error */ - rt2800_wait_wpdma_ready(rt2x00dev); + rt2800pci_wait_wpdma_ready(rt2x00dev); } static int rt2800pci_set_state(struct rt2x00_dev *rt2x00dev, @@ -809,6 +835,7 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry, struct rxdone_entry_desc *rxdesc) { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); struct queue_entry_priv_pci *entry_priv = entry->priv_data; __le32 *rxd = entry_priv->desc; __le32 *rxwi = (__le32 *)entry->skb->data; @@ -856,8 +883,10 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry, if (rt2x00_get_field32(rxd3, RXD_W3_MY_BSS)) rxdesc->dev_flags |= RXDONE_MY_BSS; - if (rt2x00_get_field32(rxd3, RXD_W3_L2PAD)) + if (rt2x00_get_field32(rxd3, RXD_W3_L2PAD)) { rxdesc->dev_flags |= RXDONE_L2PAD; + skbdesc->flags |= SKBDESC_L2_PADDED; + } if (rt2x00_get_field32(rxwi1, RXWI_W1_SHORT_GI)) rxdesc->flags |= RX_FLAG_SHORT_GI; @@ -898,6 +927,7 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry, * Remove TXWI descriptor from start of buffer. */ skb_pull(entry->skb, RXWI_DESC_SIZE); + skb_trim(entry->skb, rxdesc->size); } /* @@ -1041,12 +1071,18 @@ static int rt2800pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) /* * Read EEPROM into buffer */ - if (rt2x00_is_soc(rt2x00dev)) + switch (rt2x00dev->chip.rt) { + case RT2880: + case RT3052: rt2800pci_read_eeprom_soc(rt2x00dev); - else if (rt2800pci_efuse_detect(rt2x00dev)) - rt2800pci_read_eeprom_efuse(rt2x00dev); - else - rt2800pci_read_eeprom_pci(rt2x00dev); + break; + default: + if (rt2800pci_efuse_detect(rt2x00dev)) + rt2800pci_read_eeprom_efuse(rt2x00dev); + else + rt2800pci_read_eeprom_pci(rt2x00dev); + break; + } return rt2800_validate_eeprom(rt2x00dev); } @@ -1097,7 +1133,8 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * This device requires firmware. */ - if (!rt2x00_is_soc(rt2x00dev)) + if (!rt2x00_rt(&rt2x00dev->chip, RT2880) && + !rt2x00_rt(&rt2x00dev->chip, RT3052)) __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags); @@ -1185,10 +1222,7 @@ static const struct rt2x00_ops rt2800pci_ops = { * RT2800pci module information. */ static struct pci_device_id rt2800pci_device_table[] = { - { PCI_DEVICE(0x1814, 0x0601), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1814, 0x0681), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1814, 0x0701), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1814, 0x0781), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { PCI_DEVICE(0x1462, 0x891a), PCI_DEVICE_DATA(&rt2800pci_ops) }, { PCI_DEVICE(0x1432, 0x7708), PCI_DEVICE_DATA(&rt2800pci_ops) }, { PCI_DEVICE(0x1432, 0x7727), PCI_DEVICE_DATA(&rt2800pci_ops) }, { PCI_DEVICE(0x1432, 0x7728), PCI_DEVICE_DATA(&rt2800pci_ops) }, @@ -1196,19 +1230,18 @@ static struct pci_device_id rt2800pci_device_table[] = { { PCI_DEVICE(0x1432, 0x7748), PCI_DEVICE_DATA(&rt2800pci_ops) }, { PCI_DEVICE(0x1432, 0x7758), PCI_DEVICE_DATA(&rt2800pci_ops) }, { PCI_DEVICE(0x1432, 0x7768), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1a3b, 0x1059), PCI_DEVICE_DATA(&rt2800pci_ops) }, -#ifdef CONFIG_RT2800PCI_RT30XX + { PCI_DEVICE(0x1814, 0x0601), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { PCI_DEVICE(0x1814, 0x0681), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { PCI_DEVICE(0x1814, 0x0701), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { PCI_DEVICE(0x1814, 0x0781), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { PCI_DEVICE(0x1814, 0x3060), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { PCI_DEVICE(0x1814, 0x3062), PCI_DEVICE_DATA(&rt2800pci_ops) }, { PCI_DEVICE(0x1814, 0x3090), PCI_DEVICE_DATA(&rt2800pci_ops) }, { PCI_DEVICE(0x1814, 0x3091), PCI_DEVICE_DATA(&rt2800pci_ops) }, { PCI_DEVICE(0x1814, 0x3092), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1462, 0x891a), PCI_DEVICE_DATA(&rt2800pci_ops) }, -#endif -#ifdef CONFIG_RT2800PCI_RT35XX - { PCI_DEVICE(0x1814, 0x3060), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1814, 0x3062), PCI_DEVICE_DATA(&rt2800pci_ops) }, { PCI_DEVICE(0x1814, 0x3562), PCI_DEVICE_DATA(&rt2800pci_ops) }, { PCI_DEVICE(0x1814, 0x3592), PCI_DEVICE_DATA(&rt2800pci_ops) }, -#endif + { PCI_DEVICE(0x1a3b, 0x1059), PCI_DEVICE_DATA(&rt2800pci_ops) }, { 0, } }; @@ -1222,11 +1255,12 @@ MODULE_DEVICE_TABLE(pci, rt2800pci_device_table); #endif /* CONFIG_RT2800PCI_PCI */ MODULE_LICENSE("GPL"); -#ifdef CONFIG_RT2800PCI_SOC -static int rt2800soc_probe(struct platform_device *pdev) -{ - return rt2x00soc_probe(pdev, rt2800pci_ops); -} +#ifdef CONFIG_RT2800PCI_WISOC +#if defined(CONFIG_RALINK_RT288X) +__rt2x00soc_probe(RT2880, &rt2800pci_ops); +#elif defined(CONFIG_RALINK_RT305X) +__rt2x00soc_probe(RT3052, &rt2800pci_ops); +#endif static struct platform_driver rt2800soc_driver = { .driver = { @@ -1234,12 +1268,12 @@ static struct platform_driver rt2800soc_driver = { .owner = THIS_MODULE, .mod_name = KBUILD_MODNAME, }, - .probe = rt2800soc_probe, + .probe = __rt2x00soc_probe, .remove = __devexit_p(rt2x00soc_remove), .suspend = rt2x00soc_suspend, .resume = rt2x00soc_resume, }; -#endif /* CONFIG_RT2800PCI_SOC */ +#endif /* CONFIG_RT2800PCI_WISOC */ #ifdef CONFIG_RT2800PCI_PCI static struct pci_driver rt2800pci_driver = { @@ -1256,7 +1290,7 @@ static int __init rt2800pci_init(void) { int ret = 0; -#ifdef CONFIG_RT2800PCI_SOC +#ifdef CONFIG_RT2800PCI_WISOC ret = platform_driver_register(&rt2800soc_driver); if (ret) return ret; @@ -1264,7 +1298,7 @@ static int __init rt2800pci_init(void) #ifdef CONFIG_RT2800PCI_PCI ret = pci_register_driver(&rt2800pci_driver); if (ret) { -#ifdef CONFIG_RT2800PCI_SOC +#ifdef CONFIG_RT2800PCI_WISOC platform_driver_unregister(&rt2800soc_driver); #endif return ret; @@ -1279,7 +1313,7 @@ static void __exit rt2800pci_exit(void) #ifdef CONFIG_RT2800PCI_PCI pci_unregister_driver(&rt2800pci_driver); #endif -#ifdef CONFIG_RT2800PCI_SOC +#ifdef CONFIG_RT2800PCI_WISOC platform_driver_unregister(&rt2800soc_driver); #endif } diff --git a/trunk/drivers/net/wireless/rt2x00/rt2800usb.c b/trunk/drivers/net/wireless/rt2x00/rt2800usb.c index 5e4ee2023fcf..ab95346cf6a3 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/trunk/drivers/net/wireless/rt2x00/rt2800usb.c @@ -92,6 +92,7 @@ static bool rt2800usb_check_crc(const u8 *data, const size_t len) static int rt2800usb_check_firmware(struct rt2x00_dev *rt2x00dev, const u8 *data, const size_t len) { + u16 chipset = (rt2x00_rev(&rt2x00dev->chip) >> 16) & 0xffff; size_t offset = 0; /* @@ -110,9 +111,9 @@ static int rt2800usb_check_firmware(struct rt2x00_dev *rt2x00dev, * Check if we need the upper 4kb firmware data or not. */ if ((len == 4096) && - !rt2x00_rt(rt2x00dev, RT2860) && - !rt2x00_rt(rt2x00dev, RT2872) && - !rt2x00_rt(rt2x00dev, RT3070)) + (chipset != 0x2860) && + (chipset != 0x2872) && + (chipset != 0x3070)) return FW_BAD_VERSION; /* @@ -137,13 +138,14 @@ static int rt2800usb_load_firmware(struct rt2x00_dev *rt2x00dev, u32 reg; u32 offset; u32 length; + u16 chipset = (rt2x00_rev(&rt2x00dev->chip) >> 16) & 0xffff; /* * Check which section of the firmware we need. */ - if (rt2x00_rt(rt2x00dev, RT2860) || - rt2x00_rt(rt2x00dev, RT2872) || - rt2x00_rt(rt2x00dev, RT3070)) { + if ((chipset == 0x2860) || + (chipset == 0x2872) || + (chipset == 0x3070)) { offset = 0; length = 4096; } else { @@ -198,9 +200,9 @@ static int rt2800usb_load_firmware(struct rt2x00_dev *rt2x00dev, */ rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0xff, 0, 0); - if (rt2x00_rt(rt2x00dev, RT3070) || - rt2x00_rt(rt2x00dev, RT3071) || - rt2x00_rt(rt2x00dev, RT3572)) { + if ((chipset == 0x3070) || + (chipset == 0x3071) || + (chipset == 0x3572)) { udelay(200); rt2800_mcu_request(rt2x00dev, MCU_CURRENT, 0, 0, 0); udelay(10); @@ -246,6 +248,24 @@ static void rt2800usb_toggle_rx(struct rt2x00_dev *rt2x00dev, rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); } +static int rt2800usb_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev) +{ + unsigned int i; + u32 reg; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); + if (!rt2x00_get_field32(reg, WPDMA_GLO_CFG_TX_DMA_BUSY) && + !rt2x00_get_field32(reg, WPDMA_GLO_CFG_RX_DMA_BUSY)) + return 0; + + msleep(1); + } + + ERROR(rt2x00dev, "WPDMA TX/RX busy, aborting.\n"); + return -EACCES; +} + static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev) { u32 reg; @@ -254,7 +274,7 @@ static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev) /* * Initialize all registers. */ - if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev) || + if (unlikely(rt2800usb_wait_wpdma_ready(rt2x00dev) || rt2800_init_registers(rt2x00dev) || rt2800_init_bbp(rt2x00dev) || rt2800_init_rfcsr(rt2x00dev))) @@ -275,7 +295,9 @@ static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev) rt2800_register_read(rt2x00dev, USB_DMA_CFG, ®); rt2x00_set_field32(®, USB_DMA_CFG_PHY_CLEAR, 0); - rt2x00_set_field32(®, USB_DMA_CFG_RX_BULK_AGG_EN, 0); + /* Don't use bulk in aggregation when working with USB 1.1 */ + rt2x00_set_field32(®, USB_DMA_CFG_RX_BULK_AGG_EN, + (rt2x00dev->rx->usb_maxpacket == 512)); rt2x00_set_field32(®, USB_DMA_CFG_RX_BULK_AGG_TIMEOUT, 128); /* * Total room for RX frames in kilobytes, PBF might still exceed @@ -324,7 +346,7 @@ static void rt2800usb_disable_radio(struct rt2x00_dev *rt2x00dev) rt2800_register_write(rt2x00dev, TX_PIN_CFG, 0); /* Wait for DMA, ignore error */ - rt2800_wait_wpdma_ready(rt2x00dev); + rt2800usb_wait_wpdma_ready(rt2x00dev); rt2x00usb_disable_radio(rt2x00dev); } @@ -551,57 +573,41 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry, { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); - __le32 *rxi = (__le32 *)entry->skb->data; + __le32 *rxd = (__le32 *)entry->skb->data; __le32 *rxwi; - __le32 *rxd; - u32 rxi0; + u32 rxd0; u32 rxwi0; u32 rxwi1; u32 rxwi2; u32 rxwi3; - u32 rxd0; - int rx_pkt_len; - - /* - * RX frame format is : - * | RXINFO | RXWI | header | L2 pad | payload | pad | RXD | USB pad | - * |<------------ rx_pkt_len -------------->| - */ - rt2x00_desc_read(rxi, 0, &rxi0); - rx_pkt_len = rt2x00_get_field32(rxi0, RXINFO_W0_USB_DMA_RX_PKT_LEN); - - rxwi = (__le32 *)(entry->skb->data + RXINFO_DESC_SIZE); - - /* - * FIXME : we need to check for rx_pkt_len validity - */ - rxd = (__le32 *)(entry->skb->data + RXINFO_DESC_SIZE + rx_pkt_len); /* * Copy descriptor to the skbdesc->desc buffer, making it safe from * moving of frame data in rt2x00usb. */ - memcpy(skbdesc->desc, rxi, skbdesc->desc_len); + memcpy(skbdesc->desc, rxd, skbdesc->desc_len); + rxd = (__le32 *)skbdesc->desc; + rxwi = &rxd[RXINFO_DESC_SIZE / sizeof(__le32)]; /* * It is now safe to read the descriptor on all architectures. */ + rt2x00_desc_read(rxd, 0, &rxd0); rt2x00_desc_read(rxwi, 0, &rxwi0); rt2x00_desc_read(rxwi, 1, &rxwi1); rt2x00_desc_read(rxwi, 2, &rxwi2); rt2x00_desc_read(rxwi, 3, &rxwi3); - rt2x00_desc_read(rxd, 0, &rxd0); - if (rt2x00_get_field32(rxd0, RXD_W0_CRC_ERROR)) + if (rt2x00_get_field32(rxd0, RXINFO_W0_CRC_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) { rxdesc->cipher = rt2x00_get_field32(rxwi0, RXWI_W0_UDF); rxdesc->cipher_status = - rt2x00_get_field32(rxd0, RXD_W0_CIPHER_ERROR); + rt2x00_get_field32(rxd0, RXINFO_W0_CIPHER_ERROR); } - if (rt2x00_get_field32(rxd0, RXD_W0_DECRYPTED)) { + if (rt2x00_get_field32(rxd0, RXINFO_W0_DECRYPTED)) { /* * Hardware has stripped IV/EIV data from 802.11 frame during * decryption. Unfortunately the descriptor doesn't contain @@ -616,11 +622,13 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry, rxdesc->flags |= RX_FLAG_MMIC_ERROR; } - if (rt2x00_get_field32(rxd0, RXD_W0_MY_BSS)) + if (rt2x00_get_field32(rxd0, RXINFO_W0_MY_BSS)) rxdesc->dev_flags |= RXDONE_MY_BSS; - if (rt2x00_get_field32(rxd0, RXD_W0_L2PAD)) + if (rt2x00_get_field32(rxd0, RXINFO_W0_L2PAD)) { rxdesc->dev_flags |= RXDONE_L2PAD; + skbdesc->flags |= SKBDESC_L2_PADDED; + } if (rt2x00_get_field32(rxwi1, RXWI_W1_SHORT_GI)) rxdesc->flags |= RX_FLAG_SHORT_GI; @@ -655,6 +663,7 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry, * Remove RXWI descriptor from start of buffer. */ skb_pull(entry->skb, skbdesc->desc_len); + skb_trim(entry->skb, rxdesc->size); } /* @@ -805,27 +814,51 @@ static struct usb_device_id rt2800usb_device_table[] = { /* Abocom */ { USB_DEVICE(0x07b8, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x07b8, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07b8, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07b8, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07b8, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1482, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* AirTies */ + { USB_DEVICE(0x1eda, 0x2310), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Amigo */ + { USB_DEVICE(0x0e0b, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0e0b, 0x9041), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Amit */ { USB_DEVICE(0x15c5, 0x0008), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Askey */ { USB_DEVICE(0x1690, 0x0740), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1690, 0x0744), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0930, 0x0a07), USB_DEVICE_DATA(&rt2800usb_ops) }, /* ASUS */ { USB_DEVICE(0x0b05, 0x1731), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0b05, 0x1732), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0b05, 0x1742), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0b05, 0x1760), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0b05, 0x1761), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0b05, 0x1784), USB_DEVICE_DATA(&rt2800usb_ops) }, /* AzureWave */ { USB_DEVICE(0x13d3, 0x3247), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x13d3, 0x3262), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x13d3, 0x3273), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x13d3, 0x3284), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x13d3, 0x3305), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Belkin */ { USB_DEVICE(0x050d, 0x8053), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x050d, 0x805c), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x050d, 0x815c), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x050d, 0x825a), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Buffalo */ { USB_DEVICE(0x0411, 0x00e8), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0411, 0x012e), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Cisco */ + { USB_DEVICE(0x167b, 0x4001), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Conceptronic */ { USB_DEVICE(0x14b2, 0x3c06), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x14b2, 0x3c07), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x14b2, 0x3c08), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x14b2, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x14b2, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x14b2, 0x3c12), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x14b2, 0x3c23), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x14b2, 0x3c25), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x14b2, 0x3c27), USB_DEVICE_DATA(&rt2800usb_ops) }, @@ -834,257 +867,157 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x07aa, 0x002f), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x07aa, 0x003c), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x07aa, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* D-Link */ - { USB_DEVICE(0x07d1, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07d1, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Edimax */ - { USB_DEVICE(0x7392, 0x7717), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x7392, 0x7718), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* EnGenius */ - { USB_DEVICE(0X1740, 0x9701), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1740, 0x9702), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Gigabyte */ - { USB_DEVICE(0x1044, 0x800b), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Hawking */ - { USB_DEVICE(0x0e66, 0x0001), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0e66, 0x0003), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Linksys */ - { USB_DEVICE(0x1737, 0x0070), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1737, 0x0071), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Logitec */ - { USB_DEVICE(0x0789, 0x0162), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0789, 0x0163), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0789, 0x0164), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Motorola */ - { USB_DEVICE(0x100d, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* MSI */ - { USB_DEVICE(0x0db0, 0x6899), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Philips */ - { USB_DEVICE(0x0471, 0x200f), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Planex */ - { USB_DEVICE(0x2019, 0xed06), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Ralink */ - { USB_DEVICE(0x148f, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x148f, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Samsung */ - { USB_DEVICE(0x04e8, 0x2018), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Siemens */ - { USB_DEVICE(0x129b, 0x1828), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Sitecom */ - { USB_DEVICE(0x0df6, 0x0017), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x002b), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x002c), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x002d), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x0039), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* SMC */ - { USB_DEVICE(0x083a, 0x6618), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x083a, 0x7512), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x083a, 0x7522), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x083a, 0x8522), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x083a, 0xa618), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x083a, 0xb522), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Sparklan */ - { USB_DEVICE(0x15a9, 0x0006), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Sweex */ - { USB_DEVICE(0x177f, 0x0302), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* U-Media*/ - { USB_DEVICE(0x157e, 0x300e), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* ZCOM */ - { USB_DEVICE(0x0cde, 0x0022), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0cde, 0x0025), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Zinwell */ - { USB_DEVICE(0x5a57, 0x0280), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x5a57, 0x0282), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Zyxel */ - { USB_DEVICE(0x0586, 0x3416), USB_DEVICE_DATA(&rt2800usb_ops) }, -#ifdef CONFIG_RT2800USB_RT30XX - /* Abocom */ - { USB_DEVICE(0x07b8, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07b8, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07b8, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* AirTies */ - { USB_DEVICE(0x1eda, 0x2310), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* AzureWave */ - { USB_DEVICE(0x13d3, 0x3273), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Conceptronic */ - { USB_DEVICE(0x14b2, 0x3c12), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Corega */ + { USB_DEVICE(0x07aa, 0x0041), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07aa, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x18c5, 0x0008), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x18c5, 0x0012), USB_DEVICE_DATA(&rt2800usb_ops) }, /* D-Link */ + { USB_DEVICE(0x07d1, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x07d1, 0x3c0a), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07d1, 0x3c0b), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x07d1, 0x3c0d), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x07d1, 0x3c0e), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x07d1, 0x3c0f), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07d1, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07d1, 0x3c13), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07d1, 0x3c15), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Edimax */ { USB_DEVICE(0x7392, 0x7711), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x7392, 0x7717), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x7392, 0x7718), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Encore */ { USB_DEVICE(0x203d, 0x1480), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x203d, 0x14a1), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x203d, 0x14a9), USB_DEVICE_DATA(&rt2800usb_ops) }, /* EnGenius */ + { USB_DEVICE(0X1740, 0x9701), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1740, 0x9702), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1740, 0x9703), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1740, 0x9705), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1740, 0x9706), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Gigabyte */ - { USB_DEVICE(0x1044, 0x800d), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* I-O DATA */ - { USB_DEVICE(0x04bb, 0x0945), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* MSI */ - { USB_DEVICE(0x0db0, 0x3820), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Pegatron */ - { USB_DEVICE(0x1d4d, 0x000c), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1d4d, 0x000e), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Planex */ - { USB_DEVICE(0x2019, 0xab25), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Quanta */ - { USB_DEVICE(0x1a32, 0x0304), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Ralink */ - { USB_DEVICE(0x148f, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x148f, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x148f, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x148f, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Sitecom */ - { USB_DEVICE(0x0df6, 0x003e), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* SMC */ - { USB_DEVICE(0x083a, 0x7511), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Zinwell */ - { USB_DEVICE(0x5a57, 0x0283), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x5a57, 0x5257), USB_DEVICE_DATA(&rt2800usb_ops) }, -#endif -#ifdef CONFIG_RT2800USB_RT35XX - /* Askey */ - { USB_DEVICE(0x1690, 0x0744), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Cisco */ - { USB_DEVICE(0x167b, 0x4001), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* EnGenius */ - { USB_DEVICE(0x1740, 0x9801), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* I-O DATA */ - { USB_DEVICE(0x04bb, 0x0944), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Ralink */ - { USB_DEVICE(0x148f, 0x3370), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x148f, 0x3572), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x148f, 0x8070), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Sitecom */ - { USB_DEVICE(0x0df6, 0x0041), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Zinwell */ - { USB_DEVICE(0x5a57, 0x0284), USB_DEVICE_DATA(&rt2800usb_ops) }, -#endif -#ifdef CONFIG_RT2800USB_UNKNOWN - /* - * Unclear what kind of devices these are (they aren't supported by the - * vendor driver). - */ - /* Allwin */ - { USB_DEVICE(0x8516, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x8516, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x8516, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x8516, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x8516, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x8516, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x8516, 0x3572), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Amigo */ - { USB_DEVICE(0x0e0b, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0e0b, 0x9041), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Askey */ - { USB_DEVICE(0x0930, 0x0a07), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* ASUS */ - { USB_DEVICE(0x0b05, 0x1760), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0b05, 0x1761), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0b05, 0x1784), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0b05, 0x1790), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1761, 0x0b05), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* AzureWave */ - { USB_DEVICE(0x13d3, 0x3262), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x13d3, 0x3284), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x13d3, 0x3305), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Belkin */ - { USB_DEVICE(0x050d, 0x825a), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Buffalo */ - { USB_DEVICE(0x0411, 0x012e), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0411, 0x0148), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0411, 0x0150), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0411, 0x015d), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Conceptronic */ - { USB_DEVICE(0x14b2, 0x3c08), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x14b2, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Corega */ - { USB_DEVICE(0x07aa, 0x0041), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07aa, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x18c5, 0x0008), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* D-Link */ - { USB_DEVICE(0x07d1, 0x3c0b), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07d1, 0x3c13), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07d1, 0x3c15), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07d1, 0x3c16), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Encore */ - { USB_DEVICE(0x203d, 0x14a1), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x203d, 0x14a9), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* EnGenius */ { USB_DEVICE(0x1740, 0x9707), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1740, 0x9708), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1740, 0x9709), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1740, 0x9801), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Gemtek */ { USB_DEVICE(0x15a9, 0x0010), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Gigabyte */ + { USB_DEVICE(0x1044, 0x800b), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1044, 0x800c), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1044, 0x800d), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Hawking */ + { USB_DEVICE(0x0e66, 0x0001), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0e66, 0x0003), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0e66, 0x0009), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0e66, 0x000b), USB_DEVICE_DATA(&rt2800usb_ops) }, /* I-O DATA */ + { USB_DEVICE(0x04bb, 0x0944), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x04bb, 0x0945), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x04bb, 0x0947), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x04bb, 0x0948), USB_DEVICE_DATA(&rt2800usb_ops) }, /* LevelOne */ { USB_DEVICE(0x1740, 0x0605), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1740, 0x0615), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Linksys */ + { USB_DEVICE(0x1737, 0x0070), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1737, 0x0071), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1737, 0x0077), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1737, 0x0078), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1737, 0x0079), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Logitec */ + { USB_DEVICE(0x0789, 0x0162), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0789, 0x0163), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0789, 0x0164), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Motorola */ + { USB_DEVICE(0x100d, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x100d, 0x9032), USB_DEVICE_DATA(&rt2800usb_ops) }, /* MSI */ + { USB_DEVICE(0x0db0, 0x3820), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0db0, 0x3821), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0db0, 0x3822), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0db0, 0x3870), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0db0, 0x3871), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0db0, 0x6899), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0db0, 0x821a), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0db0, 0x822a), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0db0, 0x870a), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0db0, 0x871a), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0db0, 0x899a), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Ovislink */ { USB_DEVICE(0x1b75, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Para */ { USB_DEVICE(0x20b8, 0x8888), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Pegatron */ - { USB_DEVICE(0x05a6, 0x0101), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1d4d, 0x0002), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1d4d, 0x0010), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1d4d, 0x000c), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1d4d, 0x000e), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Philips */ + { USB_DEVICE(0x0471, 0x200f), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Planex */ + { USB_DEVICE(0x2019, 0xed06), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x2019, 0xab24), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x2019, 0xab25), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Qcom */ { USB_DEVICE(0x18e8, 0x6259), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Quanta */ + { USB_DEVICE(0x1a32, 0x0304), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Ralink */ + { USB_DEVICE(0x148f, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x148f, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x148f, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x148f, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x148f, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x148f, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x148f, 0x3572), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Samsung */ + { USB_DEVICE(0x04e8, 0x2018), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Siemens */ + { USB_DEVICE(0x129b, 0x1828), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Sitecom */ + { USB_DEVICE(0x0df6, 0x0017), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x002b), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x002c), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x002d), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x0039), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0df6, 0x003b), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0df6, 0x003c), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0df6, 0x003d), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x003e), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0df6, 0x0040), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x0041), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0df6, 0x0047), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0df6, 0x0048), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0df6, 0x004a), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0df6, 0x004d), USB_DEVICE_DATA(&rt2800usb_ops) }, /* SMC */ + { USB_DEVICE(0x083a, 0x6618), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x083a, 0x7511), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x083a, 0x7512), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x083a, 0x7522), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x083a, 0x8522), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x083a, 0xa512), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x083a, 0xa618), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x083a, 0xa701), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x083a, 0xa702), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x083a, 0xb522), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x083a, 0xc522), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x083a, 0xd522), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Sparklan */ + { USB_DEVICE(0x15a9, 0x0006), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Sweex */ { USB_DEVICE(0x177f, 0x0153), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x177f, 0x0302), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x177f, 0x0313), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* U-Media*/ + { USB_DEVICE(0x157e, 0x300e), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* ZCOM */ + { USB_DEVICE(0x0cde, 0x0022), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0cde, 0x0025), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Zinwell */ + { USB_DEVICE(0x5a57, 0x0280), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x5a57, 0x0282), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x5a57, 0x0283), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x5a57, 0x0284), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x5a57, 0x5257), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Zyxel */ + { USB_DEVICE(0x0586, 0x3416), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0586, 0x341a), USB_DEVICE_DATA(&rt2800usb_ops) }, -#endif { 0, } }; diff --git a/trunk/drivers/net/wireless/rt2x00/rt2800usb.h b/trunk/drivers/net/wireless/rt2x00/rt2800usb.h index d1d8ae94b4d4..1e4340a182ef 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2800usb.h +++ b/trunk/drivers/net/wireless/rt2x00/rt2800usb.h @@ -79,8 +79,6 @@ */ #define TXINFO_DESC_SIZE ( 1 * sizeof(__le32) ) #define RXINFO_DESC_SIZE ( 1 * sizeof(__le32) ) -#define RXWI_DESC_SIZE ( 4 * sizeof(__le32) ) -#define RXD_DESC_SIZE ( 1 * sizeof(__le32) ) /* * TX Info structure @@ -102,54 +100,6 @@ #define TXINFO_W0_USB_DMA_NEXT_VALID FIELD32(0x40000000) #define TXINFO_W0_USB_DMA_TX_BURST FIELD32(0x80000000) -/* - * RX Info structure - */ - -/* - * Word 0 - */ - -#define RXINFO_W0_USB_DMA_RX_PKT_LEN FIELD32(0x0000ffff) - -/* - * RX WI structure - */ - -/* - * Word0 - */ -#define RXWI_W0_WIRELESS_CLI_ID FIELD32(0x000000ff) -#define RXWI_W0_KEY_INDEX FIELD32(0x00000300) -#define RXWI_W0_BSSID FIELD32(0x00001c00) -#define RXWI_W0_UDF FIELD32(0x0000e000) -#define RXWI_W0_MPDU_TOTAL_BYTE_COUNT FIELD32(0x0fff0000) -#define RXWI_W0_TID FIELD32(0xf0000000) - -/* - * Word1 - */ -#define RXWI_W1_FRAG FIELD32(0x0000000f) -#define RXWI_W1_SEQUENCE FIELD32(0x0000fff0) -#define RXWI_W1_MCS FIELD32(0x007f0000) -#define RXWI_W1_BW FIELD32(0x00800000) -#define RXWI_W1_SHORT_GI FIELD32(0x01000000) -#define RXWI_W1_STBC FIELD32(0x06000000) -#define RXWI_W1_PHYMODE FIELD32(0xc0000000) - -/* - * Word2 - */ -#define RXWI_W2_RSSI0 FIELD32(0x000000ff) -#define RXWI_W2_RSSI1 FIELD32(0x0000ff00) -#define RXWI_W2_RSSI2 FIELD32(0x00ff0000) - -/* - * Word3 - */ -#define RXWI_W3_SNR0 FIELD32(0x000000ff) -#define RXWI_W3_SNR1 FIELD32(0x0000ff00) - /* * RX descriptor format for RX Ring. */ @@ -165,25 +115,25 @@ * AMSDU: rx with 802.3 header, not 802.11 header. */ -#define RXD_W0_BA FIELD32(0x00000001) -#define RXD_W0_DATA FIELD32(0x00000002) -#define RXD_W0_NULLDATA FIELD32(0x00000004) -#define RXD_W0_FRAG FIELD32(0x00000008) -#define RXD_W0_UNICAST_TO_ME FIELD32(0x00000010) -#define RXD_W0_MULTICAST FIELD32(0x00000020) -#define RXD_W0_BROADCAST FIELD32(0x00000040) -#define RXD_W0_MY_BSS FIELD32(0x00000080) -#define RXD_W0_CRC_ERROR FIELD32(0x00000100) -#define RXD_W0_CIPHER_ERROR FIELD32(0x00000600) -#define RXD_W0_AMSDU FIELD32(0x00000800) -#define RXD_W0_HTC FIELD32(0x00001000) -#define RXD_W0_RSSI FIELD32(0x00002000) -#define RXD_W0_L2PAD FIELD32(0x00004000) -#define RXD_W0_AMPDU FIELD32(0x00008000) -#define RXD_W0_DECRYPTED FIELD32(0x00010000) -#define RXD_W0_PLCP_RSSI FIELD32(0x00020000) -#define RXD_W0_CIPHER_ALG FIELD32(0x00040000) -#define RXD_W0_LAST_AMSDU FIELD32(0x00080000) -#define RXD_W0_PLCP_SIGNAL FIELD32(0xfff00000) +#define RXINFO_W0_BA FIELD32(0x00000001) +#define RXINFO_W0_DATA FIELD32(0x00000002) +#define RXINFO_W0_NULLDATA FIELD32(0x00000004) +#define RXINFO_W0_FRAG FIELD32(0x00000008) +#define RXINFO_W0_UNICAST_TO_ME FIELD32(0x00000010) +#define RXINFO_W0_MULTICAST FIELD32(0x00000020) +#define RXINFO_W0_BROADCAST FIELD32(0x00000040) +#define RXINFO_W0_MY_BSS FIELD32(0x00000080) +#define RXINFO_W0_CRC_ERROR FIELD32(0x00000100) +#define RXINFO_W0_CIPHER_ERROR FIELD32(0x00000600) +#define RXINFO_W0_AMSDU FIELD32(0x00000800) +#define RXINFO_W0_HTC FIELD32(0x00001000) +#define RXINFO_W0_RSSI FIELD32(0x00002000) +#define RXINFO_W0_L2PAD FIELD32(0x00004000) +#define RXINFO_W0_AMPDU FIELD32(0x00008000) +#define RXINFO_W0_DECRYPTED FIELD32(0x00010000) +#define RXINFO_W0_PLCP_RSSI FIELD32(0x00020000) +#define RXINFO_W0_CIPHER_ALG FIELD32(0x00040000) +#define RXINFO_W0_LAST_AMSDU FIELD32(0x00080000) +#define RXINFO_W0_PLCP_SIGNAL FIELD32(0xfff00000) #endif /* RT2800USB_H */ diff --git a/trunk/drivers/net/wireless/rt2x00/rt2x00.h b/trunk/drivers/net/wireless/rt2x00/rt2x00.h index d9daa9c406fa..dcfc8c25d1a7 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2x00.h +++ b/trunk/drivers/net/wireless/rt2x00/rt2x00.h @@ -103,12 +103,6 @@ #define GET_DURATION(__size, __rate) (((__size) * 8 * 10) / (__rate)) #define GET_DURATION_RES(__size, __rate)(((__size) * 8 * 10) % (__rate)) -/* - * Determine the number of L2 padding bytes required between the header and - * the payload. - */ -#define L2PAD_SIZE(__hdrlen) (-(__hdrlen) & 3) - /* * Determine the alignment requirement, * to make sure the 802.11 payload is padded to a 4-byte boundrary @@ -160,7 +154,6 @@ struct avg_val { enum rt2x00_chip_intf { RT2X00_CHIP_INTF_PCI, RT2X00_CHIP_INTF_USB, - RT2X00_CHIP_INTF_SOC, }; /* @@ -170,26 +163,25 @@ enum rt2x00_chip_intf { */ struct rt2x00_chip { u16 rt; -#define RT2460 0x2460 -#define RT2560 0x2560 -#define RT2570 0x2570 -#define RT2661 0x2661 -#define RT2573 0x2573 -#define RT2860 0x2860 /* 2.4GHz PCI/CB */ -#define RT2870 0x2870 -#define RT2872 0x2872 +#define RT2460 0x0101 +#define RT2560 0x0201 +#define RT2570 0x1201 +#define RT2561s 0x0301 /* Turbo */ +#define RT2561 0x0302 +#define RT2661 0x0401 +#define RT2571 0x1300 +#define RT2860 0x0601 /* 2.4GHz PCI/CB */ +#define RT2860D 0x0681 /* 2.4GHz, 5GHz PCI/CB */ +#define RT2890 0x0701 /* 2.4GHz PCIe */ +#define RT2890D 0x0781 /* 2.4GHz, 5GHz PCIe */ #define RT2880 0x2880 /* WSOC */ -#define RT2883 0x2883 /* WSOC */ -#define RT2890 0x2890 /* 2.4GHz PCIe */ #define RT3052 0x3052 /* WSOC */ -#define RT3070 0x3070 -#define RT3071 0x3071 #define RT3090 0x3090 /* 2.4GHz PCIe */ -#define RT3390 0x3390 -#define RT3572 0x3572 +#define RT2870 0x1600 +#define RT3070 0x1800 u16 rf; - u16 rev; + u32 rev; enum rt2x00_chip_intf intf; }; @@ -919,30 +911,51 @@ static inline void rt2x00_eeprom_write(struct rt2x00_dev *rt2x00dev, * Chipset handlers */ static inline void rt2x00_set_chip(struct rt2x00_dev *rt2x00dev, - const u16 rt, const u16 rf, const u16 rev) + const u16 rt, const u16 rf, const u32 rev) { rt2x00dev->chip.rt = rt; rt2x00dev->chip.rf = rf; rt2x00dev->chip.rev = rev; +} + +static inline void rt2x00_set_chip_rt(struct rt2x00_dev *rt2x00dev, + const u16 rt) +{ + rt2x00dev->chip.rt = rt; +} + +static inline void rt2x00_set_chip_rf(struct rt2x00_dev *rt2x00dev, + const u16 rf, const u32 rev) +{ + rt2x00_set_chip(rt2x00dev, rt2x00dev->chip.rt, rf, rev); +} +static inline void rt2x00_print_chip(struct rt2x00_dev *rt2x00dev) +{ INFO(rt2x00dev, - "Chipset detected - rt: %04x, rf: %04x, rev: %04x.\n", + "Chipset detected - rt: %04x, rf: %04x, rev: %08x.\n", rt2x00dev->chip.rt, rt2x00dev->chip.rf, rt2x00dev->chip.rev); } -static inline char rt2x00_rt(struct rt2x00_dev *rt2x00dev, const u16 rt) +static inline char rt2x00_rt(const struct rt2x00_chip *chipset, const u16 chip) { - return (rt2x00dev->chip.rt == rt); + return (chipset->rt == chip); } -static inline char rt2x00_rf(struct rt2x00_dev *rt2x00dev, const u16 rf) +static inline char rt2x00_rf(const struct rt2x00_chip *chipset, const u16 chip) { - return (rt2x00dev->chip.rf == rf); + return (chipset->rf == chip); } -static inline u16 rt2x00_rev(struct rt2x00_dev *rt2x00dev) +static inline u32 rt2x00_rev(const struct rt2x00_chip *chipset) { - return rt2x00dev->chip.rev; + return chipset->rev; +} + +static inline bool rt2x00_check_rev(const struct rt2x00_chip *chipset, + const u32 mask, const u32 rev) +{ + return ((chipset->rev & mask) == rev); } static inline void rt2x00_set_chip_intf(struct rt2x00_dev *rt2x00dev, @@ -951,25 +964,20 @@ static inline void rt2x00_set_chip_intf(struct rt2x00_dev *rt2x00dev, rt2x00dev->chip.intf = intf; } -static inline bool rt2x00_intf(struct rt2x00_dev *rt2x00dev, +static inline bool rt2x00_intf(const struct rt2x00_chip *chipset, enum rt2x00_chip_intf intf) { - return (rt2x00dev->chip.intf == intf); -} - -static inline bool rt2x00_is_pci(struct rt2x00_dev *rt2x00dev) -{ - return rt2x00_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI); + return (chipset->intf == intf); } -static inline bool rt2x00_is_usb(struct rt2x00_dev *rt2x00dev) +static inline bool rt2x00_intf_is_pci(struct rt2x00_dev *rt2x00dev) { - return rt2x00_intf(rt2x00dev, RT2X00_CHIP_INTF_USB); + return rt2x00_intf(&rt2x00dev->chip, RT2X00_CHIP_INTF_PCI); } -static inline bool rt2x00_is_soc(struct rt2x00_dev *rt2x00dev) +static inline bool rt2x00_intf_is_usb(struct rt2x00_dev *rt2x00dev) { - return rt2x00_intf(rt2x00dev, RT2X00_CHIP_INTF_SOC); + return rt2x00_intf(&rt2x00dev->chip, RT2X00_CHIP_INTF_USB); } /** @@ -1011,9 +1019,9 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb); int rt2x00mac_start(struct ieee80211_hw *hw); void rt2x00mac_stop(struct ieee80211_hw *hw); int rt2x00mac_add_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif); + struct ieee80211_if_init_conf *conf); void rt2x00mac_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif); + struct ieee80211_if_init_conf *conf); int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed); void rt2x00mac_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, @@ -1030,6 +1038,8 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, #endif /* CONFIG_RT2X00_LIB_CRYPTO */ int rt2x00mac_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats); +int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw, + struct ieee80211_tx_queue_stats *stats); void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, diff --git a/trunk/drivers/net/wireless/rt2x00/rt2x00debug.c b/trunk/drivers/net/wireless/rt2x00/rt2x00debug.c index 70c04c282efc..7d323a763b54 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2x00debug.c +++ b/trunk/drivers/net/wireless/rt2x00/rt2x00debug.c @@ -184,7 +184,7 @@ void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, dump_hdr->data_length = cpu_to_le32(skb->len); dump_hdr->chip_rt = cpu_to_le16(rt2x00dev->chip.rt); dump_hdr->chip_rf = cpu_to_le16(rt2x00dev->chip.rf); - dump_hdr->chip_rev = cpu_to_le16(rt2x00dev->chip.rev); + dump_hdr->chip_rev = cpu_to_le32(rt2x00dev->chip.rev); dump_hdr->type = cpu_to_le16(type); dump_hdr->queue_index = desc->entry->queue->qid; dump_hdr->entry_index = desc->entry->entry_idx; @@ -573,7 +573,7 @@ static struct dentry *rt2x00debug_create_file_chipset(const char *name, blob->data = data; data += sprintf(data, "rt chip:\t%04x\n", intf->rt2x00dev->chip.rt); data += sprintf(data, "rf chip:\t%04x\n", intf->rt2x00dev->chip.rf); - data += sprintf(data, "revision:\t%04x\n", intf->rt2x00dev->chip.rev); + data += sprintf(data, "revision:\t%08x\n", intf->rt2x00dev->chip.rev); data += sprintf(data, "\n"); data += sprintf(data, "register\tbase\twords\twordsize\n"); data += sprintf(data, "csr\t%d\t%d\t%d\n", diff --git a/trunk/drivers/net/wireless/rt2x00/rt2x00dev.c b/trunk/drivers/net/wireless/rt2x00/rt2x00dev.c index b93731b79903..265e66dba552 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/trunk/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -385,6 +385,9 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, memset(&rxdesc, 0, sizeof(rxdesc)); rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc); + /* Trim buffer to correct size */ + skb_trim(entry->skb, rxdesc.size); + /* * The data behind the ieee80211 header must be * aligned on a 4 byte boundary. @@ -401,16 +404,11 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, (rxdesc.flags & RX_FLAG_IV_STRIPPED)) rt2x00crypto_rx_insert_iv(entry->skb, header_length, &rxdesc); - else if (header_length && - (rxdesc.size > header_length) && - (rxdesc.dev_flags & RXDONE_L2PAD)) + else if (rxdesc.dev_flags & RXDONE_L2PAD) rt2x00queue_remove_l2pad(entry->skb, header_length); else rt2x00queue_align_payload(entry->skb, header_length); - /* Trim buffer to correct size */ - skb_trim(entry->skb, rxdesc.size); - /* * Check if the frame was received using HT. In that case, * the rate is the MCS index and should be passed to mac80211 diff --git a/trunk/drivers/net/wireless/rt2x00/rt2x00mac.c b/trunk/drivers/net/wireless/rt2x00/rt2x00mac.c index abbd857ec759..de549c244ed8 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/trunk/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -187,10 +187,10 @@ void rt2x00mac_stop(struct ieee80211_hw *hw) EXPORT_SYMBOL_GPL(rt2x00mac_stop); int rt2x00mac_add_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) + struct ieee80211_if_init_conf *conf) { struct rt2x00_dev *rt2x00dev = hw->priv; - struct rt2x00_intf *intf = vif_to_intf(vif); + struct rt2x00_intf *intf = vif_to_intf(conf->vif); struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, QID_BEACON); struct queue_entry *entry = NULL; unsigned int i; @@ -203,7 +203,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, !test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags)) return -ENODEV; - switch (vif->type) { + switch (conf->type) { case NL80211_IFTYPE_AP: /* * We don't support mixed combinations of @@ -263,7 +263,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, * increase interface count and start initialization. */ - if (vif->type == NL80211_IFTYPE_AP) + if (conf->type == NL80211_IFTYPE_AP) rt2x00dev->intf_ap_count++; else rt2x00dev->intf_sta_count++; @@ -273,16 +273,16 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, mutex_init(&intf->beacon_skb_mutex); intf->beacon = entry; - if (vif->type == NL80211_IFTYPE_AP) - memcpy(&intf->bssid, vif->addr, ETH_ALEN); - memcpy(&intf->mac, vif->addr, ETH_ALEN); + if (conf->type == NL80211_IFTYPE_AP) + memcpy(&intf->bssid, conf->mac_addr, ETH_ALEN); + memcpy(&intf->mac, conf->mac_addr, ETH_ALEN); /* * The MAC adddress must be configured after the device * has been initialized. Otherwise the device can reset * the MAC registers. */ - rt2x00lib_config_intf(rt2x00dev, intf, vif->type, intf->mac, NULL); + rt2x00lib_config_intf(rt2x00dev, intf, conf->type, intf->mac, NULL); /* * Some filters depend on the current working mode. We can force @@ -296,10 +296,10 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, EXPORT_SYMBOL_GPL(rt2x00mac_add_interface); void rt2x00mac_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) + struct ieee80211_if_init_conf *conf) { struct rt2x00_dev *rt2x00dev = hw->priv; - struct rt2x00_intf *intf = vif_to_intf(vif); + struct rt2x00_intf *intf = vif_to_intf(conf->vif); /* * Don't allow interfaces to be remove while @@ -307,11 +307,11 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw, * no interface is present. */ if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) || - (vif->type == NL80211_IFTYPE_AP && !rt2x00dev->intf_ap_count) || - (vif->type != NL80211_IFTYPE_AP && !rt2x00dev->intf_sta_count)) + (conf->type == NL80211_IFTYPE_AP && !rt2x00dev->intf_ap_count) || + (conf->type != NL80211_IFTYPE_AP && !rt2x00dev->intf_sta_count)) return; - if (vif->type == NL80211_IFTYPE_AP) + if (conf->type == NL80211_IFTYPE_AP) rt2x00dev->intf_ap_count--; else rt2x00dev->intf_sta_count--; @@ -555,6 +555,22 @@ int rt2x00mac_get_stats(struct ieee80211_hw *hw, } EXPORT_SYMBOL_GPL(rt2x00mac_get_stats); +int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw, + struct ieee80211_tx_queue_stats *stats) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + unsigned int i; + + for (i = 0; i < rt2x00dev->ops->tx_queues; i++) { + stats[i].len = rt2x00dev->tx[i].length; + stats[i].limit = rt2x00dev->tx[i].limit; + stats[i].count = rt2x00dev->tx[i].count; + } + + return 0; +} +EXPORT_SYMBOL_GPL(rt2x00mac_get_tx_stats); + void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, diff --git a/trunk/drivers/net/wireless/rt2x00/rt2x00pci.c b/trunk/drivers/net/wireless/rt2x00/rt2x00pci.c index 047123b766fc..0feb4d0e4668 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/trunk/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -41,9 +41,6 @@ int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev, { unsigned int i; - if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) - return 0; - for (i = 0; i < REGISTER_BUSY_COUNT; i++) { rt2x00pci_register_read(rt2x00dev, offset, reg); if (!rt2x00_get_field32(*reg, field)) @@ -272,6 +269,7 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) struct ieee80211_hw *hw; struct rt2x00_dev *rt2x00dev; int retval; + u16 chip; retval = pci_request_regions(pci_dev, pci_name(pci_dev)); if (retval) { @@ -314,6 +312,12 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI); + /* + * Determine RT chipset by reading PCI header. + */ + pci_read_config_word(pci_dev, PCI_DEVICE_ID, &chip); + rt2x00_set_chip_rt(rt2x00dev, chip); + retval = rt2x00pci_alloc_reg(rt2x00dev); if (retval) goto exit_free_device; diff --git a/trunk/drivers/net/wireless/rt2x00/rt2x00pci.h b/trunk/drivers/net/wireless/rt2x00/rt2x00pci.h index 8149ff68410a..d4f9449ab0a4 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2x00pci.h +++ b/trunk/drivers/net/wireless/rt2x00/rt2x00pci.h @@ -27,7 +27,6 @@ #define RT2X00PCI_H #include -#include /* * This variable should be used with the diff --git a/trunk/drivers/net/wireless/rt2x00/rt2x00queue.c b/trunk/drivers/net/wireless/rt2x00/rt2x00queue.c index 0b4801a14601..9915a09141ef 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/trunk/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -177,45 +177,55 @@ void rt2x00queue_align_payload(struct sk_buff *skb, unsigned int header_length) void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length) { - unsigned int payload_length = skb->len - header_length; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); + unsigned int frame_length = skb->len; unsigned int header_align = ALIGN_SIZE(skb, 0); unsigned int payload_align = ALIGN_SIZE(skb, header_length); - unsigned int l2pad = payload_length ? L2PAD_SIZE(header_length) : 0; - - /* - * Adjust the header alignment if the payload needs to be moved more - * than the header. - */ - if (payload_align > header_align) - header_align += 4; + unsigned int l2pad = 4 - (payload_align - header_align); - /* There is nothing to do if no alignment is needed */ - if (!header_align) - return; - - /* Reserve the amount of space needed in front of the frame */ - skb_push(skb, header_align); - - /* - * Move the header. - */ - memmove(skb->data, skb->data + header_align, header_length); + if (header_align == payload_align) { + /* + * Both header and payload must be moved the same + * amount of bytes to align them properly. This means + * we don't use the L2 padding but just move the entire + * frame. + */ + rt2x00queue_align_frame(skb); + } else if (!payload_align) { + /* + * Simple L2 padding, only the header needs to be moved, + * the payload is already properly aligned. + */ + skb_push(skb, header_align); + memmove(skb->data, skb->data + header_align, frame_length); + skbdesc->flags |= SKBDESC_L2_PADDED; + } else { + /* + * + * Complicated L2 padding, both header and payload need + * to be moved. By default we only move to the start + * of the buffer, so our header alignment needs to be + * increased if there is not enough room for the header + * to be moved. + */ + if (payload_align > header_align) + header_align += 4; - /* Move the payload, if present and if required */ - if (payload_length && payload_align) + skb_push(skb, header_align); + memmove(skb->data, skb->data + header_align, header_length); memmove(skb->data + header_length + l2pad, skb->data + header_length + l2pad + payload_align, - payload_length); - - /* Trim the skb to the correct size */ - skb_trim(skb, header_length + l2pad + payload_length); + frame_length - header_length); + skbdesc->flags |= SKBDESC_L2_PADDED; + } } void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int header_length) { - unsigned int l2pad = L2PAD_SIZE(header_length); + struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); + unsigned int l2pad = 4 - (header_length & 3); - if (!l2pad) + if (!l2pad || (skbdesc->flags & SKBDESC_L2_PADDED)) return; memmove(skb->data + l2pad, skb->data, header_length); @@ -336,9 +346,7 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, * Header and alignment information. */ txdesc->header_length = ieee80211_get_hdrlen_from_skb(entry->skb); - if (test_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags) && - (entry->skb->len > txdesc->header_length)) - txdesc->l2pad = L2PAD_SIZE(txdesc->header_length); + txdesc->l2pad = ALIGN_SIZE(entry->skb, txdesc->header_length); /* * Check whether this frame is to be acked. @@ -379,13 +387,10 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, /* * Beacons and probe responses require the tsf timestamp - * to be inserted into the frame, except for a frame that has been injected - * through a monitor interface. This latter is needed for testing a - * monitor interface. + * to be inserted into the frame. */ - if ((ieee80211_is_beacon(hdr->frame_control) || - ieee80211_is_probe_resp(hdr->frame_control)) && - (!(tx_info->flags & IEEE80211_TX_CTL_INJECTED))) + if (ieee80211_is_beacon(hdr->frame_control) || + ieee80211_is_probe_resp(hdr->frame_control)) __set_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags); /* diff --git a/trunk/drivers/net/wireless/rt2x00/rt2x00queue.h b/trunk/drivers/net/wireless/rt2x00/rt2x00queue.h index c1e482bb37b3..70775e5ba1ac 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/trunk/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -92,6 +92,8 @@ enum data_queue_qid { * @SKBDESC_DMA_MAPPED_TX: &skb_dma field has been mapped for TX * @SKBDESC_IV_STRIPPED: Frame contained a IV/EIV provided by * mac80211 but was stripped for processing by the driver. + * @SKBDESC_L2_PADDED: Payload has been padded for 4-byte alignment, + * the padded bytes are located between header and payload. * @SKBDESC_NOT_MAC80211: Frame didn't originate from mac80211, * don't try to pass it back. */ @@ -99,7 +101,8 @@ enum skb_frame_desc_flags { SKBDESC_DMA_MAPPED_RX = 1 << 0, SKBDESC_DMA_MAPPED_TX = 1 << 1, SKBDESC_IV_STRIPPED = 1 << 2, - SKBDESC_NOT_MAC80211 = 1 << 3, + SKBDESC_L2_PADDED = 1 << 3, + SKBDESC_NOT_MAC80211 = 1 << 4, }; /** diff --git a/trunk/drivers/net/wireless/rt2x00/rt2x00soc.c b/trunk/drivers/net/wireless/rt2x00/rt2x00soc.c index 4efdc96010f6..19e684f8ffa1 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2x00soc.c +++ b/trunk/drivers/net/wireless/rt2x00/rt2x00soc.c @@ -71,7 +71,9 @@ static int rt2x00soc_alloc_reg(struct rt2x00_dev *rt2x00dev) return -ENOMEM; } -int rt2x00soc_probe(struct platform_device *pdev, const struct rt2x00_ops *ops) +int rt2x00soc_probe(struct platform_device *pdev, + const unsigned short chipset, + const struct rt2x00_ops *ops) { struct ieee80211_hw *hw; struct rt2x00_dev *rt2x00dev; @@ -92,7 +94,12 @@ int rt2x00soc_probe(struct platform_device *pdev, const struct rt2x00_ops *ops) rt2x00dev->irq = platform_get_irq(pdev, 0); rt2x00dev->name = pdev->dev.driver->name; - rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_SOC); + /* + * SoC devices mimic PCI behavior. + */ + rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI); + + rt2x00_set_chip_rt(rt2x00dev, chipset); retval = rt2x00soc_alloc_reg(rt2x00dev); if (retval) diff --git a/trunk/drivers/net/wireless/rt2x00/rt2x00soc.h b/trunk/drivers/net/wireless/rt2x00/rt2x00soc.h index 4739edfe2f00..8a3416624af5 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2x00soc.h +++ b/trunk/drivers/net/wireless/rt2x00/rt2x00soc.h @@ -28,10 +28,18 @@ #define KSEG1ADDR(__ptr) __ptr +#define __rt2x00soc_probe(__chipset, __ops) \ +static int __rt2x00soc_probe(struct platform_device *pdev) \ +{ \ + return rt2x00soc_probe(pdev, (__chipset), (__ops)); \ +} + /* * SoC driver handlers. */ -int rt2x00soc_probe(struct platform_device *pdev, const struct rt2x00_ops *ops); +int rt2x00soc_probe(struct platform_device *pdev, + const unsigned short chipset, + const struct rt2x00_ops *ops); int rt2x00soc_remove(struct platform_device *pdev); #ifdef CONFIG_PM int rt2x00soc_suspend(struct platform_device *pdev, pm_message_t state); diff --git a/trunk/drivers/net/wireless/rt2x00/rt61pci.c b/trunk/drivers/net/wireless/rt2x00/rt61pci.c index ee9c696fe1d4..0ca589306d71 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt61pci.c +++ b/trunk/drivers/net/wireless/rt2x00/rt61pci.c @@ -637,7 +637,8 @@ static void rt61pci_config_antenna_5x(struct rt2x00_dev *rt2x00dev, rt61pci_bbp_read(rt2x00dev, 4, &r4); rt61pci_bbp_read(rt2x00dev, 77, &r77); - rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, rt2x00_rf(rt2x00dev, RF5325)); + rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, + rt2x00_rf(&rt2x00dev->chip, RF5325)); /* * Configure the RX antenna. @@ -683,7 +684,8 @@ static void rt61pci_config_antenna_2x(struct rt2x00_dev *rt2x00dev, rt61pci_bbp_read(rt2x00dev, 4, &r4); rt61pci_bbp_read(rt2x00dev, 77, &r77); - rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, rt2x00_rf(rt2x00dev, RF2529)); + rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, + rt2x00_rf(&rt2x00dev->chip, RF2529)); rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, !test_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags)); @@ -831,11 +833,12 @@ static void rt61pci_config_ant(struct rt2x00_dev *rt2x00dev, rt2x00pci_register_write(rt2x00dev, PHY_CSR0, reg); - if (rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF5325)) + if (rt2x00_rf(&rt2x00dev->chip, RF5225) || + rt2x00_rf(&rt2x00dev->chip, RF5325)) rt61pci_config_antenna_5x(rt2x00dev, ant); - else if (rt2x00_rf(rt2x00dev, RF2527)) + else if (rt2x00_rf(&rt2x00dev->chip, RF2527)) rt61pci_config_antenna_2x(rt2x00dev, ant); - else if (rt2x00_rf(rt2x00dev, RF2529)) { + else if (rt2x00_rf(&rt2x00dev->chip, RF2529)) { if (test_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags)) rt61pci_config_antenna_2x(rt2x00dev, ant); else @@ -876,7 +879,8 @@ static void rt61pci_config_channel(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset); - smart = !(rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF2527)); + smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) || + rt2x00_rf(&rt2x00dev->chip, RF2527)); rt61pci_bbp_read(rt2x00dev, 3, &r3); rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart); @@ -1131,18 +1135,16 @@ static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev, */ static char *rt61pci_get_firmware_name(struct rt2x00_dev *rt2x00dev) { - u16 chip; char *fw_name; - pci_read_config_word(to_pci_dev(rt2x00dev->dev), PCI_DEVICE_ID, &chip); - switch (chip) { - case RT2561_PCI_ID: + switch (rt2x00dev->chip.rt) { + case RT2561: fw_name = FIRMWARE_RT2561; break; - case RT2561s_PCI_ID: + case RT2561s: fw_name = FIRMWARE_RT2561s; break; - case RT2661_PCI_ID: + case RT2661: fw_name = FIRMWARE_RT2661; break; default: @@ -2297,13 +2299,13 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) */ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); rt2x00pci_register_read(rt2x00dev, MAC_CSR0, ®); - rt2x00_set_chip(rt2x00dev, rt2x00_get_field32(reg, MAC_CSR0_CHIPSET), - value, rt2x00_get_field32(reg, MAC_CSR0_REVISION)); + rt2x00_set_chip_rf(rt2x00dev, value, reg); + rt2x00_print_chip(rt2x00dev); - if (!rt2x00_rf(rt2x00dev, RF5225) && - !rt2x00_rf(rt2x00dev, RF5325) && - !rt2x00_rf(rt2x00dev, RF2527) && - !rt2x00_rf(rt2x00dev, RF2529)) { + if (!rt2x00_rf(&rt2x00dev->chip, RF5225) && + !rt2x00_rf(&rt2x00dev->chip, RF5325) && + !rt2x00_rf(&rt2x00dev->chip, RF2527) && + !rt2x00_rf(&rt2x00dev->chip, RF2529)) { ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); return -ENODEV; } @@ -2358,7 +2360,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) * the antenna settings should be gathered from the NIC * eeprom word. */ - if (rt2x00_rf(rt2x00dev, RF2529) && + if (rt2x00_rf(&rt2x00dev->chip, RF2529) && !test_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags)) { rt2x00dev->default_ant.rx = ANTENNA_A + rt2x00_get_field16(eeprom, EEPROM_NIC_RX_FIXED); @@ -2569,7 +2571,8 @@ static int rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) spec->channels = rf_vals_seq; } - if (rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF5325)) { + if (rt2x00_rf(&rt2x00dev->chip, RF5225) || + rt2x00_rf(&rt2x00dev->chip, RF5325)) { spec->supported_bands |= SUPPORT_BAND_5GHZ; spec->num_channels = ARRAY_SIZE(rf_vals_seq); } @@ -2732,6 +2735,7 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = { .get_stats = rt2x00mac_get_stats, .bss_info_changed = rt2x00mac_bss_info_changed, .conf_tx = rt61pci_conf_tx, + .get_tx_stats = rt2x00mac_get_tx_stats, .get_tsf = rt61pci_get_tsf, .rfkill_poll = rt2x00mac_rfkill_poll, }; diff --git a/trunk/drivers/net/wireless/rt2x00/rt61pci.h b/trunk/drivers/net/wireless/rt2x00/rt61pci.h index ab20c7758824..6f33f7f5668c 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt61pci.h +++ b/trunk/drivers/net/wireless/rt2x00/rt61pci.h @@ -27,13 +27,6 @@ #ifndef RT61PCI_H #define RT61PCI_H -/* - * RT chip PCI IDs. - */ -#define RT2561s_PCI_ID 0x0301 -#define RT2561_PCI_ID 0x0302 -#define RT2661_PCI_ID 0x0401 - /* * RF chip defines. */ @@ -232,8 +225,6 @@ struct hw_pairwise_ta_entry { * MAC_CSR0: ASIC revision number. */ #define MAC_CSR0 0x3000 -#define MAC_CSR0_REVISION FIELD32(0x0000000f) -#define MAC_CSR0_CHIPSET FIELD32(0x000ffff0) /* * MAC_CSR1: System control register. diff --git a/trunk/drivers/net/wireless/rt2x00/rt73usb.c b/trunk/drivers/net/wireless/rt2x00/rt73usb.c index f39a8ed17841..ced3b6ab5e16 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt73usb.c +++ b/trunk/drivers/net/wireless/rt2x00/rt73usb.c @@ -136,8 +136,8 @@ static void rt73usb_rf_write(struct rt2x00_dev *rt2x00dev, * all others contain 20 bits. */ rt2x00_set_field32(®, PHY_CSR4_NUMBER_OF_BITS, - 20 + (rt2x00_rf(rt2x00dev, RF5225) || - rt2x00_rf(rt2x00dev, RF2527))); + 20 + (rt2x00_rf(&rt2x00dev->chip, RF5225) || + rt2x00_rf(&rt2x00dev->chip, RF2527))); rt2x00_set_field32(®, PHY_CSR4_IF_SELECT, 0); rt2x00_set_field32(®, PHY_CSR4_BUSY, 1); @@ -741,9 +741,11 @@ static void rt73usb_config_ant(struct rt2x00_dev *rt2x00dev, rt2x00usb_register_write(rt2x00dev, PHY_CSR0, reg); - if (rt2x00_rf(rt2x00dev, RF5226) || rt2x00_rf(rt2x00dev, RF5225)) + if (rt2x00_rf(&rt2x00dev->chip, RF5226) || + rt2x00_rf(&rt2x00dev->chip, RF5225)) rt73usb_config_antenna_5x(rt2x00dev, ant); - else if (rt2x00_rf(rt2x00dev, RF2528) || rt2x00_rf(rt2x00dev, RF2527)) + else if (rt2x00_rf(&rt2x00dev->chip, RF2528) || + rt2x00_rf(&rt2x00dev->chip, RF2527)) rt73usb_config_antenna_2x(rt2x00dev, ant); } @@ -777,7 +779,8 @@ static void rt73usb_config_channel(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset); - smart = !(rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF2527)); + smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) || + rt2x00_rf(&rt2x00dev->chip, RF2527)); rt73usb_bbp_read(rt2x00dev, 3, &r3); rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart); @@ -1207,7 +1210,8 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00usb_register_write(rt2x00dev, SEC_CSR5, 0x00000000); reg = 0x000023b0; - if (rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF2527)) + if (rt2x00_rf(&rt2x00dev->chip, RF5225) || + rt2x00_rf(&rt2x00dev->chip, RF2527)) rt2x00_set_field32(®, PHY_CSR1_RF_RPI, 1); rt2x00usb_register_write(rt2x00dev, PHY_CSR1, reg); @@ -1820,18 +1824,19 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev) */ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); rt2x00usb_register_read(rt2x00dev, MAC_CSR0, ®); - rt2x00_set_chip(rt2x00dev, rt2x00_get_field32(reg, MAC_CSR0_CHIPSET), - value, rt2x00_get_field32(reg, MAC_CSR0_REVISION)); + rt2x00_set_chip(rt2x00dev, RT2571, value, reg); + rt2x00_print_chip(rt2x00dev); - if (!rt2x00_rt(rt2x00dev, RT2573) || (rt2x00_rev(rt2x00dev) == 0)) { + if (!rt2x00_check_rev(&rt2x00dev->chip, 0x000ffff0, 0x25730) || + rt2x00_check_rev(&rt2x00dev->chip, 0x0000000f, 0)) { ERROR(rt2x00dev, "Invalid RT chipset detected.\n"); return -ENODEV; } - if (!rt2x00_rf(rt2x00dev, RF5226) && - !rt2x00_rf(rt2x00dev, RF2528) && - !rt2x00_rf(rt2x00dev, RF5225) && - !rt2x00_rf(rt2x00dev, RF2527)) { + if (!rt2x00_rf(&rt2x00dev->chip, RF5226) && + !rt2x00_rf(&rt2x00dev->chip, RF2528) && + !rt2x00_rf(&rt2x00dev->chip, RF5225) && + !rt2x00_rf(&rt2x00dev->chip, RF2527)) { ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); return -ENODEV; } @@ -2076,17 +2081,17 @@ static int rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) spec->supported_bands = SUPPORT_BAND_2GHZ; spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM; - if (rt2x00_rf(rt2x00dev, RF2528)) { + if (rt2x00_rf(&rt2x00dev->chip, RF2528)) { spec->num_channels = ARRAY_SIZE(rf_vals_bg_2528); spec->channels = rf_vals_bg_2528; - } else if (rt2x00_rf(rt2x00dev, RF5226)) { + } else if (rt2x00_rf(&rt2x00dev->chip, RF5226)) { spec->supported_bands |= SUPPORT_BAND_5GHZ; spec->num_channels = ARRAY_SIZE(rf_vals_5226); spec->channels = rf_vals_5226; - } else if (rt2x00_rf(rt2x00dev, RF2527)) { + } else if (rt2x00_rf(&rt2x00dev->chip, RF2527)) { spec->num_channels = 14; spec->channels = rf_vals_5225_2527; - } else if (rt2x00_rf(rt2x00dev, RF5225)) { + } else if (rt2x00_rf(&rt2x00dev->chip, RF5225)) { spec->supported_bands |= SUPPORT_BAND_5GHZ; spec->num_channels = ARRAY_SIZE(rf_vals_5225_2527); spec->channels = rf_vals_5225_2527; @@ -2244,6 +2249,7 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = { .get_stats = rt2x00mac_get_stats, .bss_info_changed = rt2x00mac_bss_info_changed, .conf_tx = rt73usb_conf_tx, + .get_tx_stats = rt2x00mac_get_tx_stats, .get_tsf = rt73usb_get_tsf, .rfkill_poll = rt2x00mac_rfkill_poll, }; @@ -2348,7 +2354,6 @@ static struct usb_device_id rt73usb_device_table[] = { { USB_DEVICE(0x08dd, 0x0120), USB_DEVICE_DATA(&rt73usb_ops) }, /* Buffalo */ { USB_DEVICE(0x0411, 0x00d8), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x0411, 0x00d9), USB_DEVICE_DATA(&rt73usb_ops) }, { USB_DEVICE(0x0411, 0x00f4), USB_DEVICE_DATA(&rt73usb_ops) }, { USB_DEVICE(0x0411, 0x0116), USB_DEVICE_DATA(&rt73usb_ops) }, { USB_DEVICE(0x0411, 0x0119), USB_DEVICE_DATA(&rt73usb_ops) }, diff --git a/trunk/drivers/net/wireless/rt2x00/rt73usb.h b/trunk/drivers/net/wireless/rt2x00/rt73usb.h index b4e3ddda06cf..e783a099a8f1 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt73usb.h +++ b/trunk/drivers/net/wireless/rt2x00/rt73usb.h @@ -142,8 +142,6 @@ struct hw_pairwise_ta_entry { * MAC_CSR0: ASIC revision number. */ #define MAC_CSR0 0x3000 -#define MAC_CSR0_REVISION FIELD32(0x0000000f) -#define MAC_CSR0_CHIPSET FIELD32(0x000ffff0) /* * MAC_CSR1: System control register. diff --git a/trunk/drivers/net/wireless/rtl818x/rtl8180.h b/trunk/drivers/net/wireless/rtl818x/rtl8180.h index de3844fe06d8..8721282a8185 100644 --- a/trunk/drivers/net/wireless/rtl818x/rtl8180.h +++ b/trunk/drivers/net/wireless/rtl818x/rtl8180.h @@ -60,6 +60,7 @@ struct rtl8180_priv { struct rtl818x_csr __iomem *map; const struct rtl818x_rf_ops *rf; struct ieee80211_vif *vif; + int mode; /* rtl8180 driver specific */ spinlock_t lock; diff --git a/trunk/drivers/net/wireless/rtl818x/rtl8180_dev.c b/trunk/drivers/net/wireless/rtl818x/rtl8180_dev.c index 109ab1baf625..8a40a1439984 100644 --- a/trunk/drivers/net/wireless/rtl818x/rtl8180_dev.c +++ b/trunk/drivers/net/wireless/rtl818x/rtl8180_dev.c @@ -82,6 +82,8 @@ static const struct ieee80211_channel rtl818x_channels[] = { }; + + void rtl8180_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data) { struct rtl8180_priv *priv = dev->priv; @@ -613,6 +615,7 @@ static int rtl8180_start(struct ieee80211_hw *dev) reg |= RTL818X_CMD_TX_ENABLE; rtl818x_iowrite8(priv, &priv->map->CMD, reg); + priv->mode = NL80211_IFTYPE_MONITOR; return 0; err_free_rings: @@ -630,6 +633,8 @@ static void rtl8180_stop(struct ieee80211_hw *dev) u8 reg; int i; + priv->mode = NL80211_IFTYPE_UNSPECIFIED; + rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0); reg = rtl818x_ioread8(priv, &priv->map->CMD); @@ -652,39 +657,38 @@ static void rtl8180_stop(struct ieee80211_hw *dev) } static int rtl8180_add_interface(struct ieee80211_hw *dev, - struct ieee80211_vif *vif) + struct ieee80211_if_init_conf *conf) { struct rtl8180_priv *priv = dev->priv; - /* - * We only support one active interface at a time. - */ - if (priv->vif) - return -EBUSY; + if (priv->mode != NL80211_IFTYPE_MONITOR) + return -EOPNOTSUPP; - switch (vif->type) { + switch (conf->type) { case NL80211_IFTYPE_STATION: + priv->mode = conf->type; break; default: return -EOPNOTSUPP; } - priv->vif = vif; + priv->vif = conf->vif; rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); rtl818x_iowrite32(priv, (__le32 __iomem *)&priv->map->MAC[0], - le32_to_cpu(*(__le32 *)vif->addr)); + le32_to_cpu(*(__le32 *)conf->mac_addr)); rtl818x_iowrite16(priv, (__le16 __iomem *)&priv->map->MAC[4], - le16_to_cpu(*(__le16 *)(vif->addr + 4))); + le16_to_cpu(*(__le16 *)(conf->mac_addr + 4))); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); return 0; } static void rtl8180_remove_interface(struct ieee80211_hw *dev, - struct ieee80211_vif *vif) + struct ieee80211_if_init_conf *conf) { struct rtl8180_priv *priv = dev->priv; + priv->mode = NL80211_IFTYPE_MONITOR; priv->vif = NULL; } @@ -761,14 +765,6 @@ static void rtl8180_configure_filter(struct ieee80211_hw *dev, rtl818x_iowrite32(priv, &priv->map->RX_CONF, priv->rx_conf); } -static u64 rtl8180_get_tsf(struct ieee80211_hw *dev) -{ - struct rtl8180_priv *priv = dev->priv; - - return rtl818x_ioread32(priv, &priv->map->TSFT[0]) | - (u64)(rtl818x_ioread32(priv, &priv->map->TSFT[1])) << 32; -} - static const struct ieee80211_ops rtl8180_ops = { .tx = rtl8180_tx, .start = rtl8180_start, @@ -779,7 +775,6 @@ static const struct ieee80211_ops rtl8180_ops = { .bss_info_changed = rtl8180_bss_info_changed, .prepare_multicast = rtl8180_prepare_multicast, .configure_filter = rtl8180_configure_filter, - .get_tsf = rtl8180_get_tsf, }; static void rtl8180_eeprom_register_read(struct eeprom_93cx6 *eeprom) diff --git a/trunk/drivers/net/wireless/rtl818x/rtl8187.h b/trunk/drivers/net/wireless/rtl818x/rtl8187.h index 6bb32112e65c..6af0f3f71f3a 100644 --- a/trunk/drivers/net/wireless/rtl818x/rtl8187.h +++ b/trunk/drivers/net/wireless/rtl818x/rtl8187.h @@ -92,7 +92,7 @@ struct rtl8187_priv { struct rtl818x_csr *map; const struct rtl818x_rf_ops *rf; struct ieee80211_vif *vif; - + int mode; /* The mutex protects the TX loopback state. * Any attempt to set channels concurrently locks the device. */ diff --git a/trunk/drivers/net/wireless/rtl818x/rtl8187_dev.c b/trunk/drivers/net/wireless/rtl818x/rtl8187_dev.c index 0fb850e0c656..7ba3052b0708 100644 --- a/trunk/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/trunk/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -1019,30 +1019,31 @@ static void rtl8187_stop(struct ieee80211_hw *dev) } static int rtl8187_add_interface(struct ieee80211_hw *dev, - struct ieee80211_vif *vif) + struct ieee80211_if_init_conf *conf) { struct rtl8187_priv *priv = dev->priv; int i; int ret = -EOPNOTSUPP; mutex_lock(&priv->conf_mutex); - if (priv->vif) + if (priv->mode != NL80211_IFTYPE_MONITOR) goto exit; - switch (vif->type) { + switch (conf->type) { case NL80211_IFTYPE_STATION: + priv->mode = conf->type; break; default: goto exit; } ret = 0; - priv->vif = vif; + priv->vif = conf->vif; rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); for (i = 0; i < ETH_ALEN; i++) rtl818x_iowrite8(priv, &priv->map->MAC[i], - ((u8 *)vif->addr)[i]); + ((u8 *)conf->mac_addr)[i]); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); exit: @@ -1051,10 +1052,11 @@ static int rtl8187_add_interface(struct ieee80211_hw *dev, } static void rtl8187_remove_interface(struct ieee80211_hw *dev, - struct ieee80211_vif *vif) + struct ieee80211_if_init_conf *conf) { struct rtl8187_priv *priv = dev->priv; mutex_lock(&priv->conf_mutex); + priv->mode = NL80211_IFTYPE_MONITOR; priv->vif = NULL; mutex_unlock(&priv->conf_mutex); } @@ -1266,14 +1268,6 @@ static int rtl8187_conf_tx(struct ieee80211_hw *dev, u16 queue, return 0; } -static u64 rtl8187_get_tsf(struct ieee80211_hw *dev) -{ - struct rtl8187_priv *priv = dev->priv; - - return rtl818x_ioread32(priv, &priv->map->TSFT[0]) | - (u64)(rtl818x_ioread32(priv, &priv->map->TSFT[1])) << 32; -} - static const struct ieee80211_ops rtl8187_ops = { .tx = rtl8187_tx, .start = rtl8187_start, @@ -1285,8 +1279,7 @@ static const struct ieee80211_ops rtl8187_ops = { .prepare_multicast = rtl8187_prepare_multicast, .configure_filter = rtl8187_configure_filter, .conf_tx = rtl8187_conf_tx, - .rfkill_poll = rtl8187_rfkill_poll, - .get_tsf = rtl8187_get_tsf, + .rfkill_poll = rtl8187_rfkill_poll }; static void rtl8187_eeprom_register_read(struct eeprom_93cx6 *eeprom) @@ -1373,6 +1366,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; + priv->mode = NL80211_IFTYPE_MONITOR; dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_RX_INCLUDES_FCS; diff --git a/trunk/drivers/net/wireless/rtl818x/rtl8187_leds.c b/trunk/drivers/net/wireless/rtl818x/rtl8187_leds.c index 4637337d5ce6..ded44c045eb2 100644 --- a/trunk/drivers/net/wireless/rtl818x/rtl8187_leds.c +++ b/trunk/drivers/net/wireless/rtl818x/rtl8187_leds.c @@ -33,7 +33,7 @@ static void led_turn_on(struct work_struct *work) struct rtl8187_led *led = &priv->led_tx; /* Don't change the LED, when the device is down. */ - if (!priv->vif || priv->vif->type == NL80211_IFTYPE_UNSPECIFIED) + if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) return ; /* Skip if the LED is not registered. */ @@ -71,7 +71,7 @@ static void led_turn_off(struct work_struct *work) struct rtl8187_led *led = &priv->led_tx; /* Don't change the LED, when the device is down. */ - if (!priv->vif || priv->vif->type == NL80211_IFTYPE_UNSPECIFIED) + if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) return ; /* Skip if the LED is not registered. */ @@ -241,5 +241,5 @@ void rtl8187_leds_exit(struct ieee80211_hw *dev) cancel_delayed_work_sync(&priv->led_off); cancel_delayed_work_sync(&priv->led_on); } -#endif /* def CONFIG_RTL8187_LEDS */ +#endif /* def CONFIG_RTL8187_LED */ diff --git a/trunk/drivers/net/wireless/rtl818x/rtl8187_leds.h b/trunk/drivers/net/wireless/rtl818x/rtl8187_leds.h index d743c96d4a20..efe8041bdda4 100644 --- a/trunk/drivers/net/wireless/rtl818x/rtl8187_leds.h +++ b/trunk/drivers/net/wireless/rtl818x/rtl8187_leds.h @@ -54,6 +54,6 @@ struct rtl8187_led { void rtl8187_leds_init(struct ieee80211_hw *dev, u16 code); void rtl8187_leds_exit(struct ieee80211_hw *dev); -#endif /* def CONFIG_RTL8187_LEDS */ +#endif /* def CONFIG_RTL8187_LED */ #endif /* RTL8187_LED_H */ diff --git a/trunk/drivers/net/wireless/wl12xx/Makefile b/trunk/drivers/net/wireless/wl12xx/Makefile index f47ec94c16dc..62e37ad01cc0 100644 --- a/trunk/drivers/net/wireless/wl12xx/Makefile +++ b/trunk/drivers/net/wireless/wl12xx/Makefile @@ -10,7 +10,5 @@ obj-$(CONFIG_WL1251_SDIO) += wl1251_sdio.o wl1271-objs = wl1271_main.o wl1271_spi.o wl1271_cmd.o \ wl1271_event.o wl1271_tx.o wl1271_rx.o \ wl1271_ps.o wl1271_acx.o wl1271_boot.o \ - wl1271_init.o wl1271_debugfs.o wl1271_io.o - -wl1271-$(CONFIG_NL80211_TESTMODE) += wl1271_testmode.o + wl1271_init.o wl1271_debugfs.o obj-$(CONFIG_WL1271) += wl1271.o diff --git a/trunk/drivers/net/wireless/wl12xx/wl1251.h b/trunk/drivers/net/wireless/wl12xx/wl1251.h index 37c61c19cae5..054533f7a124 100644 --- a/trunk/drivers/net/wireless/wl12xx/wl1251.h +++ b/trunk/drivers/net/wireless/wl12xx/wl1251.h @@ -247,7 +247,6 @@ struct wl1251_debugfs { struct dentry *rxpipe_tx_xfr_host_int_trig_rx_data; struct dentry *tx_queue_len; - struct dentry *tx_queue_status; struct dentry *retry_count; struct dentry *excessive_retries; @@ -341,6 +340,9 @@ struct wl1251 { /* Are we currently scanning */ bool scanning; + /* Our association ID */ + u16 aid; + /* Default key (for WEP) */ u32 default_key; diff --git a/trunk/drivers/net/wireless/wl12xx/wl1251_acx.c b/trunk/drivers/net/wireless/wl12xx/wl1251_acx.c index beff084040b5..acfa086dbfc5 100644 --- a/trunk/drivers/net/wireless/wl12xx/wl1251_acx.c +++ b/trunk/drivers/net/wireless/wl12xx/wl1251_acx.c @@ -976,72 +976,3 @@ int wl1251_acx_wr_tbtt_and_dtim(struct wl1251 *wl, u16 tbtt, u8 dtim) kfree(acx); return ret; } - -int wl1251_acx_ac_cfg(struct wl1251 *wl, u8 ac, u8 cw_min, u16 cw_max, - u8 aifs, u16 txop) -{ - struct wl1251_acx_ac_cfg *acx; - int ret = 0; - - wl1251_debug(DEBUG_ACX, "acx ac cfg %d cw_ming %d cw_max %d " - "aifs %d txop %d", ac, cw_min, cw_max, aifs, txop); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->ac = ac; - acx->cw_min = cw_min; - acx->cw_max = cw_max; - acx->aifsn = aifs; - acx->txop_limit = txop; - - ret = wl1251_cmd_configure(wl, ACX_AC_CFG, acx, sizeof(*acx)); - if (ret < 0) { - wl1251_warning("acx ac cfg failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1251_acx_tid_cfg(struct wl1251 *wl, u8 queue, - enum wl1251_acx_channel_type type, - u8 tsid, enum wl1251_acx_ps_scheme ps_scheme, - enum wl1251_acx_ack_policy ack_policy) -{ - struct wl1251_acx_tid_cfg *acx; - int ret = 0; - - wl1251_debug(DEBUG_ACX, "acx tid cfg %d type %d tsid %d " - "ps_scheme %d ack_policy %d", queue, type, tsid, - ps_scheme, ack_policy); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->queue = queue; - acx->type = type; - acx->tsid = tsid; - acx->ps_scheme = ps_scheme; - acx->ack_policy = ack_policy; - - ret = wl1251_cmd_configure(wl, ACX_TID_CFG, acx, sizeof(*acx)); - if (ret < 0) { - wl1251_warning("acx tid cfg failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} diff --git a/trunk/drivers/net/wireless/wl12xx/wl1251_acx.h b/trunk/drivers/net/wireless/wl12xx/wl1251_acx.h index 26160c45784c..652371432cd8 100644 --- a/trunk/drivers/net/wireless/wl12xx/wl1251_acx.h +++ b/trunk/drivers/net/wireless/wl12xx/wl1251_acx.h @@ -1166,87 +1166,6 @@ struct wl1251_acx_wr_tbtt_and_dtim { u8 padding; } __attribute__ ((packed)); -struct wl1251_acx_ac_cfg { - struct acx_header header; - - /* - * Access Category - The TX queue's access category - * (refer to AccessCategory_enum) - */ - u8 ac; - - /* - * The contention window minimum size (in slots) for - * the access class. - */ - u8 cw_min; - - /* - * The contention window maximum size (in slots) for - * the access class. - */ - u16 cw_max; - - /* The AIF value (in slots) for the access class. */ - u8 aifsn; - - u8 reserved; - - /* The TX Op Limit (in microseconds) for the access class. */ - u16 txop_limit; -} __attribute__ ((packed)); - - -enum wl1251_acx_channel_type { - CHANNEL_TYPE_DCF = 0, - CHANNEL_TYPE_EDCF = 1, - CHANNEL_TYPE_HCCA = 2, -}; - -enum wl1251_acx_ps_scheme { - /* regular ps: simple sending of packets */ - WL1251_ACX_PS_SCHEME_LEGACY = 0, - - /* sending a packet triggers a unscheduled apsd downstream */ - WL1251_ACX_PS_SCHEME_UPSD_TRIGGER = 1, - - /* a pspoll packet will be sent before every data packet */ - WL1251_ACX_PS_SCHEME_LEGACY_PSPOLL = 2, - - /* scheduled apsd mode */ - WL1251_ACX_PS_SCHEME_SAPSD = 3, -}; - -enum wl1251_acx_ack_policy { - WL1251_ACX_ACK_POLICY_LEGACY = 0, - WL1251_ACX_ACK_POLICY_NO_ACK = 1, - WL1251_ACX_ACK_POLICY_BLOCK = 2, -}; - -struct wl1251_acx_tid_cfg { - struct acx_header header; - - /* tx queue id number (0-7) */ - u8 queue; - - /* channel access type for the queue, enum wl1251_acx_channel_type */ - u8 type; - - /* EDCA: ac index (0-3), HCCA: traffic stream id (8-15) */ - u8 tsid; - - /* ps scheme of the specified queue, enum wl1251_acx_ps_scheme */ - u8 ps_scheme; - - /* the tx queue ack policy, enum wl1251_acx_ack_policy */ - u8 ack_policy; - - u8 padding[3]; - - /* not supported */ - u32 apsdconf[2]; -} __attribute__ ((packed)); - /************************************************************************* Host Interrupt Register (WiLink -> Host) @@ -1403,11 +1322,5 @@ int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime); int wl1251_acx_rate_policies(struct wl1251 *wl); int wl1251_acx_mem_cfg(struct wl1251 *wl); int wl1251_acx_wr_tbtt_and_dtim(struct wl1251 *wl, u16 tbtt, u8 dtim); -int wl1251_acx_ac_cfg(struct wl1251 *wl, u8 ac, u8 cw_min, u16 cw_max, - u8 aifs, u16 txop); -int wl1251_acx_tid_cfg(struct wl1251 *wl, u8 queue, - enum wl1251_acx_channel_type type, - u8 tsid, enum wl1251_acx_ps_scheme ps_scheme, - enum wl1251_acx_ack_policy ack_policy); #endif /* __WL1251_ACX_H__ */ diff --git a/trunk/drivers/net/wireless/wl12xx/wl1251_cmd.c b/trunk/drivers/net/wireless/wl12xx/wl1251_cmd.c index 0320b478bb3f..770f260726bd 100644 --- a/trunk/drivers/net/wireless/wl12xx/wl1251_cmd.c +++ b/trunk/drivers/net/wireless/wl12xx/wl1251_cmd.c @@ -410,86 +410,3 @@ int wl1251_cmd_template_set(struct wl1251 *wl, u16 cmd_id, kfree(cmd); return ret; } - -int wl1251_cmd_scan(struct wl1251 *wl, u8 *ssid, size_t ssid_len, - struct ieee80211_channel *channels[], - unsigned int n_channels, unsigned int n_probes) -{ - struct wl1251_cmd_scan *cmd; - int i, ret = 0; - - wl1251_debug(DEBUG_CMD, "cmd scan"); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) - return -ENOMEM; - - cmd->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD); - cmd->params.rx_filter_options = cpu_to_le32(CFG_RX_PRSP_EN | - CFG_RX_MGMT_EN | - CFG_RX_BCN_EN); - cmd->params.scan_options = 0; - cmd->params.num_channels = n_channels; - cmd->params.num_probe_requests = n_probes; - cmd->params.tx_rate = cpu_to_le16(1 << 1); /* 2 Mbps */ - cmd->params.tid_trigger = 0; - - for (i = 0; i < n_channels; i++) { - cmd->channels[i].min_duration = - cpu_to_le32(WL1251_SCAN_MIN_DURATION); - cmd->channels[i].max_duration = - cpu_to_le32(WL1251_SCAN_MAX_DURATION); - memset(&cmd->channels[i].bssid_lsb, 0xff, 4); - memset(&cmd->channels[i].bssid_msb, 0xff, 2); - cmd->channels[i].early_termination = 0; - cmd->channels[i].tx_power_att = 0; - cmd->channels[i].channel = channels[i]->hw_value; - } - - cmd->params.ssid_len = ssid_len; - if (ssid) - memcpy(cmd->params.ssid, ssid, ssid_len); - - ret = wl1251_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd)); - if (ret < 0) { - wl1251_error("cmd scan failed: %d", ret); - goto out; - } - - wl1251_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd)); - - if (cmd->header.status != CMD_STATUS_SUCCESS) { - wl1251_error("cmd scan status wasn't success: %d", - cmd->header.status); - ret = -EIO; - goto out; - } - -out: - kfree(cmd); - return ret; -} - -int wl1251_cmd_trigger_scan_to(struct wl1251 *wl, u32 timeout) -{ - struct wl1251_cmd_trigger_scan_to *cmd; - int ret; - - wl1251_debug(DEBUG_CMD, "cmd trigger scan to"); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) - return -ENOMEM; - - cmd->timeout = timeout; - - ret = wl1251_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd)); - if (ret < 0) { - wl1251_error("cmd trigger scan to failed: %d", ret); - goto out; - } - -out: - kfree(cmd); - return ret; -} diff --git a/trunk/drivers/net/wireless/wl12xx/wl1251_cmd.h b/trunk/drivers/net/wireless/wl12xx/wl1251_cmd.h index 4ad67cae94d2..dff798ad0ef5 100644 --- a/trunk/drivers/net/wireless/wl12xx/wl1251_cmd.h +++ b/trunk/drivers/net/wireless/wl12xx/wl1251_cmd.h @@ -27,8 +27,6 @@ #include "wl1251.h" -#include - struct acx_header; int wl1251_cmd_send(struct wl1251 *wl, u16 type, void *buf, size_t buf_len); @@ -45,10 +43,6 @@ int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer, size_t len); int wl1251_cmd_template_set(struct wl1251 *wl, u16 cmd_id, void *buf, size_t buf_len); -int wl1251_cmd_scan(struct wl1251 *wl, u8 *ssid, size_t ssid_len, - struct ieee80211_channel *channels[], - unsigned int n_channels, unsigned int n_probes); -int wl1251_cmd_trigger_scan_to(struct wl1251 *wl, u32 timeout); /* unit ms */ #define WL1251_COMMAND_TIMEOUT 2000 @@ -169,12 +163,8 @@ struct cmd_read_write_memory { #define CMDMBOX_HEADER_LEN 4 #define CMDMBOX_INFO_ELEM_HEADER_LEN 4 -#define WL1251_SCAN_MIN_DURATION 30000 -#define WL1251_SCAN_MAX_DURATION 60000 - -#define WL1251_SCAN_NUM_PROBES 3 -struct wl1251_scan_parameters { +struct basic_scan_parameters { u32 rx_config_options; u32 rx_filter_options; @@ -199,11 +189,11 @@ struct wl1251_scan_parameters { u8 tid_trigger; u8 ssid_len; - u8 ssid[32]; + u32 ssid[8]; } __attribute__ ((packed)); -struct wl1251_scan_ch_parameters { +struct basic_scan_channel_parameters { u32 min_duration; /* in TU */ u32 max_duration; /* in TU */ u32 bssid_lsb; @@ -223,11 +213,11 @@ struct wl1251_scan_ch_parameters { /* SCAN parameters */ #define SCAN_MAX_NUM_OF_CHANNELS 16 -struct wl1251_cmd_scan { +struct cmd_scan { struct wl1251_cmd_header header; - struct wl1251_scan_parameters params; - struct wl1251_scan_ch_parameters channels[SCAN_MAX_NUM_OF_CHANNELS]; + struct basic_scan_parameters params; + struct basic_scan_channel_parameters channels[SCAN_MAX_NUM_OF_CHANNELS]; } __attribute__ ((packed)); enum { diff --git a/trunk/drivers/net/wireless/wl12xx/wl1251_debugfs.c b/trunk/drivers/net/wireless/wl12xx/wl1251_debugfs.c index 0ccba57fb9fb..a00723059f83 100644 --- a/trunk/drivers/net/wireless/wl12xx/wl1251_debugfs.c +++ b/trunk/drivers/net/wireless/wl12xx/wl1251_debugfs.c @@ -237,27 +237,6 @@ static const struct file_operations tx_queue_len_ops = { .open = wl1251_open_file_generic, }; -static ssize_t tx_queue_status_read(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - struct wl1251 *wl = file->private_data; - char buf[3], status; - int len; - - if (wl->tx_queue_stopped) - status = 's'; - else - status = 'r'; - - len = scnprintf(buf, sizeof(buf), "%c\n", status); - return simple_read_from_buffer(userbuf, count, ppos, buf, len); -} - -static const struct file_operations tx_queue_status_ops = { - .read = tx_queue_status_read, - .open = wl1251_open_file_generic, -}; - static void wl1251_debugfs_delete_files(struct wl1251 *wl) { DEBUGFS_FWSTATS_DEL(tx, internal_desc_overflow); @@ -352,7 +331,6 @@ static void wl1251_debugfs_delete_files(struct wl1251 *wl) DEBUGFS_FWSTATS_DEL(rxpipe, tx_xfr_host_int_trig_rx_data); DEBUGFS_DEL(tx_queue_len); - DEBUGFS_DEL(tx_queue_status); DEBUGFS_DEL(retry_count); DEBUGFS_DEL(excessive_retries); } @@ -453,7 +431,6 @@ static int wl1251_debugfs_add_files(struct wl1251 *wl) DEBUGFS_FWSTATS_ADD(rxpipe, tx_xfr_host_int_trig_rx_data); DEBUGFS_ADD(tx_queue_len, wl->debugfs.rootdir); - DEBUGFS_ADD(tx_queue_status, wl->debugfs.rootdir); DEBUGFS_ADD(retry_count, wl->debugfs.rootdir); DEBUGFS_ADD(excessive_retries, wl->debugfs.rootdir); diff --git a/trunk/drivers/net/wireless/wl12xx/wl1251_init.c b/trunk/drivers/net/wireless/wl12xx/wl1251_init.c index 5aad56ea7153..5cb573383eeb 100644 --- a/trunk/drivers/net/wireless/wl12xx/wl1251_init.c +++ b/trunk/drivers/net/wireless/wl12xx/wl1251_init.c @@ -294,11 +294,6 @@ static int wl1251_hw_init_tx_queue_config(struct wl1251 *wl) goto out; } - wl1251_acx_ac_cfg(wl, AC_BE, CWMIN_BE, CWMAX_BE, AIFS_DIFS, TXOP_BE); - wl1251_acx_ac_cfg(wl, AC_BK, CWMIN_BK, CWMAX_BK, AIFS_DIFS, TXOP_BK); - wl1251_acx_ac_cfg(wl, AC_VI, CWMIN_VI, CWMAX_VI, AIFS_DIFS, TXOP_VI); - wl1251_acx_ac_cfg(wl, AC_VO, CWMIN_VO, CWMAX_VO, AIFS_DIFS, TXOP_VO); - out: kfree(config); return ret; diff --git a/trunk/drivers/net/wireless/wl12xx/wl1251_init.h b/trunk/drivers/net/wireless/wl12xx/wl1251_init.h index 269cefb3e7d4..b3b25ec885ea 100644 --- a/trunk/drivers/net/wireless/wl12xx/wl1251_init.h +++ b/trunk/drivers/net/wireless/wl12xx/wl1251_init.h @@ -26,53 +26,6 @@ #include "wl1251.h" -enum { - /* best effort/legacy */ - AC_BE = 0, - - /* background */ - AC_BK = 1, - - /* video */ - AC_VI = 2, - - /* voice */ - AC_VO = 3, - - /* broadcast dummy access category */ - AC_BCAST = 4, - - NUM_ACCESS_CATEGORIES = 4 -}; - -/* following are defult values for the IE fields*/ -#define CWMIN_BK 15 -#define CWMIN_BE 15 -#define CWMIN_VI 7 -#define CWMIN_VO 3 -#define CWMAX_BK 1023 -#define CWMAX_BE 63 -#define CWMAX_VI 15 -#define CWMAX_VO 7 - -/* slot number setting to start transmission at PIFS interval */ -#define AIFS_PIFS 1 - -/* - * slot number setting to start transmission at DIFS interval - normal DCF - * access - */ -#define AIFS_DIFS 2 - -#define AIFSN_BK 7 -#define AIFSN_BE 3 -#define AIFSN_VI AIFS_PIFS -#define AIFSN_VO AIFS_PIFS -#define TXOP_BK 0 -#define TXOP_BE 0 -#define TXOP_VI 3008 -#define TXOP_VO 1504 - int wl1251_hw_init_hwenc_config(struct wl1251 *wl); int wl1251_hw_init_templates_config(struct wl1251 *wl); int wl1251_hw_init_rx_config(struct wl1251 *wl, u32 config, u32 filter); diff --git a/trunk/drivers/net/wireless/wl12xx/wl1251_main.c b/trunk/drivers/net/wireless/wl12xx/wl1251_main.c index 24ae6a360ac8..2f50a256efa5 100644 --- a/trunk/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/trunk/drivers/net/wireless/wl12xx/wl1251_main.c @@ -395,7 +395,6 @@ static int wl1251_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) * the queue here, otherwise the queue will get too long. */ if (skb_queue_len(&wl->tx_queue) >= WL1251_TX_QUEUE_MAX_LENGTH) { - wl1251_debug(DEBUG_TX, "op_tx: tx_queue full, stop queues"); ieee80211_stop_queues(wl->hw); /* @@ -511,13 +510,13 @@ static void wl1251_op_stop(struct ieee80211_hw *hw) } static int wl1251_op_add_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) + struct ieee80211_if_init_conf *conf) { struct wl1251 *wl = hw->priv; int ret = 0; wl1251_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", - vif->type, vif->addr); + conf->type, conf->mac_addr); mutex_lock(&wl->mutex); if (wl->vif) { @@ -525,9 +524,9 @@ static int wl1251_op_add_interface(struct ieee80211_hw *hw, goto out; } - wl->vif = vif; + wl->vif = conf->vif; - switch (vif->type) { + switch (conf->type) { case NL80211_IFTYPE_STATION: wl->bss_type = BSS_TYPE_STA_BSS; break; @@ -539,8 +538,8 @@ static int wl1251_op_add_interface(struct ieee80211_hw *hw, goto out; } - if (memcmp(wl->mac_addr, vif->addr, ETH_ALEN)) { - memcpy(wl->mac_addr, vif->addr, ETH_ALEN); + if (memcmp(wl->mac_addr, conf->mac_addr, ETH_ALEN)) { + memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN); SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); ret = wl1251_acx_station_id(wl); if (ret < 0) @@ -553,7 +552,7 @@ static int wl1251_op_add_interface(struct ieee80211_hw *hw, } static void wl1251_op_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) + struct ieee80211_if_init_conf *conf) { struct wl1251 *wl = hw->priv; @@ -563,25 +562,43 @@ static void wl1251_op_remove_interface(struct ieee80211_hw *hw, mutex_unlock(&wl->mutex); } -static int wl1251_build_qos_null_data(struct wl1251 *wl) +static int wl1251_build_null_data(struct wl1251 *wl) { - struct ieee80211_qos_hdr template; + struct wl12xx_null_data_template template; - memset(&template, 0, sizeof(template)); + if (!is_zero_ether_addr(wl->bssid)) { + memcpy(template.header.da, wl->bssid, ETH_ALEN); + memcpy(template.header.bssid, wl->bssid, ETH_ALEN); + } else { + memset(template.header.da, 0xff, ETH_ALEN); + memset(template.header.bssid, 0xff, ETH_ALEN); + } + + memcpy(template.header.sa, wl->mac_addr, ETH_ALEN); + template.header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA | + IEEE80211_STYPE_NULLFUNC | + IEEE80211_FCTL_TODS); + + return wl1251_cmd_template_set(wl, CMD_NULL_DATA, &template, + sizeof(template)); + +} + +static int wl1251_build_ps_poll(struct wl1251 *wl, u16 aid) +{ + struct wl12xx_ps_poll_template template; - memcpy(template.addr1, wl->bssid, ETH_ALEN); - memcpy(template.addr2, wl->mac_addr, ETH_ALEN); - memcpy(template.addr3, wl->bssid, ETH_ALEN); + memcpy(template.bssid, wl->bssid, ETH_ALEN); + memcpy(template.ta, wl->mac_addr, ETH_ALEN); - template.frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | - IEEE80211_STYPE_QOS_NULLFUNC | - IEEE80211_FCTL_TODS); + /* aid in PS-Poll has its two MSBs each set to 1 */ + template.aid = cpu_to_le16(1 << 15 | 1 << 14 | aid); - /* FIXME: not sure what priority to use here */ - template.qos_ctrl = cpu_to_le16(0); + template.fc = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL); - return wl1251_cmd_template_set(wl, CMD_QOS_NULL_DATA, &template, + return wl1251_cmd_template_set(wl, CMD_PS_POLL, &template, sizeof(template)); + } static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) @@ -617,34 +634,26 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) wl->psm_requested = true; - wl->dtim_period = conf->ps_dtim_period; - - ret = wl1251_acx_wr_tbtt_and_dtim(wl, wl->beacon_int, - wl->dtim_period); - /* - * mac80211 enables PSM only if we're already associated. + * We enter PSM only if we're already associated. + * If we're not, we'll enter it when joining an SSID, + * through the bss_info_changed() hook. */ ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE); - if (ret < 0) - goto out_sleep; } else if (!(conf->flags & IEEE80211_CONF_PS) && wl->psm_requested) { wl1251_debug(DEBUG_PSM, "psm disabled"); wl->psm_requested = false; - if (wl->psm) { + if (wl->psm) ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE); - if (ret < 0) - goto out_sleep; - } } if (conf->power_level != wl->power_level) { ret = wl1251_acx_tx_power(wl, conf->power_level); if (ret < 0) - goto out_sleep; + goto out; wl->power_level = conf->power_level; } @@ -855,61 +864,199 @@ static int wl1251_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return ret; } -static int wl1251_op_hw_scan(struct ieee80211_hw *hw, - struct cfg80211_scan_request *req) +static int wl1251_build_basic_rates(char *rates) { - struct wl1251 *wl = hw->priv; - struct sk_buff *skb; - size_t ssid_len = 0; - u8 *ssid = NULL; - int ret; + u8 index = 0; - wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan"); + rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB; + rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB; + rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB; + rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB; - if (req->n_ssids) { - ssid = req->ssids[0].ssid; - ssid_len = req->ssids[0].ssid_len; + return index; +} + +static int wl1251_build_extended_rates(char *rates) +{ + u8 index = 0; + + rates[index++] = IEEE80211_OFDM_RATE_6MB; + rates[index++] = IEEE80211_OFDM_RATE_9MB; + rates[index++] = IEEE80211_OFDM_RATE_12MB; + rates[index++] = IEEE80211_OFDM_RATE_18MB; + rates[index++] = IEEE80211_OFDM_RATE_24MB; + rates[index++] = IEEE80211_OFDM_RATE_36MB; + rates[index++] = IEEE80211_OFDM_RATE_48MB; + rates[index++] = IEEE80211_OFDM_RATE_54MB; + + return index; +} + + +static int wl1251_build_probe_req(struct wl1251 *wl, u8 *ssid, size_t ssid_len) +{ + struct wl12xx_probe_req_template template; + struct wl12xx_ie_rates *rates; + char *ptr; + u16 size; + + ptr = (char *)&template; + size = sizeof(struct ieee80211_header); + + memset(template.header.da, 0xff, ETH_ALEN); + memset(template.header.bssid, 0xff, ETH_ALEN); + memcpy(template.header.sa, wl->mac_addr, ETH_ALEN); + template.header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); + + /* IEs */ + /* SSID */ + template.ssid.header.id = WLAN_EID_SSID; + template.ssid.header.len = ssid_len; + if (ssid_len && ssid) + memcpy(template.ssid.ssid, ssid, ssid_len); + size += sizeof(struct wl12xx_ie_header) + ssid_len; + ptr += size; + + /* Basic Rates */ + rates = (struct wl12xx_ie_rates *)ptr; + rates->header.id = WLAN_EID_SUPP_RATES; + rates->header.len = wl1251_build_basic_rates(rates->rates); + size += sizeof(struct wl12xx_ie_header) + rates->header.len; + ptr += sizeof(struct wl12xx_ie_header) + rates->header.len; + + /* Extended rates */ + rates = (struct wl12xx_ie_rates *)ptr; + rates->header.id = WLAN_EID_EXT_SUPP_RATES; + rates->header.len = wl1251_build_extended_rates(rates->rates); + size += sizeof(struct wl12xx_ie_header) + rates->header.len; + + wl1251_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size); + + return wl1251_cmd_template_set(wl, CMD_PROBE_REQ, &template, + size); +} + +static int wl1251_hw_scan(struct wl1251 *wl, u8 *ssid, size_t len, + u8 active_scan, u8 high_prio, u8 num_channels, + u8 probe_requests) +{ + struct wl1251_cmd_trigger_scan_to *trigger = NULL; + struct cmd_scan *params = NULL; + int i, ret; + u16 scan_options = 0; + + if (wl->scanning) + return -EINVAL; + + params = kzalloc(sizeof(*params), GFP_KERNEL); + if (!params) + return -ENOMEM; + + params->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD); + params->params.rx_filter_options = + cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN); + + /* High priority scan */ + if (!active_scan) + scan_options |= SCAN_PASSIVE; + if (high_prio) + scan_options |= SCAN_PRIORITY_HIGH; + params->params.scan_options = scan_options; + + params->params.num_channels = num_channels; + params->params.num_probe_requests = probe_requests; + params->params.tx_rate = cpu_to_le16(1 << 1); /* 2 Mbps */ + params->params.tid_trigger = 0; + + for (i = 0; i < num_channels; i++) { + params->channels[i].min_duration = cpu_to_le32(30000); + params->channels[i].max_duration = cpu_to_le32(60000); + memset(¶ms->channels[i].bssid_lsb, 0xff, 4); + memset(¶ms->channels[i].bssid_msb, 0xff, 2); + params->channels[i].early_termination = 0; + params->channels[i].tx_power_att = 0; + params->channels[i].channel = i + 1; + memset(params->channels[i].pad, 0, 3); } - mutex_lock(&wl->mutex); + for (i = num_channels; i < SCAN_MAX_NUM_OF_CHANNELS; i++) + memset(¶ms->channels[i], 0, + sizeof(struct basic_scan_channel_parameters)); - if (wl->scanning) { - wl1251_debug(DEBUG_SCAN, "scan already in progress"); - ret = -EINVAL; + if (len && ssid) { + params->params.ssid_len = len; + memcpy(params->params.ssid, ssid, len); + } else { + params->params.ssid_len = 0; + memset(params->params.ssid, 0, 32); + } + + ret = wl1251_build_probe_req(wl, ssid, len); + if (ret < 0) { + wl1251_error("PROBE request template failed"); goto out; } - ret = wl1251_ps_elp_wakeup(wl); - if (ret < 0) + trigger = kzalloc(sizeof(*trigger), GFP_KERNEL); + if (!trigger) goto out; - skb = ieee80211_probereq_get(wl->hw, wl->vif, ssid, ssid_len, - req->ie, req->ie_len); - if (!skb) { - ret = -ENOMEM; + trigger->timeout = 0; + + ret = wl1251_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger, + sizeof(*trigger)); + if (ret < 0) { + wl1251_error("trigger scan to failed for hw scan"); goto out; } - ret = wl1251_cmd_template_set(wl, CMD_PROBE_REQ, skb->data, - skb->len); - dev_kfree_skb(skb); - if (ret < 0) - goto out_sleep; + wl1251_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params)); + + wl->scanning = true; - ret = wl1251_cmd_trigger_scan_to(wl, 0); + ret = wl1251_cmd_send(wl, CMD_SCAN, params, sizeof(*params)); if (ret < 0) - goto out_sleep; + wl1251_error("SCAN failed"); - wl->scanning = true; + wl1251_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params)); - ret = wl1251_cmd_scan(wl, ssid, ssid_len, req->channels, - req->n_channels, WL1251_SCAN_NUM_PROBES); - if (ret < 0) { + if (params->header.status != CMD_STATUS_SUCCESS) { + wl1251_error("TEST command answer error: %d", + params->header.status); wl->scanning = false; - goto out_sleep; + ret = -EIO; + goto out; } -out_sleep: +out: + kfree(params); + return ret; + +} + +static int wl1251_op_hw_scan(struct ieee80211_hw *hw, + struct cfg80211_scan_request *req) +{ + struct wl1251 *wl = hw->priv; + int ret; + u8 *ssid = NULL; + size_t ssid_len = 0; + + wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan"); + + if (req->n_ssids) { + ssid = req->ssids[0].ssid; + ssid_len = req->ssids[0].ssid_len; + } + + mutex_lock(&wl->mutex); + + ret = wl1251_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + ret = wl1251_hw_scan(hw->priv, ssid, ssid_len, 1, 0, 13, 3); + wl1251_ps_elp_sleep(wl); out: @@ -946,8 +1093,9 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_bss_conf *bss_conf, u32 changed) { + enum wl1251_cmd_ps_mode mode; struct wl1251 *wl = hw->priv; - struct sk_buff *beacon, *skb; + struct sk_buff *beacon; int ret; wl1251_debug(DEBUG_MAC80211, "mac80211 bss info changed"); @@ -961,17 +1109,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_BSSID) { memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN); - skb = ieee80211_nullfunc_get(wl->hw, wl->vif); - if (!skb) - goto out_sleep; - - ret = wl1251_cmd_template_set(wl, CMD_NULL_DATA, - skb->data, skb->len); - dev_kfree_skb(skb); - if (ret < 0) - goto out_sleep; - - ret = wl1251_build_qos_null_data(wl); + ret = wl1251_build_null_data(wl); if (ret < 0) goto out; @@ -986,21 +1124,27 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_ASSOC) { if (bss_conf->assoc) { wl->beacon_int = bss_conf->beacon_int; + wl->dtim_period = bss_conf->dtim_period; - skb = ieee80211_pspoll_get(wl->hw, wl->vif); - if (!skb) - goto out_sleep; + ret = wl1251_acx_wr_tbtt_and_dtim(wl, wl->beacon_int, + wl->dtim_period); + wl->aid = bss_conf->aid; - ret = wl1251_cmd_template_set(wl, CMD_PS_POLL, - skb->data, - skb->len); - dev_kfree_skb(skb); + ret = wl1251_build_ps_poll(wl, wl->aid); if (ret < 0) goto out_sleep; - ret = wl1251_acx_aid(wl, bss_conf->aid); + ret = wl1251_acx_aid(wl, wl->aid); if (ret < 0) goto out_sleep; + + /* If we want to go in PSM but we're not there yet */ + if (wl->psm_requested && !wl->psm) { + mode = STATION_POWER_SAVE_MODE; + ret = wl1251_ps_set_mode(wl, mode); + if (ret < 0) + goto out_sleep; + } } else { /* use defaults when not associated */ wl->beacon_int = WL1251_DEFAULT_BEACON_INT; @@ -1032,7 +1176,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, ret = wl1251_acx_cts_protect(wl, CTSPROTECT_DISABLE); if (ret < 0) { wl1251_warning("Set ctsprotect failed %d", ret); - goto out_sleep; + goto out; } } @@ -1043,7 +1187,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, if (ret < 0) { dev_kfree_skb(beacon); - goto out_sleep; + goto out; } ret = wl1251_cmd_template_set(wl, CMD_PROBE_RESP, beacon->data, @@ -1052,13 +1196,13 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, dev_kfree_skb(beacon); if (ret < 0) - goto out_sleep; + goto out; ret = wl1251_join(wl, wl->bss_type, wl->beacon_int, wl->channel, wl->dtim_period); if (ret < 0) - goto out_sleep; + goto out; } out_sleep: @@ -1129,49 +1273,6 @@ static struct ieee80211_channel wl1251_channels[] = { { .hw_value = 13, .center_freq = 2472}, }; -static int wl1251_op_conf_tx(struct ieee80211_hw *hw, u16 queue, - const struct ieee80211_tx_queue_params *params) -{ - enum wl1251_acx_ps_scheme ps_scheme; - struct wl1251 *wl = hw->priv; - int ret; - - mutex_lock(&wl->mutex); - - wl1251_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue); - - ret = wl1251_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - /* mac80211 uses units of 32 usec */ - ret = wl1251_acx_ac_cfg(wl, wl1251_tx_get_queue(queue), - params->cw_min, params->cw_max, - params->aifs, params->txop * 32); - if (ret < 0) - goto out_sleep; - - if (params->uapsd) - ps_scheme = WL1251_ACX_PS_SCHEME_UPSD_TRIGGER; - else - ps_scheme = WL1251_ACX_PS_SCHEME_LEGACY; - - ret = wl1251_acx_tid_cfg(wl, wl1251_tx_get_queue(queue), - CHANNEL_TYPE_EDCF, - wl1251_tx_get_queue(queue), ps_scheme, - WL1251_ACX_ACK_POLICY_LEGACY); - if (ret < 0) - goto out_sleep; - -out_sleep: - wl1251_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); - - return ret; -} - /* can't be const, mac80211 writes to this */ static struct ieee80211_supported_band wl1251_band_2ghz = { .channels = wl1251_channels, @@ -1192,7 +1293,6 @@ static const struct ieee80211_ops wl1251_ops = { .hw_scan = wl1251_op_hw_scan, .bss_info_changed = wl1251_op_bss_info_changed, .set_rts_threshold = wl1251_op_set_rts_threshold, - .conf_tx = wl1251_op_conf_tx, }; static int wl1251_register_hw(struct wl1251 *wl) @@ -1232,15 +1332,12 @@ int wl1251_init_ieee80211(struct wl1251 *wl) wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM | IEEE80211_HW_SUPPORTS_PS | - IEEE80211_HW_BEACON_FILTER | - IEEE80211_HW_SUPPORTS_UAPSD; + IEEE80211_HW_BEACON_FILTER; wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); wl->hw->wiphy->max_scan_ssids = 1; wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1251_band_2ghz; - wl->hw->queues = 4; - ret = wl1251_register_hw(wl); if (ret) goto out; diff --git a/trunk/drivers/net/wireless/wl12xx/wl1251_ps.c b/trunk/drivers/net/wireless/wl12xx/wl1251_ps.c index 851dfb65e474..9931b197ff77 100644 --- a/trunk/drivers/net/wireless/wl12xx/wl1251_ps.c +++ b/trunk/drivers/net/wireless/wl12xx/wl1251_ps.c @@ -26,8 +26,7 @@ #include "wl1251_cmd.h" #include "wl1251_io.h" -/* in ms */ -#define WL1251_WAKEUP_TIMEOUT 100 +#define WL1251_WAKEUP_TIMEOUT 2000 void wl1251_elp_work(struct work_struct *work) { @@ -68,7 +67,7 @@ void wl1251_ps_elp_sleep(struct wl1251 *wl) int wl1251_ps_elp_wakeup(struct wl1251 *wl) { - unsigned long timeout, start; + unsigned long timeout; u32 elp_reg; if (!wl->elp) @@ -76,7 +75,6 @@ int wl1251_ps_elp_wakeup(struct wl1251 *wl) wl1251_debug(DEBUG_PSM, "waking up chip from elp"); - start = jiffies; timeout = jiffies + msecs_to_jiffies(WL1251_WAKEUP_TIMEOUT); wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP); @@ -97,7 +95,8 @@ int wl1251_ps_elp_wakeup(struct wl1251 *wl) } wl1251_debug(DEBUG_PSM, "wakeup time: %u ms", - jiffies_to_msecs(jiffies - start)); + jiffies_to_msecs(jiffies) - + (jiffies_to_msecs(timeout) - WL1251_WAKEUP_TIMEOUT)); wl->elp = false; diff --git a/trunk/drivers/net/wireless/wl12xx/wl1251_rx.c b/trunk/drivers/net/wireless/wl12xx/wl1251_rx.c index b56732226cc0..f84cc89cbffc 100644 --- a/trunk/drivers/net/wireless/wl12xx/wl1251_rx.c +++ b/trunk/drivers/net/wireless/wl12xx/wl1251_rx.c @@ -126,7 +126,7 @@ static void wl1251_rx_body(struct wl1251 *wl, if (wl->rx_current_buffer) rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size; - skb = __dev_alloc_skb(length, GFP_KERNEL); + skb = dev_alloc_skb(length); if (!skb) { wl1251_error("Couldn't allocate RX frame"); return; diff --git a/trunk/drivers/net/wireless/wl12xx/wl1251_tx.c b/trunk/drivers/net/wireless/wl12xx/wl1251_tx.c index c8223185efd2..f85970615849 100644 --- a/trunk/drivers/net/wireless/wl12xx/wl1251_tx.c +++ b/trunk/drivers/net/wireless/wl12xx/wl1251_tx.c @@ -167,7 +167,8 @@ static int wl1251_tx_fill_hdr(struct wl1251 *wl, struct sk_buff *skb, tx_hdr->expiry_time = cpu_to_le32(1 << 16); tx_hdr->id = id; - tx_hdr->xmit_queue = wl1251_tx_get_queue(skb_get_queue_mapping(skb)); + /* FIXME: how to get the correct queue id? */ + tx_hdr->xmit_queue = 0; wl1251_tx_control(tx_hdr, control, fc); wl1251_tx_frag_block_num(tx_hdr); @@ -219,7 +220,6 @@ static int wl1251_tx_send_packet(struct wl1251 *wl, struct sk_buff *skb, /* align the buffer on a 4-byte boundary */ skb_reserve(skb, offset); memmove(skb->data, src, skb->len); - tx_hdr = (struct tx_double_buffer_desc *) skb->data; } else { wl1251_info("No handler, fixme!"); return -EINVAL; @@ -237,9 +237,8 @@ static int wl1251_tx_send_packet(struct wl1251 *wl, struct sk_buff *skb, wl1251_mem_write(wl, addr, skb->data, len); - wl1251_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x " - "queue %d", tx_hdr->id, skb, tx_hdr->length, - tx_hdr->rate, tx_hdr->xmit_queue); + wl1251_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x", + tx_hdr->id, skb, tx_hdr->length, tx_hdr->rate); return 0; } diff --git a/trunk/drivers/net/wireless/wl12xx/wl1251_tx.h b/trunk/drivers/net/wireless/wl12xx/wl1251_tx.h index 55856c6bb97a..7c1c1665c810 100644 --- a/trunk/drivers/net/wireless/wl12xx/wl1251_tx.h +++ b/trunk/drivers/net/wireless/wl12xx/wl1251_tx.h @@ -26,7 +26,6 @@ #define __WL1251_TX_H__ #include -#include "wl1251_acx.h" /* * @@ -210,22 +209,6 @@ struct tx_result { u8 done_2; } __attribute__ ((packed)); -static inline int wl1251_tx_get_queue(int queue) -{ - switch (queue) { - case 0: - return QOS_AC_VO; - case 1: - return QOS_AC_VI; - case 2: - return QOS_AC_BE; - case 3: - return QOS_AC_BK; - default: - return QOS_AC_BE; - } -} - void wl1251_tx_work(struct work_struct *work); void wl1251_tx_complete(struct wl1251 *wl); void wl1251_tx_flush(struct wl1251 *wl); diff --git a/trunk/drivers/net/wireless/wl12xx/wl1271.h b/trunk/drivers/net/wireless/wl12xx/wl1271.h index 97ea5096bc8c..94359b1a861f 100644 --- a/trunk/drivers/net/wireless/wl12xx/wl1271.h +++ b/trunk/drivers/net/wireless/wl12xx/wl1271.h @@ -43,7 +43,7 @@ enum { DEBUG_SPI = BIT(1), DEBUG_BOOT = BIT(2), DEBUG_MAILBOX = BIT(3), - DEBUG_TESTMODE = BIT(4), + DEBUG_NETLINK = BIT(4), DEBUG_EVENT = BIT(5), DEBUG_TX = BIT(6), DEBUG_RX = BIT(7), @@ -107,36 +107,11 @@ enum { CFG_RX_CTL_EN | CFG_RX_BCN_EN | \ CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN) +#define WL1271_DEFAULT_BASIC_RATE_SET (CONF_TX_RATE_MASK_ALL) + #define WL1271_FW_NAME "wl1271-fw.bin" #define WL1271_NVS_NAME "wl1271-nvs.bin" -/* NVS data structure */ -#define WL1271_NVS_SECTION_SIZE 468 - -#define WL1271_NVS_GENERAL_PARAMS_SIZE 57 -#define WL1271_NVS_GENERAL_PARAMS_SIZE_PADDED \ - (WL1271_NVS_GENERAL_PARAMS_SIZE + 1) -#define WL1271_NVS_STAT_RADIO_PARAMS_SIZE 17 -#define WL1271_NVS_STAT_RADIO_PARAMS_SIZE_PADDED \ - (WL1271_NVS_STAT_RADIO_PARAMS_SIZE + 1) -#define WL1271_NVS_DYN_RADIO_PARAMS_SIZE 65 -#define WL1271_NVS_DYN_RADIO_PARAMS_SIZE_PADDED \ - (WL1271_NVS_DYN_RADIO_PARAMS_SIZE + 1) -#define WL1271_NVS_FEM_COUNT 2 -#define WL1271_NVS_INI_SPARE_SIZE 124 - -struct wl1271_nvs_file { - /* NVS section */ - u8 nvs[WL1271_NVS_SECTION_SIZE]; - - /* INI section */ - u8 general_params[WL1271_NVS_GENERAL_PARAMS_SIZE_PADDED]; - u8 stat_radio_params[WL1271_NVS_STAT_RADIO_PARAMS_SIZE_PADDED]; - u8 dyn_radio_params[WL1271_NVS_FEM_COUNT] - [WL1271_NVS_DYN_RADIO_PARAMS_SIZE_PADDED]; - u8 ini_spare[WL1271_NVS_INI_SPARE_SIZE]; -} __attribute__ ((packed)); - /* * Enable/disable 802.11a support for WL1273 */ @@ -301,7 +276,6 @@ struct wl1271_debugfs { struct dentry *retry_count; struct dentry *excessive_retries; - struct dentry *gpio_power; }; #define NUM_TX_QUEUES 4 @@ -348,17 +322,6 @@ struct wl1271 { enum wl1271_state state; struct mutex mutex; -#define WL1271_FLAG_STA_RATES_CHANGED (0) -#define WL1271_FLAG_STA_ASSOCIATED (1) -#define WL1271_FLAG_JOINED (2) -#define WL1271_FLAG_GPIO_POWER (3) -#define WL1271_FLAG_TX_QUEUE_STOPPED (4) -#define WL1271_FLAG_SCANNING (5) -#define WL1271_FLAG_IN_ELP (6) -#define WL1271_FLAG_PSM (7) -#define WL1271_FLAG_PSM_REQUESTED (8) - unsigned long flags; - struct wl1271_partition_set part; struct wl1271_chip chip; @@ -368,7 +331,8 @@ struct wl1271 { u8 *fw; size_t fw_len; - struct wl1271_nvs_file *nvs; + u8 *nvs; + size_t nvs_len; u8 bssid[ETH_ALEN]; u8 mac_addr[ETH_ALEN]; @@ -395,6 +359,7 @@ struct wl1271 { /* Frames scheduled for transmission, not handled yet */ struct sk_buff_head tx_queue; + bool tx_queue_stopped; struct work_struct tx_work; @@ -422,15 +387,14 @@ struct wl1271 { u32 mbox_ptr[2]; /* Are we currently scanning */ + bool scanning; struct wl1271_scan scan; /* Our association ID */ u16 aid; /* currently configured rate set */ - u32 sta_rate_set; u32 basic_rate_set; - u32 rate_set; /* The current band */ enum ieee80211_band band; @@ -441,9 +405,18 @@ struct wl1271 { unsigned int rx_config; unsigned int rx_filter; + /* is firmware in elp mode */ + bool elp; + struct completion *elp_compl; struct delayed_work elp_work; + /* we can be in psm, but not in elp, we have to differentiate */ + bool psm; + + /* PSM mode requested */ + bool psm_requested; + /* retry counter for PSM entries */ u8 psm_entry_retry; @@ -462,6 +435,9 @@ struct wl1271 { struct ieee80211_vif *vif; + /* Used for a workaround to send disconnect before rejoining */ + bool joined; + /* Current chipset configuration */ struct conf_drv_settings conf; @@ -479,14 +455,11 @@ int wl1271_plt_stop(struct wl1271 *wl); #define WL1271_TX_QUEUE_MAX_LENGTH 20 -/* WL1271 needs a 200ms sleep after power on, and a 20ms sleep before power - on in case is has been shut down shortly before */ -#define WL1271_PRE_POWER_ON_SLEEP 20 /* in miliseconds */ +/* WL1271 needs a 200ms sleep after power on */ #define WL1271_POWER_ON_SLEEP 200 /* in miliseconds */ static inline bool wl1271_11a_enabled(void) { - /* FIXME: this could be determined based on the NVS-INI file */ #ifdef WL1271_80211A_ENABLED return true; #else diff --git a/trunk/drivers/net/wireless/wl12xx/wl1271_acx.c b/trunk/drivers/net/wireless/wl12xx/wl1271_acx.c index 60f10dce4800..5cc89bbdac7a 100644 --- a/trunk/drivers/net/wireless/wl12xx/wl1271_acx.c +++ b/trunk/drivers/net/wireless/wl12xx/wl1271_acx.c @@ -390,35 +390,6 @@ int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold) return ret; } -int wl1271_acx_dco_itrim_params(struct wl1271 *wl) -{ - struct acx_dco_itrim_params *dco; - struct conf_itrim_settings *c = &wl->conf.itrim; - int ret; - - wl1271_debug(DEBUG_ACX, "acx dco itrim parameters"); - - dco = kzalloc(sizeof(*dco), GFP_KERNEL); - if (!dco) { - ret = -ENOMEM; - goto out; - } - - dco->enable = c->enable; - dco->timeout = cpu_to_le32(c->timeout); - - ret = wl1271_cmd_configure(wl, ACX_SET_DCO_ITRIM_PARAMS, - dco, sizeof(*dco)); - if (ret < 0) { - wl1271_warning("failed to set dco itrim parameters: %d", ret); - goto out; - } - -out: - kfree(dco); - return ret; -} - int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter) { struct acx_beacon_filter_option *beacon_filter = NULL; @@ -787,11 +758,10 @@ int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats) return 0; } -int wl1271_acx_rate_policies(struct wl1271 *wl) +int wl1271_acx_rate_policies(struct wl1271 *wl, u32 enabled_rates) { struct acx_rate_policy *acx; struct conf_tx_rate_class *c = &wl->conf.tx.rc_conf; - int idx = 0; int ret = 0; wl1271_debug(DEBUG_ACX, "acx rate policies"); @@ -803,21 +773,12 @@ int wl1271_acx_rate_policies(struct wl1271 *wl) goto out; } - /* configure one basic rate class */ - idx = ACX_TX_BASIC_RATE; - acx->rate_class[idx].enabled_rates = cpu_to_le32(wl->basic_rate_set); - acx->rate_class[idx].short_retry_limit = c->short_retry_limit; - acx->rate_class[idx].long_retry_limit = c->long_retry_limit; - acx->rate_class[idx].aflags = c->aflags; - - /* configure one AP supported rate class */ - idx = ACX_TX_AP_FULL_RATE; - acx->rate_class[idx].enabled_rates = cpu_to_le32(wl->rate_set); - acx->rate_class[idx].short_retry_limit = c->short_retry_limit; - acx->rate_class[idx].long_retry_limit = c->long_retry_limit; - acx->rate_class[idx].aflags = c->aflags; - - acx->rate_class_cnt = cpu_to_le32(ACX_TX_RATE_POLICY_CNT); + /* configure one default (one-size-fits-all) rate class */ + acx->rate_class_cnt = cpu_to_le32(1); + acx->rate_class[0].enabled_rates = cpu_to_le32(enabled_rates); + acx->rate_class[0].short_retry_limit = c->short_retry_limit; + acx->rate_class[0].long_retry_limit = c->long_retry_limit; + acx->rate_class[0].aflags = c->aflags; ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); if (ret < 0) { @@ -830,14 +791,12 @@ int wl1271_acx_rate_policies(struct wl1271 *wl) return ret; } -int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max, - u8 aifsn, u16 txop) +int wl1271_acx_ac_cfg(struct wl1271 *wl) { struct acx_ac_cfg *acx; - int ret = 0; + int i, ret = 0; - wl1271_debug(DEBUG_ACX, "acx ac cfg %d cw_ming %d cw_max %d " - "aifs %d txop %d", ac, cw_min, cw_max, aifsn, txop); + wl1271_debug(DEBUG_ACX, "acx access category config"); acx = kzalloc(sizeof(*acx), GFP_KERNEL); @@ -846,16 +805,21 @@ int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max, goto out; } - acx->ac = ac; - acx->cw_min = cw_min; - acx->cw_max = cpu_to_le16(cw_max); - acx->aifsn = aifsn; - acx->tx_op_limit = cpu_to_le16(txop); + for (i = 0; i < wl->conf.tx.ac_conf_count; i++) { + struct conf_tx_ac_category *c = &(wl->conf.tx.ac_conf[i]); + acx->ac = c->ac; + acx->cw_min = c->cw_min; + acx->cw_max = cpu_to_le16(c->cw_max); + acx->aifsn = c->aifsn; + acx->reserved = 0; + acx->tx_op_limit = cpu_to_le16(c->tx_op_limit); - ret = wl1271_cmd_configure(wl, ACX_AC_CFG, acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("acx ac cfg failed: %d", ret); - goto out; + ret = wl1271_cmd_configure(wl, ACX_AC_CFG, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("Setting of access category " + "config: %d", ret); + goto out; + } } out: @@ -863,12 +827,10 @@ int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max, return ret; } -int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type, - u8 tsid, u8 ps_scheme, u8 ack_policy, - u32 apsd_conf0, u32 apsd_conf1) +int wl1271_acx_tid_cfg(struct wl1271 *wl) { struct acx_tid_config *acx; - int ret = 0; + int i, ret = 0; wl1271_debug(DEBUG_ACX, "acx tid config"); @@ -879,18 +841,21 @@ int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type, goto out; } - acx->queue_id = queue_id; - acx->channel_type = channel_type; - acx->tsid = tsid; - acx->ps_scheme = ps_scheme; - acx->ack_policy = ack_policy; - acx->apsd_conf[0] = cpu_to_le32(apsd_conf0); - acx->apsd_conf[1] = cpu_to_le32(apsd_conf1); + for (i = 0; i < wl->conf.tx.tid_conf_count; i++) { + struct conf_tx_tid *c = &(wl->conf.tx.tid_conf[i]); + acx->queue_id = c->queue_id; + acx->channel_type = c->channel_type; + acx->tsid = c->tsid; + acx->ps_scheme = c->ps_scheme; + acx->ack_policy = c->ack_policy; + acx->apsd_conf[0] = cpu_to_le32(c->apsd_conf[0]); + acx->apsd_conf[1] = cpu_to_le32(c->apsd_conf[1]); - ret = wl1271_cmd_configure(wl, ACX_TID_CFG, acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("Setting of tid config failed: %d", ret); - goto out; + ret = wl1271_cmd_configure(wl, ACX_TID_CFG, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("Setting of tid config failed: %d", ret); + goto out; + } } out: @@ -1047,6 +1012,59 @@ int wl1271_acx_init_rx_interrupt(struct wl1271 *wl) return ret; } +int wl1271_acx_smart_reflex(struct wl1271 *wl) +{ + struct acx_smart_reflex_state *sr_state = NULL; + struct acx_smart_reflex_config_params *sr_param = NULL; + int i, ret; + + wl1271_debug(DEBUG_ACX, "acx smart reflex"); + + sr_param = kzalloc(sizeof(*sr_param), GFP_KERNEL); + if (!sr_param) { + ret = -ENOMEM; + goto out; + } + + for (i = 0; i < CONF_SR_ERR_TBL_COUNT; i++) { + struct conf_mart_reflex_err_table *e = + &(wl->conf.init.sr_err_tbl[i]); + + sr_param->error_table[i].len = e->len; + sr_param->error_table[i].upper_limit = e->upper_limit; + memcpy(sr_param->error_table[i].values, e->values, e->len); + } + + ret = wl1271_cmd_configure(wl, ACX_SET_SMART_REFLEX_PARAMS, + sr_param, sizeof(*sr_param)); + if (ret < 0) { + wl1271_warning("failed to set smart reflex params: %d", ret); + goto out; + } + + sr_state = kzalloc(sizeof(*sr_state), GFP_KERNEL); + if (!sr_state) { + ret = -ENOMEM; + goto out; + } + + /* enable smart reflex */ + sr_state->enable = wl->conf.init.sr_enable; + + ret = wl1271_cmd_configure(wl, ACX_SET_SMART_REFLEX_STATE, + sr_state, sizeof(*sr_state)); + if (ret < 0) { + wl1271_warning("failed to set smart reflex params: %d", ret); + goto out; + } + +out: + kfree(sr_state); + kfree(sr_param); + return ret; + +} + int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable) { struct wl1271_acx_bet_enable *acx = NULL; @@ -1114,31 +1132,3 @@ int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, u8 *address, kfree(acx); return ret; } - -int wl1271_acx_pm_config(struct wl1271 *wl) -{ - struct wl1271_acx_pm_config *acx = NULL; - struct conf_pm_config_settings *c = &wl->conf.pm_config; - int ret = 0; - - wl1271_debug(DEBUG_ACX, "acx pm config"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->host_clk_settling_time = cpu_to_le32(c->host_clk_settling_time); - acx->host_fast_wakeup_support = c->host_fast_wakeup_support; - - ret = wl1271_cmd_configure(wl, ACX_PM_CONFIG, acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("acx pm config failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} diff --git a/trunk/drivers/net/wireless/wl12xx/wl1271_acx.h b/trunk/drivers/net/wireless/wl12xx/wl1271_acx.h index aeccc98581eb..2ce0a8128542 100644 --- a/trunk/drivers/net/wireless/wl12xx/wl1271_acx.h +++ b/trunk/drivers/net/wireless/wl12xx/wl1271_acx.h @@ -2,7 +2,7 @@ * This file is part of wl1271 * * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. - * Copyright (C) 2008-2010 Nokia Corporation + * Copyright (C) 2008-2009 Nokia Corporation * * Contact: Luciano Coelho * @@ -348,7 +348,7 @@ struct acx_beacon_filter_option { * ACXBeaconFilterEntry (not 221) * Byte Offset Size (Bytes) Definition * =========== ============ ========== - * 0 1 IE identifier + * 0 1 IE identifier * 1 1 Treatment bit mask * * ACXBeaconFilterEntry (221) @@ -381,8 +381,8 @@ struct acx_beacon_filter_ie_table { struct acx_header header; u8 num_ie; - u8 pad[3]; u8 table[BEACON_FILTER_TABLE_MAX_SIZE]; + u8 pad[3]; } __attribute__ ((packed)); struct acx_conn_monit_params { @@ -415,12 +415,23 @@ struct acx_bt_wlan_coex { u8 pad[3]; } __attribute__ ((packed)); -struct acx_dco_itrim_params { +struct acx_smart_reflex_state { struct acx_header header; u8 enable; u8 padding[3]; - __le32 timeout; +} __attribute__ ((packed)); + +struct smart_reflex_err_table { + u8 len; + s8 upper_limit; + s8 values[14]; +} __attribute__ ((packed)); + +struct acx_smart_reflex_config_params { + struct acx_header header; + + struct smart_reflex_err_table error_table[3]; } __attribute__ ((packed)); #define PTA_ANTENNA_TYPE_DEF (0) @@ -826,9 +837,6 @@ struct acx_rate_class { u8 reserved; }; -#define ACX_TX_BASIC_RATE 0 -#define ACX_TX_AP_FULL_RATE 1 -#define ACX_TX_RATE_POLICY_CNT 2 struct acx_rate_policy { struct acx_header header; @@ -869,8 +877,8 @@ struct acx_tx_config_options { __le16 tx_compl_threshold; /* number of packets */ } __attribute__ ((packed)); -#define ACX_RX_MEM_BLOCKS 70 -#define ACX_TX_MIN_MEM_BLOCKS 40 +#define ACX_RX_MEM_BLOCKS 64 +#define ACX_TX_MIN_MEM_BLOCKS 64 #define ACX_TX_DESCRIPTORS 32 #define ACX_NUM_SSID_PROFILES 1 @@ -961,13 +969,6 @@ struct wl1271_acx_arp_filter { used. */ } __attribute__((packed)); -struct wl1271_acx_pm_config { - struct acx_header header; - - __le32 host_clk_settling_time; - u8 host_fast_wakeup_support; - u8 padding[3]; -} __attribute__ ((packed)); enum { ACX_WAKE_UP_CONDITIONS = 0x0002, @@ -1026,13 +1027,13 @@ enum { ACX_HT_BSS_OPERATION = 0x0058, ACX_COEX_ACTIVITY = 0x0059, ACX_SET_SMART_REFLEX_DEBUG = 0x005A, - ACX_SET_DCO_ITRIM_PARAMS = 0x0061, + ACX_SET_SMART_REFLEX_STATE = 0x005B, + ACX_SET_SMART_REFLEX_PARAMS = 0x005F, DOT11_RX_MSDU_LIFE_TIME = 0x1004, DOT11_CUR_TX_PWR = 0x100D, DOT11_RX_DOT11_MODE = 0x1012, DOT11_RTS_THRESHOLD = 0x1013, DOT11_GROUP_ADDRESS_TBL = 0x1014, - ACX_PM_CONFIG = 0x1016, MAX_DOT11_IE = DOT11_GROUP_ADDRESS_TBL, @@ -1055,7 +1056,6 @@ int wl1271_acx_group_address_tbl(struct wl1271 *wl, bool enable, void *mc_list, u32 mc_list_len); int wl1271_acx_service_period_timeout(struct wl1271 *wl); int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold); -int wl1271_acx_dco_itrim_params(struct wl1271 *wl); int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter); int wl1271_acx_beacon_filter_table(struct wl1271 *wl); int wl1271_acx_conn_monit_params(struct wl1271 *wl); @@ -1069,12 +1069,9 @@ int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble); int wl1271_acx_cts_protect(struct wl1271 *wl, enum acx_ctsprotect_type ctsprotect); int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats); -int wl1271_acx_rate_policies(struct wl1271 *wl); -int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max, - u8 aifsn, u16 txop); -int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type, - u8 tsid, u8 ps_scheme, u8 ack_policy, - u32 apsd_conf0, u32 apsd_conf1); +int wl1271_acx_rate_policies(struct wl1271 *wl, u32 enabled_rates); +int wl1271_acx_ac_cfg(struct wl1271 *wl); +int wl1271_acx_tid_cfg(struct wl1271 *wl); int wl1271_acx_frag_threshold(struct wl1271 *wl); int wl1271_acx_tx_config_options(struct wl1271 *wl); int wl1271_acx_mem_cfg(struct wl1271 *wl); @@ -1084,6 +1081,5 @@ int wl1271_acx_smart_reflex(struct wl1271 *wl); int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable); int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, u8 *address, u8 version); -int wl1271_acx_pm_config(struct wl1271 *wl); #endif /* __WL1271_ACX_H__ */ diff --git a/trunk/drivers/net/wireless/wl12xx/wl1271_boot.c b/trunk/drivers/net/wireless/wl12xx/wl1271_boot.c index 2be76ee42bb9..b7c96454cca3 100644 --- a/trunk/drivers/net/wireless/wl12xx/wl1271_boot.c +++ b/trunk/drivers/net/wireless/wl12xx/wl1271_boot.c @@ -27,7 +27,6 @@ #include "wl1271_reg.h" #include "wl1271_boot.h" #include "wl1271_spi.h" -#include "wl1271_io.h" #include "wl1271_event.h" static struct wl1271_partition_set part_table[PART_TABLE_LEN] = { @@ -94,19 +93,19 @@ static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag) u32 cpu_ctrl; /* 10.5.0 run the firmware (I) */ - cpu_ctrl = wl1271_read32(wl, ACX_REG_ECPU_CONTROL); + cpu_ctrl = wl1271_spi_read32(wl, ACX_REG_ECPU_CONTROL); /* 10.5.1 run the firmware (II) */ cpu_ctrl |= flag; - wl1271_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl); + wl1271_spi_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl); } static void wl1271_boot_fw_version(struct wl1271 *wl) { struct wl1271_static_data static_data; - wl1271_read(wl, wl->cmd_box_addr, &static_data, sizeof(static_data), - false); + wl1271_spi_read(wl, wl->cmd_box_addr, + &static_data, sizeof(static_data), false); strncpy(wl->chip.fw_ver, static_data.fw_version, sizeof(wl->chip.fw_ver)); @@ -165,7 +164,7 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, memcpy(chunk, p, CHUNK_SIZE); wl1271_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x", p, addr); - wl1271_write(wl, addr, chunk, CHUNK_SIZE, false); + wl1271_spi_write(wl, addr, chunk, CHUNK_SIZE, false); chunk_num++; } @@ -176,7 +175,7 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, memcpy(chunk, p, fw_data_len % CHUNK_SIZE); wl1271_debug(DEBUG_BOOT, "uploading fw last chunk (%zd B) 0x%p to 0x%x", fw_data_len % CHUNK_SIZE, p, addr); - wl1271_write(wl, addr, chunk, fw_data_len % CHUNK_SIZE, false); + wl1271_spi_write(wl, addr, chunk, fw_data_len % CHUNK_SIZE, false); kfree(chunk); return 0; @@ -220,14 +219,23 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) size_t nvs_len, burst_len; int i; u32 dest_addr, val; - u8 *nvs_ptr, *nvs_aligned; + u8 *nvs_ptr, *nvs, *nvs_aligned; - if (wl->nvs == NULL) + nvs = wl->nvs; + if (nvs == NULL) return -ENODEV; - /* only the first part of the NVS needs to be uploaded */ - nvs_len = sizeof(wl->nvs->nvs); - nvs_ptr = (u8 *)wl->nvs->nvs; + nvs_ptr = nvs; + + nvs_len = wl->nvs_len; + + /* Update the device MAC address into the nvs */ + nvs[11] = wl->mac_addr[0]; + nvs[10] = wl->mac_addr[1]; + nvs[6] = wl->mac_addr[2]; + nvs[5] = wl->mac_addr[3]; + nvs[4] = wl->mac_addr[4]; + nvs[3] = wl->mac_addr[5]; /* * Layout before the actual NVS tables: @@ -257,7 +265,7 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) wl1271_debug(DEBUG_BOOT, "nvs burst write 0x%x: 0x%x", dest_addr, val); - wl1271_write32(wl, dest_addr, val); + wl1271_spi_write32(wl, dest_addr, val); nvs_ptr += 4; dest_addr += 4; @@ -269,7 +277,7 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) * is 7 bytes further. */ nvs_ptr += 7; - nvs_len -= nvs_ptr - (u8 *)wl->nvs->nvs; + nvs_len -= nvs_ptr - nvs; nvs_len = ALIGN(nvs_len, 4); /* FIXME: The driver sets the partition here, but this is not needed, @@ -278,20 +286,15 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) wl1271_set_partition(wl, &part_table[PART_WORK]); /* Copy the NVS tables to a new block to ensure alignment */ - /* FIXME: We jump 3 more bytes before uploading the NVS. It seems - that our NVS files have three extra zeros here. I'm not sure whether - the problem is in our NVS generation or we should really jumpt these - 3 bytes here */ - nvs_ptr += 3; - - nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL); if - (!nvs_aligned) return -ENOMEM; + nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL); + if (!nvs_aligned) + return -ENOMEM; /* And finally we upload the NVS tables */ /* FIXME: In wl1271, we upload everything at once. No endianness handling needed here?! The ref driver doesn't do anything about it at this point */ - wl1271_write(wl, CMD_MBOX_ADDRESS, nvs_aligned, nvs_len, false); + wl1271_spi_write(wl, CMD_MBOX_ADDRESS, nvs_aligned, nvs_len, false); kfree(nvs_aligned); return 0; @@ -300,9 +303,9 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) static void wl1271_boot_enable_interrupts(struct wl1271 *wl) { enable_irq(wl->irq); - wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, - WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK)); - wl1271_write32(wl, HI_CFG, HI_CFG_DEF_VAL); + wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK, + WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK)); + wl1271_spi_write32(wl, HI_CFG, HI_CFG_DEF_VAL); } static int wl1271_boot_soft_reset(struct wl1271 *wl) @@ -311,12 +314,13 @@ static int wl1271_boot_soft_reset(struct wl1271 *wl) u32 boot_data; /* perform soft reset */ - wl1271_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT); + wl1271_spi_write32(wl, ACX_REG_SLV_SOFT_RESET, + ACX_SLV_SOFT_RESET_BIT); /* SOFT_RESET is self clearing */ timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME); while (1) { - boot_data = wl1271_read32(wl, ACX_REG_SLV_SOFT_RESET); + boot_data = wl1271_spi_read32(wl, ACX_REG_SLV_SOFT_RESET); wl1271_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data); if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0) break; @@ -332,10 +336,10 @@ static int wl1271_boot_soft_reset(struct wl1271 *wl) } /* disable Rx/Tx */ - wl1271_write32(wl, ENABLE, 0x0); + wl1271_spi_write32(wl, ENABLE, 0x0); /* disable auto calibration on start*/ - wl1271_write32(wl, SPARE_A2, 0xffff); + wl1271_spi_write32(wl, SPARE_A2, 0xffff); return 0; } @@ -347,7 +351,7 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl) wl1271_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT); - chip_id = wl1271_read32(wl, CHIP_ID_B); + chip_id = wl1271_spi_read32(wl, CHIP_ID_B); wl1271_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id); @@ -360,7 +364,8 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl) loop = 0; while (loop++ < INIT_LOOP) { udelay(INIT_LOOP_DELAY); - interrupt = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); + interrupt = wl1271_spi_read32(wl, + ACX_REG_INTERRUPT_NO_CLEAR); if (interrupt == 0xffffffff) { wl1271_error("error reading hardware complete " @@ -369,8 +374,8 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl) } /* check that ACX_INTR_INIT_COMPLETE is enabled */ else if (interrupt & WL1271_ACX_INTR_INIT_COMPLETE) { - wl1271_write32(wl, ACX_REG_INTERRUPT_ACK, - WL1271_ACX_INTR_INIT_COMPLETE); + wl1271_spi_write32(wl, ACX_REG_INTERRUPT_ACK, + WL1271_ACX_INTR_INIT_COMPLETE); break; } } @@ -382,10 +387,10 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl) } /* get hardware config command mail box */ - wl->cmd_box_addr = wl1271_read32(wl, REG_COMMAND_MAILBOX_PTR); + wl->cmd_box_addr = wl1271_spi_read32(wl, REG_COMMAND_MAILBOX_PTR); /* get hardware config event mail box */ - wl->event_box_addr = wl1271_read32(wl, REG_EVENT_MAILBOX_PTR); + wl->event_box_addr = wl1271_spi_read32(wl, REG_EVENT_MAILBOX_PTR); /* set the working partition to its "running" mode offset */ wl1271_set_partition(wl, &part_table[PART_WORK]); @@ -458,9 +463,9 @@ int wl1271_boot(struct wl1271 *wl) wl1271_top_reg_write(wl, OCP_REG_CLK_POLARITY, val); } - wl1271_write32(wl, PLL_PARAMETERS, clk); + wl1271_spi_write32(wl, PLL_PARAMETERS, clk); - pause = wl1271_read32(wl, PLL_PARAMETERS); + pause = wl1271_spi_read32(wl, PLL_PARAMETERS); wl1271_debug(DEBUG_BOOT, "pause1 0x%x", pause); @@ -469,10 +474,10 @@ int wl1271_boot(struct wl1271 *wl) * 0x3ff (magic number ). How does * this work?! */ pause |= WU_COUNTER_PAUSE_VAL; - wl1271_write32(wl, WU_COUNTER_PAUSE, pause); + wl1271_spi_write32(wl, WU_COUNTER_PAUSE, pause); /* Continue the ELP wake up sequence */ - wl1271_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL); + wl1271_spi_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL); udelay(500); wl1271_set_partition(wl, &part_table[PART_DRPW]); @@ -482,18 +487,18 @@ int wl1271_boot(struct wl1271 *wl) before taking DRPw out of reset */ wl1271_debug(DEBUG_BOOT, "DRPW_SCRATCH_START %08x", DRPW_SCRATCH_START); - clk = wl1271_read32(wl, DRPW_SCRATCH_START); + clk = wl1271_spi_read32(wl, DRPW_SCRATCH_START); wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk); /* 2 */ clk |= (REF_CLOCK << 1) << 4; - wl1271_write32(wl, DRPW_SCRATCH_START, clk); + wl1271_spi_write32(wl, DRPW_SCRATCH_START, clk); wl1271_set_partition(wl, &part_table[PART_WORK]); /* Disable interrupts */ - wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL); + wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL); ret = wl1271_boot_soft_reset(wl); if (ret < 0) @@ -508,22 +513,23 @@ int wl1271_boot(struct wl1271 *wl) * ACX_EEPROMLESS_IND_REG */ wl1271_debug(DEBUG_BOOT, "ACX_EEPROMLESS_IND_REG"); - wl1271_write32(wl, ACX_EEPROMLESS_IND_REG, ACX_EEPROMLESS_IND_REG); + wl1271_spi_write32(wl, ACX_EEPROMLESS_IND_REG, + ACX_EEPROMLESS_IND_REG); - tmp = wl1271_read32(wl, CHIP_ID_B); + tmp = wl1271_spi_read32(wl, CHIP_ID_B); wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp); /* 6. read the EEPROM parameters */ - tmp = wl1271_read32(wl, SCR_PAD2); + tmp = wl1271_spi_read32(wl, SCR_PAD2); ret = wl1271_boot_write_irq_polarity(wl); if (ret < 0) goto out; /* FIXME: Need to check whether this is really what we want */ - wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, - WL1271_ACX_ALL_EVENTS_VECTOR); + wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK, + WL1271_ACX_ALL_EVENTS_VECTOR); /* WL1271: The reference driver skips steps 7 to 10 (jumps directly * to upload_fw) */ diff --git a/trunk/drivers/net/wireless/wl12xx/wl1271_cmd.c b/trunk/drivers/net/wireless/wl12xx/wl1271_cmd.c index 36a64e06f290..c3385b3d246c 100644 --- a/trunk/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/trunk/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -30,7 +30,6 @@ #include "wl1271.h" #include "wl1271_reg.h" #include "wl1271_spi.h" -#include "wl1271_io.h" #include "wl1271_acx.h" #include "wl12xx_80211.h" #include "wl1271_cmd.h" @@ -58,13 +57,13 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, WARN_ON(len % 4 != 0); - wl1271_write(wl, wl->cmd_box_addr, buf, len, false); + wl1271_spi_write(wl, wl->cmd_box_addr, buf, len, false); - wl1271_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); + wl1271_spi_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT); - intr = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); + intr = wl1271_spi_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) { if (time_after(jiffies, timeout)) { wl1271_error("command complete timeout"); @@ -74,13 +73,13 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, msleep(1); - intr = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); + intr = wl1271_spi_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); } /* read back the status code of the command */ if (res_len == 0) res_len = sizeof(struct wl1271_cmd_header); - wl1271_read(wl, wl->cmd_box_addr, cmd, res_len, false); + wl1271_spi_read(wl, wl->cmd_box_addr, cmd, res_len, false); status = le16_to_cpu(cmd->status); if (status != CMD_STATUS_SUCCESS) { @@ -88,8 +87,8 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, ret = -EIO; } - wl1271_write32(wl, ACX_REG_INTERRUPT_ACK, - WL1271_ACX_INTR_CMD_COMPLETE); + wl1271_spi_write32(wl, ACX_REG_INTERRUPT_ACK, + WL1271_ACX_INTR_CMD_COMPLETE); out: return ret; @@ -192,19 +191,23 @@ static int wl1271_cmd_cal(struct wl1271 *wl) int wl1271_cmd_general_parms(struct wl1271 *wl) { struct wl1271_general_parms_cmd *gen_parms; + struct conf_general_parms *g = &wl->conf.init.genparam; int ret; - if (!wl->nvs) - return -ENODEV; - gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL); if (!gen_parms) return -ENOMEM; gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM; - memcpy(gen_parms->params, wl->nvs->general_params, - WL1271_NVS_GENERAL_PARAMS_SIZE); + gen_parms->ref_clk = g->ref_clk; + gen_parms->settling_time = g->settling_time; + gen_parms->clk_valid_on_wakeup = g->clk_valid_on_wakeup; + gen_parms->dc2dcmode = g->dc2dcmode; + gen_parms->single_dual_band = g->single_dual_band; + gen_parms->tx_bip_fem_autodetect = g->tx_bip_fem_autodetect; + gen_parms->tx_bip_fem_manufacturer = g->tx_bip_fem_manufacturer; + gen_parms->settings = g->settings; ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), 0); if (ret < 0) @@ -217,11 +220,8 @@ int wl1271_cmd_general_parms(struct wl1271 *wl) int wl1271_cmd_radio_parms(struct wl1271 *wl) { struct wl1271_radio_parms_cmd *radio_parms; - struct conf_radio_parms *rparam = &wl->conf.init.radioparam; - int ret; - - if (!wl->nvs) - return -ENODEV; + struct conf_radio_parms *r = &wl->conf.init.radioparam; + int i, ret; radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL); if (!radio_parms) @@ -229,13 +229,60 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl) radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM; - memcpy(radio_parms->stat_radio_params, wl->nvs->stat_radio_params, - WL1271_NVS_STAT_RADIO_PARAMS_SIZE); - memcpy(radio_parms->dyn_radio_params, - wl->nvs->dyn_radio_params[rparam->fem], - WL1271_NVS_DYN_RADIO_PARAMS_SIZE); - - /* FIXME: current NVS is missing 5GHz parameters */ + /* Static radio parameters */ + radio_parms->rx_trace_loss = r->rx_trace_loss; + radio_parms->tx_trace_loss = r->tx_trace_loss; + memcpy(radio_parms->rx_rssi_and_proc_compens, + r->rx_rssi_and_proc_compens, + CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE); + + memcpy(radio_parms->rx_trace_loss_5, r->rx_trace_loss_5, + CONF_NUMBER_OF_SUB_BANDS_5); + memcpy(radio_parms->tx_trace_loss_5, r->tx_trace_loss_5, + CONF_NUMBER_OF_SUB_BANDS_5); + memcpy(radio_parms->rx_rssi_and_proc_compens_5, + r->rx_rssi_and_proc_compens_5, + CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE); + + /* Dynamic radio parameters */ + radio_parms->tx_ref_pd_voltage = cpu_to_le16(r->tx_ref_pd_voltage); + radio_parms->tx_ref_power = r->tx_ref_power; + radio_parms->tx_offset_db = r->tx_offset_db; + + memcpy(radio_parms->tx_rate_limits_normal, r->tx_rate_limits_normal, + CONF_NUMBER_OF_RATE_GROUPS); + memcpy(radio_parms->tx_rate_limits_degraded, r->tx_rate_limits_degraded, + CONF_NUMBER_OF_RATE_GROUPS); + + memcpy(radio_parms->tx_channel_limits_11b, r->tx_channel_limits_11b, + CONF_NUMBER_OF_CHANNELS_2_4); + memcpy(radio_parms->tx_channel_limits_ofdm, r->tx_channel_limits_ofdm, + CONF_NUMBER_OF_CHANNELS_2_4); + memcpy(radio_parms->tx_pdv_rate_offsets, r->tx_pdv_rate_offsets, + CONF_NUMBER_OF_RATE_GROUPS); + memcpy(radio_parms->tx_ibias, r->tx_ibias, CONF_NUMBER_OF_RATE_GROUPS); + + radio_parms->rx_fem_insertion_loss = r->rx_fem_insertion_loss; + + for (i = 0; i < CONF_NUMBER_OF_SUB_BANDS_5; i++) + radio_parms->tx_ref_pd_voltage_5[i] = + cpu_to_le16(r->tx_ref_pd_voltage_5[i]); + memcpy(radio_parms->tx_ref_power_5, r->tx_ref_power_5, + CONF_NUMBER_OF_SUB_BANDS_5); + memcpy(radio_parms->tx_offset_db_5, r->tx_offset_db_5, + CONF_NUMBER_OF_SUB_BANDS_5); + memcpy(radio_parms->tx_rate_limits_normal_5, + r->tx_rate_limits_normal_5, CONF_NUMBER_OF_RATE_GROUPS); + memcpy(radio_parms->tx_rate_limits_degraded_5, + r->tx_rate_limits_degraded_5, CONF_NUMBER_OF_RATE_GROUPS); + memcpy(radio_parms->tx_channel_limits_ofdm_5, + r->tx_channel_limits_ofdm_5, CONF_NUMBER_OF_CHANNELS_5); + memcpy(radio_parms->tx_pdv_rate_offsets_5, r->tx_pdv_rate_offsets_5, + CONF_NUMBER_OF_RATE_GROUPS); + memcpy(radio_parms->tx_ibias_5, r->tx_ibias_5, + CONF_NUMBER_OF_RATE_GROUPS); + memcpy(radio_parms->rx_fem_insertion_loss_5, + r->rx_fem_insertion_loss_5, CONF_NUMBER_OF_SUB_BANDS_5); wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ", radio_parms, sizeof(*radio_parms)); @@ -264,6 +311,19 @@ int wl1271_cmd_join(struct wl1271 *wl) do_cal = false; } + /* FIXME: This is a workaround, because with the current stack, we + * cannot know when we have disassociated. So, if we have already + * joined, we disconnect before joining again. */ + if (wl->joined) { + ret = wl1271_cmd_disconnect(wl); + if (ret < 0) { + wl1271_error("failed to disconnect before rejoining"); + goto out; + } + + wl->joined = false; + } + join = kzalloc(sizeof(*join), GFP_KERNEL); if (!join) { ret = -ENOMEM; @@ -328,6 +388,8 @@ int wl1271_cmd_join(struct wl1271 *wl) goto out_free; } + wl->joined = true; + /* * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to * simplify locking we just sleep instead, for now @@ -425,7 +487,7 @@ int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len) return 0; } -int wl1271_cmd_data_path(struct wl1271 *wl, bool enable) +int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable) { struct cmd_enabledisable_path *cmd; int ret; @@ -439,8 +501,7 @@ int wl1271_cmd_data_path(struct wl1271 *wl, bool enable) goto out; } - /* the channel here is only used for calibration, so hardcoded to 1 */ - cmd->channel = 1; + cmd->channel = channel; if (enable) { cmd_rx = CMD_ENABLE_RX; @@ -453,29 +514,29 @@ int wl1271_cmd_data_path(struct wl1271 *wl, bool enable) ret = wl1271_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_error("rx %s cmd for channel %d failed", - enable ? "start" : "stop", cmd->channel); + enable ? "start" : "stop", channel); goto out; } wl1271_debug(DEBUG_BOOT, "rx %s cmd channel %d", - enable ? "start" : "stop", cmd->channel); + enable ? "start" : "stop", channel); ret = wl1271_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_error("tx %s cmd for channel %d failed", - enable ? "start" : "stop", cmd->channel); + enable ? "start" : "stop", channel); return ret; } wl1271_debug(DEBUG_BOOT, "tx %s cmd channel %d", - enable ? "start" : "stop", cmd->channel); + enable ? "start" : "stop", channel); out: kfree(cmd); return ret; } -int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, bool send) +int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode) { struct wl1271_cmd_ps_params *ps_params = NULL; int ret = 0; @@ -496,7 +557,7 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, bool send) } ps_params->ps_mode = ps_mode; - ps_params->send_null_data = send; + ps_params->send_null_data = 1; ps_params->retries = 5; ps_params->hang_over_period = 128; ps_params->null_data_rate = cpu_to_le32(1); /* 1 Mbps */ @@ -575,7 +636,7 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, channels = wl->hw->wiphy->bands[ieee_band]->channels; n_ch = wl->hw->wiphy->bands[ieee_band]->n_channels; - if (test_bit(WL1271_FLAG_SCANNING, &wl->flags)) + if (wl->scanning) return -EINVAL; params = kzalloc(sizeof(*params), GFP_KERNEL); @@ -650,7 +711,7 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, wl1271_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params)); - set_bit(WL1271_FLAG_SCANNING, &wl->flags); + wl->scanning = true; if (wl1271_11a_enabled()) { wl->scan.state = band; if (band == WL1271_SCAN_BAND_DUAL) { @@ -668,7 +729,7 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, ret = wl1271_cmd_send(wl, CMD_SCAN, params, sizeof(*params), 0); if (ret < 0) { wl1271_error("SCAN failed"); - clear_bit(WL1271_FLAG_SCANNING, &wl->flags); + wl->scanning = false; goto out; } @@ -942,7 +1003,7 @@ int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_warning("could not set keys"); - goto out; + goto out; } out: diff --git a/trunk/drivers/net/wireless/wl12xx/wl1271_cmd.h b/trunk/drivers/net/wireless/wl12xx/wl1271_cmd.h index 2dc06c73532b..b4fa4acb9229 100644 --- a/trunk/drivers/net/wireless/wl12xx/wl1271_cmd.h +++ b/trunk/drivers/net/wireless/wl12xx/wl1271_cmd.h @@ -37,8 +37,8 @@ int wl1271_cmd_join(struct wl1271 *wl); int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer); int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len); int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len); -int wl1271_cmd_data_path(struct wl1271 *wl, bool enable); -int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, bool send); +int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable); +int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode); int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer, size_t len); int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, @@ -428,24 +428,67 @@ struct wl1271_general_parms_cmd { struct wl1271_cmd_test_header test; - u8 params[WL1271_NVS_GENERAL_PARAMS_SIZE]; - s8 reserved[23]; -} __attribute__ ((packed)); + u8 ref_clk; + u8 settling_time; + u8 clk_valid_on_wakeup; + u8 dc2dcmode; + u8 single_dual_band; -#define WL1271_STAT_RADIO_PARAMS_5_SIZE 29 -#define WL1271_DYN_RADIO_PARAMS_5_SIZE 104 + u8 tx_bip_fem_autodetect; + u8 tx_bip_fem_manufacturer; + u8 settings; +} __attribute__ ((packed)); struct wl1271_radio_parms_cmd { struct wl1271_cmd_header header; struct wl1271_cmd_test_header test; - u8 stat_radio_params[WL1271_NVS_STAT_RADIO_PARAMS_SIZE]; - u8 stat_radio_params_5[WL1271_STAT_RADIO_PARAMS_5_SIZE]; + /* Static radio parameters */ + /* 2.4GHz */ + u8 rx_trace_loss; + u8 tx_trace_loss; + s8 rx_rssi_and_proc_compens[CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE]; - u8 dyn_radio_params[WL1271_NVS_DYN_RADIO_PARAMS_SIZE]; - u8 reserved; - u8 dyn_radio_params_5[WL1271_DYN_RADIO_PARAMS_5_SIZE]; + /* 5GHz */ + u8 rx_trace_loss_5[CONF_NUMBER_OF_SUB_BANDS_5]; + u8 tx_trace_loss_5[CONF_NUMBER_OF_SUB_BANDS_5]; + s8 rx_rssi_and_proc_compens_5[CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE]; + + /* Dynamic radio parameters */ + /* 2.4GHz */ + __le16 tx_ref_pd_voltage; + s8 tx_ref_power; + s8 tx_offset_db; + + s8 tx_rate_limits_normal[CONF_NUMBER_OF_RATE_GROUPS]; + s8 tx_rate_limits_degraded[CONF_NUMBER_OF_RATE_GROUPS]; + + s8 tx_channel_limits_11b[CONF_NUMBER_OF_CHANNELS_2_4]; + s8 tx_channel_limits_ofdm[CONF_NUMBER_OF_CHANNELS_2_4]; + s8 tx_pdv_rate_offsets[CONF_NUMBER_OF_RATE_GROUPS]; + + u8 tx_ibias[CONF_NUMBER_OF_RATE_GROUPS]; + u8 rx_fem_insertion_loss; + + u8 padding2; + + /* 5GHz */ + __le16 tx_ref_pd_voltage_5[CONF_NUMBER_OF_SUB_BANDS_5]; + s8 tx_ref_power_5[CONF_NUMBER_OF_SUB_BANDS_5]; + s8 tx_offset_db_5[CONF_NUMBER_OF_SUB_BANDS_5]; + + s8 tx_rate_limits_normal_5[CONF_NUMBER_OF_RATE_GROUPS]; + s8 tx_rate_limits_degraded_5[CONF_NUMBER_OF_RATE_GROUPS]; + + s8 tx_channel_limits_ofdm_5[CONF_NUMBER_OF_CHANNELS_5]; + s8 tx_pdv_rate_offsets_5[CONF_NUMBER_OF_RATE_GROUPS]; + + /* FIXME: this is inconsistent with the types for 2.4GHz */ + s8 tx_ibias_5[CONF_NUMBER_OF_RATE_GROUPS]; + s8 rx_fem_insertion_loss_5[CONF_NUMBER_OF_SUB_BANDS_5]; + + u8 padding3[2]; } __attribute__ ((packed)); struct wl1271_cmd_cal_channel_tune { diff --git a/trunk/drivers/net/wireless/wl12xx/wl1271_conf.h b/trunk/drivers/net/wireless/wl12xx/wl1271_conf.h index 6f9e75cc5640..565373ede265 100644 --- a/trunk/drivers/net/wireless/wl12xx/wl1271_conf.h +++ b/trunk/drivers/net/wireless/wl12xx/wl1271_conf.h @@ -258,8 +258,7 @@ struct conf_rx_settings { #define CONF_TX_MAX_RATE_CLASSES 8 #define CONF_TX_RATE_MASK_UNSPECIFIED 0 -#define CONF_TX_RATE_MASK_BASIC (CONF_HW_BIT_RATE_1MBPS | \ - CONF_HW_BIT_RATE_2MBPS) +#define CONF_TX_RATE_MASK_ALL 0x1eff #define CONF_TX_RATE_RETRY_LIMIT 10 struct conf_tx_rate_class { @@ -723,6 +722,31 @@ struct conf_conn_settings { u8 psm_entry_retries; }; +#define CONF_SR_ERR_TBL_MAX_VALUES 14 + +struct conf_mart_reflex_err_table { + /* + * Length of the error table values table. + * + * Range: 0 - CONF_SR_ERR_TBL_MAX_VALUES + */ + u8 len; + + /* + * Smart Reflex error table upper limit. + * + * Range: s8 + */ + s8 upper_limit; + + /* + * Smart Reflex error table values. + * + * Range: s8 + */ + s8 values[CONF_SR_ERR_TBL_MAX_VALUES]; +}; + enum { CONF_REF_CLK_19_2_E, CONF_REF_CLK_26_E, @@ -735,6 +759,64 @@ enum single_dual_band_enum { CONF_DUAL_BAND }; +struct conf_general_parms { + /* + * RF Reference Clock type / speed + * + * Range: CONF_REF_CLK_* + */ + u8 ref_clk; + + /* + * Settling time of the reference clock after boot. + * + * Range: u8 + */ + u8 settling_time; + + /* + * Flag defining whether clock is valid on wakeup. + * + * Range: 0 - not valid on wakeup, 1 - valid on wakeup + */ + u8 clk_valid_on_wakeup; + + /* + * DC-to-DC mode. + * + * Range: Unknown + */ + u8 dc2dcmode; + + /* + * Flag defining whether used as single or dual-band. + * + * Range: CONF_SINGLE_BAND, CONF_DUAL_BAND + */ + u8 single_dual_band; + + /* + * TX bip fem autodetect flag. + * + * Range: Unknown + */ + u8 tx_bip_fem_autodetect; + + /* + * TX bip gem manufacturer. + * + * Range: Unknown + */ + u8 tx_bip_fem_manufacturer; + + /* + * Settings flags. + * + * Range: Unknown + */ + u8 settings; +}; + #define CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE 15 #define CONF_NUMBER_OF_SUB_BANDS_5 7 #define CONF_NUMBER_OF_RATE_GROUPS 6 @@ -743,43 +825,87 @@ enum single_dual_band_enum { struct conf_radio_parms { /* - * FEM parameter set to use + * Static radio parameters for 2.4GHz * - * Range: 0 or 1 + * Range: unknown */ - u8 fem; -}; + u8 rx_trace_loss; + u8 tx_trace_loss; + s8 rx_rssi_and_proc_compens[CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE]; -struct conf_init_settings { /* - * Configure radio parameters. + * Static radio parameters for 5GHz + * + * Range: unknown */ - struct conf_radio_parms radioparam; + u8 rx_trace_loss_5[CONF_NUMBER_OF_SUB_BANDS_5]; + u8 tx_trace_loss_5[CONF_NUMBER_OF_SUB_BANDS_5]; + s8 rx_rssi_and_proc_compens_5[CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE]; -}; + /* + * Dynamic radio parameters for 2.4GHz + * + * Range: unknown + */ + s16 tx_ref_pd_voltage; + s8 tx_ref_power; + s8 tx_offset_db; -struct conf_itrim_settings { - /* enable dco itrim */ - u8 enable; + s8 tx_rate_limits_normal[CONF_NUMBER_OF_RATE_GROUPS]; + s8 tx_rate_limits_degraded[CONF_NUMBER_OF_RATE_GROUPS]; - /* moderation timeout in microsecs from the last TX */ - u32 timeout; -}; + s8 tx_channel_limits_11b[CONF_NUMBER_OF_CHANNELS_2_4]; + s8 tx_channel_limits_ofdm[CONF_NUMBER_OF_CHANNELS_2_4]; + s8 tx_pdv_rate_offsets[CONF_NUMBER_OF_RATE_GROUPS]; + + u8 tx_ibias[CONF_NUMBER_OF_RATE_GROUPS]; + u8 rx_fem_insertion_loss; -struct conf_pm_config_settings { /* - * Host clock settling time + * Dynamic radio parameters for 5GHz * - * Range: 0 - 30000 us + * Range: unknown + */ + s16 tx_ref_pd_voltage_5[CONF_NUMBER_OF_SUB_BANDS_5]; + s8 tx_ref_power_5[CONF_NUMBER_OF_SUB_BANDS_5]; + s8 tx_offset_db_5[CONF_NUMBER_OF_SUB_BANDS_5]; + + s8 tx_rate_limits_normal_5[CONF_NUMBER_OF_RATE_GROUPS]; + s8 tx_rate_limits_degraded_5[CONF_NUMBER_OF_RATE_GROUPS]; + + s8 tx_channel_limits_ofdm_5[CONF_NUMBER_OF_CHANNELS_5]; + s8 tx_pdv_rate_offsets_5[CONF_NUMBER_OF_RATE_GROUPS]; + + /* FIXME: this is inconsistent with the types for 2.4GHz */ + s8 tx_ibias_5[CONF_NUMBER_OF_RATE_GROUPS]; + s8 rx_fem_insertion_loss_5[CONF_NUMBER_OF_SUB_BANDS_5]; +}; + +#define CONF_SR_ERR_TBL_COUNT 3 + +struct conf_init_settings { + /* + * Configure Smart Reflex error table values. */ - u32 host_clk_settling_time; + struct conf_mart_reflex_err_table sr_err_tbl[CONF_SR_ERR_TBL_COUNT]; /* - * Host fast wakeup support + * Smart Reflex enable flag. * - * Range: true, false + * Range: 1 - Smart Reflex enabled, 0 - Smart Reflex disabled */ - bool host_fast_wakeup_support; + u8 sr_enable; + + /* + * Configure general parameters. + */ + struct conf_general_parms genparam; + + /* + * Configure radio parameters. + */ + struct conf_radio_parms radioparam; + }; struct conf_drv_settings { @@ -788,8 +914,6 @@ struct conf_drv_settings { struct conf_tx_settings tx; struct conf_conn_settings conn; struct conf_init_settings init; - struct conf_itrim_settings itrim; - struct conf_pm_config_settings pm_config; }; #endif diff --git a/trunk/drivers/net/wireless/wl12xx/wl1271_debugfs.c b/trunk/drivers/net/wireless/wl12xx/wl1271_debugfs.c index 8d7588ca68fd..c1805e5f8964 100644 --- a/trunk/drivers/net/wireless/wl12xx/wl1271_debugfs.c +++ b/trunk/drivers/net/wireless/wl12xx/wl1271_debugfs.c @@ -237,64 +237,6 @@ static const struct file_operations tx_queue_len_ops = { .open = wl1271_open_file_generic, }; -static ssize_t gpio_power_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct wl1271 *wl = file->private_data; - bool state = test_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); - - int res; - char buf[10]; - - res = scnprintf(buf, sizeof(buf), "%d\n", state); - - return simple_read_from_buffer(user_buf, count, ppos, buf, res); -} - -static ssize_t gpio_power_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct wl1271 *wl = file->private_data; - char buf[10]; - size_t len; - unsigned long value; - int ret; - - mutex_lock(&wl->mutex); - - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) { - ret = -EFAULT; - goto out; - } - buf[len] = '\0'; - - ret = strict_strtoul(buf, 0, &value); - if (ret < 0) { - wl1271_warning("illegal value in gpio_power"); - goto out; - } - - if (value) { - wl->set_power(true); - set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); - } else { - wl->set_power(false); - clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); - } - -out: - mutex_unlock(&wl->mutex); - return count; -} - -static const struct file_operations gpio_power_ops = { - .read = gpio_power_read, - .write = gpio_power_write, - .open = wl1271_open_file_generic -}; - static void wl1271_debugfs_delete_files(struct wl1271 *wl) { DEBUGFS_FWSTATS_DEL(tx, internal_desc_overflow); @@ -391,8 +333,6 @@ static void wl1271_debugfs_delete_files(struct wl1271 *wl) DEBUGFS_DEL(tx_queue_len); DEBUGFS_DEL(retry_count); DEBUGFS_DEL(excessive_retries); - - DEBUGFS_DEL(gpio_power); } static int wl1271_debugfs_add_files(struct wl1271 *wl) @@ -494,8 +434,6 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl) DEBUGFS_ADD(retry_count, wl->debugfs.rootdir); DEBUGFS_ADD(excessive_retries, wl->debugfs.rootdir); - DEBUGFS_ADD(gpio_power, wl->debugfs.rootdir); - out: if (ret < 0) wl1271_debugfs_delete_files(wl); diff --git a/trunk/drivers/net/wireless/wl12xx/wl1271_event.c b/trunk/drivers/net/wireless/wl12xx/wl1271_event.c index 7468ef10194b..d13fdd99c85c 100644 --- a/trunk/drivers/net/wireless/wl12xx/wl1271_event.c +++ b/trunk/drivers/net/wireless/wl12xx/wl1271_event.c @@ -24,7 +24,6 @@ #include "wl1271.h" #include "wl1271_reg.h" #include "wl1271_spi.h" -#include "wl1271_io.h" #include "wl1271_event.h" #include "wl1271_ps.h" #include "wl12xx_80211.h" @@ -36,7 +35,7 @@ static int wl1271_event_scan_complete(struct wl1271 *wl, wl1271_debug(DEBUG_EVENT, "status: 0x%x", mbox->scheduled_scan_status); - if (test_bit(WL1271_FLAG_SCANNING, &wl->flags)) { + if (wl->scanning) { if (wl->scan.state == WL1271_SCAN_BAND_DUAL) { wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL, size); @@ -44,7 +43,7 @@ static int wl1271_event_scan_complete(struct wl1271 *wl, * to the wl1271_cmd_scan function that we are not * scanning as it checks that. */ - clear_bit(WL1271_FLAG_SCANNING, &wl->flags); + wl->scanning = false; wl1271_cmd_scan(wl, wl->scan.ssid, wl->scan.ssid_len, wl->scan.active, wl->scan.high_prio, @@ -63,7 +62,7 @@ static int wl1271_event_scan_complete(struct wl1271 *wl, mutex_unlock(&wl->mutex); ieee80211_scan_completed(wl->hw, false); mutex_lock(&wl->mutex); - clear_bit(WL1271_FLAG_SCANNING, &wl->flags); + wl->scanning = false; } } return 0; @@ -79,61 +78,25 @@ static int wl1271_event_ps_report(struct wl1271 *wl, switch (mbox->ps_status) { case EVENT_ENTER_POWER_SAVE_FAIL: - wl1271_debug(DEBUG_PSM, "PSM entry failed"); - - if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) { - /* remain in active mode */ + if (!wl->psm) { wl->psm_entry_retry = 0; break; } if (wl->psm_entry_retry < wl->conf.conn.psm_entry_retries) { wl->psm_entry_retry++; - ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, - true); + ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE); } else { wl1271_error("PSM entry failed, giving up.\n"); - /* FIXME: this may need to be reconsidered. for now it - is not possible to indicate to the mac80211 - afterwards that PSM entry failed. To maximize - functionality (receiving data and remaining - associated) make sure that we are in sync with the - AP in regard of PSM mode. */ - ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE, - false); wl->psm_entry_retry = 0; + *beacon_loss = true; } break; case EVENT_ENTER_POWER_SAVE_SUCCESS: wl->psm_entry_retry = 0; - - /* enable beacon filtering */ - ret = wl1271_acx_beacon_filter_opt(wl, true); - if (ret < 0) - break; - - /* enable beacon early termination */ - ret = wl1271_acx_bet_enable(wl, true); - if (ret < 0) - break; - - /* go to extremely low power mode */ - wl1271_ps_elp_sleep(wl); - if (ret < 0) - break; break; case EVENT_EXIT_POWER_SAVE_FAIL: - wl1271_debug(DEBUG_PSM, "PSM exit failed"); - - if (test_bit(WL1271_FLAG_PSM, &wl->flags)) { - wl->psm_entry_retry = 0; - break; - } - - /* make sure the firmware goes to active mode - the frame to - be sent next will indicate to the AP, that we are active. */ - ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE, - false); + wl1271_info("PSM exit failed"); break; case EVENT_EXIT_POWER_SAVE_SUCCESS: default: @@ -173,8 +136,7 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) * filtering) is enabled. Without PSM, the stack will receive all * beacons and can detect beacon loss by itself. */ - if (vector & BSS_LOSE_EVENT_ID && - test_bit(WL1271_FLAG_PSM, &wl->flags)) { + if (vector & BSS_LOSE_EVENT_ID && wl->psm) { wl1271_debug(DEBUG_EVENT, "BSS_LOSE_EVENT"); /* indicate to the stack, that beacons have been lost */ @@ -188,7 +150,7 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) return ret; } - if (wl->vif && beacon_loss) { + if (beacon_loss) { /* Obviously, it's dangerous to release the mutex while we are holding many of the variables in the wl struct. That's why it's done last in the function, and care must @@ -215,14 +177,14 @@ int wl1271_event_unmask(struct wl1271 *wl) void wl1271_event_mbox_config(struct wl1271 *wl) { - wl->mbox_ptr[0] = wl1271_read32(wl, REG_EVENT_MAILBOX_PTR); + wl->mbox_ptr[0] = wl1271_spi_read32(wl, REG_EVENT_MAILBOX_PTR); wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox); wl1271_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x", wl->mbox_ptr[0], wl->mbox_ptr[1]); } -int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num) +int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num, bool do_ack) { struct event_mailbox mbox; int ret; @@ -233,8 +195,8 @@ int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num) return -EINVAL; /* first we read the mbox descriptor */ - wl1271_read(wl, wl->mbox_ptr[mbox_num], &mbox, - sizeof(struct event_mailbox), false); + wl1271_spi_read(wl, wl->mbox_ptr[mbox_num], &mbox, + sizeof(struct event_mailbox), false); /* process the descriptor */ ret = wl1271_event_process(wl, &mbox); @@ -242,7 +204,9 @@ int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num) return ret; /* then we let the firmware know it can go on...*/ - wl1271_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK); + if (do_ack) + wl1271_spi_write32(wl, ACX_REG_INTERRUPT_TRIG, + INTR_TRIG_EVENT_ACK); return 0; } diff --git a/trunk/drivers/net/wireless/wl12xx/wl1271_event.h b/trunk/drivers/net/wireless/wl12xx/wl1271_event.h index 278f9206aa56..4e3f55ebb1a8 100644 --- a/trunk/drivers/net/wireless/wl12xx/wl1271_event.h +++ b/trunk/drivers/net/wireless/wl12xx/wl1271_event.h @@ -112,6 +112,6 @@ struct event_mailbox { int wl1271_event_unmask(struct wl1271 *wl); void wl1271_event_mbox_config(struct wl1271 *wl); -int wl1271_event_handle(struct wl1271 *wl, u8 mbox); +int wl1271_event_handle(struct wl1271 *wl, u8 mbox, bool do_ack); #endif diff --git a/trunk/drivers/net/wireless/wl12xx/wl1271_init.c b/trunk/drivers/net/wireless/wl12xx/wl1271_init.c index 86c30a86a456..11249b436cf1 100644 --- a/trunk/drivers/net/wireless/wl12xx/wl1271_init.c +++ b/trunk/drivers/net/wireless/wl12xx/wl1271_init.c @@ -49,7 +49,7 @@ static int wl1271_init_hwenc_config(struct wl1271 *wl) return 0; } -int wl1271_init_templates_config(struct wl1271 *wl) +static int wl1271_init_templates_config(struct wl1271 *wl) { int ret; @@ -113,7 +113,7 @@ static int wl1271_init_rx_config(struct wl1271 *wl, u32 config, u32 filter) return 0; } -int wl1271_init_phy_config(struct wl1271 *wl) +static int wl1271_init_phy_config(struct wl1271 *wl) { int ret; @@ -156,7 +156,7 @@ static int wl1271_init_beacon_filter(struct wl1271 *wl) return 0; } -int wl1271_init_pta(struct wl1271 *wl) +static int wl1271_init_pta(struct wl1271 *wl) { int ret; @@ -171,7 +171,7 @@ int wl1271_init_pta(struct wl1271 *wl) return 0; } -int wl1271_init_energy_detection(struct wl1271 *wl) +static int wl1271_init_energy_detection(struct wl1271 *wl) { int ret; @@ -195,9 +195,7 @@ static int wl1271_init_beacon_broadcast(struct wl1271 *wl) int wl1271_hw_init(struct wl1271 *wl) { - struct conf_tx_ac_category *conf_ac; - struct conf_tx_tid *conf_tid; - int ret, i; + int ret; ret = wl1271_cmd_general_parms(wl); if (ret < 0) @@ -231,10 +229,6 @@ int wl1271_hw_init(struct wl1271 *wl) if (ret < 0) goto out_free_memmap; - ret = wl1271_acx_dco_itrim_params(wl); - if (ret < 0) - goto out_free_memmap; - /* Initialize connection monitoring thresholds */ ret = wl1271_acx_conn_monit_params(wl); if (ret < 0) @@ -276,36 +270,22 @@ int wl1271_hw_init(struct wl1271 *wl) goto out_free_memmap; /* Default TID configuration */ - for (i = 0; i < wl->conf.tx.tid_conf_count; i++) { - conf_tid = &wl->conf.tx.tid_conf[i]; - ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id, - conf_tid->channel_type, - conf_tid->tsid, - conf_tid->ps_scheme, - conf_tid->ack_policy, - conf_tid->apsd_conf[0], - conf_tid->apsd_conf[1]); - if (ret < 0) - goto out_free_memmap; - } + ret = wl1271_acx_tid_cfg(wl); + if (ret < 0) + goto out_free_memmap; /* Default AC configuration */ - for (i = 0; i < wl->conf.tx.ac_conf_count; i++) { - conf_ac = &wl->conf.tx.ac_conf[i]; - ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min, - conf_ac->cw_max, conf_ac->aifsn, - conf_ac->tx_op_limit); - if (ret < 0) - goto out_free_memmap; - } + ret = wl1271_acx_ac_cfg(wl); + if (ret < 0) + goto out_free_memmap; /* Configure TX rate classes */ - ret = wl1271_acx_rate_policies(wl); + ret = wl1271_acx_rate_policies(wl, CONF_TX_RATE_MASK_ALL); if (ret < 0) goto out_free_memmap; /* Enable data path */ - ret = wl1271_cmd_data_path(wl, 1); + ret = wl1271_cmd_data_path(wl, wl->channel, 1); if (ret < 0) goto out_free_memmap; @@ -319,8 +299,8 @@ int wl1271_hw_init(struct wl1271 *wl) if (ret < 0) goto out_free_memmap; - /* configure PM */ - ret = wl1271_acx_pm_config(wl); + /* Configure smart reflex */ + ret = wl1271_acx_smart_reflex(wl); if (ret < 0) goto out_free_memmap; diff --git a/trunk/drivers/net/wireless/wl12xx/wl1271_init.h b/trunk/drivers/net/wireless/wl12xx/wl1271_init.h index bc26f8c53b91..930677fbe852 100644 --- a/trunk/drivers/net/wireless/wl12xx/wl1271_init.h +++ b/trunk/drivers/net/wireless/wl12xx/wl1271_init.h @@ -27,10 +27,6 @@ #include "wl1271.h" int wl1271_hw_init_power_auth(struct wl1271 *wl); -int wl1271_init_templates_config(struct wl1271 *wl); -int wl1271_init_phy_config(struct wl1271 *wl); -int wl1271_init_pta(struct wl1271 *wl); -int wl1271_init_energy_detection(struct wl1271 *wl); int wl1271_hw_init(struct wl1271 *wl); #endif diff --git a/trunk/drivers/net/wireless/wl12xx/wl1271_io.c b/trunk/drivers/net/wireless/wl12xx/wl1271_io.c deleted file mode 100644 index 5cd94d5666c2..000000000000 --- a/trunk/drivers/net/wireless/wl12xx/wl1271_io.c +++ /dev/null @@ -1,213 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 2008-2010 Nokia Corporation - * - * Contact: Luciano Coelho - * - * 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 published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include -#include -#include -#include - -#include "wl1271.h" -#include "wl12xx_80211.h" -#include "wl1271_spi.h" -#include "wl1271_io.h" - -static int wl1271_translate_addr(struct wl1271 *wl, int addr) -{ - /* - * To translate, first check to which window of addresses the - * particular address belongs. Then subtract the starting address - * of that window from the address. Then, add offset of the - * translated region. - * - * The translated regions occur next to each other in physical device - * memory, so just add the sizes of the preceeding address regions to - * get the offset to the new region. - * - * Currently, only the two first regions are addressed, and the - * assumption is that all addresses will fall into either of those - * two. - */ - if ((addr >= wl->part.reg.start) && - (addr < wl->part.reg.start + wl->part.reg.size)) - return addr - wl->part.reg.start + wl->part.mem.size; - else - return addr - wl->part.mem.start; -} - -/* Set the SPI partitions to access the chip addresses - * - * To simplify driver code, a fixed (virtual) memory map is defined for - * register and memory addresses. Because in the chipset, in different stages - * of operation, those addresses will move around, an address translation - * mechanism is required. - * - * There are four partitions (three memory and one register partition), - * which are mapped to two different areas of the hardware memory. - * - * Virtual address - * space - * - * | | - * ...+----+--> mem.start - * Physical address ... | | - * space ... | | [PART_0] - * ... | | - * 00000000 <--+----+... ...+----+--> mem.start + mem.size - * | | ... | | - * |MEM | ... | | - * | | ... | | - * mem.size <--+----+... | | {unused area) - * | | ... | | - * |REG | ... | | - * mem.size | | ... | | - * + <--+----+... ...+----+--> reg.start - * reg.size | | ... | | - * |MEM2| ... | | [PART_1] - * | | ... | | - * ...+----+--> reg.start + reg.size - * | | - * - */ -int wl1271_set_partition(struct wl1271 *wl, - struct wl1271_partition_set *p) -{ - /* copy partition info */ - memcpy(&wl->part, p, sizeof(*p)); - - wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", - p->mem.start, p->mem.size); - wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", - p->reg.start, p->reg.size); - wl1271_debug(DEBUG_SPI, "mem2_start %08X mem2_size %08X", - p->mem2.start, p->mem2.size); - wl1271_debug(DEBUG_SPI, "mem3_start %08X mem3_size %08X", - p->mem3.start, p->mem3.size); - - /* write partition info to the chipset */ - wl1271_raw_write32(wl, HW_PART0_START_ADDR, p->mem.start); - wl1271_raw_write32(wl, HW_PART0_SIZE_ADDR, p->mem.size); - wl1271_raw_write32(wl, HW_PART1_START_ADDR, p->reg.start); - wl1271_raw_write32(wl, HW_PART1_SIZE_ADDR, p->reg.size); - wl1271_raw_write32(wl, HW_PART2_START_ADDR, p->mem2.start); - wl1271_raw_write32(wl, HW_PART2_SIZE_ADDR, p->mem2.size); - wl1271_raw_write32(wl, HW_PART3_START_ADDR, p->mem3.start); - - return 0; -} - -void wl1271_io_reset(struct wl1271 *wl) -{ - wl1271_spi_reset(wl); -} - -void wl1271_io_init(struct wl1271 *wl) -{ - wl1271_spi_init(wl); -} - -void wl1271_raw_write(struct wl1271 *wl, int addr, void *buf, - size_t len, bool fixed) -{ - wl1271_spi_raw_write(wl, addr, buf, len, fixed); -} - -void wl1271_raw_read(struct wl1271 *wl, int addr, void *buf, - size_t len, bool fixed) -{ - wl1271_spi_raw_read(wl, addr, buf, len, fixed); -} - -void wl1271_read(struct wl1271 *wl, int addr, void *buf, size_t len, - bool fixed) -{ - int physical; - - physical = wl1271_translate_addr(wl, addr); - - wl1271_spi_raw_read(wl, physical, buf, len, fixed); -} - -void wl1271_write(struct wl1271 *wl, int addr, void *buf, size_t len, - bool fixed) -{ - int physical; - - physical = wl1271_translate_addr(wl, addr); - - wl1271_spi_raw_write(wl, physical, buf, len, fixed); -} - -u32 wl1271_read32(struct wl1271 *wl, int addr) -{ - return wl1271_raw_read32(wl, wl1271_translate_addr(wl, addr)); -} - -void wl1271_write32(struct wl1271 *wl, int addr, u32 val) -{ - wl1271_raw_write32(wl, wl1271_translate_addr(wl, addr), val); -} - -void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val) -{ - /* write address >> 1 + 0x30000 to OCP_POR_CTR */ - addr = (addr >> 1) + 0x30000; - wl1271_write32(wl, OCP_POR_CTR, addr); - - /* write value to OCP_POR_WDATA */ - wl1271_write32(wl, OCP_DATA_WRITE, val); - - /* write 1 to OCP_CMD */ - wl1271_write32(wl, OCP_CMD, OCP_CMD_WRITE); -} - -u16 wl1271_top_reg_read(struct wl1271 *wl, int addr) -{ - u32 val; - int timeout = OCP_CMD_LOOP; - - /* write address >> 1 + 0x30000 to OCP_POR_CTR */ - addr = (addr >> 1) + 0x30000; - wl1271_write32(wl, OCP_POR_CTR, addr); - - /* write 2 to OCP_CMD */ - wl1271_write32(wl, OCP_CMD, OCP_CMD_READ); - - /* poll for data ready */ - do { - val = wl1271_read32(wl, OCP_DATA_READ); - } while (!(val & OCP_READY_MASK) && --timeout); - - if (!timeout) { - wl1271_warning("Top register access timed out."); - return 0xffff; - } - - /* check data status and return if OK */ - if ((val & OCP_STATUS_MASK) == OCP_STATUS_OK) - return val & 0xffff; - else { - wl1271_warning("Top register access returned error."); - return 0xffff; - } -} - diff --git a/trunk/drivers/net/wireless/wl12xx/wl1271_io.h b/trunk/drivers/net/wireless/wl12xx/wl1271_io.h deleted file mode 100644 index fa9a0b35788f..000000000000 --- a/trunk/drivers/net/wireless/wl12xx/wl1271_io.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. - * Copyright (C) 2008-2010 Nokia Corporation - * - * Contact: Luciano Coelho - * - * 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 published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL1271_IO_H__ -#define __WL1271_IO_H__ - -struct wl1271; - -void wl1271_io_reset(struct wl1271 *wl); -void wl1271_io_init(struct wl1271 *wl); - -/* Raw target IO, address is not translated */ -void wl1271_raw_write(struct wl1271 *wl, int addr, void *buf, - size_t len, bool fixed); -void wl1271_raw_read(struct wl1271 *wl, int addr, void *buf, - size_t len, bool fixed); - -/* Translated target IO */ -void wl1271_read(struct wl1271 *wl, int addr, void *buf, size_t len, - bool fixed); -void wl1271_write(struct wl1271 *wl, int addr, void *buf, size_t len, - bool fixed); -u32 wl1271_read32(struct wl1271 *wl, int addr); -void wl1271_write32(struct wl1271 *wl, int addr, u32 val); - -/* Top Register IO */ -void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val); -u16 wl1271_top_reg_read(struct wl1271 *wl, int addr); - -int wl1271_set_partition(struct wl1271 *wl, - struct wl1271_partition_set *p); - -static inline u32 wl1271_raw_read32(struct wl1271 *wl, int addr) -{ - wl1271_raw_read(wl, addr, &wl->buffer_32, - sizeof(wl->buffer_32), false); - - return wl->buffer_32; -} - -static inline void wl1271_raw_write32(struct wl1271 *wl, int addr, u32 val) -{ - wl->buffer_32 = val; - wl1271_raw_write(wl, addr, &wl->buffer_32, - sizeof(wl->buffer_32), false); -} -#endif diff --git a/trunk/drivers/net/wireless/wl12xx/wl1271_main.c b/trunk/drivers/net/wireless/wl12xx/wl1271_main.c index 2a864b24291d..b62c00ff42fe 100644 --- a/trunk/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/trunk/drivers/net/wireless/wl12xx/wl1271_main.c @@ -1,7 +1,7 @@ /* * This file is part of wl1271 * - * Copyright (C) 2008-2010 Nokia Corporation + * Copyright (C) 2008-2009 Nokia Corporation * * Contact: Luciano Coelho * @@ -38,7 +38,6 @@ #include "wl12xx_80211.h" #include "wl1271_reg.h" #include "wl1271_spi.h" -#include "wl1271_io.h" #include "wl1271_event.h" #include "wl1271_tx.h" #include "wl1271_rx.h" @@ -47,9 +46,6 @@ #include "wl1271_debugfs.h" #include "wl1271_cmd.h" #include "wl1271_boot.h" -#include "wl1271_testmode.h" - -#define WL1271_BOOT_RETRIES 3 static struct conf_drv_settings default_conf = { .sg = { @@ -71,17 +67,16 @@ static struct conf_drv_settings default_conf = { .ps_poll_timeout = 15, .upsd_timeout = 15, .rts_threshold = 2347, - .rx_cca_threshold = 0, - .irq_blk_threshold = 0xFFFF, - .irq_pkt_threshold = 0, - .irq_timeout = 600, + .rx_cca_threshold = 0xFFEF, + .irq_blk_threshold = 0, + .irq_pkt_threshold = USHORT_MAX, + .irq_timeout = 5, .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY, }, .tx = { .tx_energy_detection = 0, .rc_conf = { - .enabled_rates = CONF_HW_BIT_RATE_1MBPS | - CONF_HW_BIT_RATE_2MBPS, + .enabled_rates = CONF_TX_RATE_MASK_UNSPECIFIED, .short_retry_limit = 10, .long_retry_limit = 10, .aflags = 0 @@ -177,8 +172,8 @@ static struct conf_drv_settings default_conf = { } }, .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD, - .tx_compl_timeout = 700, - .tx_compl_threshold = 4 + .tx_compl_timeout = 5, + .tx_compl_threshold = 5 }, .conn = { .wake_up_event = CONF_WAKE_UP_EVENT_DTIM, @@ -191,12 +186,12 @@ static struct conf_drv_settings default_conf = { .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE, } }, - .synch_fail_thold = 10, + .synch_fail_thold = 5, .bss_lose_timeout = 100, .beacon_rx_timeout = 10000, .broadcast_timeout = 20000, .rx_broadcast_in_ps = 1, - .ps_poll_threshold = 20, + .ps_poll_threshold = 4, .sig_trigger_count = 2, .sig_trigger = { [0] = { @@ -231,17 +226,97 @@ static struct conf_drv_settings default_conf = { .psm_entry_retries = 3 }, .init = { + .sr_err_tbl = { + [0] = { + .len = 7, + .upper_limit = 0x03, + .values = { + 0x18, 0x10, 0x05, 0xfb, 0xf0, 0xe8, + 0x00 } + }, + [1] = { + .len = 7, + .upper_limit = 0x03, + .values = { + 0x18, 0x10, 0x05, 0xf6, 0xf0, 0xe8, + 0x00 } + }, + [2] = { + .len = 7, + .upper_limit = 0x03, + .values = { + 0x18, 0x10, 0x05, 0xfb, 0xf0, 0xe8, + 0x00 } + } + }, + .sr_enable = 1, + .genparam = { + .ref_clk = CONF_REF_CLK_38_4_E, + .settling_time = 5, + .clk_valid_on_wakeup = 0, + .dc2dcmode = 0, + .single_dual_band = CONF_SINGLE_BAND, + .tx_bip_fem_autodetect = 0, + .tx_bip_fem_manufacturer = 1, + .settings = 1, + }, .radioparam = { - .fem = 1, + .rx_trace_loss = 10, + .tx_trace_loss = 10, + .rx_rssi_and_proc_compens = { + 0xec, 0xf6, 0x00, 0x0c, 0x18, 0xf8, + 0xfc, 0x00, 0x08, 0x10, 0xf0, 0xf8, + 0x00, 0x0a, 0x14 }, + .rx_trace_loss_5 = { 0, 0, 0, 0, 0, 0, 0 }, + .tx_trace_loss_5 = { 0, 0, 0, 0, 0, 0, 0 }, + .rx_rssi_and_proc_compens_5 = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00 }, + .tx_ref_pd_voltage = 0x24e, + .tx_ref_power = 0x78, + .tx_offset_db = 0x0, + .tx_rate_limits_normal = { + 0x1e, 0x1f, 0x22, 0x24, 0x28, 0x29 }, + .tx_rate_limits_degraded = { + 0x1b, 0x1c, 0x1e, 0x20, 0x24, 0x25 }, + .tx_channel_limits_11b = { + 0x22, 0x50, 0x50, 0x50, 0x50, 0x50, + 0x50, 0x50, 0x50, 0x50, 0x22, 0x50, + 0x22, 0x50 }, + .tx_channel_limits_ofdm = { + 0x20, 0x50, 0x50, 0x50, 0x50, 0x50, + 0x50, 0x50, 0x50, 0x50, 0x20, 0x50, + 0x20, 0x50 }, + .tx_pdv_rate_offsets = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .tx_ibias = { + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x27 }, + .rx_fem_insertion_loss = 0x14, + .tx_ref_pd_voltage_5 = { + 0x0190, 0x01a4, 0x01c3, 0x01d8, + 0x020a, 0x021c }, + .tx_ref_power_5 = { + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 }, + .tx_offset_db_5 = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .tx_rate_limits_normal_5 = { + 0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 }, + .tx_rate_limits_degraded_5 = { + 0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 }, + .tx_channel_limits_ofdm_5 = { + 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, + 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, + 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, + 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, + 0x50, 0x50, 0x50 }, + .tx_pdv_rate_offsets_5 = { + 0x01, 0x02, 0x02, 0x02, 0x02, 0x00 }, + .tx_ibias_5 = { + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 }, + .rx_fem_insertion_loss_5 = { + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 } } - }, - .itrim = { - .enable = false, - .timeout = 50000, - }, - .pm_config = { - .host_clk_settling_time = 5000, - .host_fast_wakeup_support = false } }; @@ -262,14 +337,15 @@ static void wl1271_conf_init(struct wl1271 *wl) /* apply driver default configuration */ memcpy(&wl->conf, &default_conf, sizeof(default_conf)); + + if (wl1271_11a_enabled()) + wl->conf.init.genparam.single_dual_band = CONF_DUAL_BAND; } static int wl1271_plt_init(struct wl1271 *wl) { - struct conf_tx_ac_category *conf_ac; - struct conf_tx_tid *conf_tid; - int ret, i; + int ret; ret = wl1271_cmd_general_parms(wl); if (ret < 0) @@ -279,89 +355,15 @@ static int wl1271_plt_init(struct wl1271 *wl) if (ret < 0) return ret; - ret = wl1271_init_templates_config(wl); - if (ret < 0) - return ret; - ret = wl1271_acx_init_mem_config(wl); if (ret < 0) return ret; - /* PHY layer config */ - ret = wl1271_init_phy_config(wl); - if (ret < 0) - goto out_free_memmap; - - ret = wl1271_acx_dco_itrim_params(wl); - if (ret < 0) - goto out_free_memmap; - - /* Initialize connection monitoring thresholds */ - ret = wl1271_acx_conn_monit_params(wl); - if (ret < 0) - goto out_free_memmap; - - /* Bluetooth WLAN coexistence */ - ret = wl1271_init_pta(wl); - if (ret < 0) - goto out_free_memmap; - - /* Energy detection */ - ret = wl1271_init_energy_detection(wl); - if (ret < 0) - goto out_free_memmap; - - /* Default fragmentation threshold */ - ret = wl1271_acx_frag_threshold(wl); - if (ret < 0) - goto out_free_memmap; - - /* Default TID configuration */ - for (i = 0; i < wl->conf.tx.tid_conf_count; i++) { - conf_tid = &wl->conf.tx.tid_conf[i]; - ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id, - conf_tid->channel_type, - conf_tid->tsid, - conf_tid->ps_scheme, - conf_tid->ack_policy, - conf_tid->apsd_conf[0], - conf_tid->apsd_conf[1]); - if (ret < 0) - goto out_free_memmap; - } - - /* Default AC configuration */ - for (i = 0; i < wl->conf.tx.ac_conf_count; i++) { - conf_ac = &wl->conf.tx.ac_conf[i]; - ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min, - conf_ac->cw_max, conf_ac->aifsn, - conf_ac->tx_op_limit); - if (ret < 0) - goto out_free_memmap; - } - - /* Enable data path */ - ret = wl1271_cmd_data_path(wl, 1); + ret = wl1271_cmd_data_path(wl, wl->channel, 1); if (ret < 0) - goto out_free_memmap; - - /* Configure for CAM power saving (ie. always active) */ - ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM); - if (ret < 0) - goto out_free_memmap; - - /* configure PM */ - ret = wl1271_acx_pm_config(wl); - if (ret < 0) - goto out_free_memmap; + return ret; return 0; - - out_free_memmap: - kfree(wl->target_mem_map); - wl->target_mem_map = NULL; - - return ret; } static void wl1271_disable_interrupts(struct wl1271 *wl) @@ -372,13 +374,11 @@ static void wl1271_disable_interrupts(struct wl1271 *wl) static void wl1271_power_off(struct wl1271 *wl) { wl->set_power(false); - clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); } static void wl1271_power_on(struct wl1271 *wl) { wl->set_power(true); - set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); } static void wl1271_fw_status(struct wl1271 *wl, @@ -387,7 +387,8 @@ static void wl1271_fw_status(struct wl1271 *wl, u32 total = 0; int i; - wl1271_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false); + wl1271_spi_read(wl, FW_STATUS_ADDR, status, + sizeof(*status), false); wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, " "drv_rx_counter = %d, tx_results_counter = %d)", @@ -434,7 +435,7 @@ static void wl1271_irq_work(struct work_struct *work) if (ret < 0) goto out; - wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL); + wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL); wl1271_fw_status(wl, wl->fw_status); intr = le32_to_cpu(wl->fw_status->intr); @@ -446,13 +447,14 @@ static void wl1271_irq_work(struct work_struct *work) intr &= WL1271_INTR_MASK; if (intr & WL1271_ACX_INTR_EVENT_A) { + bool do_ack = (intr & WL1271_ACX_INTR_EVENT_B) ? false : true; wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A"); - wl1271_event_handle(wl, 0); + wl1271_event_handle(wl, 0, do_ack); } if (intr & WL1271_ACX_INTR_EVENT_B) { wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B"); - wl1271_event_handle(wl, 1); + wl1271_event_handle(wl, 1, true); } if (intr & WL1271_ACX_INTR_INIT_COMPLETE) @@ -476,8 +478,8 @@ static void wl1271_irq_work(struct work_struct *work) } out_sleep: - wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, - WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK)); + wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK, + WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK)); wl1271_ps_elp_sleep(wl); out: @@ -544,40 +546,6 @@ static int wl1271_fetch_firmware(struct wl1271 *wl) return ret; } -static int wl1271_update_mac_addr(struct wl1271 *wl) -{ - int ret = 0; - u8 *nvs_ptr = (u8 *)wl->nvs->nvs; - - /* get mac address from the NVS */ - wl->mac_addr[0] = nvs_ptr[11]; - wl->mac_addr[1] = nvs_ptr[10]; - wl->mac_addr[2] = nvs_ptr[6]; - wl->mac_addr[3] = nvs_ptr[5]; - wl->mac_addr[4] = nvs_ptr[4]; - wl->mac_addr[5] = nvs_ptr[3]; - - /* FIXME: if it is a zero-address, we should bail out. Now, instead, - we randomize an address */ - if (is_zero_ether_addr(wl->mac_addr)) { - static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf}; - memcpy(wl->mac_addr, nokia_oui, 3); - get_random_bytes(wl->mac_addr + 3, 3); - - /* update this address to the NVS */ - nvs_ptr[11] = wl->mac_addr[0]; - nvs_ptr[10] = wl->mac_addr[1]; - nvs_ptr[6] = wl->mac_addr[2]; - nvs_ptr[5] = wl->mac_addr[3]; - nvs_ptr[4] = wl->mac_addr[4]; - nvs_ptr[3] = wl->mac_addr[5]; - } - - SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); - - return ret; -} - static int wl1271_fetch_nvs(struct wl1271 *wl) { const struct firmware *fw; @@ -590,14 +558,15 @@ static int wl1271_fetch_nvs(struct wl1271 *wl) return ret; } - if (fw->size != sizeof(struct wl1271_nvs_file)) { - wl1271_error("nvs size is not as expected: %zu != %zu", - fw->size, sizeof(struct wl1271_nvs_file)); + if (fw->size % 4) { + wl1271_error("nvs size is not multiple of 32 bits: %zu", + fw->size); ret = -EILSEQ; goto out; } - wl->nvs = kmalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL); + wl->nvs_len = fw->size; + wl->nvs = kmalloc(wl->nvs_len, GFP_KERNEL); if (!wl->nvs) { wl1271_error("could not allocate memory for the nvs file"); @@ -605,9 +574,9 @@ static int wl1271_fetch_nvs(struct wl1271 *wl) goto out; } - memcpy(wl->nvs, fw->data, sizeof(struct wl1271_nvs_file)); + memcpy(wl->nvs, fw->data, wl->nvs_len); - ret = wl1271_update_mac_addr(wl); + ret = 0; out: release_firmware(fw); @@ -645,11 +614,10 @@ static int wl1271_chip_wakeup(struct wl1271 *wl) struct wl1271_partition_set partition; int ret = 0; - msleep(WL1271_PRE_POWER_ON_SLEEP); wl1271_power_on(wl); msleep(WL1271_POWER_ON_SLEEP); - wl1271_io_reset(wl); - wl1271_io_init(wl); + wl1271_spi_reset(wl); + wl1271_spi_init(wl); /* We don't need a real memory partition here, because we only want * to use the registers at this point. */ @@ -664,7 +632,7 @@ static int wl1271_chip_wakeup(struct wl1271 *wl) /* whal_FwCtrl_BootSm() */ /* 0. read chip id from CHIP_ID */ - wl->chip.id = wl1271_read32(wl, CHIP_ID_B); + wl->chip.id = wl1271_spi_read32(wl, CHIP_ID_B); /* 1. check if chip id is valid */ @@ -675,7 +643,7 @@ static int wl1271_chip_wakeup(struct wl1271 *wl) ret = wl1271_setup(wl); if (ret < 0) - goto out; + goto out_power_off; break; case CHIP_ID_1271_PG20: wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)", @@ -683,34 +651,38 @@ static int wl1271_chip_wakeup(struct wl1271 *wl) ret = wl1271_setup(wl); if (ret < 0) - goto out; + goto out_power_off; break; default: - wl1271_warning("unsupported chip id: 0x%x", wl->chip.id); + wl1271_error("unsupported chip id: 0x%x", wl->chip.id); ret = -ENODEV; - goto out; + goto out_power_off; } if (wl->fw == NULL) { ret = wl1271_fetch_firmware(wl); if (ret < 0) - goto out; + goto out_power_off; } /* No NVS from netlink, try to get it from the filesystem */ if (wl->nvs == NULL) { ret = wl1271_fetch_nvs(wl); if (ret < 0) - goto out; + goto out_power_off; } + goto out; + +out_power_off: + wl1271_power_off(wl); + out: return ret; } int wl1271_plt_start(struct wl1271 *wl) { - int retries = WL1271_BOOT_RETRIES; int ret; mutex_lock(&wl->mutex); @@ -724,43 +696,35 @@ int wl1271_plt_start(struct wl1271 *wl) goto out; } - while (retries) { - retries--; - ret = wl1271_chip_wakeup(wl); - if (ret < 0) - goto power_off; + wl->state = WL1271_STATE_PLT; - ret = wl1271_boot(wl); - if (ret < 0) - goto power_off; + ret = wl1271_chip_wakeup(wl); + if (ret < 0) + goto out; - ret = wl1271_plt_init(wl); - if (ret < 0) - goto irq_disable; + ret = wl1271_boot(wl); + if (ret < 0) + goto out_power_off; - wl->state = WL1271_STATE_PLT; - wl1271_notice("firmware booted in PLT mode (%s)", - wl->chip.fw_ver); - goto out; + wl1271_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver); -irq_disable: - wl1271_disable_interrupts(wl); - mutex_unlock(&wl->mutex); - /* Unlocking the mutex in the middle of handling is - inherently unsafe. In this case we deem it safe to do, - because we need to let any possibly pending IRQ out of - the system (and while we are WL1271_STATE_OFF the IRQ - work function will not do anything.) Also, any other - possible concurrent operations will fail due to the - current state, hence the wl1271 struct should be safe. */ - cancel_work_sync(&wl->irq_work); - mutex_lock(&wl->mutex); -power_off: - wl1271_power_off(wl); - } + ret = wl1271_plt_init(wl); + if (ret < 0) + goto out_irq_disable; + + /* Make sure power saving is disabled */ + ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM); + if (ret < 0) + goto out_irq_disable; + + goto out; + +out_irq_disable: + wl1271_disable_interrupts(wl); + +out_power_off: + wl1271_power_off(wl); - wl1271_error("firmware boot in PLT mode failed despite %d retries", - WL1271_BOOT_RETRIES); out: mutex_unlock(&wl->mutex); @@ -798,20 +762,7 @@ int wl1271_plt_stop(struct wl1271 *wl) static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct wl1271 *wl = hw->priv; - struct ieee80211_conf *conf = &hw->conf; - struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb); - struct ieee80211_sta *sta = txinfo->control.sta; - unsigned long flags; - - /* peek into the rates configured in the STA entry */ - spin_lock_irqsave(&wl->wl_lock, flags); - if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) { - wl->sta_rate_set = sta->supp_rates[conf->channel->band]; - set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags); - } - spin_unlock_irqrestore(&wl->wl_lock, flags); - /* queue the packet */ skb_queue_tail(&wl->tx_queue, skb); /* @@ -833,7 +784,7 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) * protected. Maybe fix this by removing the stupid * variable altogether and checking the real queue state? */ - set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags); + wl->tx_queue_stopped = true; } return NETDEV_TX_OK; @@ -929,7 +880,6 @@ static struct notifier_block wl1271_dev_notifier = { static int wl1271_op_start(struct ieee80211_hw *hw) { struct wl1271 *wl = hw->priv; - int retries = WL1271_BOOT_RETRIES; int ret = 0; wl1271_debug(DEBUG_MAC80211, "mac80211 start"); @@ -943,42 +893,30 @@ static int wl1271_op_start(struct ieee80211_hw *hw) goto out; } - while (retries) { - retries--; - ret = wl1271_chip_wakeup(wl); - if (ret < 0) - goto power_off; + ret = wl1271_chip_wakeup(wl); + if (ret < 0) + goto out; - ret = wl1271_boot(wl); - if (ret < 0) - goto power_off; + ret = wl1271_boot(wl); + if (ret < 0) + goto out_power_off; - ret = wl1271_hw_init(wl); - if (ret < 0) - goto irq_disable; + ret = wl1271_hw_init(wl); + if (ret < 0) + goto out_irq_disable; - wl->state = WL1271_STATE_ON; - wl1271_info("firmware booted (%s)", wl->chip.fw_ver); - goto out; + wl->state = WL1271_STATE_ON; -irq_disable: - wl1271_disable_interrupts(wl); - mutex_unlock(&wl->mutex); - /* Unlocking the mutex in the middle of handling is - inherently unsafe. In this case we deem it safe to do, - because we need to let any possibly pending IRQ out of - the system (and while we are WL1271_STATE_OFF the IRQ - work function will not do anything.) Also, any other - possible concurrent operations will fail due to the - current state, hence the wl1271 struct should be safe. */ - cancel_work_sync(&wl->irq_work); - mutex_lock(&wl->mutex); -power_off: - wl1271_power_off(wl); - } + wl1271_info("firmware booted (%s)", wl->chip.fw_ver); + + goto out; + +out_irq_disable: + wl1271_disable_interrupts(wl); + +out_power_off: + wl1271_power_off(wl); - wl1271_error("firmware boot failed despite %d retries", - WL1271_BOOT_RETRIES); out: mutex_unlock(&wl->mutex); @@ -1006,10 +944,11 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) WARN_ON(wl->state != WL1271_STATE_ON); - if (test_and_clear_bit(WL1271_FLAG_SCANNING, &wl->flags)) { + if (wl->scanning) { mutex_unlock(&wl->mutex); ieee80211_scan_completed(wl->hw, true); mutex_lock(&wl->mutex); + wl->scanning = false; } wl->state = WL1271_STATE_OFF; @@ -1034,7 +973,10 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) wl->band = IEEE80211_BAND_2GHZ; wl->rx_counter = 0; + wl->elp = false; + wl->psm = 0; wl->psm_entry_retry = 0; + wl->tx_queue_stopped = false; wl->power_level = WL1271_DEFAULT_POWER_LEVEL; wl->tx_blocks_available = 0; wl->tx_results_count = 0; @@ -1044,9 +986,7 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) wl->tx_security_seq_32 = 0; wl->time_offset = 0; wl->session_counter = 0; - wl->rate_set = CONF_TX_RATE_MASK_BASIC; - wl->sta_rate_set = 0; - wl->flags = 0; + wl->joined = false; for (i = 0; i < NUM_TX_QUEUES; i++) wl->tx_blocks_freed[i] = 0; @@ -1056,13 +996,13 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) } static int wl1271_op_add_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) + struct ieee80211_if_init_conf *conf) { struct wl1271 *wl = hw->priv; int ret = 0; wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", - vif->type, vif->addr); + conf->type, conf->mac_addr); mutex_lock(&wl->mutex); if (wl->vif) { @@ -1070,9 +1010,9 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, goto out; } - wl->vif = vif; + wl->vif = conf->vif; - switch (vif->type) { + switch (conf->type) { case NL80211_IFTYPE_STATION: wl->bss_type = BSS_TYPE_STA_BSS; break; @@ -1092,7 +1032,7 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, } static void wl1271_op_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) + struct ieee80211_if_init_conf *conf) { struct wl1271 *wl = hw->priv; @@ -1169,51 +1109,6 @@ static int wl1271_op_config_interface(struct ieee80211_hw *hw, } #endif -static int wl1271_join_channel(struct wl1271 *wl, int channel) -{ - int ret = 0; - /* we need to use a dummy BSSID for now */ - static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde, - 0xad, 0xbe, 0xef }; - - /* the dummy join is not required for ad-hoc */ - if (wl->bss_type == BSS_TYPE_IBSS) - goto out; - - /* disable mac filter, so we hear everything */ - wl->rx_config &= ~CFG_BSSID_FILTER_EN; - - wl->channel = channel; - memcpy(wl->bssid, dummy_bssid, ETH_ALEN); - - ret = wl1271_cmd_join(wl); - if (ret < 0) - goto out; - - set_bit(WL1271_FLAG_JOINED, &wl->flags); - -out: - return ret; -} - -static int wl1271_unjoin_channel(struct wl1271 *wl) -{ - int ret; - - /* to stop listening to a channel, we disconnect */ - ret = wl1271_cmd_disconnect(wl); - if (ret < 0) - goto out; - - clear_bit(WL1271_FLAG_JOINED, &wl->flags); - wl->channel = 0; - memset(wl->bssid, 0, ETH_ALEN); - wl->rx_config = WL1271_DEFAULT_RX_CONFIG; - -out: - return ret; -} - static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) { struct wl1271 *wl = hw->priv; @@ -1222,11 +1117,10 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) channel = ieee80211_frequency_to_channel(conf->channel->center_freq); - wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s", + wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d", channel, conf->flags & IEEE80211_CONF_PS ? "on" : "off", - conf->power_level, - conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use"); + conf->power_level); mutex_lock(&wl->mutex); @@ -1236,55 +1130,35 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) if (ret < 0) goto out; - if (changed & IEEE80211_CONF_CHANGE_IDLE) { - if (conf->flags & IEEE80211_CONF_IDLE && - test_bit(WL1271_FLAG_JOINED, &wl->flags)) - wl1271_unjoin_channel(wl); - else if (!(conf->flags & IEEE80211_CONF_IDLE)) - wl1271_join_channel(wl, channel); - - if (conf->flags & IEEE80211_CONF_IDLE) { - wl->rate_set = CONF_TX_RATE_MASK_BASIC; - wl->sta_rate_set = 0; - wl1271_acx_rate_policies(wl); - } + if (channel != wl->channel) { + /* + * We assume that the stack will configure the right channel + * before associating, so we don't need to send a join + * command here. We will join the right channel when the + * BSSID changes + */ + wl->channel = channel; } - /* if the channel changes while joined, join again */ - if (channel != wl->channel && - test_bit(WL1271_FLAG_JOINED, &wl->flags)) { - wl->channel = channel; - /* FIXME: maybe use CMD_CHANNEL_SWITCH for this? */ - ret = wl1271_cmd_join(wl); - if (ret < 0) - wl1271_warning("cmd join to update channel failed %d", - ret); - } else - wl->channel = channel; + if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) { + wl1271_info("psm enabled"); - if (conf->flags & IEEE80211_CONF_PS && - !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) { - set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags); + wl->psm_requested = true; /* * We enter PSM only if we're already associated. * If we're not, we'll enter it when joining an SSID, * through the bss_info_changed() hook. */ - if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) { - wl1271_info("psm enabled"); - ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, - true); - } + ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE); } else if (!(conf->flags & IEEE80211_CONF_PS) && - test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) { + wl->psm_requested) { wl1271_info("psm disabled"); - clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags); + wl->psm_requested = false; - if (test_bit(WL1271_FLAG_PSM, &wl->flags)) - ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE, - true); + if (wl->psm) + ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE); } if (conf->power_level != wl->power_level) { @@ -1476,24 +1350,9 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, wl1271_error("Could not add or replace key"); goto out_sleep; } - - /* the default WEP key needs to be configured at least once */ - if (key_type == KEY_WEP) { - ret = wl1271_cmd_set_default_wep_key(wl, - wl->default_key); - if (ret < 0) - goto out_sleep; - } break; case DISABLE_KEY: - /* The wl1271 does not allow to remove unicast keys - they - will be cleared automatically on next CMD_JOIN. Ignore the - request silently, as we dont want the mac80211 to emit - an error message. */ - if (!is_broadcast_ether_addr(addr)) - break; - ret = wl1271_cmd_set_key(wl, KEY_REMOVE, key_conf->keyidx, key_type, key_conf->keylen, key_conf->key, @@ -1581,21 +1440,20 @@ static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) return ret; } -static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon) +static u32 wl1271_enabled_rates_get(struct wl1271 *wl, u64 basic_rate_set) { - u8 *ptr = beacon->data + - offsetof(struct ieee80211_mgmt, u.beacon.variable); - - /* find the location of the ssid in the beacon */ - while (ptr < beacon->data + beacon->len) { - if (ptr[0] == WLAN_EID_SSID) { - wl->ssid_len = ptr[1]; - memcpy(wl->ssid, ptr+2, wl->ssid_len); - return; - } - ptr += ptr[1]; + struct ieee80211_supported_band *band; + u32 enabled_rates = 0; + int bit; + + band = wl->hw->wiphy->bands[wl->band]; + for (bit = 0; bit < band->n_bitrates; bit++) { + if (basic_rate_set & 0x1) + enabled_rates |= band->bitrates[bit].hw_value; + basic_rate_set >>= 1; } - wl1271_error("ad-hoc beacon template has no SSID!\n"); + + return enabled_rates; } static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, @@ -1605,7 +1463,6 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, { enum wl1271_cmd_ps_mode mode; struct wl1271 *wl = hw->priv; - bool do_join = false; int ret; wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed"); @@ -1616,67 +1473,9 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, if (ret < 0) goto out; - if (wl->bss_type == BSS_TYPE_IBSS) { - /* FIXME: This implements rudimentary ad-hoc support - - proper templates are on the wish list and notification - on when they change. This patch will update the templates - on every call to this function. */ - struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); - - if (beacon) { - struct ieee80211_hdr *hdr; - - wl1271_ssid_set(wl, beacon); - ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON, - beacon->data, - beacon->len); - - if (ret < 0) { - dev_kfree_skb(beacon); - goto out_sleep; - } - - hdr = (struct ieee80211_hdr *) beacon->data; - hdr->frame_control = cpu_to_le16( - IEEE80211_FTYPE_MGMT | - IEEE80211_STYPE_PROBE_RESP); - - ret = wl1271_cmd_template_set(wl, - CMD_TEMPL_PROBE_RESPONSE, - beacon->data, - beacon->len); - dev_kfree_skb(beacon); - if (ret < 0) - goto out_sleep; - - /* Need to update the SSID (for filtering etc) */ - do_join = true; - } - } - - if ((changed & BSS_CHANGED_BSSID) && - /* - * Now we know the correct bssid, so we send a new join command - * and enable the BSSID filter - */ - memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) { - wl->rx_config |= CFG_BSSID_FILTER_EN; - memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN); - ret = wl1271_cmd_build_null_data(wl); - if (ret < 0) { - wl1271_warning("cmd buld null data failed %d", - ret); - goto out_sleep; - } - - /* Need to update the BSSID (for filtering etc) */ - do_join = true; - } - if (changed & BSS_CHANGED_ASSOC) { if (bss_conf->assoc) { wl->aid = bss_conf->aid; - set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags); /* * with wl1271, we don't need to update the @@ -1693,16 +1492,15 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, goto out_sleep; /* If we want to go in PSM but we're not there yet */ - if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) && - !test_bit(WL1271_FLAG_PSM, &wl->flags)) { + if (wl->psm_requested && !wl->psm) { mode = STATION_POWER_SAVE_MODE; - ret = wl1271_ps_set_mode(wl, mode, true); + ret = wl1271_ps_set_mode(wl, mode); if (ret < 0) goto out_sleep; } } else { /* use defaults when not associated */ - clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags); + wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET; wl->aid = 0; } @@ -1737,13 +1535,15 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, } } - if (do_join) { - ret = wl1271_cmd_join(wl); + if (changed & BSS_CHANGED_BASIC_RATES) { + wl->basic_rate_set = wl1271_enabled_rates_get( + wl, bss_conf->basic_rates); + + ret = wl1271_acx_rate_policies(wl, wl->basic_rate_set); if (ret < 0) { - wl1271_warning("cmd join failed %d", ret); + wl1271_warning("Set rate policies failed %d", ret); goto out_sleep; } - set_bit(WL1271_FLAG_JOINED, &wl->flags); } out_sleep: @@ -1753,43 +1553,6 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, mutex_unlock(&wl->mutex); } -static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue, - const struct ieee80211_tx_queue_params *params) -{ - struct wl1271 *wl = hw->priv; - int ret; - - mutex_lock(&wl->mutex); - - wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue); - - ret = wl1271_ps_elp_wakeup(wl, false); - if (ret < 0) - goto out; - - ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue), - params->cw_min, params->cw_max, - params->aifs, params->txop); - if (ret < 0) - goto out_sleep; - - ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue), - CONF_CHANNEL_TYPE_EDCF, - wl1271_tx_get_queue(queue), - CONF_PS_SCHEME_LEGACY_PSPOLL, - CONF_ACK_POLICY_LEGACY, 0, 0); - if (ret < 0) - goto out_sleep; - -out_sleep: - wl1271_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); - - return ret; -} - /* can't be const, mac80211 writes to this */ static struct ieee80211_rate wl1271_rates[] = { @@ -1836,19 +1599,19 @@ static struct ieee80211_rate wl1271_rates[] = { /* can't be const, mac80211 writes to this */ static struct ieee80211_channel wl1271_channels[] = { - { .hw_value = 1, .center_freq = 2412, .max_power = 25 }, - { .hw_value = 2, .center_freq = 2417, .max_power = 25 }, - { .hw_value = 3, .center_freq = 2422, .max_power = 25 }, - { .hw_value = 4, .center_freq = 2427, .max_power = 25 }, - { .hw_value = 5, .center_freq = 2432, .max_power = 25 }, - { .hw_value = 6, .center_freq = 2437, .max_power = 25 }, - { .hw_value = 7, .center_freq = 2442, .max_power = 25 }, - { .hw_value = 8, .center_freq = 2447, .max_power = 25 }, - { .hw_value = 9, .center_freq = 2452, .max_power = 25 }, - { .hw_value = 10, .center_freq = 2457, .max_power = 25 }, - { .hw_value = 11, .center_freq = 2462, .max_power = 25 }, - { .hw_value = 12, .center_freq = 2467, .max_power = 25 }, - { .hw_value = 13, .center_freq = 2472, .max_power = 25 }, + { .hw_value = 1, .center_freq = 2412}, + { .hw_value = 2, .center_freq = 2417}, + { .hw_value = 3, .center_freq = 2422}, + { .hw_value = 4, .center_freq = 2427}, + { .hw_value = 5, .center_freq = 2432}, + { .hw_value = 6, .center_freq = 2437}, + { .hw_value = 7, .center_freq = 2442}, + { .hw_value = 8, .center_freq = 2447}, + { .hw_value = 9, .center_freq = 2452}, + { .hw_value = 10, .center_freq = 2457}, + { .hw_value = 11, .center_freq = 2462}, + { .hw_value = 12, .center_freq = 2467}, + { .hw_value = 13, .center_freq = 2472}, }; /* can't be const, mac80211 writes to this */ @@ -1955,8 +1718,6 @@ static const struct ieee80211_ops wl1271_ops = { .hw_scan = wl1271_op_hw_scan, .bss_info_changed = wl1271_op_bss_info_changed, .set_rts_threshold = wl1271_op_set_rts_threshold, - .conf_tx = wl1271_op_conf_tx, - CFG80211_TESTMODE_CMD(wl1271_tm_cmd) }; static int wl1271_register_hw(struct wl1271 *wl) @@ -1996,8 +1757,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) IEEE80211_HW_BEACON_FILTER | IEEE80211_HW_SUPPORTS_PS; - wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC); + wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); wl->hw->wiphy->max_scan_ssids = 1; wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz; @@ -2025,17 +1785,24 @@ static struct platform_device wl1271_device = { }; #define WL1271_DEFAULT_CHANNEL 0 - -static struct ieee80211_hw *wl1271_alloc_hw(void) +static int __devinit wl1271_probe(struct spi_device *spi) { + struct wl12xx_platform_data *pdata; struct ieee80211_hw *hw; struct wl1271 *wl; - int i; + int ret, i; + static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf}; + + pdata = spi->dev.platform_data; + if (!pdata) { + wl1271_error("no platform data"); + return -ENODEV; + } hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops); if (!hw) { wl1271_error("could not alloc ieee80211_hw"); - return ERR_PTR(-ENOMEM); + return -ENOMEM; } wl = hw->priv; @@ -2044,80 +1811,44 @@ static struct ieee80211_hw *wl1271_alloc_hw(void) INIT_LIST_HEAD(&wl->list); wl->hw = hw; + dev_set_drvdata(&spi->dev, wl); + wl->spi = spi; skb_queue_head_init(&wl->tx_queue); INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work); wl->channel = WL1271_DEFAULT_CHANNEL; + wl->scanning = false; wl->default_key = 0; wl->rx_counter = 0; wl->rx_config = WL1271_DEFAULT_RX_CONFIG; wl->rx_filter = WL1271_DEFAULT_RX_FILTER; + wl->elp = false; + wl->psm = 0; + wl->psm_requested = false; wl->psm_entry_retry = 0; + wl->tx_queue_stopped = false; wl->power_level = WL1271_DEFAULT_POWER_LEVEL; - wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC; - wl->rate_set = CONF_TX_RATE_MASK_BASIC; - wl->sta_rate_set = 0; + wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET; wl->band = IEEE80211_BAND_2GHZ; wl->vif = NULL; - wl->flags = 0; + wl->joined = false; for (i = 0; i < ACX_TX_DESCRIPTORS; i++) wl->tx_frames[i] = NULL; spin_lock_init(&wl->wl_lock); + /* + * In case our MAC address is not correctly set, + * we use a random but Nokia MAC. + */ + memcpy(wl->mac_addr, nokia_oui, 3); + get_random_bytes(wl->mac_addr + 3, 3); + wl->state = WL1271_STATE_OFF; mutex_init(&wl->mutex); - /* Apply default driver configuration. */ - wl1271_conf_init(wl); - - return hw; -} - -int wl1271_free_hw(struct wl1271 *wl) -{ - ieee80211_unregister_hw(wl->hw); - - wl1271_debugfs_exit(wl); - - kfree(wl->target_mem_map); - vfree(wl->fw); - wl->fw = NULL; - kfree(wl->nvs); - wl->nvs = NULL; - - kfree(wl->fw_status); - kfree(wl->tx_res_if); - - ieee80211_free_hw(wl->hw); - - return 0; -} - -static int __devinit wl1271_probe(struct spi_device *spi) -{ - struct wl12xx_platform_data *pdata; - struct ieee80211_hw *hw; - struct wl1271 *wl; - int ret; - - pdata = spi->dev.platform_data; - if (!pdata) { - wl1271_error("no platform data"); - return -ENODEV; - } - - hw = wl1271_alloc_hw(); - if (IS_ERR(hw)) - return PTR_ERR(hw); - - wl = hw->priv; - - dev_set_drvdata(&spi->dev, wl); - wl->spi = spi; - /* This is the only SPI value that we need to set here, the rest * comes from the board-peripherals file */ spi->bits_per_word = 32; @@ -2159,6 +1890,9 @@ static int __devinit wl1271_probe(struct spi_device *spi) } dev_set_drvdata(&wl1271_device.dev, wl); + /* Apply default driver configuration. */ + wl1271_conf_init(wl); + ret = wl1271_init_ieee80211(wl); if (ret) goto out_platform; @@ -2189,10 +1923,21 @@ static int __devexit wl1271_remove(struct spi_device *spi) { struct wl1271 *wl = dev_get_drvdata(&spi->dev); + ieee80211_unregister_hw(wl->hw); + + wl1271_debugfs_exit(wl); platform_device_unregister(&wl1271_device); free_irq(wl->irq, wl); + kfree(wl->target_mem_map); + vfree(wl->fw); + wl->fw = NULL; + kfree(wl->nvs); + wl->nvs = NULL; - wl1271_free_hw(wl); + kfree(wl->fw_status); + kfree(wl->tx_res_if); + + ieee80211_free_hw(wl->hw); return 0; } diff --git a/trunk/drivers/net/wireless/wl12xx/wl1271_ps.c b/trunk/drivers/net/wireless/wl12xx/wl1271_ps.c index e2b1ebf096e8..507cd91d7eed 100644 --- a/trunk/drivers/net/wireless/wl12xx/wl1271_ps.c +++ b/trunk/drivers/net/wireless/wl12xx/wl1271_ps.c @@ -24,7 +24,6 @@ #include "wl1271_reg.h" #include "wl1271_ps.h" #include "wl1271_spi.h" -#include "wl1271_io.h" #define WL1271_WAKEUP_TIMEOUT 500 @@ -40,13 +39,12 @@ void wl1271_elp_work(struct work_struct *work) mutex_lock(&wl->mutex); - if (test_bit(WL1271_FLAG_IN_ELP, &wl->flags) || - !test_bit(WL1271_FLAG_PSM, &wl->flags)) + if (wl->elp || !wl->psm) goto out; wl1271_debug(DEBUG_PSM, "chip to elp"); wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP); - set_bit(WL1271_FLAG_IN_ELP, &wl->flags); + wl->elp = true; out: mutex_unlock(&wl->mutex); @@ -57,7 +55,7 @@ void wl1271_elp_work(struct work_struct *work) /* Routines to toggle sleep mode while in ELP */ void wl1271_ps_elp_sleep(struct wl1271 *wl) { - if (test_bit(WL1271_FLAG_PSM, &wl->flags)) { + if (wl->psm) { cancel_delayed_work(&wl->elp_work); ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, msecs_to_jiffies(ELP_ENTRY_DELAY)); @@ -72,7 +70,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake) u32 start_time = jiffies; bool pending = false; - if (!test_bit(WL1271_FLAG_IN_ELP, &wl->flags)) + if (!wl->elp) return 0; wl1271_debug(DEBUG_PSM, "waking up chip from elp"); @@ -103,7 +101,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake) } } - clear_bit(WL1271_FLAG_IN_ELP, &wl->flags); + wl->elp = false; wl1271_debug(DEBUG_PSM, "wakeup time: %u ms", jiffies_to_msecs(jiffies - start_time)); @@ -119,8 +117,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake) return 0; } -int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode, - bool send) +int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode) { int ret; @@ -128,11 +125,25 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode, case STATION_POWER_SAVE_MODE: wl1271_debug(DEBUG_PSM, "entering psm"); - ret = wl1271_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE, send); + /* enable beacon filtering */ + ret = wl1271_acx_beacon_filter_opt(wl, true); if (ret < 0) return ret; - set_bit(WL1271_FLAG_PSM, &wl->flags); + /* enable beacon early termination */ + ret = wl1271_acx_bet_enable(wl, true); + if (ret < 0) + return ret; + + ret = wl1271_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE); + if (ret < 0) + return ret; + + wl1271_ps_elp_sleep(wl); + if (ret < 0) + return ret; + + wl->psm = 1; break; case STATION_ACTIVE_MODE: default: @@ -151,11 +162,11 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode, if (ret < 0) return ret; - ret = wl1271_cmd_ps_mode(wl, STATION_ACTIVE_MODE, send); + ret = wl1271_cmd_ps_mode(wl, STATION_ACTIVE_MODE); if (ret < 0) return ret; - clear_bit(WL1271_FLAG_PSM, &wl->flags); + wl->psm = 0; break; } diff --git a/trunk/drivers/net/wireless/wl12xx/wl1271_ps.h b/trunk/drivers/net/wireless/wl12xx/wl1271_ps.h index 940276f517a4..779653d0ae85 100644 --- a/trunk/drivers/net/wireless/wl12xx/wl1271_ps.h +++ b/trunk/drivers/net/wireless/wl12xx/wl1271_ps.h @@ -27,8 +27,7 @@ #include "wl1271.h" #include "wl1271_acx.h" -int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode, - bool send); +int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode); void wl1271_ps_elp_sleep(struct wl1271 *wl); int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake); void wl1271_elp_work(struct work_struct *work); diff --git a/trunk/drivers/net/wireless/wl12xx/wl1271_reg.h b/trunk/drivers/net/wireless/wl12xx/wl1271_reg.h index 990960771528..1f237389d1c7 100644 --- a/trunk/drivers/net/wireless/wl12xx/wl1271_reg.h +++ b/trunk/drivers/net/wireless/wl12xx/wl1271_reg.h @@ -62,10 +62,73 @@ #define WL1271_SLV_REG_DATA (REGISTERS_BASE + 0x0008) #define WL1271_SLV_REG_ADATA (REGISTERS_BASE + 0x000c) #define WL1271_SLV_MEM_DATA (REGISTERS_BASE + 0x0018) +/* + * Interrupt registers. + * 64 bit interrupt sources registers ws ced. + * sme interupts were removed and new ones were added. + * Order was changed. + */ +#define FIQ_MASK (REGISTERS_BASE + 0x0400) +#define FIQ_MASK_L (REGISTERS_BASE + 0x0400) +#define FIQ_MASK_H (REGISTERS_BASE + 0x0404) +#define FIQ_MASK_SET (REGISTERS_BASE + 0x0408) +#define FIQ_MASK_SET_L (REGISTERS_BASE + 0x0408) +#define FIQ_MASK_SET_H (REGISTERS_BASE + 0x040C) +#define FIQ_MASK_CLR (REGISTERS_BASE + 0x0410) +#define FIQ_MASK_CLR_L (REGISTERS_BASE + 0x0410) +#define FIQ_MASK_CLR_H (REGISTERS_BASE + 0x0414) +#define IRQ_MASK (REGISTERS_BASE + 0x0418) +#define IRQ_MASK_L (REGISTERS_BASE + 0x0418) +#define IRQ_MASK_H (REGISTERS_BASE + 0x041C) +#define IRQ_MASK_SET (REGISTERS_BASE + 0x0420) +#define IRQ_MASK_SET_L (REGISTERS_BASE + 0x0420) +#define IRQ_MASK_SET_H (REGISTERS_BASE + 0x0424) +#define IRQ_MASK_CLR (REGISTERS_BASE + 0x0428) +#define IRQ_MASK_CLR_L (REGISTERS_BASE + 0x0428) +#define IRQ_MASK_CLR_H (REGISTERS_BASE + 0x042C) +#define ECPU_MASK (REGISTERS_BASE + 0x0448) +#define FIQ_STS_L (REGISTERS_BASE + 0x044C) +#define FIQ_STS_H (REGISTERS_BASE + 0x0450) +#define IRQ_STS_L (REGISTERS_BASE + 0x0454) +#define IRQ_STS_H (REGISTERS_BASE + 0x0458) +#define INT_STS_ND (REGISTERS_BASE + 0x0464) +#define INT_STS_RAW_L (REGISTERS_BASE + 0x0464) +#define INT_STS_RAW_H (REGISTERS_BASE + 0x0468) +#define INT_STS_CLR (REGISTERS_BASE + 0x04B4) +#define INT_STS_CLR_L (REGISTERS_BASE + 0x04B4) +#define INT_STS_CLR_H (REGISTERS_BASE + 0x04B8) +#define INT_ACK (REGISTERS_BASE + 0x046C) +#define INT_ACK_L (REGISTERS_BASE + 0x046C) +#define INT_ACK_H (REGISTERS_BASE + 0x0470) +#define INT_TRIG (REGISTERS_BASE + 0x0474) +#define INT_TRIG_L (REGISTERS_BASE + 0x0474) +#define INT_TRIG_H (REGISTERS_BASE + 0x0478) +#define HOST_STS_L (REGISTERS_BASE + 0x045C) +#define HOST_STS_H (REGISTERS_BASE + 0x0460) +#define HOST_MASK (REGISTERS_BASE + 0x0430) +#define HOST_MASK_L (REGISTERS_BASE + 0x0430) +#define HOST_MASK_H (REGISTERS_BASE + 0x0434) +#define HOST_MASK_SET (REGISTERS_BASE + 0x0438) +#define HOST_MASK_SET_L (REGISTERS_BASE + 0x0438) +#define HOST_MASK_SET_H (REGISTERS_BASE + 0x043C) +#define HOST_MASK_CLR (REGISTERS_BASE + 0x0440) +#define HOST_MASK_CLR_L (REGISTERS_BASE + 0x0440) +#define HOST_MASK_CLR_H (REGISTERS_BASE + 0x0444) #define ACX_REG_INTERRUPT_TRIG (REGISTERS_BASE + 0x0474) #define ACX_REG_INTERRUPT_TRIG_H (REGISTERS_BASE + 0x0478) +/* Host Interrupts*/ +#define HINT_MASK (REGISTERS_BASE + 0x0494) +#define HINT_MASK_SET (REGISTERS_BASE + 0x0498) +#define HINT_MASK_CLR (REGISTERS_BASE + 0x049C) +#define HINT_STS_ND_MASKED (REGISTERS_BASE + 0x04A0) +/*1150 spec calls this HINT_STS_RAW*/ +#define HINT_STS_ND (REGISTERS_BASE + 0x04B0) +#define HINT_STS_CLR (REGISTERS_BASE + 0x04A4) +#define HINT_ACK (REGISTERS_BASE + 0x04A8) +#define HINT_TRIG (REGISTERS_BASE + 0x04AC) + /*============================================= Host Interrupt Mask Register - 32bit (RW) ------------------------------------------ @@ -369,6 +432,16 @@ | CFG_RX_PRSP_EN) +/*=============================================== + Phy regs + ===============================================*/ +#define ACX_PHY_ADDR_REG SBB_ADDR +#define ACX_PHY_DATA_REG SBB_DATA +#define ACX_PHY_CTRL_REG SBB_CTL +#define ACX_PHY_REG_WR_MASK 0x00000001ul +#define ACX_PHY_REG_RD_MASK 0x00000002ul + + /*=============================================== EEPROM Read/Write Request 32bit RW ------------------------------------------ @@ -438,6 +511,28 @@ #define ACX_CONT_WIND_MIN_MASK 0x0000007f #define ACX_CONT_WIND_MAX 0x03ff0000 +/* + * Indirect slave register/memory registers + * ---------------------------------------- + */ +#define HW_SLAVE_REG_ADDR_REG 0x00000004 +#define HW_SLAVE_REG_DATA_REG 0x00000008 +#define HW_SLAVE_REG_CTRL_REG 0x0000000c + +#define SLAVE_AUTO_INC 0x00010000 +#define SLAVE_NO_AUTO_INC 0x00000000 +#define SLAVE_HOST_LITTLE_ENDIAN 0x00000000 + +#define HW_SLAVE_MEM_ADDR_REG SLV_MEM_ADDR +#define HW_SLAVE_MEM_DATA_REG SLV_MEM_DATA +#define HW_SLAVE_MEM_CTRL_REG SLV_MEM_CTL +#define HW_SLAVE_MEM_ENDIAN_REG SLV_END_CTL + +#define HW_FUNC_EVENT_INT_EN 0x8000 +#define HW_FUNC_EVENT_MASK_REG 0x00000034 + +#define ACX_MAC_TIMESTAMP_REG (MAC_TIMESTAMP) + /*=============================================== HI_CFG Interface Configuration Register Values ------------------------------------------ @@ -552,6 +647,10 @@ b12-b0 - Supported Rate indicator bits as defined below. ******************************************************************************/ +#define TNETW1251_CHIP_ID_PG1_0 0x07010101 +#define TNETW1251_CHIP_ID_PG1_1 0x07020101 +#define TNETW1251_CHIP_ID_PG1_2 0x07030101 + /************************************************************************* Interrupt Trigger Register (Host -> WiLink) diff --git a/trunk/drivers/net/wireless/wl12xx/wl1271_rx.c b/trunk/drivers/net/wireless/wl12xx/wl1271_rx.c index 6730f5b96e76..ca645f38109b 100644 --- a/trunk/drivers/net/wireless/wl12xx/wl1271_rx.c +++ b/trunk/drivers/net/wireless/wl12xx/wl1271_rx.c @@ -26,7 +26,6 @@ #include "wl1271_reg.h" #include "wl1271_rx.h" #include "wl1271_spi.h" -#include "wl1271_io.h" static u8 wl1271_rx_get_mem_block(struct wl1271_fw_status *status, u32 drv_rx_counter) @@ -167,7 +166,7 @@ static void wl1271_rx_handle_data(struct wl1271 *wl, u32 length) } buf = skb_put(skb, length); - wl1271_read(wl, WL1271_SLV_MEM_DATA, buf, length, true); + wl1271_spi_read(wl, WL1271_SLV_MEM_DATA, buf, length, true); /* the data read starts with the descriptor */ desc = (struct wl1271_rx_descriptor *) buf; @@ -211,13 +210,15 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status) wl->rx_mem_pool_addr.addr + 4; /* Choose the block we want to read */ - wl1271_write(wl, WL1271_SLV_REG_DATA, &wl->rx_mem_pool_addr, - sizeof(wl->rx_mem_pool_addr), false); + wl1271_spi_write(wl, WL1271_SLV_REG_DATA, + &wl->rx_mem_pool_addr, + sizeof(wl->rx_mem_pool_addr), false); wl1271_rx_handle_data(wl, buf_size); wl->rx_counter++; drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK; - wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter); } + + wl1271_spi_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter); } diff --git a/trunk/drivers/net/wireless/wl12xx/wl1271_spi.c b/trunk/drivers/net/wireless/wl12xx/wl1271_spi.c index 67a82934f36e..02978a16e732 100644 --- a/trunk/drivers/net/wireless/wl12xx/wl1271_spi.c +++ b/trunk/drivers/net/wireless/wl12xx/wl1271_spi.c @@ -30,6 +30,28 @@ #include "wl12xx_80211.h" #include "wl1271_spi.h" +static int wl1271_translate_addr(struct wl1271 *wl, int addr) +{ + /* + * To translate, first check to which window of addresses the + * particular address belongs. Then subtract the starting address + * of that window from the address. Then, add offset of the + * translated region. + * + * The translated regions occur next to each other in physical device + * memory, so just add the sizes of the preceeding address regions to + * get the offset to the new region. + * + * Currently, only the two first regions are addressed, and the + * assumption is that all addresses will fall into either of those + * two. + */ + if ((addr >= wl->part.reg.start) && + (addr < wl->part.reg.start + wl->part.reg.size)) + return addr - wl->part.reg.start + wl->part.mem.size; + else + return addr - wl->part.mem.start; +} void wl1271_spi_reset(struct wl1271 *wl) { @@ -111,6 +133,67 @@ void wl1271_spi_init(struct wl1271 *wl) wl1271_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN); } +/* Set the SPI partitions to access the chip addresses + * + * To simplify driver code, a fixed (virtual) memory map is defined for + * register and memory addresses. Because in the chipset, in different stages + * of operation, those addresses will move around, an address translation + * mechanism is required. + * + * There are four partitions (three memory and one register partition), + * which are mapped to two different areas of the hardware memory. + * + * Virtual address + * space + * + * | | + * ...+----+--> mem.start + * Physical address ... | | + * space ... | | [PART_0] + * ... | | + * 00000000 <--+----+... ...+----+--> mem.start + mem.size + * | | ... | | + * |MEM | ... | | + * | | ... | | + * mem.size <--+----+... | | {unused area) + * | | ... | | + * |REG | ... | | + * mem.size | | ... | | + * + <--+----+... ...+----+--> reg.start + * reg.size | | ... | | + * |MEM2| ... | | [PART_1] + * | | ... | | + * ...+----+--> reg.start + reg.size + * | | + * + */ +int wl1271_set_partition(struct wl1271 *wl, + struct wl1271_partition_set *p) +{ + /* copy partition info */ + memcpy(&wl->part, p, sizeof(*p)); + + wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + p->mem.start, p->mem.size); + wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + p->reg.start, p->reg.size); + wl1271_debug(DEBUG_SPI, "mem2_start %08X mem2_size %08X", + p->mem2.start, p->mem2.size); + wl1271_debug(DEBUG_SPI, "mem3_start %08X mem3_size %08X", + p->mem3.start, p->mem3.size); + + /* write partition info to the chipset */ + wl1271_raw_write32(wl, HW_PART0_START_ADDR, p->mem.start); + wl1271_raw_write32(wl, HW_PART0_SIZE_ADDR, p->mem.size); + wl1271_raw_write32(wl, HW_PART1_START_ADDR, p->reg.start); + wl1271_raw_write32(wl, HW_PART1_SIZE_ADDR, p->reg.size); + wl1271_raw_write32(wl, HW_PART2_START_ADDR, p->mem2.start); + wl1271_raw_write32(wl, HW_PART2_SIZE_ADDR, p->mem2.size); + wl1271_raw_write32(wl, HW_PART3_START_ADDR, p->mem3.start); + + return 0; +} + #define WL1271_BUSY_WORD_TIMEOUT 1000 /* FIXME: Check busy words, removed due to SPI bug */ @@ -255,3 +338,78 @@ void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf, wl1271_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); wl1271_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); } + +void wl1271_spi_read(struct wl1271 *wl, int addr, void *buf, size_t len, + bool fixed) +{ + int physical; + + physical = wl1271_translate_addr(wl, addr); + + wl1271_spi_raw_read(wl, physical, buf, len, fixed); +} + +void wl1271_spi_write(struct wl1271 *wl, int addr, void *buf, size_t len, + bool fixed) +{ + int physical; + + physical = wl1271_translate_addr(wl, addr); + + wl1271_spi_raw_write(wl, physical, buf, len, fixed); +} + +u32 wl1271_spi_read32(struct wl1271 *wl, int addr) +{ + return wl1271_raw_read32(wl, wl1271_translate_addr(wl, addr)); +} + +void wl1271_spi_write32(struct wl1271 *wl, int addr, u32 val) +{ + wl1271_raw_write32(wl, wl1271_translate_addr(wl, addr), val); +} + +void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val) +{ + /* write address >> 1 + 0x30000 to OCP_POR_CTR */ + addr = (addr >> 1) + 0x30000; + wl1271_spi_write32(wl, OCP_POR_CTR, addr); + + /* write value to OCP_POR_WDATA */ + wl1271_spi_write32(wl, OCP_DATA_WRITE, val); + + /* write 1 to OCP_CMD */ + wl1271_spi_write32(wl, OCP_CMD, OCP_CMD_WRITE); +} + +u16 wl1271_top_reg_read(struct wl1271 *wl, int addr) +{ + u32 val; + int timeout = OCP_CMD_LOOP; + + /* write address >> 1 + 0x30000 to OCP_POR_CTR */ + addr = (addr >> 1) + 0x30000; + wl1271_spi_write32(wl, OCP_POR_CTR, addr); + + /* write 2 to OCP_CMD */ + wl1271_spi_write32(wl, OCP_CMD, OCP_CMD_READ); + + /* poll for data ready */ + do { + val = wl1271_spi_read32(wl, OCP_DATA_READ); + timeout--; + } while (!(val & OCP_READY_MASK) && timeout); + + if (!timeout) { + wl1271_warning("Top register access timed out."); + return 0xffff; + } + + /* check data status and return if OK */ + if ((val & OCP_STATUS_MASK) == OCP_STATUS_OK) + return val & 0xffff; + else { + wl1271_warning("Top register access returned error."); + return 0xffff; + } +} diff --git a/trunk/drivers/net/wireless/wl12xx/wl1271_spi.h b/trunk/drivers/net/wireless/wl12xx/wl1271_spi.h index a803596dad4a..cb7df1c56314 100644 --- a/trunk/drivers/net/wireless/wl12xx/wl1271_spi.h +++ b/trunk/drivers/net/wireless/wl12xx/wl1271_spi.h @@ -90,7 +90,37 @@ void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf, void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf, size_t len, bool fixed); +/* Translated target IO */ +void wl1271_spi_read(struct wl1271 *wl, int addr, void *buf, size_t len, + bool fixed); +void wl1271_spi_write(struct wl1271 *wl, int addr, void *buf, size_t len, + bool fixed); +u32 wl1271_spi_read32(struct wl1271 *wl, int addr); +void wl1271_spi_write32(struct wl1271 *wl, int addr, u32 val); + +/* Top Register IO */ +void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val); +u16 wl1271_top_reg_read(struct wl1271 *wl, int addr); + /* INIT and RESET words */ void wl1271_spi_reset(struct wl1271 *wl); void wl1271_spi_init(struct wl1271 *wl); +int wl1271_set_partition(struct wl1271 *wl, + struct wl1271_partition_set *p); + +static inline u32 wl1271_raw_read32(struct wl1271 *wl, int addr) +{ + wl1271_spi_raw_read(wl, addr, &wl->buffer_32, + sizeof(wl->buffer_32), false); + + return wl->buffer_32; +} + +static inline void wl1271_raw_write32(struct wl1271 *wl, int addr, u32 val) +{ + wl->buffer_32 = val; + wl1271_spi_raw_write(wl, addr, &wl->buffer_32, + sizeof(wl->buffer_32), false); +} + #endif /* __WL1271_SPI_H__ */ diff --git a/trunk/drivers/net/wireless/wl12xx/wl1271_testmode.c b/trunk/drivers/net/wireless/wl12xx/wl1271_testmode.c deleted file mode 100644 index 3919102e942e..000000000000 --- a/trunk/drivers/net/wireless/wl12xx/wl1271_testmode.c +++ /dev/null @@ -1,283 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 2010 Nokia Corporation - * - * Contact: Luciano Coelho - * - * 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 published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ -#include "wl1271_testmode.h" - -#include - -#include "wl1271.h" -#include "wl1271_spi.h" -#include "wl1271_acx.h" - -#define WL1271_TM_MAX_DATA_LENGTH 1024 - -enum wl1271_tm_commands { - WL1271_TM_CMD_UNSPEC, - WL1271_TM_CMD_TEST, - WL1271_TM_CMD_INTERROGATE, - WL1271_TM_CMD_CONFIGURE, - WL1271_TM_CMD_NVS_PUSH, - WL1271_TM_CMD_SET_PLT_MODE, - - __WL1271_TM_CMD_AFTER_LAST -}; -#define WL1271_TM_CMD_MAX (__WL1271_TM_CMD_AFTER_LAST - 1) - -enum wl1271_tm_attrs { - WL1271_TM_ATTR_UNSPEC, - WL1271_TM_ATTR_CMD_ID, - WL1271_TM_ATTR_ANSWER, - WL1271_TM_ATTR_DATA, - WL1271_TM_ATTR_IE_ID, - WL1271_TM_ATTR_PLT_MODE, - - __WL1271_TM_ATTR_AFTER_LAST -}; -#define WL1271_TM_ATTR_MAX (__WL1271_TM_ATTR_AFTER_LAST - 1) - -static struct nla_policy wl1271_tm_policy[WL1271_TM_ATTR_MAX + 1] = { - [WL1271_TM_ATTR_CMD_ID] = { .type = NLA_U32 }, - [WL1271_TM_ATTR_ANSWER] = { .type = NLA_U8 }, - [WL1271_TM_ATTR_DATA] = { .type = NLA_BINARY, - .len = WL1271_TM_MAX_DATA_LENGTH }, - [WL1271_TM_ATTR_IE_ID] = { .type = NLA_U32 }, - [WL1271_TM_ATTR_PLT_MODE] = { .type = NLA_U32 }, -}; - - -static int wl1271_tm_cmd_test(struct wl1271 *wl, struct nlattr *tb[]) -{ - int buf_len, ret, len; - struct sk_buff *skb; - void *buf; - u8 answer = 0; - - wl1271_debug(DEBUG_TESTMODE, "testmode cmd test"); - - if (!tb[WL1271_TM_ATTR_DATA]) - return -EINVAL; - - buf = nla_data(tb[WL1271_TM_ATTR_DATA]); - buf_len = nla_len(tb[WL1271_TM_ATTR_DATA]); - - if (tb[WL1271_TM_ATTR_ANSWER]) - answer = nla_get_u8(tb[WL1271_TM_ATTR_ANSWER]); - - if (buf_len > sizeof(struct wl1271_command)) - return -EMSGSIZE; - - mutex_lock(&wl->mutex); - ret = wl1271_cmd_test(wl, buf, buf_len, answer); - mutex_unlock(&wl->mutex); - - if (ret < 0) { - wl1271_warning("testmode cmd test failed: %d", ret); - return ret; - } - - if (answer) { - len = nla_total_size(buf_len); - skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, len); - if (!skb) - return -ENOMEM; - - NLA_PUT(skb, WL1271_TM_ATTR_DATA, buf_len, buf); - ret = cfg80211_testmode_reply(skb); - if (ret < 0) - return ret; - } - - return 0; - -nla_put_failure: - kfree_skb(skb); - return -EMSGSIZE; -} - -static int wl1271_tm_cmd_interrogate(struct wl1271 *wl, struct nlattr *tb[]) -{ - int ret; - struct wl1271_command *cmd; - struct sk_buff *skb; - u8 ie_id; - - wl1271_debug(DEBUG_TESTMODE, "testmode cmd interrogate"); - - if (!tb[WL1271_TM_ATTR_IE_ID]) - return -EINVAL; - - ie_id = nla_get_u8(tb[WL1271_TM_ATTR_IE_ID]); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) - return -ENOMEM; - - mutex_lock(&wl->mutex); - ret = wl1271_cmd_interrogate(wl, ie_id, cmd, sizeof(*cmd)); - mutex_unlock(&wl->mutex); - - if (ret < 0) { - wl1271_warning("testmode cmd interrogate failed: %d", ret); - return ret; - } - - skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, sizeof(*cmd)); - if (!skb) - return -ENOMEM; - - NLA_PUT(skb, WL1271_TM_ATTR_DATA, sizeof(*cmd), cmd); - - return 0; - -nla_put_failure: - kfree_skb(skb); - return -EMSGSIZE; -} - -static int wl1271_tm_cmd_configure(struct wl1271 *wl, struct nlattr *tb[]) -{ - int buf_len, ret; - void *buf; - u8 ie_id; - - wl1271_debug(DEBUG_TESTMODE, "testmode cmd configure"); - - if (!tb[WL1271_TM_ATTR_DATA]) - return -EINVAL; - if (!tb[WL1271_TM_ATTR_IE_ID]) - return -EINVAL; - - ie_id = nla_get_u8(tb[WL1271_TM_ATTR_IE_ID]); - buf = nla_data(tb[WL1271_TM_ATTR_DATA]); - buf_len = nla_len(tb[WL1271_TM_ATTR_DATA]); - - if (buf_len > sizeof(struct wl1271_command)) - return -EMSGSIZE; - - mutex_lock(&wl->mutex); - ret = wl1271_cmd_configure(wl, ie_id, buf, buf_len); - mutex_unlock(&wl->mutex); - - if (ret < 0) { - wl1271_warning("testmode cmd configure failed: %d", ret); - return ret; - } - - return 0; -} - -static int wl1271_tm_cmd_nvs_push(struct wl1271 *wl, struct nlattr *tb[]) -{ - int ret = 0; - size_t len; - void *buf; - - wl1271_debug(DEBUG_TESTMODE, "testmode cmd nvs push"); - - if (!tb[WL1271_TM_ATTR_DATA]) - return -EINVAL; - - buf = nla_data(tb[WL1271_TM_ATTR_DATA]); - len = nla_len(tb[WL1271_TM_ATTR_DATA]); - - if (len != sizeof(struct wl1271_nvs_file)) { - wl1271_error("nvs size is not as expected: %zu != %zu", - len, sizeof(struct wl1271_nvs_file)); - return -EMSGSIZE; - } - - mutex_lock(&wl->mutex); - - kfree(wl->nvs); - - wl->nvs = kmalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL); - if (!wl->nvs) { - wl1271_error("could not allocate memory for the nvs file"); - ret = -ENOMEM; - goto out; - } - - memcpy(wl->nvs, buf, len); - - wl1271_debug(DEBUG_TESTMODE, "testmode pushed nvs"); - -out: - mutex_unlock(&wl->mutex); - - return ret; -} - -static int wl1271_tm_cmd_set_plt_mode(struct wl1271 *wl, struct nlattr *tb[]) -{ - u32 val; - int ret; - - wl1271_debug(DEBUG_TESTMODE, "testmode cmd set plt mode"); - - if (!tb[WL1271_TM_ATTR_PLT_MODE]) - return -EINVAL; - - val = nla_get_u32(tb[WL1271_TM_ATTR_PLT_MODE]); - - switch (val) { - case 0: - ret = wl1271_plt_stop(wl); - break; - case 1: - ret = wl1271_plt_start(wl); - break; - default: - ret = -EINVAL; - break; - } - - return ret; -} - -int wl1271_tm_cmd(struct ieee80211_hw *hw, void *data, int len) -{ - struct wl1271 *wl = hw->priv; - struct nlattr *tb[WL1271_TM_ATTR_MAX + 1]; - int err; - - err = nla_parse(tb, WL1271_TM_ATTR_MAX, data, len, wl1271_tm_policy); - if (err) - return err; - - if (!tb[WL1271_TM_ATTR_CMD_ID]) - return -EINVAL; - - switch (nla_get_u32(tb[WL1271_TM_ATTR_CMD_ID])) { - case WL1271_TM_CMD_TEST: - return wl1271_tm_cmd_test(wl, tb); - case WL1271_TM_CMD_INTERROGATE: - return wl1271_tm_cmd_interrogate(wl, tb); - case WL1271_TM_CMD_CONFIGURE: - return wl1271_tm_cmd_configure(wl, tb); - case WL1271_TM_CMD_NVS_PUSH: - return wl1271_tm_cmd_nvs_push(wl, tb); - case WL1271_TM_CMD_SET_PLT_MODE: - return wl1271_tm_cmd_set_plt_mode(wl, tb); - default: - return -EOPNOTSUPP; - } -} diff --git a/trunk/drivers/net/wireless/wl12xx/wl1271_testmode.h b/trunk/drivers/net/wireless/wl12xx/wl1271_testmode.h deleted file mode 100644 index c196d28f9d9d..000000000000 --- a/trunk/drivers/net/wireless/wl12xx/wl1271_testmode.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 2010 Nokia Corporation - * - * Contact: Luciano Coelho - * - * 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 published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL1271_TESTMODE_H__ -#define __WL1271_TESTMODE_H__ - -#include - -int wl1271_tm_cmd(struct ieee80211_hw *hw, void *data, int len); - -#endif /* __WL1271_TESTMODE_H__ */ diff --git a/trunk/drivers/net/wireless/wl12xx/wl1271_tx.c b/trunk/drivers/net/wireless/wl12xx/wl1271_tx.c index 811e739d05bf..00af065c77c2 100644 --- a/trunk/drivers/net/wireless/wl12xx/wl1271_tx.c +++ b/trunk/drivers/net/wireless/wl12xx/wl1271_tx.c @@ -26,7 +26,6 @@ #include "wl1271.h" #include "wl1271_spi.h" -#include "wl1271_io.h" #include "wl1271_reg.h" #include "wl1271_ps.h" #include "wl1271_tx.h" @@ -88,7 +87,7 @@ static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, u32 extra, struct ieee80211_tx_info *control) { struct wl1271_tx_hw_descr *desc; - int pad, ac; + int pad; u16 tx_attr; desc = (struct wl1271_tx_hw_descr *) skb->data; @@ -108,11 +107,9 @@ static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, /* configure the tx attributes */ tx_attr = wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER; - - /* queue */ - ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); - desc->tid = wl1271_tx_ac_to_tid(ac); - + /* FIXME: do we know the packet priority? can we identify mgmt + packets, and use max prio for them at least? */ + desc->tid = 0; desc->aid = TX_HW_DEFAULT_AID; desc->reserved = 0; @@ -124,11 +121,6 @@ static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, pad = pad - skb->len; tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD; - /* if the packets are destined for AP (have a STA entry) send them - with AP rate policies, otherwise use default basic rates */ - if (control->control.sta) - tx_attr |= ACX_TX_AP_FULL_RATE << TX_HW_ATTR_OFST_RATE_POLICY; - desc->tx_attr = cpu_to_le16(tx_attr); wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d", pad); @@ -166,11 +158,11 @@ static int wl1271_tx_send_packet(struct wl1271 *wl, struct sk_buff *skb, len = WL1271_TX_ALIGN(skb->len); /* perform a fixed address block write with the packet */ - wl1271_write(wl, WL1271_SLV_MEM_DATA, skb->data, len, true); + wl1271_spi_write(wl, WL1271_SLV_MEM_DATA, skb->data, len, true); /* write packet new counter into the write access register */ wl->tx_packets_count++; - wl1271_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count); + wl1271_spi_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count); desc = (struct wl1271_tx_hw_descr *) skb->data; wl1271_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u (%u words)", @@ -204,7 +196,6 @@ static int wl1271_tx_frame(struct wl1271 *wl, struct sk_buff *skb) ret = wl1271_cmd_set_default_wep_key(wl, idx); if (ret < 0) return ret; - wl->default_key = idx; } } @@ -223,50 +214,18 @@ static int wl1271_tx_frame(struct wl1271 *wl, struct sk_buff *skb) return ret; } -static u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set) -{ - struct ieee80211_supported_band *band; - u32 enabled_rates = 0; - int bit; - - band = wl->hw->wiphy->bands[wl->band]; - for (bit = 0; bit < band->n_bitrates; bit++) { - if (rate_set & 0x1) - enabled_rates |= band->bitrates[bit].hw_value; - rate_set >>= 1; - } - - return enabled_rates; -} - void wl1271_tx_work(struct work_struct *work) { struct wl1271 *wl = container_of(work, struct wl1271, tx_work); struct sk_buff *skb; bool woken_up = false; - u32 sta_rates = 0; int ret; - /* check if the rates supported by the AP have changed */ - if (unlikely(test_and_clear_bit(WL1271_FLAG_STA_RATES_CHANGED, - &wl->flags))) { - unsigned long flags; - spin_lock_irqsave(&wl->wl_lock, flags); - sta_rates = wl->sta_rate_set; - spin_unlock_irqrestore(&wl->wl_lock, flags); - } - mutex_lock(&wl->mutex); if (unlikely(wl->state == WL1271_STATE_OFF)) goto out; - /* if rates have changed, re-configure the rate policy */ - if (unlikely(sta_rates)) { - wl->rate_set = wl1271_tx_enabled_rates_get(wl, sta_rates); - wl1271_acx_rate_policies(wl); - } - while ((skb = skb_dequeue(&wl->tx_queue))) { if (!woken_up) { ret = wl1271_ps_elp_wakeup(wl, false); @@ -281,18 +240,18 @@ void wl1271_tx_work(struct work_struct *work) wl1271_debug(DEBUG_TX, "tx_work: fw buffer full, " "stop queues"); ieee80211_stop_queues(wl->hw); - set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags); + wl->tx_queue_stopped = true; skb_queue_head(&wl->tx_queue, skb); goto out; } else if (ret < 0) { dev_kfree_skb(skb); goto out; - } else if (test_and_clear_bit(WL1271_FLAG_TX_QUEUE_STOPPED, - &wl->flags)) { + } else if (wl->tx_queue_stopped) { /* firmware buffer has space, restart queues */ wl1271_debug(DEBUG_TX, "complete_packet: waking queues"); ieee80211_wake_queues(wl->hw); + wl->tx_queue_stopped = false; } } @@ -376,8 +335,8 @@ void wl1271_tx_complete(struct wl1271 *wl, u32 count) wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count); /* read the tx results from the chipset */ - wl1271_read(wl, le32_to_cpu(memmap->tx_result), - wl->tx_res_if, sizeof(*wl->tx_res_if), false); + wl1271_spi_read(wl, le32_to_cpu(memmap->tx_result), + wl->tx_res_if, sizeof(*wl->tx_res_if), false); /* verify that the result buffer is not getting overrun */ if (count > TX_HW_RESULT_QUEUE_LEN) { @@ -398,10 +357,10 @@ void wl1271_tx_complete(struct wl1271 *wl, u32 count) } /* write host counter to chipset (to ack) */ - wl1271_write32(wl, le32_to_cpu(memmap->tx_result) + - offsetof(struct wl1271_tx_hw_res_if, - tx_result_host_counter), - le32_to_cpu(wl->tx_res_if->tx_result_fw_counter)); + wl1271_spi_write32(wl, le32_to_cpu(memmap->tx_result) + + offsetof(struct wl1271_tx_hw_res_if, + tx_result_host_counter), + le32_to_cpu(wl->tx_res_if->tx_result_fw_counter)); } /* caller must hold wl->mutex */ diff --git a/trunk/drivers/net/wireless/wl12xx/wl1271_tx.h b/trunk/drivers/net/wireless/wl12xx/wl1271_tx.h index 17e405a09caa..416396caf0a0 100644 --- a/trunk/drivers/net/wireless/wl12xx/wl1271_tx.h +++ b/trunk/drivers/net/wireless/wl12xx/wl1271_tx.h @@ -123,42 +123,6 @@ struct wl1271_tx_hw_res_if { struct wl1271_tx_hw_res_descr tx_results_queue[TX_HW_RESULT_QUEUE_LEN]; } __attribute__ ((packed)); -static inline int wl1271_tx_get_queue(int queue) -{ - /* FIXME: use best effort until WMM is enabled */ - return CONF_TX_AC_BE; - - switch (queue) { - case 0: - return CONF_TX_AC_VO; - case 1: - return CONF_TX_AC_VI; - case 2: - return CONF_TX_AC_BE; - case 3: - return CONF_TX_AC_BK; - default: - return CONF_TX_AC_BE; - } -} - -/* wl1271 tx descriptor needs the tid and we need to convert it from ac */ -static inline int wl1271_tx_ac_to_tid(int ac) -{ - switch (ac) { - case 0: - return 0; - case 1: - return 2; - case 2: - return 4; - case 3: - return 6; - default: - return 0; - } -} - void wl1271_tx_work(struct work_struct *work); void wl1271_tx_complete(struct wl1271 *wl, u32 count); void wl1271_tx_flush(struct wl1271 *wl); diff --git a/trunk/drivers/net/wireless/zd1211rw/zd_mac.c b/trunk/drivers/net/wireless/zd1211rw/zd_mac.c index d90f0a25b9cf..9d9b263733e6 100644 --- a/trunk/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/trunk/drivers/net/wireless/zd1211rw/zd_mac.c @@ -869,7 +869,7 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length) } static int zd_op_add_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) + struct ieee80211_if_init_conf *conf) { struct zd_mac *mac = zd_hw_mac(hw); @@ -877,22 +877,22 @@ static int zd_op_add_interface(struct ieee80211_hw *hw, if (mac->type != NL80211_IFTYPE_UNSPECIFIED) return -EOPNOTSUPP; - switch (vif->type) { + switch (conf->type) { case NL80211_IFTYPE_MONITOR: case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_ADHOC: - mac->type = vif->type; + mac->type = conf->type; break; default: return -EOPNOTSUPP; } - return zd_write_mac_addr(&mac->chip, vif->addr); + return zd_write_mac_addr(&mac->chip, conf->mac_addr); } static void zd_op_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) + struct ieee80211_if_init_conf *conf) { struct zd_mac *mac = zd_hw_mac(hw); mac->type = NL80211_IFTYPE_UNSPECIFIED; diff --git a/trunk/drivers/net/wireless/zd1211rw/zd_usb.c b/trunk/drivers/net/wireless/zd1211rw/zd_usb.c index 442fc1117326..72d3e437e190 100644 --- a/trunk/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/trunk/drivers/net/wireless/zd1211rw/zd_usb.c @@ -1079,15 +1079,11 @@ static int eject_installer(struct usb_interface *intf) int r; /* Find bulk out endpoint */ - for (r = 1; r >= 0; r--) { - endpoint = &iface_desc->endpoint[r].desc; - if (usb_endpoint_dir_out(endpoint) && - usb_endpoint_xfer_bulk(endpoint)) { - bulk_out_ep = endpoint->bEndpointAddress; - break; - } - } - if (r == -1) { + endpoint = &iface_desc->endpoint[1].desc; + if (usb_endpoint_dir_out(endpoint) && + usb_endpoint_xfer_bulk(endpoint)) { + bulk_out_ep = endpoint->bEndpointAddress; + } else { dev_err(&udev->dev, "zd1211rw: Could not find bulk out endpoint\n"); return -ENODEV; diff --git a/trunk/drivers/ssb/driver_chipcommon_pmu.c b/trunk/drivers/ssb/driver_chipcommon_pmu.c index 3d551245a4e2..64abd11f6fbb 100644 --- a/trunk/drivers/ssb/driver_chipcommon_pmu.c +++ b/trunk/drivers/ssb/driver_chipcommon_pmu.c @@ -332,12 +332,6 @@ static void ssb_pmu_pll_init(struct ssb_chipcommon *cc) case 0x5354: ssb_pmu0_pllinit_r0(cc, crystalfreq); break; - case 0x4322: - if (cc->pmu.rev == 2) { - chipco_write32(cc, SSB_CHIPCO_PLLCTL_ADDR, 0x0000000A); - chipco_write32(cc, SSB_CHIPCO_PLLCTL_DATA, 0x380005C0); - } - break; default: ssb_printk(KERN_ERR PFX "ERROR: PLL init unknown for device %04X\n", @@ -423,7 +417,6 @@ static void ssb_pmu_resources_init(struct ssb_chipcommon *cc) switch (bus->chip_id) { case 0x4312: - case 0x4322: /* We keep the default settings: * min_msk = 0xCBB * max_msk = 0x7FFFF diff --git a/trunk/drivers/ssb/driver_mipscore.c b/trunk/drivers/ssb/driver_mipscore.c index 97efce184a8f..3c6feed46f6e 100644 --- a/trunk/drivers/ssb/driver_mipscore.c +++ b/trunk/drivers/ssb/driver_mipscore.c @@ -270,6 +270,7 @@ void ssb_mipscore_init(struct ssb_mipscore *mcore) set_irq(dev, irq++); } break; + /* fallthrough */ case SSB_DEV_PCI: case SSB_DEV_ETHERNET: case SSB_DEV_ETHERNET_GBIT: @@ -280,10 +281,6 @@ void ssb_mipscore_init(struct ssb_mipscore *mcore) set_irq(dev, irq++); break; } - /* fallthrough */ - case SSB_DEV_EXTIF: - set_irq(dev, 0); - break; } } ssb_dprintk(KERN_INFO PFX "after irq reconfiguration\n"); diff --git a/trunk/drivers/ssb/ssb_private.h b/trunk/drivers/ssb/ssb_private.h index 0331139a726f..56054be4d113 100644 --- a/trunk/drivers/ssb/ssb_private.h +++ b/trunk/drivers/ssb/ssb_private.h @@ -196,7 +196,7 @@ extern int ssb_devices_thaw(struct ssb_freeze_context *ctx); #ifdef CONFIG_SSB_B43_PCI_BRIDGE extern int __init b43_pci_ssb_bridge_init(void); extern void __exit b43_pci_ssb_bridge_exit(void); -#else /* CONFIG_SSB_B43_PCI_BRIDGE */ +#else /* CONFIG_SSB_B43_PCI_BRIDGR */ static inline int b43_pci_ssb_bridge_init(void) { return 0; @@ -204,6 +204,6 @@ static inline int b43_pci_ssb_bridge_init(void) static inline void b43_pci_ssb_bridge_exit(void) { } -#endif /* CONFIG_SSB_B43_PCI_BRIDGE */ +#endif /* CONFIG_SSB_PCIHOST */ #endif /* LINUX_SSB_PRIVATE_H_ */ diff --git a/trunk/drivers/staging/rtl8187se/ieee80211/ieee80211.h b/trunk/drivers/staging/rtl8187se/ieee80211/ieee80211.h index 462578703d07..3222c22152fb 100644 --- a/trunk/drivers/staging/rtl8187se/ieee80211/ieee80211.h +++ b/trunk/drivers/staging/rtl8187se/ieee80211/ieee80211.h @@ -482,6 +482,15 @@ struct ieee80211_header_data { u16 seq_ctrl; }; +struct ieee80211_hdr_3addr { + u16 frame_ctl; + u16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; + u16 seq_ctl; +} __attribute__ ((packed)); + struct ieee80211_hdr_4addr { u16 frame_ctl; u16 duration_id; diff --git a/trunk/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c b/trunk/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c index cc9da3713526..334e4c7ec61b 100644 --- a/trunk/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c +++ b/trunk/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c @@ -203,7 +203,7 @@ inline void softmac_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *ieee enqueue_mgmt(ieee,skb); }else{ - header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0]<<4); + header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0]<<4); if (ieee->seq_ctrl[0] == 0xFFF) ieee->seq_ctrl[0] = 0; @@ -220,7 +220,7 @@ inline void softmac_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *ieee spin_unlock_irqrestore(&ieee->lock, flags); spin_lock_irqsave(&ieee->mgmt_tx_lock, flags); - header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4); + header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); if (ieee->seq_ctrl[0] == 0xFFF) ieee->seq_ctrl[0] = 0; @@ -246,7 +246,7 @@ inline void softmac_ps_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *i if(single){ - header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4); + header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); if (ieee->seq_ctrl[0] == 0xFFF) ieee->seq_ctrl[0] = 0; @@ -259,7 +259,7 @@ inline void softmac_ps_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *i }else{ - header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4); + header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); if (ieee->seq_ctrl[0] == 0xFFF) ieee->seq_ctrl[0] = 0; @@ -287,7 +287,7 @@ inline struct sk_buff *ieee80211_disassociate_skb( return NULL; disass = (struct ieee80211_disassoc_frame *) skb_put(skb,sizeof(struct ieee80211_disassoc_frame)); - disass->header.frame_control = cpu_to_le16(IEEE80211_STYPE_DISASSOC); + disass->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_DISASSOC); disass->header.duration_id = 0; memcpy(disass->header.addr1, beacon->bssid, ETH_ALEN); @@ -905,7 +905,7 @@ struct sk_buff* ieee80211_assoc_resp(struct ieee80211_device *ieee, u8 *dest) assoc = (struct ieee80211_assoc_response_frame *) skb_put(skb,sizeof(struct ieee80211_assoc_response_frame)); - assoc->header.frame_control = cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP); + assoc->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP); memcpy(assoc->header.addr1, dest,ETH_ALEN); memcpy(assoc->header.addr3, ieee->dev->dev_addr, ETH_ALEN); memcpy(assoc->header.addr2, ieee->dev->dev_addr, ETH_ALEN); @@ -981,7 +981,7 @@ struct sk_buff* ieee80211_null_func(struct ieee80211_device *ieee,short pwr) memcpy(hdr->addr2, ieee->dev->dev_addr, ETH_ALEN); memcpy(hdr->addr3, ieee->current_network.bssid, ETH_ALEN); - hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | + hdr->frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | IEEE80211_FCTL_TODS | (pwr ? IEEE80211_FCTL_PM:0)); @@ -1084,7 +1084,7 @@ inline struct sk_buff *ieee80211_association_req(struct ieee80211_network *beaco skb_put(skb, sizeof(struct ieee80211_assoc_request_frame)); - hdr->header.frame_control = IEEE80211_STYPE_ASSOC_REQ; + hdr->header.frame_ctl = IEEE80211_STYPE_ASSOC_REQ; hdr->header.duration_id= 37; //FIXME memcpy(hdr->header.addr1, beacon->bssid, ETH_ALEN); memcpy(hdr->header.addr2, ieee->dev->dev_addr, ETH_ALEN); @@ -1786,11 +1786,11 @@ ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb, tasklet_schedule(&ieee->ps_task); - if (WLAN_FC_GET_STYPE(header->frame_control) != IEEE80211_STYPE_PROBE_RESP && - WLAN_FC_GET_STYPE(header->frame_control) != IEEE80211_STYPE_BEACON) + if(WLAN_FC_GET_STYPE(header->frame_ctl) != IEEE80211_STYPE_PROBE_RESP && + WLAN_FC_GET_STYPE(header->frame_ctl) != IEEE80211_STYPE_BEACON) ieee->last_rx_ps_time = jiffies; - switch (WLAN_FC_GET_STYPE(header->frame_control)) { + switch (WLAN_FC_GET_STYPE(header->frame_ctl)) { case IEEE80211_STYPE_ASSOC_RESP: case IEEE80211_STYPE_REASSOC_RESP: @@ -2064,7 +2064,7 @@ void ieee80211_wake_queue(struct ieee80211_device *ieee) header = (struct ieee80211_hdr_3addr *) skb->data; - header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4); + header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); if (ieee->seq_ctrl[0] == 0xFFF) ieee->seq_ctrl[0] = 0; diff --git a/trunk/drivers/staging/rtl8187se/r8180_core.c b/trunk/drivers/staging/rtl8187se/r8180_core.c index 7788bc42e9b4..53e654d0d4fa 100644 --- a/trunk/drivers/staging/rtl8187se/r8180_core.c +++ b/trunk/drivers/staging/rtl8187se/r8180_core.c @@ -1909,7 +1909,7 @@ rate) struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); int mode; struct ieee80211_hdr_3addr *h = (struct ieee80211_hdr_3addr *) skb->data; - short morefrag = (h->frame_control) & IEEE80211_FCTL_MOREFRAGS; + short morefrag = (h->frame_ctl) & IEEE80211_FCTL_MOREFRAGS; unsigned long flags; int priority; @@ -2177,7 +2177,7 @@ short rtl8180_tx(struct net_device *dev, u8* txbuf, int len, int priority, TxDescDuration = ThisFrameTime + aSifsTime + AckTime; } - if (!(frag_hdr->frame_control & IEEE80211_FCTL_MOREFRAGS)) { + if(!(frag_hdr->frame_ctl & IEEE80211_FCTL_MOREFRAGS)) { //no more fragment // ThisFrame-ACK. Duration = aSifsTime + AckTime; } else { // One or more fragments remained. diff --git a/trunk/drivers/staging/rtl8192su/ieee80211/ieee80211.h b/trunk/drivers/staging/rtl8192su/ieee80211/ieee80211.h index 6963e5448f34..f22d024b1c39 100644 --- a/trunk/drivers/staging/rtl8192su/ieee80211/ieee80211.h +++ b/trunk/drivers/staging/rtl8192su/ieee80211/ieee80211.h @@ -609,6 +609,16 @@ struct ieee80211_hdr_2addr { u8 payload[0]; } __attribute__ ((packed)); +struct ieee80211_hdr_3addr { + __le16 frame_ctl; + __le16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; + __le16 seq_ctl; + u8 payload[0]; +} __attribute__ ((packed)); + struct ieee80211_hdr_4addr { __le16 frame_ctl; __le16 duration_id; @@ -1662,7 +1672,7 @@ static inline u8 *ieee80211_get_payload(struct rtl_ieee80211_hdr *hdr) case IEEE80211_2ADDR_LEN: return ((struct ieee80211_hdr_2addr *)hdr)->payload; case IEEE80211_3ADDR_LEN: - return (void *)hdr+sizeof(struct ieee80211_hdr_3addr); + return ((struct ieee80211_hdr_3addr *)hdr)->payload; case IEEE80211_4ADDR_LEN: return ((struct ieee80211_hdr_4addr *)hdr)->payload; } diff --git a/trunk/drivers/staging/rtl8192su/ieee80211/ieee80211_r8192s.h b/trunk/drivers/staging/rtl8192su/ieee80211/ieee80211_r8192s.h index 7d6c3bc143ae..123abcf0f497 100644 --- a/trunk/drivers/staging/rtl8192su/ieee80211/ieee80211_r8192s.h +++ b/trunk/drivers/staging/rtl8192su/ieee80211/ieee80211_r8192s.h @@ -201,7 +201,7 @@ typedef union _frameqos { static inline u8 Frame_QoSTID(u8 *buf) { struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr *)buf; - u16 fc = le16_to_cpu(hdr->frame_control); + u16 fc = le16_to_cpu(hdr->frame_ctl); return (u8)((frameqos *)(buf + (((fc & IEEE80211_FCTL_TODS) && diff --git a/trunk/drivers/staging/rtl8192su/ieee80211/ieee80211_rx.c b/trunk/drivers/staging/rtl8192su/ieee80211/ieee80211_rx.c index 72498e8e0ded..8e56f97a8f57 100644 --- a/trunk/drivers/staging/rtl8192su/ieee80211/ieee80211_rx.c +++ b/trunk/drivers/staging/rtl8192su/ieee80211/ieee80211_rx.c @@ -745,7 +745,7 @@ u8 parse_subframe(struct sk_buff *skb, struct ieee80211_rxb *rxb,u8* src,u8* dst) { struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr* )skb->data; - u16 fc = le16_to_cpu(hdr->frame_control); + u16 fc = le16_to_cpu(hdr->frame_ctl); u16 LLCOffset= sizeof(struct ieee80211_hdr_3addr); u16 ChkLength; @@ -757,7 +757,7 @@ u8 parse_subframe(struct sk_buff *skb, struct sk_buff *sub_skb; u8 *data_ptr; /* just for debug purpose */ - SeqNum = WLAN_GET_SEQ_SEQ(le16_to_cpu(hdr->seq_ctrl)); + SeqNum = WLAN_GET_SEQ_SEQ(le16_to_cpu(hdr->seq_ctl)); if((IEEE80211_QOS_HAS_SEQ(fc))&&\ (((frameqos *)(skb->data + IEEE80211_3ADDR_LEN))->field.reserved)) { @@ -2371,7 +2371,7 @@ static inline void ieee80211_process_probe_response( escape_essid(info_element->data, info_element->len), MAC_ARG(beacon->header.addr3), - WLAN_FC_GET_STYPE(beacon->header.frame_control) == + WLAN_FC_GET_STYPE(beacon->header.frame_ctl) == IEEE80211_STYPE_PROBE_RESP ? "PROBE RESPONSE" : "BEACON"); return; @@ -2388,7 +2388,7 @@ static inline void ieee80211_process_probe_response( return; if(ieee->bGlobalDomain) { - if (WLAN_FC_GET_STYPE(beacon->header.frame_control) == IEEE80211_STYPE_PROBE_RESP) + if (WLAN_FC_GET_STYPE(beacon->header.frame_ctl) == IEEE80211_STYPE_PROBE_RESP) { // Case 1: Country code if(IS_COUNTRY_IE_VALID(ieee) ) @@ -2455,7 +2455,7 @@ static inline void ieee80211_process_probe_response( else ieee->current_network.buseprotection = false; } - if(is_beacon(beacon->header.frame_control)) + if(is_beacon(beacon->header.frame_ctl)) { if(ieee->state == IEEE80211_LINKED) ieee->LinkDetectInfo.NumRecvBcnInPeriod++; @@ -2497,7 +2497,7 @@ static inline void ieee80211_process_probe_response( escape_essid(network.ssid, network.ssid_len), MAC_ARG(network.bssid), - WLAN_FC_GET_STYPE(beacon->header.frame_control) == + WLAN_FC_GET_STYPE(beacon->header.frame_ctl) == IEEE80211_STYPE_PROBE_RESP ? "PROBE RESPONSE" : "BEACON"); #endif @@ -2510,7 +2510,7 @@ static inline void ieee80211_process_probe_response( escape_essid(target->ssid, target->ssid_len), MAC_ARG(target->bssid), - WLAN_FC_GET_STYPE(beacon->header.frame_control) == + WLAN_FC_GET_STYPE(beacon->header.frame_ctl) == IEEE80211_STYPE_PROBE_RESP ? "PROBE RESPONSE" : "BEACON"); @@ -2520,7 +2520,7 @@ static inline void ieee80211_process_probe_response( */ renew = !time_after(target->last_scanned + ieee->scan_age, jiffies); //YJ,add,080819,for hidden ap - if(is_beacon(beacon->header.frame_control) == 0) + if(is_beacon(beacon->header.frame_ctl) == 0) network.flags = (~NETWORK_EMPTY_ESSID & network.flags)|(NETWORK_EMPTY_ESSID & target->flags); //if(strncmp(network.ssid, "linksys-c",9) == 0) // printk("====>2 network.ssid=%s FLAG=%d target.ssid=%s FLAG=%d\n", network.ssid, network.flags, target->ssid, target->flags); @@ -2536,7 +2536,7 @@ static inline void ieee80211_process_probe_response( } spin_unlock_irqrestore(&ieee->lock, flags); - if (is_beacon(beacon->header.frame_control)&&is_same_network(&ieee->current_network, &network, ieee)&&\ + if (is_beacon(beacon->header.frame_ctl)&&is_same_network(&ieee->current_network, &network, ieee)&&\ (ieee->state == IEEE80211_LINKED)) { if(ieee->handle_beacon != NULL) { ieee->handle_beacon(ieee->dev,beacon,&ieee->current_network); diff --git a/trunk/drivers/staging/rtl8192su/ieee80211/ieee80211_softmac.c b/trunk/drivers/staging/rtl8192su/ieee80211/ieee80211_softmac.c index 8da0c4c83673..fd8e11252f1b 100644 --- a/trunk/drivers/staging/rtl8192su/ieee80211/ieee80211_softmac.c +++ b/trunk/drivers/staging/rtl8192su/ieee80211/ieee80211_softmac.c @@ -242,7 +242,7 @@ inline void softmac_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *ieee if(ieee->queue_stop){ enqueue_mgmt(ieee,skb); }else{ - header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0]<<4); + header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0]<<4); if (ieee->seq_ctrl[0] == 0xFFF) ieee->seq_ctrl[0] = 0; @@ -260,7 +260,7 @@ inline void softmac_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *ieee spin_unlock_irqrestore(&ieee->lock, flags); spin_lock_irqsave(&ieee->mgmt_tx_lock, flags); - header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4); + header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); if (ieee->seq_ctrl[0] == 0xFFF) ieee->seq_ctrl[0] = 0; @@ -302,7 +302,7 @@ inline void softmac_ps_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *i //printk("=============>%s()\n", __FUNCTION__); if(single){ - header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4); + header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); if (ieee->seq_ctrl[0] == 0xFFF) ieee->seq_ctrl[0] = 0; @@ -315,7 +315,7 @@ inline void softmac_ps_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *i }else{ - header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4); + header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); if (ieee->seq_ctrl[0] == 0xFFF) ieee->seq_ctrl[0] = 0; @@ -347,7 +347,7 @@ inline struct sk_buff *ieee80211_probe_req(struct ieee80211_device *ieee) skb_reserve(skb, ieee->tx_headroom); req = (struct ieee80211_probe_request *) skb_put(skb,sizeof(struct ieee80211_probe_request)); - req->header.frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); + req->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); req->header.duration_id = 0; //FIXME: is this OK ? memset(req->header.addr1, 0xff, ETH_ALEN); @@ -662,8 +662,8 @@ inline struct sk_buff *ieee80211_authentication_req(struct ieee80211_network *be auth = (struct ieee80211_authentication *) skb_put(skb, sizeof(struct ieee80211_authentication)); - auth->header.frame_control = IEEE80211_STYPE_AUTH; - if (challengelen) auth->header.frame_control |= IEEE80211_FCTL_WEP; + auth->header.frame_ctl = IEEE80211_STYPE_AUTH; + if (challengelen) auth->header.frame_ctl |= IEEE80211_FCTL_WEP; auth->header.duration_id = 0x013a; //FIXME @@ -801,7 +801,7 @@ static struct sk_buff* ieee80211_probe_resp(struct ieee80211_device *ieee, u8 *d beacon_buf->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); - beacon_buf->header.frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_RESP); + beacon_buf->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_RESP); beacon_buf->info_element[0].id = MFIE_TYPE_SSID; beacon_buf->info_element[0].len = ssid_len; @@ -880,7 +880,7 @@ struct sk_buff* ieee80211_assoc_resp(struct ieee80211_device *ieee, u8 *dest) assoc = (struct ieee80211_assoc_response_frame *) skb_put(skb,sizeof(struct ieee80211_assoc_response_frame)); - assoc->header.frame_control = cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP); + assoc->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP); memcpy(assoc->header.addr1, dest,ETH_ALEN); memcpy(assoc->header.addr3, ieee->dev->dev_addr, ETH_ALEN); memcpy(assoc->header.addr2, ieee->dev->dev_addr, ETH_ALEN); @@ -935,7 +935,7 @@ struct sk_buff* ieee80211_auth_resp(struct ieee80211_device *ieee,int status, u8 memcpy(auth->header.addr3, ieee->dev->dev_addr, ETH_ALEN); memcpy(auth->header.addr2, ieee->dev->dev_addr, ETH_ALEN); memcpy(auth->header.addr1, dest, ETH_ALEN); - auth->header.frame_control = cpu_to_le16(IEEE80211_STYPE_AUTH); + auth->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_AUTH); return skb; @@ -957,7 +957,7 @@ struct sk_buff* ieee80211_null_func(struct ieee80211_device *ieee,short pwr) memcpy(hdr->addr2, ieee->dev->dev_addr, ETH_ALEN); memcpy(hdr->addr3, ieee->current_network.bssid, ETH_ALEN); - hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | + hdr->frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | IEEE80211_FCTL_TODS | (pwr ? IEEE80211_FCTL_PM:0)); @@ -1083,7 +1083,7 @@ inline struct sk_buff *ieee80211_association_req(struct ieee80211_network *beaco skb_put(skb, sizeof(struct ieee80211_assoc_request_frame)+2); - hdr->header.frame_control = IEEE80211_STYPE_ASSOC_REQ; + hdr->header.frame_ctl = IEEE80211_STYPE_ASSOC_REQ; hdr->header.duration_id= 37; //FIXME memcpy(hdr->header.addr1, beacon->bssid, ETH_ALEN); memcpy(hdr->header.addr2, ieee->dev->dev_addr, ETH_ALEN); @@ -1940,13 +1940,13 @@ ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb, if(!ieee->proto_started) return 0; - switch (WLAN_FC_GET_STYPE(header->frame_control)) { + switch (WLAN_FC_GET_STYPE(header->frame_ctl)) { case IEEE80211_STYPE_ASSOC_RESP: case IEEE80211_STYPE_REASSOC_RESP: IEEE80211_DEBUG_MGMT("received [RE]ASSOCIATION RESPONSE (%d)\n", - WLAN_FC_GET_STYPE(header->frame_control)); + WLAN_FC_GET_STYPE(header->frame_ctl)); if ((ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) && ieee->state == IEEE80211_ASSOCIATING_AUTHENTICATED && ieee->iw_mode == IW_MODE_INFRA){ @@ -2088,7 +2088,7 @@ ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb, if ((ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) && ieee->state == IEEE80211_LINKED && ieee->iw_mode == IW_MODE_INFRA){ - printk("==========>received disassoc/deauth(%x) frame, reason code:%x\n",WLAN_FC_GET_STYPE(header->frame_control), ((struct ieee80211_disassoc*)skb->data)->reason); + printk("==========>received disassoc/deauth(%x) frame, reason code:%x\n",WLAN_FC_GET_STYPE(header->frame_ctl), ((struct ieee80211_disassoc*)skb->data)->reason); ieee->state = IEEE80211_ASSOCIATING; ieee->softmac_stats.reassoc++; ieee->is_roaming = true; @@ -2239,7 +2239,7 @@ void ieee80211_wake_queue(struct ieee80211_device *ieee) header = (struct ieee80211_hdr_3addr *) skb->data; - header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4); + header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); if (ieee->seq_ctrl[0] == 0xFFF) ieee->seq_ctrl[0] = 0; @@ -2574,7 +2574,7 @@ struct sk_buff *ieee80211_get_beacon_(struct ieee80211_device *ieee) return NULL; b = (struct ieee80211_probe_response *) skb->data; - b->header.frame_control = cpu_to_le16(IEEE80211_STYPE_BEACON); + b->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_BEACON); return skb; @@ -2590,7 +2590,7 @@ struct sk_buff *ieee80211_get_beacon(struct ieee80211_device *ieee) return NULL; b = (struct ieee80211_probe_response *) skb->data; - b->header.seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4); + b->header.seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); if (ieee->seq_ctrl[0] == 0xFFF) ieee->seq_ctrl[0] = 0; @@ -3139,7 +3139,7 @@ inline struct sk_buff *ieee80211_disassociate_skb( return NULL; disass = (struct ieee80211_disassoc *) skb_put(skb,sizeof(struct ieee80211_disassoc)); - disass->header.frame_control = cpu_to_le16(IEEE80211_STYPE_DISASSOC); + disass->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_DISASSOC); disass->header.duration_id = 0; memcpy(disass->header.addr1, beacon->bssid, ETH_ALEN); diff --git a/trunk/drivers/staging/rtl8192su/ieee80211/rtl819x_BAProc.c b/trunk/drivers/staging/rtl8192su/ieee80211/rtl819x_BAProc.c index c6962450e06f..8d12ffca18fa 100644 --- a/trunk/drivers/staging/rtl8192su/ieee80211/rtl819x_BAProc.c +++ b/trunk/drivers/staging/rtl8192su/ieee80211/rtl819x_BAProc.c @@ -136,7 +136,7 @@ static struct sk_buff* ieee80211_ADDBA(struct ieee80211_device* ieee, u8* Dst, P memcpy(BAReq->addr3, ieee->current_network.bssid, ETH_ALEN); - BAReq->frame_control = cpu_to_le16(IEEE80211_STYPE_MANAGE_ACT); //action frame + BAReq->frame_ctl = cpu_to_le16(IEEE80211_STYPE_MANAGE_ACT); //action frame //tag += sizeof( struct ieee80211_hdr_3addr); //move to action field tag = (u8*)skb_put(skb, 9); @@ -221,7 +221,7 @@ static struct sk_buff* ieee80211_DELBA( memcpy(Delba->addr1, dst, ETH_ALEN); memcpy(Delba->addr2, ieee->dev->dev_addr, ETH_ALEN); memcpy(Delba->addr3, ieee->current_network.bssid, ETH_ALEN); - Delba->frame_control = cpu_to_le16(IEEE80211_STYPE_MANAGE_ACT); //action frame + Delba->frame_ctl = cpu_to_le16(IEEE80211_STYPE_MANAGE_ACT); //action frame tag = (u8*)skb_put(skb, 6); diff --git a/trunk/drivers/staging/rtl8192su/r8192U_core.c b/trunk/drivers/staging/rtl8192su/r8192U_core.c index 2b079fb67d31..66274d7666ff 100644 --- a/trunk/drivers/staging/rtl8192su/r8192U_core.c +++ b/trunk/drivers/staging/rtl8192su/r8192U_core.c @@ -6166,7 +6166,7 @@ void rtl8192_process_phyinfo(struct r8192_priv * priv,u8* buffer, struct ieee802 u16 sc ; unsigned int frag,seq; hdr = (struct ieee80211_hdr_3addr *)buffer; - sc = le16_to_cpu(hdr->seq_ctrl); + sc = le16_to_cpu(hdr->seq_ctl); frag = WLAN_GET_SEQ_FRAG(sc); seq = WLAN_GET_SEQ_SEQ(sc); //cosa add 04292008 to record the sequence number @@ -6825,7 +6825,7 @@ void rtl8192SU_TranslateRxSignalStuff(struct sk_buff *skb, tmp_buf = (u8*)skb->data;// + get_rxpacket_shiftbytes_819xusb(pstats); hdr = (struct ieee80211_hdr_3addr *)tmp_buf; - fc = le16_to_cpu(hdr->frame_control); + fc = le16_to_cpu(hdr->frame_ctl); type = WLAN_FC_GET_TYPE(fc); praddr = hdr->addr1; diff --git a/trunk/include/linux/ieee80211.h b/trunk/include/linux/ieee80211.h index 19984958ab7b..163c840437d6 100644 --- a/trunk/include/linux/ieee80211.h +++ b/trunk/include/linux/ieee80211.h @@ -120,26 +120,6 @@ #define IEEE80211_QOS_CTL_TID_MASK 0x000F #define IEEE80211_QOS_CTL_TAG1D_MASK 0x0007 -/* U-APSD queue for WMM IEs sent by AP */ -#define IEEE80211_WMM_IE_AP_QOSINFO_UAPSD (1<<7) - -/* U-APSD queues for WMM IEs sent by STA */ -#define IEEE80211_WMM_IE_STA_QOSINFO_AC_VO (1<<0) -#define IEEE80211_WMM_IE_STA_QOSINFO_AC_VI (1<<1) -#define IEEE80211_WMM_IE_STA_QOSINFO_AC_BK (1<<2) -#define IEEE80211_WMM_IE_STA_QOSINFO_AC_BE (1<<3) -#define IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK 0x0f - -/* U-APSD max SP length for WMM IEs sent by STA */ -#define IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL 0x00 -#define IEEE80211_WMM_IE_STA_QOSINFO_SP_2 0x01 -#define IEEE80211_WMM_IE_STA_QOSINFO_SP_4 0x02 -#define IEEE80211_WMM_IE_STA_QOSINFO_SP_6 0x03 -#define IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK 0x03 -#define IEEE80211_WMM_IE_STA_QOSINFO_SP_SHIFT 5 - -#define IEEE80211_HT_CTL_LEN 4 - struct ieee80211_hdr { __le16 frame_control; __le16 duration_id; @@ -150,25 +130,6 @@ struct ieee80211_hdr { u8 addr4[6]; } __attribute__ ((packed)); -struct ieee80211_hdr_3addr { - __le16 frame_control; - __le16 duration_id; - u8 addr1[6]; - u8 addr2[6]; - u8 addr3[6]; - __le16 seq_ctrl; -} __attribute__ ((packed)); - -struct ieee80211_qos_hdr { - __le16 frame_control; - __le16 duration_id; - u8 addr1[6]; - u8 addr2[6]; - u8 addr3[6]; - __le16 seq_ctrl; - __le16 qos_ctrl; -} __attribute__ ((packed)); - /** * ieee80211_has_tods - check if IEEE80211_FCTL_TODS is set * @fc: frame control bytes in little-endian byteorder @@ -746,10 +707,6 @@ struct ieee80211_mgmt { u8 action; u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN]; } __attribute__ ((packed)) sa_query; - struct { - u8 action; - u8 smps_control; - } __attribute__ ((packed)) ht_smps; } u; } __attribute__ ((packed)) action; } u; @@ -814,10 +771,7 @@ struct ieee80211_bar { /** * struct ieee80211_mcs_info - MCS information * @rx_mask: RX mask - * @rx_highest: highest supported RX rate. If set represents - * the highest supported RX data rate in units of 1 Mbps. - * If this field is 0 this value should not be used to - * consider the highest RX data rate supported. + * @rx_highest: highest supported RX rate * @tx_params: TX parameters */ struct ieee80211_mcs_info { @@ -870,7 +824,6 @@ struct ieee80211_ht_cap { #define IEEE80211_HT_CAP_LDPC_CODING 0x0001 #define IEEE80211_HT_CAP_SUP_WIDTH_20_40 0x0002 #define IEEE80211_HT_CAP_SM_PS 0x000C -#define IEEE80211_HT_CAP_SM_PS_SHIFT 2 #define IEEE80211_HT_CAP_GRN_FLD 0x0010 #define IEEE80211_HT_CAP_SGI_20 0x0020 #define IEEE80211_HT_CAP_SGI_40 0x0040 @@ -886,7 +839,6 @@ struct ieee80211_ht_cap { /* 802.11n HT capability AMPDU settings (for ampdu_params_info) */ #define IEEE80211_HT_AMPDU_PARM_FACTOR 0x03 #define IEEE80211_HT_AMPDU_PARM_DENSITY 0x1C -#define IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT 2 /* * Maximum length of AMPDU that the STA can receive. @@ -970,17 +922,12 @@ struct ieee80211_ht_info { #define IEEE80211_MAX_AMPDU_BUF 0x40 -/* Spatial Multiplexing Power Save Modes (for capability) */ +/* Spatial Multiplexing Power Save Modes */ #define WLAN_HT_CAP_SM_PS_STATIC 0 #define WLAN_HT_CAP_SM_PS_DYNAMIC 1 #define WLAN_HT_CAP_SM_PS_INVALID 2 #define WLAN_HT_CAP_SM_PS_DISABLED 3 -/* for SM power control field lower two bits */ -#define WLAN_HT_SMPS_CONTROL_DISABLED 0 -#define WLAN_HT_SMPS_CONTROL_STATIC 1 -#define WLAN_HT_SMPS_CONTROL_DYNAMIC 3 - /* Authentication algorithms */ #define WLAN_AUTH_OPEN 0 #define WLAN_AUTH_SHARED_KEY 1 @@ -1124,12 +1071,12 @@ enum ieee80211_eid { WLAN_EID_TIM = 5, WLAN_EID_IBSS_PARAMS = 6, WLAN_EID_CHALLENGE = 16, - + /* 802.11d */ WLAN_EID_COUNTRY = 7, WLAN_EID_HP_PARAMS = 8, WLAN_EID_HP_TABLE = 9, WLAN_EID_REQUEST = 10, - + /* 802.11e */ WLAN_EID_QBSS_LOAD = 11, WLAN_EID_EDCA_PARAM_SET = 12, WLAN_EID_TSPEC = 13, @@ -1152,7 +1099,7 @@ enum ieee80211_eid { WLAN_EID_PREP = 69, WLAN_EID_PERR = 70, WLAN_EID_RANN = 49, /* compatible with FreeBSD */ - + /* 802.11h */ WLAN_EID_PWR_CONSTRAINT = 32, WLAN_EID_PWR_CAPABILITY = 33, WLAN_EID_TPC_REQUEST = 34, @@ -1163,41 +1110,20 @@ enum ieee80211_eid { WLAN_EID_MEASURE_REPORT = 39, WLAN_EID_QUIET = 40, WLAN_EID_IBSS_DFS = 41, - + /* 802.11g */ WLAN_EID_ERP_INFO = 42, WLAN_EID_EXT_SUPP_RATES = 50, - + /* 802.11n */ WLAN_EID_HT_CAPABILITY = 45, WLAN_EID_HT_INFORMATION = 61, - + /* 802.11i */ WLAN_EID_RSN = 48, - WLAN_EID_MMIE = 76, + WLAN_EID_TIMEOUT_INTERVAL = 56, + WLAN_EID_MMIE = 76 /* 802.11w */, WLAN_EID_WPA = 221, WLAN_EID_GENERIC = 221, WLAN_EID_VENDOR_SPECIFIC = 221, - WLAN_EID_QOS_PARAMETER = 222, - - WLAN_EID_AP_CHAN_REPORT = 51, - WLAN_EID_NEIGHBOR_REPORT = 52, - WLAN_EID_RCPI = 53, - WLAN_EID_BSS_AVG_ACCESS_DELAY = 63, - WLAN_EID_ANTENNA_INFO = 64, - WLAN_EID_RSNI = 65, - WLAN_EID_MEASUREMENT_PILOT_TX_INFO = 66, - WLAN_EID_BSS_AVAILABLE_CAPACITY = 67, - WLAN_EID_BSS_AC_ACCESS_DELAY = 68, - WLAN_EID_RRM_ENABLED_CAPABILITIES = 70, - WLAN_EID_MULTIPLE_BSSID = 71, - - WLAN_EID_MOBILITY_DOMAIN = 54, - WLAN_EID_FAST_BSS_TRANSITION = 55, - WLAN_EID_TIMEOUT_INTERVAL = 56, - WLAN_EID_RIC_DATA = 57, - WLAN_EID_RIC_DESCRIPTOR = 75, - - WLAN_EID_DSE_REGISTERED_LOCATION = 58, - WLAN_EID_SUPPORTED_REGULATORY_CLASSES = 59, - WLAN_EID_EXT_CHANSWITCH_ANN = 60, + WLAN_EID_QOS_PARAMETER = 222 }; /* Action category code */ @@ -1224,18 +1150,6 @@ enum ieee80211_spectrum_mgmt_actioncode { WLAN_ACTION_SPCT_CHL_SWITCH = 4, }; -/* HT action codes */ -enum ieee80211_ht_actioncode { - WLAN_HT_ACTION_NOTIFY_CHANWIDTH = 0, - WLAN_HT_ACTION_SMPS = 1, - WLAN_HT_ACTION_PSMP = 2, - WLAN_HT_ACTION_PCO_PHASE = 3, - WLAN_HT_ACTION_CSI = 4, - WLAN_HT_ACTION_NONCOMPRESSED_BF = 5, - WLAN_HT_ACTION_COMPRESSED_BF = 6, - WLAN_HT_ACTION_ASEL_IDX_FEEDBACK = 7, -}; - /* Security key length */ enum ieee80211_key_len { WLAN_KEY_LEN_WEP40 = 5, diff --git a/trunk/include/linux/nl80211.h b/trunk/include/linux/nl80211.h index 28ba20fda3e2..da8ea2e19273 100644 --- a/trunk/include/linux/nl80211.h +++ b/trunk/include/linux/nl80211.h @@ -3,7 +3,7 @@ /* * 802.11 netlink interface public header * - * Copyright 2006-2010 Johannes Berg + * Copyright 2006, 2007, 2008 Johannes Berg * Copyright 2008 Michael Wu * Copyright 2008 Luis Carlos Cobo * Copyright 2008 Michael Buesch @@ -270,60 +270,6 @@ * @NL80211_CMD_SET_WIPHY_NETNS: Set a wiphy's netns. Note that all devices * associated with this wiphy must be down and will follow. * - * @NL80211_CMD_REMAIN_ON_CHANNEL: Request to remain awake on the specified - * channel for the specified amount of time. This can be used to do - * off-channel operations like transmit a Public Action frame and wait for - * a response while being associated to an AP on another channel. - * %NL80211_ATTR_WIPHY or %NL80211_ATTR_IFINDEX is used to specify which - * radio is used. %NL80211_ATTR_WIPHY_FREQ is used to specify the - * frequency for the operation and %NL80211_ATTR_WIPHY_CHANNEL_TYPE may be - * optionally used to specify additional channel parameters. - * %NL80211_ATTR_DURATION is used to specify the duration in milliseconds - * to remain on the channel. This command is also used as an event to - * notify when the requested duration starts (it may take a while for the - * driver to schedule this time due to other concurrent needs for the - * radio). - * When called, this operation returns a cookie (%NL80211_ATTR_COOKIE) - * that will be included with any events pertaining to this request; - * the cookie is also used to cancel the request. - * @NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL: This command can be used to cancel a - * pending remain-on-channel duration if the desired operation has been - * completed prior to expiration of the originally requested duration. - * %NL80211_ATTR_WIPHY or %NL80211_ATTR_IFINDEX is used to specify the - * radio. The %NL80211_ATTR_COOKIE attribute must be given as well to - * uniquely identify the request. - * This command is also used as an event to notify when a requested - * remain-on-channel duration has expired. - * - * @NL80211_CMD_SET_TX_BITRATE_MASK: Set the mask of rates to be used in TX - * rate selection. %NL80211_ATTR_IFINDEX is used to specify the interface - * and @NL80211_ATTR_TX_RATES the set of allowed rates. - * - * @NL80211_CMD_REGISTER_ACTION: Register for receiving certain action frames - * (via @NL80211_CMD_ACTION) for processing in userspace. This command - * requires an interface index and a match attribute containing the first - * few bytes of the frame that should match, e.g. a single byte for only - * a category match or four bytes for vendor frames including the OUI. - * The registration cannot be dropped, but is removed automatically - * when the netlink socket is closed. Multiple registrations can be made. - * @NL80211_CMD_ACTION: Action frame TX request and RX notification. This - * command is used both as a request to transmit an Action frame and as an - * event indicating reception of an Action frame that was not processed in - * kernel code, but is for us (i.e., which may need to be processed in a - * user space application). %NL80211_ATTR_FRAME is used to specify the - * frame contents (including header). %NL80211_ATTR_WIPHY_FREQ (and - * optionally %NL80211_ATTR_WIPHY_CHANNEL_TYPE) is used to indicate on - * which channel the frame is to be transmitted or was received. This - * channel has to be the current channel (remain-on-channel or the - * operational channel). When called, this operation returns a cookie - * (%NL80211_ATTR_COOKIE) that will be included with the TX status event - * pertaining to the TX request. - * @NL80211_CMD_ACTION_TX_STATUS: Report TX status of an Action frame - * transmitted with %NL80211_CMD_ACTION. %NL80211_ATTR_COOKIE identifies - * the TX command and %NL80211_ATTR_FRAME includes the contents of the - * frame. %NL80211_ATTR_ACK flag is included if the recipient acknowledged - * the frame. - * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -407,18 +353,6 @@ enum nl80211_commands { NL80211_CMD_DEL_PMKSA, NL80211_CMD_FLUSH_PMKSA, - NL80211_CMD_REMAIN_ON_CHANNEL, - NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, - - NL80211_CMD_SET_TX_BITRATE_MASK, - - NL80211_CMD_REGISTER_ACTION, - NL80211_CMD_ACTION, - NL80211_CMD_ACTION_TX_STATUS, - - NL80211_CMD_SET_POWER_SAVE, - NL80211_CMD_GET_POWER_SAVE, - /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -468,8 +402,6 @@ enum nl80211_commands { * @NL80211_ATTR_WIPHY_RTS_THRESHOLD: RTS threshold (TX frames with length * larger than or equal to this use RTS/CTS handshake); allowed range: * 0..65536, disable with (u32)-1; dot11RTSThreshold; u32 - * @NL80211_ATTR_WIPHY_COVERAGE_CLASS: Coverage Class as defined by IEEE 802.11 - * section 7.3.2.9; dot11CoverageClass; u8 * * @NL80211_ATTR_IFINDEX: network interface index of the device to operate on * @NL80211_ATTR_IFNAME: network interface name @@ -674,23 +606,6 @@ enum nl80211_commands { * @NL80211_ATTR_MAX_NUM_PMKIDS: maximum number of PMKIDs a firmware can * cache, a wiphy attribute. * - * @NL80211_ATTR_DURATION: Duration of an operation in milliseconds, u32. - * - * @NL80211_ATTR_COOKIE: Generic 64-bit cookie to identify objects. - * - * @NL80211_ATTR_TX_RATES: Nested set of attributes - * (enum nl80211_tx_rate_attributes) describing TX rates per band. The - * enum nl80211_band value is used as the index (nla_type() of the nested - * data. If a band is not included, it will be configured to allow all - * rates based on negotiated supported rates information. This attribute - * is used with %NL80211_CMD_SET_TX_BITRATE_MASK. - * - * @NL80211_ATTR_FRAME_MATCH: A binary attribute which typically must contain - * at least one byte, currently used with @NL80211_CMD_REGISTER_ACTION. - * - * @NL80211_ATTR_ACK: Flag attribute indicating that the frame was - * acknowledged by the recipient. - * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -828,20 +743,6 @@ enum nl80211_attrs { NL80211_ATTR_PMKID, NL80211_ATTR_MAX_NUM_PMKIDS, - NL80211_ATTR_DURATION, - - NL80211_ATTR_COOKIE, - - NL80211_ATTR_WIPHY_COVERAGE_CLASS, - - NL80211_ATTR_TX_RATES, - - NL80211_ATTR_FRAME_MATCH, - - NL80211_ATTR_ACK, - - NL80211_ATTR_PS_STATE, - /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -1422,20 +1323,13 @@ enum nl80211_channel_type { * @NL80211_BSS_BEACON_INTERVAL: beacon interval of the (I)BSS (u16) * @NL80211_BSS_CAPABILITY: capability field (CPU order, u16) * @NL80211_BSS_INFORMATION_ELEMENTS: binary attribute containing the - * raw information elements from the probe response/beacon (bin); - * if the %NL80211_BSS_BEACON_IES attribute is present, the IEs here are - * from a Probe Response frame; otherwise they are from a Beacon frame. - * However, if the driver does not indicate the source of the IEs, these - * IEs may be from either frame subtype. + * raw information elements from the probe response/beacon (bin) * @NL80211_BSS_SIGNAL_MBM: signal strength of probe response/beacon * in mBm (100 * dBm) (s32) * @NL80211_BSS_SIGNAL_UNSPEC: signal strength of the probe response/beacon * in unspecified units, scaled to 0..100 (u8) * @NL80211_BSS_STATUS: status, if this BSS is "used" * @NL80211_BSS_SEEN_MS_AGO: age of this BSS entry in ms - * @NL80211_BSS_BEACON_IES: binary attribute containing the raw information - * elements from a Beacon frame (bin); not present if no Beacon frame has - * yet been received * @__NL80211_BSS_AFTER_LAST: internal * @NL80211_BSS_MAX: highest BSS attribute */ @@ -1451,7 +1345,6 @@ enum nl80211_bss { NL80211_BSS_SIGNAL_UNSPEC, NL80211_BSS_STATUS, NL80211_BSS_SEEN_MS_AGO, - NL80211_BSS_BEACON_IES, /* keep last */ __NL80211_BSS_AFTER_LAST, @@ -1549,38 +1442,4 @@ enum nl80211_key_attributes { NL80211_KEY_MAX = __NL80211_KEY_AFTER_LAST - 1 }; -/** - * enum nl80211_tx_rate_attributes - TX rate set attributes - * @__NL80211_TXRATE_INVALID: invalid - * @NL80211_TXRATE_LEGACY: Legacy (non-MCS) rates allowed for TX rate selection - * in an array of rates as defined in IEEE 802.11 7.3.2.2 (u8 values with - * 1 = 500 kbps) but without the IE length restriction (at most - * %NL80211_MAX_SUPP_RATES in a single array). - * @__NL80211_TXRATE_AFTER_LAST: internal - * @NL80211_TXRATE_MAX: highest TX rate attribute - */ -enum nl80211_tx_rate_attributes { - __NL80211_TXRATE_INVALID, - NL80211_TXRATE_LEGACY, - - /* keep last */ - __NL80211_TXRATE_AFTER_LAST, - NL80211_TXRATE_MAX = __NL80211_TXRATE_AFTER_LAST - 1 -}; - -/** - * enum nl80211_band - Frequency band - * @NL80211_BAND_2GHZ - 2.4 GHz ISM band - * @NL80211_BAND_5GHZ - around 5 GHz band (4.9 - 5.7 GHz) - */ -enum nl80211_band { - NL80211_BAND_2GHZ, - NL80211_BAND_5GHZ, -}; - -enum nl80211_ps_state { - NL80211_PS_DISABLED, - NL80211_PS_ENABLED, -}; - #endif /* __LINUX_NL80211_H */ diff --git a/trunk/include/net/cfg80211.h b/trunk/include/net/cfg80211.h index 3d134a1fb96b..0884b9a0f778 100644 --- a/trunk/include/net/cfg80211.h +++ b/trunk/include/net/cfg80211.h @@ -3,7 +3,7 @@ /* * 802.11 device and configuration interface * - * Copyright 2006-2010 Johannes Berg + * Copyright 2006-2009 Johannes Berg * * 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 @@ -39,8 +39,8 @@ * @IEEE80211_BAND_5GHZ: around 5GHz band (4.9-5.7) */ enum ieee80211_band { - IEEE80211_BAND_2GHZ = NL80211_BAND_2GHZ, - IEEE80211_BAND_5GHZ = NL80211_BAND_5GHZ, + IEEE80211_BAND_2GHZ, + IEEE80211_BAND_5GHZ, /* keep last */ IEEE80211_NUM_BANDS @@ -626,14 +626,8 @@ enum cfg80211_signal_type { * @beacon_interval: the beacon interval as from the frame * @capability: the capability field in host byte order * @information_elements: the information elements (Note that there - * is no guarantee that these are well-formed!); this is a pointer to - * either the beacon_ies or proberesp_ies depending on whether Probe - * Response frame has been received + * is no guarantee that these are well-formed!) * @len_information_elements: total length of the information elements - * @beacon_ies: the information elements from the last Beacon frame - * @len_beacon_ies: total length of the beacon_ies - * @proberesp_ies: the information elements from the last Probe Response frame - * @len_proberesp_ies: total length of the proberesp_ies * @signal: signal strength value (type depends on the wiphy's signal_type) * @free_priv: function pointer to free private data * @priv: private area for driver use, has at least wiphy->bss_priv_size bytes @@ -647,10 +641,6 @@ struct cfg80211_bss { u16 capability; u8 *information_elements; size_t len_information_elements; - u8 *beacon_ies; - size_t len_beacon_ies; - u8 *proberesp_ies; - size_t len_proberesp_ies; s32 signal; @@ -847,7 +837,6 @@ enum wiphy_params_flags { WIPHY_PARAM_RETRY_LONG = 1 << 1, WIPHY_PARAM_FRAG_THRESHOLD = 1 << 2, WIPHY_PARAM_RTS_THRESHOLD = 1 << 3, - WIPHY_PARAM_COVERAGE_CLASS = 1 << 4, }; /** @@ -867,11 +856,20 @@ enum tx_power_setting { * cfg80211_bitrate_mask - masks for bitrate control */ struct cfg80211_bitrate_mask { +/* + * As discussed in Berlin, this struct really + * should look like this: + struct { u32 legacy; - /* TODO: add support for masking MCS rates; e.g.: */ - /* u8 mcs[IEEE80211_HT_MCS_MASK_LEN]; */ + u8 mcs[IEEE80211_HT_MCS_MASK_LEN]; } control[IEEE80211_NUM_BANDS]; + + * Since we can always fix in-kernel users, let's keep + * it simpler for now: + */ + u32 fixed; /* fixed bitrate, 0 == not fixed */ + u32 maxrate; /* in kbps, 0 == no limit */ }; /** * struct cfg80211_pmksa - PMK Security Association @@ -990,16 +988,6 @@ struct cfg80211_pmksa { * * @dump_survey: get site survey information. * - * @remain_on_channel: Request the driver to remain awake on the specified - * channel for the specified duration to complete an off-channel - * operation (e.g., public action frame exchange). When the driver is - * ready on the requested channel, it must indicate this with an event - * notification by calling cfg80211_ready_on_channel(). - * @cancel_remain_on_channel: Cancel an on-going remain-on-channel operation. - * This allows the operation to be terminated prior to timeout based on - * the duration value. - * @action: Transmit an action frame - * * @testmode_cmd: run a test mode command * * @set_pmksa: Cache a PMKID for a BSSID. This is mostly useful for fullmac @@ -1135,21 +1123,7 @@ struct cfg80211_ops { struct cfg80211_pmksa *pmksa); int (*flush_pmksa)(struct wiphy *wiphy, struct net_device *netdev); - int (*remain_on_channel)(struct wiphy *wiphy, - struct net_device *dev, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, - unsigned int duration, - u64 *cookie); - int (*cancel_remain_on_channel)(struct wiphy *wiphy, - struct net_device *dev, - u64 cookie); - - int (*action)(struct wiphy *wiphy, struct net_device *dev, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, - const u8 *buf, size_t len, u64 *cookie); - + /* some temporary stuff to finish wext */ int (*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev, bool enabled, int timeout); }; @@ -1200,10 +1174,6 @@ enum wiphy_flags { WIPHY_FLAG_4ADDR_STATION = BIT(6), }; -struct mac_address { - u8 addr[ETH_ALEN]; -}; - /** * struct wiphy - wireless hardware description * @idx: the wiphy index assigned to this item @@ -1222,28 +1192,12 @@ struct mac_address { * -1 = fragmentation disabled, only odd values >= 256 used * @rts_threshold: RTS threshold (dot11RTSThreshold); -1 = RTS/CTS disabled * @net: the network namespace this wiphy currently lives in - * @perm_addr: permanent MAC address of this device - * @addr_mask: If the device supports multiple MAC addresses by masking, - * set this to a mask with variable bits set to 1, e.g. if the last - * four bits are variable then set it to 00:...:00:0f. The actual - * variable bits shall be determined by the interfaces added, with - * interfaces not matching the mask being rejected to be brought up. - * @n_addresses: number of addresses in @addresses. - * @addresses: If the device has more than one address, set this pointer - * to a list of addresses (6 bytes each). The first one will be used - * by default for perm_addr. In this case, the mask should be set to - * all-zeroes. In this case it is assumed that the device can handle - * the same number of arbitrary MAC addresses. */ struct wiphy { /* assign these fields before you register the wiphy */ - /* permanent MAC address(es) */ + /* permanent MAC address */ u8 perm_addr[ETH_ALEN]; - u8 addr_mask[ETH_ALEN]; - - u16 n_addresses; - struct mac_address *addresses; /* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */ u16 interface_modes; @@ -1263,7 +1217,6 @@ struct wiphy { u8 retry_long; u32 frag_threshold; u32 rts_threshold; - u8 coverage_class; char fw_version[ETHTOOL_BUSINFO_LEN]; u32 hw_version; @@ -1450,8 +1403,6 @@ struct cfg80211_cached_keys; * set by driver (if supported) on add_interface BEFORE registering the * netdev and may otherwise be used by driver read-only, will be update * by cfg80211 on change_interface - * @action_registrations: list of registrations for action frames - * @action_registrations_lock: lock for the list */ struct wireless_dev { struct wiphy *wiphy; @@ -1461,9 +1412,6 @@ struct wireless_dev { struct list_head list; struct net_device *netdev; - struct list_head action_registrations; - spinlock_t action_registrations_lock; - struct mutex mtx; struct work_struct cleanup_work; @@ -1488,9 +1436,6 @@ struct wireless_dev { struct cfg80211_internal_bss *auth_bsses[MAX_AUTH_BSSES]; struct cfg80211_internal_bss *current_bss; /* associated / joined */ - bool ps; - int ps_timeout; - #ifdef CONFIG_CFG80211_WEXT /* wext data */ struct { @@ -1502,7 +1447,8 @@ struct wireless_dev { u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; u8 ssid[IEEE80211_MAX_SSID_LEN]; s8 default_key, default_mgmt_key; - bool prev_bssid_valid; + bool ps, prev_bssid_valid; + int ps_timeout; } wext; #endif }; @@ -1573,82 +1519,37 @@ ieee80211_get_response_rate(struct ieee80211_supported_band *sband, * Documentation in Documentation/networking/radiotap-headers.txt */ -struct radiotap_align_size { - uint8_t align:4, size:4; -}; - -struct ieee80211_radiotap_namespace { - const struct radiotap_align_size *align_size; - int n_bits; - uint32_t oui; - uint8_t subns; -}; - -struct ieee80211_radiotap_vendor_namespaces { - const struct ieee80211_radiotap_namespace *ns; - int n_ns; -}; - /** * struct ieee80211_radiotap_iterator - tracks walk thru present radiotap args - * @this_arg_index: index of current arg, valid after each successful call - * to ieee80211_radiotap_iterator_next() - * @this_arg: pointer to current radiotap arg; it is valid after each - * call to ieee80211_radiotap_iterator_next() but also after - * ieee80211_radiotap_iterator_init() where it will point to - * the beginning of the actual data portion - * @this_arg_size: length of the current arg, for convenience - * @current_namespace: pointer to the current namespace definition - * (or internally %NULL if the current namespace is unknown) - * @is_radiotap_ns: indicates whether the current namespace is the default - * radiotap namespace or not - * - * @overrides: override standard radiotap fields - * @n_overrides: number of overrides - * - * @_rtheader: pointer to the radiotap header we are walking through - * @_max_length: length of radiotap header in cpu byte ordering - * @_arg_index: next argument index - * @_arg: next argument pointer - * @_next_bitmap: internal pointer to next present u32 - * @_bitmap_shifter: internal shifter for curr u32 bitmap, b0 set == arg present - * @_vns: vendor namespace definitions - * @_next_ns_data: beginning of the next namespace's data - * @_reset_on_ext: internal; reset the arg index to 0 when going to the - * next bitmap word - * - * Describes the radiotap parser state. Fields prefixed with an underscore - * must not be used by users of the parser, only by the parser internally. + * @rtheader: pointer to the radiotap header we are walking through + * @max_length: length of radiotap header in cpu byte ordering + * @this_arg_index: IEEE80211_RADIOTAP_... index of current arg + * @this_arg: pointer to current radiotap arg + * @arg_index: internal next argument index + * @arg: internal next argument pointer + * @next_bitmap: internal pointer to next present u32 + * @bitmap_shifter: internal shifter for curr u32 bitmap, b0 set == arg present */ struct ieee80211_radiotap_iterator { - struct ieee80211_radiotap_header *_rtheader; - const struct ieee80211_radiotap_vendor_namespaces *_vns; - const struct ieee80211_radiotap_namespace *current_namespace; - - unsigned char *_arg, *_next_ns_data; - uint32_t *_next_bitmap; - - unsigned char *this_arg; + struct ieee80211_radiotap_header *rtheader; + int max_length; int this_arg_index; - int this_arg_size; - - int is_radiotap_ns; + u8 *this_arg; - int _max_length; - int _arg_index; - uint32_t _bitmap_shifter; - int _reset_on_ext; + int arg_index; + u8 *arg; + __le32 *next_bitmap; + u32 bitmap_shifter; }; extern int ieee80211_radiotap_iterator_init( - struct ieee80211_radiotap_iterator *iterator, - struct ieee80211_radiotap_header *radiotap_header, - int max_length, const struct ieee80211_radiotap_vendor_namespaces *vns); + struct ieee80211_radiotap_iterator *iterator, + struct ieee80211_radiotap_header *radiotap_header, + int max_length); extern int ieee80211_radiotap_iterator_next( - struct ieee80211_radiotap_iterator *iterator); - + struct ieee80211_radiotap_iterator *iterator); extern const unsigned char rfc1042_header[6]; extern const unsigned char bridge_tunnel_header[6]; @@ -1677,7 +1578,7 @@ unsigned int ieee80211_hdrlen(__le16 fc); * @addr: the device MAC address * @iftype: the virtual interface type */ -int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, +int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr, enum nl80211_iftype iftype); /** @@ -1688,49 +1589,15 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, * @bssid: the network bssid (used only for iftype STATION and ADHOC) * @qos: build 802.11 QoS data frame */ -int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr, +int ieee80211_data_from_8023(struct sk_buff *skb, u8 *addr, enum nl80211_iftype iftype, u8 *bssid, bool qos); -/** - * ieee80211_amsdu_to_8023s - decode an IEEE 802.11n A-MSDU frame - * - * Decode an IEEE 802.11n A-MSDU frame and convert it to a list of - * 802.3 frames. The @list will be empty if the decode fails. The - * @skb is consumed after the function returns. - * - * @skb: The input IEEE 802.11n A-MSDU frame. - * @list: The output list of 802.3 frames. It must be allocated and - * initialized by by the caller. - * @addr: The device MAC address. - * @iftype: The device interface type. - * @extra_headroom: The hardware extra headroom for SKBs in the @list. - */ -void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, - const u8 *addr, enum nl80211_iftype iftype, - const unsigned int extra_headroom); - /** * cfg80211_classify8021d - determine the 802.1p/1d tag for a data frame * @skb: the data frame */ unsigned int cfg80211_classify8021d(struct sk_buff *skb); -/** - * cfg80211_find_ie - find information element in data - * - * @eid: element ID - * @ies: data consisting of IEs - * @len: length of data - * - * This function will return %NULL if the element ID could - * not be found or if the element is invalid (claims to be - * longer than the given data), or a pointer to the first byte - * of the requested element, that is the byte containing the - * element ID. There are no checks on the element length - * other than having to fit into the given data. - */ -const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len); - /* * Regulatory helper functions for wiphys */ @@ -2262,79 +2129,5 @@ void cfg80211_roamed(struct net_device *dev, const u8 *bssid, void cfg80211_disconnected(struct net_device *dev, u16 reason, u8 *ie, size_t ie_len, gfp_t gfp); -/** - * cfg80211_ready_on_channel - notification of remain_on_channel start - * @dev: network device - * @cookie: the request cookie - * @chan: The current channel (from remain_on_channel request) - * @channel_type: Channel type - * @duration: Duration in milliseconds that the driver intents to remain on the - * channel - * @gfp: allocation flags - */ -void cfg80211_ready_on_channel(struct net_device *dev, u64 cookie, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, - unsigned int duration, gfp_t gfp); - -/** - * cfg80211_remain_on_channel_expired - remain_on_channel duration expired - * @dev: network device - * @cookie: the request cookie - * @chan: The current channel (from remain_on_channel request) - * @channel_type: Channel type - * @gfp: allocation flags - */ -void cfg80211_remain_on_channel_expired(struct net_device *dev, - u64 cookie, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, - gfp_t gfp); - - -/** - * cfg80211_new_sta - notify userspace about station - * - * @dev: the netdev - * @mac_addr: the station's address - * @sinfo: the station information - * @gfp: allocation flags - */ -void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr, - struct station_info *sinfo, gfp_t gfp); - -/** - * cfg80211_rx_action - notification of received, unprocessed Action frame - * @dev: network device - * @freq: Frequency on which the frame was received in MHz - * @buf: Action frame (header + body) - * @len: length of the frame data - * @gfp: context flags - * Returns %true if a user space application is responsible for rejecting the - * unrecognized Action frame; %false if no such application is registered - * (i.e., the driver is responsible for rejecting the unrecognized Action - * frame) - * - * This function is called whenever an Action frame is received for a station - * mode interface, but is not processed in kernel. - */ -bool cfg80211_rx_action(struct net_device *dev, int freq, const u8 *buf, - size_t len, gfp_t gfp); - -/** - * cfg80211_action_tx_status - notification of TX status for Action frame - * @dev: network device - * @cookie: Cookie returned by cfg80211_ops::action() - * @buf: Action frame (header + body) - * @len: length of the frame data - * @ack: Whether frame was acknowledged - * @gfp: context flags - * - * This function is called whenever an Action frame was requested to be - * transmitted with cfg80211_ops::action() to report the TX status of the - * transmission attempt. - */ -void cfg80211_action_tx_status(struct net_device *dev, u64 cookie, - const u8 *buf, size_t len, bool ack, gfp_t gfp); #endif /* __NET_CFG80211_H */ diff --git a/trunk/include/net/ieee80211_radiotap.h b/trunk/include/net/ieee80211_radiotap.h index af49f8ab7f81..9d3d86aaccbb 100644 --- a/trunk/include/net/ieee80211_radiotap.h +++ b/trunk/include/net/ieee80211_radiotap.h @@ -198,10 +198,6 @@ enum ieee80211_radiotap_type { IEEE80211_RADIOTAP_TX_FLAGS = 15, IEEE80211_RADIOTAP_RTS_RETRIES = 16, IEEE80211_RADIOTAP_DATA_RETRIES = 17, - - /* valid in every it_present bitmap, even vendor namespaces */ - IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE = 29, - IEEE80211_RADIOTAP_VENDOR_NAMESPACE = 30, IEEE80211_RADIOTAP_EXT = 31 }; diff --git a/trunk/include/net/mac80211.h b/trunk/include/net/mac80211.h index 80eb7cc42ce9..0bf369752274 100644 --- a/trunk/include/net/mac80211.h +++ b/trunk/include/net/mac80211.h @@ -3,7 +3,7 @@ * * Copyright 2002-2005, Devicescape Software, Inc. * Copyright 2006-2007 Jiri Benc - * Copyright 2007-2010 Johannes Berg + * Copyright 2007-2008 Johannes Berg * * 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 @@ -107,14 +107,25 @@ enum ieee80211_max_queues { * 2^n-1 in the range 1..32767] * @cw_max: maximum contention window [like @cw_min] * @txop: maximum burst time in units of 32 usecs, 0 meaning disabled - * @uapsd: is U-APSD mode enabled for the queue */ struct ieee80211_tx_queue_params { u16 txop; u16 cw_min; u16 cw_max; u8 aifs; - bool uapsd; +}; + +/** + * struct ieee80211_tx_queue_stats - transmit queue statistics + * + * @len: number of packets in queue + * @limit: queue length limit + * @count: number of frames sent + */ +struct ieee80211_tx_queue_stats { + unsigned int len; + unsigned int limit; + unsigned int count; }; struct ieee80211_low_level_stats { @@ -173,8 +184,7 @@ enum ieee80211_bss_change { * @use_short_slot: use short slot time (only relevant for ERP); * if the hardware cannot handle this it must set the * IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE hardware flag - * @dtim_period: num of beacons before the next DTIM, for beaconing, - * not valid in station mode (cf. hw conf ps_dtim_period) + * @dtim_period: num of beacons before the next DTIM, for PSM * @timestamp: beacon timestamp * @beacon_int: beacon interval * @assoc_capability: capabilities taken from assoc resp @@ -245,6 +255,9 @@ struct ieee80211_bss_conf { * @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_INTFL_RCALGO: mac80211 internal flag, do not test or + * set this flag in the driver; indicates that the rate control + * algorithm was used and should be notified of TX status * @IEEE80211_TX_INTFL_NEED_TXPROCESSING: completely internal to mac80211, * used to indicate that a pending frame requires TX processing before * it can be sent out. @@ -259,14 +272,6 @@ struct ieee80211_bss_conf { * transmit function after the current frame, this can be used * by drivers to kick the DMA queue only if unset or when the * queue gets full. - * @IEEE80211_TX_INTFL_RETRANSMISSION: This frame is being retransmitted - * after TX status because the destination was asleep, it must not - * be modified again (no seqno assignment, crypto, etc.) - * @IEEE80211_TX_INTFL_HAS_RADIOTAP: This frame was injected and still - * has a radiotap header at skb->data. - * @IEEE80211_TX_INTFL_NL80211_FRAME_TX: Frame was requested through nl80211 - * MLME command (internal to mac80211 to figure out whether to send TX - * status to user space) */ enum mac80211_tx_control_flags { IEEE80211_TX_CTL_REQ_TX_STATUS = BIT(0), @@ -282,14 +287,12 @@ enum mac80211_tx_control_flags { IEEE80211_TX_STAT_AMPDU = BIT(10), IEEE80211_TX_STAT_AMPDU_NO_BACK = BIT(11), IEEE80211_TX_CTL_RATE_CTRL_PROBE = BIT(12), + IEEE80211_TX_INTFL_RCALGO = BIT(13), IEEE80211_TX_INTFL_NEED_TXPROCESSING = BIT(14), IEEE80211_TX_INTFL_RETRIED = BIT(15), IEEE80211_TX_INTFL_DONT_ENCRYPT = BIT(16), IEEE80211_TX_CTL_PSPOLL_RESPONSE = BIT(17), IEEE80211_TX_CTL_MORE_FRAMES = BIT(18), - IEEE80211_TX_INTFL_RETRANSMISSION = BIT(19), - IEEE80211_TX_INTFL_HAS_RADIOTAP = BIT(20), - IEEE80211_TX_INTFL_NL80211_FRAME_TX = BIT(21), }; /** @@ -568,13 +571,7 @@ struct ieee80211_rx_status { * @IEEE80211_CONF_MONITOR: there's a monitor interface present -- use this * to determine for example whether to calculate timestamps for packets * or not, do not use instead of filter flags! - * @IEEE80211_CONF_PS: Enable 802.11 power save mode (managed mode only). - * This is the power save mode defined by IEEE 802.11-2007 section 11.2, - * meaning that the hardware still wakes up for beacons, is able to - * transmit frames and receive the possible acknowledgment frames. - * Not to be confused with hardware specific wakeup/sleep states, - * driver is responsible for that. See the section "Powersave support" - * for more. + * @IEEE80211_CONF_PS: Enable 802.11 power save mode (managed mode only) * @IEEE80211_CONF_IDLE: The device is running, but idle; if the flag is set * the driver should be prepared to handle configuration requests but * may turn the device off as much as possible. Typically, this flag will @@ -598,10 +595,8 @@ enum ieee80211_conf_flags { * @IEEE80211_CONF_CHANGE_CHANNEL: the channel/channel_type changed * @IEEE80211_CONF_CHANGE_RETRY_LIMITS: retry limits changed * @IEEE80211_CONF_CHANGE_IDLE: Idle flag changed - * @IEEE80211_CONF_CHANGE_SMPS: Spatial multiplexing powersave mode changed */ enum ieee80211_conf_changed { - IEEE80211_CONF_CHANGE_SMPS = BIT(1), IEEE80211_CONF_CHANGE_LISTEN_INTERVAL = BIT(2), IEEE80211_CONF_CHANGE_MONITOR = BIT(3), IEEE80211_CONF_CHANGE_PS = BIT(4), @@ -611,25 +606,6 @@ enum ieee80211_conf_changed { IEEE80211_CONF_CHANGE_IDLE = BIT(8), }; -/** - * enum ieee80211_smps_mode - spatial multiplexing power save mode - * - * @IEEE80211_SMPS_AUTOMATIC: automatic - * @IEEE80211_SMPS_OFF: off - * @IEEE80211_SMPS_STATIC: static - * @IEEE80211_SMPS_DYNAMIC: dynamic - * @IEEE80211_SMPS_NUM_MODES: internal, don't use - */ -enum ieee80211_smps_mode { - IEEE80211_SMPS_AUTOMATIC, - IEEE80211_SMPS_OFF, - IEEE80211_SMPS_STATIC, - IEEE80211_SMPS_DYNAMIC, - - /* keep last */ - IEEE80211_SMPS_NUM_MODES, -}; - /** * struct ieee80211_conf - configuration of the device * @@ -643,9 +619,6 @@ enum ieee80211_smps_mode { * value will be only achievable between DTIM frames, the hardware * needs to check for the multicast traffic bit in DTIM beacons. * This variable is valid only when the CONF_PS flag is set. - * @ps_dtim_period: The DTIM period of the AP we're connected to, for use - * in power saving. Power saving will not be enabled until a beacon - * has been received and the DTIM period is known. * @dynamic_ps_timeout: The dynamic powersave timeout (in ms), see the * powersave documentation below. This variable is valid only when * the CONF_PS flag is set. @@ -661,10 +634,6 @@ enum ieee80211_smps_mode { * @short_frame_max_tx_count: Maximum number of transmissions for a "short" * frame, called "dot11ShortRetryLimit" in 802.11, but actually means the * number of transmissions not the number of retries - * - * @smps_mode: spatial multiplexing powersave mode; note that - * %IEEE80211_SMPS_STATIC is used when the device is not - * configured for an HT channel */ struct ieee80211_conf { u32 flags; @@ -672,13 +641,11 @@ struct ieee80211_conf { int max_sleep_period; u16 listen_interval; - u8 ps_dtim_period; u8 long_frame_max_tx_count, short_frame_max_tx_count; struct ieee80211_channel *channel; enum nl80211_channel_type channel_type; - enum ieee80211_smps_mode smps_mode; }; /** @@ -690,14 +657,12 @@ struct ieee80211_conf { * @type: type of this virtual interface * @bss_conf: BSS configuration for this interface, either our own * or the BSS we're associated to - * @addr: address of this interface * @drv_priv: data area for driver use, will always be aligned to * sizeof(void *). */ struct ieee80211_vif { enum nl80211_iftype type; struct ieee80211_bss_conf bss_conf; - u8 addr[ETH_ALEN]; /* must be last */ u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *)))); }; @@ -710,6 +675,33 @@ static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif) return false; } +/** + * struct ieee80211_if_init_conf - initial configuration of an interface + * + * @vif: pointer to a driver-use per-interface structure. The pointer + * itself is also used for various functions including + * ieee80211_beacon_get() and ieee80211_get_buffered_bc(). + * @type: one of &enum nl80211_iftype constants. Determines the type of + * added/removed interface. + * @mac_addr: pointer to MAC address of the interface. This pointer is valid + * until the interface is removed (i.e. it cannot be used after + * remove_interface() callback was called for this interface). + * + * This structure is used in add_interface() and remove_interface() + * callbacks of &struct ieee80211_hw. + * + * When you allow multiple interfaces to be added to your PHY, take care + * that the hardware can actually handle multiple MAC addresses. However, + * also take care that when there's no interface left with mac_addr != %NULL + * you remove the MAC address from the device to avoid acknowledging packets + * in pure monitor mode. + */ +struct ieee80211_if_init_conf { + enum nl80211_iftype type; + struct ieee80211_vif *vif; + void *mac_addr; +}; + /** * enum ieee80211_key_alg - key algorithm * @ALG_WEP: WEP40 or WEP104 @@ -805,7 +797,7 @@ enum set_key_cmd { * mac80211, any ieee80211_sta pointer you get access to must * either be protected by rcu_read_lock() explicitly or implicitly, * or you must take good care to not use such a pointer after a - * call to your sta_remove callback that removed it. + * call to your sta_notify callback that removed it. * * @addr: MAC address * @aid: AID we assigned to the station if we're an AP @@ -831,8 +823,8 @@ struct ieee80211_sta { * indicates addition and removal of a station to station table, * or if a associated station made a power state transition. * - * @STA_NOTIFY_ADD: (DEPRECATED) a station was added to the station table - * @STA_NOTIFY_REMOVE: (DEPRECATED) a station being removed from the station table + * @STA_NOTIFY_ADD: a station was added to the station table + * @STA_NOTIFY_REMOVE: a station being removed from the station table * @STA_NOTIFY_SLEEP: a station is now sleeping * @STA_NOTIFY_AWAKE: a sleeping station woke up */ @@ -934,26 +926,6 @@ enum ieee80211_tkip_key_type { * @IEEE80211_HW_BEACON_FILTER: * Hardware supports dropping of irrelevant beacon frames to * avoid waking up cpu. - * - * @IEEE80211_HW_SUPPORTS_STATIC_SMPS: - * Hardware supports static spatial multiplexing powersave, - * ie. can turn off all but one chain even on HT connections - * that should be using more chains. - * - * @IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS: - * Hardware supports dynamic spatial multiplexing powersave, - * ie. can turn off all but one chain and then wake the rest - * up as required after, for example, rts/cts handshake. - * - * @IEEE80211_HW_SUPPORTS_UAPSD: - * Hardware supports Unscheduled Automatic Power Save Delivery - * (U-APSD) in managed mode. The mode is configured with - * conf_tx() operation. - * - * @IEEE80211_HW_REPORTS_TX_ACK_STATUS: - * Hardware can provide ack status reports of Tx frames to - * the stack. - * */ enum ieee80211_hw_flags { IEEE80211_HW_HAS_RATE_CONTROL = 1<<0, @@ -971,10 +943,6 @@ enum ieee80211_hw_flags { IEEE80211_HW_SUPPORTS_DYNAMIC_PS = 1<<12, IEEE80211_HW_MFP_CAPABLE = 1<<13, IEEE80211_HW_BEACON_FILTER = 1<<14, - IEEE80211_HW_SUPPORTS_STATIC_SMPS = 1<<15, - IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS = 1<<16, - IEEE80211_HW_SUPPORTS_UAPSD = 1<<17, - IEEE80211_HW_REPORTS_TX_ACK_STATUS = 1<<18, }; /** @@ -1153,24 +1121,18 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw, * * mac80211 has support for various powersave implementations. * - * First, it can support hardware that handles all powersaving by itself, - * such hardware should simply set the %IEEE80211_HW_SUPPORTS_PS hardware - * flag. In that case, it will be told about the desired powersave mode - * with the %IEEE80211_CONF_PS flag depending on the association status. - * The hardware must take care of sending nullfunc frames when necessary, - * i.e. when entering and leaving powersave mode. The hardware is required - * to look at the AID in beacons and signal to the AP that it woke up when - * it finds traffic directed to it. - * - * %IEEE80211_CONF_PS flag enabled means that the powersave mode defined in - * IEEE 802.11-2007 section 11.2 is enabled. This is not to be confused - * with hardware wakeup and sleep states. Driver is responsible for waking - * up the hardware before issueing commands to the hardware and putting it - * back to sleep at approriate times. - * - * When PS is enabled, hardware needs to wakeup for beacons and receive the - * buffered multicast/broadcast frames after the beacon. Also it must be - * possible to send frames and receive the acknowledment frame. + * First, it can support hardware that handles all powersaving by + * itself, such hardware should simply set the %IEEE80211_HW_SUPPORTS_PS + * hardware flag. In that case, it will be told about the desired + * powersave mode depending on the association status, and the driver + * must take care of sending nullfunc frames when necessary, i.e. when + * entering and leaving powersave mode. The driver is required to look at + * the AID in beacons and signal to the AP that it woke up when it finds + * traffic directed to it. This mode supports dynamic PS by simply + * enabling/disabling PS. + * + * Additionally, such hardware may set the %IEEE80211_HW_SUPPORTS_DYNAMIC_PS + * flag to indicate that it can support dynamic PS mode itself (see below). * * Other hardware designs cannot send nullfunc frames by themselves and also * need software support for parsing the TIM bitmap. This is also supported @@ -1178,35 +1140,14 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw, * %IEEE80211_HW_PS_NULLFUNC_STACK flags. The hardware is of course still * required to pass up beacons. The hardware is still required to handle * waking up for multicast traffic; if it cannot the driver must handle that - * as best as it can, mac80211 is too slow to do that. - * - * Dynamic powersave is an extension to normal powersave in which the - * hardware stays awake for a user-specified period of time after sending a - * frame so that reply frames need not be buffered and therefore delayed to - * the next wakeup. It's compromise of getting good enough latency when - * there's data traffic and still saving significantly power in idle - * periods. - * - * Dynamic powersave is supported by simply mac80211 enabling and disabling - * PS based on traffic. Driver needs to only set %IEEE80211_HW_SUPPORTS_PS - * flag and mac80211 will handle everything automatically. Additionally, - * hardware having support for the dynamic PS feature may set the - * %IEEE80211_HW_SUPPORTS_DYNAMIC_PS flag to indicate that it can support - * dynamic PS mode itself. The driver needs to look at the - * @dynamic_ps_timeout hardware configuration value and use it that value - * whenever %IEEE80211_CONF_PS is set. In this case mac80211 will disable - * dynamic PS feature in stack and will just keep %IEEE80211_CONF_PS - * enabled whenever user has enabled powersave. - * - * Driver informs U-APSD client support by enabling - * %IEEE80211_HW_SUPPORTS_UAPSD flag. The mode is configured through the - * uapsd paramater in conf_tx() operation. Hardware needs to send the QoS - * Nullfunc frames and stay awake until the service period has ended. To - * utilize U-APSD, dynamic powersave is disabled for voip AC and all frames - * from that AC are transmitted with powersave enabled. - * - * Note: U-APSD client mode is not yet supported with - * %IEEE80211_HW_PS_NULLFUNC_STACK. + * as best as it can, mac80211 is too slow. + * + * Dynamic powersave mode is an extension to normal powersave mode in which + * the hardware stays awake for a user-specified period of time after sending + * a frame so that reply frames need not be buffered and therefore delayed + * to the next wakeup. This can either be supported by hardware, in which case + * the driver needs to look at the @dynamic_ps_timeout hardware configuration + * value, or by the stack if all nullfunc handling is in the stack. */ /** @@ -1269,31 +1210,6 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw, * signal strength threshold checking. */ -/** - * DOC: Spatial multiplexing power save - * - * SMPS (Spatial multiplexing power save) is a mechanism to conserve - * power in an 802.11n implementation. For details on the mechanism - * and rationale, please refer to 802.11 (as amended by 802.11n-2009) - * "11.2.3 SM power save". - * - * The mac80211 implementation is capable of sending action frames - * to update the AP about the station's SMPS mode, and will instruct - * the driver to enter the specific mode. It will also announce the - * requested SMPS mode during the association handshake. Hardware - * support for this feature is required, and can be indicated by - * hardware flags. - * - * The default mode will be "automatic", which nl80211/cfg80211 - * defines to be dynamic SMPS in (regular) powersave, and SMPS - * turned off otherwise. - * - * To support this feature, the driver must set the appropriate - * hardware support flags, and handle the SMPS flag to the config() - * operation. It will then with this mechanism be instructed to - * enter the requested SMPS mode while associated to an HT AP. - */ - /** * DOC: Frame filtering * @@ -1431,7 +1347,7 @@ enum ieee80211_ampdu_mlme_action { * When the device is started it should not have a MAC address * to avoid acknowledging frames before a non-monitor device * is added. - * Must be implemented and can sleep. + * Must be implemented. * * @stop: Called after last netdevice attached to the hardware * is disabled. This should turn off the hardware (at least @@ -1439,7 +1355,7 @@ enum ieee80211_ampdu_mlme_action { * May be called right after add_interface if that rejects * an interface. If you added any work onto the mac80211 workqueue * you should ensure to cancel it on this callback. - * Must be implemented and can sleep. + * Must be implemented. * * @add_interface: Called when a netdevice attached to the hardware is * enabled. Because it is not called for monitor mode devices, @start @@ -1449,7 +1365,7 @@ enum ieee80211_ampdu_mlme_action { * interface is given in the conf parameter. * The callback may refuse to add an interface by returning a * negative error code (which will be seen in userspace.) - * Must be implemented and can sleep. + * Must be implemented. * * @remove_interface: Notifies a driver that an interface is going down. * The @stop callback is called after this if it is the last interface @@ -1458,20 +1374,19 @@ enum ieee80211_ampdu_mlme_action { * must be cleared so the device no longer acknowledges packets, * the mac_addr member of the conf structure is, however, set to the * MAC address of the device going away. - * Hence, this callback must be implemented. It can sleep. + * Hence, this callback must be implemented. * * @config: Handler for configuration requests. IEEE 802.11 code calls this * function to change hardware configuration, e.g., channel. * This function should never fail but returns a negative error code - * if it does. The callback can sleep. + * if it does. * * @bss_info_changed: Handler for configuration requests related to BSS * parameters that may vary during BSS's lifespan, and may affect low * level driver (e.g. assoc/disassoc status, erp parameters). * This function should not be used if no BSS has been set, unless * for association indication. The @changed parameter indicates which - * of the bss parameters has changed when a call is made. The callback - * can sleep. + * of the bss parameters has changed when a call is made. * * @prepare_multicast: Prepare for multicast filter configuration. * This callback is optional, and its return value is passed @@ -1479,22 +1394,20 @@ enum ieee80211_ampdu_mlme_action { * * @configure_filter: Configure the device's RX filter. * See the section "Frame filtering" for more information. - * This callback must be implemented and can sleep. + * This callback must be implemented. * * @set_tim: Set TIM bit. mac80211 calls this function when a TIM bit * must be set or cleared for a given STA. Must be atomic. * * @set_key: See the section "Hardware crypto acceleration" - * This callback is only called between add_interface and - * remove_interface calls, i.e. while the given virtual interface + * This callback can sleep, and is only called between add_interface + * and remove_interface calls, i.e. while the given virtual interface * is enabled. * Returns a negative error code if the key can't be added. - * The callback can sleep. * * @update_tkip_key: See the section "Hardware crypto acceleration" * This callback will be called in the context of Rx. Called for drivers * which set IEEE80211_KEY_FLAG_TKIP_REQ_RX_P1_KEY. - * The callback must be atomic. * * @hw_scan: Ask the hardware to service the scan request, no need to start * the scan state machine in stack. The scan must honour the channel @@ -1508,64 +1421,53 @@ enum ieee80211_ampdu_mlme_action { * When the scan finishes, ieee80211_scan_completed() must be called; * note that it also must be called when the scan cannot finish due to * any error unless this callback returned a negative error code. - * The callback can sleep. * * @sw_scan_start: Notifier function that is called just before a software scan * is started. Can be NULL, if the driver doesn't need this notification. - * The callback can sleep. * - * @sw_scan_complete: Notifier function that is called just after a - * software scan finished. Can be NULL, if the driver doesn't need - * this notification. - * The callback can sleep. + * @sw_scan_complete: Notifier function that is called just after a software scan + * finished. Can be NULL, if the driver doesn't need this notification. * * @get_stats: Return low-level statistics. * Returns zero if statistics are available. - * The callback can sleep. * * @get_tkip_seq: If your device implements TKIP encryption in hardware this * callback should be provided to read the TKIP transmit IVs (both IV32 * and IV16) for the given key from hardware. - * The callback must be atomic. * * @set_rts_threshold: Configuration of RTS threshold (if device needs it) - * The callback can sleep. - * - * @sta_add: Notifies low level driver about addition of an associated station, - * AP, IBSS/WDS/mesh peer etc. This callback can sleep. - * - * @sta_remove: Notifies low level driver about removal of an associated - * station, AP, IBSS/WDS/mesh peer etc. This callback can sleep. * - * @sta_notify: Notifies low level driver about power state transition of an - * associated station, AP, IBSS/WDS/mesh peer etc. 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. * Returns a negative error code on failure. - * The callback can sleep. + * + * @get_tx_stats: Get statistics of the current TX queue status. This is used + * to get number of currently queued packets (queue length), maximum queue + * size (limit), and total number of packets sent using each TX queue + * (count). The 'stats' pointer points to an array that has hw->queues + * items. * * @get_tsf: Get the current TSF timer value from firmware/hardware. Currently, * this is only used for IBSS mode BSSID merging and debugging. Is not a * required function. - * The callback can sleep. * * @set_tsf: Set the TSF timer to the specified value in the firmware/hardware. * Currently, this is only used for IBSS mode debugging. Is not a * required function. - * The callback can sleep. * * @reset_tsf: Reset the TSF timer and allow firmware/hardware to synchronize * with other STAs in the IBSS. This is only used in IBSS mode. This * function is optional if the firmware/hardware takes full care of * TSF synchronization. - * The callback can sleep. * * @tx_last_beacon: Determine whether the last IBSS beacon was sent by us. * This is needed only for IBSS mode and the result of this function is * used to determine whether to reply to Probe Requests. * Returns non-zero if this device sent the last beacon. - * The callback can sleep. * * @ampdu_action: Perform a certain A-MPDU action * The RA/TID combination determines the destination and TID we want @@ -1574,32 +1476,21 @@ enum ieee80211_ampdu_mlme_action { * is the first frame we expect to perform the action on. Notice * that TX/RX_STOP can pass NULL for this parameter. * Returns a negative error code on failure. - * The callback must be atomic. * * @rfkill_poll: Poll rfkill hardware state. If you need this, you also * need to set wiphy->rfkill_poll to %true before registration, * and need to call wiphy_rfkill_set_hw_state() in the callback. - * The callback can sleep. - * - * @set_coverage_class: Set slot time for given coverage class as specified - * in IEEE 802.11-2007 section 17.3.8.6 and modify ACK timeout - * accordingly. This callback is not required and may sleep. * * @testmode_cmd: Implement a cfg80211 test mode command. - * The callback can sleep. - * - * @flush: Flush all pending frames from the hardware queue, making sure - * that the hardware queues are empty. If the parameter @drop is set - * to %true, pending frames may be dropped. The callback can sleep. */ struct ieee80211_ops { int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb); int (*start)(struct ieee80211_hw *hw); void (*stop)(struct ieee80211_hw *hw); int (*add_interface)(struct ieee80211_hw *hw, - struct ieee80211_vif *vif); + struct ieee80211_if_init_conf *conf); void (*remove_interface)(struct ieee80211_hw *hw, - struct ieee80211_vif *vif); + struct ieee80211_if_init_conf *conf); int (*config)(struct ieee80211_hw *hw, u32 changed); void (*bss_info_changed)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -1617,10 +1508,8 @@ struct ieee80211_ops { struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key); void (*update_tkip_key)(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_key_conf *conf, - struct ieee80211_sta *sta, - u32 iv32, u16 *phase1key); + struct ieee80211_key_conf *conf, const u8 *address, + u32 iv32, u16 *phase1key); int (*hw_scan)(struct ieee80211_hw *hw, struct cfg80211_scan_request *req); void (*sw_scan_start)(struct ieee80211_hw *hw); @@ -1630,14 +1519,12 @@ struct ieee80211_ops { void (*get_tkip_seq)(struct ieee80211_hw *hw, u8 hw_key_idx, u32 *iv32, u16 *iv16); int (*set_rts_threshold)(struct ieee80211_hw *hw, u32 value); - int (*sta_add)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta); - int (*sta_remove)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta); void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum sta_notify_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, + struct ieee80211_tx_queue_stats *stats); u64 (*get_tsf)(struct ieee80211_hw *hw); void (*set_tsf)(struct ieee80211_hw *hw, u64 tsf); void (*reset_tsf)(struct ieee80211_hw *hw); @@ -1648,11 +1535,9 @@ struct ieee80211_ops { struct ieee80211_sta *sta, u16 tid, u16 *ssn); void (*rfkill_poll)(struct ieee80211_hw *hw); - void (*set_coverage_class)(struct ieee80211_hw *hw, u8 coverage_class); #ifdef CONFIG_NL80211_TESTMODE int (*testmode_cmd)(struct ieee80211_hw *hw, void *data, int len); #endif - void (*flush)(struct ieee80211_hw *hw, bool drop); }; /** @@ -1892,7 +1777,7 @@ void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, /** * ieee80211_beacon_get_tim - beacon generation function * @hw: pointer obtained from ieee80211_alloc_hw(). - * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. * @tim_offset: pointer to variable that will receive the TIM IE offset. * Set to 0 if invalid (in non-AP modes). * @tim_length: pointer to variable that will receive the TIM IE length, @@ -1920,7 +1805,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, /** * ieee80211_beacon_get - beacon generation function * @hw: pointer obtained from ieee80211_alloc_hw(). - * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. * * See ieee80211_beacon_get_tim(). */ @@ -1930,57 +1815,10 @@ static inline struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, return ieee80211_beacon_get_tim(hw, vif, NULL, NULL); } -/** - * ieee80211_pspoll_get - retrieve a PS Poll template - * @hw: pointer obtained from ieee80211_alloc_hw(). - * @vif: &struct ieee80211_vif pointer from the add_interface callback. - * - * Creates a PS Poll a template which can, for example, uploaded to - * hardware. The template must be updated after association so that correct - * AID, BSSID and MAC address is used. - * - * Note: Caller (or hardware) is responsible for setting the - * &IEEE80211_FCTL_PM bit. - */ -struct sk_buff *ieee80211_pspoll_get(struct ieee80211_hw *hw, - struct ieee80211_vif *vif); - -/** - * ieee80211_nullfunc_get - retrieve a nullfunc template - * @hw: pointer obtained from ieee80211_alloc_hw(). - * @vif: &struct ieee80211_vif pointer from the add_interface callback. - * - * Creates a Nullfunc template which can, for example, uploaded to - * hardware. The template must be updated after association so that correct - * BSSID and address is used. - * - * Note: Caller (or hardware) is responsible for setting the - * &IEEE80211_FCTL_PM bit as well as Duration and Sequence Control fields. - */ -struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw, - struct ieee80211_vif *vif); - -/** - * ieee80211_probereq_get - retrieve a Probe Request template - * @hw: pointer obtained from ieee80211_alloc_hw(). - * @vif: &struct ieee80211_vif pointer from the add_interface callback. - * @ssid: SSID buffer - * @ssid_len: length of SSID - * @ie: buffer containing all IEs except SSID for the template - * @ie_len: length of the IE buffer - * - * Creates a Probe Request template which can, for example, be uploaded to - * hardware. - */ -struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - const u8 *ssid, size_t ssid_len, - const u8 *ie, size_t ie_len); - /** * ieee80211_rts_get - RTS frame generation function * @hw: pointer obtained from ieee80211_alloc_hw(). - * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. * @frame: pointer to the frame that is going to be protected by the RTS. * @frame_len: the frame length (in octets). * @frame_txctl: &struct ieee80211_tx_info of the frame. @@ -1999,7 +1837,7 @@ void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, /** * ieee80211_rts_duration - Get the duration field for an RTS frame * @hw: pointer obtained from ieee80211_alloc_hw(). - * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. * @frame_len: the length of the frame that is going to be protected by the RTS. * @frame_txctl: &struct ieee80211_tx_info of the frame. * @@ -2014,7 +1852,7 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, /** * ieee80211_ctstoself_get - CTS-to-self frame generation function * @hw: pointer obtained from ieee80211_alloc_hw(). - * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. * @frame: pointer to the frame that is going to be protected by the CTS-to-self. * @frame_len: the frame length (in octets). * @frame_txctl: &struct ieee80211_tx_info of the frame. @@ -2034,7 +1872,7 @@ void ieee80211_ctstoself_get(struct ieee80211_hw *hw, /** * ieee80211_ctstoself_duration - Get the duration field for a CTS-to-self frame * @hw: pointer obtained from ieee80211_alloc_hw(). - * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. * @frame_len: the length of the frame that is going to be protected by the CTS-to-self. * @frame_txctl: &struct ieee80211_tx_info of the frame. * @@ -2050,7 +1888,7 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, /** * ieee80211_generic_frame_duration - Calculate the duration field for a frame * @hw: pointer obtained from ieee80211_alloc_hw(). - * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. * @frame_len: the length of the frame. * @rate: the rate at which the frame is going to be transmitted. * @@ -2065,7 +1903,7 @@ __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, /** * ieee80211_get_buffered_bc - accessing buffered broadcast and multicast frames * @hw: pointer as obtained from ieee80211_alloc_hw(). - * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. * * Function for accessing buffered broadcast and multicast frames. If * hardware/firmware does not implement buffering of broadcast/multicast @@ -2233,7 +2071,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *sta, u16 tid); /** * ieee80211_start_tx_ba_cb - low level driver ready to aggregate. - * @vif: &struct ieee80211_vif pointer from the add_interface callback + * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf * @ra: receiver address of the BA session recipient. * @tid: the TID to BA on. * @@ -2244,7 +2082,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid); /** * ieee80211_start_tx_ba_cb_irqsafe - low level driver ready to aggregate. - * @vif: &struct ieee80211_vif pointer from the add_interface callback + * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf * @ra: receiver address of the BA session recipient. * @tid: the TID to BA on. * @@ -2272,7 +2110,7 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_sta *sta, u16 tid, /** * ieee80211_stop_tx_ba_cb - low level driver ready to stop aggregate. - * @vif: &struct ieee80211_vif pointer from the add_interface callback + * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf * @ra: receiver address of the BA session recipient. * @tid: the desired TID to BA on. * @@ -2283,7 +2121,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid); /** * ieee80211_stop_tx_ba_cb_irqsafe - low level driver ready to stop aggregate. - * @vif: &struct ieee80211_vif pointer from the add_interface callback + * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf * @ra: receiver address of the BA session recipient. * @tid: the desired TID to BA on. * @@ -2362,7 +2200,7 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw, /** * ieee80211_beacon_loss - inform hardware does not receive beacons * - * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. * * When beacon filtering is enabled with IEEE80211_HW_BEACON_FILTERING and * IEEE80211_CONF_PS is set, the driver needs to inform whenever the @@ -2396,12 +2234,8 @@ enum rate_control_changed { * @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) - * (deprecated; this will be removed once drivers get updated to use - * rate_idx_mask) - * @rate_idx_mask: user-requested rate mask (not MCS for now) * @skb: the skb that will be transmitted, the control information in it needs * to be filled in - * @ap: whether this frame is sent out in AP mode */ struct ieee80211_tx_rate_control { struct ieee80211_hw *hw; @@ -2411,8 +2245,6 @@ struct ieee80211_tx_rate_control { struct ieee80211_tx_rate reported_rate; bool rts, short_preamble; u8 max_rate_idx; - u32 rate_idx_mask; - bool ap; }; struct rate_control_ops { diff --git a/trunk/include/net/regulatory.h b/trunk/include/net/regulatory.h index f873ee37f7e4..47995b81c5d7 100644 --- a/trunk/include/net/regulatory.h +++ b/trunk/include/net/regulatory.h @@ -39,7 +39,6 @@ enum environment_cap { * 00 - World regulatory domain * 99 - built by driver but a specific alpha2 cannot be determined * 98 - result of an intersection between two regulatory domains - * 97 - regulatory domain has not yet been configured * @intersect: indicates whether the wireless core should intersect * the requested regulatory domain with the presently set regulatory * domain. diff --git a/trunk/include/pcmcia/device_id.h b/trunk/include/pcmcia/device_id.h index 63e5b8f6b7dd..c33ea08352b8 100644 --- a/trunk/include/pcmcia/device_id.h +++ b/trunk/include/pcmcia/device_id.h @@ -34,11 +34,6 @@ .prod_id = { NULL, (v2), NULL, NULL }, \ .prod_id_hash = { 0, (vh2), 0, 0 }, } -#define PCMCIA_DEVICE_PROD_ID3(v3, vh3) { \ - .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID3, \ - .prod_id = { NULL, NULL, (v3), NULL }, \ - .prod_id_hash = { 0, 0, (vh3), 0 }, } - #define PCMCIA_DEVICE_PROD_ID12(v1, v2, vh1, vh2) { \ .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \ PCMCIA_DEV_ID_MATCH_PROD_ID2, \ diff --git a/trunk/net/mac80211/Kconfig b/trunk/net/mac80211/Kconfig index a952b7f8c648..a10d508b07e1 100644 --- a/trunk/net/mac80211/Kconfig +++ b/trunk/net/mac80211/Kconfig @@ -96,6 +96,18 @@ menuconfig MAC80211_DEBUG_MENU ---help--- This option collects various mac80211 debug settings. +config MAC80211_DEBUG_PACKET_ALIGNMENT + bool "Enable packet alignment debugging" + depends on MAC80211_DEBUG_MENU + ---help--- + This option is recommended for driver authors and strongly + discouraged for everybody else, it will trigger a warning + when a driver hands mac80211 a buffer that is aligned in + a way that will cause problems with the IP stack on some + architectures. + + Say N unless you're writing a mac80211 based driver. + config MAC80211_NOINLINE bool "Do not inline TX/RX handlers" depends on MAC80211_DEBUG_MENU diff --git a/trunk/net/mac80211/Makefile b/trunk/net/mac80211/Makefile index 04420291e7ad..298cfcc1bf8d 100644 --- a/trunk/net/mac80211/Makefile +++ b/trunk/net/mac80211/Makefile @@ -6,10 +6,10 @@ mac80211-y := \ sta_info.o \ wep.o \ wpa.o \ - scan.o offchannel.o \ + scan.o \ ht.o agg-tx.o agg-rx.o \ ibss.o \ - mlme.o work.o \ + mlme.o \ iface.o \ rate.o \ michael.o \ diff --git a/trunk/net/mac80211/agg-rx.c b/trunk/net/mac80211/agg-rx.c index a978e666ed6f..51c7dc3c4c3b 100644 --- a/trunk/net/mac80211/agg-rx.c +++ b/trunk/net/mac80211/agg-rx.c @@ -41,7 +41,8 @@ void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, sta->sta.addr, tid); #endif /* CONFIG_MAC80211_HT_DEBUG */ - if (drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_STOP, + if (drv_ampdu_action(local, &sta->sdata->vif, + IEEE80211_AMPDU_RX_STOP, &sta->sta, tid, NULL)) printk(KERN_DEBUG "HW problem - can not stop rx " "aggregation for tid %d\n", tid); @@ -82,11 +83,12 @@ void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 initiator, u16 reason) { + struct ieee80211_local *local = sdata->local; struct sta_info *sta; rcu_read_lock(); - sta = sta_info_get(sdata, ra); + sta = sta_info_get(local, ra); if (!sta) { rcu_read_unlock(); return; @@ -134,7 +136,7 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d if (!skb) { printk(KERN_DEBUG "%s: failed to allocate buffer " - "for addba resp frame\n", sdata->name); + "for addba resp frame\n", sdata->dev->name); return; } @@ -142,10 +144,10 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); memset(mgmt, 0, 24); memcpy(mgmt->da, da, ETH_ALEN); - memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); + memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); if (sdata->vif.type == NL80211_IFTYPE_AP || sdata->vif.type == NL80211_IFTYPE_AP_VLAN) - memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); + memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); else if (sdata->vif.type == NL80211_IFTYPE_STATION) memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN); @@ -279,7 +281,8 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, goto end; } - ret = drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_START, + ret = drv_ampdu_action(local, &sta->sdata->vif, + IEEE80211_AMPDU_RX_START, &sta->sta, tid, &start_seq_num); #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret); diff --git a/trunk/net/mac80211/agg-tx.c b/trunk/net/mac80211/agg-tx.c index 5538e1b4a697..5e3a7eccef5a 100644 --- a/trunk/net/mac80211/agg-tx.c +++ b/trunk/net/mac80211/agg-tx.c @@ -58,17 +58,17 @@ static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata, if (!skb) { printk(KERN_ERR "%s: failed to allocate buffer " - "for addba request frame\n", sdata->name); + "for addba request frame\n", sdata->dev->name); return; } skb_reserve(skb, local->hw.extra_tx_headroom); mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); memset(mgmt, 0, 24); memcpy(mgmt->da, da, ETH_ALEN); - memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); + memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); if (sdata->vif.type == NL80211_IFTYPE_AP || sdata->vif.type == NL80211_IFTYPE_AP_VLAN) - memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); + memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); else if (sdata->vif.type == NL80211_IFTYPE_STATION) memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN); @@ -104,7 +104,7 @@ void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u1 skb = dev_alloc_skb(sizeof(*bar) + local->hw.extra_tx_headroom); if (!skb) { printk(KERN_ERR "%s: failed to allocate buffer for " - "bar frame\n", sdata->name); + "bar frame\n", sdata->dev->name); return; } skb_reserve(skb, local->hw.extra_tx_headroom); @@ -113,7 +113,7 @@ void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u1 bar->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_BACK_REQ); memcpy(bar->ra, ra, ETH_ALEN); - memcpy(bar->ta, sdata->vif.addr, ETH_ALEN); + memcpy(bar->ta, sdata->dev->dev_addr, ETH_ALEN); bar_control |= (u16)IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL; bar_control |= (u16)IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA; bar_control |= (u16)(tid << 12); @@ -144,7 +144,7 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, *state = HT_AGG_STATE_REQ_STOP_BA_MSK | (initiator << HT_AGG_STATE_INITIATOR_SHIFT); - ret = drv_ampdu_action(local, sta->sdata, + ret = drv_ampdu_action(local, &sta->sdata->vif, IEEE80211_AMPDU_TX_STOP, &sta->sta, tid, NULL); @@ -179,8 +179,7 @@ static void sta_addba_resp_timer_expired(unsigned long data) /* check if the TID waits for addBA response */ spin_lock_bh(&sta->lock); - if ((*state & (HT_ADDBA_REQUESTED_MSK | HT_ADDBA_RECEIVED_MSK | - HT_AGG_STATE_REQ_STOP_BA_MSK)) != + if ((*state & (HT_ADDBA_REQUESTED_MSK | HT_ADDBA_RECEIVED_MSK)) != HT_ADDBA_REQUESTED_MSK) { spin_unlock_bh(&sta->lock); *state = HT_AGG_STATE_IDLE; @@ -237,14 +236,6 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid) sdata->vif.type != NL80211_IFTYPE_AP) return -EINVAL; - if (test_sta_flags(sta, WLAN_STA_DISASSOC)) { -#ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "Disassociation is in progress. " - "Denying BA session request\n"); -#endif - return -EINVAL; - } - if (test_sta_flags(sta, WLAN_STA_SUSPEND)) { #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "Suspend in progress. " @@ -310,9 +301,10 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid) * call back right away, it must see that the flow has begun */ *state |= HT_ADDBA_REQUESTED_MSK; - start_seq_num = sta->tid_seq[tid] >> 4; + start_seq_num = sta->tid_seq[tid]; - ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START, + ret = drv_ampdu_action(local, &sdata->vif, + IEEE80211_AMPDU_TX_START, pubsta, tid, &start_seq_num); if (ret) { @@ -428,7 +420,7 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local, ieee80211_agg_splice_finish(local, sta, tid); spin_unlock(&local->ampdu_lock); - drv_ampdu_action(local, sta->sdata, + drv_ampdu_action(local, &sta->sdata->vif, IEEE80211_AMPDU_TX_OPERATIONAL, &sta->sta, tid, NULL); } @@ -449,7 +441,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid) } rcu_read_lock(); - sta = sta_info_get(sdata, ra); + sta = sta_info_get(local, ra); if (!sta) { rcu_read_unlock(); #ifdef CONFIG_MAC80211_HT_DEBUG @@ -497,7 +489,7 @@ void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, #ifdef CONFIG_MAC80211_HT_DEBUG if (net_ratelimit()) printk(KERN_WARNING "%s: Not enough memory, " - "dropping start BA session", sdata->name); + "dropping start BA session", skb->dev->name); #endif return; } @@ -572,7 +564,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid) #endif /* CONFIG_MAC80211_HT_DEBUG */ rcu_read_lock(); - sta = sta_info_get(sdata, ra); + sta = sta_info_get(local, ra); if (!sta) { #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "Could not find station: %pM\n", ra); @@ -629,7 +621,7 @@ void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, #ifdef CONFIG_MAC80211_HT_DEBUG if (net_ratelimit()) printk(KERN_WARNING "%s: Not enough memory, " - "dropping stop BA session", sdata->name); + "dropping stop BA session", skb->dev->name); #endif return; } diff --git a/trunk/net/mac80211/cfg.c b/trunk/net/mac80211/cfg.c index b7116ef84a3b..9ae1a4760b58 100644 --- a/trunk/net/mac80211/cfg.c +++ b/trunk/net/mac80211/cfg.c @@ -1,7 +1,7 @@ /* * mac80211 configuration hooks for cfg80211 * - * Copyright 2006-2010 Johannes Berg + * Copyright 2006, 2007 Johannes Berg * * This file is GPLv2 as found in COPYING. */ @@ -78,15 +78,17 @@ static int ieee80211_change_iface(struct wiphy *wiphy, enum nl80211_iftype type, u32 *flags, struct vif_params *params) { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_sub_if_data *sdata; int ret; - if (ieee80211_sdata_running(sdata)) + if (netif_running(dev)) return -EBUSY; if (!nl80211_params_check(type, params)) return -EINVAL; + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + ret = ieee80211_if_change_type(sdata, type); if (ret) return ret; @@ -148,7 +150,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, rcu_read_lock(); if (mac_addr) { - sta = sta_info_get_bss(sdata, mac_addr); + sta = sta_info_get(sdata->local, mac_addr); if (!sta) { ieee80211_key_free(key); err = -ENOENT; @@ -179,7 +181,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, if (mac_addr) { ret = -ENOENT; - sta = sta_info_get_bss(sdata, mac_addr); + sta = sta_info_get(sdata->local, mac_addr); if (!sta) goto out_unlock; @@ -226,7 +228,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, rcu_read_lock(); if (mac_addr) { - sta = sta_info_get_bss(sdata, mac_addr); + sta = sta_info_get(sdata->local, mac_addr); if (!sta) goto out; @@ -413,13 +415,15 @@ static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev, static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, u8 *mac, struct station_info *sinfo) { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct sta_info *sta; int ret = -ENOENT; rcu_read_lock(); - sta = sta_info_get_bss(sdata, mac); + /* XXX: verify sta->dev == dev */ + + sta = sta_info_get(local, mac); if (sta) { ret = 0; sta_set_sinfo(sta, sinfo); @@ -515,8 +519,6 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, if (old) memcpy(new->tail, old->tail, new_tail_len); - sdata->vif.bss_conf.dtim_period = new->dtim_period; - rcu_assign_pointer(sdata->u.ap.beacon, new); synchronize_rcu(); @@ -730,7 +732,7 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, } else sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (compare_ether_addr(mac, sdata->vif.addr) == 0) + if (compare_ether_addr(mac, dev->dev_addr) == 0) return -EINVAL; if (is_multicast_ether_addr(mac)) @@ -749,7 +751,9 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN || sdata->vif.type == NL80211_IFTYPE_AP; - err = sta_info_insert_rcu(sta); + rcu_read_lock(); + + err = sta_info_insert(sta); if (err) { rcu_read_unlock(); return err; @@ -768,13 +772,27 @@ static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, { struct ieee80211_local *local = wiphy_priv(wiphy); struct ieee80211_sub_if_data *sdata; + struct sta_info *sta; sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (mac) - return sta_info_destroy_addr_bss(sdata, mac); + if (mac) { + rcu_read_lock(); + + /* XXX: get sta belonging to dev */ + sta = sta_info_get(local, mac); + if (!sta) { + rcu_read_unlock(); + return -ENOENT; + } + + sta_info_unlink(&sta); + rcu_read_unlock(); + + sta_info_destroy(sta); + } else + sta_info_flush(local, sdata); - sta_info_flush(local, sdata); return 0; } @@ -783,14 +801,14 @@ static int ieee80211_change_station(struct wiphy *wiphy, u8 *mac, struct station_parameters *params) { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = wiphy_priv(wiphy); struct sta_info *sta; struct ieee80211_sub_if_data *vlansdata; rcu_read_lock(); - sta = sta_info_get_bss(sdata, mac); + /* XXX: get sta belonging to dev */ + sta = sta_info_get(local, mac); if (!sta) { rcu_read_unlock(); return -ENOENT; @@ -829,6 +847,7 @@ static int ieee80211_change_station(struct wiphy *wiphy, static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev, u8 *dst, u8 *next_hop) { + struct ieee80211_local *local = wiphy_priv(wiphy); struct ieee80211_sub_if_data *sdata; struct mesh_path *mpath; struct sta_info *sta; @@ -837,7 +856,7 @@ static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev, sdata = IEEE80211_DEV_TO_SUB_IF(dev); rcu_read_lock(); - sta = sta_info_get(sdata, next_hop); + sta = sta_info_get(local, next_hop); if (!sta) { rcu_read_unlock(); return -ENOENT; @@ -876,6 +895,7 @@ static int ieee80211_change_mpath(struct wiphy *wiphy, struct net_device *dev, u8 *dst, u8 *next_hop) { + struct ieee80211_local *local = wiphy_priv(wiphy); struct ieee80211_sub_if_data *sdata; struct mesh_path *mpath; struct sta_info *sta; @@ -884,7 +904,7 @@ static int ieee80211_change_mpath(struct wiphy *wiphy, rcu_read_lock(); - sta = sta_info_get(sdata, next_hop); + sta = sta_info_get(local, next_hop); if (!sta) { rcu_read_unlock(); return -ENOENT; @@ -1072,13 +1092,6 @@ static int ieee80211_change_bss(struct wiphy *wiphy, params->use_short_preamble; changed |= BSS_CHANGED_ERP_PREAMBLE; } - - if (!sdata->vif.bss_conf.use_short_slot && - sdata->local->hw.conf.channel->band == IEEE80211_BAND_5GHZ) { - sdata->vif.bss_conf.use_short_slot = true; - changed |= BSS_CHANGED_ERP_SLOT; - } - if (params->use_short_slot_time >= 0) { sdata->vif.bss_conf.use_short_slot = params->use_short_slot_time; @@ -1122,13 +1135,6 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy, p.cw_max = params->cwmax; p.cw_min = params->cwmin; p.txop = params->txop; - - /* - * Setting tx queue params disables u-apsd because it's only - * called in master mode. - */ - p.uapsd = false; - if (drv_conf_tx(local, params->queue, &p)) { printk(KERN_DEBUG "%s: failed to set TX queue " "parameters for queue %d\n", @@ -1231,13 +1237,6 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) struct ieee80211_local *local = wiphy_priv(wiphy); int err; - if (changed & WIPHY_PARAM_COVERAGE_CLASS) { - err = drv_set_coverage_class(local, wiphy->coverage_class); - - if (err) - return err; - } - if (changed & WIPHY_PARAM_RTS_THRESHOLD) { err = drv_set_rts_threshold(local, wiphy->rts_threshold); @@ -1325,50 +1324,6 @@ static int ieee80211_testmode_cmd(struct wiphy *wiphy, void *data, int len) } #endif -int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, - enum ieee80211_smps_mode smps_mode) -{ - const u8 *ap; - enum ieee80211_smps_mode old_req; - int err; - - old_req = sdata->u.mgd.req_smps; - sdata->u.mgd.req_smps = smps_mode; - - if (old_req == smps_mode && - smps_mode != IEEE80211_SMPS_AUTOMATIC) - return 0; - - /* - * If not associated, or current association is not an HT - * association, there's no need to send an action frame. - */ - if (!sdata->u.mgd.associated || - sdata->local->oper_channel_type == NL80211_CHAN_NO_HT) { - mutex_lock(&sdata->local->iflist_mtx); - ieee80211_recalc_smps(sdata->local, sdata); - mutex_unlock(&sdata->local->iflist_mtx); - return 0; - } - - ap = sdata->u.mgd.associated->bssid; - - if (smps_mode == IEEE80211_SMPS_AUTOMATIC) { - if (sdata->u.mgd.powersave) - smps_mode = IEEE80211_SMPS_DYNAMIC; - else - smps_mode = IEEE80211_SMPS_OFF; - } - - /* send SM PS frame to AP */ - err = ieee80211_send_smps_action(sdata, smps_mode, - ap, ap); - if (err) - sdata->u.mgd.req_smps = old_req; - - return err; -} - static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, bool enabled, int timeout) { @@ -1389,11 +1344,6 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, sdata->u.mgd.powersave = enabled; conf->dynamic_ps_timeout = timeout; - /* no change, but if automatic follow powersave */ - mutex_lock(&sdata->u.mgd.mtx); - __ieee80211_request_smps(sdata, sdata->u.mgd.req_smps); - mutex_unlock(&sdata->u.mgd.mtx); - if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); @@ -1409,52 +1359,39 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - int i; - - /* - * This _could_ be supported by providing a hook for - * drivers for this function, but at this point it - * doesn't seem worth bothering. - */ - if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) - return -EOPNOTSUPP; - - - for (i = 0; i < IEEE80211_NUM_BANDS; i++) - sdata->rc_rateidx_mask[i] = mask->control[i].legacy; + int i, err = -EINVAL; + u32 target_rate; + struct ieee80211_supported_band *sband; - return 0; -} + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; -static int ieee80211_remain_on_channel(struct wiphy *wiphy, - struct net_device *dev, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, - unsigned int duration, - u64 *cookie) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + /* target_rate = -1, rate->fixed = 0 means auto only, so use all rates + * target_rate = X, rate->fixed = 1 means only rate X + * target_rate = X, rate->fixed = 0 means all rates <= X */ + sdata->max_ratectrl_rateidx = -1; + sdata->force_unicast_rateidx = -1; - return ieee80211_wk_remain_on_channel(sdata, chan, channel_type, - duration, cookie); -} + if (mask->fixed) + target_rate = mask->fixed / 100; + else if (mask->maxrate) + target_rate = mask->maxrate / 100; + else + return 0; -static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy, - struct net_device *dev, - u64 cookie) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + for (i=0; i< sband->n_bitrates; i++) { + struct ieee80211_rate *brate = &sband->bitrates[i]; + int this_rate = brate->bitrate; - return ieee80211_wk_cancel_remain_on_channel(sdata, cookie); -} + if (target_rate == this_rate) { + sdata->max_ratectrl_rateidx = i; + if (mask->fixed) + sdata->force_unicast_rateidx = i; + err = 0; + break; + } + } -static int ieee80211_action(struct wiphy *wiphy, struct net_device *dev, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, - const u8 *buf, size_t len, u64 *cookie) -{ - return ieee80211_mgd_action(IEEE80211_DEV_TO_SUB_IF(dev), chan, - channel_type, buf, len, cookie); + return err; } struct cfg80211_ops mac80211_config_ops = { @@ -1503,7 +1440,4 @@ struct cfg80211_ops mac80211_config_ops = { CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd) .set_power_mgmt = ieee80211_set_power_mgmt, .set_bitrate_mask = ieee80211_set_bitrate_mask, - .remain_on_channel = ieee80211_remain_on_channel, - .cancel_remain_on_channel = ieee80211_cancel_remain_on_channel, - .action = ieee80211_action, }; diff --git a/trunk/net/mac80211/debugfs.c b/trunk/net/mac80211/debugfs.c index 637929b65ccc..e4b54093d41b 100644 --- a/trunk/net/mac80211/debugfs.c +++ b/trunk/net/mac80211/debugfs.c @@ -158,130 +158,6 @@ static const struct file_operations noack_ops = { .open = mac80211_open_file_generic }; -static ssize_t uapsd_queues_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ieee80211_local *local = file->private_data; - int res; - char buf[10]; - - res = scnprintf(buf, sizeof(buf), "0x%x\n", local->uapsd_queues); - - return simple_read_from_buffer(user_buf, count, ppos, buf, res); -} - -static ssize_t uapsd_queues_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ieee80211_local *local = file->private_data; - unsigned long val; - char buf[10]; - size_t len; - int ret; - - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; - buf[len] = '\0'; - - ret = strict_strtoul(buf, 0, &val); - - if (ret) - return -EINVAL; - - if (val & ~IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK) - return -ERANGE; - - local->uapsd_queues = val; - - return count; -} - -static const struct file_operations uapsd_queues_ops = { - .read = uapsd_queues_read, - .write = uapsd_queues_write, - .open = mac80211_open_file_generic -}; - -static ssize_t uapsd_max_sp_len_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ieee80211_local *local = file->private_data; - int res; - char buf[10]; - - res = scnprintf(buf, sizeof(buf), "0x%x\n", local->uapsd_max_sp_len); - - return simple_read_from_buffer(user_buf, count, ppos, buf, res); -} - -static ssize_t uapsd_max_sp_len_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ieee80211_local *local = file->private_data; - unsigned long val; - char buf[10]; - size_t len; - int ret; - - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; - buf[len] = '\0'; - - ret = strict_strtoul(buf, 0, &val); - - if (ret) - return -EINVAL; - - if (val & ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK) - return -ERANGE; - - local->uapsd_max_sp_len = val; - - return count; -} - -static const struct file_operations uapsd_max_sp_len_ops = { - .read = uapsd_max_sp_len_read, - .write = uapsd_max_sp_len_write, - .open = mac80211_open_file_generic -}; - -static ssize_t channel_type_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ieee80211_local *local = file->private_data; - const char *buf; - - switch (local->hw.conf.channel_type) { - case NL80211_CHAN_NO_HT: - buf = "no ht\n"; - break; - case NL80211_CHAN_HT20: - buf = "ht20\n"; - break; - case NL80211_CHAN_HT40MINUS: - buf = "ht40-\n"; - break; - case NL80211_CHAN_HT40PLUS: - buf = "ht40+\n"; - break; - default: - buf = "???"; - break; - } - - return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); -} - -static const struct file_operations channel_type_ops = { - .read = channel_type_read, - .open = mac80211_open_file_generic -}; - static ssize_t queues_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -438,9 +314,6 @@ void debugfs_hw_add(struct ieee80211_local *local) DEBUGFS_ADD(queues); DEBUGFS_ADD_MODE(reset, 0200); DEBUGFS_ADD(noack); - DEBUGFS_ADD(uapsd_queues); - DEBUGFS_ADD(uapsd_max_sp_len); - DEBUGFS_ADD(channel_type); statsd = debugfs_create_dir("statistics", phyd); diff --git a/trunk/net/mac80211/debugfs_key.c b/trunk/net/mac80211/debugfs_key.c index d12e743cb4e1..e0f5224630da 100644 --- a/trunk/net/mac80211/debugfs_key.c +++ b/trunk/net/mac80211/debugfs_key.c @@ -56,7 +56,7 @@ KEY_CONF_FILE(keyidx, D); KEY_CONF_FILE(hw_key_idx, D); KEY_FILE(flags, X); KEY_FILE(tx_rx_count, D); -KEY_READ(ifindex, sdata->name, IFNAMSIZ + 2, "%s\n"); +KEY_READ(ifindex, sdata->dev->ifindex, 20, "%d\n"); KEY_OPS(ifindex); static ssize_t key_algorithm_read(struct file *file, diff --git a/trunk/net/mac80211/debugfs_netdev.c b/trunk/net/mac80211/debugfs_netdev.c index 9affe2cd185f..472b2039906c 100644 --- a/trunk/net/mac80211/debugfs_netdev.c +++ b/trunk/net/mac80211/debugfs_netdev.c @@ -41,30 +41,6 @@ static ssize_t ieee80211_if_read( return ret; } -static ssize_t ieee80211_if_write( - struct ieee80211_sub_if_data *sdata, - const char __user *userbuf, - size_t count, loff_t *ppos, - ssize_t (*write)(struct ieee80211_sub_if_data *, const char *, int)) -{ - u8 *buf; - ssize_t ret = -ENODEV; - - buf = kzalloc(count, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - if (copy_from_user(buf, userbuf, count)) - return -EFAULT; - - rtnl_lock(); - if (sdata->dev->reg_state == NETREG_REGISTERED) - ret = (*write)(sdata, buf, count); - rtnl_unlock(); - - return ret; -} - #define IEEE80211_IF_FMT(name, field, format_string) \ static ssize_t ieee80211_if_fmt_##name( \ const struct ieee80211_sub_if_data *sdata, char *buf, \ @@ -95,7 +71,7 @@ static ssize_t ieee80211_if_fmt_##name( \ return scnprintf(buf, buflen, "%pM\n", sdata->field); \ } -#define __IEEE80211_IF_FILE(name, _write) \ +#define __IEEE80211_IF_FILE(name) \ static ssize_t ieee80211_if_read_##name(struct file *file, \ char __user *userbuf, \ size_t count, loff_t *ppos) \ @@ -106,99 +82,22 @@ static ssize_t ieee80211_if_read_##name(struct file *file, \ } \ static const struct file_operations name##_ops = { \ .read = ieee80211_if_read_##name, \ - .write = (_write), \ .open = mac80211_open_file_generic, \ } -#define __IEEE80211_IF_FILE_W(name) \ -static ssize_t ieee80211_if_write_##name(struct file *file, \ - const char __user *userbuf, \ - size_t count, loff_t *ppos) \ -{ \ - return ieee80211_if_write(file->private_data, userbuf, count, \ - ppos, ieee80211_if_parse_##name); \ -} \ -__IEEE80211_IF_FILE(name, ieee80211_if_write_##name) - - #define IEEE80211_IF_FILE(name, field, format) \ IEEE80211_IF_FMT_##format(name, field) \ - __IEEE80211_IF_FILE(name, NULL) + __IEEE80211_IF_FILE(name) /* common attributes */ IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC); -IEEE80211_IF_FILE(rc_rateidx_mask_2ghz, rc_rateidx_mask[IEEE80211_BAND_2GHZ], - HEX); -IEEE80211_IF_FILE(rc_rateidx_mask_5ghz, rc_rateidx_mask[IEEE80211_BAND_5GHZ], - HEX); +IEEE80211_IF_FILE(force_unicast_rateidx, force_unicast_rateidx, DEC); +IEEE80211_IF_FILE(max_ratectrl_rateidx, max_ratectrl_rateidx, DEC); /* STA attributes */ IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); IEEE80211_IF_FILE(aid, u.mgd.aid, DEC); - -static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata, - enum ieee80211_smps_mode smps_mode) -{ - struct ieee80211_local *local = sdata->local; - int err; - - if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_STATIC_SMPS) && - smps_mode == IEEE80211_SMPS_STATIC) - return -EINVAL; - - /* auto should be dynamic if in PS mode */ - if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS) && - (smps_mode == IEEE80211_SMPS_DYNAMIC || - smps_mode == IEEE80211_SMPS_AUTOMATIC)) - return -EINVAL; - - /* supported only on managed interfaces for now */ - if (sdata->vif.type != NL80211_IFTYPE_STATION) - return -EOPNOTSUPP; - - mutex_lock(&local->iflist_mtx); - err = __ieee80211_request_smps(sdata, smps_mode); - mutex_unlock(&local->iflist_mtx); - - return err; -} - -static const char *smps_modes[IEEE80211_SMPS_NUM_MODES] = { - [IEEE80211_SMPS_AUTOMATIC] = "auto", - [IEEE80211_SMPS_OFF] = "off", - [IEEE80211_SMPS_STATIC] = "static", - [IEEE80211_SMPS_DYNAMIC] = "dynamic", -}; - -static ssize_t ieee80211_if_fmt_smps(const struct ieee80211_sub_if_data *sdata, - char *buf, int buflen) -{ - if (sdata->vif.type != NL80211_IFTYPE_STATION) - return -EOPNOTSUPP; - - return snprintf(buf, buflen, "request: %s\nused: %s\n", - smps_modes[sdata->u.mgd.req_smps], - smps_modes[sdata->u.mgd.ap_smps]); -} - -static ssize_t ieee80211_if_parse_smps(struct ieee80211_sub_if_data *sdata, - const char *buf, int buflen) -{ - enum ieee80211_smps_mode mode; - - for (mode = 0; mode < IEEE80211_SMPS_NUM_MODES; mode++) { - if (strncmp(buf, smps_modes[mode], buflen) == 0) { - int err = ieee80211_set_smps(sdata, mode); - if (!err) - return buflen; - return err; - } - } - - return -EINVAL; -} - -__IEEE80211_IF_FILE_W(smps); +IEEE80211_IF_FILE(capab, u.mgd.capab, HEX); /* AP attributes */ IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC); @@ -210,7 +109,7 @@ static ssize_t ieee80211_if_fmt_num_buffered_multicast( return scnprintf(buf, buflen, "%u\n", skb_queue_len(&sdata->u.ap.ps_bc_buf)); } -__IEEE80211_IF_FILE(num_buffered_multicast, NULL); +__IEEE80211_IF_FILE(num_buffered_multicast); /* WDS attributes */ IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC); @@ -255,50 +154,46 @@ IEEE80211_IF_FILE(dot11MeshHWMPRootMode, #endif -#define DEBUGFS_ADD(name) \ +#define DEBUGFS_ADD(name, type) \ debugfs_create_file(#name, 0400, sdata->debugfs.dir, \ sdata, &name##_ops); -#define DEBUGFS_ADD_MODE(name, mode) \ - debugfs_create_file(#name, mode, sdata->debugfs.dir, \ - sdata, &name##_ops); - static void add_sta_files(struct ieee80211_sub_if_data *sdata) { - DEBUGFS_ADD(drop_unencrypted); - DEBUGFS_ADD(rc_rateidx_mask_2ghz); - DEBUGFS_ADD(rc_rateidx_mask_5ghz); + DEBUGFS_ADD(drop_unencrypted, sta); + DEBUGFS_ADD(force_unicast_rateidx, sta); + DEBUGFS_ADD(max_ratectrl_rateidx, sta); - DEBUGFS_ADD(bssid); - DEBUGFS_ADD(aid); - DEBUGFS_ADD_MODE(smps, 0600); + DEBUGFS_ADD(bssid, sta); + DEBUGFS_ADD(aid, sta); + DEBUGFS_ADD(capab, sta); } static void add_ap_files(struct ieee80211_sub_if_data *sdata) { - DEBUGFS_ADD(drop_unencrypted); - DEBUGFS_ADD(rc_rateidx_mask_2ghz); - DEBUGFS_ADD(rc_rateidx_mask_5ghz); + DEBUGFS_ADD(drop_unencrypted, ap); + DEBUGFS_ADD(force_unicast_rateidx, ap); + DEBUGFS_ADD(max_ratectrl_rateidx, ap); - DEBUGFS_ADD(num_sta_ps); - DEBUGFS_ADD(dtim_count); - DEBUGFS_ADD(num_buffered_multicast); + DEBUGFS_ADD(num_sta_ps, ap); + DEBUGFS_ADD(dtim_count, ap); + DEBUGFS_ADD(num_buffered_multicast, ap); } static void add_wds_files(struct ieee80211_sub_if_data *sdata) { - DEBUGFS_ADD(drop_unencrypted); - DEBUGFS_ADD(rc_rateidx_mask_2ghz); - DEBUGFS_ADD(rc_rateidx_mask_5ghz); + DEBUGFS_ADD(drop_unencrypted, wds); + DEBUGFS_ADD(force_unicast_rateidx, wds); + DEBUGFS_ADD(max_ratectrl_rateidx, wds); - DEBUGFS_ADD(peer); + DEBUGFS_ADD(peer, wds); } static void add_vlan_files(struct ieee80211_sub_if_data *sdata) { - DEBUGFS_ADD(drop_unencrypted); - DEBUGFS_ADD(rc_rateidx_mask_2ghz); - DEBUGFS_ADD(rc_rateidx_mask_5ghz); + DEBUGFS_ADD(drop_unencrypted, vlan); + DEBUGFS_ADD(force_unicast_rateidx, vlan); + DEBUGFS_ADD(max_ratectrl_rateidx, vlan); } static void add_monitor_files(struct ieee80211_sub_if_data *sdata) @@ -385,11 +280,16 @@ static void add_files(struct ieee80211_sub_if_data *sdata) } } +static int notif_registered; + void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata) { char buf[10+IFNAMSIZ]; - sprintf(buf, "netdev:%s", sdata->name); + if (!notif_registered) + return; + + sprintf(buf, "netdev:%s", sdata->dev->name); sdata->debugfs.dir = debugfs_create_dir(buf, sdata->local->hw.wiphy->debugfsdir); add_files(sdata); @@ -404,18 +304,58 @@ void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata) sdata->debugfs.dir = NULL; } -void ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data *sdata) +static int netdev_notify(struct notifier_block *nb, + unsigned long state, + void *ndev) { + struct net_device *dev = ndev; struct dentry *dir; - char buf[10 + IFNAMSIZ]; + struct ieee80211_sub_if_data *sdata; + char buf[10+IFNAMSIZ]; + + if (state != NETDEV_CHANGENAME) + return 0; + + if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy) + return 0; + + if (dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid) + return 0; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); dir = sdata->debugfs.dir; if (!dir) - return; + return 0; - sprintf(buf, "netdev:%s", sdata->name); + sprintf(buf, "netdev:%s", dev->name); if (!debugfs_rename(dir->d_parent, dir, dir->d_parent, buf)) printk(KERN_ERR "mac80211: debugfs: failed to rename debugfs " "dir to %s\n", buf); + + return 0; +} + +static struct notifier_block mac80211_debugfs_netdev_notifier = { + .notifier_call = netdev_notify, +}; + +void ieee80211_debugfs_netdev_init(void) +{ + int err; + + err = register_netdevice_notifier(&mac80211_debugfs_netdev_notifier); + if (err) { + printk(KERN_ERR + "mac80211: failed to install netdev notifier," + " disabling per-netdev debugfs!\n"); + } else + notif_registered = 1; +} + +void ieee80211_debugfs_netdev_exit(void) +{ + unregister_netdevice_notifier(&mac80211_debugfs_netdev_notifier); + notif_registered = 0; } diff --git a/trunk/net/mac80211/debugfs_netdev.h b/trunk/net/mac80211/debugfs_netdev.h index 79025e79f4d6..7af731f0b731 100644 --- a/trunk/net/mac80211/debugfs_netdev.h +++ b/trunk/net/mac80211/debugfs_netdev.h @@ -6,7 +6,8 @@ #ifdef CONFIG_MAC80211_DEBUGFS void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata); void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata); -void ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data *sdata); +void ieee80211_debugfs_netdev_init(void); +void ieee80211_debugfs_netdev_exit(void); #else static inline void ieee80211_debugfs_add_netdev( struct ieee80211_sub_if_data *sdata) @@ -14,8 +15,10 @@ static inline void ieee80211_debugfs_add_netdev( static inline void ieee80211_debugfs_remove_netdev( struct ieee80211_sub_if_data *sdata) {} -static inline void ieee80211_debugfs_rename_netdev( - struct ieee80211_sub_if_data *sdata) +static inline void ieee80211_debugfs_netdev_init(void) +{} + +static inline void ieee80211_debugfs_netdev_exit(void) {} #endif diff --git a/trunk/net/mac80211/debugfs_sta.c b/trunk/net/mac80211/debugfs_sta.c index d92800bb2d2f..3f41608c8081 100644 --- a/trunk/net/mac80211/debugfs_sta.c +++ b/trunk/net/mac80211/debugfs_sta.c @@ -44,7 +44,7 @@ static const struct file_operations sta_ ##name## _ops = { \ STA_OPS(name) STA_FILE(aid, sta.aid, D); -STA_FILE(dev, sdata->name, S); +STA_FILE(dev, sdata->dev->name, S); STA_FILE(rx_packets, rx_packets, LU); STA_FILE(tx_packets, tx_packets, LU); STA_FILE(rx_bytes, rx_bytes, LU); @@ -120,38 +120,36 @@ STA_OPS(last_seq_ctrl); static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { - char buf[64 + STA_TID_NUM * 40], *p = buf; + char buf[30 + STA_TID_NUM * 70], *p = buf; int i; struct sta_info *sta = file->private_data; spin_lock_bh(&sta->lock); - p += scnprintf(p, sizeof(buf) + buf - p, "next dialog_token: %#02x\n", + p += scnprintf(p, sizeof(buf)+buf-p, "next dialog_token is %#02x\n", sta->ampdu_mlme.dialog_token_allocator + 1); - p += scnprintf(p, sizeof(buf) + buf - p, - "TID\t\tRX\tDTKN\tSSN\t\tTX\tDTKN\tSSN\tpending\n"); for (i = 0; i < STA_TID_NUM; i++) { - p += scnprintf(p, sizeof(buf) + buf - p, "%02d", i); - p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x", + p += scnprintf(p, sizeof(buf)+buf-p, "TID %02d:", i); + p += scnprintf(p, sizeof(buf)+buf-p, " RX=%x", sta->ampdu_mlme.tid_state_rx[i]); - p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.2x", + p += scnprintf(p, sizeof(buf)+buf-p, "/DTKN=%#.2x", sta->ampdu_mlme.tid_state_rx[i] ? sta->ampdu_mlme.tid_rx[i]->dialog_token : 0); - p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.3x", + p += scnprintf(p, sizeof(buf)+buf-p, "/SSN=%#.3x", sta->ampdu_mlme.tid_state_rx[i] ? sta->ampdu_mlme.tid_rx[i]->ssn : 0); - p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x", + p += scnprintf(p, sizeof(buf)+buf-p, " TX=%x", sta->ampdu_mlme.tid_state_tx[i]); - p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.2x", + p += scnprintf(p, sizeof(buf)+buf-p, "/DTKN=%#.2x", sta->ampdu_mlme.tid_state_tx[i] ? sta->ampdu_mlme.tid_tx[i]->dialog_token : 0); - p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.3x", + p += scnprintf(p, sizeof(buf)+buf-p, "/SSN=%#.3x", sta->ampdu_mlme.tid_state_tx[i] ? sta->ampdu_mlme.tid_tx[i]->ssn : 0); - p += scnprintf(p, sizeof(buf) + buf - p, "\t%03d", + p += scnprintf(p, sizeof(buf)+buf-p, "/pending=%03d", sta->ampdu_mlme.tid_state_tx[i] ? skb_queue_len(&sta->ampdu_mlme.tid_tx[i]->pending) : 0); - p += scnprintf(p, sizeof(buf) + buf - p, "\n"); + p += scnprintf(p, sizeof(buf)+buf-p, "\n"); } spin_unlock_bh(&sta->lock); @@ -162,12 +160,7 @@ STA_OPS(agg_status); static ssize_t sta_ht_capa_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { -#define PRINT_HT_CAP(_cond, _str) \ - do { \ - if (_cond) \ - p += scnprintf(p, sizeof(buf)+buf-p, "\t" _str "\n"); \ - } while (0) - char buf[512], *p = buf; + char buf[200], *p = buf; int i; struct sta_info *sta = file->private_data; struct ieee80211_sta_ht_cap *htc = &sta->sta.ht_cap; @@ -175,64 +168,15 @@ static ssize_t sta_ht_capa_read(struct file *file, char __user *userbuf, p += scnprintf(p, sizeof(buf) + buf - p, "ht %ssupported\n", htc->ht_supported ? "" : "not "); if (htc->ht_supported) { - p += scnprintf(p, sizeof(buf)+buf-p, "cap: %#.4x\n", htc->cap); - - PRINT_HT_CAP((htc->cap & BIT(0)), "RX LDCP"); - PRINT_HT_CAP((htc->cap & BIT(1)), "HT20/HT40"); - PRINT_HT_CAP(!(htc->cap & BIT(1)), "HT20"); - - PRINT_HT_CAP(((htc->cap >> 2) & 0x3) == 0, "Static SM Power Save"); - PRINT_HT_CAP(((htc->cap >> 2) & 0x3) == 1, "Dynamic SM Power Save"); - PRINT_HT_CAP(((htc->cap >> 2) & 0x3) == 3, "SM Power Save disabled"); - - PRINT_HT_CAP((htc->cap & BIT(4)), "RX Greenfield"); - PRINT_HT_CAP((htc->cap & BIT(5)), "RX HT20 SGI"); - PRINT_HT_CAP((htc->cap & BIT(6)), "RX HT40 SGI"); - PRINT_HT_CAP((htc->cap & BIT(7)), "TX STBC"); - - PRINT_HT_CAP(((htc->cap >> 8) & 0x3) == 0, "No RX STBC"); - PRINT_HT_CAP(((htc->cap >> 8) & 0x3) == 1, "RX STBC 1-stream"); - PRINT_HT_CAP(((htc->cap >> 8) & 0x3) == 2, "RX STBC 2-streams"); - PRINT_HT_CAP(((htc->cap >> 8) & 0x3) == 3, "RX STBC 3-streams"); - - PRINT_HT_CAP((htc->cap & BIT(10)), "HT Delayed Block Ack"); - - PRINT_HT_CAP((htc->cap & BIT(11)), "Max AMSDU length: " - "3839 bytes"); - PRINT_HT_CAP(!(htc->cap & BIT(11)), "Max AMSDU length: " - "7935 bytes"); - - /* - * For beacons and probe response this would mean the BSS - * does or does not allow the usage of DSSS/CCK HT40. - * Otherwise it means the STA does or does not use - * DSSS/CCK HT40. - */ - PRINT_HT_CAP((htc->cap & BIT(12)), "DSSS/CCK HT40"); - PRINT_HT_CAP(!(htc->cap & BIT(12)), "No DSSS/CCK HT40"); - - /* BIT(13) is reserved */ - - PRINT_HT_CAP((htc->cap & BIT(14)), "40 MHz Intolerant"); - - PRINT_HT_CAP((htc->cap & BIT(15)), "L-SIG TXOP protection"); - + p += scnprintf(p, sizeof(buf)+buf-p, "cap: %#.2x\n", htc->cap); p += scnprintf(p, sizeof(buf)+buf-p, "ampdu factor/density: %d/%d\n", htc->ampdu_factor, htc->ampdu_density); p += scnprintf(p, sizeof(buf)+buf-p, "MCS mask:"); - for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) p += scnprintf(p, sizeof(buf)+buf-p, " %.2x", htc->mcs.rx_mask[i]); - p += scnprintf(p, sizeof(buf)+buf-p, "\n"); - - /* If not set this is meaningless */ - if (le16_to_cpu(htc->mcs.rx_highest)) { - p += scnprintf(p, sizeof(buf)+buf-p, - "MCS rx highest: %d Mbps\n", - le16_to_cpu(htc->mcs.rx_highest)); - } - + p += scnprintf(p, sizeof(buf)+buf-p, "\nMCS rx highest: %d\n", + le16_to_cpu(htc->mcs.rx_highest)); p += scnprintf(p, sizeof(buf)+buf-p, "MCS tx params: %x\n", htc->mcs.tx_params); } diff --git a/trunk/net/mac80211/driver-ops.h b/trunk/net/mac80211/driver-ops.h index c3d844093a2f..921dd9c9ff62 100644 --- a/trunk/net/mac80211/driver-ops.h +++ b/trunk/net/mac80211/driver-ops.h @@ -14,8 +14,6 @@ static inline int drv_start(struct ieee80211_local *local) { int ret; - might_sleep(); - local->started = true; smp_mb(); ret = local->ops->start(&local->hw); @@ -25,8 +23,6 @@ static inline int drv_start(struct ieee80211_local *local) static inline void drv_stop(struct ieee80211_local *local) { - might_sleep(); - local->ops->stop(&local->hw); trace_drv_stop(local); @@ -40,47 +36,35 @@ static inline void drv_stop(struct ieee80211_local *local) } static inline int drv_add_interface(struct ieee80211_local *local, - struct ieee80211_vif *vif) + struct ieee80211_if_init_conf *conf) { - int ret; - - might_sleep(); - - ret = local->ops->add_interface(&local->hw, vif); - trace_drv_add_interface(local, vif_to_sdata(vif), ret); + int ret = local->ops->add_interface(&local->hw, conf); + trace_drv_add_interface(local, conf->mac_addr, conf->vif, ret); return ret; } static inline void drv_remove_interface(struct ieee80211_local *local, - struct ieee80211_vif *vif) + struct ieee80211_if_init_conf *conf) { - might_sleep(); - - local->ops->remove_interface(&local->hw, vif); - trace_drv_remove_interface(local, vif_to_sdata(vif)); + local->ops->remove_interface(&local->hw, conf); + trace_drv_remove_interface(local, conf->mac_addr, conf->vif); } static inline int drv_config(struct ieee80211_local *local, u32 changed) { - int ret; - - might_sleep(); - - ret = local->ops->config(&local->hw, changed); + int ret = local->ops->config(&local->hw, changed); trace_drv_config(local, changed, ret); return ret; } static inline void drv_bss_info_changed(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata, + struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, u32 changed) { - might_sleep(); - if (local->ops->bss_info_changed) - local->ops->bss_info_changed(&local->hw, &sdata->vif, info, changed); - trace_drv_bss_info_changed(local, sdata, info, changed); + local->ops->bss_info_changed(&local->hw, vif, info, changed); + trace_drv_bss_info_changed(local, vif, info, changed); } static inline u64 drv_prepare_multicast(struct ieee80211_local *local, @@ -122,53 +106,36 @@ static inline int drv_set_tim(struct ieee80211_local *local, } static inline int drv_set_key(struct ieee80211_local *local, - enum set_key_cmd cmd, - struct ieee80211_sub_if_data *sdata, + enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key) { - int ret; - - might_sleep(); - - ret = local->ops->set_key(&local->hw, cmd, &sdata->vif, sta, key); - trace_drv_set_key(local, cmd, sdata, sta, key, ret); + int ret = local->ops->set_key(&local->hw, cmd, vif, sta, key); + trace_drv_set_key(local, cmd, vif, sta, key, ret); return ret; } static inline void drv_update_tkip_key(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata, struct ieee80211_key_conf *conf, - struct sta_info *sta, u32 iv32, + const u8 *address, u32 iv32, u16 *phase1key) { - struct ieee80211_sta *ista = NULL; - - if (sta) - ista = &sta->sta; - if (local->ops->update_tkip_key) - local->ops->update_tkip_key(&local->hw, &sdata->vif, conf, - ista, iv32, phase1key); - trace_drv_update_tkip_key(local, sdata, conf, ista, iv32); + local->ops->update_tkip_key(&local->hw, conf, address, + iv32, phase1key); + trace_drv_update_tkip_key(local, conf, address, iv32); } static inline int drv_hw_scan(struct ieee80211_local *local, struct cfg80211_scan_request *req) { - int ret; - - might_sleep(); - - ret = local->ops->hw_scan(&local->hw, req); + int ret = local->ops->hw_scan(&local->hw, req); trace_drv_hw_scan(local, req, ret); return ret; } static inline void drv_sw_scan_start(struct ieee80211_local *local) { - might_sleep(); - if (local->ops->sw_scan_start) local->ops->sw_scan_start(&local->hw); trace_drv_sw_scan_start(local); @@ -176,8 +143,6 @@ static inline void drv_sw_scan_start(struct ieee80211_local *local) static inline void drv_sw_scan_complete(struct ieee80211_local *local) { - might_sleep(); - if (local->ops->sw_scan_complete) local->ops->sw_scan_complete(&local->hw); trace_drv_sw_scan_complete(local); @@ -188,8 +153,6 @@ static inline int drv_get_stats(struct ieee80211_local *local, { int ret = -EOPNOTSUPP; - might_sleep(); - if (local->ops->get_stats) ret = local->ops->get_stats(&local->hw, stats); trace_drv_get_stats(local, stats, ret); @@ -209,93 +172,43 @@ static inline int drv_set_rts_threshold(struct ieee80211_local *local, u32 value) { int ret = 0; - - might_sleep(); - if (local->ops->set_rts_threshold) ret = local->ops->set_rts_threshold(&local->hw, value); trace_drv_set_rts_threshold(local, value, ret); return ret; } -static inline int drv_set_coverage_class(struct ieee80211_local *local, - u8 value) -{ - int ret = 0; - might_sleep(); - - if (local->ops->set_coverage_class) - local->ops->set_coverage_class(&local->hw, value); - else - ret = -EOPNOTSUPP; - - trace_drv_set_coverage_class(local, value, ret); - return ret; -} - static inline void drv_sta_notify(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata, + struct ieee80211_vif *vif, enum sta_notify_cmd cmd, struct ieee80211_sta *sta) { if (local->ops->sta_notify) - local->ops->sta_notify(&local->hw, &sdata->vif, cmd, sta); - trace_drv_sta_notify(local, sdata, cmd, sta); -} - -static inline int drv_sta_add(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata, - struct ieee80211_sta *sta) -{ - int ret = 0; - - might_sleep(); - - if (local->ops->sta_add) - ret = local->ops->sta_add(&local->hw, &sdata->vif, sta); - else if (local->ops->sta_notify) - local->ops->sta_notify(&local->hw, &sdata->vif, - STA_NOTIFY_ADD, sta); - - trace_drv_sta_add(local, sdata, sta, ret); - - return ret; -} - -static inline void drv_sta_remove(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata, - struct ieee80211_sta *sta) -{ - might_sleep(); - - if (local->ops->sta_remove) - local->ops->sta_remove(&local->hw, &sdata->vif, sta); - else if (local->ops->sta_notify) - local->ops->sta_notify(&local->hw, &sdata->vif, - STA_NOTIFY_REMOVE, sta); - - trace_drv_sta_remove(local, sdata, sta); + local->ops->sta_notify(&local->hw, vif, cmd, sta); + trace_drv_sta_notify(local, vif, cmd, sta); } static inline int drv_conf_tx(struct ieee80211_local *local, u16 queue, const struct ieee80211_tx_queue_params *params) { int ret = -EOPNOTSUPP; - - might_sleep(); - if (local->ops->conf_tx) ret = local->ops->conf_tx(&local->hw, queue, params); trace_drv_conf_tx(local, queue, params, ret); return ret; } +static inline int drv_get_tx_stats(struct ieee80211_local *local, + struct ieee80211_tx_queue_stats *stats) +{ + int ret = local->ops->get_tx_stats(&local->hw, stats); + trace_drv_get_tx_stats(local, stats, ret); + return ret; +} + static inline u64 drv_get_tsf(struct ieee80211_local *local) { u64 ret = -1ULL; - - might_sleep(); - if (local->ops->get_tsf) ret = local->ops->get_tsf(&local->hw); trace_drv_get_tsf(local, ret); @@ -304,8 +217,6 @@ static inline u64 drv_get_tsf(struct ieee80211_local *local) static inline void drv_set_tsf(struct ieee80211_local *local, u64 tsf) { - might_sleep(); - if (local->ops->set_tsf) local->ops->set_tsf(&local->hw, tsf); trace_drv_set_tsf(local, tsf); @@ -313,8 +224,6 @@ static inline void drv_set_tsf(struct ieee80211_local *local, u64 tsf) static inline void drv_reset_tsf(struct ieee80211_local *local) { - might_sleep(); - if (local->ops->reset_tsf) local->ops->reset_tsf(&local->hw); trace_drv_reset_tsf(local); @@ -323,9 +232,6 @@ static inline void drv_reset_tsf(struct ieee80211_local *local) static inline int drv_tx_last_beacon(struct ieee80211_local *local) { int ret = 1; - - might_sleep(); - if (local->ops->tx_last_beacon) ret = local->ops->tx_last_beacon(&local->hw); trace_drv_tx_last_beacon(local, ret); @@ -333,34 +239,23 @@ static inline int drv_tx_last_beacon(struct ieee80211_local *local) } static inline int drv_ampdu_action(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata, + struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, u16 tid, u16 *ssn) { int ret = -EOPNOTSUPP; if (local->ops->ampdu_action) - ret = local->ops->ampdu_action(&local->hw, &sdata->vif, action, + ret = local->ops->ampdu_action(&local->hw, vif, action, sta, tid, ssn); - trace_drv_ampdu_action(local, sdata, action, sta, tid, ssn, ret); + trace_drv_ampdu_action(local, vif, action, sta, tid, ssn, ret); return ret; } static inline void drv_rfkill_poll(struct ieee80211_local *local) { - might_sleep(); - if (local->ops->rfkill_poll) local->ops->rfkill_poll(&local->hw); } - -static inline void drv_flush(struct ieee80211_local *local, bool drop) -{ - might_sleep(); - - trace_drv_flush(local, drop); - if (local->ops->flush) - local->ops->flush(&local->hw, drop); -} #endif /* __MAC80211_DRIVER_OPS */ diff --git a/trunk/net/mac80211/driver-trace.h b/trunk/net/mac80211/driver-trace.h index 41baf730a5c7..da8497ef7063 100644 --- a/trunk/net/mac80211/driver-trace.h +++ b/trunk/net/mac80211/driver-trace.h @@ -25,12 +25,10 @@ static inline void trace_ ## name(proto) {} #define STA_PR_FMT " sta:%pM" #define STA_PR_ARG __entry->sta_addr -#define VIF_ENTRY __field(enum nl80211_iftype, vif_type) __field(void *, sdata) \ - __string(vif_name, sdata->dev ? sdata->dev->name : "") -#define VIF_ASSIGN __entry->vif_type = sdata->vif.type; __entry->sdata = sdata; \ - __assign_str(vif_name, sdata->dev ? sdata->dev->name : "") -#define VIF_PR_FMT " vif:%s(%d)" -#define VIF_PR_ARG __get_str(vif_name), __entry->vif_type +#define VIF_ENTRY __field(enum nl80211_iftype, vif_type) __field(void *, vif) +#define VIF_ASSIGN __entry->vif_type = vif ? vif->type : 0; __entry->vif = vif +#define VIF_PR_FMT " vif:%p(%d)" +#define VIF_PR_ARG __entry->vif, __entry->vif_type TRACE_EVENT(drv_start, TP_PROTO(struct ieee80211_local *local, int ret), @@ -72,10 +70,11 @@ TRACE_EVENT(drv_stop, TRACE_EVENT(drv_add_interface, TP_PROTO(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata, + const u8 *addr, + struct ieee80211_vif *vif, int ret), - TP_ARGS(local, sdata, ret), + TP_ARGS(local, addr, vif, ret), TP_STRUCT__entry( LOCAL_ENTRY @@ -87,7 +86,7 @@ TRACE_EVENT(drv_add_interface, TP_fast_assign( LOCAL_ASSIGN; VIF_ASSIGN; - memcpy(__entry->addr, sdata->vif.addr, 6); + memcpy(__entry->addr, addr, 6); __entry->ret = ret; ), @@ -98,9 +97,10 @@ TRACE_EVENT(drv_add_interface, ); TRACE_EVENT(drv_remove_interface, - TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata), + TP_PROTO(struct ieee80211_local *local, + const u8 *addr, struct ieee80211_vif *vif), - TP_ARGS(local, sdata), + TP_ARGS(local, addr, vif), TP_STRUCT__entry( LOCAL_ENTRY @@ -111,7 +111,7 @@ TRACE_EVENT(drv_remove_interface, TP_fast_assign( LOCAL_ASSIGN; VIF_ASSIGN; - memcpy(__entry->addr, sdata->vif.addr, 6); + memcpy(__entry->addr, addr, 6); ), TP_printk( @@ -140,7 +140,6 @@ TRACE_EVENT(drv_config, __field(u8, short_frame_max_tx_count) __field(int, center_freq) __field(int, channel_type) - __field(int, smps) ), TP_fast_assign( @@ -156,7 +155,6 @@ TRACE_EVENT(drv_config, __entry->short_frame_max_tx_count = local->hw.conf.short_frame_max_tx_count; __entry->center_freq = local->hw.conf.channel->center_freq; __entry->channel_type = local->hw.conf.channel_type; - __entry->smps = local->hw.conf.smps_mode; ), TP_printk( @@ -167,11 +165,11 @@ TRACE_EVENT(drv_config, TRACE_EVENT(drv_bss_info_changed, TP_PROTO(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata, + struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, u32 changed), - TP_ARGS(local, sdata, info, changed), + TP_ARGS(local, vif, info, changed), TP_STRUCT__entry( LOCAL_ENTRY @@ -295,11 +293,11 @@ TRACE_EVENT(drv_set_tim, TRACE_EVENT(drv_set_key, TP_PROTO(struct ieee80211_local *local, - enum set_key_cmd cmd, struct ieee80211_sub_if_data *sdata, + enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key, int ret), - TP_ARGS(local, cmd, sdata, sta, key, ret), + TP_ARGS(local, cmd, vif, sta, key, ret), TP_STRUCT__entry( LOCAL_ENTRY @@ -331,29 +329,26 @@ TRACE_EVENT(drv_set_key, TRACE_EVENT(drv_update_tkip_key, TP_PROTO(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata, struct ieee80211_key_conf *conf, - struct ieee80211_sta *sta, u32 iv32), + const u8 *address, u32 iv32), - TP_ARGS(local, sdata, conf, sta, iv32), + TP_ARGS(local, conf, address, iv32), TP_STRUCT__entry( LOCAL_ENTRY - VIF_ENTRY - STA_ENTRY + __array(u8, addr, 6) __field(u32, iv32) ), TP_fast_assign( LOCAL_ASSIGN; - VIF_ASSIGN; - STA_ASSIGN; + memcpy(__entry->addr, address, 6); __entry->iv32 = iv32; ), TP_printk( - LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " iv32:%#x", - LOCAL_PR_ARG,VIF_PR_ARG,STA_PR_ARG, __entry->iv32 + LOCAL_PR_FMT " addr:%pM iv32:%#x", + LOCAL_PR_ARG, __entry->addr, __entry->iv32 ) ); @@ -494,36 +489,13 @@ TRACE_EVENT(drv_set_rts_threshold, ) ); -TRACE_EVENT(drv_set_coverage_class, - TP_PROTO(struct ieee80211_local *local, u8 value, int ret), - - TP_ARGS(local, value, ret), - - TP_STRUCT__entry( - LOCAL_ENTRY - __field(u8, value) - __field(int, ret) - ), - - TP_fast_assign( - LOCAL_ASSIGN; - __entry->ret = ret; - __entry->value = value; - ), - - TP_printk( - LOCAL_PR_FMT " value:%d ret:%d", - LOCAL_PR_ARG, __entry->value, __entry->ret - ) -); - TRACE_EVENT(drv_sta_notify, TP_PROTO(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata, + struct ieee80211_vif *vif, enum sta_notify_cmd cmd, struct ieee80211_sta *sta), - TP_ARGS(local, sdata, cmd, sta), + TP_ARGS(local, vif, cmd, sta), TP_STRUCT__entry( LOCAL_ENTRY @@ -545,88 +517,59 @@ TRACE_EVENT(drv_sta_notify, ) ); -TRACE_EVENT(drv_sta_add, - TP_PROTO(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata, - struct ieee80211_sta *sta, int ret), +TRACE_EVENT(drv_conf_tx, + TP_PROTO(struct ieee80211_local *local, u16 queue, + const struct ieee80211_tx_queue_params *params, + int ret), - TP_ARGS(local, sdata, sta, ret), + TP_ARGS(local, queue, params, ret), TP_STRUCT__entry( LOCAL_ENTRY - VIF_ENTRY - STA_ENTRY + __field(u16, queue) + __field(u16, txop) + __field(u16, cw_min) + __field(u16, cw_max) + __field(u8, aifs) __field(int, ret) ), TP_fast_assign( LOCAL_ASSIGN; - VIF_ASSIGN; - STA_ASSIGN; + __entry->queue = queue; __entry->ret = ret; + __entry->txop = params->txop; + __entry->cw_max = params->cw_max; + __entry->cw_min = params->cw_min; + __entry->aifs = params->aifs; ), TP_printk( - LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " ret:%d", - LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->ret + LOCAL_PR_FMT " queue:%d ret:%d", + LOCAL_PR_ARG, __entry->queue, __entry->ret ) ); -TRACE_EVENT(drv_sta_remove, +TRACE_EVENT(drv_get_tx_stats, TP_PROTO(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata, - struct ieee80211_sta *sta), - - TP_ARGS(local, sdata, sta), - - TP_STRUCT__entry( - LOCAL_ENTRY - VIF_ENTRY - STA_ENTRY - ), - - TP_fast_assign( - LOCAL_ASSIGN; - VIF_ASSIGN; - STA_ASSIGN; - ), - - TP_printk( - LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT, - LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG - ) -); - -TRACE_EVENT(drv_conf_tx, - TP_PROTO(struct ieee80211_local *local, u16 queue, - const struct ieee80211_tx_queue_params *params, + struct ieee80211_tx_queue_stats *stats, int ret), - TP_ARGS(local, queue, params, ret), + TP_ARGS(local, stats, ret), TP_STRUCT__entry( LOCAL_ENTRY - __field(u16, queue) - __field(u16, txop) - __field(u16, cw_min) - __field(u16, cw_max) - __field(u8, aifs) __field(int, ret) ), TP_fast_assign( LOCAL_ASSIGN; - __entry->queue = queue; __entry->ret = ret; - __entry->txop = params->txop; - __entry->cw_max = params->cw_max; - __entry->cw_min = params->cw_min; - __entry->aifs = params->aifs; ), TP_printk( - LOCAL_PR_FMT " queue:%d ret:%d", - LOCAL_PR_ARG, __entry->queue, __entry->ret + LOCAL_PR_FMT " ret:%d", + LOCAL_PR_ARG, __entry->ret ) ); @@ -713,12 +656,12 @@ TRACE_EVENT(drv_tx_last_beacon, TRACE_EVENT(drv_ampdu_action, TP_PROTO(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata, + struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, u16 tid, u16 *ssn, int ret), - TP_ARGS(local, sdata, action, sta, tid, ssn, ret), + TP_ARGS(local, vif, action, sta, tid, ssn, ret), TP_STRUCT__entry( LOCAL_ENTRY @@ -745,27 +688,6 @@ TRACE_EVENT(drv_ampdu_action, LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->action, __entry->tid, __entry->ret ) ); - -TRACE_EVENT(drv_flush, - TP_PROTO(struct ieee80211_local *local, bool drop), - - TP_ARGS(local, drop), - - TP_STRUCT__entry( - LOCAL_ENTRY - __field(bool, drop) - ), - - TP_fast_assign( - LOCAL_ASSIGN; - __entry->drop = drop; - ), - - TP_printk( - LOCAL_PR_FMT " drop:%d", - LOCAL_PR_ARG, __entry->drop - ) -); #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */ #undef TRACE_INCLUDE_PATH diff --git a/trunk/net/mac80211/ht.c b/trunk/net/mac80211/ht.c index bb677a73b7c9..d7dcee680728 100644 --- a/trunk/net/mac80211/ht.c +++ b/trunk/net/mac80211/ht.c @@ -125,7 +125,7 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, if (!skb) { printk(KERN_ERR "%s: failed to allocate buffer " - "for delba frame\n", sdata->name); + "for delba frame\n", sdata->dev->name); return; } @@ -133,10 +133,10 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); memset(mgmt, 0, 24); memcpy(mgmt->da, da, ETH_ALEN); - memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); + memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); if (sdata->vif.type == NL80211_IFTYPE_AP || sdata->vif.type == NL80211_IFTYPE_AP_VLAN) - memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); + memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); else if (sdata->vif.type == NL80211_IFTYPE_STATION) memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN); @@ -185,50 +185,3 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, spin_unlock_bh(&sta->lock); } } - -int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata, - enum ieee80211_smps_mode smps, const u8 *da, - const u8 *bssid) -{ - struct ieee80211_local *local = sdata->local; - struct sk_buff *skb; - struct ieee80211_mgmt *action_frame; - - /* 27 = header + category + action + smps mode */ - skb = dev_alloc_skb(27 + local->hw.extra_tx_headroom); - if (!skb) - return -ENOMEM; - - skb_reserve(skb, local->hw.extra_tx_headroom); - action_frame = (void *)skb_put(skb, 27); - memcpy(action_frame->da, da, ETH_ALEN); - memcpy(action_frame->sa, sdata->dev->dev_addr, ETH_ALEN); - memcpy(action_frame->bssid, bssid, ETH_ALEN); - action_frame->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | - IEEE80211_STYPE_ACTION); - action_frame->u.action.category = WLAN_CATEGORY_HT; - action_frame->u.action.u.ht_smps.action = WLAN_HT_ACTION_SMPS; - switch (smps) { - case IEEE80211_SMPS_AUTOMATIC: - case IEEE80211_SMPS_NUM_MODES: - WARN_ON(1); - case IEEE80211_SMPS_OFF: - action_frame->u.action.u.ht_smps.smps_control = - WLAN_HT_SMPS_CONTROL_DISABLED; - break; - case IEEE80211_SMPS_STATIC: - action_frame->u.action.u.ht_smps.smps_control = - WLAN_HT_SMPS_CONTROL_STATIC; - break; - case IEEE80211_SMPS_DYNAMIC: - action_frame->u.action.u.ht_smps.smps_control = - WLAN_HT_SMPS_CONTROL_DYNAMIC; - break; - } - - /* we'll do more on status of this frame */ - IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; - ieee80211_tx_skb(sdata, skb); - - return 0; -} diff --git a/trunk/net/mac80211/ibss.c b/trunk/net/mac80211/ibss.c index f3e942486749..22f0c2aa7a89 100644 --- a/trunk/net/mac80211/ibss.c +++ b/trunk/net/mac80211/ibss.c @@ -117,7 +117,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_RESP); memset(mgmt->da, 0xff, ETH_ALEN); - memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); + memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); memcpy(mgmt->bssid, ifibss->bssid, ETH_ALEN); mgmt->u.beacon.beacon_int = cpu_to_le16(beacon_int); mgmt->u.beacon.timestamp = cpu_to_le64(tsf); @@ -187,17 +187,15 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, struct ieee80211_bss *bss) { - struct cfg80211_bss *cbss = - container_of((void *)bss, struct cfg80211_bss, priv); struct ieee80211_supported_band *sband; u32 basic_rates; int i, j; - u16 beacon_int = cbss->beacon_interval; + u16 beacon_int = bss->cbss.beacon_interval; if (beacon_int < 10) beacon_int = 10; - sband = sdata->local->hw.wiphy->bands[cbss->channel->band]; + sband = sdata->local->hw.wiphy->bands[bss->cbss.channel->band]; basic_rates = 0; @@ -214,12 +212,12 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, } } - __ieee80211_sta_join_ibss(sdata, cbss->bssid, + __ieee80211_sta_join_ibss(sdata, bss->cbss.bssid, beacon_int, - cbss->channel, + bss->cbss.channel, basic_rates, - cbss->capability, - cbss->tsf); + bss->cbss.capability, + bss->cbss.tsf); } static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, @@ -231,7 +229,6 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, { struct ieee80211_local *local = sdata->local; int freq; - struct cfg80211_bss *cbss; struct ieee80211_bss *bss; struct sta_info *sta; struct ieee80211_channel *channel; @@ -255,7 +252,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, rcu_read_lock(); - sta = sta_info_get(sdata, mgmt->sa); + sta = sta_info_get(local, mgmt->sa); if (sta) { u32 prev_rates; @@ -269,18 +266,16 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, printk(KERN_DEBUG "%s: updated supp_rates set " "for %pM based on beacon info (0x%llx | " "0x%llx -> 0x%llx)\n", - sdata->name, + sdata->dev->name, sta->sta.addr, (unsigned long long) prev_rates, (unsigned long long) supp_rates, (unsigned long long) sta->sta.supp_rates[band]); #endif - rcu_read_unlock(); - } else { - rcu_read_unlock(); - ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, - supp_rates, GFP_KERNEL); - } + } else + ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates); + + rcu_read_unlock(); } bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, @@ -288,23 +283,25 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, if (!bss) return; - cbss = container_of((void *)bss, struct cfg80211_bss, priv); - /* was just updated in ieee80211_bss_info_update */ - beacon_timestamp = cbss->tsf; + beacon_timestamp = bss->cbss.tsf; /* check if we need to merge IBSS */ + /* merge only on beacons (???) */ + if (!beacon) + goto put_bss; + /* we use a fixed BSSID */ - if (sdata->u.ibss.fixed_bssid) + if (sdata->u.ibss.bssid) goto put_bss; /* not an IBSS */ - if (!(cbss->capability & WLAN_CAPABILITY_IBSS)) + if (!(bss->cbss.capability & WLAN_CAPABILITY_IBSS)) goto put_bss; /* different channel */ - if (cbss->channel != local->oper_channel) + if (bss->cbss.channel != local->oper_channel) goto put_bss; /* different SSID */ @@ -314,7 +311,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, goto put_bss; /* same BSSID */ - if (memcmp(cbss->bssid, sdata->u.ibss.bssid, ETH_ALEN) == 0) + if (memcmp(bss->cbss.bssid, sdata->u.ibss.bssid, ETH_ALEN) == 0) goto put_bss; if (rx_status->flag & RX_FLAG_TSFT) { @@ -367,11 +364,10 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, #ifdef CONFIG_MAC80211_IBSS_DEBUG printk(KERN_DEBUG "%s: beacon TSF higher than " "local TSF - IBSS merge with BSSID %pM\n", - sdata->name, mgmt->bssid); + sdata->dev->name, mgmt->bssid); #endif ieee80211_sta_join_ibss(sdata, bss); - ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, - supp_rates, GFP_KERNEL); + ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates); } put_bss: @@ -384,8 +380,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, * must be callable in atomic context. */ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, - u8 *bssid,u8 *addr, u32 supp_rates, - gfp_t gfp) + u8 *bssid,u8 *addr, u32 supp_rates) { struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; struct ieee80211_local *local = sdata->local; @@ -399,7 +394,7 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) { if (net_ratelimit()) printk(KERN_DEBUG "%s: No room for a new IBSS STA entry %pM\n", - sdata->name, addr); + sdata->dev->name, addr); return NULL; } @@ -411,10 +406,10 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, #ifdef CONFIG_MAC80211_VERBOSE_DEBUG printk(KERN_DEBUG "%s: Adding new IBSS station %pM (dev=%s)\n", - wiphy_name(local->hw.wiphy), addr, sdata->name); + wiphy_name(local->hw.wiphy), addr, sdata->dev->name); #endif - sta = sta_info_alloc(sdata, addr, gfp); + sta = sta_info_alloc(sdata, addr, GFP_ATOMIC); if (!sta) return NULL; @@ -426,9 +421,9 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, rate_control_rate_init(sta); - /* If it fails, maybe we raced another insertion? */ if (sta_info_insert(sta)) - return sta_info_get(sdata, addr); + return NULL; + return sta; } @@ -454,9 +449,6 @@ static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata) return active; } -/* - * This function is called with state == IEEE80211_IBSS_MLME_JOINED - */ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata) { @@ -478,7 +470,7 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata) return; printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other " - "IBSS networks with same SSID (merge)\n", sdata->name); + "IBSS networks with same SSID (merge)\n", sdata->dev->name); ieee80211_request_internal_scan(sdata, ifibss->ssid, ifibss->ssid_len); } @@ -500,13 +492,13 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) * random number generator get different BSSID. */ get_random_bytes(bssid, ETH_ALEN); for (i = 0; i < ETH_ALEN; i++) - bssid[i] ^= sdata->vif.addr[i]; + bssid[i] ^= sdata->dev->dev_addr[i]; bssid[0] &= ~0x01; bssid[0] |= 0x02; } printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n", - sdata->name, bssid); + sdata->dev->name, bssid); sband = local->hw.wiphy->bands[ifibss->channel->band]; @@ -522,15 +514,11 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) capability, 0); } -/* - * This function is called with state == IEEE80211_IBSS_MLME_SEARCH - */ - static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; struct ieee80211_local *local = sdata->local; - struct cfg80211_bss *cbss; + struct ieee80211_bss *bss; struct ieee80211_channel *chan = NULL; const u8 *bssid = NULL; int active_ibss; @@ -539,7 +527,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) active_ibss = ieee80211_sta_active_ibss(sdata); #ifdef CONFIG_MAC80211_IBSS_DEBUG printk(KERN_DEBUG "%s: sta_find_ibss (active_ibss=%d)\n", - sdata->name, active_ibss); + sdata->dev->name, active_ibss); #endif /* CONFIG_MAC80211_IBSS_DEBUG */ if (active_ibss) @@ -554,23 +542,21 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) chan = ifibss->channel; if (!is_zero_ether_addr(ifibss->bssid)) bssid = ifibss->bssid; - cbss = cfg80211_get_bss(local->hw.wiphy, chan, bssid, - ifibss->ssid, ifibss->ssid_len, - WLAN_CAPABILITY_IBSS | WLAN_CAPABILITY_PRIVACY, - capability); - - if (cbss) { - struct ieee80211_bss *bss; + bss = (void *)cfg80211_get_bss(local->hw.wiphy, chan, bssid, + ifibss->ssid, ifibss->ssid_len, + WLAN_CAPABILITY_IBSS | + WLAN_CAPABILITY_PRIVACY, + capability); - bss = (void *)cbss->priv; + if (bss) { #ifdef CONFIG_MAC80211_IBSS_DEBUG printk(KERN_DEBUG " sta_find_ibss: selected %pM current " - "%pM\n", cbss->bssid, ifibss->bssid); + "%pM\n", bss->cbss.bssid, ifibss->bssid); #endif /* CONFIG_MAC80211_IBSS_DEBUG */ printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM" " based on configured SSID\n", - sdata->name, cbss->bssid); + sdata->dev->name, bss->cbss.bssid); ieee80211_sta_join_ibss(sdata, bss); ieee80211_rx_bss_put(local, bss); @@ -582,14 +568,18 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) #endif /* CONFIG_MAC80211_IBSS_DEBUG */ /* Selected IBSS not found in current scan results - try to scan */ - if (time_after(jiffies, ifibss->last_scan_completed + + if (ifibss->state == IEEE80211_IBSS_MLME_JOINED && + !ieee80211_sta_active_ibss(sdata)) { + mod_timer(&ifibss->timer, + round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL)); + } else if (time_after(jiffies, ifibss->last_scan_completed + IEEE80211_SCAN_INTERVAL)) { printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to " - "join\n", sdata->name); + "join\n", sdata->dev->name); ieee80211_request_internal_scan(sdata, ifibss->ssid, ifibss->ssid_len); - } else { + } else if (ifibss->state != IEEE80211_IBSS_MLME_JOINED) { int interval = IEEE80211_SCAN_INTERVAL; if (time_after(jiffies, ifibss->ibss_join_req + @@ -599,7 +589,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) return; } printk(KERN_DEBUG "%s: IBSS not allowed on" - " %d MHz\n", sdata->name, + " %d MHz\n", sdata->dev->name, local->hw.conf.channel->center_freq); /* No IBSS found - decrease scan interval and continue @@ -607,6 +597,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) interval = IEEE80211_SCAN_INTERVAL_SLOW; } + ifibss->state = IEEE80211_IBSS_MLME_SEARCH; mod_timer(&ifibss->timer, round_jiffies(jiffies + interval)); } @@ -632,7 +623,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, #ifdef CONFIG_MAC80211_IBSS_DEBUG printk(KERN_DEBUG "%s: RX ProbeReq SA=%pM DA=%pM BSSID=%pM" " (tx_last_beacon=%d)\n", - sdata->name, mgmt->sa, mgmt->da, + sdata->dev->name, mgmt->sa, mgmt->da, mgmt->bssid, tx_last_beacon); #endif /* CONFIG_MAC80211_IBSS_DEBUG */ @@ -650,7 +641,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, #ifdef CONFIG_MAC80211_IBSS_DEBUG printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq " "from %pM\n", - sdata->name, mgmt->sa); + sdata->dev->name, mgmt->sa); #endif return; } @@ -670,7 +661,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, memcpy(resp->da, mgmt->sa, ETH_ALEN); #ifdef CONFIG_MAC80211_IBSS_DEBUG printk(KERN_DEBUG "%s: Sending ProbeResp to %pM\n", - sdata->name, resp->da); + sdata->dev->name, resp->da); #endif /* CONFIG_MAC80211_IBSS_DEBUG */ IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; ieee80211_tx_skb(sdata, skb); @@ -684,7 +675,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, size_t baselen; struct ieee802_11_elems elems; - if (memcmp(mgmt->da, sdata->vif.addr, ETH_ALEN)) + if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN)) return; /* ignore ProbeResp to foreign address */ baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt; @@ -757,7 +748,7 @@ static void ieee80211_ibss_work(struct work_struct *work) if (WARN_ON(local->suspended)) return; - if (!ieee80211_sdata_running(sdata)) + if (!netif_running(sdata->dev)) return; if (local->scanning) @@ -840,7 +831,7 @@ void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local) mutex_lock(&local->iflist_mtx); list_for_each_entry(sdata, &local->interfaces, list) { - if (!ieee80211_sdata_running(sdata)) + if (!netif_running(sdata->dev)) continue; if (sdata->vif.type != NL80211_IFTYPE_ADHOC) continue; diff --git a/trunk/net/mac80211/ieee80211_i.h b/trunk/net/mac80211/ieee80211_i.h index 241533e1bc03..91dc8636d644 100644 --- a/trunk/net/mac80211/ieee80211_i.h +++ b/trunk/net/mac80211/ieee80211_i.h @@ -2,7 +2,7 @@ * Copyright 2002-2005, Instant802 Networks, Inc. * Copyright 2005, Devicescape Software, Inc. * Copyright 2006-2007 Jiri Benc - * Copyright 2007-2010 Johannes Berg + * Copyright 2007-2008 Johannes Berg * * 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 @@ -58,15 +58,6 @@ struct ieee80211_local; #define TU_TO_EXP_TIME(x) (jiffies + usecs_to_jiffies((x) * 1024)) -#define IEEE80211_DEFAULT_UAPSD_QUEUES \ - (IEEE80211_WMM_IE_STA_QOSINFO_AC_BK | \ - IEEE80211_WMM_IE_STA_QOSINFO_AC_BE | \ - IEEE80211_WMM_IE_STA_QOSINFO_AC_VI | \ - IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) - -#define IEEE80211_DEFAULT_MAX_SP_LEN \ - IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL - struct ieee80211_fragment_entry { unsigned long first_frag_time; unsigned int seq; @@ -80,6 +71,9 @@ struct ieee80211_fragment_entry { struct ieee80211_bss { + /* Yes, this is a hack */ + struct cfg80211_bss cbss; + /* don't want to look up all the time */ size_t ssid_len; u8 ssid[IEEE80211_MAX_SSID_LEN]; @@ -87,7 +81,6 @@ struct ieee80211_bss { u8 dtim_period; bool wmm_used; - bool uapsd_supported; unsigned long last_probe_resp; @@ -147,6 +140,7 @@ typedef unsigned __bitwise__ ieee80211_tx_result; struct ieee80211_tx_data { struct sk_buff *skb; + struct net_device *dev; struct ieee80211_local *local; struct ieee80211_sub_if_data *sdata; struct sta_info *sta; @@ -234,77 +228,31 @@ struct mesh_preq_queue { u8 flags; }; -enum ieee80211_work_type { - IEEE80211_WORK_ABORT, - IEEE80211_WORK_DIRECT_PROBE, - IEEE80211_WORK_AUTH, - IEEE80211_WORK_ASSOC, - IEEE80211_WORK_REMAIN_ON_CHANNEL, +enum ieee80211_mgd_state { + IEEE80211_MGD_STATE_IDLE, + IEEE80211_MGD_STATE_PROBE, + IEEE80211_MGD_STATE_AUTH, + IEEE80211_MGD_STATE_ASSOC, }; -/** - * enum work_done_result - indicates what to do after work was done - * - * @WORK_DONE_DESTROY: This work item is no longer needed, destroy. - * @WORK_DONE_REQUEUE: This work item was reset to be reused, and - * should be requeued. - */ -enum work_done_result { - WORK_DONE_DESTROY, - WORK_DONE_REQUEUE, -}; - -struct ieee80211_work { +struct ieee80211_mgd_work { struct list_head list; - - struct rcu_head rcu_head; - - struct ieee80211_sub_if_data *sdata; - - enum work_done_result (*done)(struct ieee80211_work *wk, - struct sk_buff *skb); - - struct ieee80211_channel *chan; - enum nl80211_channel_type chan_type; - + struct ieee80211_bss *bss; + int ie_len; + u8 prev_bssid[ETH_ALEN]; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + u8 ssid_len; unsigned long timeout; - enum ieee80211_work_type type; - - u8 filter_ta[ETH_ALEN]; + enum ieee80211_mgd_state state; + u16 auth_alg, auth_transaction; - bool started; + int tries; - union { - struct { - int tries; - u16 algorithm, transaction; - u8 ssid[IEEE80211_MAX_SSID_LEN]; - u8 ssid_len; - u8 key[WLAN_KEY_LEN_WEP104]; - u8 key_len, key_idx; - bool privacy; - } probe_auth; - struct { - struct cfg80211_bss *bss; - const u8 *supp_rates; - const u8 *ht_information_ie; - enum ieee80211_smps_mode smps; - int tries; - u16 capability; - u8 prev_bssid[ETH_ALEN]; - u8 ssid[IEEE80211_MAX_SSID_LEN]; - u8 ssid_len; - u8 supp_rates_len; - bool wmm_used, use_11n, uapsd_used; - } assoc; - struct { - u32 duration; - } remain; - }; + u8 key[WLAN_KEY_LEN_WEP104]; + u8 key_len, key_idx; - int ie_len; /* must be last */ - u8 ie[0]; + u8 ie[0]; /* for auth or assoc frame, not probe */ }; /* flags used in struct ieee80211_if_managed.flags */ @@ -312,11 +260,15 @@ enum ieee80211_sta_flags { IEEE80211_STA_BEACON_POLL = BIT(0), IEEE80211_STA_CONNECTION_POLL = BIT(1), IEEE80211_STA_CONTROL_PORT = BIT(2), + IEEE80211_STA_WMM_ENABLED = BIT(3), IEEE80211_STA_DISABLE_11N = BIT(4), IEEE80211_STA_CSA_RECEIVED = BIT(5), IEEE80211_STA_MFP_ENABLED = BIT(6), - IEEE80211_STA_UAPSD_ENABLED = BIT(7), - IEEE80211_STA_NULLFUNC_ACKED = BIT(8), +}; + +/* flags for MLME request */ +enum ieee80211_sta_request { + IEEE80211_STA_REQ_SCAN, }; struct ieee80211_if_managed { @@ -333,18 +285,21 @@ struct ieee80211_if_managed { int probe_send_count; struct mutex mtx; - struct cfg80211_bss *associated; + struct ieee80211_bss *associated; + struct ieee80211_mgd_work *old_associate_work; + struct list_head work_list; u8 bssid[ETH_ALEN]; u16 aid; + u16 capab; struct sk_buff_head skb_queue; unsigned long timers_running; /* used for quiesce/restart */ bool powersave; /* powersave requested for this iface */ - enum ieee80211_smps_mode req_smps, /* requested smps mode */ - ap_smps; /* smps mode AP thinks we're in */ + + unsigned long request; unsigned int flags; @@ -478,8 +433,6 @@ struct ieee80211_sub_if_data { int drop_unencrypted; - char name[IFNAMSIZ]; - /* * keep track of whether the HT opmode (stored in * vif.bss_info.ht_operation_mode) is valid. @@ -505,8 +458,8 @@ struct ieee80211_sub_if_data { */ struct ieee80211_if_ap *bss; - /* bitmap of allowed (non-MCS) rate indexes for rate control */ - u32 rc_rateidx_mask[IEEE80211_NUM_BANDS]; + int force_unicast_rateidx; /* forced TX rateidx for unicast frames */ + int max_ratectrl_rateidx; /* max TX rateidx for rate control */ union { struct ieee80211_if_ap ap; @@ -611,15 +564,6 @@ struct ieee80211_local { const struct ieee80211_ops *ops; - /* - * work stuff, potentially off-channel (in the future) - */ - struct mutex work_mtx; - struct list_head work_list; - struct timer_list work_timer; - struct work_struct work_work; - struct sk_buff_head work_skb_queue; - /* * private workqueue to mac80211. mac80211 makes this accessible * via ieee80211_queue_work() @@ -642,9 +586,6 @@ struct ieee80211_local { /* used for uploading changed mc list */ struct work_struct reconfig_filter; - /* used to reconfigure hardware SM PS */ - struct work_struct recalc_smps; - /* aggregated multicast list */ struct dev_addr_list *mc_list; int mc_count; @@ -689,18 +630,15 @@ struct ieee80211_local { /* Station data */ /* - * The mutex only protects the list and counter, - * reads are done in RCU. - * Additionally, the lock protects the hash table, - * the pending list and each BSS's TIM bitmap. + * The lock only protects the list, hash, timer and counter + * against manipulation, reads are done in RCU. Additionally, + * the lock protects each BSS's TIM bitmap. */ - struct mutex sta_mtx; spinlock_t sta_lock; unsigned long num_sta; - struct list_head sta_list, sta_pending_list; + struct list_head sta_list; struct sta_info *sta_hash[STA_HASH_SIZE]; struct timer_list sta_cleanup; - struct work_struct sta_finish_work; int sta_generation; struct sk_buff_head pending[IEEE80211_MAX_QUEUES]; @@ -751,10 +689,6 @@ struct ieee80211_local { enum nl80211_channel_type oper_channel_type; struct ieee80211_channel *oper_channel, *csa_channel; - /* Temporary remain-on-channel for off-channel operations */ - struct ieee80211_channel *tmp_channel; - enum nl80211_channel_type tmp_channel_type; - /* SNMP counters */ /* dot11CountersTable */ u32 dot11TransmittedFragmentCount; @@ -774,6 +708,10 @@ struct ieee80211_local { assoc_led_name[32], radio_led_name[32]; #endif +#ifdef CONFIG_MAC80211_DEBUGFS + struct work_struct sta_debugfs_add; +#endif + #ifdef CONFIG_MAC80211_DEBUG_COUNTERS /* TX/RX handler statistics */ unsigned int tx_handlers_drop; @@ -807,22 +745,8 @@ struct ieee80211_local { int wifi_wme_noack_test; unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */ - /* - * Bitmask of enabled u-apsd queues, - * IEEE80211_WMM_IE_STA_QOSINFO_AC_BE & co. Needs a new association - * to take effect. - */ - unsigned int uapsd_queues; - - /* - * Maximum number of buffered frames AP can deliver during a - * service period, IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL or similar. - * Needs a new association to take effect. - */ - unsigned int uapsd_max_sp_len; - bool pspolling; - bool offchannel_ps_enabled; + bool scan_ps_enabled; /* * PS can only be enabled when we have exactly one managed * interface (and monitors) in PS, this then points there. @@ -836,8 +760,6 @@ struct ieee80211_local { int user_power_level; /* in dBm */ int power_constr_level; /* in dBm */ - enum ieee80211_smps_mode smps_mode; - struct work_struct restart_work; #ifdef CONFIG_MAC80211_DEBUGFS @@ -952,8 +874,6 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, void ieee80211_configure_filter(struct ieee80211_local *local); u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata); -extern bool ieee80211_disable_40mhz_24ghz; - /* STA code */ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata); int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, @@ -966,10 +886,6 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, struct cfg80211_disassoc_request *req, void *cookie); -int ieee80211_mgd_action(struct ieee80211_sub_if_data *sdata, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, - const u8 *buf, size_t len, u64 *cookie); ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); void ieee80211_send_pspoll(struct ieee80211_local *local, @@ -989,8 +905,7 @@ void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata); ieee80211_rx_result ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, - u8 *bssid, u8 *addr, u32 supp_rates, - gfp_t gfp); + u8 *bssid, u8 *addr, u32 supp_rates); int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, struct cfg80211_ibss_params *params); int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata); @@ -1022,15 +937,7 @@ ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq, void ieee80211_rx_bss_put(struct ieee80211_local *local, struct ieee80211_bss *bss); -/* off-channel helpers */ -void ieee80211_offchannel_stop_beaconing(struct ieee80211_local *local); -void ieee80211_offchannel_stop_station(struct ieee80211_local *local); -void ieee80211_offchannel_return(struct ieee80211_local *local, - bool enable_beaconing); - /* interface handling */ -int ieee80211_iface_init(void); -void ieee80211_iface_exit(void); int ieee80211_if_add(struct ieee80211_local *local, const char *name, struct net_device **new_dev, enum nl80211_iftype type, struct vif_params *params); @@ -1041,11 +948,6 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local); u32 __ieee80211_recalc_idle(struct ieee80211_local *local); void ieee80211_recalc_idle(struct ieee80211_local *local); -static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata) -{ - return netif_running(sdata->dev); -} - /* tx handling */ void ieee80211_clear_tx_pending(struct ieee80211_local *local); void ieee80211_tx_pending(unsigned long data); @@ -1074,9 +976,6 @@ void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u1 void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, const u8 *da, u16 tid, u16 initiator, u16 reason_code); -int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata, - enum ieee80211_smps_mode smps, const u8 *da, - const u8 *bssid); void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *da, u16 tid, u16 initiator, u16 reason); @@ -1187,28 +1086,6 @@ void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, u32 ieee80211_sta_get_rates(struct ieee80211_local *local, struct ieee802_11_elems *elems, enum ieee80211_band band); -int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, - enum ieee80211_smps_mode smps_mode); -void ieee80211_recalc_smps(struct ieee80211_local *local, - struct ieee80211_sub_if_data *forsdata); - -size_t ieee80211_ie_split(const u8 *ies, size_t ielen, - const u8 *ids, int n_ids, size_t offset); -size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset); - -/* internal work items */ -void ieee80211_work_init(struct ieee80211_local *local); -void ieee80211_add_work(struct ieee80211_work *wk); -void free_work(struct ieee80211_work *wk); -void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata); -ieee80211_rx_result ieee80211_work_rx_mgmt(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb); -int ieee80211_wk_remain_on_channel(struct ieee80211_sub_if_data *sdata, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, - unsigned int duration, u64 *cookie); -int ieee80211_wk_cancel_remain_on_channel( - struct ieee80211_sub_if_data *sdata, u64 cookie); #ifdef CONFIG_MAC80211_NOINLINE #define debug_noinline noinline diff --git a/trunk/net/mac80211/iface.c b/trunk/net/mac80211/iface.c index 0793d7a8d743..32abae3ce32a 100644 --- a/trunk/net/mac80211/iface.c +++ b/trunk/net/mac80211/iface.c @@ -62,23 +62,6 @@ static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) return 0; } -static int ieee80211_change_mac(struct net_device *dev, void *addr) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct sockaddr *sa = addr; - int ret; - - if (ieee80211_sdata_running(sdata)) - return -EBUSY; - - ret = eth_mac_addr(dev, sa); - - if (ret == 0) - memcpy(sdata->vif.addr, sa->sa_data, ETH_ALEN); - - return ret; -} - static inline int identical_mac_addr_allowed(int type1, int type2) { return type1 == NL80211_IFTYPE_MONITOR || @@ -99,6 +82,7 @@ static int ieee80211_open(struct net_device *dev) struct ieee80211_sub_if_data *nsdata; struct ieee80211_local *local = sdata->local; struct sta_info *sta; + struct ieee80211_if_init_conf conf; u32 changed = 0; int res; u32 hw_reconf_flags = 0; @@ -113,7 +97,7 @@ static int ieee80211_open(struct net_device *dev) list_for_each_entry(nsdata, &local->interfaces, list) { struct net_device *ndev = nsdata->dev; - if (ndev != dev && ieee80211_sdata_running(nsdata)) { + if (ndev != dev && netif_running(ndev)) { /* * Allow only a single IBSS interface to be up at any * time. This is restricted because beacon distribution @@ -199,7 +183,7 @@ static int ieee80211_open(struct net_device *dev) struct net_device *ndev = nsdata->dev; /* - * No need to check running since we do not allow + * No need to check netif_running since we do not allow * it to start up with this invalid address. */ if (compare_ether_addr(null_addr, ndev->dev_addr) == 0) { @@ -250,7 +234,10 @@ static int ieee80211_open(struct net_device *dev) ieee80211_configure_filter(local); break; default: - res = drv_add_interface(local, &sdata->vif); + conf.vif = &sdata->vif; + conf.type = sdata->vif.type; + conf.mac_addr = dev->dev_addr; + res = drv_add_interface(local, &conf); if (res) goto err_stop; @@ -333,7 +320,7 @@ static int ieee80211_open(struct net_device *dev) return 0; err_del_interface: - drv_remove_interface(local, &sdata->vif); + drv_remove_interface(local, &conf); err_stop: if (!local->open_count) drv_stop(local); @@ -348,6 +335,7 @@ static int ieee80211_stop(struct net_device *dev) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = sdata->local; + struct ieee80211_if_init_conf conf; struct sta_info *sta; unsigned long flags; struct sk_buff *skb, *tmp; @@ -359,11 +347,6 @@ static int ieee80211_stop(struct net_device *dev) */ netif_tx_stop_all_queues(dev); - /* - * Purge work for this interface. - */ - ieee80211_work_purge(sdata); - /* * Now delete all active aggregation sessions. */ @@ -531,9 +514,12 @@ static int ieee80211_stop(struct net_device *dev) BSS_CHANGED_BEACON_ENABLED); } + conf.vif = &sdata->vif; + conf.type = sdata->vif.type; + conf.mac_addr = dev->dev_addr; /* disable all keys for as long as this netdev is down */ ieee80211_disable_keys(sdata); - drv_remove_interface(local, &sdata->vif); + drv_remove_interface(local, &conf); } sdata->bss = NULL; @@ -673,7 +659,7 @@ static const struct net_device_ops ieee80211_dataif_ops = { .ndo_start_xmit = ieee80211_subif_start_xmit, .ndo_set_multicast_list = ieee80211_set_multicast_list, .ndo_change_mtu = ieee80211_change_mtu, - .ndo_set_mac_address = ieee80211_change_mac, + .ndo_set_mac_address = eth_mac_addr, .ndo_select_queue = ieee80211_netdev_select_queue, }; @@ -695,12 +681,8 @@ static u16 ieee80211_monitor_select_queue(struct net_device *dev, hdr = (void *)((u8 *)skb->data + le16_to_cpu(rtap->it_len)); - if (!ieee80211_is_data(hdr->frame_control)) { - skb->priority = 7; - return ieee802_1d_to_ac[skb->priority]; - } if (!ieee80211_is_data_qos(hdr->frame_control)) { - skb->priority = 0; + skb->priority = 7; return ieee802_1d_to_ac[skb->priority]; } @@ -797,7 +779,7 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, * and goes into the requested mode. */ - if (ieee80211_sdata_running(sdata)) + if (netif_running(sdata->dev)) return -EBUSY; /* Purge and reset type-dependent state. */ @@ -851,8 +833,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, /* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */ sdata = netdev_priv(ndev); ndev->ieee80211_ptr = &sdata->wdev; - memcpy(sdata->vif.addr, ndev->dev_addr, ETH_ALEN); - memcpy(sdata->name, ndev->name, IFNAMSIZ); /* initialise type-independent data */ sdata->wdev.wiphy = local->hw.wiphy; @@ -864,12 +844,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, INIT_LIST_HEAD(&sdata->key_list); - for (i = 0; i < IEEE80211_NUM_BANDS; i++) { - struct ieee80211_supported_band *sband; - sband = local->hw.wiphy->bands[i]; - sdata->rc_rateidx_mask[i] = - sband ? (1 << sband->n_bitrates) - 1 : 0; - } + sdata->force_unicast_rateidx = -1; + sdata->max_ratectrl_rateidx = -1; /* setup type-dependent data */ ieee80211_setup_sdata(sdata, type); @@ -962,8 +938,6 @@ static u32 ieee80211_idle_on(struct ieee80211_local *local) wiphy_name(local->hw.wiphy)); #endif - drv_flush(local, false); - local->hw.conf.flags |= IEEE80211_CONF_IDLE; return IEEE80211_CONF_CHANGE_IDLE; } @@ -973,18 +947,16 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local) struct ieee80211_sub_if_data *sdata; int count = 0; - if (!list_empty(&local->work_list)) - return ieee80211_idle_off(local, "working"); - if (local->scanning) return ieee80211_idle_off(local, "scanning"); list_for_each_entry(sdata, &local->interfaces, list) { - if (!ieee80211_sdata_running(sdata)) + if (!netif_running(sdata->dev)) continue; /* do not count disabled managed interfaces */ if (sdata->vif.type == NL80211_IFTYPE_STATION && - !sdata->u.mgd.associated) + !sdata->u.mgd.associated && + list_empty(&sdata->u.mgd.work_list)) continue; /* do not count unused IBSS interfaces */ if (sdata->vif.type == NL80211_IFTYPE_ADHOC && @@ -1012,41 +984,3 @@ void ieee80211_recalc_idle(struct ieee80211_local *local) if (chg) ieee80211_hw_config(local, chg); } - -static int netdev_notify(struct notifier_block *nb, - unsigned long state, - void *ndev) -{ - struct net_device *dev = ndev; - struct ieee80211_sub_if_data *sdata; - - if (state != NETDEV_CHANGENAME) - return 0; - - if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy) - return 0; - - if (dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid) - return 0; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - memcpy(sdata->name, dev->name, IFNAMSIZ); - - ieee80211_debugfs_rename_netdev(sdata); - return 0; -} - -static struct notifier_block mac80211_netdev_notifier = { - .notifier_call = netdev_notify, -}; - -int ieee80211_iface_init(void) -{ - return register_netdevice_notifier(&mac80211_netdev_notifier); -} - -void ieee80211_iface_exit(void) -{ - unregister_netdevice_notifier(&mac80211_netdev_notifier); -} diff --git a/trunk/net/mac80211/key.c b/trunk/net/mac80211/key.c index 8160d9c5372e..659a42d529e3 100644 --- a/trunk/net/mac80211/key.c +++ b/trunk/net/mac80211/key.c @@ -139,7 +139,7 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key) struct ieee80211_sub_if_data, u.ap); - ret = drv_set_key(key->local, SET_KEY, sdata, sta, &key->conf); + ret = drv_set_key(key->local, SET_KEY, &sdata->vif, sta, &key->conf); if (!ret) { spin_lock_bh(&todo_lock); @@ -181,7 +181,7 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) struct ieee80211_sub_if_data, u.ap); - ret = drv_set_key(key->local, DISABLE_KEY, sdata, + ret = drv_set_key(key->local, DISABLE_KEY, &sdata->vif, sta, &key->conf); if (ret) @@ -421,7 +421,7 @@ void ieee80211_key_link(struct ieee80211_key *key, */ /* same here, the AP could be using QoS */ - ap = sta_info_get(key->sdata, key->sdata->u.mgd.bssid); + ap = sta_info_get(key->local, key->sdata->u.mgd.bssid); if (ap) { if (test_sta_flags(ap, WLAN_STA_WME)) key->conf.flags |= @@ -443,7 +443,7 @@ void ieee80211_key_link(struct ieee80211_key *key, add_todo(old_key, KEY_FLAG_TODO_DELETE); add_todo(key, KEY_FLAG_TODO_ADD_DEBUGFS); - if (ieee80211_sdata_running(sdata)) + if (netif_running(sdata->dev)) add_todo(key, KEY_FLAG_TODO_HWACCEL_ADD); spin_unlock_irqrestore(&sdata->local->key_lock, flags); @@ -509,7 +509,7 @@ void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata) { ASSERT_RTNL(); - if (WARN_ON(!ieee80211_sdata_running(sdata))) + if (WARN_ON(!netif_running(sdata->dev))) return; ieee80211_todo_for_each_key(sdata, KEY_FLAG_TODO_HWACCEL_ADD); diff --git a/trunk/net/mac80211/key.h b/trunk/net/mac80211/key.h index bdc2968c2bbe..a49f93b79e92 100644 --- a/trunk/net/mac80211/key.h +++ b/trunk/net/mac80211/key.h @@ -59,17 +59,11 @@ enum ieee80211_internal_key_flags { KEY_FLAG_TODO_DEFMGMTKEY = BIT(6), }; -enum ieee80211_internal_tkip_state { - TKIP_STATE_NOT_INIT, - TKIP_STATE_PHASE1_DONE, - TKIP_STATE_PHASE1_HW_UPLOADED, -}; - struct tkip_ctx { u32 iv32; u16 iv16; u16 p1k[5]; - enum ieee80211_internal_tkip_state state; + int initialized; }; struct ieee80211_key { diff --git a/trunk/net/mac80211/main.c b/trunk/net/mac80211/main.c index ec8f767ba95b..0d2d94881f1f 100644 --- a/trunk/net/mac80211/main.c +++ b/trunk/net/mac80211/main.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -31,12 +32,7 @@ #include "led.h" #include "cfg.h" #include "debugfs.h" - - -bool ieee80211_disable_40mhz_24ghz; -module_param(ieee80211_disable_40mhz_24ghz, bool, 0644); -MODULE_PARM_DESC(ieee80211_disable_40mhz_24ghz, - "Disable 40MHz support in the 2.4GHz band"); +#include "debugfs_netdev.h" void ieee80211_configure_filter(struct ieee80211_local *local) { @@ -106,9 +102,6 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) if (scan_chan) { chan = scan_chan; channel_type = NL80211_CHAN_NO_HT; - } else if (local->tmp_channel) { - chan = scan_chan = local->tmp_channel; - channel_type = local->tmp_channel_type; } else { chan = local->oper_channel; channel_type = local->oper_channel_type; @@ -121,18 +114,6 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) changed |= IEEE80211_CONF_CHANGE_CHANNEL; } - if (!conf_is_ht(&local->hw.conf)) { - /* - * mac80211.h documents that this is only valid - * when the channel is set to an HT type, and - * that otherwise STATIC is used. - */ - local->hw.conf.smps_mode = IEEE80211_SMPS_STATIC; - } else if (local->hw.conf.smps_mode != local->smps_mode) { - local->hw.conf.smps_mode = local->smps_mode; - changed |= IEEE80211_CONF_CHANGE_SMPS; - } - if (scan_chan) power = chan->max_power; else @@ -192,7 +173,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid; else if (sdata->vif.type == NL80211_IFTYPE_AP) - sdata->vif.bss_conf.bssid = sdata->vif.addr; + sdata->vif.bss_conf.bssid = sdata->dev->dev_addr; else if (ieee80211_vif_is_mesh(&sdata->vif)) { sdata->vif.bss_conf.bssid = zero; } else { @@ -214,7 +195,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, } if (changed & BSS_CHANGED_BEACON_ENABLED) { - if (local->quiescing || !ieee80211_sdata_running(sdata) || + if (local->quiescing || !netif_running(sdata->dev) || test_bit(SCAN_SW_SCANNING, &local->scanning)) { sdata->vif.bss_conf.enable_beacon = false; } else { @@ -242,7 +223,8 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, } } - drv_bss_info_changed(local, sdata, &sdata->vif.bss_conf, changed); + drv_bss_info_changed(local, &sdata->vif, + &sdata->vif.bss_conf, changed); } u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata) @@ -317,16 +299,6 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw) } EXPORT_SYMBOL(ieee80211_restart_hw); -static void ieee80211_recalc_smps_work(struct work_struct *work) -{ - struct ieee80211_local *local = - container_of(work, struct ieee80211_local, recalc_smps); - - mutex_lock(&local->iflist_mtx); - ieee80211_recalc_smps(local, NULL); - mutex_unlock(&local->iflist_mtx); -} - struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, const struct ieee80211_ops *ops) { @@ -361,7 +333,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, WIPHY_FLAG_4ADDR_STATION; wiphy->privid = mac80211_wiphy_privid; - wiphy->bss_priv_size = sizeof(struct ieee80211_bss); + /* Yes, putting cfg80211_bss into ieee80211_bss is a hack */ + wiphy->bss_priv_size = sizeof(struct ieee80211_bss) - + sizeof(struct cfg80211_bss); local = wiphy_priv(wiphy); @@ -384,8 +358,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; local->user_power_level = -1; - local->uapsd_queues = IEEE80211_DEFAULT_UAPSD_QUEUES; - local->uapsd_max_sp_len = IEEE80211_DEFAULT_MAX_SP_LEN; INIT_LIST_HEAD(&local->interfaces); mutex_init(&local->iflist_mtx); @@ -397,13 +369,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work); - ieee80211_work_init(local); - INIT_WORK(&local->restart_work, ieee80211_restart_work); INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter); - INIT_WORK(&local->recalc_smps, ieee80211_recalc_smps_work); - local->smps_mode = IEEE80211_SMPS_OFF; INIT_WORK(&local->dynamic_ps_enable_work, ieee80211_dynamic_ps_enable_work); @@ -493,10 +461,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; - WARN((local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD) - && (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK), - "U-APSD not supported with HW_PS_NULLFUNC_STACK\n"); - /* * Calculate scan IE length -- we need this to alloc * memory and to subtract from the driver limit. It @@ -710,19 +674,11 @@ static int __init ieee80211_init(void) ret = rc80211_pid_init(); if (ret) - goto err_pid; + return ret; - ret = ieee80211_iface_init(); - if (ret) - goto err_netdev; + ieee80211_debugfs_netdev_init(); return 0; - err_netdev: - rc80211_pid_exit(); - err_pid: - rc80211_minstrel_exit(); - - return ret; } static void __exit ieee80211_exit(void) @@ -739,7 +695,7 @@ static void __exit ieee80211_exit(void) if (mesh_allocated) ieee80211s_stop(); - ieee80211_iface_exit(); + ieee80211_debugfs_netdev_exit(); } diff --git a/trunk/net/mac80211/mesh.c b/trunk/net/mac80211/mesh.c index 61080c5fad50..6a4331429598 100644 --- a/trunk/net/mac80211/mesh.c +++ b/trunk/net/mac80211/mesh.c @@ -457,7 +457,7 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata, #ifdef CONFIG_MAC80211_VERBOSE_DEBUG printk(KERN_DEBUG "%s: running mesh housekeeping\n", - sdata->name); + sdata->dev->name); #endif ieee80211_sta_expire(sdata, IEEE80211_MESH_PEER_INACTIVITY_LIMIT); @@ -565,7 +565,7 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, /* ignore ProbeResp to foreign address */ if (stype == IEEE80211_STYPE_PROBE_RESP && - compare_ether_addr(mgmt->da, sdata->vif.addr)) + compare_ether_addr(mgmt->da, sdata->dev->dev_addr)) return; baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt; @@ -645,7 +645,7 @@ static void ieee80211_mesh_work(struct work_struct *work) struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct sk_buff *skb; - if (!ieee80211_sdata_running(sdata)) + if (!netif_running(sdata->dev)) return; if (local->scanning) diff --git a/trunk/net/mac80211/mesh_hwmp.c b/trunk/net/mac80211/mesh_hwmp.c index ce84237ebad3..d28acb6b1f81 100644 --- a/trunk/net/mac80211/mesh_hwmp.c +++ b/trunk/net/mac80211/mesh_hwmp.c @@ -128,9 +128,9 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, IEEE80211_STYPE_ACTION); memcpy(mgmt->da, da, ETH_ALEN); - memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); + memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); /* BSSID == SA */ - memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); + memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); mgmt->u.action.category = MESH_PATH_SEL_CATEGORY; mgmt->u.action.u.mesh_action.action_code = MESH_PATH_SEL_ACTION; @@ -222,7 +222,7 @@ int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn, IEEE80211_STYPE_ACTION); memcpy(mgmt->da, ra, ETH_ALEN); - memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); + memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); /* BSSID is left zeroed, wildcard value */ mgmt->u.action.category = MESH_PATH_SEL_CATEGORY; mgmt->u.action.u.mesh_action.action_code = MESH_PATH_SEL_ACTION; @@ -335,7 +335,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, bool process = true; rcu_read_lock(); - sta = sta_info_get(sdata, mgmt->sa); + sta = sta_info_get(local, mgmt->sa); if (!sta) { rcu_read_unlock(); return 0; @@ -374,7 +374,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, new_metric = MAX_METRIC; exp_time = TU_TO_EXP_TIME(orig_lifetime); - if (memcmp(orig_addr, sdata->vif.addr, ETH_ALEN) == 0) { + if (memcmp(orig_addr, sdata->dev->dev_addr, ETH_ALEN) == 0) { /* This MP is the originator, we are not interested in this * frame, except for updating transmitter's path info. */ @@ -486,7 +486,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, mhwmp_dbg("received PREQ from %pM\n", orig_addr); - if (memcmp(target_addr, sdata->vif.addr, ETH_ALEN) == 0) { + if (memcmp(target_addr, sdata->dev->dev_addr, ETH_ALEN) == 0) { mhwmp_dbg("PREQ is for us\n"); forward = false; reply = true; @@ -579,7 +579,7 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, * replies */ target_addr = PREP_IE_TARGET_ADDR(prep_elem); - if (memcmp(target_addr, sdata->vif.addr, ETH_ALEN) == 0) + if (memcmp(target_addr, sdata->dev->dev_addr, ETH_ALEN) == 0) /* destination, no forwarding required */ return; @@ -890,7 +890,7 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata) target_flags = MP_F_RF; spin_unlock_bh(&mpath->state_lock); - mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->vif.addr, + mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->dev->dev_addr, cpu_to_le32(ifmsh->sn), target_flags, mpath->dst, cpu_to_le32(mpath->sn), broadcast_addr, 0, ttl, cpu_to_le32(lifetime), 0, @@ -939,7 +939,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb, if (time_after(jiffies, mpath->exp_time - msecs_to_jiffies(sdata->u.mesh.mshcfg.path_refresh_time)) && - !memcmp(sdata->vif.addr, hdr->addr4, ETH_ALEN) && + !memcmp(sdata->dev->dev_addr, hdr->addr4, ETH_ALEN) && !(mpath->flags & MESH_PATH_RESOLVING) && !(mpath->flags & MESH_PATH_FIXED)) { mesh_queue_preq(mpath, @@ -1010,7 +1010,7 @@ mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; - mesh_path_sel_frame_tx(MPATH_RANN, 0, sdata->vif.addr, + mesh_path_sel_frame_tx(MPATH_RANN, 0, sdata->dev->dev_addr, cpu_to_le32(++ifmsh->sn), 0, NULL, 0, broadcast_addr, 0, MESH_TTL, 0, 0, 0, sdata); diff --git a/trunk/net/mac80211/mesh_pathtbl.c b/trunk/net/mac80211/mesh_pathtbl.c index fbef678f64c8..a8da23905c70 100644 --- a/trunk/net/mac80211/mesh_pathtbl.c +++ b/trunk/net/mac80211/mesh_pathtbl.c @@ -260,7 +260,7 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) int err = 0; u32 hash_idx; - if (memcmp(dst, sdata->vif.addr, ETH_ALEN) == 0) + if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0) /* never add ourselves as neighbours */ return -ENOTSUPP; @@ -377,7 +377,7 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) int err = 0; u32 hash_idx; - if (memcmp(dst, sdata->vif.addr, ETH_ALEN) == 0) + if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0) /* never add ourselves as neighbours */ return -ENOTSUPP; @@ -605,7 +605,7 @@ void mesh_path_discard_frame(struct sk_buff *skb, struct mesh_path *mpath; u32 sn = 0; - if (memcmp(hdr->addr4, sdata->vif.addr, ETH_ALEN) != 0) { + if (memcmp(hdr->addr4, sdata->dev->dev_addr, ETH_ALEN) != 0) { u8 *ra, *da; da = hdr->addr3; diff --git a/trunk/net/mac80211/mesh_plink.c b/trunk/net/mac80211/mesh_plink.c index bc4e20e57ff5..0f7c6e6a4248 100644 --- a/trunk/net/mac80211/mesh_plink.c +++ b/trunk/net/mac80211/mesh_plink.c @@ -102,7 +102,7 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, if (local->num_sta >= MESH_MAX_PLINKS) return NULL; - sta = sta_info_alloc(sdata, hw_addr, GFP_KERNEL); + sta = sta_info_alloc(sdata, hw_addr, GFP_ATOMIC); if (!sta) return NULL; @@ -169,7 +169,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION); memcpy(mgmt->da, da, ETH_ALEN); - memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); + memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); /* BSSID is left zeroed, wildcard value */ mgmt->u.action.category = MESH_PLINK_CATEGORY; mgmt->u.action.u.plink_action.action_code = action; @@ -234,14 +234,14 @@ void mesh_neighbour_update(u8 *hw_addr, u32 rates, struct ieee80211_sub_if_data rcu_read_lock(); - sta = sta_info_get(sdata, hw_addr); + sta = sta_info_get(local, hw_addr); if (!sta) { - rcu_read_unlock(); - sta = mesh_plink_alloc(sdata, hw_addr, rates); - if (!sta) + if (!sta) { + rcu_read_unlock(); return; - if (sta_info_insert_rcu(sta)) { + } + if (sta_info_insert(sta)) { rcu_read_unlock(); return; } @@ -455,7 +455,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m rcu_read_lock(); - sta = sta_info_get(sdata, mgmt->sa); + sta = sta_info_get(local, mgmt->sa); if (!sta && ftype != PLINK_OPEN) { mpl_dbg("Mesh plink: cls or cnf from unknown peer\n"); rcu_read_unlock(); @@ -485,11 +485,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m } else if (!sta) { /* ftype == PLINK_OPEN */ u32 rates; - - rcu_read_unlock(); - if (!mesh_plink_free_count(sdata)) { mpl_dbg("Mesh plink error: no more free plinks\n"); + rcu_read_unlock(); return; } @@ -497,9 +495,10 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m sta = mesh_plink_alloc(sdata, mgmt->sa, rates); if (!sta) { mpl_dbg("Mesh plink error: plink table full\n"); + rcu_read_unlock(); return; } - if (sta_info_insert_rcu(sta)) { + if (sta_info_insert(sta)) { rcu_read_unlock(); return; } diff --git a/trunk/net/mac80211/mlme.c b/trunk/net/mac80211/mlme.c index 41812a15eea0..05a18f43e1bf 100644 --- a/trunk/net/mac80211/mlme.c +++ b/trunk/net/mac80211/mlme.c @@ -27,6 +27,10 @@ #include "rate.h" #include "led.h" +#define IEEE80211_AUTH_TIMEOUT (HZ / 5) +#define IEEE80211_AUTH_MAX_TRIES 3 +#define IEEE80211_ASSOC_TIMEOUT (HZ / 5) +#define IEEE80211_ASSOC_MAX_TRIES 3 #define IEEE80211_MAX_PROBE_TRIES 5 /* @@ -71,8 +75,11 @@ enum rx_mgmt_action { /* caller must call cfg80211_send_disassoc() */ RX_MGMT_CFG80211_DISASSOC, - /* caller must tell cfg80211 about internal error */ - RX_MGMT_CFG80211_ASSOC_ERROR, + /* caller must call cfg80211_auth_timeout() & free work */ + RX_MGMT_CFG80211_AUTH_TO, + + /* caller must call cfg80211_assoc_timeout() & free work */ + RX_MGMT_CFG80211_ASSOC_TO, }; /* utils */ @@ -115,6 +122,27 @@ static int ecw2cw(int ecw) return (1 << ecw) - 1; } +static int ieee80211_compatible_rates(struct ieee80211_bss *bss, + struct ieee80211_supported_band *sband, + u32 *rates) +{ + int i, j, count; + *rates = 0; + count = 0; + for (i = 0; i < bss->supp_rates_len; i++) { + int rate = (bss->supp_rates[i] & 0x7F) * 5; + + for (j = 0; j < sband->n_bitrates; j++) + if (sband->bitrates[j].bitrate == rate) { + *rates |= BIT(j); + count++; + break; + } + } + + return count; +} + /* * ieee80211_enable_ht should be called only after the operating band * has been determined as ht configuration depends on the hw's @@ -174,7 +202,7 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, ieee80211_hw_config(local, 0); rcu_read_lock(); - sta = sta_info_get(sdata, bssid); + sta = sta_info_get(local, bssid); if (sta) rate_control_rate_update(local, sband, sta, IEEE80211_RC_HT_CHANGED); @@ -200,6 +228,209 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, /* frame sending functions */ +static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgd_work *wk) +{ + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + struct ieee80211_local *local = sdata->local; + struct sk_buff *skb; + struct ieee80211_mgmt *mgmt; + u8 *pos; + const u8 *ies, *ht_ie; + int i, len, count, rates_len, supp_rates_len; + u16 capab; + int wmm = 0; + struct ieee80211_supported_band *sband; + u32 rates = 0; + + skb = dev_alloc_skb(local->hw.extra_tx_headroom + + sizeof(*mgmt) + 200 + wk->ie_len + + wk->ssid_len); + if (!skb) { + printk(KERN_DEBUG "%s: failed to allocate buffer for assoc " + "frame\n", sdata->dev->name); + return; + } + skb_reserve(skb, local->hw.extra_tx_headroom); + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + + capab = ifmgd->capab; + + if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) { + if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE)) + capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME; + if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE)) + capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; + } + + if (wk->bss->cbss.capability & WLAN_CAPABILITY_PRIVACY) + capab |= WLAN_CAPABILITY_PRIVACY; + if (wk->bss->wmm_used) + wmm = 1; + + /* get all rates supported by the device and the AP as + * some APs don't like getting a superset of their rates + * in the association request (e.g. D-Link DAP 1353 in + * b-only mode) */ + rates_len = ieee80211_compatible_rates(wk->bss, sband, &rates); + + if ((wk->bss->cbss.capability & WLAN_CAPABILITY_SPECTRUM_MGMT) && + (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)) + capab |= WLAN_CAPABILITY_SPECTRUM_MGMT; + + mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); + memset(mgmt, 0, 24); + memcpy(mgmt->da, wk->bss->cbss.bssid, ETH_ALEN); + memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); + memcpy(mgmt->bssid, wk->bss->cbss.bssid, ETH_ALEN); + + if (!is_zero_ether_addr(wk->prev_bssid)) { + skb_put(skb, 10); + mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | + IEEE80211_STYPE_REASSOC_REQ); + mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab); + mgmt->u.reassoc_req.listen_interval = + cpu_to_le16(local->hw.conf.listen_interval); + memcpy(mgmt->u.reassoc_req.current_ap, wk->prev_bssid, + ETH_ALEN); + } else { + skb_put(skb, 4); + mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | + IEEE80211_STYPE_ASSOC_REQ); + mgmt->u.assoc_req.capab_info = cpu_to_le16(capab); + mgmt->u.assoc_req.listen_interval = + cpu_to_le16(local->hw.conf.listen_interval); + } + + /* SSID */ + ies = pos = skb_put(skb, 2 + wk->ssid_len); + *pos++ = WLAN_EID_SSID; + *pos++ = wk->ssid_len; + memcpy(pos, wk->ssid, wk->ssid_len); + + /* add all rates which were marked to be used above */ + supp_rates_len = rates_len; + if (supp_rates_len > 8) + supp_rates_len = 8; + + len = sband->n_bitrates; + pos = skb_put(skb, supp_rates_len + 2); + *pos++ = WLAN_EID_SUPP_RATES; + *pos++ = supp_rates_len; + + count = 0; + for (i = 0; i < sband->n_bitrates; i++) { + if (BIT(i) & rates) { + int rate = sband->bitrates[i].bitrate; + *pos++ = (u8) (rate / 5); + if (++count == 8) + break; + } + } + + if (rates_len > count) { + pos = skb_put(skb, rates_len - count + 2); + *pos++ = WLAN_EID_EXT_SUPP_RATES; + *pos++ = rates_len - count; + + for (i++; i < sband->n_bitrates; i++) { + if (BIT(i) & rates) { + int rate = sband->bitrates[i].bitrate; + *pos++ = (u8) (rate / 5); + } + } + } + + if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) { + /* 1. power capabilities */ + pos = skb_put(skb, 4); + *pos++ = WLAN_EID_PWR_CAPABILITY; + *pos++ = 2; + *pos++ = 0; /* min tx power */ + *pos++ = local->hw.conf.channel->max_power; /* max tx power */ + + /* 2. supported channels */ + /* TODO: get this in reg domain format */ + pos = skb_put(skb, 2 * sband->n_channels + 2); + *pos++ = WLAN_EID_SUPPORTED_CHANNELS; + *pos++ = 2 * sband->n_channels; + for (i = 0; i < sband->n_channels; i++) { + *pos++ = ieee80211_frequency_to_channel( + sband->channels[i].center_freq); + *pos++ = 1; /* one channel in the subband*/ + } + } + + if (wk->ie_len && wk->ie) { + pos = skb_put(skb, wk->ie_len); + memcpy(pos, wk->ie, wk->ie_len); + } + + if (wmm && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED)) { + pos = skb_put(skb, 9); + *pos++ = WLAN_EID_VENDOR_SPECIFIC; + *pos++ = 7; /* len */ + *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */ + *pos++ = 0x50; + *pos++ = 0xf2; + *pos++ = 2; /* WME */ + *pos++ = 0; /* WME info */ + *pos++ = 1; /* WME ver */ + *pos++ = 0; + } + + /* wmm support is a must to HT */ + /* + * IEEE802.11n does not allow TKIP/WEP as pairwise + * ciphers in HT mode. We still associate in non-ht + * mode (11a/b/g) if any one of these ciphers is + * configured as pairwise. + */ + if (wmm && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) && + sband->ht_cap.ht_supported && + (ht_ie = ieee80211_bss_get_ie(&wk->bss->cbss, WLAN_EID_HT_INFORMATION)) && + ht_ie[1] >= sizeof(struct ieee80211_ht_info) && + (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N))) { + struct ieee80211_ht_info *ht_info = + (struct ieee80211_ht_info *)(ht_ie + 2); + u16 cap = sband->ht_cap.cap; + __le16 tmp; + u32 flags = local->hw.conf.channel->flags; + + switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { + case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: + if (flags & IEEE80211_CHAN_NO_HT40PLUS) { + cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; + cap &= ~IEEE80211_HT_CAP_SGI_40; + } + break; + case IEEE80211_HT_PARAM_CHA_SEC_BELOW: + if (flags & IEEE80211_CHAN_NO_HT40MINUS) { + cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; + cap &= ~IEEE80211_HT_CAP_SGI_40; + } + break; + } + + tmp = cpu_to_le16(cap); + pos = skb_put(skb, sizeof(struct ieee80211_ht_cap)+2); + *pos++ = WLAN_EID_HT_CAPABILITY; + *pos++ = sizeof(struct ieee80211_ht_cap); + memset(pos, 0, sizeof(struct ieee80211_ht_cap)); + memcpy(pos, &tmp, sizeof(u16)); + pos += sizeof(u16); + /* TODO: needs a define here for << 2 */ + *pos++ = sband->ht_cap.ampdu_factor | + (sband->ht_cap.ampdu_density << 2); + memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); + } + + IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; + ieee80211_tx_skb(sdata, skb); +} + + static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, const u8 *bssid, u16 stype, u16 reason, void *cookie) @@ -212,7 +443,7 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt)); if (!skb) { printk(KERN_DEBUG "%s: failed to allocate buffer for " - "deauth/disassoc frame\n", sdata->name); + "deauth/disassoc frame\n", sdata->dev->name); return; } skb_reserve(skb, local->hw.extra_tx_headroom); @@ -220,7 +451,7 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); memset(mgmt, 0, 24); memcpy(mgmt->da, bssid, ETH_ALEN); - memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); + memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); memcpy(mgmt->bssid, bssid, ETH_ALEN); mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype); skb_put(skb, 2); @@ -245,15 +476,30 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, void ieee80211_send_pspoll(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata) { + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_pspoll *pspoll; struct sk_buff *skb; + u16 fc; - skb = ieee80211_pspoll_get(&local->hw, &sdata->vif); - if (!skb) + skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*pspoll)); + if (!skb) { + printk(KERN_DEBUG "%s: failed to allocate buffer for " + "pspoll frame\n", sdata->dev->name); return; + } + skb_reserve(skb, local->hw.extra_tx_headroom); + + pspoll = (struct ieee80211_pspoll *) skb_put(skb, sizeof(*pspoll)); + memset(pspoll, 0, sizeof(*pspoll)); + fc = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL | IEEE80211_FCTL_PM; + pspoll->frame_control = cpu_to_le16(fc); + pspoll->aid = cpu_to_le16(ifmgd->aid); + + /* aid in PS-Poll has its two MSBs each set to 1 */ + pspoll->aid |= cpu_to_le16(1 << 15 | 1 << 14); - pspoll = (struct ieee80211_pspoll *) skb->data; - pspoll->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); + memcpy(pspoll->bssid, ifmgd->bssid, ETH_ALEN); + memcpy(pspoll->ta, sdata->dev->dev_addr, ETH_ALEN); IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; ieee80211_tx_skb(sdata, skb); @@ -262,24 +508,6 @@ void ieee80211_send_pspoll(struct ieee80211_local *local, void ieee80211_send_nullfunc(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, int powersave) -{ - struct sk_buff *skb; - struct ieee80211_hdr_3addr *nullfunc; - - skb = ieee80211_nullfunc_get(&local->hw, &sdata->vif); - if (!skb) - return; - - nullfunc = (struct ieee80211_hdr_3addr *) skb->data; - if (powersave) - nullfunc->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); - - IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; - ieee80211_tx_skb(sdata, skb); -} - -static void ieee80211_send_4addr_nullfunc(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata) { struct sk_buff *skb; struct ieee80211_hdr *nullfunc; @@ -288,23 +516,24 @@ static void ieee80211_send_4addr_nullfunc(struct ieee80211_local *local, if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) return; - skb = dev_alloc_skb(local->hw.extra_tx_headroom + 30); + skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24); if (!skb) { - printk(KERN_DEBUG "%s: failed to allocate buffer for 4addr " - "nullfunc frame\n", sdata->name); + printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc " + "frame\n", sdata->dev->name); return; } skb_reserve(skb, local->hw.extra_tx_headroom); - nullfunc = (struct ieee80211_hdr *) skb_put(skb, 30); - memset(nullfunc, 0, 30); + nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24); + memset(nullfunc, 0, 24); fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | - IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); + IEEE80211_FCTL_TODS); + if (powersave) + fc |= cpu_to_le16(IEEE80211_FCTL_PM); nullfunc->frame_control = fc; memcpy(nullfunc->addr1, sdata->u.mgd.bssid, ETH_ALEN); - memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN); + memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN); memcpy(nullfunc->addr3, sdata->u.mgd.bssid, ETH_ALEN); - memcpy(nullfunc->addr4, sdata->vif.addr, ETH_ALEN); IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; ieee80211_tx_skb(sdata, skb); @@ -317,7 +546,7 @@ static void ieee80211_chswitch_work(struct work_struct *work) container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work); struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - if (!ieee80211_sdata_running(sdata)) + if (!netif_running(sdata->dev)) return; mutex_lock(&ifmgd->mtx); @@ -328,7 +557,7 @@ static void ieee80211_chswitch_work(struct work_struct *work) ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL); /* XXX: shouldn't really modify cfg80211-owned data! */ - ifmgd->associated->channel = sdata->local->oper_channel; + ifmgd->associated->cbss.channel = sdata->local->oper_channel; ieee80211_wake_queues_by_reason(&sdata->local->hw, IEEE80211_QUEUE_STOP_REASON_CSA); @@ -355,8 +584,6 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, struct ieee80211_channel_sw_ie *sw_elem, struct ieee80211_bss *bss) { - struct cfg80211_bss *cbss = - container_of((void *)bss, struct cfg80211_bss, priv); struct ieee80211_channel *new_ch; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num); @@ -390,7 +617,7 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, mod_timer(&ifmgd->chswitch_timer, jiffies + msecs_to_jiffies(sw_elem->count * - cbss->beacon_interval)); + bss->cbss.beacon_interval)); } } @@ -434,11 +661,8 @@ static void ieee80211_enable_ps(struct ieee80211_local *local, } else { if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) ieee80211_send_nullfunc(local, sdata, 1); - - if (!(local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)) { - conf->flags |= IEEE80211_CONF_PS; - ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); - } + conf->flags |= IEEE80211_CONF_PS; + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); } } @@ -467,13 +691,8 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) return; } - if (!list_empty(&local->work_list)) { - local->ps_sdata = NULL; - goto change; - } - list_for_each_entry(sdata, &local->interfaces, list) { - if (!ieee80211_sdata_running(sdata)) + if (!netif_running(sdata->dev)) continue; if (sdata->vif.type != NL80211_IFTYPE_STATION) continue; @@ -482,8 +701,7 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) } if (count == 1 && found->u.mgd.powersave && - found->u.mgd.associated && - found->u.mgd.associated->beacon_ies && + found->u.mgd.associated && list_empty(&found->u.mgd.work_list) && !(found->u.mgd.flags & (IEEE80211_STA_BEACON_POLL | IEEE80211_STA_CONNECTION_POLL))) { s32 beaconint_us; @@ -497,29 +715,20 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) if (beaconint_us > latency) { local->ps_sdata = NULL; } else { - struct ieee80211_bss *bss; + u8 dtimper = found->vif.bss_conf.dtim_period; int maxslp = 1; - u8 dtimper; - - bss = (void *)found->u.mgd.associated->priv; - dtimper = bss->dtim_period; - /* If the TIM IE is invalid, pretend the value is 1 */ - if (!dtimper) - dtimper = 1; - else if (dtimper > 1) + if (dtimper > 1) maxslp = min_t(int, dtimper, latency / beaconint_us); local->hw.conf.max_sleep_period = maxslp; - local->hw.conf.ps_dtim_period = dtimper; local->ps_sdata = found; } } else { local->ps_sdata = NULL; } - change: ieee80211_change_ps(local); } @@ -544,7 +753,6 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work) container_of(work, struct ieee80211_local, dynamic_ps_enable_work); struct ieee80211_sub_if_data *sdata = local->ps_sdata; - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; /* can only happen when PS was just disabled anyway */ if (!sdata) @@ -553,16 +761,11 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work) if (local->hw.conf.flags & IEEE80211_CONF_PS) return; - if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && - (!(ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED))) + if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) ieee80211_send_nullfunc(local, sdata, 1); - if (!(local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) || - (ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED)) { - ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED; - local->hw.conf.flags |= IEEE80211_CONF_PS; - ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); - } + local->hw.conf.flags |= IEEE80211_CONF_PS; + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); } void ieee80211_dynamic_ps_timer(unsigned long data) @@ -583,9 +786,9 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, struct ieee80211_tx_queue_params params; size_t left; int count; - u8 *pos, uapsd_queues = 0; + u8 *pos; - if (local->hw.queues < 4) + if (!(ifmgd->flags & IEEE80211_STA_WMM_ENABLED)) return; if (!wmm_param) @@ -593,10 +796,6 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1) return; - - if (ifmgd->flags & IEEE80211_STA_UAPSD_ENABLED) - uapsd_queues = local->uapsd_queues; - count = wmm_param[6] & 0x0f; if (count == ifmgd->wmm_last_param_set) return; @@ -611,7 +810,6 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, for (; left >= 4; left -= 4, pos += 4) { int aci = (pos[0] >> 5) & 0x03; int acm = (pos[0] >> 4) & 0x01; - bool uapsd = false; int queue; switch (aci) { @@ -619,30 +817,22 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, queue = 3; if (acm) local->wmm_acm |= BIT(1) | BIT(2); /* BK/- */ - if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK) - uapsd = true; break; case 2: /* AC_VI */ queue = 1; if (acm) local->wmm_acm |= BIT(4) | BIT(5); /* CL/VI */ - if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI) - uapsd = true; break; case 3: /* AC_VO */ queue = 0; if (acm) local->wmm_acm |= BIT(6) | BIT(7); /* VO/NC */ - if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) - uapsd = true; break; case 0: /* AC_BE */ default: queue = 2; if (acm) local->wmm_acm |= BIT(0) | BIT(3); /* BE/EE */ - if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) - uapsd = true; break; } @@ -650,14 +840,11 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4); params.cw_min = ecw2cw(pos[1] & 0x0f); params.txop = get_unaligned_le16(pos + 2); - params.uapsd = uapsd; - #ifdef CONFIG_MAC80211_VERBOSE_DEBUG printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d " - "cWmin=%d cWmax=%d txop=%d uapsd=%d\n", + "cWmin=%d cWmax=%d txop=%d\n", wiphy_name(local->hw.wiphy), queue, aci, acm, - params.aifs, params.cw_min, params.cw_max, params.txop, - params.uapsd); + params.aifs, params.cw_min, params.cw_max, params.txop); #endif if (drv_conf_tx(local, queue, ¶ms) && local->ops->conf_tx) printk(KERN_DEBUG "%s: failed to set TX queue " @@ -684,8 +871,6 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, } use_short_slot = !!(capab & WLAN_CAPABILITY_SHORT_SLOT_TIME); - if (sdata->local->hw.conf.channel->band == IEEE80211_BAND_5GHZ) - use_short_slot = true; if (use_protection != bss_conf->use_cts_prot) { bss_conf->use_cts_prot = use_protection; @@ -706,23 +891,25 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, } static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, - struct cfg80211_bss *cbss, + struct ieee80211_mgd_work *wk, u32 bss_info_changed) { - struct ieee80211_bss *bss = (void *)cbss->priv; struct ieee80211_local *local = sdata->local; + struct ieee80211_bss *bss = wk->bss; bss_info_changed |= BSS_CHANGED_ASSOC; /* set timing information */ - sdata->vif.bss_conf.beacon_int = cbss->beacon_interval; - sdata->vif.bss_conf.timestamp = cbss->tsf; + sdata->vif.bss_conf.beacon_int = bss->cbss.beacon_interval; + sdata->vif.bss_conf.timestamp = bss->cbss.tsf; + sdata->vif.bss_conf.dtim_period = bss->dtim_period; bss_info_changed |= BSS_CHANGED_BEACON_INT; bss_info_changed |= ieee80211_handle_bss_capability(sdata, - cbss->capability, bss->has_erp_value, bss->erp_value); + bss->cbss.capability, bss->has_erp_value, bss->erp_value); - sdata->u.mgd.associated = cbss; - memcpy(sdata->u.mgd.bssid, cbss->bssid, ETH_ALEN); + sdata->u.mgd.associated = bss; + sdata->u.mgd.old_associate_work = wk; + memcpy(sdata->u.mgd.bssid, bss->cbss.bssid, ETH_ALEN); /* just to be sure */ sdata->u.mgd.flags &= ~(IEEE80211_STA_CONNECTION_POLL | @@ -753,14 +940,99 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, mutex_lock(&local->iflist_mtx); ieee80211_recalc_ps(local, -1); - ieee80211_recalc_smps(local, sdata); mutex_unlock(&local->iflist_mtx); netif_tx_start_all_queues(sdata->dev); netif_carrier_on(sdata->dev); } -static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata) +static enum rx_mgmt_action __must_check +ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgd_work *wk) +{ + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + struct ieee80211_local *local = sdata->local; + + wk->tries++; + if (wk->tries > IEEE80211_AUTH_MAX_TRIES) { + printk(KERN_DEBUG "%s: direct probe to AP %pM timed out\n", + sdata->dev->name, wk->bss->cbss.bssid); + + /* + * Most likely AP is not in the range so remove the + * bss struct for that AP. + */ + cfg80211_unlink_bss(local->hw.wiphy, &wk->bss->cbss); + + /* + * We might have a pending scan which had no chance to run yet + * due to work needing to be done. Hence, queue the STAs work + * again for that. + */ + ieee80211_queue_work(&local->hw, &ifmgd->work); + return RX_MGMT_CFG80211_AUTH_TO; + } + + printk(KERN_DEBUG "%s: direct probe to AP %pM (try %d)\n", + sdata->dev->name, wk->bss->cbss.bssid, + wk->tries); + + /* + * Direct probe is sent to broadcast address as some APs + * will not answer to direct packet in unassociated state. + */ + ieee80211_send_probe_req(sdata, NULL, wk->ssid, wk->ssid_len, NULL, 0); + + wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; + run_again(ifmgd, wk->timeout); + + return RX_MGMT_NONE; +} + + +static enum rx_mgmt_action __must_check +ieee80211_authenticate(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgd_work *wk) +{ + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + struct ieee80211_local *local = sdata->local; + + wk->tries++; + if (wk->tries > IEEE80211_AUTH_MAX_TRIES) { + printk(KERN_DEBUG "%s: authentication with AP %pM" + " timed out\n", + sdata->dev->name, wk->bss->cbss.bssid); + + /* + * Most likely AP is not in the range so remove the + * bss struct for that AP. + */ + cfg80211_unlink_bss(local->hw.wiphy, &wk->bss->cbss); + + /* + * We might have a pending scan which had no chance to run yet + * due to work needing to be done. Hence, queue the STAs work + * again for that. + */ + ieee80211_queue_work(&local->hw, &ifmgd->work); + return RX_MGMT_CFG80211_AUTH_TO; + } + + printk(KERN_DEBUG "%s: authenticate with AP %pM (try %d)\n", + sdata->dev->name, wk->bss->cbss.bssid, wk->tries); + + ieee80211_send_auth(sdata, 1, wk->auth_alg, wk->ie, wk->ie_len, + wk->bss->cbss.bssid, NULL, 0, 0); + wk->auth_transaction = 2; + + wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; + run_again(ifmgd, wk->timeout); + + return RX_MGMT_NONE; +} + +static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, + bool deauth) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; @@ -773,11 +1045,21 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata) if (WARN_ON(!ifmgd->associated)) return; - memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN); + memcpy(bssid, ifmgd->associated->cbss.bssid, ETH_ALEN); ifmgd->associated = NULL; memset(ifmgd->bssid, 0, ETH_ALEN); + if (deauth) { + kfree(ifmgd->old_associate_work); + ifmgd->old_associate_work = NULL; + } else { + struct ieee80211_mgd_work *wk = ifmgd->old_associate_work; + + wk->state = IEEE80211_MGD_STATE_IDLE; + list_add(&wk->list, &ifmgd->work_list); + } + /* * we need to commit the associated = NULL change because the * scan code uses that to determine whether this iface should @@ -796,11 +1078,9 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata) netif_carrier_off(sdata->dev); rcu_read_lock(); - sta = sta_info_get(sdata, bssid); - if (sta) { - set_sta_flags(sta, WLAN_STA_DISASSOC); + sta = sta_info_get(local, bssid); + if (sta) ieee80211_sta_tear_down_BA_sessions(sta); - } rcu_read_unlock(); changed |= ieee80211_reset_erp_info(sdata); @@ -833,7 +1113,57 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata) changed |= BSS_CHANGED_BSSID; ieee80211_bss_info_change_notify(sdata, changed); - sta_info_destroy_addr(sdata, bssid); + rcu_read_lock(); + + sta = sta_info_get(local, bssid); + if (!sta) { + rcu_read_unlock(); + return; + } + + sta_info_unlink(&sta); + + rcu_read_unlock(); + + sta_info_destroy(sta); +} + +static enum rx_mgmt_action __must_check +ieee80211_associate(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgd_work *wk) +{ + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + struct ieee80211_local *local = sdata->local; + + wk->tries++; + if (wk->tries > IEEE80211_ASSOC_MAX_TRIES) { + printk(KERN_DEBUG "%s: association with AP %pM" + " timed out\n", + sdata->dev->name, wk->bss->cbss.bssid); + + /* + * Most likely AP is not in the range so remove the + * bss struct for that AP. + */ + cfg80211_unlink_bss(local->hw.wiphy, &wk->bss->cbss); + + /* + * We might have a pending scan which had no chance to run yet + * due to work needing to be done. Hence, queue the STAs work + * again for that. + */ + ieee80211_queue_work(&local->hw, &ifmgd->work); + return RX_MGMT_CFG80211_ASSOC_TO; + } + + printk(KERN_DEBUG "%s: associate with AP %pM (try %d)\n", + sdata->dev->name, wk->bss->cbss.bssid, wk->tries); + ieee80211_send_assoc(sdata, wk); + + wk->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT; + run_again(ifmgd, wk->timeout); + + return RX_MGMT_NONE; } void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, @@ -859,8 +1189,8 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; const u8 *ssid; - ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); - ieee80211_send_probe_req(sdata, ifmgd->associated->bssid, + ssid = ieee80211_bss_get_ie(&ifmgd->associated->cbss, WLAN_EID_SSID); + ieee80211_send_probe_req(sdata, ifmgd->associated->cbss.bssid, ssid + 2, ssid[1], NULL, 0); ifmgd->probe_send_count++; @@ -874,15 +1204,12 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; bool already = false; - if (!ieee80211_sdata_running(sdata)) + if (!netif_running(sdata->dev)) return; if (sdata->local->scanning) return; - if (sdata->local->tmp_channel) - return; - mutex_lock(&ifmgd->mtx); if (!ifmgd->associated) @@ -891,7 +1218,7 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, #ifdef CONFIG_MAC80211_VERBOSE_DEBUG if (beacon && net_ratelimit()) printk(KERN_DEBUG "%s: detected beacon loss from AP " - "- sending probe request\n", sdata->name); + "- sending probe request\n", sdata->dev->name); #endif /* @@ -944,8 +1271,88 @@ void ieee80211_beacon_loss(struct ieee80211_vif *vif) } EXPORT_SYMBOL(ieee80211_beacon_loss); +static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgd_work *wk) +{ + wk->state = IEEE80211_MGD_STATE_IDLE; + printk(KERN_DEBUG "%s: authenticated\n", sdata->dev->name); +} + + +static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgd_work *wk, + struct ieee80211_mgmt *mgmt, + size_t len) +{ + u8 *pos; + struct ieee802_11_elems elems; + + pos = mgmt->u.auth.variable; + ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); + if (!elems.challenge) + return; + ieee80211_send_auth(sdata, 3, wk->auth_alg, + elems.challenge - 2, elems.challenge_len + 2, + wk->bss->cbss.bssid, + wk->key, wk->key_len, wk->key_idx); + wk->auth_transaction = 4; +} + +static enum rx_mgmt_action __must_check +ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgd_work *wk, + struct ieee80211_mgmt *mgmt, size_t len) +{ + u16 auth_alg, auth_transaction, status_code; + + if (wk->state != IEEE80211_MGD_STATE_AUTH) + return RX_MGMT_NONE; + + if (len < 24 + 6) + return RX_MGMT_NONE; + + if (memcmp(wk->bss->cbss.bssid, mgmt->sa, ETH_ALEN) != 0) + return RX_MGMT_NONE; + + if (memcmp(wk->bss->cbss.bssid, mgmt->bssid, ETH_ALEN) != 0) + return RX_MGMT_NONE; + + auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); + auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); + status_code = le16_to_cpu(mgmt->u.auth.status_code); + + if (auth_alg != wk->auth_alg || + auth_transaction != wk->auth_transaction) + return RX_MGMT_NONE; + + if (status_code != WLAN_STATUS_SUCCESS) { + list_del(&wk->list); + kfree(wk); + return RX_MGMT_CFG80211_AUTH; + } + + switch (wk->auth_alg) { + case WLAN_AUTH_OPEN: + case WLAN_AUTH_LEAP: + case WLAN_AUTH_FT: + ieee80211_auth_completed(sdata, wk); + return RX_MGMT_CFG80211_AUTH; + case WLAN_AUTH_SHARED_KEY: + if (wk->auth_transaction == 4) { + ieee80211_auth_completed(sdata, wk); + return RX_MGMT_CFG80211_AUTH; + } else + ieee80211_auth_challenge(sdata, wk, mgmt, len); + break; + } + + return RX_MGMT_NONE; +} + + static enum rx_mgmt_action __must_check ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgd_work *wk, struct ieee80211_mgmt *mgmt, size_t len) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; @@ -957,15 +1364,23 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, ASSERT_MGD_MTX(ifmgd); - bssid = ifmgd->associated->bssid; + if (wk) + bssid = wk->bss->cbss.bssid; + else + bssid = ifmgd->associated->cbss.bssid; reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); printk(KERN_DEBUG "%s: deauthenticated from %pM (Reason: %u)\n", - sdata->name, bssid, reason_code); + sdata->dev->name, bssid, reason_code); - ieee80211_set_disassoc(sdata); - ieee80211_recalc_idle(sdata->local); + if (!wk) { + ieee80211_set_disassoc(sdata, true); + ieee80211_recalc_idle(sdata->local); + } else { + list_del(&wk->list); + kfree(wk); + } return RX_MGMT_CFG80211_DEAUTH; } @@ -986,71 +1401,122 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, if (WARN_ON(!ifmgd->associated)) return RX_MGMT_NONE; - if (WARN_ON(memcmp(ifmgd->associated->bssid, mgmt->sa, ETH_ALEN))) + if (WARN_ON(memcmp(ifmgd->associated->cbss.bssid, mgmt->sa, ETH_ALEN))) return RX_MGMT_NONE; reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); printk(KERN_DEBUG "%s: disassociated from %pM (Reason: %u)\n", - sdata->name, mgmt->sa, reason_code); + sdata->dev->name, mgmt->sa, reason_code); - ieee80211_set_disassoc(sdata); + ieee80211_set_disassoc(sdata, false); ieee80211_recalc_idle(sdata->local); return RX_MGMT_CFG80211_DISASSOC; } -static bool ieee80211_assoc_success(struct ieee80211_work *wk, - struct ieee80211_mgmt *mgmt, size_t len) +static enum rx_mgmt_action __must_check +ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgd_work *wk, + struct ieee80211_mgmt *mgmt, size_t len, + bool reassoc) { - struct ieee80211_sub_if_data *sdata = wk->sdata; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; struct ieee80211_supported_band *sband; struct sta_info *sta; - struct cfg80211_bss *cbss = wk->assoc.bss; - u8 *pos; u32 rates, basic_rates; - u16 capab_info, aid; + u16 capab_info, status_code, aid; struct ieee802_11_elems elems; struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; + u8 *pos; u32 changed = 0; - int i, j, err; - bool have_higher_than_11mbit = false; + int i, j; + bool have_higher_than_11mbit = false, newsta = false; u16 ap_ht_cap_flags; - /* AssocResp and ReassocResp have identical structure */ + /* + * AssocResp and ReassocResp have identical structure, so process both + * of them in this function. + */ + + if (len < 24 + 6) + return RX_MGMT_NONE; + + if (memcmp(wk->bss->cbss.bssid, mgmt->sa, ETH_ALEN) != 0) + return RX_MGMT_NONE; - aid = le16_to_cpu(mgmt->u.assoc_resp.aid); capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); + status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); + aid = le16_to_cpu(mgmt->u.assoc_resp.aid); - if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) - printk(KERN_DEBUG "%s: invalid aid value %d; bits 15:14 not " - "set\n", sdata->name, aid); - aid &= ~(BIT(15) | BIT(14)); + printk(KERN_DEBUG "%s: RX %sssocResp from %pM (capab=0x%x " + "status=%d aid=%d)\n", + sdata->dev->name, reassoc ? "Rea" : "A", mgmt->sa, + capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14)))); pos = mgmt->u.assoc_resp.variable; ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); + if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY && + elems.timeout_int && elems.timeout_int_len == 5 && + elems.timeout_int[0] == WLAN_TIMEOUT_ASSOC_COMEBACK) { + u32 tu, ms; + tu = get_unaligned_le32(elems.timeout_int + 1); + ms = tu * 1024 / 1000; + printk(KERN_DEBUG "%s: AP rejected association temporarily; " + "comeback duration %u TU (%u ms)\n", + sdata->dev->name, tu, ms); + wk->timeout = jiffies + msecs_to_jiffies(ms); + if (ms > IEEE80211_ASSOC_TIMEOUT) + run_again(ifmgd, jiffies + msecs_to_jiffies(ms)); + return RX_MGMT_NONE; + } + + if (status_code != WLAN_STATUS_SUCCESS) { + printk(KERN_DEBUG "%s: AP denied association (code=%d)\n", + sdata->dev->name, status_code); + wk->state = IEEE80211_MGD_STATE_IDLE; + return RX_MGMT_CFG80211_ASSOC; + } + + if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) + printk(KERN_DEBUG "%s: invalid aid value %d; bits 15:14 not " + "set\n", sdata->dev->name, aid); + aid &= ~(BIT(15) | BIT(14)); + if (!elems.supp_rates) { printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n", - sdata->name); - return false; + sdata->dev->name); + return RX_MGMT_NONE; } + printk(KERN_DEBUG "%s: associated\n", sdata->dev->name); ifmgd->aid = aid; - sta = sta_info_alloc(sdata, cbss->bssid, GFP_KERNEL); + rcu_read_lock(); + + /* Add STA entry for the AP */ + sta = sta_info_get(local, wk->bss->cbss.bssid); if (!sta) { - printk(KERN_DEBUG "%s: failed to alloc STA entry for" - " the AP\n", sdata->name); - return false; - } + newsta = true; + + rcu_read_unlock(); + + sta = sta_info_alloc(sdata, wk->bss->cbss.bssid, GFP_KERNEL); + if (!sta) { + printk(KERN_DEBUG "%s: failed to alloc STA entry for" + " the AP\n", sdata->dev->name); + return RX_MGMT_NONE; + } - set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC | - WLAN_STA_ASSOC_AP); - if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) - set_sta_flags(sta, WLAN_STA_AUTHORIZED); + set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC | + WLAN_STA_ASSOC_AP); + if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) + set_sta_flags(sta, WLAN_STA_AUTHORIZED); + + rcu_read_lock(); + } rates = 0; basic_rates = 0; @@ -1114,40 +1580,40 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, if (elems.wmm_param) set_sta_flags(sta, WLAN_STA_WME); - err = sta_info_insert(sta); - sta = NULL; - if (err) { - printk(KERN_DEBUG "%s: failed to insert STA entry for" - " the AP (error %d)\n", sdata->name, err); - return false; + if (newsta) { + int err = sta_info_insert(sta); + if (err) { + printk(KERN_DEBUG "%s: failed to insert STA entry for" + " the AP (error %d)\n", sdata->dev->name, err); + rcu_read_unlock(); + return RX_MGMT_NONE; + } } + rcu_read_unlock(); + if (elems.wmm_param) ieee80211_sta_wmm_params(local, ifmgd, elems.wmm_param, elems.wmm_param_len); else ieee80211_set_wmm_default(sdata); - local->oper_channel = wk->chan; - if (elems.ht_info_elem && elems.wmm_param && - (sdata->local->hw.queues >= 4) && + (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) && !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem, - cbss->bssid, ap_ht_cap_flags); + wk->bss->cbss.bssid, + ap_ht_cap_flags); + + /* delete work item -- must be before set_associated for PS */ + list_del(&wk->list); /* set AID and assoc capability, * ieee80211_set_associated() will tell the driver */ bss_conf->aid = aid; bss_conf->assoc_capability = capab_info; - ieee80211_set_associated(sdata, cbss, changed); - - /* - * If we're using 4-addr mode, let the AP know that we're - * doing so, so that it can create the STA VLAN on its side - */ - if (ifmgd->use_4addr) - ieee80211_send_4addr_nullfunc(local, sdata); + /* this will take ownership of wk */ + ieee80211_set_associated(sdata, wk, changed); /* * Start timer to probe the connection to the AP now. @@ -1156,7 +1622,7 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt); mod_beacon_timer(sdata); - return true; + return RX_MGMT_CFG80211_ASSOC; } @@ -1171,13 +1637,6 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, int freq; struct ieee80211_bss *bss; struct ieee80211_channel *channel; - bool need_ps = false; - - if (sdata->u.mgd.associated) { - bss = (void *)sdata->u.mgd.associated->priv; - /* not previously set so we may need to recalc */ - need_ps = !bss->dtim_period; - } if (elems->ds_params && elems->ds_params_len == 1) freq = ieee80211_channel_to_frequency(elems->ds_params[0]); @@ -1197,14 +1656,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, if (!sdata->u.mgd.associated) return; - if (need_ps) { - mutex_lock(&local->iflist_mtx); - ieee80211_recalc_ps(local, -1); - mutex_unlock(&local->iflist_mtx); - } - if (elems->ch_switch_elem && (elems->ch_switch_elem_len == 3) && - (memcmp(mgmt->bssid, sdata->u.mgd.associated->bssid, + (memcmp(mgmt->bssid, sdata->u.mgd.associated->cbss.bssid, ETH_ALEN) == 0)) { struct ieee80211_channel_sw_ie *sw_elem = (struct ieee80211_channel_sw_ie *)elems->ch_switch_elem; @@ -1214,19 +1667,19 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb) + struct ieee80211_mgd_work *wk, + struct ieee80211_mgmt *mgmt, size_t len, + struct ieee80211_rx_status *rx_status) { - struct ieee80211_mgmt *mgmt = (void *)skb->data; struct ieee80211_if_managed *ifmgd; - struct ieee80211_rx_status *rx_status = (void *) skb->cb; - size_t baselen, len = skb->len; + size_t baselen; struct ieee802_11_elems elems; ifmgd = &sdata->u.mgd; ASSERT_MGD_MTX(ifmgd); - if (memcmp(mgmt->da, sdata->vif.addr, ETH_ALEN)) + if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN)) return; /* ignore ProbeResp to foreign address */ baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt; @@ -1238,8 +1691,17 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false); + /* direct probe may be part of the association flow */ + if (wk && wk->state == IEEE80211_MGD_STATE_PROBE) { + printk(KERN_DEBUG "%s: direct probe responded\n", + sdata->dev->name); + wk->tries = 0; + wk->state = IEEE80211_MGD_STATE_AUTH; + WARN_ON(ieee80211_authenticate(sdata, wk) != RX_MGMT_NONE); + } + if (ifmgd->associated && - memcmp(mgmt->bssid, ifmgd->associated->bssid, ETH_ALEN) == 0 && + memcmp(mgmt->bssid, ifmgd->associated->cbss.bssid, ETH_ALEN) == 0 && ifmgd->flags & (IEEE80211_STA_BEACON_POLL | IEEE80211_STA_CONNECTION_POLL)) { ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL | @@ -1312,7 +1774,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, if (!ifmgd->associated) return; - bssid = ifmgd->associated->bssid; + bssid = ifmgd->associated->cbss.bssid; /* * And in theory even frames from a different AP we were just @@ -1325,7 +1787,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, #ifdef CONFIG_MAC80211_VERBOSE_DEBUG if (net_ratelimit()) { printk(KERN_DEBUG "%s: cancelling probereq poll due " - "to a received beacon\n", sdata->name); + "to a received beacon\n", sdata->dev->name); } #endif ifmgd->flags &= ~IEEE80211_STA_BEACON_POLL; @@ -1403,7 +1865,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, rcu_read_lock(); - sta = sta_info_get(sdata, bssid); + sta = sta_info_get(local, bssid); if (WARN_ON(!sta)) { rcu_read_unlock(); return; @@ -1451,6 +1913,9 @@ ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, switch (fc & IEEE80211_FCTL_STYPE) { case IEEE80211_STYPE_PROBE_RESP: case IEEE80211_STYPE_BEACON: + case IEEE80211_STYPE_AUTH: + case IEEE80211_STYPE_ASSOC_RESP: + case IEEE80211_STYPE_REASSOC_RESP: case IEEE80211_STYPE_DEAUTH: case IEEE80211_STYPE_DISASSOC: case IEEE80211_STYPE_ACTION: @@ -1468,6 +1933,7 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_rx_status *rx_status; struct ieee80211_mgmt *mgmt; + struct ieee80211_mgd_work *wk; enum rx_mgmt_action rma = RX_MGMT_NONE; u16 fc; @@ -1478,17 +1944,20 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, mutex_lock(&ifmgd->mtx); if (ifmgd->associated && - memcmp(ifmgd->associated->bssid, mgmt->bssid, ETH_ALEN) == 0) { + memcmp(ifmgd->associated->cbss.bssid, mgmt->bssid, + ETH_ALEN) == 0) { switch (fc & IEEE80211_FCTL_STYPE) { case IEEE80211_STYPE_BEACON: ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, rx_status); break; case IEEE80211_STYPE_PROBE_RESP: - ieee80211_rx_mgmt_probe_resp(sdata, skb); + ieee80211_rx_mgmt_probe_resp(sdata, NULL, mgmt, + skb->len, rx_status); break; case IEEE80211_STYPE_DEAUTH: - rma = ieee80211_rx_mgmt_deauth(sdata, mgmt, skb->len); + rma = ieee80211_rx_mgmt_deauth(sdata, NULL, + mgmt, skb->len); break; case IEEE80211_STYPE_DISASSOC: rma = ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len); @@ -1499,7 +1968,7 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, ieee80211_sta_process_chanswitch(sdata, &mgmt->u.action.u.chan_switch.sw_elem, - (void *)ifmgd->associated->priv); + ifmgd->associated); break; } mutex_unlock(&ifmgd->mtx); @@ -1520,11 +1989,58 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, goto out; } + list_for_each_entry(wk, &ifmgd->work_list, list) { + if (memcmp(wk->bss->cbss.bssid, mgmt->bssid, ETH_ALEN) != 0) + continue; + + switch (fc & IEEE80211_FCTL_STYPE) { + case IEEE80211_STYPE_PROBE_RESP: + ieee80211_rx_mgmt_probe_resp(sdata, wk, mgmt, skb->len, + rx_status); + break; + case IEEE80211_STYPE_AUTH: + rma = ieee80211_rx_mgmt_auth(sdata, wk, mgmt, skb->len); + break; + case IEEE80211_STYPE_ASSOC_RESP: + rma = ieee80211_rx_mgmt_assoc_resp(sdata, wk, mgmt, + skb->len, false); + break; + case IEEE80211_STYPE_REASSOC_RESP: + rma = ieee80211_rx_mgmt_assoc_resp(sdata, wk, mgmt, + skb->len, true); + break; + case IEEE80211_STYPE_DEAUTH: + rma = ieee80211_rx_mgmt_deauth(sdata, wk, mgmt, + skb->len); + break; + } + /* + * We've processed this frame for that work, so it can't + * belong to another work struct. + * NB: this is also required for correctness because the + * called functions can free 'wk', and for 'rma'! + */ + break; + } + mutex_unlock(&ifmgd->mtx); - if (skb->len >= 24 + 2 /* mgmt + deauth reason */ && - (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_DEAUTH) + switch (rma) { + case RX_MGMT_NONE: + /* no action */ + break; + case RX_MGMT_CFG80211_AUTH: + cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, skb->len); + break; + case RX_MGMT_CFG80211_ASSOC: + cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, skb->len); + break; + case RX_MGMT_CFG80211_DEAUTH: cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); + break; + default: + WARN(1, "unexpected: %d", rma); + } out: kfree_skb(skb); @@ -1552,8 +2068,12 @@ static void ieee80211_sta_work(struct work_struct *work) struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd; struct sk_buff *skb; + struct ieee80211_mgd_work *wk, *tmp; + LIST_HEAD(free_work); + enum rx_mgmt_action rma; + bool anybusy = false; - if (!ieee80211_sdata_running(sdata)) + if (!netif_running(sdata->dev)) return; if (local->scanning) @@ -1584,7 +2104,7 @@ static void ieee80211_sta_work(struct work_struct *work) ifmgd->associated) { u8 bssid[ETH_ALEN]; - memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN); + memcpy(bssid, ifmgd->associated->cbss.bssid, ETH_ALEN); if (time_is_after_jiffies(ifmgd->probe_timeout)) run_again(ifmgd, ifmgd->probe_timeout); @@ -1606,7 +2126,7 @@ static void ieee80211_sta_work(struct work_struct *work) printk(KERN_DEBUG "No probe response from AP %pM" " after %dms, disconnecting.\n", bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); - ieee80211_set_disassoc(sdata); + ieee80211_set_disassoc(sdata, true); ieee80211_recalc_idle(local); mutex_unlock(&ifmgd->mtx); /* @@ -1621,7 +2141,87 @@ static void ieee80211_sta_work(struct work_struct *work) } } + + ieee80211_recalc_idle(local); + + list_for_each_entry_safe(wk, tmp, &ifmgd->work_list, list) { + if (time_is_after_jiffies(wk->timeout)) { + /* + * This work item isn't supposed to be worked on + * right now, but take care to adjust the timer + * properly. + */ + run_again(ifmgd, wk->timeout); + continue; + } + + switch (wk->state) { + default: + WARN_ON(1); + /* fall through */ + case IEEE80211_MGD_STATE_IDLE: + /* nothing */ + rma = RX_MGMT_NONE; + break; + case IEEE80211_MGD_STATE_PROBE: + rma = ieee80211_direct_probe(sdata, wk); + break; + case IEEE80211_MGD_STATE_AUTH: + rma = ieee80211_authenticate(sdata, wk); + break; + case IEEE80211_MGD_STATE_ASSOC: + rma = ieee80211_associate(sdata, wk); + break; + } + + switch (rma) { + case RX_MGMT_NONE: + /* no action required */ + break; + case RX_MGMT_CFG80211_AUTH_TO: + case RX_MGMT_CFG80211_ASSOC_TO: + list_del(&wk->list); + list_add(&wk->list, &free_work); + wk->tries = rma; /* small abuse but only local */ + break; + default: + WARN(1, "unexpected: %d", rma); + } + } + + list_for_each_entry(wk, &ifmgd->work_list, list) { + if (wk->state != IEEE80211_MGD_STATE_IDLE) { + anybusy = true; + break; + } + } + if (!anybusy && + test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request)) + ieee80211_queue_delayed_work(&local->hw, + &local->scan_work, + round_jiffies_relative(0)); + mutex_unlock(&ifmgd->mtx); + + list_for_each_entry_safe(wk, tmp, &free_work, list) { + switch (wk->tries) { + case RX_MGMT_CFG80211_AUTH_TO: + cfg80211_send_auth_timeout(sdata->dev, + wk->bss->cbss.bssid); + break; + case RX_MGMT_CFG80211_ASSOC_TO: + cfg80211_send_assoc_timeout(sdata->dev, + wk->bss->cbss.bssid); + break; + default: + WARN(1, "unexpected: %d", wk->tries); + } + + list_del(&wk->list); + kfree(wk); + } + + ieee80211_recalc_idle(local); } static void ieee80211_sta_bcn_mon_timer(unsigned long data) @@ -1730,14 +2330,14 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) (unsigned long) sdata); skb_queue_head_init(&ifmgd->skb_queue); + INIT_LIST_HEAD(&ifmgd->work_list); + + ifmgd->capab = WLAN_CAPABILITY_ESS; ifmgd->flags = 0; + if (sdata->local->hw.queues >= 4) + ifmgd->flags |= IEEE80211_STA_WMM_ENABLED; mutex_init(&ifmgd->mtx); - - if (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS) - ifmgd->req_smps = IEEE80211_SMPS_AUTOMATIC; - else - ifmgd->req_smps = IEEE80211_SMPS_OFF; } /* scan finished notification */ @@ -1768,34 +2368,12 @@ int ieee80211_max_network_latency(struct notifier_block *nb, } /* config hooks */ -static enum work_done_result -ieee80211_probe_auth_done(struct ieee80211_work *wk, - struct sk_buff *skb) -{ - if (!skb) { - cfg80211_send_auth_timeout(wk->sdata->dev, wk->filter_ta); - return WORK_DONE_DESTROY; - } - - if (wk->type == IEEE80211_WORK_AUTH) { - cfg80211_send_rx_auth(wk->sdata->dev, skb->data, skb->len); - return WORK_DONE_DESTROY; - } - - mutex_lock(&wk->sdata->u.mgd.mtx); - ieee80211_rx_mgmt_probe_resp(wk->sdata, skb); - mutex_unlock(&wk->sdata->u.mgd.mtx); - - wk->type = IEEE80211_WORK_AUTH; - wk->probe_auth.tries = 0; - return WORK_DONE_REQUEUE; -} - int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, struct cfg80211_auth_request *req) { + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; const u8 *ssid; - struct ieee80211_work *wk; + struct ieee80211_mgd_work *wk; u16 auth_alg; switch (req->auth_type) { @@ -1819,7 +2397,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, if (!wk) return -ENOMEM; - memcpy(wk->filter_ta, req->bss->bssid, ETH_ALEN); + wk->bss = (void *)req->bss; if (req->ie && req->ie_len) { memcpy(wk->ie, req->ie, req->ie_len); @@ -1827,83 +2405,68 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, } if (req->key && req->key_len) { - wk->probe_auth.key_len = req->key_len; - wk->probe_auth.key_idx = req->key_idx; - memcpy(wk->probe_auth.key, req->key, req->key_len); + wk->key_len = req->key_len; + wk->key_idx = req->key_idx; + memcpy(wk->key, req->key, req->key_len); } ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); - memcpy(wk->probe_auth.ssid, ssid + 2, ssid[1]); - wk->probe_auth.ssid_len = ssid[1]; + memcpy(wk->ssid, ssid + 2, ssid[1]); + wk->ssid_len = ssid[1]; - wk->probe_auth.algorithm = auth_alg; - wk->probe_auth.privacy = req->bss->capability & WLAN_CAPABILITY_PRIVACY; + wk->state = IEEE80211_MGD_STATE_PROBE; + wk->auth_alg = auth_alg; + wk->timeout = jiffies; /* run right away */ - /* if we already have a probe, don't probe again */ - if (req->bss->proberesp_ies) - wk->type = IEEE80211_WORK_AUTH; - else - wk->type = IEEE80211_WORK_DIRECT_PROBE; - wk->chan = req->bss->channel; - wk->sdata = sdata; - wk->done = ieee80211_probe_auth_done; + /* + * XXX: if still associated need to tell AP that we're going + * to sleep and then change channel etc. + */ + sdata->local->oper_channel = req->bss->channel; + ieee80211_hw_config(sdata->local, 0); + + mutex_lock(&ifmgd->mtx); + list_add(&wk->list, &sdata->u.mgd.work_list); + mutex_unlock(&ifmgd->mtx); - ieee80211_add_work(wk); + ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.work); return 0; } -static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk, - struct sk_buff *skb) +int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, + struct cfg80211_assoc_request *req) { - struct ieee80211_mgmt *mgmt; - u16 status; - - if (!skb) { - cfg80211_send_assoc_timeout(wk->sdata->dev, wk->filter_ta); - return WORK_DONE_DESTROY; - } + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + struct ieee80211_mgd_work *wk, *found = NULL; + int i, err; - mgmt = (void *)skb->data; - status = le16_to_cpu(mgmt->u.assoc_resp.status_code); + mutex_lock(&ifmgd->mtx); - if (status == WLAN_STATUS_SUCCESS) { - mutex_lock(&wk->sdata->u.mgd.mtx); - if (!ieee80211_assoc_success(wk, mgmt, skb->len)) { - mutex_unlock(&wk->sdata->u.mgd.mtx); - /* oops -- internal error -- send timeout for now */ - cfg80211_send_assoc_timeout(wk->sdata->dev, - wk->filter_ta); - return WORK_DONE_DESTROY; + list_for_each_entry(wk, &ifmgd->work_list, list) { + if (&wk->bss->cbss == req->bss && + wk->state == IEEE80211_MGD_STATE_IDLE) { + found = wk; + break; } - mutex_unlock(&wk->sdata->u.mgd.mtx); } - cfg80211_send_rx_assoc(wk->sdata->dev, skb->data, skb->len); - return WORK_DONE_DESTROY; -} + if (!found) { + err = -ENOLINK; + goto out; + } -int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, - struct cfg80211_assoc_request *req) -{ - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - struct ieee80211_bss *bss = (void *)req->bss->priv; - struct ieee80211_work *wk; - const u8 *ssid; - int i; + list_del(&found->list); - mutex_lock(&ifmgd->mtx); - if (ifmgd->associated) { - mutex_unlock(&ifmgd->mtx); - return -EALREADY; + wk = krealloc(found, sizeof(*wk) + req->ie_len, GFP_KERNEL); + if (!wk) { + list_add(&found->list, &ifmgd->work_list); + err = -ENOMEM; + goto out; } - mutex_unlock(&ifmgd->mtx); - wk = kzalloc(sizeof(*wk) + req->ie_len, GFP_KERNEL); - if (!wk) - return -ENOMEM; + list_add(&wk->list, &ifmgd->work_list); ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N; - ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED; for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 || @@ -1911,6 +2474,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) ifmgd->flags |= IEEE80211_STA_DISABLE_11N; + sdata->local->oper_channel = req->bss->channel; + ieee80211_hw_config(sdata->local, 0); if (req->ie && req->ie_len) { memcpy(wk->ie, req->ie, req->ie_len); @@ -1918,55 +2483,12 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, } else wk->ie_len = 0; - wk->assoc.bss = req->bss; - - memcpy(wk->filter_ta, req->bss->bssid, ETH_ALEN); - - /* new association always uses requested smps mode */ - if (ifmgd->req_smps == IEEE80211_SMPS_AUTOMATIC) { - if (ifmgd->powersave) - ifmgd->ap_smps = IEEE80211_SMPS_DYNAMIC; - else - ifmgd->ap_smps = IEEE80211_SMPS_OFF; - } else - ifmgd->ap_smps = ifmgd->req_smps; - - wk->assoc.smps = ifmgd->ap_smps; - /* - * IEEE802.11n does not allow TKIP/WEP as pairwise ciphers in HT mode. - * We still associate in non-HT mode (11a/b/g) if any one of these - * ciphers is configured as pairwise. - * We can set this to true for non-11n hardware, that'll be checked - * separately along with the peer capabilities. - */ - wk->assoc.use_11n = !(ifmgd->flags & IEEE80211_STA_DISABLE_11N); - wk->assoc.capability = req->bss->capability; - wk->assoc.wmm_used = bss->wmm_used; - wk->assoc.supp_rates = bss->supp_rates; - wk->assoc.supp_rates_len = bss->supp_rates_len; - wk->assoc.ht_information_ie = - ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_INFORMATION); - - if (bss->wmm_used && bss->uapsd_supported && - (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) { - wk->assoc.uapsd_used = true; - ifmgd->flags |= IEEE80211_STA_UAPSD_ENABLED; - } else { - wk->assoc.uapsd_used = false; - ifmgd->flags &= ~IEEE80211_STA_UAPSD_ENABLED; - } - - ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); - memcpy(wk->assoc.ssid, ssid + 2, ssid[1]); - wk->assoc.ssid_len = ssid[1]; - if (req->prev_bssid) - memcpy(wk->assoc.prev_bssid, req->prev_bssid, ETH_ALEN); + memcpy(wk->prev_bssid, req->prev_bssid, ETH_ALEN); - wk->type = IEEE80211_WORK_ASSOC; - wk->chan = req->bss->channel; - wk->sdata = sdata; - wk->done = ieee80211_assoc_done; + wk->state = IEEE80211_MGD_STATE_ASSOC; + wk->tries = 0; + wk->timeout = jiffies; /* run right away */ if (req->use_mfp) { ifmgd->mfp = IEEE80211_MFP_REQUIRED; @@ -1981,65 +2503,69 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, else ifmgd->flags &= ~IEEE80211_STA_CONTROL_PORT; - ieee80211_add_work(wk); - return 0; + ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.work); + + err = 0; + + out: + mutex_unlock(&ifmgd->mtx); + return err; } int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, struct cfg80211_deauth_request *req, void *cookie) { - struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - struct ieee80211_work *wk; - const u8 *bssid = req->bss->bssid; + struct ieee80211_mgd_work *wk; + const u8 *bssid = NULL; + bool not_auth_yet = false; mutex_lock(&ifmgd->mtx); - if (ifmgd->associated == req->bss) { + if (ifmgd->associated && &ifmgd->associated->cbss == req->bss) { bssid = req->bss->bssid; - ieee80211_set_disassoc(sdata); - mutex_unlock(&ifmgd->mtx); - } else { - bool not_auth_yet = false; - - mutex_unlock(&ifmgd->mtx); - - mutex_lock(&local->work_mtx); - list_for_each_entry(wk, &local->work_list, list) { - if (wk->sdata != sdata) - continue; - - if (wk->type != IEEE80211_WORK_DIRECT_PROBE && - wk->type != IEEE80211_WORK_AUTH) - continue; - - if (memcmp(req->bss->bssid, wk->filter_ta, ETH_ALEN)) - continue; - - not_auth_yet = wk->type == IEEE80211_WORK_DIRECT_PROBE; - list_del_rcu(&wk->list); - free_work(wk); + ieee80211_set_disassoc(sdata, true); + } else list_for_each_entry(wk, &ifmgd->work_list, list) { + if (&wk->bss->cbss == req->bss) { + bssid = req->bss->bssid; + if (wk->state == IEEE80211_MGD_STATE_PROBE) + not_auth_yet = true; + list_del(&wk->list); + kfree(wk); break; } - mutex_unlock(&local->work_mtx); + } - /* - * If somebody requests authentication and we haven't - * sent out an auth frame yet there's no need to send - * out a deauth frame either. If the state was PROBE, - * then this is the case. If it's AUTH we have sent a - * frame, and if it's IDLE we have completed the auth - * process already. - */ - if (not_auth_yet) { - __cfg80211_auth_canceled(sdata->dev, bssid); - return 0; - } + /* + * If somebody requests authentication and we haven't + * sent out an auth frame yet there's no need to send + * out a deauth frame either. If the state was PROBE, + * then this is the case. If it's AUTH we have sent a + * frame, and if it's IDLE we have completed the auth + * process already. + */ + if (not_auth_yet) { + mutex_unlock(&ifmgd->mtx); + __cfg80211_auth_canceled(sdata->dev, bssid); + return 0; } + /* + * cfg80211 should catch this ... but it's racy since + * we can receive a deauth frame, process it, hand it + * to cfg80211 while that's in a locked section already + * trying to tell us that the user wants to disconnect. + */ + if (!bssid) { + mutex_unlock(&ifmgd->mtx); + return -ENOLINK; + } + + mutex_unlock(&ifmgd->mtx); + printk(KERN_DEBUG "%s: deauthenticating from %pM by local choice (reason=%d)\n", - sdata->name, bssid, req->reason_code); + sdata->dev->name, bssid, req->reason_code); ieee80211_send_deauth_disassoc(sdata, bssid, IEEE80211_STYPE_DEAUTH, req->reason_code, @@ -2064,15 +2590,15 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, * to cfg80211 while that's in a locked section already * trying to tell us that the user wants to disconnect. */ - if (ifmgd->associated != req->bss) { + if (&ifmgd->associated->cbss != req->bss) { mutex_unlock(&ifmgd->mtx); return -ENOLINK; } printk(KERN_DEBUG "%s: disassociating from %pM by local choice (reason=%d)\n", - sdata->name, req->bss->bssid, req->reason_code); + sdata->dev->name, req->bss->bssid, req->reason_code); - ieee80211_set_disassoc(sdata); + ieee80211_set_disassoc(sdata, false); mutex_unlock(&ifmgd->mtx); @@ -2084,38 +2610,3 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, return 0; } - -int ieee80211_mgd_action(struct ieee80211_sub_if_data *sdata, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, - const u8 *buf, size_t len, u64 *cookie) -{ - struct ieee80211_local *local = sdata->local; - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - struct sk_buff *skb; - - /* Check that we are on the requested channel for transmission */ - if ((chan != local->tmp_channel || - channel_type != local->tmp_channel_type) && - (chan != local->oper_channel || - channel_type != local->oper_channel_type)) - return -EBUSY; - - skb = dev_alloc_skb(local->hw.extra_tx_headroom + len); - if (!skb) - return -ENOMEM; - skb_reserve(skb, local->hw.extra_tx_headroom); - - memcpy(skb_put(skb, len), buf, len); - - if (!(ifmgd->flags & IEEE80211_STA_MFP_ENABLED)) - IEEE80211_SKB_CB(skb)->flags |= - IEEE80211_TX_INTFL_DONT_ENCRYPT; - IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_NL80211_FRAME_TX | - IEEE80211_TX_CTL_REQ_TX_STATUS; - skb->dev = sdata->dev; - ieee80211_tx_skb(sdata, skb); - - *cookie = (unsigned long) skb; - return 0; -} diff --git a/trunk/net/mac80211/offchannel.c b/trunk/net/mac80211/offchannel.c deleted file mode 100644 index c36b1911987a..000000000000 --- a/trunk/net/mac80211/offchannel.c +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Off-channel operation helpers - * - * Copyright 2003, Jouni Malinen - * Copyright 2004, Instant802 Networks, Inc. - * Copyright 2005, Devicescape Software, Inc. - * Copyright 2006-2007 Jiri Benc - * Copyright 2007, Michael Wu - * Copyright 2009 Johannes Berg - * - * 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 - * published by the Free Software Foundation. - */ -#include -#include "ieee80211_i.h" - -/* - * inform AP that we will go to sleep so that it will buffer the frames - * while we scan - */ -static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata) -{ - struct ieee80211_local *local = sdata->local; - - local->offchannel_ps_enabled = false; - - /* FIXME: what to do when local->pspolling is true? */ - - del_timer_sync(&local->dynamic_ps_timer); - cancel_work_sync(&local->dynamic_ps_enable_work); - - if (local->hw.conf.flags & IEEE80211_CONF_PS) { - local->offchannel_ps_enabled = true; - local->hw.conf.flags &= ~IEEE80211_CONF_PS; - ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); - } - - if (!(local->offchannel_ps_enabled) || - !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)) - /* - * If power save was enabled, no need to send a nullfunc - * frame because AP knows that we are sleeping. But if the - * hardware is creating the nullfunc frame for power save - * status (ie. IEEE80211_HW_PS_NULLFUNC_STACK is not - * enabled) and power save was enabled, the firmware just - * sent a null frame with power save disabled. So we need - * to send a new nullfunc frame to inform the AP that we - * are again sleeping. - */ - ieee80211_send_nullfunc(local, sdata, 1); -} - -/* inform AP that we are awake again, unless power save is enabled */ -static void ieee80211_offchannel_ps_disable(struct ieee80211_sub_if_data *sdata) -{ - struct ieee80211_local *local = sdata->local; - - if (!local->ps_sdata) - ieee80211_send_nullfunc(local, sdata, 0); - else if (local->offchannel_ps_enabled) { - /* - * In !IEEE80211_HW_PS_NULLFUNC_STACK case the hardware - * will send a nullfunc frame with the powersave bit set - * even though the AP already knows that we are sleeping. - * This could be avoided by sending a null frame with power - * save bit disabled before enabling the power save, but - * this doesn't gain anything. - * - * When IEEE80211_HW_PS_NULLFUNC_STACK is enabled, no need - * to send a nullfunc frame because AP already knows that - * we are sleeping, let's just enable power save mode in - * hardware. - */ - local->hw.conf.flags |= IEEE80211_CONF_PS; - ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); - } else if (local->hw.conf.dynamic_ps_timeout > 0) { - /* - * If IEEE80211_CONF_PS was not set and the dynamic_ps_timer - * had been running before leaving the operating channel, - * restart the timer now and send a nullfunc frame to inform - * the AP that we are awake. - */ - ieee80211_send_nullfunc(local, sdata, 0); - mod_timer(&local->dynamic_ps_timer, jiffies + - msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout)); - } -} - -void ieee80211_offchannel_stop_beaconing(struct ieee80211_local *local) -{ - struct ieee80211_sub_if_data *sdata; - - mutex_lock(&local->iflist_mtx); - list_for_each_entry(sdata, &local->interfaces, list) { - if (!ieee80211_sdata_running(sdata)) - continue; - - /* disable beaconing */ - if (sdata->vif.type == NL80211_IFTYPE_AP || - sdata->vif.type == NL80211_IFTYPE_ADHOC || - sdata->vif.type == NL80211_IFTYPE_MESH_POINT) - ieee80211_bss_info_change_notify( - sdata, BSS_CHANGED_BEACON_ENABLED); - - /* - * only handle non-STA interfaces here, STA interfaces - * are handled in ieee80211_offchannel_stop_station(), - * e.g., from the background scan state machine. - * - * In addition, do not stop monitor interface to allow it to be - * used from user space controlled off-channel operations. - */ - if (sdata->vif.type != NL80211_IFTYPE_STATION && - sdata->vif.type != NL80211_IFTYPE_MONITOR) - netif_tx_stop_all_queues(sdata->dev); - } - mutex_unlock(&local->iflist_mtx); -} - -void ieee80211_offchannel_stop_station(struct ieee80211_local *local) -{ - struct ieee80211_sub_if_data *sdata; - - /* - * notify the AP about us leaving the channel and stop all STA interfaces - */ - mutex_lock(&local->iflist_mtx); - list_for_each_entry(sdata, &local->interfaces, list) { - if (!ieee80211_sdata_running(sdata)) - continue; - - if (sdata->vif.type == NL80211_IFTYPE_STATION) { - netif_tx_stop_all_queues(sdata->dev); - if (sdata->u.mgd.associated) - ieee80211_offchannel_ps_enable(sdata); - } - } - mutex_unlock(&local->iflist_mtx); -} - -void ieee80211_offchannel_return(struct ieee80211_local *local, - bool enable_beaconing) -{ - struct ieee80211_sub_if_data *sdata; - - mutex_lock(&local->iflist_mtx); - list_for_each_entry(sdata, &local->interfaces, list) { - if (!ieee80211_sdata_running(sdata)) - continue; - - /* Tell AP we're back */ - if (sdata->vif.type == NL80211_IFTYPE_STATION) { - if (sdata->u.mgd.associated) - ieee80211_offchannel_ps_disable(sdata); - } - - if (sdata->vif.type != NL80211_IFTYPE_MONITOR) - netif_tx_wake_all_queues(sdata->dev); - - /* re-enable beaconing */ - if (enable_beaconing && - (sdata->vif.type == NL80211_IFTYPE_AP || - sdata->vif.type == NL80211_IFTYPE_ADHOC || - sdata->vif.type == NL80211_IFTYPE_MESH_POINT)) - ieee80211_bss_info_change_notify( - sdata, BSS_CHANGED_BEACON_ENABLED); - } - mutex_unlock(&local->iflist_mtx); -} diff --git a/trunk/net/mac80211/pm.c b/trunk/net/mac80211/pm.c index 0e64484e861c..e535f1c988fe 100644 --- a/trunk/net/mac80211/pm.c +++ b/trunk/net/mac80211/pm.c @@ -10,7 +10,9 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata; + struct ieee80211_if_init_conf conf; struct sta_info *sta; + unsigned long flags; ieee80211_scan_cancel(local); @@ -54,21 +56,22 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) rcu_read_unlock(); /* remove STAs */ - mutex_lock(&local->sta_mtx); + spin_lock_irqsave(&local->sta_lock, flags); list_for_each_entry(sta, &local->sta_list, list) { - if (sta->uploaded) { + if (local->ops->sta_notify) { sdata = sta->sdata; if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, u.ap); - drv_sta_remove(local, sdata, &sta->sta); + drv_sta_notify(local, &sdata->vif, STA_NOTIFY_REMOVE, + &sta->sta); } mesh_plink_quiesce(sta); } - mutex_unlock(&local->sta_mtx); + spin_unlock_irqrestore(&local->sta_lock, flags); /* remove all interfaces */ list_for_each_entry(sdata, &local->interfaces, list) { @@ -90,14 +93,17 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) break; } - if (!ieee80211_sdata_running(sdata)) + if (!netif_running(sdata->dev)) continue; /* disable beaconing */ ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); - drv_remove_interface(local, &sdata->vif); + conf.vif = &sdata->vif; + conf.type = sdata->vif.type; + conf.mac_addr = sdata->dev->dev_addr; + drv_remove_interface(local, &conf); } /* stop hardware - this must stop RX */ diff --git a/trunk/net/mac80211/rate.c b/trunk/net/mac80211/rate.c index 0b299d236fa1..12a2bff7dcdb 100644 --- a/trunk/net/mac80211/rate.c +++ b/trunk/net/mac80211/rate.c @@ -145,7 +145,7 @@ static const struct file_operations rcname_ops = { }; #endif -static struct rate_control_ref *rate_control_alloc(const char *name, +struct rate_control_ref *rate_control_alloc(const char *name, struct ieee80211_local *local) { struct dentry *debugfsdir = NULL; @@ -207,27 +207,6 @@ static bool rc_no_data_or_no_ack(struct ieee80211_tx_rate_control *txrc) return ((info->flags & IEEE80211_TX_CTL_NO_ACK) || !ieee80211_is_data(fc)); } -static void rc_send_low_broadcast(s8 *idx, u32 basic_rates, u8 max_rate_idx) -{ - u8 i; - - if (basic_rates == 0) - return; /* assume basic rates unknown and accept rate */ - if (*idx < 0) - return; - if (basic_rates & (1 << *idx)) - return; /* selected rate is a basic rate */ - - for (i = *idx + 1; i <= max_rate_idx; i++) { - if (basic_rates & (1 << i)) { - *idx = i; - return; - } - } - - /* could not find a basic rate; use original selection */ -} - bool rate_control_send_low(struct ieee80211_sta *sta, void *priv_sta, struct ieee80211_tx_rate_control *txrc) @@ -239,48 +218,12 @@ bool rate_control_send_low(struct ieee80211_sta *sta, info->control.rates[0].count = (info->flags & IEEE80211_TX_CTL_NO_ACK) ? 1 : txrc->hw->max_rate_tries; - if (!sta && txrc->ap) - rc_send_low_broadcast(&info->control.rates[0].idx, - txrc->bss_conf->basic_rates, - txrc->sband->n_bitrates); return true; } return false; } EXPORT_SYMBOL(rate_control_send_low); -static void rate_idx_match_mask(struct ieee80211_tx_rate *rate, - int n_bitrates, u32 mask) -{ - int j; - - /* See whether the selected rate or anything below it is allowed. */ - for (j = rate->idx; j >= 0; j--) { - if (mask & (1 << j)) { - /* Okay, found a suitable rate. Use it. */ - rate->idx = j; - return; - } - } - - /* Try to find a higher rate that would be allowed */ - for (j = rate->idx + 1; j < n_bitrates; j++) { - if (mask & (1 << j)) { - /* Okay, found a suitable rate. Use it. */ - rate->idx = j; - return; - } - } - - /* - * Uh.. No suitable rate exists. This should not really happen with - * sane TX rate mask configurations. However, should someone manage to - * configure supported rates and TX rate mask in incompatible way, - * allow the frame to be transmitted with whatever the rate control - * selected. - */ -} - void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, struct sta_info *sta, struct ieee80211_tx_rate_control *txrc) @@ -290,7 +233,6 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, struct ieee80211_sta *ista = NULL; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb); int i; - u32 mask; if (sta) { ista = &sta->sta; @@ -306,31 +248,23 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, if (sdata->local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) return; - ref->ops->get_rate(ref->priv, ista, priv_sta, txrc); + if (sta && sdata->force_unicast_rateidx > -1) { + info->control.rates[0].idx = sdata->force_unicast_rateidx; + } else { + ref->ops->get_rate(ref->priv, ista, priv_sta, txrc); + info->flags |= IEEE80211_TX_INTFL_RCALGO; + } /* - * Try to enforce the rateidx mask the user wanted. skip this if the - * default mask (allow all rates) is used to save some processing for - * the common case. + * try to enforce the maximum rate the user wanted */ - mask = sdata->rc_rateidx_mask[info->band]; - if (mask != (1 << txrc->sband->n_bitrates) - 1) { - if (sta) { - /* Filter out rates that the STA does not support */ - mask &= sta->sta.supp_rates[info->band]; - } - /* - * Make sure the rate index selected for each TX rate is - * included in the configured mask and change the rate indexes - * if needed. - */ + if (sdata->max_ratectrl_rateidx > -1) for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { - /* Rate masking supports only legacy rates for now */ if (info->control.rates[i].flags & IEEE80211_TX_RC_MCS) continue; - rate_idx_match_mask(&info->control.rates[i], - txrc->sband->n_bitrates, mask); - } + 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); diff --git a/trunk/net/mac80211/rate.h b/trunk/net/mac80211/rate.h index b6108bca96d4..cb9bd1f65e27 100644 --- a/trunk/net/mac80211/rate.h +++ b/trunk/net/mac80211/rate.h @@ -26,6 +26,10 @@ struct rate_control_ref { struct kref kref; }; +/* Get a reference to the rate control algorithm. If `name' is NULL, get the + * first available algorithm. */ +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 sta_info *sta, struct ieee80211_tx_rate_control *txrc); @@ -40,11 +44,10 @@ static inline void rate_control_tx_status(struct ieee80211_local *local, struct rate_control_ref *ref = local->rate_ctrl; struct ieee80211_sta *ista = &sta->sta; void *priv_sta = sta->rate_ctrl_priv; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - if (!ref) - return; - - ref->ops->tx_status(ref->priv, sband, ista, priv_sta, skb); + if (likely(info->flags & IEEE80211_TX_INTFL_RCALGO)) + ref->ops->tx_status(ref->priv, sband, ista, priv_sta, skb); } @@ -112,8 +115,7 @@ static inline void rate_control_remove_sta_debugfs(struct sta_info *sta) #endif } -/* Get a reference to the rate control algorithm. If `name' is NULL, get the - * first available algorithm. */ +/* functions for rate control related to a device */ int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, const char *name); void rate_control_deinitialize(struct ieee80211_local *local); diff --git a/trunk/net/mac80211/rc80211_pid_algo.c b/trunk/net/mac80211/rc80211_pid_algo.c index 2652a374974e..29bc4c516238 100644 --- a/trunk/net/mac80211/rc80211_pid_algo.c +++ b/trunk/net/mac80211/rc80211_pid_algo.c @@ -157,7 +157,9 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo, /* In case nothing happened during the previous control interval, turn * the sharpening factor on. */ - period = msecs_to_jiffies(pinfo->sampling_period); + period = (HZ * pinfo->sampling_period + 500) / 1000; + if (!period) + period = 1; if (jiffies - spinfo->last_sample > 2 * period) spinfo->sharp_cnt = pinfo->sharpen_duration; @@ -250,7 +252,9 @@ static void rate_control_pid_tx_status(void *priv, struct ieee80211_supported_ba } /* Update PID controller state. */ - period = msecs_to_jiffies(pinfo->sampling_period); + period = (HZ * pinfo->sampling_period + 500) / 1000; + if (!period) + period = 1; if (time_after(jiffies, spinfo->last_sample + period)) rate_control_pid_sample(pinfo, sband, sta, spinfo); } diff --git a/trunk/net/mac80211/rx.c b/trunk/net/mac80211/rx.c index b5c48de81d8b..82a30c1bf3ab 100644 --- a/trunk/net/mac80211/rx.c +++ b/trunk/net/mac80211/rx.c @@ -2,7 +2,7 @@ * Copyright 2002-2005, Instant802 Networks, Inc. * Copyright 2005-2006, Devicescape Software, Inc. * Copyright 2006-2007 Jiri Benc - * Copyright 2007-2010 Johannes Berg + * Copyright 2007 Johannes Berg * * 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 @@ -283,13 +283,13 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, skb->protocol = htons(ETH_P_802_2); list_for_each_entry_rcu(sdata, &local->interfaces, list) { - if (sdata->vif.type != NL80211_IFTYPE_MONITOR) + if (!netif_running(sdata->dev)) continue; - if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) + if (sdata->vif.type != NL80211_IFTYPE_MONITOR) continue; - if (!ieee80211_sdata_running(sdata)) + if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) continue; if (prev_dev) { @@ -361,9 +361,7 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx) * boundary. In the case of regular frames, this simply means aligning the * payload to a four-byte boundary (because either the IP header is directly * contained, or IV/RFC1042 headers that have a length divisible by four are - * in front of it). If the payload data is not properly aligned and the - * architecture doesn't support efficient unaligned operations, mac80211 - * will align the data. + * in front of it). * * With A-MSDU frames, however, the payload data address must yield two modulo * four because there are 14-byte 802.3 headers within the A-MSDU frames that @@ -377,10 +375,25 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx) */ static void ieee80211_verify_alignment(struct ieee80211_rx_data *rx) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - WARN_ONCE((unsigned long)rx->skb->data & 1, - "unaligned packet at 0x%p\n", rx->skb->data); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; + int hdrlen; + +#ifndef CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT + return; #endif + + if (WARN_ONCE((unsigned long)rx->skb->data & 1, + "unaligned packet at 0x%p\n", rx->skb->data)) + return; + + if (!ieee80211_is_data_present(hdr->frame_control)) + return; + + hdrlen = ieee80211_hdrlen(hdr->frame_control); + if (rx->flags & IEEE80211_RX_AMSDU) + hdrlen += ETH_HLEN; + WARN_ONCE(((unsigned long)(rx->skb->data + hdrlen)) & 3, + "unaligned IP payload at 0x%p\n", rx->skb->data + hdrlen); } @@ -463,7 +476,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; unsigned int hdrlen = ieee80211_hdrlen(hdr->frame_control); - char *dev_addr = rx->sdata->vif.addr; + char *dev_addr = rx->sdata->dev->dev_addr; if (ieee80211_is_data(hdr->frame_control)) { if (is_multicast_ether_addr(hdr->addr1)) { @@ -1008,10 +1021,10 @@ static void ap_sta_ps_start(struct sta_info *sta) atomic_inc(&sdata->bss->num_sta_ps); set_sta_flags(sta, WLAN_STA_PS_STA); - drv_sta_notify(local, sdata, STA_NOTIFY_SLEEP, &sta->sta); + drv_sta_notify(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->name, sta->sta.addr, sta->sta.aid); + sdata->dev->name, sta->sta.addr, sta->sta.aid); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ } @@ -1025,13 +1038,13 @@ static void ap_sta_ps_end(struct sta_info *sta) #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "%s: STA %pM aid %d exits power save mode\n", - sdata->name, sta->sta.addr, sta->sta.aid); + sdata->dev->name, sta->sta.addr, sta->sta.aid); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ if (test_sta_flags(sta, WLAN_STA_PS_DRIVER)) { #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "%s: STA %pM aid %d driver-ps-blocked\n", - sdata->name, sta->sta.addr, sta->sta.aid); + sdata->dev->name, sta->sta.addr, sta->sta.aid); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ return; } @@ -1111,18 +1124,6 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) if (ieee80211_is_nullfunc(hdr->frame_control) || ieee80211_is_qos_nullfunc(hdr->frame_control)) { I802_DEBUG_INC(rx->local->rx_handlers_drop_nullfunc); - - /* - * If we receive a 4-addr nullfunc frame from a STA - * that was not moved to a 4-addr STA vlan yet, drop - * the frame to the monitor interface, to make sure - * that hostapd sees it - */ - if (ieee80211_has_a4(hdr->frame_control) && - (rx->sdata->vif.type == NL80211_IFTYPE_AP || - (rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN && - !rx->sdata->u.vlan.sta))) - return RX_DROP_MONITOR; /* * Update counter and free packet here to avoid * counting this as a dropped packed. @@ -1155,7 +1156,7 @@ ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata, printk(KERN_DEBUG "%s: RX reassembly removed oldest " "fragment entry (idx=%d age=%lu seq=%d last_frag=%d " "addr1=%pM addr2=%pM\n", - sdata->name, idx, + sdata->dev->name, idx, jiffies - entry->first_frag_time, entry->seq, entry->last_frag, hdr->addr1, hdr->addr2); #endif @@ -1397,21 +1398,6 @@ ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc) ieee80211_is_data(fc) && (rx->key || rx->sdata->drop_unencrypted))) return -EACCES; - - return 0; -} - -static int -ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; - __le16 fc = hdr->frame_control; - int res; - - res = ieee80211_drop_unencrypted(rx, fc); - if (unlikely(res)) - return res; - if (rx->sta && test_sta_flags(rx->sta, WLAN_STA_MFP)) { if (unlikely(ieee80211_is_unicast_robust_mgmt_frame(rx->skb) && rx->key)) @@ -1438,6 +1424,7 @@ static int __ieee80211_data_to_8023(struct ieee80211_rx_data *rx) { struct ieee80211_sub_if_data *sdata = rx->sdata; + struct net_device *dev = sdata->dev; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; if (ieee80211_has_a4(hdr->frame_control) && @@ -1449,7 +1436,7 @@ __ieee80211_data_to_8023(struct ieee80211_rx_data *rx) (sdata->vif.type == NL80211_IFTYPE_STATION && sdata->u.mgd.use_4addr))) return -1; - return ieee80211_data_to_8023(rx->skb, sdata->vif.addr, sdata->vif.type); + return ieee80211_data_to_8023(rx->skb, dev->dev_addr, sdata->vif.type); } /* @@ -1466,7 +1453,7 @@ static bool ieee80211_frame_allowed(struct ieee80211_rx_data *rx, __le16 fc) * of whether the frame was encrypted or not. */ if (ehdr->h_proto == htons(ETH_P_PAE) && - (compare_ether_addr(ehdr->h_dest, rx->sdata->vif.addr) == 0 || + (compare_ether_addr(ehdr->h_dest, rx->sdata->dev->dev_addr) == 0 || compare_ether_addr(ehdr->h_dest, pae_group_addr) == 0)) return true; @@ -1485,6 +1472,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) { struct ieee80211_sub_if_data *sdata = rx->sdata; struct net_device *dev = sdata->dev; + struct ieee80211_local *local = rx->local; struct sk_buff *skb, *xmit_skb; struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data; struct sta_info *dsta; @@ -1507,8 +1495,8 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) printk(KERN_DEBUG "%s: failed to clone " "multicast frame\n", dev->name); } else { - dsta = sta_info_get(sdata, skb->data); - if (dsta) { + dsta = sta_info_get(local, skb->data); + if (dsta && dsta->sdata->dev == dev) { /* * The destination station is associated to * this AP (in this VLAN), so send the frame @@ -1524,7 +1512,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) if (skb) { int align __maybe_unused; -#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS +#if defined(CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT) || !defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) /* * 'align' will only take the values 0 or 2 here * since all frames are required to be aligned @@ -1568,10 +1556,16 @@ static ieee80211_rx_result debug_noinline ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) { struct net_device *dev = rx->sdata->dev; - struct sk_buff *skb = rx->skb; + struct ieee80211_local *local = rx->local; + u16 ethertype; + u8 *payload; + struct sk_buff *skb = rx->skb, *frame = NULL; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; __le16 fc = hdr->frame_control; - struct sk_buff_head frame_list; + const struct ethhdr *eth; + int remaining, err; + u8 dst[ETH_ALEN]; + u8 src[ETH_ALEN]; if (unlikely(!ieee80211_is_data(fc))) return RX_CONTINUE; @@ -1582,34 +1576,94 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) if (!(rx->flags & IEEE80211_RX_AMSDU)) return RX_CONTINUE; - if (ieee80211_has_a4(hdr->frame_control) && - rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN && - !rx->sdata->u.vlan.sta) + err = __ieee80211_data_to_8023(rx); + if (unlikely(err)) return RX_DROP_UNUSABLE; - if (is_multicast_ether_addr(hdr->addr1) && - ((rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN && - rx->sdata->u.vlan.sta) || - (rx->sdata->vif.type == NL80211_IFTYPE_STATION && - rx->sdata->u.mgd.use_4addr))) + skb->dev = dev; + + dev->stats.rx_packets++; + dev->stats.rx_bytes += skb->len; + + /* skip the wrapping header */ + eth = (struct ethhdr *) skb_pull(skb, sizeof(struct ethhdr)); + if (!eth) return RX_DROP_UNUSABLE; - skb->dev = dev; - __skb_queue_head_init(&frame_list); + while (skb != frame) { + u8 padding; + __be16 len = eth->h_proto; + unsigned int subframe_len = sizeof(struct ethhdr) + ntohs(len); + + remaining = skb->len; + memcpy(dst, eth->h_dest, ETH_ALEN); + memcpy(src, eth->h_source, ETH_ALEN); + + padding = ((4 - subframe_len) & 0x3); + /* the last MSDU has no padding */ + if (subframe_len > remaining) + return RX_DROP_UNUSABLE; - ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr, - rx->sdata->vif.type, - rx->local->hw.extra_tx_headroom); + skb_pull(skb, sizeof(struct ethhdr)); + /* if last subframe reuse skb */ + if (remaining <= subframe_len + padding) + frame = skb; + else { + /* + * Allocate and reserve two bytes more for payload + * alignment since sizeof(struct ethhdr) is 14. + */ + frame = dev_alloc_skb( + ALIGN(local->hw.extra_tx_headroom, 4) + + subframe_len + 2); + + if (frame == NULL) + return RX_DROP_UNUSABLE; + + skb_reserve(frame, + ALIGN(local->hw.extra_tx_headroom, 4) + + sizeof(struct ethhdr) + 2); + memcpy(skb_put(frame, ntohs(len)), skb->data, + ntohs(len)); + + eth = (struct ethhdr *) skb_pull(skb, ntohs(len) + + padding); + if (!eth) { + dev_kfree_skb(frame); + return RX_DROP_UNUSABLE; + } + } - while (!skb_queue_empty(&frame_list)) { - rx->skb = __skb_dequeue(&frame_list); + skb_reset_network_header(frame); + frame->dev = dev; + frame->priority = skb->priority; + rx->skb = frame; + + payload = frame->data; + ethertype = (payload[6] << 8) | payload[7]; + + if (likely((compare_ether_addr(payload, rfc1042_header) == 0 && + ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || + compare_ether_addr(payload, + bridge_tunnel_header) == 0)) { + /* remove RFC1042 or Bridge-Tunnel + * encapsulation and replace EtherType */ + skb_pull(frame, 6); + memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN); + memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN); + } else { + memcpy(skb_push(frame, sizeof(__be16)), + &len, sizeof(__be16)); + memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN); + memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN); + } if (!ieee80211_frame_allowed(rx, fc)) { - dev_kfree_skb(rx->skb); + if (skb == frame) /* last frame */ + return RX_DROP_UNUSABLE; + dev_kfree_skb(frame); continue; } - dev->stats.rx_packets++; - dev->stats.rx_bytes += rx->skb->len; ieee80211_deliver_skb(rx); } @@ -1667,7 +1721,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) /* Frame has reached destination. Don't forward */ if (!is_multicast_ether_addr(hdr->addr1) && - compare_ether_addr(sdata->vif.addr, hdr->addr3) == 0) + compare_ether_addr(sdata->dev->dev_addr, hdr->addr3) == 0) return RX_CONTINUE; mesh_hdr->ttl--; @@ -1684,10 +1738,10 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) if (!fwd_skb && net_ratelimit()) printk(KERN_DEBUG "%s: failed to clone mesh frame\n", - sdata->name); + sdata->dev->name); fwd_hdr = (struct ieee80211_hdr *) fwd_skb->data; - memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN); + memcpy(fwd_hdr->addr2, sdata->dev->dev_addr, ETH_ALEN); info = IEEE80211_SKB_CB(fwd_skb); memset(info, 0, sizeof(*info)); info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; @@ -1734,7 +1788,6 @@ static ieee80211_rx_result debug_noinline ieee80211_rx_h_data(struct ieee80211_rx_data *rx) { struct ieee80211_sub_if_data *sdata = rx->sdata; - struct ieee80211_local *local = rx->local; struct net_device *dev = sdata->dev; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; __le16 fc = hdr->frame_control; @@ -1766,13 +1819,6 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx) dev->stats.rx_packets++; dev->stats.rx_bytes += rx->skb->len; - if (ieee80211_is_data(hdr->frame_control) && - !is_multicast_ether_addr(hdr->addr1) && - local->hw.conf.dynamic_ps_timeout > 0 && local->ps_sdata) { - mod_timer(&local->dynamic_ps_timer, jiffies + - msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout)); - } - ieee80211_deliver_skb(rx); return RX_QUEUED; @@ -1826,7 +1872,7 @@ static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb; struct ieee80211_mgmt *resp; - if (compare_ether_addr(mgmt->da, sdata->vif.addr) != 0) { + if (compare_ether_addr(mgmt->da, sdata->dev->dev_addr) != 0) { /* Not to own unicast address */ return; } @@ -1850,7 +1896,7 @@ static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata, resp = (struct ieee80211_mgmt *) skb_put(skb, 24); memset(resp, 0, 24); memcpy(resp->da, mgmt->sa, ETH_ALEN); - memcpy(resp->sa, sdata->vif.addr, ETH_ALEN); + memcpy(resp->sa, sdata->dev->dev_addr, ETH_ALEN); memcpy(resp->bssid, sdata->u.mgd.bssid, ETH_ALEN); resp->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION); @@ -1870,25 +1916,23 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) struct ieee80211_local *local = rx->local; struct ieee80211_sub_if_data *sdata = rx->sdata; struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; - struct sk_buff *nskb; - struct ieee80211_rx_status *status; int len = rx->skb->len; if (!ieee80211_is_action(mgmt->frame_control)) return RX_CONTINUE; - /* drop too small frames */ - if (len < IEEE80211_MIN_ACTION_SIZE) - return RX_DROP_UNUSABLE; - - if (!rx->sta && mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) - return RX_DROP_UNUSABLE; + if (!rx->sta) + return RX_DROP_MONITOR; if (!(rx->flags & IEEE80211_RX_RA_MATCH)) - return RX_DROP_UNUSABLE; + return RX_DROP_MONITOR; - if (ieee80211_drop_unencrypted_mgmt(rx)) - return RX_DROP_UNUSABLE; + if (ieee80211_drop_unencrypted(rx, mgmt->frame_control)) + return RX_DROP_MONITOR; + + /* all categories we currently handle have action_code */ + if (len < IEEE80211_MIN_ACTION_SIZE + 1) + return RX_DROP_MONITOR; switch (mgmt->u.action.category) { case WLAN_CATEGORY_BACK: @@ -1901,11 +1945,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) if (sdata->vif.type != NL80211_IFTYPE_STATION && sdata->vif.type != NL80211_IFTYPE_AP_VLAN && sdata->vif.type != NL80211_IFTYPE_AP) - break; - - /* verify action_code is present */ - if (len < IEEE80211_MIN_ACTION_SIZE + 1) - break; + return RX_DROP_MONITOR; switch (mgmt->u.action.u.addba_req.action_code) { case WLAN_ACTION_ADDBA_REQ: @@ -1913,49 +1953,45 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) sizeof(mgmt->u.action.u.addba_req))) return RX_DROP_MONITOR; ieee80211_process_addba_request(local, rx->sta, mgmt, len); - goto handled; + break; case WLAN_ACTION_ADDBA_RESP: if (len < (IEEE80211_MIN_ACTION_SIZE + sizeof(mgmt->u.action.u.addba_resp))) - break; + return RX_DROP_MONITOR; ieee80211_process_addba_resp(local, rx->sta, mgmt, len); - goto handled; + break; case WLAN_ACTION_DELBA: if (len < (IEEE80211_MIN_ACTION_SIZE + sizeof(mgmt->u.action.u.delba))) - break; + return RX_DROP_MONITOR; ieee80211_process_delba(sdata, rx->sta, mgmt, len); - goto handled; + break; } break; case WLAN_CATEGORY_SPECTRUM_MGMT: if (local->hw.conf.channel->band != IEEE80211_BAND_5GHZ) - break; + return RX_DROP_MONITOR; if (sdata->vif.type != NL80211_IFTYPE_STATION) - break; - - /* verify action_code is present */ - if (len < IEEE80211_MIN_ACTION_SIZE + 1) - break; + return RX_DROP_MONITOR; switch (mgmt->u.action.u.measurement.action_code) { case WLAN_ACTION_SPCT_MSR_REQ: if (len < (IEEE80211_MIN_ACTION_SIZE + sizeof(mgmt->u.action.u.measurement))) - break; + return RX_DROP_MONITOR; ieee80211_process_measurement_req(sdata, mgmt, len); - goto handled; + break; case WLAN_ACTION_SPCT_CHL_SWITCH: if (len < (IEEE80211_MIN_ACTION_SIZE + sizeof(mgmt->u.action.u.chan_switch))) - break; + return RX_DROP_MONITOR; if (sdata->vif.type != NL80211_IFTYPE_STATION) - break; + return RX_DROP_MONITOR; if (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN)) - break; + return RX_DROP_MONITOR; return ieee80211_sta_rx_mgmt(sdata, rx->skb); } @@ -1963,64 +1999,30 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) case WLAN_CATEGORY_SA_QUERY: if (len < (IEEE80211_MIN_ACTION_SIZE + sizeof(mgmt->u.action.u.sa_query))) - break; - + return RX_DROP_MONITOR; switch (mgmt->u.action.u.sa_query.action) { case WLAN_ACTION_SA_QUERY_REQUEST: if (sdata->vif.type != NL80211_IFTYPE_STATION) - break; + return RX_DROP_MONITOR; ieee80211_process_sa_query_req(sdata, mgmt, len); - goto handled; + break; + case WLAN_ACTION_SA_QUERY_RESPONSE: + /* + * SA Query response is currently only used in AP mode + * and it is processed in user space. + */ + return RX_CONTINUE; } break; - } - - /* - * For AP mode, hostapd is responsible for handling any action - * frames that we didn't handle, including returning unknown - * ones. For all other modes we will return them to the sender, - * setting the 0x80 bit in the action category, as required by - * 802.11-2007 7.3.1.11. - */ - if (sdata->vif.type == NL80211_IFTYPE_AP || - sdata->vif.type == NL80211_IFTYPE_AP_VLAN) - return RX_DROP_MONITOR; - - /* - * Getting here means the kernel doesn't know how to handle - * it, but maybe userspace does ... include returned frames - * so userspace can register for those to know whether ones - * it transmitted were processed or returned. - */ - status = IEEE80211_SKB_RXCB(rx->skb); - - if (sdata->vif.type == NL80211_IFTYPE_STATION && - cfg80211_rx_action(rx->sdata->dev, status->freq, - rx->skb->data, rx->skb->len, - GFP_ATOMIC)) - goto handled; - - /* do not return rejected action frames */ - if (mgmt->u.action.category & 0x80) - return RX_DROP_UNUSABLE; - - nskb = skb_copy_expand(rx->skb, local->hw.extra_tx_headroom, 0, - GFP_ATOMIC); - if (nskb) { - struct ieee80211_mgmt *mgmt = (void *)nskb->data; - - mgmt->u.action.category |= 0x80; - memcpy(mgmt->da, mgmt->sa, ETH_ALEN); - memcpy(mgmt->sa, rx->sdata->vif.addr, ETH_ALEN); - - memset(nskb->cb, 0, sizeof(nskb->cb)); + default: + /* do not process rejected action frames */ + if (mgmt->u.action.category & 0x80) + return RX_DROP_MONITOR; - ieee80211_tx_skb(rx->sdata, nskb); + return RX_CONTINUE; } - handled: - if (rx->sta) - rx->sta->rx_packets++; + rx->sta->rx_packets++; dev_kfree_skb(rx->skb); return RX_QUEUED; } @@ -2029,17 +2031,13 @@ static ieee80211_rx_result debug_noinline ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) { struct ieee80211_sub_if_data *sdata = rx->sdata; - ieee80211_rx_result rxs; + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; if (!(rx->flags & IEEE80211_RX_RA_MATCH)) return RX_DROP_MONITOR; - if (ieee80211_drop_unencrypted_mgmt(rx)) - return RX_DROP_UNUSABLE; - - rxs = ieee80211_work_rx_mgmt(rx->sdata, rx->skb); - if (rxs != RX_CONTINUE) - return rxs; + if (ieee80211_drop_unencrypted(rx, mgmt->frame_control)) + return RX_DROP_MONITOR; if (ieee80211_vif_is_mesh(&sdata->vif)) return ieee80211_mesh_rx_mgmt(sdata, rx->skb); @@ -2145,7 +2143,7 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx, skb->protocol = htons(ETH_P_802_2); list_for_each_entry_rcu(sdata, &local->interfaces, list) { - if (!ieee80211_sdata_running(sdata)) + if (!netif_running(sdata->dev)) continue; if (sdata->vif.type != NL80211_IFTYPE_MONITOR || @@ -2282,7 +2280,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, if (!bssid && !sdata->u.mgd.use_4addr) return 0; if (!multicast && - compare_ether_addr(sdata->vif.addr, hdr->addr1) != 0) { + compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) { if (!(sdata->dev->flags & IFF_PROMISC)) return 0; rx->flags &= ~IEEE80211_RX_RA_MATCH; @@ -2299,7 +2297,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, return 0; rx->flags &= ~IEEE80211_RX_RA_MATCH; } else if (!multicast && - compare_ether_addr(sdata->vif.addr, + compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) { if (!(sdata->dev->flags & IFF_PROMISC)) return 0; @@ -2310,13 +2308,13 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, rate_idx = 0; /* TODO: HT rates */ else rate_idx = status->rate_idx; - rx->sta = ieee80211_ibss_add_sta(sdata, bssid, - hdr->addr2, BIT(rate_idx), GFP_ATOMIC); + rx->sta = ieee80211_ibss_add_sta(sdata, bssid, hdr->addr2, + BIT(rate_idx)); } break; case NL80211_IFTYPE_MESH_POINT: if (!multicast && - compare_ether_addr(sdata->vif.addr, + compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) { if (!(sdata->dev->flags & IFF_PROMISC)) return 0; @@ -2327,11 +2325,11 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, case NL80211_IFTYPE_AP_VLAN: case NL80211_IFTYPE_AP: if (!bssid) { - if (compare_ether_addr(sdata->vif.addr, + if (compare_ether_addr(sdata->dev->dev_addr, hdr->addr1)) return 0; } else if (!ieee80211_bssid_match(bssid, - sdata->vif.addr)) { + sdata->dev->dev_addr)) { if (!(rx->flags & IEEE80211_RX_IN_SCAN)) return 0; rx->flags &= ~IEEE80211_RX_RA_MATCH; @@ -2370,8 +2368,6 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, int prepares; struct ieee80211_sub_if_data *prev = NULL; struct sk_buff *skb_new; - struct sta_info *sta, *tmp; - bool found_sta = false; hdr = (struct ieee80211_hdr *)skb->data; memset(&rx, 0, sizeof(rx)); @@ -2388,87 +2384,68 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, ieee80211_parse_qos(&rx); ieee80211_verify_alignment(&rx); - if (ieee80211_is_data(hdr->frame_control)) { - for_each_sta_info(local, hdr->addr2, sta, tmp) { - rx.sta = sta; - found_sta = true; - rx.sdata = sta->sdata; - - rx.flags |= IEEE80211_RX_RA_MATCH; - prepares = prepare_for_handlers(rx.sdata, &rx, hdr); - if (prepares) { - if (status->flag & RX_FLAG_MMIC_ERROR) { - if (rx.flags & IEEE80211_RX_RA_MATCH) - ieee80211_rx_michael_mic_report(hdr, &rx); - } else - prev = rx.sdata; - } - } - } - if (!found_sta) { - list_for_each_entry_rcu(sdata, &local->interfaces, list) { - if (!ieee80211_sdata_running(sdata)) - continue; - - if (sdata->vif.type == NL80211_IFTYPE_MONITOR || - sdata->vif.type == NL80211_IFTYPE_AP_VLAN) - continue; - - /* - * frame is destined for this interface, but if it's - * not also for the previous one we handle that after - * the loop to avoid copying the SKB once too much - */ + rx.sta = sta_info_get(local, hdr->addr2); + if (rx.sta) + rx.sdata = rx.sta->sdata; - if (!prev) { - prev = sdata; - continue; - } + if (rx.sdata && ieee80211_is_data(hdr->frame_control)) { + rx.flags |= IEEE80211_RX_RA_MATCH; + prepares = prepare_for_handlers(rx.sdata, &rx, hdr); + if (prepares) { + if (status->flag & RX_FLAG_MMIC_ERROR) { + if (rx.flags & IEEE80211_RX_RA_MATCH) + ieee80211_rx_michael_mic_report(hdr, &rx); + } else + prev = rx.sdata; + } + } else list_for_each_entry_rcu(sdata, &local->interfaces, list) { + if (!netif_running(sdata->dev)) + continue; - rx.sta = sta_info_get_bss(prev, hdr->addr2); + if (sdata->vif.type == NL80211_IFTYPE_MONITOR || + sdata->vif.type == NL80211_IFTYPE_AP_VLAN) + continue; - rx.flags |= IEEE80211_RX_RA_MATCH; - prepares = prepare_for_handlers(prev, &rx, hdr); + rx.flags |= IEEE80211_RX_RA_MATCH; + prepares = prepare_for_handlers(sdata, &rx, hdr); - if (!prepares) - goto next; + if (!prepares) + continue; - if (status->flag & RX_FLAG_MMIC_ERROR) { - rx.sdata = prev; - if (rx.flags & IEEE80211_RX_RA_MATCH) - ieee80211_rx_michael_mic_report(hdr, - &rx); - goto next; - } + if (status->flag & RX_FLAG_MMIC_ERROR) { + rx.sdata = sdata; + if (rx.flags & IEEE80211_RX_RA_MATCH) + ieee80211_rx_michael_mic_report(hdr, &rx); + continue; + } - /* - * frame was destined for the previous interface - * so invoke RX handlers for it - */ + /* + * frame is destined for this interface, but if it's not + * also for the previous one we handle that after the + * loop to avoid copying the SKB once too much + */ - skb_new = skb_copy(skb, GFP_ATOMIC); - if (!skb_new) { - if (net_ratelimit()) - printk(KERN_DEBUG "%s: failed to copy " - "multicast frame for %s\n", - wiphy_name(local->hw.wiphy), - prev->name); - goto next; - } - ieee80211_invoke_rx_handlers(prev, &rx, skb_new, rate); -next: + if (!prev) { prev = sdata; + continue; } - if (prev) { - rx.sta = sta_info_get_bss(prev, hdr->addr2); - - rx.flags |= IEEE80211_RX_RA_MATCH; - prepares = prepare_for_handlers(prev, &rx, hdr); + /* + * frame was destined for the previous interface + * so invoke RX handlers for it + */ - if (!prepares) - prev = NULL; + skb_new = skb_copy(skb, GFP_ATOMIC); + if (!skb_new) { + if (net_ratelimit()) + printk(KERN_DEBUG "%s: failed to copy " + "multicast frame for %s\n", + wiphy_name(local->hw.wiphy), + prev->dev->name); + continue; } + ieee80211_invoke_rx_handlers(prev, &rx, skb_new, rate); + prev = sdata; } if (prev) ieee80211_invoke_rx_handlers(prev, &rx, skb, rate); diff --git a/trunk/net/mac80211/scan.c b/trunk/net/mac80211/scan.c index b822dce97867..bc17cf7d68db 100644 --- a/trunk/net/mac80211/scan.c +++ b/trunk/net/mac80211/scan.c @@ -12,6 +12,7 @@ * published by the Free Software Foundation. */ +#include #include #include #include @@ -28,19 +29,16 @@ struct ieee80211_bss * ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq, u8 *ssid, u8 ssid_len) { - struct cfg80211_bss *cbss; - - cbss = cfg80211_get_bss(local->hw.wiphy, - ieee80211_get_channel(local->hw.wiphy, freq), - bssid, ssid, ssid_len, 0, 0); - if (!cbss) - return NULL; - return (void *)cbss->priv; + return (void *)cfg80211_get_bss(local->hw.wiphy, + ieee80211_get_channel(local->hw.wiphy, + freq), + bssid, ssid, ssid_len, + 0, 0); } static void ieee80211_rx_bss_free(struct cfg80211_bss *cbss) { - struct ieee80211_bss *bss = (void *)cbss->priv; + struct ieee80211_bss *bss = (void *)cbss; kfree(bss_mesh_id(bss)); kfree(bss_mesh_cfg(bss)); @@ -49,26 +47,7 @@ static void ieee80211_rx_bss_free(struct cfg80211_bss *cbss) void ieee80211_rx_bss_put(struct ieee80211_local *local, struct ieee80211_bss *bss) { - if (!bss) - return; - cfg80211_put_bss(container_of((void *)bss, struct cfg80211_bss, priv)); -} - -static bool is_uapsd_supported(struct ieee802_11_elems *elems) -{ - u8 qos_info; - - if (elems->wmm_info && elems->wmm_info_len == 7 - && elems->wmm_info[5] == 1) - qos_info = elems->wmm_info[6]; - else if (elems->wmm_param && elems->wmm_param_len == 24 - && elems->wmm_param[5] == 1) - qos_info = elems->wmm_param[6]; - else - /* no valid wmm information or parameter element found */ - return false; - - return qos_info & IEEE80211_WMM_IE_AP_QOSINFO_UAPSD; + cfg80211_put_bss((struct cfg80211_bss *)bss); } struct ieee80211_bss * @@ -80,7 +59,6 @@ ieee80211_bss_info_update(struct ieee80211_local *local, struct ieee80211_channel *channel, bool beacon) { - struct cfg80211_bss *cbss; struct ieee80211_bss *bss; int clen; s32 signal = 0; @@ -90,14 +68,13 @@ ieee80211_bss_info_update(struct ieee80211_local *local, else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) signal = (rx_status->signal * 100) / local->hw.max_signal; - cbss = cfg80211_inform_bss_frame(local->hw.wiphy, channel, - mgmt, len, signal, GFP_ATOMIC); + bss = (void *)cfg80211_inform_bss_frame(local->hw.wiphy, channel, + mgmt, len, signal, GFP_ATOMIC); - if (!cbss) + if (!bss) return NULL; - cbss->free_priv = ieee80211_rx_bss_free; - bss = (void *)cbss->priv; + bss->cbss.free_priv = ieee80211_rx_bss_free; /* save the ERP value so that it is available at association time */ if (elems->erp_info && elems->erp_info_len >= 1) { @@ -111,6 +88,10 @@ ieee80211_bss_info_update(struct ieee80211_local *local, bss->dtim_period = tim_ie->dtim_period; } + /* set default value for buggy AP/no TIM element */ + if (bss->dtim_period == 0) + bss->dtim_period = 1; + bss->supp_rates_len = 0; if (elems->supp_rates) { clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len; @@ -130,7 +111,6 @@ ieee80211_bss_info_update(struct ieee80211_local *local, } bss->wmm_used = elems->wmm_param || elems->wmm_info; - bss->uapsd_supported = is_uapsd_supported(elems); if (!beacon) bss->last_probe_resp = jiffies; @@ -167,7 +147,7 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) presp = ieee80211_is_probe_resp(fc); if (presp) { /* ignore ProbeResp to foreign address */ - if (memcmp(mgmt->da, sdata->vif.addr, ETH_ALEN)) + if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN)) return RX_DROP_MONITOR; presp = true; @@ -240,9 +220,82 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) return true; } +/* + * inform AP that we will go to sleep so that it will buffer the frames + * while we scan + */ +static void ieee80211_scan_ps_enable(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_local *local = sdata->local; + + local->scan_ps_enabled = false; + + /* FIXME: what to do when local->pspolling is true? */ + + del_timer_sync(&local->dynamic_ps_timer); + cancel_work_sync(&local->dynamic_ps_enable_work); + + if (local->hw.conf.flags & IEEE80211_CONF_PS) { + local->scan_ps_enabled = true; + local->hw.conf.flags &= ~IEEE80211_CONF_PS; + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); + } + + if (!(local->scan_ps_enabled) || + !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)) + /* + * If power save was enabled, no need to send a nullfunc + * frame because AP knows that we are sleeping. But if the + * hardware is creating the nullfunc frame for power save + * status (ie. IEEE80211_HW_PS_NULLFUNC_STACK is not + * enabled) and power save was enabled, the firmware just + * sent a null frame with power save disabled. So we need + * to send a new nullfunc frame to inform the AP that we + * are again sleeping. + */ + ieee80211_send_nullfunc(local, sdata, 1); +} + +/* inform AP that we are awake again, unless power save is enabled */ +static void ieee80211_scan_ps_disable(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_local *local = sdata->local; + + if (!local->ps_sdata) + ieee80211_send_nullfunc(local, sdata, 0); + else if (local->scan_ps_enabled) { + /* + * In !IEEE80211_HW_PS_NULLFUNC_STACK case the hardware + * will send a nullfunc frame with the powersave bit set + * even though the AP already knows that we are sleeping. + * This could be avoided by sending a null frame with power + * save bit disabled before enabling the power save, but + * this doesn't gain anything. + * + * When IEEE80211_HW_PS_NULLFUNC_STACK is enabled, no need + * to send a nullfunc frame because AP already knows that + * we are sleeping, let's just enable power save mode in + * hardware. + */ + local->hw.conf.flags |= IEEE80211_CONF_PS; + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); + } else if (local->hw.conf.dynamic_ps_timeout > 0) { + /* + * If IEEE80211_CONF_PS was not set and the dynamic_ps_timer + * had been running before leaving the operating channel, + * restart the timer now and send a nullfunc frame to inform + * the AP that we are awake. + */ + ieee80211_send_nullfunc(local, sdata, 0); + mod_timer(&local->dynamic_ps_timer, jiffies + + msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout)); + } +} + void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) { struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_sub_if_data *sdata; bool was_hw_scan; mutex_lock(&local->scan_mtx); @@ -291,19 +344,41 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) drv_sw_scan_complete(local); - ieee80211_offchannel_return(local, true); + mutex_lock(&local->iflist_mtx); + list_for_each_entry(sdata, &local->interfaces, list) { + if (!netif_running(sdata->dev)) + continue; + + /* Tell AP we're back */ + if (sdata->vif.type == NL80211_IFTYPE_STATION) { + if (sdata->u.mgd.associated) { + ieee80211_scan_ps_disable(sdata); + netif_tx_wake_all_queues(sdata->dev); + } + } else + netif_tx_wake_all_queues(sdata->dev); + + /* re-enable beaconing */ + if (sdata->vif.type == NL80211_IFTYPE_AP || + sdata->vif.type == NL80211_IFTYPE_ADHOC || + sdata->vif.type == NL80211_IFTYPE_MESH_POINT) + ieee80211_bss_info_change_notify( + sdata, BSS_CHANGED_BEACON_ENABLED); + } + mutex_unlock(&local->iflist_mtx); done: ieee80211_recalc_idle(local); ieee80211_mlme_notify_scan_completed(local); ieee80211_ibss_notify_scan_completed(local); ieee80211_mesh_notify_scan_completed(local); - ieee80211_queue_work(&local->hw, &local->work_work); } EXPORT_SYMBOL(ieee80211_scan_completed); static int ieee80211_start_sw_scan(struct ieee80211_local *local) { + struct ieee80211_sub_if_data *sdata; + /* * Hardware/driver doesn't support hw_scan, so use software * scanning instead. First send a nullfunc frame with power save @@ -319,15 +394,33 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local) */ drv_sw_scan_start(local); - ieee80211_offchannel_stop_beaconing(local); + mutex_lock(&local->iflist_mtx); + list_for_each_entry(sdata, &local->interfaces, list) { + if (!netif_running(sdata->dev)) + continue; + + /* disable beaconing */ + if (sdata->vif.type == NL80211_IFTYPE_AP || + sdata->vif.type == NL80211_IFTYPE_ADHOC || + sdata->vif.type == NL80211_IFTYPE_MESH_POINT) + ieee80211_bss_info_change_notify( + sdata, BSS_CHANGED_BEACON_ENABLED); + + /* + * only handle non-STA interfaces here, STA interfaces + * are handled in the scan state machine + */ + if (sdata->vif.type != NL80211_IFTYPE_STATION) + netif_tx_stop_all_queues(sdata->dev); + } + mutex_unlock(&local->iflist_mtx); local->next_scan_state = SCAN_DECISION; local->scan_channel_idx = 0; - drv_flush(local, false); - ieee80211_configure_filter(local); + /* TODO: start scan as soon as all nullfunc frames are ACKed */ ieee80211_queue_delayed_work(&local->hw, &local->scan_work, IEEE80211_CHANNEL_TIME); @@ -340,13 +433,17 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, struct cfg80211_scan_request *req) { struct ieee80211_local *local = sdata->local; + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; int rc; if (local->scan_req) return -EBUSY; - if (!list_empty(&local->work_list)) { - /* wait for the work to finish/time out */ + if (req != local->int_scan_req && + sdata->vif.type == NL80211_IFTYPE_STATION && + !list_empty(&ifmgd->work_list)) { + /* actually wait for the work it's doing to finish/time out */ + set_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request); local->scan_req = req; local->scan_sdata = sdata; return 0; @@ -371,14 +468,6 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, local->hw_scan_req->ie = ies; local->hw_scan_band = 0; - - /* - * After allocating local->hw_scan_req, we must - * go through until ieee80211_prep_hw_scan(), so - * anything that might be changed here and leave - * this function early must not go after this - * allocation. - */ } local->scan_req = req; @@ -388,16 +477,15 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, __set_bit(SCAN_HW_SCANNING, &local->scanning); else __set_bit(SCAN_SW_SCANNING, &local->scanning); - /* * Kicking off the scan need not be protected, * only the scan variable stuff, since now * local->scan_req is assigned and other callers * will abort their scan attempts. * - * This avoids too many locking dependencies - * so that the scan completed calls have more - * locking freedom. + * This avoids getting a scan_mtx -> iflist_mtx + * dependency, so that the scan completed calls + * have more locking freedom. */ ieee80211_recalc_idle(local); @@ -440,7 +528,7 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local, /* check if at least one STA interface is associated */ mutex_lock(&local->iflist_mtx); list_for_each_entry(sdata, &local->interfaces, list) { - if (!ieee80211_sdata_running(sdata)) + if (!netif_running(sdata->dev)) continue; if (sdata->vif.type == NL80211_IFTYPE_STATION) { @@ -478,35 +566,56 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local, static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *local, unsigned long *next_delay) { - ieee80211_offchannel_stop_station(local); - - __set_bit(SCAN_OFF_CHANNEL, &local->scanning); + struct ieee80211_sub_if_data *sdata; /* - * What if the nullfunc frames didn't arrive? + * notify the AP about us leaving the channel and stop all STA interfaces */ - drv_flush(local, false); - if (local->ops->flush) - *next_delay = 0; - else - *next_delay = HZ / 10; + mutex_lock(&local->iflist_mtx); + list_for_each_entry(sdata, &local->interfaces, list) { + if (!netif_running(sdata->dev)) + continue; + + if (sdata->vif.type == NL80211_IFTYPE_STATION) { + netif_tx_stop_all_queues(sdata->dev); + if (sdata->u.mgd.associated) + ieee80211_scan_ps_enable(sdata); + } + } + mutex_unlock(&local->iflist_mtx); + + __set_bit(SCAN_OFF_CHANNEL, &local->scanning); /* advance to the next channel to be scanned */ + *next_delay = HZ / 10; local->next_scan_state = SCAN_SET_CHANNEL; } static void ieee80211_scan_state_enter_oper_channel(struct ieee80211_local *local, unsigned long *next_delay) { + struct ieee80211_sub_if_data *sdata = local->scan_sdata; + /* switch back to the operating channel */ local->scan_channel = NULL; ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); /* - * Only re-enable station mode interface now; beaconing will be - * re-enabled once the full scan has been completed. + * notify the AP about us being back and restart all STA interfaces */ - ieee80211_offchannel_return(local, false); + mutex_lock(&local->iflist_mtx); + list_for_each_entry(sdata, &local->interfaces, list) { + if (!netif_running(sdata->dev)) + continue; + + /* Tell AP we're back */ + if (sdata->vif.type == NL80211_IFTYPE_STATION) { + if (sdata->u.mgd.associated) + ieee80211_scan_ps_disable(sdata); + netif_tx_wake_all_queues(sdata->dev); + } + } + mutex_unlock(&local->iflist_mtx); __clear_bit(SCAN_OFF_CHANNEL, &local->scanning); @@ -620,7 +729,7 @@ void ieee80211_scan_work(struct work_struct *work) /* * Avoid re-scheduling when the sdata is going away. */ - if (!ieee80211_sdata_running(sdata)) { + if (!netif_running(sdata->dev)) { ieee80211_scan_completed(&local->hw, true); return; } diff --git a/trunk/net/mac80211/spectmgmt.c b/trunk/net/mac80211/spectmgmt.c index 7733f66ee2c4..aa743a895cf9 100644 --- a/trunk/net/mac80211/spectmgmt.c +++ b/trunk/net/mac80211/spectmgmt.c @@ -35,7 +35,7 @@ static void ieee80211_send_refuse_measurement_request(struct ieee80211_sub_if_da if (!skb) { printk(KERN_ERR "%s: failed to allocate buffer for " - "measurement report frame\n", sdata->name); + "measurement report frame\n", sdata->dev->name); return; } @@ -43,7 +43,7 @@ static void ieee80211_send_refuse_measurement_request(struct ieee80211_sub_if_da msr_report = (struct ieee80211_mgmt *)skb_put(skb, 24); memset(msr_report, 0, 24); memcpy(msr_report->da, da, ETH_ALEN); - memcpy(msr_report->sa, sdata->vif.addr, ETH_ALEN); + memcpy(msr_report->sa, sdata->dev->dev_addr, ETH_ALEN); memcpy(msr_report->bssid, bssid, ETH_ALEN); msr_report->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION); diff --git a/trunk/net/mac80211/sta_info.c b/trunk/net/mac80211/sta_info.c index 211c475f73c6..71f370dd24bc 100644 --- a/trunk/net/mac80211/sta_info.c +++ b/trunk/net/mac80211/sta_info.c @@ -32,33 +32,49 @@ * for faster lookup and a list for iteration. They are managed using * RCU, i.e. access to the list and hash table is protected by RCU. * - * Upon allocating a STA info structure with sta_info_alloc(), the caller - * owns that structure. It must then insert it into the hash table using - * either sta_info_insert() or sta_info_insert_rcu(); only in the latter - * case (which acquires an rcu read section but must not be called from - * within one) will the pointer still be valid after the call. Note that - * the caller may not do much with the STA info before inserting it, in - * particular, it may not start any mesh peer link management or add - * encryption keys. + * Upon allocating a STA info structure with sta_info_alloc(), the caller owns + * that structure. It must then either destroy it using sta_info_destroy() + * (which is pretty useless) or insert it into the hash table using + * sta_info_insert() which demotes the reference from ownership to a regular + * RCU-protected reference; if the function is called without protection by an + * RCU critical section the reference is instantly invalidated. Note that the + * caller may not do much with the STA info before inserting it, in particular, + * it may not start any mesh peer link management or add encryption keys. * * When the insertion fails (sta_info_insert()) returns non-zero), the * structure will have been freed by sta_info_insert()! * - * Station entries are added by mac80211 when you establish a link with a + * sta entries are added by mac80211 when you establish a link with a * peer. This means different things for the different type of interfaces * we support. For a regular station this mean we add the AP sta when we * receive an assocation response from the AP. For IBSS this occurs when - * get to know about a peer on the same IBSS. For WDS we add the sta for - * the peer imediately upon device open. When using AP mode we add stations - * for each respective station upon request from userspace through nl80211. + * we receive a probe response or a beacon from target IBSS network. For + * WDS we add the sta for the peer imediately upon device open. When using + * AP mode we add stations for each respective station upon request from + * userspace through nl80211. * - * In order to remove a STA info structure, various sta_info_destroy_*() - * calls are available. + * Because there are debugfs entries for each station, and adding those + * must be able to sleep, it is also possible to "pin" a station entry, + * that means it can be removed from the hash table but not be freed. + * See the comment in __sta_info_unlink() for more information, this is + * an internal capability only. * - * There is no concept of ownership on a STA entry, each structure is - * owned by the global hash table/list until it is removed. All users of - * the structure need to be RCU protected so that the structure won't be - * freed before they are done using it. + * In order to remove a STA info structure, the caller needs to first + * unlink it (sta_info_unlink()) from the list and hash tables and + * then destroy it; sta_info_destroy() will wait for an RCU grace period + * to elapse before actually freeing it. Due to the pinning and the + * possibility of multiple callers trying to remove the same STA info at + * the same time, sta_info_unlink() can clear the STA info pointer it is + * passed to indicate that the STA info is owned by somebody else now. + * + * If sta_info_unlink() did not clear the pointer then the caller owns + * the STA info structure now and is responsible of destroying it with + * a call to sta_info_destroy(). + * + * In all other cases, there is no concept of ownership on a STA entry, + * each structure is owned by the global hash table/list until it is + * removed. All users of the structure need to be RCU protected so that + * the structure won't be freed before they are done using it. */ /* Caller must hold local->sta_lock */ @@ -87,37 +103,13 @@ static int sta_info_hash_del(struct ieee80211_local *local, } /* protected by RCU */ -struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata, - const u8 *addr) +struct sta_info *sta_info_get(struct ieee80211_local *local, const u8 *addr) { - struct ieee80211_local *local = sdata->local; struct sta_info *sta; sta = rcu_dereference(local->sta_hash[STA_HASH(addr)]); while (sta) { - if (sta->sdata == sdata && - memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) - break; - sta = rcu_dereference(sta->hnext); - } - return sta; -} - -/* - * Get sta info either from the specified interface - * or from one of its vlans - */ -struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata, - const u8 *addr) -{ - struct ieee80211_local *local = sdata->local; - struct sta_info *sta; - - sta = rcu_dereference(local->sta_hash[STA_HASH(addr)]); - while (sta) { - if ((sta->sdata == sdata || - sta->sdata->bss == sdata->bss) && - memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) + if (memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) break; sta = rcu_dereference(sta->hnext); } @@ -169,6 +161,101 @@ static void __sta_info_free(struct ieee80211_local *local, kfree(sta); } +void sta_info_destroy(struct sta_info *sta) +{ + struct ieee80211_local *local; + struct sk_buff *skb; + int i; + + might_sleep(); + + if (!sta) + return; + + local = sta->local; + + cancel_work_sync(&sta->drv_unblock_wk); + + rate_control_remove_sta_debugfs(sta); + ieee80211_sta_debugfs_remove(sta); + +#ifdef CONFIG_MAC80211_MESH + if (ieee80211_vif_is_mesh(&sta->sdata->vif)) + mesh_plink_deactivate(sta); +#endif + + /* + * We have only unlinked the key, and actually destroying it + * may mean it is removed from hardware which requires that + * the key->sta pointer is still valid, so flush the key todo + * list here. + * + * ieee80211_key_todo() will synchronize_rcu() so after this + * nothing can reference this sta struct any more. + */ + ieee80211_key_todo(); + +#ifdef CONFIG_MAC80211_MESH + if (ieee80211_vif_is_mesh(&sta->sdata->vif)) + del_timer_sync(&sta->plink_timer); +#endif + + while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { + local->total_ps_buffered--; + dev_kfree_skb_any(skb); + } + + while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) + dev_kfree_skb_any(skb); + + for (i = 0; i < STA_TID_NUM; i++) { + struct tid_ampdu_rx *tid_rx; + struct tid_ampdu_tx *tid_tx; + + spin_lock_bh(&sta->lock); + tid_rx = sta->ampdu_mlme.tid_rx[i]; + /* Make sure timer won't free the tid_rx struct, see below */ + if (tid_rx) + tid_rx->shutdown = true; + + spin_unlock_bh(&sta->lock); + + /* + * Outside spinlock - shutdown is true now so that the timer + * won't free tid_rx, we have to do that now. Can't let the + * timer do it because we have to sync the timer outside the + * lock that it takes itself. + */ + if (tid_rx) { + del_timer_sync(&tid_rx->session_timer); + kfree(tid_rx); + } + + /* + * No need to do such complications for TX agg sessions, the + * path leading to freeing the tid_tx struct goes via a call + * from the driver, and thus needs to look up the sta struct + * again, which cannot be found when we get here. Hence, we + * just need to delete the timer and free the aggregation + * info; we won't be telling the peer about it then but that + * doesn't matter if we're not talking to it again anyway. + */ + tid_tx = sta->ampdu_mlme.tid_tx[i]; + if (tid_tx) { + del_timer_sync(&tid_tx->addba_resp_timer); + /* + * STA removed while aggregation session being + * started? Bit odd, but purge frames anyway. + */ + skb_queue_purge(&tid_tx->pending); + kfree(tid_tx); + } + } + + __sta_info_free(local, sta); +} + + /* Caller must hold local->sta_lock */ static void sta_info_hash_add(struct ieee80211_local *local, struct sta_info *sta) @@ -265,93 +352,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, return sta; } -static int sta_info_finish_insert(struct sta_info *sta, bool async) -{ - struct ieee80211_local *local = sta->local; - struct ieee80211_sub_if_data *sdata = sta->sdata; - struct station_info sinfo; - unsigned long flags; - int err = 0; - - WARN_ON(!mutex_is_locked(&local->sta_mtx)); - - /* notify driver */ - if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) - sdata = container_of(sdata->bss, - struct ieee80211_sub_if_data, - u.ap); - err = drv_sta_add(local, sdata, &sta->sta); - if (err) { - if (!async) - return err; - printk(KERN_DEBUG "%s: failed to add IBSS STA %pM to driver (%d)" - " - keeping it anyway.\n", - sdata->name, sta->sta.addr, err); - } else { - sta->uploaded = true; -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - if (async) - printk(KERN_DEBUG "%s: Finished adding IBSS STA %pM\n", - wiphy_name(local->hw.wiphy), sta->sta.addr); -#endif - } - - sdata = sta->sdata; - - if (!async) { - local->num_sta++; - local->sta_generation++; - smp_mb(); - - /* make the station visible */ - spin_lock_irqsave(&local->sta_lock, flags); - sta_info_hash_add(local, sta); - spin_unlock_irqrestore(&local->sta_lock, flags); - } - - list_add(&sta->list, &local->sta_list); - - ieee80211_sta_debugfs_add(sta); - rate_control_add_sta_debugfs(sta); - - sinfo.filled = 0; - sinfo.generation = local->sta_generation; - cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL); - - - return 0; -} - -static void sta_info_finish_pending(struct ieee80211_local *local) -{ - struct sta_info *sta; - unsigned long flags; - - spin_lock_irqsave(&local->sta_lock, flags); - while (!list_empty(&local->sta_pending_list)) { - sta = list_first_entry(&local->sta_pending_list, - struct sta_info, list); - list_del(&sta->list); - spin_unlock_irqrestore(&local->sta_lock, flags); - - sta_info_finish_insert(sta, true); - - spin_lock_irqsave(&local->sta_lock, flags); - } - spin_unlock_irqrestore(&local->sta_lock, flags); -} - -static void sta_info_finish_work(struct work_struct *work) -{ - struct ieee80211_local *local = - container_of(work, struct ieee80211_local, sta_finish_work); - - mutex_lock(&local->sta_mtx); - sta_info_finish_pending(local); - mutex_unlock(&local->sta_mtx); -} - -int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU) +int sta_info_insert(struct sta_info *sta) { struct ieee80211_local *local = sta->local; struct ieee80211_sub_if_data *sdata = sta->sdata; @@ -363,89 +364,38 @@ int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU) * something inserts a STA (on one CPU) without holding the RTNL * and another CPU turns off the net device. */ - if (unlikely(!ieee80211_sdata_running(sdata))) { + if (unlikely(!netif_running(sdata->dev))) { err = -ENETDOWN; - rcu_read_lock(); goto out_free; } - if (WARN_ON(compare_ether_addr(sta->sta.addr, sdata->vif.addr) == 0 || + if (WARN_ON(compare_ether_addr(sta->sta.addr, sdata->dev->dev_addr) == 0 || is_multicast_ether_addr(sta->sta.addr))) { err = -EINVAL; - rcu_read_lock(); goto out_free; } - /* - * In ad-hoc mode, we sometimes need to insert stations - * from tasklet context from the RX path. To avoid races, - * always do so in that case -- see the comment below. - */ - if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { - spin_lock_irqsave(&local->sta_lock, flags); - /* check if STA exists already */ - if (sta_info_get_bss(sdata, sta->sta.addr)) { - spin_unlock_irqrestore(&local->sta_lock, flags); - rcu_read_lock(); - err = -EEXIST; - goto out_free; - } - - local->num_sta++; - local->sta_generation++; - smp_mb(); - sta_info_hash_add(local, sta); - - list_add_tail(&sta->list, &local->sta_pending_list); - - rcu_read_lock(); - spin_unlock_irqrestore(&local->sta_lock, flags); - -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: Added IBSS STA %pM\n", - wiphy_name(local->hw.wiphy), sta->sta.addr); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ - - ieee80211_queue_work(&local->hw, &local->sta_finish_work); - - return 0; - } - - /* - * On first glance, this will look racy, because the code - * below this point, which inserts a station with sleeping, - * unlocks the sta_lock between checking existence in the - * hash table and inserting into it. - * - * However, it is not racy against itself because it keeps - * the mutex locked. It still seems to race against the - * above code that atomically inserts the station... That, - * however, is not true because the above code can only - * be invoked for IBSS interfaces, and the below code will - * not be -- and the two do not race against each other as - * the hash table also keys off the interface. - */ - - might_sleep(); - - mutex_lock(&local->sta_mtx); - spin_lock_irqsave(&local->sta_lock, flags); /* check if STA exists already */ - if (sta_info_get_bss(sdata, sta->sta.addr)) { + if (sta_info_get(local, sta->sta.addr)) { spin_unlock_irqrestore(&local->sta_lock, flags); - rcu_read_lock(); err = -EEXIST; goto out_free; } + list_add(&sta->list, &local->sta_list); + local->sta_generation++; + local->num_sta++; + sta_info_hash_add(local, sta); - spin_unlock_irqrestore(&local->sta_lock, flags); + /* notify driver */ + if (local->ops->sta_notify) { + if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) + sdata = container_of(sdata->bss, + struct ieee80211_sub_if_data, + u.ap); - err = sta_info_finish_insert(sta, false); - if (err) { - mutex_unlock(&local->sta_mtx); - rcu_read_lock(); - goto out_free; + drv_sta_notify(local, &sdata->vif, STA_NOTIFY_ADD, &sta->sta); + sdata = sta->sdata; } #ifdef CONFIG_MAC80211_VERBOSE_DEBUG @@ -453,9 +403,18 @@ int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU) wiphy_name(local->hw.wiphy), sta->sta.addr); #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ - /* move reference to rcu-protected */ - rcu_read_lock(); - mutex_unlock(&local->sta_mtx); + spin_unlock_irqrestore(&local->sta_lock, flags); + +#ifdef CONFIG_MAC80211_DEBUGFS + /* + * Debugfs entry adding might sleep, so schedule process + * context task for adding entry for STAs that do not yet + * have one. + * NOTE: due to auto-freeing semantics this may only be done + * if the insertion is successful! + */ + schedule_work(&local->sta_debugfs_add); +#endif if (ieee80211_vif_is_mesh(&sdata->vif)) mesh_accept_plinks_update(sdata); @@ -467,15 +426,6 @@ int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU) return err; } -int sta_info_insert(struct sta_info *sta) -{ - int err = sta_info_insert_rcu(sta); - - rcu_read_unlock(); - - return err; -} - static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid) { /* @@ -544,6 +494,108 @@ void sta_info_clear_tim_bit(struct sta_info *sta) spin_unlock_irqrestore(&sta->local->sta_lock, flags); } +static void __sta_info_unlink(struct sta_info **sta) +{ + struct ieee80211_local *local = (*sta)->local; + struct ieee80211_sub_if_data *sdata = (*sta)->sdata; + /* + * pull caller's reference if we're already gone. + */ + if (sta_info_hash_del(local, *sta)) { + *sta = NULL; + return; + } + + if ((*sta)->key) { + ieee80211_key_free((*sta)->key); + WARN_ON((*sta)->key); + } + + list_del(&(*sta)->list); + (*sta)->dead = true; + + if (test_and_clear_sta_flags(*sta, + WLAN_STA_PS_STA | WLAN_STA_PS_DRIVER)) { + BUG_ON(!sdata->bss); + + atomic_dec(&sdata->bss->num_sta_ps); + __sta_info_clear_tim_bit(sdata->bss, *sta); + } + + local->num_sta--; + local->sta_generation++; + + if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) + rcu_assign_pointer(sdata->u.vlan.sta, NULL); + + if (local->ops->sta_notify) { + if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) + sdata = container_of(sdata->bss, + struct ieee80211_sub_if_data, + u.ap); + + drv_sta_notify(local, &sdata->vif, STA_NOTIFY_REMOVE, + &(*sta)->sta); + sdata = (*sta)->sdata; + } + + if (ieee80211_vif_is_mesh(&sdata->vif)) { + mesh_accept_plinks_update(sdata); +#ifdef CONFIG_MAC80211_MESH + del_timer(&(*sta)->plink_timer); +#endif + } + +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG + printk(KERN_DEBUG "%s: Removed STA %pM\n", + wiphy_name(local->hw.wiphy), (*sta)->sta.addr); +#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ + + /* + * Finally, pull caller's reference if the STA is pinned by the + * task that is adding the debugfs entries. In that case, we + * leave the STA "to be freed". + * + * The rules are not trivial, but not too complex either: + * (1) pin_status is only modified under the sta_lock + * (2) STAs may only be pinned under the RTNL so that + * sta_info_flush() is guaranteed to actually destroy + * all STAs that are active for a given interface, this + * is required for correctness because otherwise we + * could notify a driver that an interface is going + * away and only after that (!) notify it about a STA + * on that interface going away. + * (3) sta_info_debugfs_add_work() will set the status + * to PINNED when it found an item that needs a new + * debugfs directory created. In that case, that item + * must not be freed although all *RCU* users are done + * with it. Hence, we tell the caller of _unlink() + * that the item is already gone (as can happen when + * two tasks try to unlink/destroy at the same time) + * (4) We set the pin_status to DESTROY here when we + * find such an item. + * (5) sta_info_debugfs_add_work() will reset the pin_status + * from PINNED to NORMAL when it is done with the item, + * but will check for DESTROY before resetting it in + * which case it will free the item. + */ + if ((*sta)->pin_status == STA_INFO_PIN_STAT_PINNED) { + (*sta)->pin_status = STA_INFO_PIN_STAT_DESTROY; + *sta = NULL; + return; + } +} + +void sta_info_unlink(struct sta_info **sta) +{ + struct ieee80211_local *local = (*sta)->local; + unsigned long flags; + + spin_lock_irqsave(&local->sta_lock, flags); + __sta_info_unlink(sta); + spin_unlock_irqrestore(&local->sta_lock, flags); +} + static int sta_info_buffer_expired(struct sta_info *sta, struct sk_buff *skb) { @@ -600,209 +652,109 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local, } } -static int __must_check __sta_info_destroy(struct sta_info *sta) -{ - struct ieee80211_local *local; - struct ieee80211_sub_if_data *sdata; - struct sk_buff *skb; - unsigned long flags; - int ret, i; - - might_sleep(); - - if (!sta) - return -ENOENT; - - local = sta->local; - sdata = sta->sdata; - - spin_lock_irqsave(&local->sta_lock, flags); - ret = sta_info_hash_del(local, sta); - /* this might still be the pending list ... which is fine */ - if (!ret) - list_del(&sta->list); - spin_unlock_irqrestore(&local->sta_lock, flags); - if (ret) - return ret; - - if (sta->key) { - ieee80211_key_free(sta->key); - /* - * We have only unlinked the key, and actually destroying it - * may mean it is removed from hardware which requires that - * the key->sta pointer is still valid, so flush the key todo - * list here. - * - * ieee80211_key_todo() will synchronize_rcu() so after this - * nothing can reference this sta struct any more. - */ - ieee80211_key_todo(); - - WARN_ON(sta->key); - } - - sta->dead = true; - - if (test_and_clear_sta_flags(sta, - WLAN_STA_PS_STA | WLAN_STA_PS_DRIVER)) { - BUG_ON(!sdata->bss); - - atomic_dec(&sdata->bss->num_sta_ps); - __sta_info_clear_tim_bit(sdata->bss, sta); - } - - local->num_sta--; - local->sta_generation++; - - if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) - rcu_assign_pointer(sdata->u.vlan.sta, NULL); - - if (sta->uploaded) { - if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) - sdata = container_of(sdata->bss, - struct ieee80211_sub_if_data, - u.ap); - drv_sta_remove(local, sdata, &sta->sta); - sdata = sta->sdata; - } - -#ifdef CONFIG_MAC80211_MESH - if (ieee80211_vif_is_mesh(&sdata->vif)) { - mesh_accept_plinks_update(sdata); - del_timer(&sta->plink_timer); - } -#endif - -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: Removed STA %pM\n", - wiphy_name(local->hw.wiphy), sta->sta.addr); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ - cancel_work_sync(&sta->drv_unblock_wk); - - rate_control_remove_sta_debugfs(sta); - ieee80211_sta_debugfs_remove(sta); - -#ifdef CONFIG_MAC80211_MESH - if (ieee80211_vif_is_mesh(&sta->sdata->vif)) { - mesh_plink_deactivate(sta); - del_timer_sync(&sta->plink_timer); - } -#endif - while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { - local->total_ps_buffered--; - dev_kfree_skb_any(skb); - } - - while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) - dev_kfree_skb_any(skb); - - for (i = 0; i < STA_TID_NUM; i++) { - struct tid_ampdu_rx *tid_rx; - struct tid_ampdu_tx *tid_tx; - - spin_lock_bh(&sta->lock); - tid_rx = sta->ampdu_mlme.tid_rx[i]; - /* Make sure timer won't free the tid_rx struct, see below */ - if (tid_rx) - tid_rx->shutdown = true; - - spin_unlock_bh(&sta->lock); - - /* - * Outside spinlock - shutdown is true now so that the timer - * won't free tid_rx, we have to do that now. Can't let the - * timer do it because we have to sync the timer outside the - * lock that it takes itself. - */ - if (tid_rx) { - del_timer_sync(&tid_rx->session_timer); - kfree(tid_rx); - } +static void sta_info_cleanup(unsigned long data) +{ + struct ieee80211_local *local = (struct ieee80211_local *) data; + struct sta_info *sta; - /* - * No need to do such complications for TX agg sessions, the - * path leading to freeing the tid_tx struct goes via a call - * from the driver, and thus needs to look up the sta struct - * again, which cannot be found when we get here. Hence, we - * just need to delete the timer and free the aggregation - * info; we won't be telling the peer about it then but that - * doesn't matter if we're not talking to it again anyway. - */ - tid_tx = sta->ampdu_mlme.tid_tx[i]; - if (tid_tx) { - del_timer_sync(&tid_tx->addba_resp_timer); - /* - * STA removed while aggregation session being - * started? Bit odd, but purge frames anyway. - */ - skb_queue_purge(&tid_tx->pending); - kfree(tid_tx); - } - } + rcu_read_lock(); + list_for_each_entry_rcu(sta, &local->sta_list, list) + sta_info_cleanup_expire_buffered(local, sta); + rcu_read_unlock(); - __sta_info_free(local, sta); + if (local->quiescing) + return; - return 0; + local->sta_cleanup.expires = + round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); + add_timer(&local->sta_cleanup); } -int sta_info_destroy_addr(struct ieee80211_sub_if_data *sdata, const u8 *addr) +#ifdef CONFIG_MAC80211_DEBUGFS +/* + * See comment in __sta_info_unlink, + * caller must hold local->sta_lock. + */ +static void __sta_info_pin(struct sta_info *sta) { - struct sta_info *sta; - int ret; - - mutex_lock(&sdata->local->sta_mtx); - sta = sta_info_get(sdata, addr); - ret = __sta_info_destroy(sta); - mutex_unlock(&sdata->local->sta_mtx); - - return ret; + WARN_ON(sta->pin_status != STA_INFO_PIN_STAT_NORMAL); + sta->pin_status = STA_INFO_PIN_STAT_PINNED; } -int sta_info_destroy_addr_bss(struct ieee80211_sub_if_data *sdata, - const u8 *addr) +/* + * See comment in __sta_info_unlink, returns sta if it + * needs to be destroyed. + */ +static struct sta_info *__sta_info_unpin(struct sta_info *sta) { - struct sta_info *sta; - int ret; + struct sta_info *ret = NULL; + unsigned long flags; - mutex_lock(&sdata->local->sta_mtx); - sta = sta_info_get_bss(sdata, addr); - ret = __sta_info_destroy(sta); - mutex_unlock(&sdata->local->sta_mtx); + spin_lock_irqsave(&sta->local->sta_lock, flags); + WARN_ON(sta->pin_status != STA_INFO_PIN_STAT_DESTROY && + sta->pin_status != STA_INFO_PIN_STAT_PINNED); + if (sta->pin_status == STA_INFO_PIN_STAT_DESTROY) + ret = sta; + sta->pin_status = STA_INFO_PIN_STAT_NORMAL; + spin_unlock_irqrestore(&sta->local->sta_lock, flags); return ret; } -static void sta_info_cleanup(unsigned long data) +static void sta_info_debugfs_add_work(struct work_struct *work) { - struct ieee80211_local *local = (struct ieee80211_local *) data; - struct sta_info *sta; + struct ieee80211_local *local = + container_of(work, struct ieee80211_local, sta_debugfs_add); + struct sta_info *sta, *tmp; + unsigned long flags; - rcu_read_lock(); - list_for_each_entry_rcu(sta, &local->sta_list, list) - sta_info_cleanup_expire_buffered(local, sta); - rcu_read_unlock(); + /* We need to keep the RTNL across the whole pinned status. */ + rtnl_lock(); + while (1) { + sta = NULL; - if (local->quiescing) - return; + spin_lock_irqsave(&local->sta_lock, flags); + list_for_each_entry(tmp, &local->sta_list, list) { + /* + * debugfs.add_has_run will be set by + * ieee80211_sta_debugfs_add regardless + * of what else it does. + */ + if (!tmp->debugfs.add_has_run) { + sta = tmp; + __sta_info_pin(sta); + break; + } + } + spin_unlock_irqrestore(&local->sta_lock, flags); - local->sta_cleanup.expires = - round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); - add_timer(&local->sta_cleanup); + if (!sta) + break; + + ieee80211_sta_debugfs_add(sta); + rate_control_add_sta_debugfs(sta); + + sta = __sta_info_unpin(sta); + sta_info_destroy(sta); + } + rtnl_unlock(); } +#endif void sta_info_init(struct ieee80211_local *local) { spin_lock_init(&local->sta_lock); - mutex_init(&local->sta_mtx); INIT_LIST_HEAD(&local->sta_list); - INIT_LIST_HEAD(&local->sta_pending_list); - INIT_WORK(&local->sta_finish_work, sta_info_finish_work); setup_timer(&local->sta_cleanup, sta_info_cleanup, (unsigned long)local); local->sta_cleanup.expires = round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); + +#ifdef CONFIG_MAC80211_DEBUGFS + INIT_WORK(&local->sta_debugfs_add, sta_info_debugfs_add_work); +#endif } int sta_info_start(struct ieee80211_local *local) @@ -814,6 +766,16 @@ int sta_info_start(struct ieee80211_local *local) void sta_info_stop(struct ieee80211_local *local) { del_timer(&local->sta_cleanup); +#ifdef CONFIG_MAC80211_DEBUGFS + /* + * Make sure the debugfs adding work isn't pending after this + * because we're about to be destroyed. It doesn't matter + * whether it ran or not since we're going to flush all STAs + * anyway. + */ + cancel_work_sync(&local->sta_debugfs_add); +#endif + sta_info_flush(local, NULL); } @@ -829,19 +791,26 @@ int sta_info_flush(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata) { struct sta_info *sta, *tmp; + LIST_HEAD(tmp_list); int ret = 0; + unsigned long flags; might_sleep(); - mutex_lock(&local->sta_mtx); - - sta_info_finish_pending(local); - + spin_lock_irqsave(&local->sta_lock, flags); list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { - if (!sdata || sdata == sta->sdata) - WARN_ON(__sta_info_destroy(sta)); + if (!sdata || sdata == sta->sdata) { + __sta_info_unlink(&sta); + if (sta) { + list_add_tail(&sta->list, &tmp_list); + ret++; + } + } } - mutex_unlock(&local->sta_mtx); + spin_unlock_irqrestore(&local->sta_lock, flags); + + list_for_each_entry_safe(sta, tmp, &tmp_list, list) + sta_info_destroy(sta); return ret; } @@ -851,28 +820,34 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, { struct ieee80211_local *local = sdata->local; struct sta_info *sta, *tmp; + LIST_HEAD(tmp_list); + unsigned long flags; - mutex_lock(&local->sta_mtx); + spin_lock_irqsave(&local->sta_lock, flags); list_for_each_entry_safe(sta, tmp, &local->sta_list, list) if (time_after(jiffies, sta->last_rx + exp_time)) { #ifdef CONFIG_MAC80211_IBSS_DEBUG printk(KERN_DEBUG "%s: expiring inactive STA %pM\n", - sdata->name, sta->sta.addr); + sdata->dev->name, sta->sta.addr); #endif - WARN_ON(__sta_info_destroy(sta)); + __sta_info_unlink(&sta); + if (sta) + list_add(&sta->list, &tmp_list); } - mutex_unlock(&local->sta_mtx); + spin_unlock_irqrestore(&local->sta_lock, flags); + + list_for_each_entry_safe(sta, tmp, &tmp_list, list) + sta_info_destroy(sta); } struct ieee80211_sta *ieee80211_find_sta_by_hw(struct ieee80211_hw *hw, const u8 *addr) { - struct sta_info *sta, *nxt; + struct sta_info *sta = sta_info_get(hw_to_local(hw), addr); - /* Just return a random station ... first in list ... */ - for_each_sta_info(hw_to_local(hw), addr, sta, nxt) - return &sta->sta; - return NULL; + if (!sta) + return NULL; + return &sta->sta; } EXPORT_SYMBOL_GPL(ieee80211_find_sta_by_hw); @@ -897,7 +872,7 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) struct ieee80211_local *local = sdata->local; int sent, buffered; - drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta); + drv_sta_notify(local, &sdata->vif, STA_NOTIFY_AWAKE, &sta->sta); if (!skb_queue_empty(&sta->ps_tx_buf)) sta_info_clear_tim_bit(sta); @@ -910,7 +885,7 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "%s: STA %pM aid %d sending %d filtered/%d PS frames " - "since STA not sleeping anymore\n", sdata->name, + "since STA not sleeping anymore\n", sdata->dev->name, sta->sta.addr, sta->sta.aid, sent - buffered, buffered); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ } @@ -969,7 +944,7 @@ void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta) */ printk(KERN_DEBUG "%s: STA %pM sent PS Poll even " "though there are no buffered frames for it\n", - sdata->name, sta->sta.addr); + sdata->dev->name, sta->sta.addr); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ } } diff --git a/trunk/net/mac80211/sta_info.h b/trunk/net/mac80211/sta_info.h index 822d84522937..b4810f6aa94f 100644 --- a/trunk/net/mac80211/sta_info.h +++ b/trunk/net/mac80211/sta_info.h @@ -42,9 +42,6 @@ * be in the queues * @WLAN_STA_PSPOLL: Station sent PS-poll while driver was keeping * station in power-save mode, reply when the driver unblocks. - * @WLAN_STA_DISASSOC: Disassociation in progress. - * This is used to reject TX BA session requests when disassociation - * is in progress. */ enum ieee80211_sta_info_flags { WLAN_STA_AUTH = 1<<0, @@ -60,7 +57,6 @@ enum ieee80211_sta_info_flags { WLAN_STA_SUSPEND = 1<<11, WLAN_STA_PS_DRIVER = 1<<12, WLAN_STA_PSPOLL = 1<<13, - WLAN_STA_DISASSOC = 1<<14, }; #define STA_TID_NUM 16 @@ -166,6 +162,11 @@ struct sta_ampdu_mlme { }; +/* see __sta_info_unlink */ +#define STA_INFO_PIN_STAT_NORMAL 0 +#define STA_INFO_PIN_STAT_PINNED 1 +#define STA_INFO_PIN_STAT_DESTROY 2 + /** * struct sta_info - STA information * @@ -186,6 +187,7 @@ struct sta_ampdu_mlme { * @flaglock: spinlock for flags accesses * @drv_unblock_wk: used for driver PS unblocking * @listen_interval: listen interval of this station, when we're acting as AP + * @pin_status: used internally for pinning a STA struct into memory * @flags: STA flags, see &enum ieee80211_sta_info_flags * @ps_tx_buf: buffer of frames to transmit to this station * when it leaves power saving state @@ -224,7 +226,6 @@ struct sta_ampdu_mlme { * @debugfs: debug filesystem info * @sta: station information we share with the driver * @dead: set to true when sta is unlinked - * @uploaded: set to true when sta is uploaded to the driver */ struct sta_info { /* General information, mostly static */ @@ -244,7 +245,11 @@ struct sta_info { bool dead; - bool uploaded; + /* + * for use by the internal lifetime management, + * see __sta_info_unlink + */ + u8 pin_status; /* * frequently updated, locked with own spinlock (flaglock), @@ -398,37 +403,9 @@ static inline u32 get_sta_flags(struct sta_info *sta) #define STA_INFO_CLEANUP_INTERVAL (10 * HZ) /* - * Get a STA info, must be under RCU read lock. + * Get a STA info, must have be under RCU read lock. */ -struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata, - const u8 *addr); - -struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata, - const u8 *addr); - -static inline -void for_each_sta_info_type_check(struct ieee80211_local *local, - const u8 *addr, - struct sta_info *sta, - struct sta_info *nxt) -{ -} - -#define for_each_sta_info(local, _addr, sta, nxt) \ - for ( /* initialise loop */ \ - sta = rcu_dereference(local->sta_hash[STA_HASH(_addr)]),\ - nxt = sta ? rcu_dereference(sta->hnext) : NULL; \ - /* typecheck */ \ - for_each_sta_info_type_check(local, (_addr), sta, nxt), \ - /* continue condition */ \ - sta; \ - /* advance loop */ \ - sta = nxt, \ - nxt = sta ? rcu_dereference(sta->hnext) : NULL \ - ) \ - /* compare address and run code only if it matches */ \ - if (memcmp(sta->sta.addr, (_addr), ETH_ALEN) == 0) - +struct sta_info *sta_info_get(struct ieee80211_local *local, const u8 *addr); /* * Get STA info by index, BROKEN! */ @@ -444,19 +421,18 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, * Insert STA info into hash table/list, returns zero or a * -EEXIST if (if the same MAC address is already present). * - * Calling the non-rcu version makes the caller relinquish, - * the _rcu version calls read_lock_rcu() and must be called - * without it held. + * Calling this without RCU protection makes the caller + * relinquish its reference to @sta. */ int sta_info_insert(struct sta_info *sta); -int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU); -int sta_info_insert_atomic(struct sta_info *sta); - -int sta_info_destroy_addr(struct ieee80211_sub_if_data *sdata, - const u8 *addr); -int sta_info_destroy_addr_bss(struct ieee80211_sub_if_data *sdata, - const u8 *addr); +/* + * Unlink a STA info from the hash table/list. + * This can NULL the STA pointer if somebody else + * has already unlinked it. + */ +void sta_info_unlink(struct sta_info **sta); +void sta_info_destroy(struct sta_info *sta); void sta_info_set_tim_bit(struct sta_info *sta); void sta_info_clear_tim_bit(struct sta_info *sta); diff --git a/trunk/net/mac80211/status.c b/trunk/net/mac80211/status.c index 56d5b9a6ec5b..d78f36c64c7b 100644 --- a/trunk/net/mac80211/status.c +++ b/trunk/net/mac80211/status.c @@ -2,7 +2,7 @@ * Copyright 2002-2005, Instant802 Networks, Inc. * Copyright 2005-2006, Devicescape Software, Inc. * Copyright 2006-2007 Jiri Benc - * Copyright 2008-2010 Johannes Berg + * Copyright 2008-2009 Johannes Berg * * 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 @@ -45,19 +45,29 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); /* - * This skb 'survived' a round-trip through the driver, and - * hopefully the driver didn't mangle it too badly. However, - * we can definitely not rely on the the control information - * being correct. Clear it so we don't get junk there, and - * indicate that it needs new processing, but must not be - * modified/encrypted again. + * XXX: This is temporary! + * + * The problem here is that when we get here, the driver will + * quite likely have pretty much overwritten info->control by + * using info->driver_data or info->rate_driver_data. Thus, + * when passing out the frame to the driver again, we would be + * passing completely bogus data since the driver would then + * expect a properly filled info->control. In mac80211 itself + * the same problem occurs, since we need info->control.vif + * internally. + * + * To fix this, we should send the frame through TX processing + * again. However, it's not that simple, since the frame will + * have been software-encrypted (if applicable) already, and + * encrypting it again doesn't do much good. So to properly do + * that, we not only have to skip the actual 'raw' encryption + * (key selection etc. still has to be done!) but also the + * sequence number assignment since that impacts the crypto + * encapsulation, of course. + * + * Hence, for now, fix the bug by just dropping the frame. */ - memset(&info->control, 0, sizeof(info->control)); - - info->control.jiffies = jiffies; - info->control.vif = &sta->sdata->vif; - info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING | - IEEE80211_TX_INTFL_RETRANSMISSION; + goto drop; sta->tx_filtered_count++; @@ -112,6 +122,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, return; } + drop: #ifdef CONFIG_MAC80211_VERBOSE_DEBUG if (net_ratelimit()) printk(KERN_DEBUG "%s: dropped TX filtered frame, " @@ -123,40 +134,6 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, dev_kfree_skb(skb); } -static void ieee80211_frame_acked(struct sta_info *sta, struct sk_buff *skb) -{ - struct ieee80211_mgmt *mgmt = (void *) skb->data; - struct ieee80211_local *local = sta->local; - struct ieee80211_sub_if_data *sdata = sta->sdata; - - if (ieee80211_is_action(mgmt->frame_control) && - sdata->vif.type == NL80211_IFTYPE_STATION && - mgmt->u.action.category == WLAN_CATEGORY_HT && - mgmt->u.action.u.ht_smps.action == WLAN_HT_ACTION_SMPS) { - /* - * This update looks racy, but isn't -- if we come - * here we've definitely got a station that we're - * talking to, and on a managed interface that can - * only be the AP. And the only other place updating - * this variable is before we're associated. - */ - switch (mgmt->u.action.u.ht_smps.smps_control) { - case WLAN_HT_SMPS_CONTROL_DYNAMIC: - sta->sdata->u.mgd.ap_smps = IEEE80211_SMPS_DYNAMIC; - break; - case WLAN_HT_SMPS_CONTROL_STATIC: - sta->sdata->u.mgd.ap_smps = IEEE80211_SMPS_STATIC; - break; - case WLAN_HT_SMPS_CONTROL_DISABLED: - default: /* shouldn't happen since we don't send that */ - sta->sdata->u.mgd.ap_smps = IEEE80211_SMPS_OFF; - break; - } - - ieee80211_queue_work(&local->hw, &local->recalc_smps); - } -} - void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) { struct sk_buff *skb2; @@ -169,7 +146,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) struct ieee80211_tx_status_rtap_hdr *rthdr; struct ieee80211_sub_if_data *sdata; struct net_device *prev_dev = NULL; - struct sta_info *sta, *tmp; + struct sta_info *sta; int retry_count = -1, i; bool injected; @@ -188,13 +165,10 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) rcu_read_lock(); sband = local->hw.wiphy->bands[info->band]; - fc = hdr->frame_control; - for_each_sta_info(local, hdr->addr1, sta, tmp) { - /* skip wrong virtual interface */ - if (memcmp(hdr->addr2, sta->sdata->vif.addr, ETH_ALEN)) - continue; + sta = sta_info_get(local, hdr->addr1); + if (sta) { if (!(info->flags & IEEE80211_TX_STAT_ACK) && test_sta_flags(sta, WLAN_STA_PS_STA)) { /* @@ -206,6 +180,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) return; } + fc = hdr->frame_control; + if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) && (ieee80211_is_data_qos(fc))) { u16 tid, ssn; @@ -232,10 +208,6 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) rate_control_tx_status(local, sband, sta, skb); if (ieee80211_vif_is_mesh(&sta->sdata->vif)) ieee80211s_update_metric(local, sta, skb); - - if (!(info->flags & IEEE80211_TX_CTL_INJECTED) && - (info->flags & IEEE80211_TX_STAT_ACK)) - ieee80211_frame_acked(sta, skb); } rcu_read_unlock(); @@ -274,25 +246,6 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) local->dot11FailedCount++; } - if (ieee80211_is_nullfunc(fc) && ieee80211_has_pm(fc) && - (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) && - !(info->flags & IEEE80211_TX_CTL_INJECTED) && - local->ps_sdata && !(local->scanning)) { - if (info->flags & IEEE80211_TX_STAT_ACK) { - local->ps_sdata->u.mgd.flags |= - IEEE80211_STA_NULLFUNC_ACKED; - ieee80211_queue_work(&local->hw, - &local->dynamic_ps_enable_work); - } else - mod_timer(&local->dynamic_ps_timer, jiffies + - msecs_to_jiffies(10)); - } - - if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) - cfg80211_action_tx_status( - skb->dev, (unsigned long) skb, skb->data, skb->len, - !!(info->flags & IEEE80211_TX_STAT_ACK), GFP_ATOMIC); - /* this was a transmitted frame, but now we want to reuse it */ skb_orphan(skb); @@ -358,7 +311,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) rcu_read_lock(); list_for_each_entry_rcu(sdata, &local->interfaces, list) { if (sdata->vif.type == NL80211_IFTYPE_MONITOR) { - if (!ieee80211_sdata_running(sdata)) + if (!netif_running(sdata->dev)) continue; if ((sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) && diff --git a/trunk/net/mac80211/tkip.c b/trunk/net/mac80211/tkip.c index 7ef491e9d66d..4921d724b6c7 100644 --- a/trunk/net/mac80211/tkip.c +++ b/trunk/net/mac80211/tkip.c @@ -100,7 +100,7 @@ static void tkip_mixing_phase1(const u8 *tk, struct tkip_ctx *ctx, p1k[3] += tkipS(p1k[2] ^ get_unaligned_le16(tk + 12 + j)); p1k[4] += tkipS(p1k[3] ^ get_unaligned_le16(tk + 0 + j)) + i; } - ctx->state = TKIP_STATE_PHASE1_DONE; + ctx->initialized = 1; } static void tkip_mixing_phase2(const u8 *tk, struct tkip_ctx *ctx, @@ -183,7 +183,7 @@ void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf, /* Update the p1k only when the iv16 in the packet wraps around, this * might occur after the wrap around of iv16 in the key in case of * fragmented packets. */ - if (iv16 == 0 || ctx->state == TKIP_STATE_NOT_INIT) + if (iv16 == 0 || !ctx->initialized) tkip_mixing_phase1(tk, ctx, hdr->addr2, iv32); if (type == IEEE80211_TKIP_P1_KEY) { @@ -195,13 +195,11 @@ void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf, } EXPORT_SYMBOL(ieee80211_get_tkip_key); -/* - * Encrypt packet payload with TKIP using @key. @pos is a pointer to the +/* Encrypt packet payload with TKIP using @key. @pos is a pointer to the * beginning of the buffer containing payload. This payload must include - * the IV/Ext.IV and space for (taildroom) four octets for ICV. - * @payload_len is the length of payload (_not_ including IV/ICV length). - * @ta is the transmitter addresses. - */ + * headroom of eight octets for IV and Ext. IV and taildroom of four octets + * for ICV. @payload_len is the length of payload (_not_ including extra + * headroom and tailroom). @ta is the transmitter addresses. */ void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm, struct ieee80211_key *key, u8 *pos, size_t payload_len, u8 *ta) @@ -211,11 +209,12 @@ void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm, const u8 *tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY]; /* Calculate per-packet key */ - if (ctx->iv16 == 0 || ctx->state == TKIP_STATE_NOT_INIT) + if (ctx->iv16 == 0 || !ctx->initialized) tkip_mixing_phase1(tk, ctx, ta, ctx->iv32); tkip_mixing_phase2(tk, ctx, ctx->iv16, rc4key); + pos = ieee80211_tkip_add_iv(pos, key, key->u.tkip.tx.iv16); ieee80211_wep_encrypt_data(tfm, rc4key, 16, pos, payload_len); } @@ -260,7 +259,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, if ((keyid >> 6) != key->conf.keyidx) return TKIP_DECRYPT_INVALID_KEYIDX; - if (key->u.tkip.rx[queue].state != TKIP_STATE_NOT_INIT && + if (key->u.tkip.rx[queue].initialized && (iv32 < key->u.tkip.rx[queue].iv32 || (iv32 == key->u.tkip.rx[queue].iv32 && iv16 <= key->u.tkip.rx[queue].iv16))) { @@ -276,11 +275,11 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, if (only_iv) { res = TKIP_DECRYPT_OK; - key->u.tkip.rx[queue].state = TKIP_STATE_PHASE1_HW_UPLOADED; + key->u.tkip.rx[queue].initialized = 1; goto done; } - if (key->u.tkip.rx[queue].state == TKIP_STATE_NOT_INIT || + if (!key->u.tkip.rx[queue].initialized || key->u.tkip.rx[queue].iv32 != iv32) { /* IV16 wrapped around - perform TKIP phase 1 */ tkip_mixing_phase1(tk, &key->u.tkip.rx[queue], ta, iv32); @@ -300,18 +299,18 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, printk("\n"); } #endif - } - if (key->local->ops->update_tkip_key && - key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE && - key->u.tkip.rx[queue].state != TKIP_STATE_PHASE1_HW_UPLOADED) { - struct ieee80211_sub_if_data *sdata = key->sdata; - - if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) - sdata = container_of(key->sdata->bss, - struct ieee80211_sub_if_data, u.ap); - drv_update_tkip_key(key->local, sdata, &key->conf, key->sta, - iv32, key->u.tkip.rx[queue].p1k); - key->u.tkip.rx[queue].state = TKIP_STATE_PHASE1_HW_UPLOADED; + if (key->local->ops->update_tkip_key && + key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { + static const u8 bcast[ETH_ALEN] = + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + const u8 *sta_addr = key->sta->sta.addr; + + if (is_multicast_ether_addr(ra)) + sta_addr = bcast; + + drv_update_tkip_key(key->local, &key->conf, sta_addr, + iv32, key->u.tkip.rx[queue].p1k); + } } tkip_mixing_phase2(tk, &key->u.tkip.rx[queue], iv16, rc4key); diff --git a/trunk/net/mac80211/tx.c b/trunk/net/mac80211/tx.c index cbe53ed4fb0b..ac210b586702 100644 --- a/trunk/net/mac80211/tx.c +++ b/trunk/net/mac80211/tx.c @@ -180,71 +180,6 @@ static int inline is_ieee80211_device(struct ieee80211_local *local, } /* tx handlers */ -static ieee80211_tx_result debug_noinline -ieee80211_tx_h_dynamic_ps(struct ieee80211_tx_data *tx) -{ - struct ieee80211_local *local = tx->local; - struct ieee80211_if_managed *ifmgd; - - /* driver doesn't support power save */ - if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS)) - return TX_CONTINUE; - - /* hardware does dynamic power save */ - if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) - return TX_CONTINUE; - - /* dynamic power save disabled */ - if (local->hw.conf.dynamic_ps_timeout <= 0) - return TX_CONTINUE; - - /* we are scanning, don't enable power save */ - if (local->scanning) - return TX_CONTINUE; - - if (!local->ps_sdata) - return TX_CONTINUE; - - /* No point if we're going to suspend */ - if (local->quiescing) - return TX_CONTINUE; - - /* dynamic ps is supported only in managed mode */ - if (tx->sdata->vif.type != NL80211_IFTYPE_STATION) - return TX_CONTINUE; - - ifmgd = &tx->sdata->u.mgd; - - /* - * Don't wakeup from power save if u-apsd is enabled, voip ac has - * u-apsd enabled and the frame is in voip class. This effectively - * means that even if all access categories have u-apsd enabled, in - * practise u-apsd is only used with the voip ac. This is a - * workaround for the case when received voip class packets do not - * have correct qos tag for some reason, due the network or the - * peer application. - * - * Note: local->uapsd_queues access is racy here. If the value is - * changed via debugfs, user needs to reassociate manually to have - * everything in sync. - */ - if ((ifmgd->flags & IEEE80211_STA_UAPSD_ENABLED) - && (local->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) - && skb_get_queue_mapping(tx->skb) == 0) - return TX_CONTINUE; - - if (local->hw.conf.flags & IEEE80211_CONF_PS) { - ieee80211_stop_queues_by_reason(&local->hw, - IEEE80211_QUEUE_STOP_REASON_PS); - ieee80211_queue_work(&local->hw, - &local->dynamic_ps_disable_work); - } - - mod_timer(&local->dynamic_ps_timer, jiffies + - msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout)); - - return TX_CONTINUE; -} static ieee80211_tx_result debug_noinline ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) @@ -288,7 +223,7 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) #ifdef CONFIG_MAC80211_VERBOSE_DEBUG printk(KERN_DEBUG "%s: dropped data frame to not " "associated station %pM\n", - tx->sdata->name, hdr->addr1); + tx->dev->name, hdr->addr1); #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ I802_DEBUG_INC(tx->local->tx_handlers_drop_not_assoc); return TX_DROP; @@ -396,7 +331,7 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx) #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG if (net_ratelimit()) printk(KERN_DEBUG "%s: BC TX buffer full - dropping the oldest frame\n", - tx->sdata->name); + tx->dev->name); #endif dev_kfree_skb(skb_dequeue(&tx->sdata->bss->ps_bc_buf)); } else @@ -456,7 +391,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) if (net_ratelimit()) { printk(KERN_DEBUG "%s: STA %pM TX " "buffer full - dropping oldest frame\n", - tx->sdata->name, sta->sta.addr); + tx->dev->name, sta->sta.addr); } #endif dev_kfree_skb(old); @@ -481,7 +416,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG else if (unlikely(staflags & WLAN_STA_PS_STA)) { printk(KERN_DEBUG "%s: STA %pM in PS mode, but pspoll " - "set -> send frame\n", tx->sdata->name, + "set -> send frame\n", tx->dev->name, sta->sta.addr); } #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ @@ -529,8 +464,6 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) tx->key = NULL; if (tx->key) { - bool skip_hw = false; - tx->key->tx_rx_count++; /* TODO: add threshold stuff again */ @@ -547,32 +480,16 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) !ieee80211_use_mfp(hdr->frame_control, tx->sta, tx->skb)) tx->key = NULL; - else - skip_hw = (tx->key->conf.flags & - IEEE80211_KEY_FLAG_SW_MGMT) && - ieee80211_is_mgmt(hdr->frame_control); break; case ALG_AES_CMAC: if (!ieee80211_is_mgmt(hdr->frame_control)) tx->key = NULL; break; } - - if (!skip_hw && tx->key && - tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) - info->control.hw_key = &tx->key->conf; } - return TX_CONTINUE; -} - -static ieee80211_tx_result debug_noinline -ieee80211_tx_h_sta(struct ieee80211_tx_data *tx) -{ - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); - - if (tx->sta && tx->sta->uploaded) - info->control.sta = &tx->sta->sta; + if (!tx->key || !(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) + info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; return TX_CONTINUE; } @@ -602,12 +519,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) txrc.bss_conf = &tx->sdata->vif.bss_conf; txrc.skb = tx->skb; txrc.reported_rate.idx = -1; - txrc.rate_idx_mask = tx->sdata->rc_rateidx_mask[tx->channel->band]; - if (txrc.rate_idx_mask == (1 << sband->n_bitrates) - 1) - txrc.max_rate_idx = -1; - else - txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1; - txrc.ap = tx->sdata->vif.type == NL80211_IFTYPE_AP; + txrc.max_rate_idx = tx->sdata->max_ratectrl_rateidx; /* set up RTS protection if desired */ if (len > tx->local->hw.wiphy->rts_threshold) { @@ -637,7 +549,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) "%s: Dropped data frame as no usable bitrate found while " "scanning and associated. Target station: " "%pM on %d GHz band\n", - tx->sdata->name, hdr->addr1, + tx->dev->name, hdr->addr1, tx->channel->band ? 5 : 2)) return TX_DROP; @@ -751,6 +663,17 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) 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; + + return TX_CONTINUE; +} + static ieee80211_tx_result debug_noinline ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx) { @@ -1010,8 +933,7 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, (struct ieee80211_radiotap_header *) skb->data; struct ieee80211_supported_band *sband; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len, - NULL); + int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len); sband = tx->local->hw.wiphy->bands[tx->channel->band]; @@ -1047,7 +969,7 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, * because it will be recomputed and added * on transmission */ - if (skb->len < (iterator._max_length + FCS_LEN)) + if (skb->len < (iterator.max_length + FCS_LEN)) return false; skb_trim(skb, skb->len - FCS_LEN); @@ -1074,10 +996,10 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, /* * remove the radiotap header - * iterator->_max_length was sanity-checked against + * iterator->max_length was sanity-checked against * skb->len by iterator init */ - skb_pull(skb, iterator._max_length); + skb_pull(skb, iterator.max_length); return true; } @@ -1099,6 +1021,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, memset(tx, 0, sizeof(*tx)); tx->skb = skb; + tx->dev = sdata->dev; /* use original interface */ tx->local = local; tx->sdata = sdata; tx->channel = local->hw.conf.channel; @@ -1109,7 +1032,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, tx->flags |= IEEE80211_TX_FRAGMENTED; /* process and remove the injection radiotap header */ - if (unlikely(info->flags & IEEE80211_TX_INTFL_HAS_RADIOTAP)) { + if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED)) { if (!__ieee80211_parse_tx_radiotap(tx, skb)) return TX_DROP; @@ -1118,7 +1041,6 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, * the radiotap header that was present and pre-filled * 'tx' with tx control information. */ - info->flags &= ~IEEE80211_TX_INTFL_HAS_RADIOTAP; } /* @@ -1130,15 +1052,10 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, hdr = (struct ieee80211_hdr *) skb->data; - if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { + if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) tx->sta = rcu_dereference(sdata->u.vlan.sta); - if (!tx->sta && sdata->dev->ieee80211_ptr->use_4addr) - return TX_DROP; - } else if (info->flags & IEEE80211_TX_CTL_INJECTED) { - tx->sta = sta_info_get_bss(sdata, hdr->addr1); - } if (!tx->sta) - tx->sta = sta_info_get(sdata, hdr->addr1); + tx->sta = sta_info_get(local, hdr->addr1); if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) && (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION)) { @@ -1290,7 +1207,6 @@ static int __ieee80211_tx(struct ieee80211_local *local, static int invoke_tx_handlers(struct ieee80211_tx_data *tx) { struct sk_buff *skb = tx->skb; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); ieee80211_tx_result res = TX_DROP; #define CALL_TXH(txh) \ @@ -1300,18 +1216,13 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx) goto txh_done; \ } while (0) - CALL_TXH(ieee80211_tx_h_dynamic_ps); CALL_TXH(ieee80211_tx_h_check_assoc); CALL_TXH(ieee80211_tx_h_ps_buf); CALL_TXH(ieee80211_tx_h_select_key); - CALL_TXH(ieee80211_tx_h_sta); + CALL_TXH(ieee80211_tx_h_michael_mic_add); if (!(tx->local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL)) CALL_TXH(ieee80211_tx_h_rate_ctrl); - - if (unlikely(info->flags & IEEE80211_TX_INTFL_RETRANSMISSION)) - goto txh_done; - - CALL_TXH(ieee80211_tx_h_michael_mic_add); + CALL_TXH(ieee80211_tx_h_misc); CALL_TXH(ieee80211_tx_h_sequence); CALL_TXH(ieee80211_tx_h_fragment); /* handlers after fragment must be aware of tx info fragmentation! */ @@ -1487,6 +1398,34 @@ static int ieee80211_skb_resize(struct ieee80211_local *local, return 0; } +static bool need_dynamic_ps(struct ieee80211_local *local) +{ + /* driver doesn't support power save */ + if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS)) + return false; + + /* hardware does dynamic power save */ + if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) + return false; + + /* dynamic power save disabled */ + if (local->hw.conf.dynamic_ps_timeout <= 0) + return false; + + /* we are scanning, don't enable power save */ + if (local->scanning) + return false; + + if (!local->ps_sdata) + return false; + + /* No point if we're going to suspend */ + if (local->quiescing) + return false; + + return true; +} + static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) { @@ -1497,14 +1436,25 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, int headroom; bool may_encrypt; + if (need_dynamic_ps(local)) { + if (local->hw.conf.flags & IEEE80211_CONF_PS) { + ieee80211_stop_queues_by_reason(&local->hw, + IEEE80211_QUEUE_STOP_REASON_PS); + ieee80211_queue_work(&local->hw, + &local->dynamic_ps_disable_work); + } + + mod_timer(&local->dynamic_ps_timer, jiffies + + msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout)); + } + rcu_read_lock(); if (unlikely(sdata->vif.type == NL80211_IFTYPE_MONITOR)) { int hdrlen; u16 len_rthdr; - info->flags |= IEEE80211_TX_CTL_INJECTED | - IEEE80211_TX_INTFL_HAS_RADIOTAP; + info->flags |= IEEE80211_TX_CTL_INJECTED; len_rthdr = ieee80211_get_radiotap_len(skb->data); hdr = (struct ieee80211_hdr *)(skb->data + len_rthdr); @@ -1524,11 +1474,11 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, list_for_each_entry_rcu(tmp_sdata, &local->interfaces, list) { - if (!ieee80211_sdata_running(tmp_sdata)) + if (!netif_running(tmp_sdata->dev)) continue; if (tmp_sdata->vif.type != NL80211_IFTYPE_AP) continue; - if (compare_ether_addr(tmp_sdata->vif.addr, + if (compare_ether_addr(tmp_sdata->dev->dev_addr, hdr->addr2) == 0) { sdata = tmp_sdata; break; @@ -1692,7 +1642,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); /* RA TA DA SA */ memcpy(hdr.addr1, sta->sta.addr, ETH_ALEN); - memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN); + memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); memcpy(hdr.addr3, skb->data, ETH_ALEN); memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); hdrlen = 30; @@ -1706,7 +1656,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); /* DA BSSID SA */ memcpy(hdr.addr1, skb->data, ETH_ALEN); - memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN); + memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN); hdrlen = 24; break; @@ -1714,7 +1664,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); /* RA TA DA SA */ memcpy(hdr.addr1, sdata->u.wds.remote_addr, ETH_ALEN); - memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN); + memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); memcpy(hdr.addr3, skb->data, ETH_ALEN); memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); hdrlen = 30; @@ -1728,8 +1678,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, goto fail; } - if (compare_ether_addr(sdata->vif.addr, - skb->data + ETH_ALEN) == 0) { + if (compare_ether_addr(dev->dev_addr, + skb->data + ETH_ALEN) == 0) { hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc, skb->data, skb->data + ETH_ALEN); meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, @@ -1759,7 +1709,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, } } hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc, - mesh_da, sdata->vif.addr); + mesh_da, dev->dev_addr); rcu_read_unlock(); if (is_mesh_mcast) meshhdrlen = @@ -1784,7 +1734,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, if (sdata->u.mgd.use_4addr && ethertype != ETH_P_PAE) { fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); /* RA TA DA SA */ - memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN); + memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); memcpy(hdr.addr3, skb->data, ETH_ALEN); memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); hdrlen = 30; @@ -1815,8 +1765,9 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, */ if (!is_multicast_ether_addr(hdr.addr1)) { rcu_read_lock(); - sta = sta_info_get(sdata, hdr.addr1); - if (sta) + sta = sta_info_get(local, hdr.addr1); + /* XXX: in the future, use sdata to look up the sta */ + if (sta && sta->sdata == sdata) sta_flags = get_sta_flags(sta); rcu_read_unlock(); } @@ -1835,7 +1786,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, unlikely(!is_multicast_ether_addr(hdr.addr1) && !(sta_flags & WLAN_STA_AUTHORIZED) && !(ethertype == ETH_P_PAE && - compare_ether_addr(sdata->vif.addr, + compare_ether_addr(dev->dev_addr, skb->data + ETH_ALEN) == 0))) { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG if (net_ratelimit()) @@ -1975,7 +1926,7 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local, ieee80211_tx(sdata, skb, true); } else { hdr = (struct ieee80211_hdr *)skb->data; - sta = sta_info_get(sdata, hdr->addr1); + sta = sta_info_get(local, hdr->addr1); ret = __ieee80211_tx(local, &skb, sta, true); if (ret != IEEE80211_TX_OK) @@ -2111,7 +2062,6 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, struct beacon_data *beacon; struct ieee80211_supported_band *sband; enum ieee80211_band band = local->hw.conf.channel->band; - struct ieee80211_tx_rate_control txrc; sband = local->hw.wiphy->bands[band]; @@ -2200,8 +2150,8 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON); memset(mgmt->da, 0xff, ETH_ALEN); - memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); - memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); + memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); + memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); mgmt->u.beacon.beacon_int = cpu_to_le16(sdata->vif.bss_conf.beacon_int); mgmt->u.beacon.capab_info = 0x0; /* 0x0 for MPs */ @@ -2219,25 +2169,21 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, info = IEEE80211_SKB_CB(skb); info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; - info->flags |= IEEE80211_TX_CTL_NO_ACK; info->band = band; - - memset(&txrc, 0, sizeof(txrc)); - txrc.hw = hw; - txrc.sband = sband; - txrc.bss_conf = &sdata->vif.bss_conf; - txrc.skb = skb; - txrc.reported_rate.idx = -1; - txrc.rate_idx_mask = sdata->rc_rateidx_mask[band]; - if (txrc.rate_idx_mask == (1 << sband->n_bitrates) - 1) - txrc.max_rate_idx = -1; - else - txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1; - txrc.ap = true; - rate_control_get_rate(sdata, NULL, &txrc); + /* + * 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->flags |= IEEE80211_TX_CTL_NO_ACK; info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ; out: @@ -2246,134 +2192,6 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, } EXPORT_SYMBOL(ieee80211_beacon_get_tim); -struct sk_buff *ieee80211_pspoll_get(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct ieee80211_sub_if_data *sdata; - struct ieee80211_if_managed *ifmgd; - struct ieee80211_pspoll *pspoll; - struct ieee80211_local *local; - struct sk_buff *skb; - - if (WARN_ON(vif->type != NL80211_IFTYPE_STATION)) - return NULL; - - sdata = vif_to_sdata(vif); - ifmgd = &sdata->u.mgd; - local = sdata->local; - - skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*pspoll)); - if (!skb) { - printk(KERN_DEBUG "%s: failed to allocate buffer for " - "pspoll template\n", sdata->name); - return NULL; - } - skb_reserve(skb, local->hw.extra_tx_headroom); - - pspoll = (struct ieee80211_pspoll *) skb_put(skb, sizeof(*pspoll)); - memset(pspoll, 0, sizeof(*pspoll)); - pspoll->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | - IEEE80211_STYPE_PSPOLL); - pspoll->aid = cpu_to_le16(ifmgd->aid); - - /* aid in PS-Poll has its two MSBs each set to 1 */ - pspoll->aid |= cpu_to_le16(1 << 15 | 1 << 14); - - memcpy(pspoll->bssid, ifmgd->bssid, ETH_ALEN); - memcpy(pspoll->ta, vif->addr, ETH_ALEN); - - return skb; -} -EXPORT_SYMBOL(ieee80211_pspoll_get); - -struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct ieee80211_hdr_3addr *nullfunc; - struct ieee80211_sub_if_data *sdata; - struct ieee80211_if_managed *ifmgd; - struct ieee80211_local *local; - struct sk_buff *skb; - - if (WARN_ON(vif->type != NL80211_IFTYPE_STATION)) - return NULL; - - sdata = vif_to_sdata(vif); - ifmgd = &sdata->u.mgd; - local = sdata->local; - - skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*nullfunc)); - if (!skb) { - printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc " - "template\n", sdata->name); - return NULL; - } - skb_reserve(skb, local->hw.extra_tx_headroom); - - nullfunc = (struct ieee80211_hdr_3addr *) skb_put(skb, - sizeof(*nullfunc)); - memset(nullfunc, 0, sizeof(*nullfunc)); - nullfunc->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | - IEEE80211_STYPE_NULLFUNC | - IEEE80211_FCTL_TODS); - memcpy(nullfunc->addr1, ifmgd->bssid, ETH_ALEN); - memcpy(nullfunc->addr2, vif->addr, ETH_ALEN); - memcpy(nullfunc->addr3, ifmgd->bssid, ETH_ALEN); - - return skb; -} -EXPORT_SYMBOL(ieee80211_nullfunc_get); - -struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - const u8 *ssid, size_t ssid_len, - const u8 *ie, size_t ie_len) -{ - struct ieee80211_sub_if_data *sdata; - struct ieee80211_local *local; - struct ieee80211_hdr_3addr *hdr; - struct sk_buff *skb; - size_t ie_ssid_len; - u8 *pos; - - sdata = vif_to_sdata(vif); - local = sdata->local; - ie_ssid_len = 2 + ssid_len; - - skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*hdr) + - ie_ssid_len + ie_len); - if (!skb) { - printk(KERN_DEBUG "%s: failed to allocate buffer for probe " - "request template\n", sdata->name); - return NULL; - } - - skb_reserve(skb, local->hw.extra_tx_headroom); - - hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr)); - memset(hdr, 0, sizeof(*hdr)); - hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | - IEEE80211_STYPE_PROBE_REQ); - memset(hdr->addr1, 0xff, ETH_ALEN); - memcpy(hdr->addr2, vif->addr, ETH_ALEN); - memset(hdr->addr3, 0xff, ETH_ALEN); - - pos = skb_put(skb, ie_ssid_len); - *pos++ = WLAN_EID_SSID; - *pos++ = ssid_len; - if (ssid) - memcpy(pos, ssid, ssid_len); - pos += ssid_len; - - if (ie) { - pos = skb_put(skb, ie_len); - memcpy(pos, ie, ie_len); - } - - return skb; -} -EXPORT_SYMBOL(ieee80211_probereq_get); - void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const void *frame, size_t frame_len, const struct ieee80211_tx_info *frame_txctl, diff --git a/trunk/net/mac80211/util.c b/trunk/net/mac80211/util.c index c453226f06b2..3848140313f5 100644 --- a/trunk/net/mac80211/util.c +++ b/trunk/net/mac80211/util.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -479,8 +480,8 @@ void ieee80211_iterate_active_interfaces( case NL80211_IFTYPE_MESH_POINT: break; } - if (ieee80211_sdata_running(sdata)) - iterator(data, sdata->vif.addr, + if (netif_running(sdata->dev)) + iterator(data, sdata->dev->dev_addr, &sdata->vif); } @@ -513,8 +514,8 @@ void ieee80211_iterate_active_interfaces_atomic( case NL80211_IFTYPE_MESH_POINT: break; } - if (ieee80211_sdata_running(sdata)) - iterator(data, sdata->vif.addr, + if (netif_running(sdata->dev)) + iterator(data, sdata->dev->dev_addr, &sdata->vif); } @@ -792,8 +793,6 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata) break; } - qparam.uapsd = false; - drv_conf_tx(local, queue, &qparam); } } @@ -861,7 +860,7 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, sizeof(*mgmt) + 6 + extra_len); if (!skb) { printk(KERN_DEBUG "%s: failed to allocate buffer for auth " - "frame\n", sdata->name); + "frame\n", sdata->dev->name); return; } skb_reserve(skb, local->hw.extra_tx_headroom); @@ -871,7 +870,7 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH); memcpy(mgmt->da, bssid, ETH_ALEN); - memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); + memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); memcpy(mgmt->bssid, bssid, ETH_ALEN); mgmt->u.auth.auth_alg = cpu_to_le16(auth_alg); mgmt->u.auth.auth_transaction = cpu_to_le16(transaction); @@ -894,87 +893,43 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, enum ieee80211_band band) { struct ieee80211_supported_band *sband; - u8 *pos; - size_t offset = 0, noffset; - int supp_rates_len, i; + u8 *pos, *supp_rates_len, *esupp_rates_len = NULL; + int i; sband = local->hw.wiphy->bands[band]; pos = buffer; - supp_rates_len = min_t(int, sband->n_bitrates, 8); - *pos++ = WLAN_EID_SUPP_RATES; - *pos++ = supp_rates_len; - - for (i = 0; i < supp_rates_len; i++) { - int rate = sband->bitrates[i].bitrate; - *pos++ = (u8) (rate / 5); - } - - /* insert "request information" if in custom IEs */ - if (ie && ie_len) { - static const u8 before_extrates[] = { - WLAN_EID_SSID, - WLAN_EID_SUPP_RATES, - WLAN_EID_REQUEST, - }; - noffset = ieee80211_ie_split(ie, ie_len, - before_extrates, - ARRAY_SIZE(before_extrates), - offset); - memcpy(pos, ie + offset, noffset - offset); - pos += noffset - offset; - offset = noffset; - } - - if (sband->n_bitrates > i) { - *pos++ = WLAN_EID_EXT_SUPP_RATES; - *pos++ = sband->n_bitrates - i; - - for (; i < sband->n_bitrates; i++) { - int rate = sband->bitrates[i].bitrate; - *pos++ = (u8) (rate / 5); - } - } + supp_rates_len = pos; + *pos++ = 0; + + for (i = 0; i < sband->n_bitrates; i++) { + struct ieee80211_rate *rate = &sband->bitrates[i]; + + if (esupp_rates_len) { + *esupp_rates_len += 1; + } else if (*supp_rates_len == 8) { + *pos++ = WLAN_EID_EXT_SUPP_RATES; + esupp_rates_len = pos; + *pos++ = 1; + } else + *supp_rates_len += 1; - /* insert custom IEs that go before HT */ - if (ie && ie_len) { - static const u8 before_ht[] = { - WLAN_EID_SSID, - WLAN_EID_SUPP_RATES, - WLAN_EID_REQUEST, - WLAN_EID_EXT_SUPP_RATES, - WLAN_EID_DS_PARAMS, - WLAN_EID_SUPPORTED_REGULATORY_CLASSES, - }; - noffset = ieee80211_ie_split(ie, ie_len, - before_ht, ARRAY_SIZE(before_ht), - offset); - memcpy(pos, ie + offset, noffset - offset); - pos += noffset - offset; - offset = noffset; + *pos++ = rate->bitrate / 5; } if (sband->ht_cap.ht_supported) { - u16 cap = sband->ht_cap.cap; - __le16 tmp; - - if (ieee80211_disable_40mhz_24ghz && - sband->band == IEEE80211_BAND_2GHZ) { - cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; - cap &= ~IEEE80211_HT_CAP_SGI_40; - } + __le16 tmp = cpu_to_le16(sband->ht_cap.cap); *pos++ = WLAN_EID_HT_CAPABILITY; *pos++ = sizeof(struct ieee80211_ht_cap); memset(pos, 0, sizeof(struct ieee80211_ht_cap)); - tmp = cpu_to_le16(cap); memcpy(pos, &tmp, sizeof(u16)); pos += sizeof(u16); + /* TODO: needs a define here for << 2 */ *pos++ = sband->ht_cap.ampdu_factor | - (sband->ht_cap.ampdu_density << - IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT); + (sband->ht_cap.ampdu_density << 2); memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); pos += sizeof(sband->ht_cap.mcs); pos += 2 + 4 + 1; /* ext info, BF cap, antsel */ @@ -985,11 +940,9 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, * that calculates local->scan_ies_len. */ - /* add any remaining custom IEs */ - if (ie && ie_len) { - noffset = ie_len; - memcpy(pos, ie + offset, noffset - offset); - pos += noffset - offset; + if (ie) { + memcpy(pos, ie, ie_len); + pos += ie_len; } return pos - buffer; @@ -1002,33 +955,40 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, struct ieee80211_local *local = sdata->local; struct sk_buff *skb; struct ieee80211_mgmt *mgmt; - size_t buf_len; - u8 *buf; - - /* FIXME: come up with a proper value */ - buf = kmalloc(200 + ie_len, GFP_KERNEL); - if (!buf) { - printk(KERN_DEBUG "%s: failed to allocate temporary IE " - "buffer\n", sdata->name); + u8 *pos; + + skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200 + + ie_len); + if (!skb) { + printk(KERN_DEBUG "%s: failed to allocate buffer for probe " + "request\n", sdata->dev->name); return; } + skb_reserve(skb, local->hw.extra_tx_headroom); - buf_len = ieee80211_build_preq_ies(local, buf, ie, ie_len, - local->hw.conf.channel->band); - - skb = ieee80211_probereq_get(&local->hw, &sdata->vif, - ssid, ssid_len, - buf, buf_len); - + mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); + memset(mgmt, 0, 24); + mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | + IEEE80211_STYPE_PROBE_REQ); + memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); if (dst) { - mgmt = (struct ieee80211_mgmt *) skb->data; memcpy(mgmt->da, dst, ETH_ALEN); memcpy(mgmt->bssid, dst, ETH_ALEN); + } else { + memset(mgmt->da, 0xff, ETH_ALEN); + memset(mgmt->bssid, 0xff, ETH_ALEN); } + pos = skb_put(skb, 2 + ssid_len); + *pos++ = WLAN_EID_SSID; + *pos++ = ssid_len; + memcpy(pos, ssid, ssid_len); + pos += ssid_len; + + skb_put(skb, ieee80211_build_preq_ies(local, pos, ie, ie_len, + local->hw.conf.channel->band)); IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; ieee80211_tx_skb(sdata, skb); - kfree(buf); } u32 ieee80211_sta_get_rates(struct ieee80211_local *local, @@ -1072,16 +1032,18 @@ void ieee80211_stop_device(struct ieee80211_local *local) ieee80211_led_radio(local, false); cancel_work_sync(&local->reconfig_filter); + drv_stop(local); flush_workqueue(local->workqueue); - drv_stop(local); } int ieee80211_reconfig(struct ieee80211_local *local) { struct ieee80211_hw *hw = &local->hw; struct ieee80211_sub_if_data *sdata; + struct ieee80211_if_init_conf conf; struct sta_info *sta; + unsigned long flags; int res; if (local->suspended) @@ -1099,7 +1061,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) if (res) { WARN(local->suspended, "Harware became unavailable " "upon resume. This is could be a software issue" - "prior to suspend or a hardware issue\n"); + "prior to suspend or a harware issue\n"); return res; } @@ -1110,24 +1072,29 @@ int ieee80211_reconfig(struct ieee80211_local *local) list_for_each_entry(sdata, &local->interfaces, list) { if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && sdata->vif.type != NL80211_IFTYPE_MONITOR && - ieee80211_sdata_running(sdata)) - res = drv_add_interface(local, &sdata->vif); + netif_running(sdata->dev)) { + conf.vif = &sdata->vif; + conf.type = sdata->vif.type; + conf.mac_addr = sdata->dev->dev_addr; + res = drv_add_interface(local, &conf); + } } /* add STAs back */ - mutex_lock(&local->sta_mtx); - list_for_each_entry(sta, &local->sta_list, list) { - if (sta->uploaded) { + if (local->ops->sta_notify) { + spin_lock_irqsave(&local->sta_lock, flags); + list_for_each_entry(sta, &local->sta_list, list) { sdata = sta->sdata; if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, u.ap); - WARN_ON(drv_sta_add(local, sdata, &sta->sta)); + drv_sta_notify(local, &sdata->vif, STA_NOTIFY_ADD, + &sta->sta); } + spin_unlock_irqrestore(&local->sta_lock, flags); } - mutex_unlock(&local->sta_mtx); /* Clear Suspend state so that ADDBA requests can be processed */ @@ -1152,7 +1119,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) /* Finally also reconfigure all the BSS information */ list_for_each_entry(sdata, &local->interfaces, list) { u32 changed = ~0; - if (!ieee80211_sdata_running(sdata)) + if (!netif_running(sdata->dev)) continue; switch (sdata->vif.type) { case NL80211_IFTYPE_STATION: @@ -1178,17 +1145,9 @@ int ieee80211_reconfig(struct ieee80211_local *local) } } - rcu_read_lock(); - if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { - list_for_each_entry_rcu(sta, &local->sta_list, list) { - ieee80211_sta_tear_down_BA_sessions(sta); - } - } - rcu_read_unlock(); - /* add back keys */ list_for_each_entry(sdata, &local->interfaces, list) - if (ieee80211_sdata_running(sdata)) + if (netif_running(sdata->dev)) ieee80211_enable_keys(sdata); ieee80211_wake_queues_by_reason(hw, @@ -1225,143 +1184,13 @@ int ieee80211_reconfig(struct ieee80211_local *local) add_timer(&local->sta_cleanup); - mutex_lock(&local->sta_mtx); + spin_lock_irqsave(&local->sta_lock, flags); list_for_each_entry(sta, &local->sta_list, list) mesh_plink_restart(sta); - mutex_unlock(&local->sta_mtx); + spin_unlock_irqrestore(&local->sta_lock, flags); #else WARN_ON(1); #endif return 0; } -static int check_mgd_smps(struct ieee80211_if_managed *ifmgd, - enum ieee80211_smps_mode *smps_mode) -{ - if (ifmgd->associated) { - *smps_mode = ifmgd->ap_smps; - - if (*smps_mode == IEEE80211_SMPS_AUTOMATIC) { - if (ifmgd->powersave) - *smps_mode = IEEE80211_SMPS_DYNAMIC; - else - *smps_mode = IEEE80211_SMPS_OFF; - } - - return 1; - } - - return 0; -} - -/* must hold iflist_mtx */ -void ieee80211_recalc_smps(struct ieee80211_local *local, - struct ieee80211_sub_if_data *forsdata) -{ - struct ieee80211_sub_if_data *sdata; - enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_OFF; - int count = 0; - - if (forsdata) - WARN_ON(!mutex_is_locked(&forsdata->u.mgd.mtx)); - - WARN_ON(!mutex_is_locked(&local->iflist_mtx)); - - /* - * This function could be improved to handle multiple - * interfaces better, but right now it makes any - * non-station interfaces force SM PS to be turned - * off. If there are multiple station interfaces it - * could also use the best possible mode, e.g. if - * one is in static and the other in dynamic then - * dynamic is ok. - */ - - list_for_each_entry(sdata, &local->interfaces, list) { - if (!netif_running(sdata->dev)) - continue; - if (sdata->vif.type != NL80211_IFTYPE_STATION) - goto set; - if (sdata != forsdata) { - /* - * This nested is ok -- we are holding the iflist_mtx - * so can't get here twice or so. But it's required - * since normally we acquire it first and then the - * iflist_mtx. - */ - mutex_lock_nested(&sdata->u.mgd.mtx, SINGLE_DEPTH_NESTING); - count += check_mgd_smps(&sdata->u.mgd, &smps_mode); - mutex_unlock(&sdata->u.mgd.mtx); - } else - count += check_mgd_smps(&sdata->u.mgd, &smps_mode); - - if (count > 1) { - smps_mode = IEEE80211_SMPS_OFF; - break; - } - } - - if (smps_mode == local->smps_mode) - return; - - set: - local->smps_mode = smps_mode; - /* changed flag is auto-detected for this */ - ieee80211_hw_config(local, 0); -} - -static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id) -{ - int i; - - for (i = 0; i < n_ids; i++) - if (ids[i] == id) - return true; - return false; -} - -/** - * ieee80211_ie_split - split an IE buffer according to ordering - * - * @ies: the IE buffer - * @ielen: the length of the IE buffer - * @ids: an array with element IDs that are allowed before - * the split - * @n_ids: the size of the element ID array - * @offset: offset where to start splitting in the buffer - * - * This function splits an IE buffer by updating the @offset - * variable to point to the location where the buffer should be - * split. - * - * It assumes that the given IE buffer is well-formed, this - * has to be guaranteed by the caller! - * - * It also assumes that the IEs in the buffer are ordered - * correctly, if not the result of using this function will not - * be ordered correctly either, i.e. it does no reordering. - * - * The function returns the offset where the next part of the - * buffer starts, which may be @ielen if the entire (remainder) - * of the buffer should be used. - */ -size_t ieee80211_ie_split(const u8 *ies, size_t ielen, - const u8 *ids, int n_ids, size_t offset) -{ - size_t pos = offset; - - while (pos < ielen && ieee80211_id_in_list(ids, n_ids, ies[pos])) - pos += 2 + ies[pos + 1]; - - return pos; -} - -size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset) -{ - size_t pos = offset; - - while (pos < ielen && ies[pos] != WLAN_EID_VENDOR_SPECIFIC) - pos += 2 + ies[pos + 1]; - - return pos; -} diff --git a/trunk/net/mac80211/wep.c b/trunk/net/mac80211/wep.c index 5d745f2d7236..247123fe1a7a 100644 --- a/trunk/net/mac80211/wep.c +++ b/trunk/net/mac80211/wep.c @@ -305,19 +305,20 @@ static int wep_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - if (!info->control.hw_key) { + if (!(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) { if (ieee80211_wep_encrypt(tx->local, skb, tx->key->conf.key, tx->key->conf.keylen, tx->key->conf.keyidx)) return -1; - } else if (info->control.hw_key->flags & - IEEE80211_KEY_FLAG_GENERATE_IV) { - if (!ieee80211_wep_add_iv(tx->local, skb, - tx->key->conf.keylen, - tx->key->conf.keyidx)) - return -1; + } else { + info->control.hw_key = &tx->key->conf; + if (tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) { + if (!ieee80211_wep_add_iv(tx->local, skb, + tx->key->conf.keylen, + tx->key->conf.keyidx)) + return -1; + } } - return 0; } diff --git a/trunk/net/mac80211/wme.c b/trunk/net/mac80211/wme.c index 34e6d02da779..79d887dae738 100644 --- a/trunk/net/mac80211/wme.c +++ b/trunk/net/mac80211/wme.c @@ -96,7 +96,7 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, } if (!sta && ra && !is_multicast_ether_addr(ra)) { - sta = sta_info_get(sdata, ra); + sta = sta_info_get(local, ra); if (sta) sta_flags = get_sta_flags(sta); } diff --git a/trunk/net/mac80211/work.c b/trunk/net/mac80211/work.c deleted file mode 100644 index 7e708d5c88b4..000000000000 --- a/trunk/net/mac80211/work.c +++ /dev/null @@ -1,1099 +0,0 @@ -/* - * mac80211 work implementation - * - * Copyright 2003-2008, Jouni Malinen - * Copyright 2004, Instant802 Networks, Inc. - * Copyright 2005, Devicescape Software, Inc. - * Copyright 2006-2007 Jiri Benc - * Copyright 2007, Michael Wu - * Copyright 2009, Johannes Berg - * - * 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 - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ieee80211_i.h" -#include "rate.h" - -#define IEEE80211_AUTH_TIMEOUT (HZ / 5) -#define IEEE80211_AUTH_MAX_TRIES 3 -#define IEEE80211_ASSOC_TIMEOUT (HZ / 5) -#define IEEE80211_ASSOC_MAX_TRIES 3 -#define IEEE80211_MAX_PROBE_TRIES 5 - -enum work_action { - WORK_ACT_NONE, - WORK_ACT_TIMEOUT, - WORK_ACT_DONE, -}; - - -/* utils */ -static inline void ASSERT_WORK_MTX(struct ieee80211_local *local) -{ - WARN_ON(!mutex_is_locked(&local->work_mtx)); -} - -/* - * We can have multiple work items (and connection probing) - * scheduling this timer, but we need to take care to only - * reschedule it when it should fire _earlier_ than it was - * asked for before, or if it's not pending right now. This - * function ensures that. Note that it then is required to - * run this function for all timeouts after the first one - * has happened -- the work that runs from this timer will - * do that. - */ -static void run_again(struct ieee80211_local *local, - unsigned long timeout) -{ - ASSERT_WORK_MTX(local); - - if (!timer_pending(&local->work_timer) || - time_before(timeout, local->work_timer.expires)) - mod_timer(&local->work_timer, timeout); -} - -static void work_free_rcu(struct rcu_head *head) -{ - struct ieee80211_work *wk = - container_of(head, struct ieee80211_work, rcu_head); - - kfree(wk); -} - -void free_work(struct ieee80211_work *wk) -{ - call_rcu(&wk->rcu_head, work_free_rcu); -} - -static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len, - struct ieee80211_supported_band *sband, - u32 *rates) -{ - int i, j, count; - *rates = 0; - count = 0; - for (i = 0; i < supp_rates_len; i++) { - int rate = (supp_rates[i] & 0x7F) * 5; - - for (j = 0; j < sband->n_bitrates; j++) - if (sband->bitrates[j].bitrate == rate) { - *rates |= BIT(j); - count++; - break; - } - } - - return count; -} - -/* frame sending functions */ - -static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie, - struct ieee80211_supported_band *sband, - struct ieee80211_channel *channel, - enum ieee80211_smps_mode smps) -{ - struct ieee80211_ht_info *ht_info; - u8 *pos; - u32 flags = channel->flags; - u16 cap = sband->ht_cap.cap; - __le16 tmp; - - if (!sband->ht_cap.ht_supported) - return; - - if (!ht_info_ie) - return; - - if (ht_info_ie[1] < sizeof(struct ieee80211_ht_info)) - return; - - ht_info = (struct ieee80211_ht_info *)(ht_info_ie + 2); - - /* determine capability flags */ - - if (ieee80211_disable_40mhz_24ghz && - sband->band == IEEE80211_BAND_2GHZ) { - cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; - cap &= ~IEEE80211_HT_CAP_SGI_40; - } - - switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { - case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: - if (flags & IEEE80211_CHAN_NO_HT40PLUS) { - cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; - cap &= ~IEEE80211_HT_CAP_SGI_40; - } - break; - case IEEE80211_HT_PARAM_CHA_SEC_BELOW: - if (flags & IEEE80211_CHAN_NO_HT40MINUS) { - cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; - cap &= ~IEEE80211_HT_CAP_SGI_40; - } - break; - } - - /* set SM PS mode properly */ - cap &= ~IEEE80211_HT_CAP_SM_PS; - switch (smps) { - case IEEE80211_SMPS_AUTOMATIC: - case IEEE80211_SMPS_NUM_MODES: - WARN_ON(1); - case IEEE80211_SMPS_OFF: - cap |= WLAN_HT_CAP_SM_PS_DISABLED << - IEEE80211_HT_CAP_SM_PS_SHIFT; - break; - case IEEE80211_SMPS_STATIC: - cap |= WLAN_HT_CAP_SM_PS_STATIC << - IEEE80211_HT_CAP_SM_PS_SHIFT; - break; - case IEEE80211_SMPS_DYNAMIC: - cap |= WLAN_HT_CAP_SM_PS_DYNAMIC << - IEEE80211_HT_CAP_SM_PS_SHIFT; - break; - } - - /* reserve and fill IE */ - - pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); - *pos++ = WLAN_EID_HT_CAPABILITY; - *pos++ = sizeof(struct ieee80211_ht_cap); - memset(pos, 0, sizeof(struct ieee80211_ht_cap)); - - /* capability flags */ - tmp = cpu_to_le16(cap); - memcpy(pos, &tmp, sizeof(u16)); - pos += sizeof(u16); - - /* AMPDU parameters */ - *pos++ = sband->ht_cap.ampdu_factor | - (sband->ht_cap.ampdu_density << - IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT); - - /* MCS set */ - memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); - pos += sizeof(sband->ht_cap.mcs); - - /* extended capabilities */ - pos += sizeof(__le16); - - /* BF capabilities */ - pos += sizeof(__le32); - - /* antenna selection */ - pos += sizeof(u8); -} - -static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, - struct ieee80211_work *wk) -{ - struct ieee80211_local *local = sdata->local; - struct sk_buff *skb; - struct ieee80211_mgmt *mgmt; - u8 *pos, qos_info; - const u8 *ies; - size_t offset = 0, noffset; - int i, len, count, rates_len, supp_rates_len; - u16 capab; - struct ieee80211_supported_band *sband; - u32 rates = 0; - - sband = local->hw.wiphy->bands[wk->chan->band]; - - /* - * Get all rates supported by the device and the AP as - * some APs don't like getting a superset of their rates - * in the association request (e.g. D-Link DAP 1353 in - * b-only mode)... - */ - rates_len = ieee80211_compatible_rates(wk->assoc.supp_rates, - wk->assoc.supp_rates_len, - sband, &rates); - - skb = alloc_skb(local->hw.extra_tx_headroom + - sizeof(*mgmt) + /* bit too much but doesn't matter */ - 2 + wk->assoc.ssid_len + /* SSID */ - 4 + rates_len + /* (extended) rates */ - 4 + /* power capability */ - 2 + 2 * sband->n_channels + /* supported channels */ - 2 + sizeof(struct ieee80211_ht_cap) + /* HT */ - wk->ie_len + /* extra IEs */ - 9, /* WMM */ - GFP_KERNEL); - if (!skb) { - printk(KERN_DEBUG "%s: failed to allocate buffer for assoc " - "frame\n", sdata->name); - return; - } - skb_reserve(skb, local->hw.extra_tx_headroom); - - capab = WLAN_CAPABILITY_ESS; - - if (sband->band == IEEE80211_BAND_2GHZ) { - if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE)) - capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME; - if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE)) - capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; - } - - if (wk->assoc.capability & WLAN_CAPABILITY_PRIVACY) - capab |= WLAN_CAPABILITY_PRIVACY; - - if ((wk->assoc.capability & WLAN_CAPABILITY_SPECTRUM_MGMT) && - (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)) - capab |= WLAN_CAPABILITY_SPECTRUM_MGMT; - - mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); - memset(mgmt, 0, 24); - memcpy(mgmt->da, wk->filter_ta, ETH_ALEN); - memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); - memcpy(mgmt->bssid, wk->filter_ta, ETH_ALEN); - - if (!is_zero_ether_addr(wk->assoc.prev_bssid)) { - skb_put(skb, 10); - mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | - IEEE80211_STYPE_REASSOC_REQ); - mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab); - mgmt->u.reassoc_req.listen_interval = - cpu_to_le16(local->hw.conf.listen_interval); - memcpy(mgmt->u.reassoc_req.current_ap, wk->assoc.prev_bssid, - ETH_ALEN); - } else { - skb_put(skb, 4); - mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | - IEEE80211_STYPE_ASSOC_REQ); - mgmt->u.assoc_req.capab_info = cpu_to_le16(capab); - mgmt->u.assoc_req.listen_interval = - cpu_to_le16(local->hw.conf.listen_interval); - } - - /* SSID */ - ies = pos = skb_put(skb, 2 + wk->assoc.ssid_len); - *pos++ = WLAN_EID_SSID; - *pos++ = wk->assoc.ssid_len; - memcpy(pos, wk->assoc.ssid, wk->assoc.ssid_len); - - /* add all rates which were marked to be used above */ - supp_rates_len = rates_len; - if (supp_rates_len > 8) - supp_rates_len = 8; - - len = sband->n_bitrates; - pos = skb_put(skb, supp_rates_len + 2); - *pos++ = WLAN_EID_SUPP_RATES; - *pos++ = supp_rates_len; - - count = 0; - for (i = 0; i < sband->n_bitrates; i++) { - if (BIT(i) & rates) { - int rate = sband->bitrates[i].bitrate; - *pos++ = (u8) (rate / 5); - if (++count == 8) - break; - } - } - - if (rates_len > count) { - pos = skb_put(skb, rates_len - count + 2); - *pos++ = WLAN_EID_EXT_SUPP_RATES; - *pos++ = rates_len - count; - - for (i++; i < sband->n_bitrates; i++) { - if (BIT(i) & rates) { - int rate = sband->bitrates[i].bitrate; - *pos++ = (u8) (rate / 5); - } - } - } - - if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) { - /* 1. power capabilities */ - pos = skb_put(skb, 4); - *pos++ = WLAN_EID_PWR_CAPABILITY; - *pos++ = 2; - *pos++ = 0; /* min tx power */ - *pos++ = wk->chan->max_power; /* max tx power */ - - /* 2. supported channels */ - /* TODO: get this in reg domain format */ - pos = skb_put(skb, 2 * sband->n_channels + 2); - *pos++ = WLAN_EID_SUPPORTED_CHANNELS; - *pos++ = 2 * sband->n_channels; - for (i = 0; i < sband->n_channels; i++) { - *pos++ = ieee80211_frequency_to_channel( - sband->channels[i].center_freq); - *pos++ = 1; /* one channel in the subband*/ - } - } - - /* if present, add any custom IEs that go before HT */ - if (wk->ie_len && wk->ie) { - static const u8 before_ht[] = { - WLAN_EID_SSID, - WLAN_EID_SUPP_RATES, - WLAN_EID_EXT_SUPP_RATES, - WLAN_EID_PWR_CAPABILITY, - WLAN_EID_SUPPORTED_CHANNELS, - WLAN_EID_RSN, - WLAN_EID_QOS_CAPA, - WLAN_EID_RRM_ENABLED_CAPABILITIES, - WLAN_EID_MOBILITY_DOMAIN, - WLAN_EID_SUPPORTED_REGULATORY_CLASSES, - }; - noffset = ieee80211_ie_split(wk->ie, wk->ie_len, - before_ht, ARRAY_SIZE(before_ht), - offset); - pos = skb_put(skb, noffset - offset); - memcpy(pos, wk->ie + offset, noffset - offset); - offset = noffset; - } - - if (wk->assoc.use_11n && wk->assoc.wmm_used && - local->hw.queues >= 4) - ieee80211_add_ht_ie(skb, wk->assoc.ht_information_ie, - sband, wk->chan, wk->assoc.smps); - - /* if present, add any custom non-vendor IEs that go after HT */ - if (wk->ie_len && wk->ie) { - noffset = ieee80211_ie_split_vendor(wk->ie, wk->ie_len, - offset); - pos = skb_put(skb, noffset - offset); - memcpy(pos, wk->ie + offset, noffset - offset); - offset = noffset; - } - - if (wk->assoc.wmm_used && local->hw.queues >= 4) { - if (wk->assoc.uapsd_used) { - qos_info = local->uapsd_queues; - qos_info |= (local->uapsd_max_sp_len << - IEEE80211_WMM_IE_STA_QOSINFO_SP_SHIFT); - } else { - qos_info = 0; - } - - pos = skb_put(skb, 9); - *pos++ = WLAN_EID_VENDOR_SPECIFIC; - *pos++ = 7; /* len */ - *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */ - *pos++ = 0x50; - *pos++ = 0xf2; - *pos++ = 2; /* WME */ - *pos++ = 0; /* WME info */ - *pos++ = 1; /* WME ver */ - *pos++ = qos_info; - } - - /* add any remaining custom (i.e. vendor specific here) IEs */ - if (wk->ie_len && wk->ie) { - noffset = wk->ie_len; - pos = skb_put(skb, noffset - offset); - memcpy(pos, wk->ie + offset, noffset - offset); - } - - IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; - ieee80211_tx_skb(sdata, skb); -} - -static void ieee80211_remove_auth_bss(struct ieee80211_local *local, - struct ieee80211_work *wk) -{ - struct cfg80211_bss *cbss; - u16 capa_val = WLAN_CAPABILITY_ESS; - - if (wk->probe_auth.privacy) - capa_val |= WLAN_CAPABILITY_PRIVACY; - - cbss = cfg80211_get_bss(local->hw.wiphy, wk->chan, wk->filter_ta, - wk->probe_auth.ssid, wk->probe_auth.ssid_len, - WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_PRIVACY, - capa_val); - if (!cbss) - return; - - cfg80211_unlink_bss(local->hw.wiphy, cbss); - cfg80211_put_bss(cbss); -} - -static enum work_action __must_check -ieee80211_direct_probe(struct ieee80211_work *wk) -{ - struct ieee80211_sub_if_data *sdata = wk->sdata; - struct ieee80211_local *local = sdata->local; - - wk->probe_auth.tries++; - if (wk->probe_auth.tries > IEEE80211_AUTH_MAX_TRIES) { - printk(KERN_DEBUG "%s: direct probe to %pM timed out\n", - sdata->name, wk->filter_ta); - - /* - * Most likely AP is not in the range so remove the - * bss struct for that AP. - */ - ieee80211_remove_auth_bss(local, wk); - - return WORK_ACT_TIMEOUT; - } - - printk(KERN_DEBUG "%s: direct probe to %pM (try %d)\n", - sdata->name, wk->filter_ta, wk->probe_auth.tries); - - /* - * Direct probe is sent to broadcast address as some APs - * will not answer to direct packet in unassociated state. - */ - ieee80211_send_probe_req(sdata, NULL, wk->probe_auth.ssid, - wk->probe_auth.ssid_len, NULL, 0); - - wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; - run_again(local, wk->timeout); - - return WORK_ACT_NONE; -} - - -static enum work_action __must_check -ieee80211_authenticate(struct ieee80211_work *wk) -{ - struct ieee80211_sub_if_data *sdata = wk->sdata; - struct ieee80211_local *local = sdata->local; - - wk->probe_auth.tries++; - if (wk->probe_auth.tries > IEEE80211_AUTH_MAX_TRIES) { - printk(KERN_DEBUG "%s: authentication with %pM" - " timed out\n", sdata->name, wk->filter_ta); - - /* - * Most likely AP is not in the range so remove the - * bss struct for that AP. - */ - ieee80211_remove_auth_bss(local, wk); - - return WORK_ACT_TIMEOUT; - } - - printk(KERN_DEBUG "%s: authenticate with %pM (try %d)\n", - sdata->name, wk->filter_ta, wk->probe_auth.tries); - - ieee80211_send_auth(sdata, 1, wk->probe_auth.algorithm, wk->ie, - wk->ie_len, wk->filter_ta, NULL, 0, 0); - wk->probe_auth.transaction = 2; - - wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; - run_again(local, wk->timeout); - - return WORK_ACT_NONE; -} - -static enum work_action __must_check -ieee80211_associate(struct ieee80211_work *wk) -{ - struct ieee80211_sub_if_data *sdata = wk->sdata; - struct ieee80211_local *local = sdata->local; - - wk->assoc.tries++; - if (wk->assoc.tries > IEEE80211_ASSOC_MAX_TRIES) { - printk(KERN_DEBUG "%s: association with %pM" - " timed out\n", - sdata->name, wk->filter_ta); - - /* - * Most likely AP is not in the range so remove the - * bss struct for that AP. - */ - if (wk->assoc.bss) - cfg80211_unlink_bss(local->hw.wiphy, wk->assoc.bss); - - return WORK_ACT_TIMEOUT; - } - - printk(KERN_DEBUG "%s: associate with %pM (try %d)\n", - sdata->name, wk->filter_ta, wk->assoc.tries); - ieee80211_send_assoc(sdata, wk); - - wk->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT; - run_again(local, wk->timeout); - - return WORK_ACT_NONE; -} - -static enum work_action __must_check -ieee80211_remain_on_channel_timeout(struct ieee80211_work *wk) -{ - /* - * First time we run, do nothing -- the generic code will - * have switched to the right channel etc. - */ - if (!wk->started) { - wk->timeout = jiffies + msecs_to_jiffies(wk->remain.duration); - - cfg80211_ready_on_channel(wk->sdata->dev, (unsigned long) wk, - wk->chan, wk->chan_type, - wk->remain.duration, GFP_KERNEL); - - return WORK_ACT_NONE; - } - - return WORK_ACT_TIMEOUT; -} - -static void ieee80211_auth_challenge(struct ieee80211_work *wk, - struct ieee80211_mgmt *mgmt, - size_t len) -{ - struct ieee80211_sub_if_data *sdata = wk->sdata; - u8 *pos; - struct ieee802_11_elems elems; - - pos = mgmt->u.auth.variable; - ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); - if (!elems.challenge) - return; - ieee80211_send_auth(sdata, 3, wk->probe_auth.algorithm, - elems.challenge - 2, elems.challenge_len + 2, - wk->filter_ta, wk->probe_auth.key, - wk->probe_auth.key_len, wk->probe_auth.key_idx); - wk->probe_auth.transaction = 4; -} - -static enum work_action __must_check -ieee80211_rx_mgmt_auth(struct ieee80211_work *wk, - struct ieee80211_mgmt *mgmt, size_t len) -{ - u16 auth_alg, auth_transaction, status_code; - - if (wk->type != IEEE80211_WORK_AUTH) - return WORK_ACT_NONE; - - if (len < 24 + 6) - return WORK_ACT_NONE; - - auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); - auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); - status_code = le16_to_cpu(mgmt->u.auth.status_code); - - if (auth_alg != wk->probe_auth.algorithm || - auth_transaction != wk->probe_auth.transaction) - return WORK_ACT_NONE; - - if (status_code != WLAN_STATUS_SUCCESS) { - printk(KERN_DEBUG "%s: %pM denied authentication (status %d)\n", - wk->sdata->name, mgmt->sa, status_code); - return WORK_ACT_DONE; - } - - switch (wk->probe_auth.algorithm) { - case WLAN_AUTH_OPEN: - case WLAN_AUTH_LEAP: - case WLAN_AUTH_FT: - break; - case WLAN_AUTH_SHARED_KEY: - if (wk->probe_auth.transaction != 4) { - ieee80211_auth_challenge(wk, mgmt, len); - /* need another frame */ - return WORK_ACT_NONE; - } - break; - default: - WARN_ON(1); - return WORK_ACT_NONE; - } - - printk(KERN_DEBUG "%s: authenticated\n", wk->sdata->name); - return WORK_ACT_DONE; -} - -static enum work_action __must_check -ieee80211_rx_mgmt_assoc_resp(struct ieee80211_work *wk, - struct ieee80211_mgmt *mgmt, size_t len, - bool reassoc) -{ - struct ieee80211_sub_if_data *sdata = wk->sdata; - struct ieee80211_local *local = sdata->local; - u16 capab_info, status_code, aid; - struct ieee802_11_elems elems; - u8 *pos; - - /* - * AssocResp and ReassocResp have identical structure, so process both - * of them in this function. - */ - - if (len < 24 + 6) - return WORK_ACT_NONE; - - capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); - status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); - aid = le16_to_cpu(mgmt->u.assoc_resp.aid); - - printk(KERN_DEBUG "%s: RX %sssocResp from %pM (capab=0x%x " - "status=%d aid=%d)\n", - sdata->name, reassoc ? "Rea" : "A", mgmt->sa, - capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14)))); - - pos = mgmt->u.assoc_resp.variable; - ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); - - if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY && - elems.timeout_int && elems.timeout_int_len == 5 && - elems.timeout_int[0] == WLAN_TIMEOUT_ASSOC_COMEBACK) { - u32 tu, ms; - tu = get_unaligned_le32(elems.timeout_int + 1); - ms = tu * 1024 / 1000; - printk(KERN_DEBUG "%s: %pM rejected association temporarily; " - "comeback duration %u TU (%u ms)\n", - sdata->name, mgmt->sa, tu, ms); - wk->timeout = jiffies + msecs_to_jiffies(ms); - if (ms > IEEE80211_ASSOC_TIMEOUT) - run_again(local, wk->timeout); - return WORK_ACT_NONE; - } - - if (status_code != WLAN_STATUS_SUCCESS) - printk(KERN_DEBUG "%s: %pM denied association (code=%d)\n", - sdata->name, mgmt->sa, status_code); - else - printk(KERN_DEBUG "%s: associated\n", sdata->name); - - return WORK_ACT_DONE; -} - -static enum work_action __must_check -ieee80211_rx_mgmt_probe_resp(struct ieee80211_work *wk, - struct ieee80211_mgmt *mgmt, size_t len, - struct ieee80211_rx_status *rx_status) -{ - struct ieee80211_sub_if_data *sdata = wk->sdata; - struct ieee80211_local *local = sdata->local; - size_t baselen; - - ASSERT_WORK_MTX(local); - - baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt; - if (baselen > len) - return WORK_ACT_NONE; - - printk(KERN_DEBUG "%s: direct probe responded\n", sdata->name); - return WORK_ACT_DONE; -} - -static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local, - struct sk_buff *skb) -{ - struct ieee80211_rx_status *rx_status; - struct ieee80211_mgmt *mgmt; - struct ieee80211_work *wk; - enum work_action rma = WORK_ACT_NONE; - u16 fc; - - rx_status = (struct ieee80211_rx_status *) skb->cb; - mgmt = (struct ieee80211_mgmt *) skb->data; - fc = le16_to_cpu(mgmt->frame_control); - - mutex_lock(&local->work_mtx); - - list_for_each_entry(wk, &local->work_list, list) { - const u8 *bssid = NULL; - - switch (wk->type) { - case IEEE80211_WORK_DIRECT_PROBE: - case IEEE80211_WORK_AUTH: - case IEEE80211_WORK_ASSOC: - bssid = wk->filter_ta; - break; - default: - continue; - } - - /* - * Before queuing, we already verified mgmt->sa, - * so this is needed just for matching. - */ - if (compare_ether_addr(bssid, mgmt->bssid)) - continue; - - switch (fc & IEEE80211_FCTL_STYPE) { - case IEEE80211_STYPE_PROBE_RESP: - rma = ieee80211_rx_mgmt_probe_resp(wk, mgmt, skb->len, - rx_status); - break; - case IEEE80211_STYPE_AUTH: - rma = ieee80211_rx_mgmt_auth(wk, mgmt, skb->len); - break; - case IEEE80211_STYPE_ASSOC_RESP: - rma = ieee80211_rx_mgmt_assoc_resp(wk, mgmt, - skb->len, false); - break; - case IEEE80211_STYPE_REASSOC_RESP: - rma = ieee80211_rx_mgmt_assoc_resp(wk, mgmt, - skb->len, true); - break; - default: - WARN_ON(1); - } - /* - * We've processed this frame for that work, so it can't - * belong to another work struct. - * NB: this is also required for correctness for 'rma'! - */ - break; - } - - switch (rma) { - case WORK_ACT_NONE: - break; - case WORK_ACT_DONE: - list_del_rcu(&wk->list); - break; - default: - WARN(1, "unexpected: %d", rma); - } - - mutex_unlock(&local->work_mtx); - - if (rma != WORK_ACT_DONE) - goto out; - - switch (wk->done(wk, skb)) { - case WORK_DONE_DESTROY: - free_work(wk); - break; - case WORK_DONE_REQUEUE: - synchronize_rcu(); - wk->started = false; /* restart */ - mutex_lock(&local->work_mtx); - list_add_tail(&wk->list, &local->work_list); - mutex_unlock(&local->work_mtx); - } - - out: - kfree_skb(skb); -} - -static void ieee80211_work_timer(unsigned long data) -{ - struct ieee80211_local *local = (void *) data; - - if (local->quiescing) - return; - - ieee80211_queue_work(&local->hw, &local->work_work); -} - -static void ieee80211_work_work(struct work_struct *work) -{ - struct ieee80211_local *local = - container_of(work, struct ieee80211_local, work_work); - struct sk_buff *skb; - struct ieee80211_work *wk, *tmp; - LIST_HEAD(free_work); - enum work_action rma; - bool remain_off_channel = false; - - if (local->scanning) - return; - - /* - * ieee80211_queue_work() should have picked up most cases, - * here we'll pick the the rest. - */ - if (WARN(local->suspended, "work scheduled while going to suspend\n")) - return; - - /* first process frames to avoid timing out while a frame is pending */ - while ((skb = skb_dequeue(&local->work_skb_queue))) - ieee80211_work_rx_queued_mgmt(local, skb); - - ieee80211_recalc_idle(local); - - mutex_lock(&local->work_mtx); - - list_for_each_entry_safe(wk, tmp, &local->work_list, list) { - bool started = wk->started; - - /* mark work as started if it's on the current off-channel */ - if (!started && local->tmp_channel && - wk->chan == local->tmp_channel && - wk->chan_type == local->tmp_channel_type) { - started = true; - wk->timeout = jiffies; - } - - if (!started && !local->tmp_channel) { - /* - * TODO: could optimize this by leaving the - * station vifs in awake mode if they - * happen to be on the same channel as - * the requested channel - */ - ieee80211_offchannel_stop_beaconing(local); - ieee80211_offchannel_stop_station(local); - - local->tmp_channel = wk->chan; - local->tmp_channel_type = wk->chan_type; - ieee80211_hw_config(local, 0); - started = true; - wk->timeout = jiffies; - } - - /* don't try to work with items that aren't started */ - if (!started) - continue; - - if (time_is_after_jiffies(wk->timeout)) { - /* - * This work item isn't supposed to be worked on - * right now, but take care to adjust the timer - * properly. - */ - run_again(local, wk->timeout); - continue; - } - - switch (wk->type) { - default: - WARN_ON(1); - /* nothing */ - rma = WORK_ACT_NONE; - break; - case IEEE80211_WORK_ABORT: - rma = WORK_ACT_TIMEOUT; - case IEEE80211_WORK_DIRECT_PROBE: - rma = ieee80211_direct_probe(wk); - break; - case IEEE80211_WORK_AUTH: - rma = ieee80211_authenticate(wk); - break; - case IEEE80211_WORK_ASSOC: - rma = ieee80211_associate(wk); - break; - case IEEE80211_WORK_REMAIN_ON_CHANNEL: - rma = ieee80211_remain_on_channel_timeout(wk); - break; - } - - wk->started = started; - - switch (rma) { - case WORK_ACT_NONE: - /* might have changed the timeout */ - run_again(local, wk->timeout); - break; - case WORK_ACT_TIMEOUT: - list_del_rcu(&wk->list); - synchronize_rcu(); - list_add(&wk->list, &free_work); - break; - default: - WARN(1, "unexpected: %d", rma); - } - } - - list_for_each_entry(wk, &local->work_list, list) { - if (!wk->started) - continue; - if (wk->chan != local->tmp_channel) - continue; - if (wk->chan_type != local->tmp_channel_type) - continue; - remain_off_channel = true; - } - - if (!remain_off_channel && local->tmp_channel) { - local->tmp_channel = NULL; - ieee80211_hw_config(local, 0); - ieee80211_offchannel_return(local, true); - /* give connection some time to breathe */ - run_again(local, jiffies + HZ/2); - } - - if (list_empty(&local->work_list) && local->scan_req) - ieee80211_queue_delayed_work(&local->hw, - &local->scan_work, - round_jiffies_relative(0)); - - mutex_unlock(&local->work_mtx); - - ieee80211_recalc_idle(local); - - list_for_each_entry_safe(wk, tmp, &free_work, list) { - wk->done(wk, NULL); - list_del(&wk->list); - kfree(wk); - } -} - -void ieee80211_add_work(struct ieee80211_work *wk) -{ - struct ieee80211_local *local; - - if (WARN_ON(!wk->chan)) - return; - - if (WARN_ON(!wk->sdata)) - return; - - if (WARN_ON(!wk->done)) - return; - - if (WARN_ON(!ieee80211_sdata_running(wk->sdata))) - return; - - wk->started = false; - - local = wk->sdata->local; - mutex_lock(&local->work_mtx); - list_add_tail(&wk->list, &local->work_list); - mutex_unlock(&local->work_mtx); - - ieee80211_queue_work(&local->hw, &local->work_work); -} - -void ieee80211_work_init(struct ieee80211_local *local) -{ - mutex_init(&local->work_mtx); - INIT_LIST_HEAD(&local->work_list); - setup_timer(&local->work_timer, ieee80211_work_timer, - (unsigned long)local); - INIT_WORK(&local->work_work, ieee80211_work_work); - skb_queue_head_init(&local->work_skb_queue); -} - -void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata) -{ - struct ieee80211_local *local = sdata->local; - struct ieee80211_work *wk; - - mutex_lock(&local->work_mtx); - list_for_each_entry(wk, &local->work_list, list) { - if (wk->sdata != sdata) - continue; - wk->type = IEEE80211_WORK_ABORT; - wk->started = true; - wk->timeout = jiffies; - } - mutex_unlock(&local->work_mtx); - - /* run cleanups etc. */ - ieee80211_work_work(&local->work_work); - - mutex_lock(&local->work_mtx); - list_for_each_entry(wk, &local->work_list, list) { - if (wk->sdata != sdata) - continue; - WARN_ON(1); - break; - } - mutex_unlock(&local->work_mtx); -} - -ieee80211_rx_result ieee80211_work_rx_mgmt(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb) -{ - struct ieee80211_local *local = sdata->local; - struct ieee80211_mgmt *mgmt; - struct ieee80211_work *wk; - u16 fc; - - if (skb->len < 24) - return RX_DROP_MONITOR; - - mgmt = (struct ieee80211_mgmt *) skb->data; - fc = le16_to_cpu(mgmt->frame_control); - - list_for_each_entry_rcu(wk, &local->work_list, list) { - if (sdata != wk->sdata) - continue; - if (compare_ether_addr(wk->filter_ta, mgmt->sa)) - continue; - if (compare_ether_addr(wk->filter_ta, mgmt->bssid)) - continue; - - switch (fc & IEEE80211_FCTL_STYPE) { - case IEEE80211_STYPE_AUTH: - case IEEE80211_STYPE_PROBE_RESP: - case IEEE80211_STYPE_ASSOC_RESP: - case IEEE80211_STYPE_REASSOC_RESP: - skb_queue_tail(&local->work_skb_queue, skb); - ieee80211_queue_work(&local->hw, &local->work_work); - return RX_QUEUED; - } - } - - return RX_CONTINUE; -} - -static enum work_done_result ieee80211_remain_done(struct ieee80211_work *wk, - struct sk_buff *skb) -{ - /* - * We are done serving the remain-on-channel command. - */ - cfg80211_remain_on_channel_expired(wk->sdata->dev, (unsigned long) wk, - wk->chan, wk->chan_type, - GFP_KERNEL); - - return WORK_DONE_DESTROY; -} - -int ieee80211_wk_remain_on_channel(struct ieee80211_sub_if_data *sdata, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, - unsigned int duration, u64 *cookie) -{ - struct ieee80211_work *wk; - - wk = kzalloc(sizeof(*wk), GFP_KERNEL); - if (!wk) - return -ENOMEM; - - wk->type = IEEE80211_WORK_REMAIN_ON_CHANNEL; - wk->chan = chan; - wk->chan_type = channel_type; - wk->sdata = sdata; - wk->done = ieee80211_remain_done; - - wk->remain.duration = duration; - - *cookie = (unsigned long) wk; - - ieee80211_add_work(wk); - - return 0; -} - -int ieee80211_wk_cancel_remain_on_channel(struct ieee80211_sub_if_data *sdata, - u64 cookie) -{ - struct ieee80211_local *local = sdata->local; - struct ieee80211_work *wk, *tmp; - bool found = false; - - mutex_lock(&local->work_mtx); - list_for_each_entry_safe(wk, tmp, &local->work_list, list) { - if ((unsigned long) wk == cookie) { - wk->timeout = jiffies; - found = true; - break; - } - } - mutex_unlock(&local->work_mtx); - - if (!found) - return -ENOENT; - - ieee80211_queue_work(&local->hw, &local->work_work); - - return 0; -} diff --git a/trunk/net/mac80211/wpa.c b/trunk/net/mac80211/wpa.c index f4971cd45c64..5332014cb229 100644 --- a/trunk/net/mac80211/wpa.c +++ b/trunk/net/mac80211/wpa.c @@ -31,8 +31,8 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx) unsigned int hdrlen; struct ieee80211_hdr *hdr; struct sk_buff *skb = tx->skb; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int authenticator; + int wpa_test = 0; int tail; hdr = (struct ieee80211_hdr *)skb->data; @@ -47,15 +47,16 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx) data = skb->data + hdrlen; data_len = skb->len - hdrlen; - if (info->control.hw_key && + if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && !(tx->flags & IEEE80211_TX_FRAGMENTED) && - !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) { - /* hwaccel - with no need for SW-generated MMIC */ + !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) && + !wpa_test) { + /* hwaccel - with no need for preallocated room for MMIC */ return TX_CONTINUE; } tail = MICHAEL_MIC_LEN; - if (!info->control.hw_key) + if (!(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) tail += TKIP_ICV_LEN; if (WARN_ON(skb_tailroom(skb) < tail || @@ -146,16 +147,17 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) int len, tail; u8 *pos; - if (info->control.hw_key && - !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { - /* hwaccel - with no need for software-generated IV */ + if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && + !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { + /* hwaccel - with no need for preallocated room for IV/ICV */ + info->control.hw_key = &tx->key->conf; return 0; } hdrlen = ieee80211_hdrlen(hdr->frame_control); len = skb->len - hdrlen; - if (info->control.hw_key) + if (tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) tail = 0; else tail = TKIP_ICV_LEN; @@ -173,11 +175,13 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) if (key->u.tkip.tx.iv16 == 0) key->u.tkip.tx.iv32++; - pos = ieee80211_tkip_add_iv(pos, key, key->u.tkip.tx.iv16); + if (tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { + /* hwaccel - with preallocated room for IV */ + ieee80211_tkip_add_iv(pos, key, key->u.tkip.tx.iv16); - /* hwaccel - with software IV */ - if (info->control.hw_key) + info->control.hw_key = &tx->key->conf; return 0; + } /* Add room for ICV */ skb_put(skb, TKIP_ICV_LEN); @@ -359,20 +363,24 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) int hdrlen, len, tail; u8 *pos, *pn; int i; + bool skip_hw; + + skip_hw = (tx->key->conf.flags & IEEE80211_KEY_FLAG_SW_MGMT) && + ieee80211_is_mgmt(hdr->frame_control); - if (info->control.hw_key && - !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { - /* - * hwaccel has no need for preallocated room for CCMP - * header or MIC fields - */ + if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && + !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) && + !skip_hw) { + /* hwaccel - with no need for preallocated room for CCMP + * header or MIC fields */ + info->control.hw_key = &tx->key->conf; return 0; } hdrlen = ieee80211_hdrlen(hdr->frame_control); len = skb->len - hdrlen; - if (info->control.hw_key) + if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) tail = 0; else tail = CCMP_MIC_LEN; @@ -397,9 +405,11 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) ccmp_pn2hdr(pos, pn, key->conf.keyidx); - /* hwaccel - with software CCMP header */ - if (info->control.hw_key) + if ((key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && !skip_hw) { + /* hwaccel - with preallocated room for CCMP header */ + info->control.hw_key = &tx->key->conf; return 0; + } pos += CCMP_HDR_LEN; ccmp_special_blocks(skb, pn, key->u.ccmp.tx_crypto_buf, 0); @@ -515,8 +525,11 @@ ieee80211_crypto_aes_cmac_encrypt(struct ieee80211_tx_data *tx) u8 *pn, aad[20]; int i; - if (info->control.hw_key) + if (tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { + /* hwaccel */ + info->control.hw_key = &tx->key->conf; return 0; + } if (WARN_ON(skb_tailroom(skb) < sizeof(*mmie))) return TX_DROP; diff --git a/trunk/net/wireless/.gitignore b/trunk/net/wireless/.gitignore deleted file mode 100644 index c33451b896d9..000000000000 --- a/trunk/net/wireless/.gitignore +++ /dev/null @@ -1 +0,0 @@ -regdb.c diff --git a/trunk/net/wireless/Kconfig b/trunk/net/wireless/Kconfig index d0ee29063e5d..90e93a5701aa 100644 --- a/trunk/net/wireless/Kconfig +++ b/trunk/net/wireless/Kconfig @@ -94,21 +94,20 @@ config CFG80211_DEBUGFS If unsure, say N. -config CFG80211_INTERNAL_REGDB - bool "use statically compiled regulatory rules database" if EMBEDDED +config WIRELESS_OLD_REGULATORY + bool "Old wireless static regulatory definitions" default n depends on CFG80211 ---help--- - This option generates an internal data structure representing - the wireless regulatory rules described in net/wireless/db.txt - and includes code to query that database. This is an alternative - to using CRDA for defining regulatory rules for the kernel. + This option enables the old static regulatory information + and uses it within the new framework. This option is available + for historical reasons and it is advised to leave it off. For details see: http://wireless.kernel.org/en/developers/Regulatory - Most distributions have a CRDA package. So if unsure, say N. + Say N and if you say Y, please tell us why. The default is N. config CFG80211_WEXT bool "cfg80211 wireless extensions compatibility" diff --git a/trunk/net/wireless/Makefile b/trunk/net/wireless/Makefile index e77e508126fa..f07c8dc7aab2 100644 --- a/trunk/net/wireless/Makefile +++ b/trunk/net/wireless/Makefile @@ -13,11 +13,5 @@ cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o -cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o ccflags-y += -D__CHECK_ENDIAN__ - -$(obj)/regdb.c: $(src)/db.txt $(src)/genregdb.awk - @$(AWK) -f $(srctree)/$(src)/genregdb.awk < $< > $@ - -clean-files := regdb.c diff --git a/trunk/net/wireless/chan.c b/trunk/net/wireless/chan.c index bf1737fc9a7e..a46ac6c9b365 100644 --- a/trunk/net/wireless/chan.c +++ b/trunk/net/wireless/chan.c @@ -41,57 +41,44 @@ rdev_fixed_channel(struct cfg80211_registered_device *rdev, return result; } -struct ieee80211_channel * -rdev_freq_to_chan(struct cfg80211_registered_device *rdev, +int rdev_set_freq(struct cfg80211_registered_device *rdev, + struct wireless_dev *for_wdev, int freq, enum nl80211_channel_type channel_type) { struct ieee80211_channel *chan; struct ieee80211_sta_ht_cap *ht_cap; + int result; + + if (rdev_fixed_channel(rdev, for_wdev)) + return -EBUSY; + + if (!rdev->ops->set_channel) + return -EOPNOTSUPP; chan = ieee80211_get_channel(&rdev->wiphy, freq); /* Primary channel not allowed */ if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) - return NULL; + return -EINVAL; if (channel_type == NL80211_CHAN_HT40MINUS && chan->flags & IEEE80211_CHAN_NO_HT40MINUS) - return NULL; + return -EINVAL; else if (channel_type == NL80211_CHAN_HT40PLUS && chan->flags & IEEE80211_CHAN_NO_HT40PLUS) - return NULL; + return -EINVAL; ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap; if (channel_type != NL80211_CHAN_NO_HT) { if (!ht_cap->ht_supported) - return NULL; + return -EINVAL; if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) || ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT) - return NULL; + return -EINVAL; } - return chan; -} - -int rdev_set_freq(struct cfg80211_registered_device *rdev, - struct wireless_dev *for_wdev, - int freq, enum nl80211_channel_type channel_type) -{ - struct ieee80211_channel *chan; - int result; - - if (rdev_fixed_channel(rdev, for_wdev)) - return -EBUSY; - - if (!rdev->ops->set_channel) - return -EOPNOTSUPP; - - chan = rdev_freq_to_chan(rdev, freq, channel_type); - if (!chan) - return -EINVAL; - result = rdev->ops->set_channel(&rdev->wiphy, chan, channel_type); if (result) return result; diff --git a/trunk/net/wireless/core.c b/trunk/net/wireless/core.c index 7fdb9409ad2a..92b812442488 100644 --- a/trunk/net/wireless/core.c +++ b/trunk/net/wireless/core.c @@ -1,7 +1,7 @@ /* * This is the linux wireless configuration interface. * - * Copyright 2006-2010 Johannes Berg + * Copyright 2006-2009 Johannes Berg */ #include @@ -31,10 +31,15 @@ MODULE_AUTHOR("Johannes Berg"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("wireless configuration support"); -/* RCU-protected (and cfg80211_mutex for writers) */ +/* RCU might be appropriate here since we usually + * only read the list, and that can happen quite + * often because we need to do it for each command */ LIST_HEAD(cfg80211_rdev_list); int cfg80211_rdev_list_generation; +/* + * This is used to protect the cfg80211_rdev_list + */ DEFINE_MUTEX(cfg80211_mutex); /* for debugfs */ @@ -397,7 +402,6 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) rdev->wiphy.retry_long = 4; rdev->wiphy.frag_threshold = (u32) -1; rdev->wiphy.rts_threshold = (u32) -1; - rdev->wiphy.coverage_class = 0; return &rdev->wiphy; } @@ -413,18 +417,6 @@ int wiphy_register(struct wiphy *wiphy) int i; u16 ifmodes = wiphy->interface_modes; - if (WARN_ON(wiphy->addresses && !wiphy->n_addresses)) - return -EINVAL; - - if (WARN_ON(wiphy->addresses && - !is_zero_ether_addr(wiphy->perm_addr) && - memcmp(wiphy->perm_addr, wiphy->addresses[0].addr, - ETH_ALEN))) - return -EINVAL; - - if (wiphy->addresses) - memcpy(wiphy->perm_addr, wiphy->addresses[0].addr, ETH_ALEN); - /* sanity check ifmodes */ WARN_ON(!ifmodes); ifmodes &= ((1 << __NL80211_IFTYPE_AFTER_LAST) - 1) & ~1; @@ -484,7 +476,7 @@ int wiphy_register(struct wiphy *wiphy) /* set up regulatory info */ wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE); - list_add_rcu(&rdev->list, &cfg80211_rdev_list); + list_add(&rdev->list, &cfg80211_rdev_list); cfg80211_rdev_list_generation++; mutex_unlock(&cfg80211_mutex); @@ -561,8 +553,7 @@ void wiphy_unregister(struct wiphy *wiphy) * it impossible to find from userspace. */ debugfs_remove_recursive(rdev->wiphy.debugfsdir); - list_del_rcu(&rdev->list); - synchronize_rcu(); + list_del(&rdev->list); /* * Try to grab rdev->mtx. If a command is still in progress, @@ -677,11 +668,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, INIT_WORK(&wdev->cleanup_work, wdev_cleanup_work); INIT_LIST_HEAD(&wdev->event_list); spin_lock_init(&wdev->event_lock); - INIT_LIST_HEAD(&wdev->action_registrations); - spin_lock_init(&wdev->action_registrations_lock); - mutex_lock(&rdev->devlist_mtx); - list_add_rcu(&wdev->list, &rdev->netdev_list); + list_add(&wdev->list, &rdev->netdev_list); rdev->devlist_generation++; /* can only change netns with wiphy */ dev->features |= NETIF_F_NETNS_LOCAL; @@ -698,21 +686,19 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, wdev->wext.default_key = -1; wdev->wext.default_mgmt_key = -1; wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; -#endif - if (wdev->wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT) - wdev->ps = true; + wdev->wext.ps = true; else - wdev->ps = false; - wdev->ps_timeout = 100; + wdev->wext.ps = false; + wdev->wext.ps_timeout = 100; if (rdev->ops->set_power_mgmt) if (rdev->ops->set_power_mgmt(wdev->wiphy, dev, - wdev->ps, - wdev->ps_timeout)) { + wdev->wext.ps, + wdev->wext.ps_timeout)) { /* assume this means it's off */ - wdev->ps = false; + wdev->wext.ps = false; } - +#endif if (!dev->ethtool_ops) dev->ethtool_ops = &cfg80211_ethtool_ops; @@ -795,22 +781,13 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, */ if (!list_empty(&wdev->list)) { sysfs_remove_link(&dev->dev.kobj, "phy80211"); - list_del_rcu(&wdev->list); + list_del_init(&wdev->list); rdev->devlist_generation++; - cfg80211_mlme_purge_actions(wdev); #ifdef CONFIG_CFG80211_WEXT kfree(wdev->wext.keys); #endif } mutex_unlock(&rdev->devlist_mtx); - /* - * synchronise (so that we won't find this netdev - * from other code any more) and then clear the list - * head so that the above code can safely check for - * !list_empty() to avoid double-cleanup. - */ - synchronize_rcu(); - INIT_LIST_HEAD(&wdev->list); break; case NETDEV_PRE_UP: if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype))) diff --git a/trunk/net/wireless/core.h b/trunk/net/wireless/core.h index d52da913145a..4ef3efc94106 100644 --- a/trunk/net/wireless/core.h +++ b/trunk/net/wireless/core.h @@ -1,7 +1,7 @@ /* * Wireless configuration interface internals. * - * Copyright 2006-2010 Johannes Berg + * Copyright 2006-2009 Johannes Berg */ #ifndef __NET_WIRELESS_CORE_H #define __NET_WIRELESS_CORE_H @@ -48,7 +48,6 @@ struct cfg80211_registered_device { /* associate netdev list */ struct mutex devlist_mtx; - /* protected by devlist_mtx or RCU */ struct list_head netdev_list; int devlist_generation; int opencount; /* also protected by devlist_mtx */ @@ -112,8 +111,7 @@ struct cfg80211_internal_bss { unsigned long ts; struct kref ref; atomic_t hold; - bool beacon_ies_allocated; - bool proberesp_ies_allocated; + bool ies_allocated; /* must be last because of priv member */ struct cfg80211_bss pub; @@ -329,15 +327,6 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, const u8 *resp_ie, size_t resp_ie_len, u16 status, bool wextev, struct cfg80211_bss *bss); -int cfg80211_mlme_register_action(struct wireless_dev *wdev, u32 snd_pid, - const u8 *match_data, int match_len); -void cfg80211_mlme_unregister_actions(struct wireless_dev *wdev, u32 nlpid); -void cfg80211_mlme_purge_actions(struct wireless_dev *wdev); -int cfg80211_mlme_action(struct cfg80211_registered_device *rdev, - struct net_device *dev, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, - const u8 *buf, size_t len, u64 *cookie); /* SME */ int __cfg80211_connect(struct cfg80211_registered_device *rdev, @@ -385,15 +374,10 @@ void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev); struct ieee80211_channel * rdev_fixed_channel(struct cfg80211_registered_device *rdev, struct wireless_dev *for_wdev); -struct ieee80211_channel * -rdev_freq_to_chan(struct cfg80211_registered_device *rdev, - int freq, enum nl80211_channel_type channel_type); int rdev_set_freq(struct cfg80211_registered_device *rdev, struct wireless_dev *for_wdev, int freq, enum nl80211_channel_type channel_type); -u16 cfg80211_calculate_bitrate(struct rate_info *rate); - #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS #define CFG80211_DEV_WARN_ON(cond) WARN_ON(cond) #else diff --git a/trunk/net/wireless/db.txt b/trunk/net/wireless/db.txt deleted file mode 100644 index a2fc3a09ccdc..000000000000 --- a/trunk/net/wireless/db.txt +++ /dev/null @@ -1,17 +0,0 @@ -# -# This file is a placeholder to prevent accidental build breakage if someone -# enables CONFIG_CFG80211_INTERNAL_REGDB. Almost no one actually needs to -# enable that build option. -# -# You should be using CRDA instead. It is even better if you use the CRDA -# package provided by your distribution, since they will probably keep it -# up-to-date on your behalf. -# -# If you _really_ intend to use CONFIG_CFG80211_INTERNAL_REGDB then you will -# need to replace this file with one containing appropriately formatted -# regulatory rules that cover the regulatory domains you will be using. Your -# best option is to extract the db.txt file from the wireless-regdb git -# repository: -# -# git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-regdb.git -# diff --git a/trunk/net/wireless/genregdb.awk b/trunk/net/wireless/genregdb.awk deleted file mode 100644 index 8316cf075ce9..000000000000 --- a/trunk/net/wireless/genregdb.awk +++ /dev/null @@ -1,118 +0,0 @@ -#!/usr/bin/awk -f -# -# genregdb.awk -- generate regdb.c from db.txt -# -# Actually, it reads from stdin (presumed to be db.txt) and writes -# to stdout (presumed to be regdb.c), but close enough... -# -# Copyright 2009 John W. Linville -# -# 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 -# published by the Free Software Foundation. -# - -BEGIN { - active = 0 - rules = 0; - print "/*" - print " * DO NOT EDIT -- file generated from data in db.txt" - print " */" - print "" - print "#include " - print "#include " - print "" - regdb = "const struct ieee80211_regdomain *reg_regdb[] = {\n" -} - -/^[ \t]*#/ { - /* Ignore */ -} - -!active && /^[ \t]*$/ { - /* Ignore */ -} - -!active && /country/ { - country=$2 - sub(/:/, "", country) - printf "static const struct ieee80211_regdomain regdom_%s = {\n", country - printf "\t.alpha2 = \"%s\",\n", country - printf "\t.reg_rules = {\n" - active = 1 - regdb = regdb "\t®dom_" country ",\n" -} - -active && /^[ \t]*\(/ { - start = $1 - sub(/\(/, "", start) - end = $3 - bw = $5 - sub(/\),/, "", bw) - gain = $6 - sub(/\(/, "", gain) - sub(/,/, "", gain) - power = $7 - sub(/\)/, "", power) - sub(/,/, "", power) - # power might be in mW... - units = $8 - sub(/\)/, "", units) - sub(/,/, "", units) - if (units == "mW") { - if (power == 100) { - power = 20 - } else if (power == 200) { - power = 23 - } else if (power == 500) { - power = 27 - } else if (power == 1000) { - power = 30 - } else { - print "Unknown power value in database!" - } - } - flagstr = "" - for (i=8; i<=NF; i++) - flagstr = flagstr $i - split(flagstr, flagarray, ",") - flags = "" - for (arg in flagarray) { - if (flagarray[arg] == "NO-OFDM") { - flags = flags "\n\t\t\tNL80211_RRF_NO_OFDM | " - } else if (flagarray[arg] == "NO-CCK") { - flags = flags "\n\t\t\tNL80211_RRF_NO_CCK | " - } else if (flagarray[arg] == "NO-INDOOR") { - flags = flags "\n\t\t\tNL80211_RRF_NO_INDOOR | " - } else if (flagarray[arg] == "NO-OUTDOOR") { - flags = flags "\n\t\t\tNL80211_RRF_NO_OUTDOOR | " - } else if (flagarray[arg] == "DFS") { - flags = flags "\n\t\t\tNL80211_RRF_DFS | " - } else if (flagarray[arg] == "PTP-ONLY") { - flags = flags "\n\t\t\tNL80211_RRF_PTP_ONLY | " - } else if (flagarray[arg] == "PTMP-ONLY") { - flags = flags "\n\t\t\tNL80211_RRF_PTMP_ONLY | " - } else if (flagarray[arg] == "PASSIVE-SCAN") { - flags = flags "\n\t\t\tNL80211_RRF_PASSIVE_SCAN | " - } else if (flagarray[arg] == "NO-IBSS") { - flags = flags "\n\t\t\tNL80211_RRF_NO_IBSS | " - } - } - flags = flags "0" - printf "\t\tREG_RULE(%d, %d, %d, %d, %d, %s),\n", start, end, bw, gain, power, flags - rules++ -} - -active && /^[ \t]*$/ { - active = 0 - printf "\t},\n" - printf "\t.n_reg_rules = %d\n", rules - printf "};\n\n" - rules = 0; -} - -END { - print regdb "};" - print "" - print "int reg_regdb_size = ARRAY_SIZE(reg_regdb);" -} diff --git a/trunk/net/wireless/lib80211_crypt_ccmp.c b/trunk/net/wireless/lib80211_crypt_ccmp.c index b7fa31d5fd13..2301dc1edc4c 100644 --- a/trunk/net/wireless/lib80211_crypt_ccmp.c +++ b/trunk/net/wireless/lib80211_crypt_ccmp.c @@ -237,6 +237,7 @@ static int lib80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv) return -1; pos = skb->data + hdr_len + CCMP_HDR_LEN; + mic = skb_put(skb, CCMP_MIC_LEN); hdr = (struct ieee80211_hdr *)skb->data; ccmp_init_blocks(key->tfm, hdr, key->tx_pn, data_len, b0, b, s0); @@ -256,7 +257,6 @@ static int lib80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv) pos += len; } - mic = skb_put(skb, CCMP_MIC_LEN); for (i = 0; i < CCMP_MIC_LEN; i++) mic[i] = b[i] ^ s0[i]; diff --git a/trunk/net/wireless/lib80211_crypt_tkip.c b/trunk/net/wireless/lib80211_crypt_tkip.c index 8cbdb32ff316..c36287399d7e 100644 --- a/trunk/net/wireless/lib80211_crypt_tkip.c +++ b/trunk/net/wireless/lib80211_crypt_tkip.c @@ -36,8 +36,6 @@ MODULE_AUTHOR("Jouni Malinen"); MODULE_DESCRIPTION("lib80211 crypt: TKIP"); MODULE_LICENSE("GPL"); -#define TKIP_HDR_LEN 8 - struct lib80211_tkip_data { #define TKIP_KEY_LEN 32 u8 key[TKIP_KEY_LEN]; @@ -316,12 +314,13 @@ static int lib80211_tkip_hdr(struct sk_buff *skb, int hdr_len, u8 * rc4key, int keylen, void *priv) { struct lib80211_tkip_data *tkey = priv; + int len; u8 *pos; struct ieee80211_hdr *hdr; hdr = (struct ieee80211_hdr *)skb->data; - if (skb_headroom(skb) < TKIP_HDR_LEN || skb->len < hdr_len) + if (skb_headroom(skb) < 8 || skb->len < hdr_len) return -1; if (rc4key == NULL || keylen < 16) @@ -334,8 +333,9 @@ static int lib80211_tkip_hdr(struct sk_buff *skb, int hdr_len, } tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, tkey->tx_iv16); - pos = skb_push(skb, TKIP_HDR_LEN); - memmove(pos, pos + TKIP_HDR_LEN, hdr_len); + len = skb->len - hdr_len; + pos = skb_push(skb, 8); + memmove(pos, pos + 8, hdr_len); pos += hdr_len; *pos++ = *rc4key; @@ -353,7 +353,7 @@ static int lib80211_tkip_hdr(struct sk_buff *skb, int hdr_len, tkey->tx_iv32++; } - return TKIP_HDR_LEN; + return 8; } static int lib80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) @@ -384,8 +384,9 @@ static int lib80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) if ((lib80211_tkip_hdr(skb, hdr_len, rc4key, 16, priv)) < 0) return -1; - crc = ~crc32_le(~0, pos, len); icv = skb_put(skb, 4); + + crc = ~crc32_le(~0, pos, len); icv[0] = crc; icv[1] = crc >> 8; icv[2] = crc >> 16; @@ -433,7 +434,7 @@ static int lib80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) return -1; } - if (skb->len < hdr_len + TKIP_HDR_LEN + 4) + if (skb->len < hdr_len + 8 + 4) return -1; pos = skb->data + hdr_len; @@ -461,7 +462,7 @@ static int lib80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) } iv16 = (pos[0] << 8) | pos[2]; iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24); - pos += TKIP_HDR_LEN; + pos += 8; if (tkip_replay_check(iv32, iv16, tkey->rx_iv32, tkey->rx_iv16)) { #ifdef CONFIG_LIB80211_DEBUG @@ -522,8 +523,8 @@ static int lib80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) tkey->rx_iv16_new = iv16; /* Remove IV and ICV */ - memmove(skb->data + TKIP_HDR_LEN, skb->data, hdr_len); - skb_pull(skb, TKIP_HDR_LEN); + memmove(skb->data + 8, skb->data, hdr_len); + skb_pull(skb, 8); skb_trim(skb, skb->len - 4); return keyidx; diff --git a/trunk/net/wireless/mlme.c b/trunk/net/wireless/mlme.c index 62bc8855e123..82e6002c8d67 100644 --- a/trunk/net/wireless/mlme.c +++ b/trunk/net/wireless/mlme.c @@ -148,23 +148,22 @@ void __cfg80211_send_deauth(struct net_device *dev, struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; const u8 *bssid = mgmt->bssid; int i; - bool found = false; ASSERT_WDEV_LOCK(wdev); + nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL); + if (wdev->current_bss && memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) { cfg80211_unhold_bss(wdev->current_bss); cfg80211_put_bss(&wdev->current_bss->pub); wdev->current_bss = NULL; - found = true; } else for (i = 0; i < MAX_AUTH_BSSES; i++) { if (wdev->auth_bsses[i] && memcmp(wdev->auth_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) { cfg80211_unhold_bss(wdev->auth_bsses[i]); cfg80211_put_bss(&wdev->auth_bsses[i]->pub); wdev->auth_bsses[i] = NULL; - found = true; break; } if (wdev->authtry_bsses[i] && @@ -172,16 +171,10 @@ void __cfg80211_send_deauth(struct net_device *dev, cfg80211_unhold_bss(wdev->authtry_bsses[i]); cfg80211_put_bss(&wdev->authtry_bsses[i]->pub); wdev->authtry_bsses[i] = NULL; - found = true; break; } } - if (!found) - return; - - nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL); - if (wdev->sme_state == CFG80211_SME_CONNECTED) { u16 reason_code; bool from_ap; @@ -691,206 +684,3 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, } } } - -void cfg80211_ready_on_channel(struct net_device *dev, u64 cookie, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, - unsigned int duration, gfp_t gfp) -{ - struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); - - nl80211_send_remain_on_channel(rdev, dev, cookie, chan, channel_type, - duration, gfp); -} -EXPORT_SYMBOL(cfg80211_ready_on_channel); - -void cfg80211_remain_on_channel_expired(struct net_device *dev, - u64 cookie, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, - gfp_t gfp) -{ - struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); - - nl80211_send_remain_on_channel_cancel(rdev, dev, cookie, chan, - channel_type, gfp); -} -EXPORT_SYMBOL(cfg80211_remain_on_channel_expired); - -void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr, - struct station_info *sinfo, gfp_t gfp) -{ - struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); - - nl80211_send_sta_event(rdev, dev, mac_addr, sinfo, gfp); -} -EXPORT_SYMBOL(cfg80211_new_sta); - -struct cfg80211_action_registration { - struct list_head list; - - u32 nlpid; - - int match_len; - - u8 match[]; -}; - -int cfg80211_mlme_register_action(struct wireless_dev *wdev, u32 snd_pid, - const u8 *match_data, int match_len) -{ - struct cfg80211_action_registration *reg, *nreg; - int err = 0; - - nreg = kzalloc(sizeof(*reg) + match_len, GFP_KERNEL); - if (!nreg) - return -ENOMEM; - - spin_lock_bh(&wdev->action_registrations_lock); - - list_for_each_entry(reg, &wdev->action_registrations, list) { - int mlen = min(match_len, reg->match_len); - - if (memcmp(reg->match, match_data, mlen) == 0) { - err = -EALREADY; - break; - } - } - - if (err) { - kfree(nreg); - goto out; - } - - memcpy(nreg->match, match_data, match_len); - nreg->match_len = match_len; - nreg->nlpid = snd_pid; - list_add(&nreg->list, &wdev->action_registrations); - - out: - spin_unlock_bh(&wdev->action_registrations_lock); - return err; -} - -void cfg80211_mlme_unregister_actions(struct wireless_dev *wdev, u32 nlpid) -{ - struct cfg80211_action_registration *reg, *tmp; - - spin_lock_bh(&wdev->action_registrations_lock); - - list_for_each_entry_safe(reg, tmp, &wdev->action_registrations, list) { - if (reg->nlpid == nlpid) { - list_del(®->list); - kfree(reg); - } - } - - spin_unlock_bh(&wdev->action_registrations_lock); -} - -void cfg80211_mlme_purge_actions(struct wireless_dev *wdev) -{ - struct cfg80211_action_registration *reg, *tmp; - - spin_lock_bh(&wdev->action_registrations_lock); - - list_for_each_entry_safe(reg, tmp, &wdev->action_registrations, list) { - list_del(®->list); - kfree(reg); - } - - spin_unlock_bh(&wdev->action_registrations_lock); -} - -int cfg80211_mlme_action(struct cfg80211_registered_device *rdev, - struct net_device *dev, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, - const u8 *buf, size_t len, u64 *cookie) -{ - struct wireless_dev *wdev = dev->ieee80211_ptr; - const struct ieee80211_mgmt *mgmt; - - if (rdev->ops->action == NULL) - return -EOPNOTSUPP; - if (len < 24 + 1) - return -EINVAL; - - mgmt = (const struct ieee80211_mgmt *) buf; - if (!ieee80211_is_action(mgmt->frame_control)) - return -EINVAL; - if (mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) { - /* Verify that we are associated with the destination AP */ - if (!wdev->current_bss || - memcmp(wdev->current_bss->pub.bssid, mgmt->bssid, - ETH_ALEN) != 0 || - memcmp(wdev->current_bss->pub.bssid, mgmt->da, - ETH_ALEN) != 0) - return -ENOTCONN; - } - - if (memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0) - return -EINVAL; - - /* Transmit the Action frame as requested by user space */ - return rdev->ops->action(&rdev->wiphy, dev, chan, channel_type, - buf, len, cookie); -} - -bool cfg80211_rx_action(struct net_device *dev, int freq, const u8 *buf, - size_t len, gfp_t gfp) -{ - struct wireless_dev *wdev = dev->ieee80211_ptr; - struct wiphy *wiphy = wdev->wiphy; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); - struct cfg80211_action_registration *reg; - const u8 *action_data; - int action_data_len; - bool result = false; - - /* frame length - min size excluding category */ - action_data_len = len - (IEEE80211_MIN_ACTION_SIZE - 1); - - /* action data starts with category */ - action_data = buf + IEEE80211_MIN_ACTION_SIZE - 1; - - spin_lock_bh(&wdev->action_registrations_lock); - - list_for_each_entry(reg, &wdev->action_registrations, list) { - if (reg->match_len > action_data_len) - continue; - - if (memcmp(reg->match, action_data, reg->match_len)) - continue; - - /* found match! */ - - /* Indicate the received Action frame to user space */ - if (nl80211_send_action(rdev, dev, reg->nlpid, freq, - buf, len, gfp)) - continue; - - result = true; - break; - } - - spin_unlock_bh(&wdev->action_registrations_lock); - - return result; -} -EXPORT_SYMBOL(cfg80211_rx_action); - -void cfg80211_action_tx_status(struct net_device *dev, u64 cookie, - const u8 *buf, size_t len, bool ack, gfp_t gfp) -{ - struct wireless_dev *wdev = dev->ieee80211_ptr; - struct wiphy *wiphy = wdev->wiphy; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); - - /* Indicate TX status of the Action frame to user space */ - nl80211_send_action_tx_status(rdev, dev, cookie, buf, len, ack, gfp); -} -EXPORT_SYMBOL(cfg80211_action_tx_status); diff --git a/trunk/net/wireless/nl80211.c b/trunk/net/wireless/nl80211.c index b0495a1da22e..a6028433e3a0 100644 --- a/trunk/net/wireless/nl80211.c +++ b/trunk/net/wireless/nl80211.c @@ -1,7 +1,7 @@ /* * This is the new netlink-based wireless configuration interface. * - * Copyright 2006-2010 Johannes Berg + * Copyright 2006-2009 Johannes Berg */ #include @@ -69,7 +69,6 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { [NL80211_ATTR_WIPHY_RETRY_LONG] = { .type = NLA_U8 }, [NL80211_ATTR_WIPHY_FRAG_THRESHOLD] = { .type = NLA_U32 }, [NL80211_ATTR_WIPHY_RTS_THRESHOLD] = { .type = NLA_U32 }, - [NL80211_ATTR_WIPHY_COVERAGE_CLASS] = { .type = NLA_U8 }, [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 }, [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, @@ -142,13 +141,6 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { [NL80211_ATTR_4ADDR] = { .type = NLA_U8 }, [NL80211_ATTR_PMKID] = { .type = NLA_BINARY, .len = WLAN_PMKID_LEN }, - [NL80211_ATTR_DURATION] = { .type = NLA_U32 }, - [NL80211_ATTR_COOKIE] = { .type = NLA_U64 }, - [NL80211_ATTR_TX_RATES] = { .type = NLA_NESTED }, - [NL80211_ATTR_FRAME] = { .type = NLA_BINARY, - .len = IEEE80211_MAX_DATA_LEN }, - [NL80211_ATTR_FRAME_MATCH] = { .type = NLA_BINARY, }, - [NL80211_ATTR_PS_STATE] = { .type = NLA_U32 }, }; /* policy for the attributes */ @@ -450,8 +442,6 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, dev->wiphy.frag_threshold); NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, dev->wiphy.rts_threshold); - NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, - dev->wiphy.coverage_class); NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS, dev->wiphy.max_scan_ssids); @@ -579,9 +569,6 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, CMD(set_pmksa, SET_PMKSA); CMD(del_pmksa, DEL_PMKSA); CMD(flush_pmksa, FLUSH_PMKSA); - CMD(remain_on_channel, REMAIN_ON_CHANNEL); - CMD(set_bitrate_mask, SET_TX_BITRATE_MASK); - CMD(action, ACTION); if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { i++; NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); @@ -694,7 +681,6 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) u32 changed; u8 retry_short = 0, retry_long = 0; u32 frag_threshold = 0, rts_threshold = 0; - u8 coverage_class = 0; rtnl_lock(); @@ -817,16 +803,9 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) changed |= WIPHY_PARAM_RTS_THRESHOLD; } - if (info->attrs[NL80211_ATTR_WIPHY_COVERAGE_CLASS]) { - coverage_class = nla_get_u8( - info->attrs[NL80211_ATTR_WIPHY_COVERAGE_CLASS]); - changed |= WIPHY_PARAM_COVERAGE_CLASS; - } - if (changed) { u8 old_retry_short, old_retry_long; u32 old_frag_threshold, old_rts_threshold; - u8 old_coverage_class; if (!rdev->ops->set_wiphy_params) { result = -EOPNOTSUPP; @@ -837,7 +816,6 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) old_retry_long = rdev->wiphy.retry_long; old_frag_threshold = rdev->wiphy.frag_threshold; old_rts_threshold = rdev->wiphy.rts_threshold; - old_coverage_class = rdev->wiphy.coverage_class; if (changed & WIPHY_PARAM_RETRY_SHORT) rdev->wiphy.retry_short = retry_short; @@ -847,8 +825,6 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) rdev->wiphy.frag_threshold = frag_threshold; if (changed & WIPHY_PARAM_RTS_THRESHOLD) rdev->wiphy.rts_threshold = rts_threshold; - if (changed & WIPHY_PARAM_COVERAGE_CLASS) - rdev->wiphy.coverage_class = coverage_class; result = rdev->ops->set_wiphy_params(&rdev->wiphy, changed); if (result) { @@ -856,7 +832,6 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) rdev->wiphy.retry_long = old_retry_long; rdev->wiphy.frag_threshold = old_frag_threshold; rdev->wiphy.rts_threshold = old_rts_threshold; - rdev->wiphy.coverage_class = old_coverage_class; } } @@ -1662,9 +1637,42 @@ static int parse_station_flags(struct genl_info *info, return 0; } +static u16 nl80211_calculate_bitrate(struct rate_info *rate) +{ + int modulation, streams, bitrate; + + if (!(rate->flags & RATE_INFO_FLAGS_MCS)) + return rate->legacy; + + /* the formula below does only work for MCS values smaller than 32 */ + if (rate->mcs >= 32) + return 0; + + modulation = rate->mcs & 7; + streams = (rate->mcs >> 3) + 1; + + bitrate = (rate->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) ? + 13500000 : 6500000; + + if (modulation < 4) + bitrate *= (modulation + 1); + else if (modulation == 4) + bitrate *= (modulation + 2); + else + bitrate *= (modulation + 3); + + bitrate *= streams; + + if (rate->flags & RATE_INFO_FLAGS_SHORT_GI) + bitrate = (bitrate / 9) * 10; + + /* do NOT round down here */ + return (bitrate + 50000) / 100000; +} + static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, int flags, struct net_device *dev, - const u8 *mac_addr, struct station_info *sinfo) + u8 *mac_addr, struct station_info *sinfo) { void *hdr; struct nlattr *sinfoattr, *txrate; @@ -1708,8 +1716,8 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, if (!txrate) goto nla_put_failure; - /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */ - bitrate = cfg80211_calculate_bitrate(&sinfo->txrate); + /* nl80211_calculate_bitrate will return 0 for mcs >= 32 */ + bitrate = nl80211_calculate_bitrate(&sinfo->txrate); if (bitrate > 0) NLA_PUT_U16(msg, NL80211_RATE_INFO_BITRATE, bitrate); @@ -2015,9 +2023,6 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) if (!info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) return -EINVAL; - if (!info->attrs[NL80211_ATTR_STA_AID]) - return -EINVAL; - mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); params.supported_rates = nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); @@ -2026,9 +2031,11 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) params.listen_interval = nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]); - params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]); - if (!params.aid || params.aid > IEEE80211_MAX_AID) - return -EINVAL; + if (info->attrs[NL80211_ATTR_STA_AID]) { + params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]); + if (!params.aid || params.aid > IEEE80211_MAX_AID) + return -EINVAL; + } if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) params.ht_capa = @@ -2043,12 +2050,6 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) if (err) goto out_rtnl; - if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN) { - err = -EINVAL; - goto out; - } - err = get_vlan(info, rdev, ¶ms.vlan); if (err) goto out; @@ -2056,6 +2057,35 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) /* validate settings */ err = 0; + switch (dev->ieee80211_ptr->iftype) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_AP_VLAN: + /* all ok but must have AID */ + if (!params.aid) + err = -EINVAL; + break; + case NL80211_IFTYPE_MESH_POINT: + /* disallow things mesh doesn't support */ + if (params.vlan) + err = -EINVAL; + if (params.aid) + err = -EINVAL; + if (params.ht_capa) + err = -EINVAL; + if (params.listen_interval >= 0) + err = -EINVAL; + if (params.supported_rates) + err = -EINVAL; + if (params.sta_flags_mask) + err = -EINVAL; + break; + default: + err = -EINVAL; + } + + if (err) + goto out; + if (!rdev->ops->add_station) { err = -EOPNOTSUPP; goto out; @@ -2096,7 +2126,8 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) goto out_rtnl; if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN) { + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { err = -EINVAL; goto out; } @@ -2552,6 +2583,12 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]); +#ifdef CONFIG_WIRELESS_OLD_REGULATORY + /* We ignore world regdom requests with the old regdom setup */ + if (is_world_regdom(data)) + return -EINVAL; +#endif + r = regulatory_hint_user(data); return r; @@ -3145,10 +3182,6 @@ static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags, NLA_PUT(msg, NL80211_BSS_INFORMATION_ELEMENTS, res->len_information_elements, res->information_elements); - if (res->beacon_ies && res->len_beacon_ies && - res->beacon_ies != res->information_elements) - NLA_PUT(msg, NL80211_BSS_BEACON_IES, - res->len_beacon_ies, res->beacon_ies); if (res->tsf) NLA_PUT_U64(msg, NL80211_BSS_TSF, res->tsf); if (res->beacon_interval) @@ -3553,7 +3586,6 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev; struct net_device *dev; - struct wireless_dev *wdev; struct cfg80211_crypto_settings crypto; struct ieee80211_channel *chan, *fixedchan; const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL; @@ -3599,8 +3631,7 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) } mutex_lock(&rdev->devlist_mtx); - wdev = dev->ieee80211_ptr; - fixedchan = rdev_fixed_channel(rdev, wdev); + fixedchan = rdev_fixed_channel(rdev, NULL); if (fixedchan && chan != fixedchan) { err = -EBUSY; mutex_unlock(&rdev->devlist_mtx); @@ -4291,498 +4322,7 @@ static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info) } -static int nl80211_remain_on_channel(struct sk_buff *skb, - struct genl_info *info) -{ - struct cfg80211_registered_device *rdev; - struct net_device *dev; - struct ieee80211_channel *chan; - struct sk_buff *msg; - void *hdr; - u64 cookie; - enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; - u32 freq, duration; - int err; - - if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] || - !info->attrs[NL80211_ATTR_DURATION]) - return -EINVAL; - - duration = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]); - - /* - * We should be on that channel for at least one jiffie, - * and more than 5 seconds seems excessive. - */ - if (!duration || !msecs_to_jiffies(duration) || duration > 5000) - return -EINVAL; - - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rtnl; - - if (!rdev->ops->remain_on_channel) { - err = -EOPNOTSUPP; - goto out; - } - - if (!netif_running(dev)) { - err = -ENETDOWN; - goto out; - } - - if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { - channel_type = nla_get_u32( - info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]); - if (channel_type != NL80211_CHAN_NO_HT && - channel_type != NL80211_CHAN_HT20 && - channel_type != NL80211_CHAN_HT40PLUS && - channel_type != NL80211_CHAN_HT40MINUS) - err = -EINVAL; - goto out; - } - - freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); - chan = rdev_freq_to_chan(rdev, freq, channel_type); - if (chan == NULL) { - err = -EINVAL; - goto out; - } - - msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); - if (!msg) { - err = -ENOMEM; - goto out; - } - - hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, - NL80211_CMD_REMAIN_ON_CHANNEL); - - if (IS_ERR(hdr)) { - err = PTR_ERR(hdr); - goto free_msg; - } - - err = rdev->ops->remain_on_channel(&rdev->wiphy, dev, chan, - channel_type, duration, &cookie); - - if (err) - goto free_msg; - - NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); - - genlmsg_end(msg, hdr); - err = genlmsg_reply(msg, info); - goto out; - - nla_put_failure: - err = -ENOBUFS; - free_msg: - nlmsg_free(msg); - out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - unlock_rtnl: - rtnl_unlock(); - return err; -} - -static int nl80211_cancel_remain_on_channel(struct sk_buff *skb, - struct genl_info *info) -{ - struct cfg80211_registered_device *rdev; - struct net_device *dev; - u64 cookie; - int err; - - if (!info->attrs[NL80211_ATTR_COOKIE]) - return -EINVAL; - - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rtnl; - - if (!rdev->ops->cancel_remain_on_channel) { - err = -EOPNOTSUPP; - goto out; - } - - if (!netif_running(dev)) { - err = -ENETDOWN; - goto out; - } - - cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]); - - err = rdev->ops->cancel_remain_on_channel(&rdev->wiphy, dev, cookie); - - out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - unlock_rtnl: - rtnl_unlock(); - return err; -} - -static u32 rateset_to_mask(struct ieee80211_supported_band *sband, - u8 *rates, u8 rates_len) -{ - u8 i; - u32 mask = 0; - - for (i = 0; i < rates_len; i++) { - int rate = (rates[i] & 0x7f) * 5; - int ridx; - for (ridx = 0; ridx < sband->n_bitrates; ridx++) { - struct ieee80211_rate *srate = - &sband->bitrates[ridx]; - if (rate == srate->bitrate) { - mask |= 1 << ridx; - break; - } - } - if (ridx == sband->n_bitrates) - return 0; /* rate not found */ - } - - return mask; -} - -static struct nla_policy -nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] __read_mostly = { - [NL80211_TXRATE_LEGACY] = { .type = NLA_BINARY, - .len = NL80211_MAX_SUPP_RATES }, -}; - -static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, - struct genl_info *info) -{ - struct nlattr *tb[NL80211_TXRATE_MAX + 1]; - struct cfg80211_registered_device *rdev; - struct cfg80211_bitrate_mask mask; - int err, rem, i; - struct net_device *dev; - struct nlattr *tx_rates; - struct ieee80211_supported_band *sband; - - if (info->attrs[NL80211_ATTR_TX_RATES] == NULL) - return -EINVAL; - - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rtnl; - - if (!rdev->ops->set_bitrate_mask) { - err = -EOPNOTSUPP; - goto unlock; - } - - memset(&mask, 0, sizeof(mask)); - /* Default to all rates enabled */ - for (i = 0; i < IEEE80211_NUM_BANDS; i++) { - sband = rdev->wiphy.bands[i]; - mask.control[i].legacy = - sband ? (1 << sband->n_bitrates) - 1 : 0; - } - - /* - * The nested attribute uses enum nl80211_band as the index. This maps - * directly to the enum ieee80211_band values used in cfg80211. - */ - nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) - { - enum ieee80211_band band = nla_type(tx_rates); - if (band < 0 || band >= IEEE80211_NUM_BANDS) { - err = -EINVAL; - goto unlock; - } - sband = rdev->wiphy.bands[band]; - if (sband == NULL) { - err = -EINVAL; - goto unlock; - } - nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates), - nla_len(tx_rates), nl80211_txattr_policy); - if (tb[NL80211_TXRATE_LEGACY]) { - mask.control[band].legacy = rateset_to_mask( - sband, - nla_data(tb[NL80211_TXRATE_LEGACY]), - nla_len(tb[NL80211_TXRATE_LEGACY])); - if (mask.control[band].legacy == 0) { - err = -EINVAL; - goto unlock; - } - } - } - - err = rdev->ops->set_bitrate_mask(&rdev->wiphy, dev, NULL, &mask); - - unlock: - dev_put(dev); - cfg80211_unlock_rdev(rdev); - unlock_rtnl: - rtnl_unlock(); - return err; -} - -static int nl80211_register_action(struct sk_buff *skb, struct genl_info *info) -{ - struct cfg80211_registered_device *rdev; - struct net_device *dev; - int err; - - if (!info->attrs[NL80211_ATTR_FRAME_MATCH]) - return -EINVAL; - - if (nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]) < 1) - return -EINVAL; - - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rtnl; - - if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { - err = -EOPNOTSUPP; - goto out; - } - - /* not much point in registering if we can't reply */ - if (!rdev->ops->action) { - err = -EOPNOTSUPP; - goto out; - } - - err = cfg80211_mlme_register_action(dev->ieee80211_ptr, info->snd_pid, - nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]), - nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH])); - out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - unlock_rtnl: - rtnl_unlock(); - return err; -} - -static int nl80211_action(struct sk_buff *skb, struct genl_info *info) -{ - struct cfg80211_registered_device *rdev; - struct net_device *dev; - struct ieee80211_channel *chan; - enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; - u32 freq; - int err; - void *hdr; - u64 cookie; - struct sk_buff *msg; - - if (!info->attrs[NL80211_ATTR_FRAME] || - !info->attrs[NL80211_ATTR_WIPHY_FREQ]) - return -EINVAL; - - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rtnl; - - if (!rdev->ops->action) { - err = -EOPNOTSUPP; - goto out; - } - - if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { - err = -EOPNOTSUPP; - goto out; - } - - if (!netif_running(dev)) { - err = -ENETDOWN; - goto out; - } - - if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { - channel_type = nla_get_u32( - info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]); - if (channel_type != NL80211_CHAN_NO_HT && - channel_type != NL80211_CHAN_HT20 && - channel_type != NL80211_CHAN_HT40PLUS && - channel_type != NL80211_CHAN_HT40MINUS) - err = -EINVAL; - goto out; - } - - freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); - chan = rdev_freq_to_chan(rdev, freq, channel_type); - if (chan == NULL) { - err = -EINVAL; - goto out; - } - - msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); - if (!msg) { - err = -ENOMEM; - goto out; - } - - hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, - NL80211_CMD_ACTION); - - if (IS_ERR(hdr)) { - err = PTR_ERR(hdr); - goto free_msg; - } - err = cfg80211_mlme_action(rdev, dev, chan, channel_type, - nla_data(info->attrs[NL80211_ATTR_FRAME]), - nla_len(info->attrs[NL80211_ATTR_FRAME]), - &cookie); - if (err) - goto free_msg; - - NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); - - genlmsg_end(msg, hdr); - err = genlmsg_reply(msg, info); - goto out; - - nla_put_failure: - err = -ENOBUFS; - free_msg: - nlmsg_free(msg); - out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); -unlock_rtnl: - rtnl_unlock(); - return err; -} - -static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info) -{ - struct cfg80211_registered_device *rdev; - struct wireless_dev *wdev; - struct net_device *dev; - u8 ps_state; - bool state; - int err; - - if (!info->attrs[NL80211_ATTR_PS_STATE]) { - err = -EINVAL; - goto out; - } - - ps_state = nla_get_u32(info->attrs[NL80211_ATTR_PS_STATE]); - - if (ps_state != NL80211_PS_DISABLED && ps_state != NL80211_PS_ENABLED) { - err = -EINVAL; - goto out; - } - - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rdev; - - wdev = dev->ieee80211_ptr; - - if (!rdev->ops->set_power_mgmt) { - err = -EOPNOTSUPP; - goto unlock_rdev; - } - - state = (ps_state == NL80211_PS_ENABLED) ? true : false; - - if (state == wdev->ps) - goto unlock_rdev; - - wdev->ps = state; - - if (rdev->ops->set_power_mgmt(wdev->wiphy, dev, wdev->ps, - wdev->ps_timeout)) - /* assume this means it's off */ - wdev->ps = false; - -unlock_rdev: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - rtnl_unlock(); - -out: - return err; -} - -static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info) -{ - struct cfg80211_registered_device *rdev; - enum nl80211_ps_state ps_state; - struct wireless_dev *wdev; - struct net_device *dev; - struct sk_buff *msg; - void *hdr; - int err; - - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rtnl; - - wdev = dev->ieee80211_ptr; - - if (!rdev->ops->set_power_mgmt) { - err = -EOPNOTSUPP; - goto out; - } - - msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); - if (!msg) { - err = -ENOMEM; - goto out; - } - - hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, - NL80211_CMD_GET_POWER_SAVE); - if (!hdr) { - err = -ENOMEM; - goto free_msg; - } - - if (wdev->ps) - ps_state = NL80211_PS_ENABLED; - else - ps_state = NL80211_PS_DISABLED; - - NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE, ps_state); - - genlmsg_end(msg, hdr); - err = genlmsg_reply(msg, info); - goto out; - -nla_put_failure: - err = -ENOBUFS; - -free_msg: - nlmsg_free(msg); - -out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - -unlock_rtnl: - rtnl_unlock(); - - return err; -} - -static struct genl_ops nl80211_ops[] = { +static struct genl_ops nl80211_ops[] = { { .cmd = NL80211_CMD_GET_WIPHY, .doit = nl80211_get_wiphy, @@ -5044,50 +4584,8 @@ static struct genl_ops nl80211_ops[] = { .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, }, - { - .cmd = NL80211_CMD_REMAIN_ON_CHANNEL, - .doit = nl80211_remain_on_channel, - .policy = nl80211_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, - .doit = nl80211_cancel_remain_on_channel, - .policy = nl80211_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = NL80211_CMD_SET_TX_BITRATE_MASK, - .doit = nl80211_set_tx_bitrate_mask, - .policy = nl80211_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = NL80211_CMD_REGISTER_ACTION, - .doit = nl80211_register_action, - .policy = nl80211_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = NL80211_CMD_ACTION, - .doit = nl80211_action, - .policy = nl80211_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = NL80211_CMD_SET_POWER_SAVE, - .doit = nl80211_set_power_save, - .policy = nl80211_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = NL80211_CMD_GET_POWER_SAVE, - .doit = nl80211_get_power_save, - .policy = nl80211_policy, - /* can be retrieved by unprivileged users */ - }, -}; +}; static struct genl_multicast_group nl80211_mlme_mcgrp = { .name = "mlme", }; @@ -5675,193 +5173,6 @@ void nl80211_send_beacon_hint_event(struct wiphy *wiphy, nlmsg_free(msg); } -static void nl80211_send_remain_on_chan_event( - int cmd, struct cfg80211_registered_device *rdev, - struct net_device *netdev, u64 cookie, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, - unsigned int duration, gfp_t gfp) -{ - struct sk_buff *msg; - void *hdr; - - msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); - if (!msg) - return; - - hdr = nl80211hdr_put(msg, 0, 0, 0, cmd); - if (!hdr) { - nlmsg_free(msg); - return; - } - - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, chan->center_freq); - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, channel_type); - NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); - - if (cmd == NL80211_CMD_REMAIN_ON_CHANNEL) - NLA_PUT_U32(msg, NL80211_ATTR_DURATION, duration); - - if (genlmsg_end(msg, hdr) < 0) { - nlmsg_free(msg); - return; - } - - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); - return; - - nla_put_failure: - genlmsg_cancel(msg, hdr); - nlmsg_free(msg); -} - -void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev, - struct net_device *netdev, u64 cookie, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, - unsigned int duration, gfp_t gfp) -{ - nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL, - rdev, netdev, cookie, chan, - channel_type, duration, gfp); -} - -void nl80211_send_remain_on_channel_cancel( - struct cfg80211_registered_device *rdev, struct net_device *netdev, - u64 cookie, struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, gfp_t gfp) -{ - nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, - rdev, netdev, cookie, chan, - channel_type, 0, gfp); -} - -void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, - struct net_device *dev, const u8 *mac_addr, - struct station_info *sinfo, gfp_t gfp) -{ - struct sk_buff *msg; - - msg = nlmsg_new(NLMSG_GOODSIZE, gfp); - if (!msg) - return; - - if (nl80211_send_station(msg, 0, 0, 0, dev, mac_addr, sinfo) < 0) { - nlmsg_free(msg); - return; - } - - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); -} - -int nl80211_send_action(struct cfg80211_registered_device *rdev, - struct net_device *netdev, u32 nlpid, - int freq, const u8 *buf, size_t len, gfp_t gfp) -{ - struct sk_buff *msg; - void *hdr; - int err; - - msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); - if (!msg) - return -ENOMEM; - - hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ACTION); - if (!hdr) { - nlmsg_free(msg); - return -ENOMEM; - } - - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); - NLA_PUT(msg, NL80211_ATTR_FRAME, len, buf); - - err = genlmsg_end(msg, hdr); - if (err < 0) { - nlmsg_free(msg); - return err; - } - - err = genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlpid); - if (err < 0) - return err; - return 0; - - nla_put_failure: - genlmsg_cancel(msg, hdr); - nlmsg_free(msg); - return -ENOBUFS; -} - -void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev, - struct net_device *netdev, u64 cookie, - const u8 *buf, size_t len, bool ack, - gfp_t gfp) -{ - struct sk_buff *msg; - void *hdr; - - msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); - if (!msg) - return; - - hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ACTION_TX_STATUS); - if (!hdr) { - nlmsg_free(msg); - return; - } - - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); - NLA_PUT(msg, NL80211_ATTR_FRAME, len, buf); - NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); - if (ack) - NLA_PUT_FLAG(msg, NL80211_ATTR_ACK); - - if (genlmsg_end(msg, hdr) < 0) { - nlmsg_free(msg); - return; - } - - genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); - return; - - nla_put_failure: - genlmsg_cancel(msg, hdr); - nlmsg_free(msg); -} - -static int nl80211_netlink_notify(struct notifier_block * nb, - unsigned long state, - void *_notify) -{ - struct netlink_notify *notify = _notify; - struct cfg80211_registered_device *rdev; - struct wireless_dev *wdev; - - if (state != NETLINK_URELEASE) - return NOTIFY_DONE; - - rcu_read_lock(); - - list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) - list_for_each_entry_rcu(wdev, &rdev->netdev_list, list) - cfg80211_mlme_unregister_actions(wdev, notify->pid); - - rcu_read_unlock(); - - return NOTIFY_DONE; -} - -static struct notifier_block nl80211_netlink_notifier = { - .notifier_call = nl80211_netlink_notify, -}; - /* initialisation/exit functions */ int nl80211_init(void) @@ -5895,10 +5206,6 @@ int nl80211_init(void) goto err_out; #endif - err = netlink_register_notifier(&nl80211_netlink_notifier); - if (err) - goto err_out; - return 0; err_out: genl_unregister_family(&nl80211_fam); @@ -5907,6 +5214,5 @@ int nl80211_init(void) void nl80211_exit(void) { - netlink_unregister_notifier(&nl80211_netlink_notifier); genl_unregister_family(&nl80211_fam); } diff --git a/trunk/net/wireless/nl80211.h b/trunk/net/wireless/nl80211.h index 4ca511102c6c..44cc2a76a1b0 100644 --- a/trunk/net/wireless/nl80211.h +++ b/trunk/net/wireless/nl80211.h @@ -59,27 +59,4 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, struct net_device *netdev, const u8 *bssid, gfp_t gfp); -void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev, - struct net_device *netdev, - u64 cookie, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, - unsigned int duration, gfp_t gfp); -void nl80211_send_remain_on_channel_cancel( - struct cfg80211_registered_device *rdev, struct net_device *netdev, - u64 cookie, struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, gfp_t gfp); - -void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, - struct net_device *dev, const u8 *mac_addr, - struct station_info *sinfo, gfp_t gfp); - -int nl80211_send_action(struct cfg80211_registered_device *rdev, - struct net_device *netdev, u32 nlpid, int freq, - const u8 *buf, size_t len, gfp_t gfp); -void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev, - struct net_device *netdev, u64 cookie, - const u8 *buf, size_t len, bool ack, - gfp_t gfp); - #endif /* __NET_WIRELESS_NL80211_H */ diff --git a/trunk/net/wireless/radiotap.c b/trunk/net/wireless/radiotap.c index 1332c445d1c7..f591871a7b4f 100644 --- a/trunk/net/wireless/radiotap.c +++ b/trunk/net/wireless/radiotap.c @@ -2,16 +2,6 @@ * Radiotap parser * * Copyright 2007 Andy Green - * Copyright 2009 Johannes Berg - * - * 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 - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See COPYING for more details. */ #include @@ -20,35 +10,6 @@ /* function prototypes and related defs are in include/net/cfg80211.h */ -static const struct radiotap_align_size rtap_namespace_sizes[] = { - [IEEE80211_RADIOTAP_TSFT] = { .align = 8, .size = 8, }, - [IEEE80211_RADIOTAP_FLAGS] = { .align = 1, .size = 1, }, - [IEEE80211_RADIOTAP_RATE] = { .align = 1, .size = 1, }, - [IEEE80211_RADIOTAP_CHANNEL] = { .align = 2, .size = 4, }, - [IEEE80211_RADIOTAP_FHSS] = { .align = 2, .size = 2, }, - [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = { .align = 1, .size = 1, }, - [IEEE80211_RADIOTAP_DBM_ANTNOISE] = { .align = 1, .size = 1, }, - [IEEE80211_RADIOTAP_LOCK_QUALITY] = { .align = 2, .size = 2, }, - [IEEE80211_RADIOTAP_TX_ATTENUATION] = { .align = 2, .size = 2, }, - [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = { .align = 2, .size = 2, }, - [IEEE80211_RADIOTAP_DBM_TX_POWER] = { .align = 1, .size = 1, }, - [IEEE80211_RADIOTAP_ANTENNA] = { .align = 1, .size = 1, }, - [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = { .align = 1, .size = 1, }, - [IEEE80211_RADIOTAP_DB_ANTNOISE] = { .align = 1, .size = 1, }, - [IEEE80211_RADIOTAP_RX_FLAGS] = { .align = 2, .size = 2, }, - [IEEE80211_RADIOTAP_TX_FLAGS] = { .align = 2, .size = 2, }, - [IEEE80211_RADIOTAP_RTS_RETRIES] = { .align = 1, .size = 1, }, - [IEEE80211_RADIOTAP_DATA_RETRIES] = { .align = 1, .size = 1, }, - /* - * add more here as they are defined in radiotap.h - */ -}; - -static const struct ieee80211_radiotap_namespace radiotap_ns = { - .n_bits = sizeof(rtap_namespace_sizes) / sizeof(rtap_namespace_sizes[0]), - .align_size = rtap_namespace_sizes, -}; - /** * ieee80211_radiotap_iterator_init - radiotap parser iterator initialization * @iterator: radiotap_iterator to initialize @@ -89,9 +50,9 @@ static const struct ieee80211_radiotap_namespace radiotap_ns = { */ int ieee80211_radiotap_iterator_init( - struct ieee80211_radiotap_iterator *iterator, - struct ieee80211_radiotap_header *radiotap_header, - int max_length, const struct ieee80211_radiotap_vendor_namespaces *vns) + struct ieee80211_radiotap_iterator *iterator, + struct ieee80211_radiotap_header *radiotap_header, + int max_length) { /* Linux only supports version 0 radiotap format */ if (radiotap_header->it_version) @@ -101,24 +62,19 @@ int ieee80211_radiotap_iterator_init( if (max_length < get_unaligned_le16(&radiotap_header->it_len)) return -EINVAL; - iterator->_rtheader = radiotap_header; - iterator->_max_length = get_unaligned_le16(&radiotap_header->it_len); - iterator->_arg_index = 0; - iterator->_bitmap_shifter = get_unaligned_le32(&radiotap_header->it_present); - iterator->_arg = (uint8_t *)radiotap_header + sizeof(*radiotap_header); - iterator->_reset_on_ext = 0; - iterator->_next_bitmap = &radiotap_header->it_present; - iterator->_next_bitmap++; - iterator->_vns = vns; - iterator->current_namespace = &radiotap_ns; - iterator->is_radiotap_ns = 1; + iterator->rtheader = radiotap_header; + iterator->max_length = get_unaligned_le16(&radiotap_header->it_len); + iterator->arg_index = 0; + iterator->bitmap_shifter = get_unaligned_le32(&radiotap_header->it_present); + iterator->arg = (u8 *)radiotap_header + sizeof(*radiotap_header); + iterator->this_arg = NULL; /* find payload start allowing for extended bitmap(s) */ - if (iterator->_bitmap_shifter & (1<_arg) & - (1 << IEEE80211_RADIOTAP_EXT)) { - iterator->_arg += sizeof(uint32_t); + if (unlikely(iterator->bitmap_shifter & (1<arg) & + (1 << IEEE80211_RADIOTAP_EXT)) { + iterator->arg += sizeof(u32); /* * check for insanity where the present bitmaps @@ -126,13 +82,12 @@ int ieee80211_radiotap_iterator_init( * stated radiotap header length */ - if ((unsigned long)iterator->_arg - - (unsigned long)iterator->_rtheader > - (unsigned long)iterator->_max_length) + if (((ulong)iterator->arg - + (ulong)iterator->rtheader) > iterator->max_length) return -EINVAL; } - iterator->_arg += sizeof(uint32_t); + iterator->arg += sizeof(u32); /* * no need to check again for blowing past stated radiotap @@ -141,36 +96,12 @@ int ieee80211_radiotap_iterator_init( */ } - iterator->this_arg = iterator->_arg; - /* we are all initialized happily */ return 0; } EXPORT_SYMBOL(ieee80211_radiotap_iterator_init); -static void find_ns(struct ieee80211_radiotap_iterator *iterator, - uint32_t oui, uint8_t subns) -{ - int i; - - iterator->current_namespace = NULL; - - if (!iterator->_vns) - return; - - for (i = 0; i < iterator->_vns->n_ns; i++) { - if (iterator->_vns->ns[i].oui != oui) - continue; - if (iterator->_vns->ns[i].subns != subns) - continue; - - iterator->current_namespace = &iterator->_vns->ns[i]; - break; - } -} - - /** * ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg @@ -196,80 +127,99 @@ static void find_ns(struct ieee80211_radiotap_iterator *iterator, */ int ieee80211_radiotap_iterator_next( - struct ieee80211_radiotap_iterator *iterator) + struct ieee80211_radiotap_iterator *iterator) { - while (1) { - int hit = 0; - int pad, align, size, subns, vnslen; - uint32_t oui; - /* if no more EXT bits, that's it */ - if ((iterator->_arg_index % 32) == IEEE80211_RADIOTAP_EXT && - !(iterator->_bitmap_shifter & 1)) - return -ENOENT; + /* + * small length lookup table for all radiotap types we heard of + * starting from b0 in the bitmap, so we can walk the payload + * area of the radiotap header + * + * There is a requirement to pad args, so that args + * of a given length must begin at a boundary of that length + * -- but note that compound args are allowed (eg, 2 x u16 + * for IEEE80211_RADIOTAP_CHANNEL) so total arg length is not + * a reliable indicator of alignment requirement. + * + * upper nybble: content alignment for arg + * lower nybble: content length for arg + */ - if (!(iterator->_bitmap_shifter & 1)) - goto next_entry; /* arg not present */ + static const u8 rt_sizes[] = { + [IEEE80211_RADIOTAP_TSFT] = 0x88, + [IEEE80211_RADIOTAP_FLAGS] = 0x11, + [IEEE80211_RADIOTAP_RATE] = 0x11, + [IEEE80211_RADIOTAP_CHANNEL] = 0x24, + [IEEE80211_RADIOTAP_FHSS] = 0x22, + [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = 0x11, + [IEEE80211_RADIOTAP_DBM_ANTNOISE] = 0x11, + [IEEE80211_RADIOTAP_LOCK_QUALITY] = 0x22, + [IEEE80211_RADIOTAP_TX_ATTENUATION] = 0x22, + [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = 0x22, + [IEEE80211_RADIOTAP_DBM_TX_POWER] = 0x11, + [IEEE80211_RADIOTAP_ANTENNA] = 0x11, + [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = 0x11, + [IEEE80211_RADIOTAP_DB_ANTNOISE] = 0x11, + [IEEE80211_RADIOTAP_RX_FLAGS] = 0x22, + [IEEE80211_RADIOTAP_TX_FLAGS] = 0x22, + [IEEE80211_RADIOTAP_RTS_RETRIES] = 0x11, + [IEEE80211_RADIOTAP_DATA_RETRIES] = 0x11, + /* + * add more here as they are defined in + * include/net/ieee80211_radiotap.h + */ + }; - /* get alignment/size of data */ - switch (iterator->_arg_index % 32) { - case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE: - case IEEE80211_RADIOTAP_EXT: - align = 1; - size = 0; - break; - case IEEE80211_RADIOTAP_VENDOR_NAMESPACE: - align = 2; - size = 6; - break; - default: - if (!iterator->current_namespace || - iterator->_arg_index >= iterator->current_namespace->n_bits) { - if (iterator->current_namespace == &radiotap_ns) - return -ENOENT; - align = 0; - } else { - align = iterator->current_namespace->align_size[iterator->_arg_index].align; - size = iterator->current_namespace->align_size[iterator->_arg_index].size; - } - if (!align) { - /* skip all subsequent data */ - iterator->_arg = iterator->_next_ns_data; - /* give up on this namespace */ - iterator->current_namespace = NULL; - goto next_entry; - } - break; - } + /* + * for every radiotap entry we can at + * least skip (by knowing the length)... + */ + + while (iterator->arg_index < sizeof(rt_sizes)) { + int hit = 0; + int pad; + + if (!(iterator->bitmap_shifter & 1)) + goto next_entry; /* arg not present */ /* * arg is present, account for alignment padding + * 8-bit args can be at any alignment + * 16-bit args must start on 16-bit boundary + * 32-bit args must start on 32-bit boundary + * 64-bit args must start on 64-bit boundary * - * Note that these alignments are relative to the start - * of the radiotap header. There is no guarantee + * note that total arg size can differ from alignment of + * elements inside arg, so we use upper nybble of length + * table to base alignment on + * + * also note: these alignments are ** relative to the + * start of the radiotap header **. There is no guarantee * that the radiotap header itself is aligned on any * kind of boundary. * - * The above is why get_unaligned() is used to dereference - * multibyte elements from the radiotap area. + * the above is why get_unaligned() is used to dereference + * multibyte elements from the radiotap area */ - pad = ((unsigned long)iterator->_arg - - (unsigned long)iterator->_rtheader) & (align - 1); + pad = (((ulong)iterator->arg) - + ((ulong)iterator->rtheader)) & + ((rt_sizes[iterator->arg_index] >> 4) - 1); if (pad) - iterator->_arg += align - pad; + iterator->arg += + (rt_sizes[iterator->arg_index] >> 4) - pad; /* * this is what we will return to user, but we need to * move on first so next call has something fresh to test */ - iterator->this_arg_index = iterator->_arg_index; - iterator->this_arg = iterator->_arg; - iterator->this_arg_size = size; + iterator->this_arg_index = iterator->arg_index; + iterator->this_arg = iterator->arg; + hit = 1; /* internally move on the size of this arg */ - iterator->_arg += size; + iterator->arg += rt_sizes[iterator->arg_index] & 0x0f; /* * check for insanity where we are given a bitmap that @@ -278,73 +228,32 @@ int ieee80211_radiotap_iterator_next( * max_length on the last arg, never exceeding it. */ - if ((unsigned long)iterator->_arg - - (unsigned long)iterator->_rtheader > - (unsigned long)iterator->_max_length) + if (((ulong)iterator->arg - (ulong)iterator->rtheader) > + iterator->max_length) return -EINVAL; - /* these special ones are valid in each bitmap word */ - switch (iterator->_arg_index % 32) { - case IEEE80211_RADIOTAP_VENDOR_NAMESPACE: - iterator->_bitmap_shifter >>= 1; - iterator->_arg_index++; - - iterator->_reset_on_ext = 1; - - vnslen = get_unaligned_le16(iterator->this_arg + 4); - iterator->_next_ns_data = iterator->_arg + vnslen; - oui = (*iterator->this_arg << 16) | - (*(iterator->this_arg + 1) << 8) | - *(iterator->this_arg + 2); - subns = *(iterator->this_arg + 3); - - find_ns(iterator, oui, subns); - - iterator->is_radiotap_ns = 0; - /* allow parsers to show this information */ - iterator->this_arg_index = - IEEE80211_RADIOTAP_VENDOR_NAMESPACE; - iterator->this_arg_size += vnslen; - if ((unsigned long)iterator->this_arg + - iterator->this_arg_size - - (unsigned long)iterator->_rtheader > - (unsigned long)(unsigned long)iterator->_max_length) - return -EINVAL; - hit = 1; - break; - case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE: - iterator->_bitmap_shifter >>= 1; - iterator->_arg_index++; - - iterator->_reset_on_ext = 1; - iterator->current_namespace = &radiotap_ns; - iterator->is_radiotap_ns = 1; - break; - case IEEE80211_RADIOTAP_EXT: - /* - * bit 31 was set, there is more - * -- move to next u32 bitmap - */ - iterator->_bitmap_shifter = - get_unaligned_le32(iterator->_next_bitmap); - iterator->_next_bitmap++; - if (iterator->_reset_on_ext) - iterator->_arg_index = 0; - else - iterator->_arg_index++; - iterator->_reset_on_ext = 0; - break; - default: - /* we've got a hit! */ - hit = 1; - next_entry: - iterator->_bitmap_shifter >>= 1; - iterator->_arg_index++; - } + next_entry: + iterator->arg_index++; + if (unlikely((iterator->arg_index & 31) == 0)) { + /* completed current u32 bitmap */ + if (iterator->bitmap_shifter & 1) { + /* b31 was set, there is more */ + /* move to next u32 bitmap */ + iterator->bitmap_shifter = + get_unaligned_le32(iterator->next_bitmap); + iterator->next_bitmap++; + } else + /* no more bitmaps: end */ + iterator->arg_index = sizeof(rt_sizes); + } else /* just try the next bit */ + iterator->bitmap_shifter >>= 1; /* if we found a valid arg earlier, return it now */ if (hit) return 0; } + + /* we don't know how to handle any more args, we're done */ + return -ENOENT; } EXPORT_SYMBOL(ieee80211_radiotap_iterator_next); diff --git a/trunk/net/wireless/reg.c b/trunk/net/wireless/reg.c index ed89c59bb431..7a0754c92df4 100644 --- a/trunk/net/wireless/reg.c +++ b/trunk/net/wireless/reg.c @@ -40,18 +40,8 @@ #include #include "core.h" #include "reg.h" -#include "regdb.h" #include "nl80211.h" -#ifdef CONFIG_CFG80211_REG_DEBUG -#define REG_DBG_PRINT(format, args...) \ - do { \ - printk(KERN_DEBUG format , ## args); \ - } while (0) -#else -#define REG_DBG_PRINT(args...) -#endif - /* Receipt of information from last regulatory request */ static struct regulatory_request *last_request; @@ -134,11 +124,82 @@ static const struct ieee80211_regdomain *cfg80211_world_regdom = &world_regdom; static char *ieee80211_regdom = "00"; -static char user_alpha2[2]; module_param(ieee80211_regdom, charp, 0444); MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); +#ifdef CONFIG_WIRELESS_OLD_REGULATORY +/* + * We assume 40 MHz bandwidth for the old regulatory work. + * We make emphasis we are using the exact same frequencies + * as before + */ + +static const struct ieee80211_regdomain us_regdom = { + .n_reg_rules = 6, + .alpha2 = "US", + .reg_rules = { + /* IEEE 802.11b/g, channels 1..11 */ + REG_RULE(2412-10, 2462+10, 40, 6, 27, 0), + /* IEEE 802.11a, channel 36..48 */ + REG_RULE(5180-10, 5240+10, 40, 6, 17, 0), + /* IEEE 802.11a, channels 48..64 */ + REG_RULE(5260-10, 5320+10, 40, 6, 20, NL80211_RRF_DFS), + /* IEEE 802.11a, channels 100..124 */ + REG_RULE(5500-10, 5590+10, 40, 6, 20, NL80211_RRF_DFS), + /* IEEE 802.11a, channels 132..144 */ + REG_RULE(5660-10, 5700+10, 40, 6, 20, NL80211_RRF_DFS), + /* IEEE 802.11a, channels 149..165, outdoor */ + REG_RULE(5745-10, 5825+10, 40, 6, 30, 0), + } +}; + +static const struct ieee80211_regdomain jp_regdom = { + .n_reg_rules = 6, + .alpha2 = "JP", + .reg_rules = { + /* IEEE 802.11b/g, channels 1..11 */ + REG_RULE(2412-10, 2462+10, 40, 6, 20, 0), + /* IEEE 802.11b/g, channels 12..13 */ + REG_RULE(2467-10, 2472+10, 20, 6, 20, 0), + /* IEEE 802.11b/g, channel 14 */ + REG_RULE(2484-10, 2484+10, 20, 6, 20, NL80211_RRF_NO_OFDM), + /* IEEE 802.11a, channels 36..48 */ + REG_RULE(5180-10, 5240+10, 40, 6, 20, 0), + /* IEEE 802.11a, channels 52..64 */ + REG_RULE(5260-10, 5320+10, 40, 6, 20, NL80211_RRF_DFS), + /* IEEE 802.11a, channels 100..144 */ + REG_RULE(5500-10, 5700+10, 40, 6, 23, NL80211_RRF_DFS), + } +}; + +static const struct ieee80211_regdomain *static_regdom(char *alpha2) +{ + if (alpha2[0] == 'U' && alpha2[1] == 'S') + return &us_regdom; + if (alpha2[0] == 'J' && alpha2[1] == 'P') + return &jp_regdom; + /* Use world roaming rules for "EU", since it was a pseudo + domain anyway... */ + if (alpha2[0] == 'E' && alpha2[1] == 'U') + return &world_regdom; + /* Default, world roaming rules */ + return &world_regdom; +} + +static bool is_old_static_regdom(const struct ieee80211_regdomain *rd) +{ + if (rd == &us_regdom || rd == &jp_regdom || rd == &world_regdom) + return true; + return false; +} +#else +static inline bool is_old_static_regdom(const struct ieee80211_regdomain *rd) +{ + return false; +} +#endif + static void reset_regdomains(void) { /* avoid freeing static information or freeing something twice */ @@ -148,6 +209,8 @@ static void reset_regdomains(void) cfg80211_world_regdom = NULL; if (cfg80211_regdomain == &world_regdom) cfg80211_regdomain = NULL; + if (is_old_static_regdom(cfg80211_regdomain)) + cfg80211_regdomain = NULL; kfree(cfg80211_regdomain); kfree(cfg80211_world_regdom); @@ -253,27 +316,6 @@ static bool regdom_changes(const char *alpha2) return true; } -/* - * The NL80211_REGDOM_SET_BY_USER regdom alpha2 is cached, this lets - * you know if a valid regulatory hint with NL80211_REGDOM_SET_BY_USER - * has ever been issued. - */ -static bool is_user_regdom_saved(void) -{ - if (user_alpha2[0] == '9' && user_alpha2[1] == '7') - return false; - - /* This would indicate a mistake on the design */ - if (WARN((!is_world_regdom(user_alpha2) && - !is_an_alpha2(user_alpha2)), - "Unexpected user alpha2: %c%c\n", - user_alpha2[0], - user_alpha2[1])) - return false; - - return true; -} - /** * country_ie_integrity_changes - tells us if the country IE has changed * @checksum: checksum of country IE of fields we are interested in @@ -293,98 +335,6 @@ static bool country_ie_integrity_changes(u32 checksum) return false; } -static int reg_copy_regd(const struct ieee80211_regdomain **dst_regd, - const struct ieee80211_regdomain *src_regd) -{ - struct ieee80211_regdomain *regd; - int size_of_regd = 0; - unsigned int i; - - size_of_regd = sizeof(struct ieee80211_regdomain) + - ((src_regd->n_reg_rules + 1) * sizeof(struct ieee80211_reg_rule)); - - regd = kzalloc(size_of_regd, GFP_KERNEL); - if (!regd) - return -ENOMEM; - - memcpy(regd, src_regd, sizeof(struct ieee80211_regdomain)); - - for (i = 0; i < src_regd->n_reg_rules; i++) - memcpy(®d->reg_rules[i], &src_regd->reg_rules[i], - sizeof(struct ieee80211_reg_rule)); - - *dst_regd = regd; - return 0; -} - -#ifdef CONFIG_CFG80211_INTERNAL_REGDB -struct reg_regdb_search_request { - char alpha2[2]; - struct list_head list; -}; - -static LIST_HEAD(reg_regdb_search_list); -static DEFINE_SPINLOCK(reg_regdb_search_lock); - -static void reg_regdb_search(struct work_struct *work) -{ - struct reg_regdb_search_request *request; - const struct ieee80211_regdomain *curdom, *regdom; - int i, r; - - spin_lock(®_regdb_search_lock); - while (!list_empty(®_regdb_search_list)) { - request = list_first_entry(®_regdb_search_list, - struct reg_regdb_search_request, - list); - list_del(&request->list); - - for (i=0; ialpha2, curdom->alpha2, 2)) { - r = reg_copy_regd(®dom, curdom); - if (r) - break; - spin_unlock(®_regdb_search_lock); - mutex_lock(&cfg80211_mutex); - set_regdom(regdom); - mutex_unlock(&cfg80211_mutex); - spin_lock(®_regdb_search_lock); - break; - } - } - - kfree(request); - } - spin_unlock(®_regdb_search_lock); -} - -static DECLARE_WORK(reg_regdb_work, reg_regdb_search); - -static void reg_regdb_query(const char *alpha2) -{ - struct reg_regdb_search_request *request; - - if (!alpha2) - return; - - request = kzalloc(sizeof(struct reg_regdb_search_request), GFP_KERNEL); - if (!request) - return; - - memcpy(request->alpha2, alpha2, 2); - - spin_lock(®_regdb_search_lock); - list_add_tail(&request->list, ®_regdb_search_list); - spin_unlock(®_regdb_search_lock); - - schedule_work(®_regdb_work); -} -#else -static inline void reg_regdb_query(const char *alpha2) {} -#endif /* CONFIG_CFG80211_INTERNAL_REGDB */ - /* * This lets us keep regulatory code which is updated on a regulatory * basis in userspace. @@ -404,9 +354,6 @@ static int call_crda(const char *alpha2) printk(KERN_INFO "cfg80211: Calling CRDA to update world " "regulatory domain\n"); - /* query internal regulatory database (if it exists) */ - reg_regdb_query(alpha2); - country_env[8] = alpha2[0]; country_env[9] = alpha2[1]; @@ -506,205 +453,6 @@ static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range, #undef ONE_GHZ_IN_KHZ } -/* - * This is a work around for sanity checking ieee80211_channel_to_frequency()'s - * work. ieee80211_channel_to_frequency() can for example currently provide a - * 2 GHz channel when in fact a 5 GHz channel was desired. An example would be - * an AP providing channel 8 on a country IE triplet when it sent this on the - * 5 GHz band, that channel is designed to be channel 8 on 5 GHz, not a 2 GHz - * channel. - * - * This can be removed once ieee80211_channel_to_frequency() takes in a band. - */ -static bool chan_in_band(int chan, enum ieee80211_band band) -{ - int center_freq = ieee80211_channel_to_frequency(chan); - - switch (band) { - case IEEE80211_BAND_2GHZ: - if (center_freq <= 2484) - return true; - return false; - case IEEE80211_BAND_5GHZ: - if (center_freq >= 5005) - return true; - return false; - default: - return false; - } -} - -/* - * Some APs may send a country IE triplet for each channel they - * support and while this is completely overkill and silly we still - * need to support it. We avoid making a single rule for each channel - * though and to help us with this we use this helper to find the - * actual subband end channel. These type of country IE triplet - * scenerios are handled then, all yielding two regulaotry rules from - * parsing a country IE: - * - * [1] - * [2] - * [36] - * [40] - * - * [1] - * [2-4] - * [5-12] - * [36] - * [40-44] - * - * [1-4] - * [5-7] - * [36-44] - * [48-64] - * - * [36-36] - * [40-40] - * [44-44] - * [48-48] - * [52-52] - * [56-56] - * [60-60] - * [64-64] - * [100-100] - * [104-104] - * [108-108] - * [112-112] - * [116-116] - * [120-120] - * [124-124] - * [128-128] - * [132-132] - * [136-136] - * [140-140] - * - * Returns 0 if the IE has been found to be invalid in the middle - * somewhere. - */ -static int max_subband_chan(enum ieee80211_band band, - int orig_cur_chan, - int orig_end_channel, - s8 orig_max_power, - u8 **country_ie, - u8 *country_ie_len) -{ - u8 *triplets_start = *country_ie; - u8 len_at_triplet = *country_ie_len; - int end_subband_chan = orig_end_channel; - - /* - * We'll deal with padding for the caller unless - * its not immediate and we don't process any channels - */ - if (*country_ie_len == 1) { - *country_ie += 1; - *country_ie_len -= 1; - return orig_end_channel; - } - - /* Move to the next triplet and then start search */ - *country_ie += 3; - *country_ie_len -= 3; - - if (!chan_in_band(orig_cur_chan, band)) - return 0; - - while (*country_ie_len >= 3) { - int end_channel = 0; - struct ieee80211_country_ie_triplet *triplet = - (struct ieee80211_country_ie_triplet *) *country_ie; - int cur_channel = 0, next_expected_chan; - - /* means last triplet is completely unrelated to this one */ - if (triplet->ext.reg_extension_id >= - IEEE80211_COUNTRY_EXTENSION_ID) { - *country_ie -= 3; - *country_ie_len += 3; - break; - } - - if (triplet->chans.first_channel == 0) { - *country_ie += 1; - *country_ie_len -= 1; - if (*country_ie_len != 0) - return 0; - break; - } - - if (triplet->chans.num_channels == 0) - return 0; - - /* Monitonically increasing channel order */ - if (triplet->chans.first_channel <= end_subband_chan) - return 0; - - if (!chan_in_band(triplet->chans.first_channel, band)) - return 0; - - /* 2 GHz */ - if (triplet->chans.first_channel <= 14) { - end_channel = triplet->chans.first_channel + - triplet->chans.num_channels - 1; - } - else { - end_channel = triplet->chans.first_channel + - (4 * (triplet->chans.num_channels - 1)); - } - - if (!chan_in_band(end_channel, band)) - return 0; - - if (orig_max_power != triplet->chans.max_power) { - *country_ie -= 3; - *country_ie_len += 3; - break; - } - - cur_channel = triplet->chans.first_channel; - - /* The key is finding the right next expected channel */ - if (band == IEEE80211_BAND_2GHZ) - next_expected_chan = end_subband_chan + 1; - else - next_expected_chan = end_subband_chan + 4; - - if (cur_channel != next_expected_chan) { - *country_ie -= 3; - *country_ie_len += 3; - break; - } - - end_subband_chan = end_channel; - - /* Move to the next one */ - *country_ie += 3; - *country_ie_len -= 3; - - /* - * Padding needs to be dealt with if we processed - * some channels. - */ - if (*country_ie_len == 1) { - *country_ie += 1; - *country_ie_len -= 1; - break; - } - - /* If seen, the IE is invalid */ - if (*country_ie_len == 2) - return 0; - } - - if (end_subband_chan == orig_end_channel) { - *country_ie = triplets_start; - *country_ie_len = len_at_triplet; - return orig_end_channel; - } - - return end_subband_chan; -} - /* * Converts a country IE to a regulatory domain. A regulatory domain * structure has a lot of information which the IE doesn't yet have, @@ -712,7 +460,6 @@ static int max_subband_chan(enum ieee80211_band band, * with our userspace regulatory agent to get lower bounds. */ static struct ieee80211_regdomain *country_ie_2_rd( - enum ieee80211_band band, u8 *country_ie, u8 country_ie_len, u32 *checksum) @@ -774,29 +521,10 @@ static struct ieee80211_regdomain *country_ie_2_rd( continue; } - /* - * APs can add padding to make length divisible - * by two, required by the spec. - */ - if (triplet->chans.first_channel == 0) { - country_ie++; - country_ie_len--; - /* This is expected to be at the very end only */ - if (country_ie_len != 0) - return NULL; - break; - } - - if (triplet->chans.num_channels == 0) - return NULL; - - if (!chan_in_band(triplet->chans.first_channel, band)) - return NULL; - /* 2 GHz */ - if (band == IEEE80211_BAND_2GHZ) + if (triplet->chans.first_channel <= 14) end_channel = triplet->chans.first_channel + - triplet->chans.num_channels - 1; + triplet->chans.num_channels; else /* * 5 GHz -- For example in country IEs if the first @@ -811,24 +539,6 @@ static struct ieee80211_regdomain *country_ie_2_rd( (4 * (triplet->chans.num_channels - 1)); cur_channel = triplet->chans.first_channel; - - /* - * Enhancement for APs that send a triplet for every channel - * or for whatever reason sends triplets with multiple channels - * separated when in fact they should be together. - */ - end_channel = max_subband_chan(band, - cur_channel, - end_channel, - triplet->chans.max_power, - &country_ie, - &country_ie_len); - if (!end_channel) - return NULL; - - if (!chan_in_band(end_channel, band)) - return NULL; - cur_sub_max_channel = end_channel; /* Basic sanity check */ @@ -859,13 +569,10 @@ static struct ieee80211_regdomain *country_ie_2_rd( last_sub_max_channel = cur_sub_max_channel; + country_ie += 3; + country_ie_len -= 3; num_rules++; - if (country_ie_len >= 3) { - country_ie += 3; - country_ie_len -= 3; - } - /* * Note: this is not a IEEE requirement but * simply a memory requirement @@ -908,12 +615,6 @@ static struct ieee80211_regdomain *country_ie_2_rd( continue; } - if (triplet->chans.first_channel == 0) { - country_ie++; - country_ie_len--; - break; - } - reg_rule = &rd->reg_rules[i]; freq_range = ®_rule->freq_range; power_rule = ®_rule->power_rule; @@ -921,20 +622,13 @@ static struct ieee80211_regdomain *country_ie_2_rd( reg_rule->flags = flags; /* 2 GHz */ - if (band == IEEE80211_BAND_2GHZ) + if (triplet->chans.first_channel <= 14) end_channel = triplet->chans.first_channel + - triplet->chans.num_channels -1; + triplet->chans.num_channels; else end_channel = triplet->chans.first_channel + (4 * (triplet->chans.num_channels - 1)); - end_channel = max_subband_chan(band, - triplet->chans.first_channel, - end_channel, - triplet->chans.max_power, - &country_ie, - &country_ie_len); - /* * The +10 is since the regulatory domain expects * the actual band edge, not the center of freq for @@ -955,15 +649,12 @@ static struct ieee80211_regdomain *country_ie_2_rd( */ freq_range->max_bandwidth_khz = MHZ_TO_KHZ(40); power_rule->max_antenna_gain = DBI_TO_MBI(100); - power_rule->max_eirp = DBM_TO_MBM(triplet->chans.max_power); + power_rule->max_eirp = DBM_TO_MBM(100); + country_ie += 3; + country_ie_len -= 3; i++; - if (country_ie_len >= 3) { - country_ie += 3; - country_ie_len -= 3; - } - BUG_ON(i > NL80211_MAX_SUPP_REG_RULES); } @@ -1259,21 +950,25 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, if (r == -ERANGE && last_request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) { - REG_DBG_PRINT("cfg80211: Leaving channel %d MHz " +#ifdef CONFIG_CFG80211_REG_DEBUG + printk(KERN_DEBUG "cfg80211: Leaving channel %d MHz " "intact on %s - no rule found in band on " "Country IE\n", - chan->center_freq, wiphy_name(wiphy)); + chan->center_freq, wiphy_name(wiphy)); +#endif } else { /* * In this case we know the country IE has at least one reg rule * for the band so we respect its band definitions */ +#ifdef CONFIG_CFG80211_REG_DEBUG if (last_request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) - REG_DBG_PRINT("cfg80211: Disabling " + printk(KERN_DEBUG "cfg80211: Disabling " "channel %d MHz on %s due to " "Country IE\n", chan->center_freq, wiphy_name(wiphy)); +#endif flags |= IEEE80211_CHAN_DISABLED; chan->flags = flags; } @@ -1647,6 +1342,30 @@ void wiphy_apply_custom_regulatory(struct wiphy *wiphy, } EXPORT_SYMBOL(wiphy_apply_custom_regulatory); +static int reg_copy_regd(const struct ieee80211_regdomain **dst_regd, + const struct ieee80211_regdomain *src_regd) +{ + struct ieee80211_regdomain *regd; + int size_of_regd = 0; + unsigned int i; + + size_of_regd = sizeof(struct ieee80211_regdomain) + + ((src_regd->n_reg_rules + 1) * sizeof(struct ieee80211_reg_rule)); + + regd = kzalloc(size_of_regd, GFP_KERNEL); + if (!regd) + return -ENOMEM; + + memcpy(regd, src_regd, sizeof(struct ieee80211_regdomain)); + + for (i = 0; i < src_regd->n_reg_rules; i++) + memcpy(®d->reg_rules[i], &src_regd->reg_rules[i], + sizeof(struct ieee80211_reg_rule)); + + *dst_regd = regd; + return 0; +} + /* * Return value which can be used by ignore_request() to indicate * it has been determined we should intersect two regulatory domains @@ -1668,7 +1387,7 @@ static int ignore_request(struct wiphy *wiphy, switch (pending_request->initiator) { case NL80211_REGDOM_SET_BY_CORE: - return 0; + return -EINVAL; case NL80211_REGDOM_SET_BY_COUNTRY_IE: last_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); @@ -1699,6 +1418,8 @@ static int ignore_request(struct wiphy *wiphy, return REG_INTERSECT; case NL80211_REGDOM_SET_BY_DRIVER: if (last_request->initiator == NL80211_REGDOM_SET_BY_CORE) { + if (is_old_static_regdom(cfg80211_regdomain)) + return 0; if (regdom_changes(pending_request->alpha2)) return 0; return -EALREADY; @@ -1735,7 +1456,8 @@ static int ignore_request(struct wiphy *wiphy, return -EAGAIN; } - if (!regdom_changes(pending_request->alpha2)) + if (!is_old_static_regdom(cfg80211_regdomain) && + !regdom_changes(pending_request->alpha2)) return -EALREADY; return 0; @@ -1807,11 +1529,6 @@ static int __regulatory_hint(struct wiphy *wiphy, pending_request = NULL; - if (last_request->initiator == NL80211_REGDOM_SET_BY_USER) { - user_alpha2[0] = last_request->alpha2[0]; - user_alpha2[1] = last_request->alpha2[1]; - } - /* When r == REG_INTERSECT we do need to call CRDA */ if (r < 0) { /* @@ -1931,16 +1648,12 @@ static void queue_regulatory_request(struct regulatory_request *request) schedule_work(®_work); } -/* - * Core regulatory hint -- happens during cfg80211_init() - * and when we restore regulatory settings. - */ +/* Core regulatory hint -- happens once during cfg80211_init() */ static int regulatory_hint_core(const char *alpha2) { struct regulatory_request *request; - kfree(last_request); - last_request = NULL; + BUG_ON(last_request); request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL); @@ -1951,12 +1664,14 @@ static int regulatory_hint_core(const char *alpha2) request->alpha2[1] = alpha2[1]; request->initiator = NL80211_REGDOM_SET_BY_CORE; + queue_regulatory_request(request); + /* * This ensures last_request is populated once modules * come swinging in and calling regulatory hints and * wiphy_apply_custom_regulatory(). */ - reg_process_hint(request); + flush_scheduled_work(); return 0; } @@ -2043,9 +1758,8 @@ static bool reg_same_country_ie_hint(struct wiphy *wiphy, * therefore cannot iterate over the rdev list here. */ void regulatory_hint_11d(struct wiphy *wiphy, - enum ieee80211_band band, - u8 *country_ie, - u8 country_ie_len) + u8 *country_ie, + u8 country_ie_len) { struct ieee80211_regdomain *rd = NULL; char alpha2[2]; @@ -2091,11 +1805,9 @@ void regulatory_hint_11d(struct wiphy *wiphy, wiphy_idx_valid(last_request->wiphy_idx))) goto out; - rd = country_ie_2_rd(band, country_ie, country_ie_len, &checksum); - if (!rd) { - REG_DBG_PRINT("cfg80211: Ignoring bogus country IE\n"); + rd = country_ie_2_rd(country_ie, country_ie_len, &checksum); + if (!rd) goto out; - } /* * This will not happen right now but we leave it here for the @@ -2138,123 +1850,6 @@ void regulatory_hint_11d(struct wiphy *wiphy, mutex_unlock(®_mutex); } -static void restore_alpha2(char *alpha2, bool reset_user) -{ - /* indicates there is no alpha2 to consider for restoration */ - alpha2[0] = '9'; - alpha2[1] = '7'; - - /* The user setting has precedence over the module parameter */ - if (is_user_regdom_saved()) { - /* Unless we're asked to ignore it and reset it */ - if (reset_user) { - REG_DBG_PRINT("cfg80211: Restoring regulatory settings " - "including user preference\n"); - user_alpha2[0] = '9'; - user_alpha2[1] = '7'; - - /* - * If we're ignoring user settings, we still need to - * check the module parameter to ensure we put things - * back as they were for a full restore. - */ - if (!is_world_regdom(ieee80211_regdom)) { - REG_DBG_PRINT("cfg80211: Keeping preference on " - "module parameter ieee80211_regdom: %c%c\n", - ieee80211_regdom[0], - ieee80211_regdom[1]); - alpha2[0] = ieee80211_regdom[0]; - alpha2[1] = ieee80211_regdom[1]; - } - } else { - REG_DBG_PRINT("cfg80211: Restoring regulatory settings " - "while preserving user preference for: %c%c\n", - user_alpha2[0], - user_alpha2[1]); - alpha2[0] = user_alpha2[0]; - alpha2[1] = user_alpha2[1]; - } - } else if (!is_world_regdom(ieee80211_regdom)) { - REG_DBG_PRINT("cfg80211: Keeping preference on " - "module parameter ieee80211_regdom: %c%c\n", - ieee80211_regdom[0], - ieee80211_regdom[1]); - alpha2[0] = ieee80211_regdom[0]; - alpha2[1] = ieee80211_regdom[1]; - } else - REG_DBG_PRINT("cfg80211: Restoring regulatory settings\n"); -} - -/* - * Restoring regulatory settings involves ingoring any - * possibly stale country IE information and user regulatory - * settings if so desired, this includes any beacon hints - * learned as we could have traveled outside to another country - * after disconnection. To restore regulatory settings we do - * exactly what we did at bootup: - * - * - send a core regulatory hint - * - send a user regulatory hint if applicable - * - * Device drivers that send a regulatory hint for a specific country - * keep their own regulatory domain on wiphy->regd so that does does - * not need to be remembered. - */ -static void restore_regulatory_settings(bool reset_user) -{ - char alpha2[2]; - struct reg_beacon *reg_beacon, *btmp; - - mutex_lock(&cfg80211_mutex); - mutex_lock(®_mutex); - - reset_regdomains(); - restore_alpha2(alpha2, reset_user); - - /* Clear beacon hints */ - spin_lock_bh(®_pending_beacons_lock); - if (!list_empty(®_pending_beacons)) { - list_for_each_entry_safe(reg_beacon, btmp, - ®_pending_beacons, list) { - list_del(®_beacon->list); - kfree(reg_beacon); - } - } - spin_unlock_bh(®_pending_beacons_lock); - - if (!list_empty(®_beacon_list)) { - list_for_each_entry_safe(reg_beacon, btmp, - ®_beacon_list, list) { - list_del(®_beacon->list); - kfree(reg_beacon); - } - } - - /* First restore to the basic regulatory settings */ - cfg80211_regdomain = cfg80211_world_regdom; - - mutex_unlock(®_mutex); - mutex_unlock(&cfg80211_mutex); - - regulatory_hint_core(cfg80211_regdomain->alpha2); - - /* - * This restores the ieee80211_regdom module parameter - * preference or the last user requested regulatory - * settings, user regulatory settings takes precedence. - */ - if (is_an_alpha2(alpha2)) - regulatory_hint_user(user_alpha2); -} - - -void regulatory_hint_disconnect(void) -{ - REG_DBG_PRINT("cfg80211: All devices are disconnected, going to " - "restore regulatory settings\n"); - restore_regulatory_settings(false); -} - static bool freq_is_chan_12_13_14(u16 freq) { if (freq == ieee80211_channel_to_frequency(12) || @@ -2280,12 +1875,13 @@ int regulatory_hint_found_beacon(struct wiphy *wiphy, if (!reg_beacon) return -ENOMEM; - REG_DBG_PRINT("cfg80211: Found new beacon on " - "frequency: %d MHz (Ch %d) on %s\n", - beacon_chan->center_freq, - ieee80211_frequency_to_channel(beacon_chan->center_freq), - wiphy_name(wiphy)); - +#ifdef CONFIG_CFG80211_REG_DEBUG + printk(KERN_DEBUG "cfg80211: Found new beacon on " + "frequency: %d MHz (Ch %d) on %s\n", + beacon_chan->center_freq, + ieee80211_frequency_to_channel(beacon_chan->center_freq), + wiphy_name(wiphy)); +#endif memcpy(®_beacon->chan, beacon_chan, sizeof(struct ieee80211_channel)); @@ -2443,7 +2039,8 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) * If someone else asked us to change the rd lets only bother * checking if the alpha2 changes if CRDA was already called */ - if (!regdom_changes(rd->alpha2)) + if (!is_old_static_regdom(cfg80211_regdomain) && + !regdom_changes(rd->alpha2)) return -EINVAL; } @@ -2642,11 +2239,15 @@ int regulatory_init(void) spin_lock_init(®_requests_lock); spin_lock_init(®_pending_beacons_lock); - cfg80211_regdomain = cfg80211_world_regdom; +#ifdef CONFIG_WIRELESS_OLD_REGULATORY + cfg80211_regdomain = static_regdom(ieee80211_regdom); - user_alpha2[0] = '9'; - user_alpha2[1] = '7'; + printk(KERN_INFO "cfg80211: Using static regulatory domain info\n"); + print_regdomain_info(cfg80211_regdomain); +#else + cfg80211_regdomain = cfg80211_world_regdom; +#endif /* We always try to get an update for the static regdomain */ err = regulatory_hint_core(cfg80211_regdomain->alpha2); if (err) { diff --git a/trunk/net/wireless/reg.h b/trunk/net/wireless/reg.h index b26224a9f3bc..3362c7c069b2 100644 --- a/trunk/net/wireless/reg.h +++ b/trunk/net/wireless/reg.h @@ -41,44 +41,15 @@ int regulatory_hint_found_beacon(struct wiphy *wiphy, * regulatory_hint_11d - hints a country IE as a regulatory domain * @wiphy: the wireless device giving the hint (used only for reporting * conflicts) - * @band: the band on which the country IE was received on. This determines - * the band we'll process the country IE channel triplets for. * @country_ie: pointer to the country IE * @country_ie_len: length of the country IE * * We will intersect the rd with the what CRDA tells us should apply * for the alpha2 this country IE belongs to, this prevents APs from * sending us incorrect or outdated information against a country. - * - * The AP is expected to provide Country IE channel triplets for the - * band it is on. It is technically possible for APs to send channel - * country IE triplets even for channels outside of the band they are - * in but for that they would have to use the regulatory extension - * in combination with a triplet but this behaviour is currently - * not observed. For this reason if a triplet is seen with channel - * information for a band the BSS is not present in it will be ignored. */ void regulatory_hint_11d(struct wiphy *wiphy, - enum ieee80211_band band, u8 *country_ie, u8 country_ie_len); -/** - * regulatory_hint_disconnect - informs all devices have been disconneted - * - * Regulotory rules can be enhanced further upon scanning and upon - * connection to an AP. These rules become stale if we disconnect - * and go to another country, whether or not we suspend and resume. - * If we suspend, go to another country and resume we'll automatically - * get disconnected shortly after resuming and things will be reset as well. - * This routine is a helper to restore regulatory settings to how they were - * prior to our first connect attempt. This includes ignoring country IE and - * beacon regulatory hints. The ieee80211_regdom module parameter will always - * be respected but if a user had set the regulatory domain that will take - * precedence. - * - * Must be called from process context. - */ -void regulatory_hint_disconnect(void); - #endif /* __NET_WIRELESS_REG_H */ diff --git a/trunk/net/wireless/regdb.h b/trunk/net/wireless/regdb.h deleted file mode 100644 index 818222c92513..000000000000 --- a/trunk/net/wireless/regdb.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef __REGDB_H__ -#define __REGDB_H__ - -extern const struct ieee80211_regdomain *reg_regdb[]; -extern int reg_regdb_size; - -#endif /* __REGDB_H__ */ diff --git a/trunk/net/wireless/scan.c b/trunk/net/wireless/scan.c index 978cac3414b5..0c2cbbebca95 100644 --- a/trunk/net/wireless/scan.c +++ b/trunk/net/wireless/scan.c @@ -100,10 +100,8 @@ static void bss_release(struct kref *ref) if (bss->pub.free_priv) bss->pub.free_priv(&bss->pub); - if (bss->beacon_ies_allocated) - kfree(bss->pub.beacon_ies); - if (bss->proberesp_ies_allocated) - kfree(bss->pub.proberesp_ies); + if (bss->ies_allocated) + kfree(bss->pub.information_elements); BUG_ON(atomic_read(&bss->hold)); @@ -143,9 +141,9 @@ void cfg80211_bss_expire(struct cfg80211_registered_device *dev) dev->bss_generation++; } -const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len) +static u8 *find_ie(u8 num, u8 *ies, int len) { - while (len > 2 && ies[0] != eid) { + while (len > 2 && ies[0] != num) { len -= ies[1] + 2; ies += ies[1] + 2; } @@ -155,12 +153,11 @@ const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len) return NULL; return ies; } -EXPORT_SYMBOL(cfg80211_find_ie); static int cmp_ies(u8 num, u8 *ies1, size_t len1, u8 *ies2, size_t len2) { - const u8 *ie1 = cfg80211_find_ie(num, ies1, len1); - const u8 *ie2 = cfg80211_find_ie(num, ies2, len2); + const u8 *ie1 = find_ie(num, ies1, len1); + const u8 *ie2 = find_ie(num, ies2, len2); int r; if (!ie1 && !ie2) @@ -186,9 +183,9 @@ static bool is_bss(struct cfg80211_bss *a, if (!ssid) return true; - ssidie = cfg80211_find_ie(WLAN_EID_SSID, - a->information_elements, - a->len_information_elements); + ssidie = find_ie(WLAN_EID_SSID, + a->information_elements, + a->len_information_elements); if (!ssidie) return false; if (ssidie[1] != ssid_len) @@ -205,9 +202,9 @@ static bool is_mesh(struct cfg80211_bss *a, if (!is_zero_ether_addr(a->bssid)) return false; - ie = cfg80211_find_ie(WLAN_EID_MESH_ID, - a->information_elements, - a->len_information_elements); + ie = find_ie(WLAN_EID_MESH_ID, + a->information_elements, + a->len_information_elements); if (!ie) return false; if (ie[1] != meshidlen) @@ -215,9 +212,9 @@ static bool is_mesh(struct cfg80211_bss *a, if (memcmp(ie + 2, meshid, meshidlen)) return false; - ie = cfg80211_find_ie(WLAN_EID_MESH_CONFIG, - a->information_elements, - a->len_information_elements); + ie = find_ie(WLAN_EID_MESH_CONFIG, + a->information_elements, + a->len_information_elements); if (!ie) return false; if (ie[1] != sizeof(struct ieee80211_meshconf_ie)) @@ -378,7 +375,8 @@ rb_find_bss(struct cfg80211_registered_device *dev, static struct cfg80211_internal_bss * cfg80211_bss_update(struct cfg80211_registered_device *dev, - struct cfg80211_internal_bss *res) + struct cfg80211_internal_bss *res, + bool overwrite) { struct cfg80211_internal_bss *found = NULL; const u8 *meshid, *meshcfg; @@ -396,12 +394,11 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, if (is_zero_ether_addr(res->pub.bssid)) { /* must be mesh, verify */ - meshid = cfg80211_find_ie(WLAN_EID_MESH_ID, - res->pub.information_elements, - res->pub.len_information_elements); - meshcfg = cfg80211_find_ie(WLAN_EID_MESH_CONFIG, - res->pub.information_elements, - res->pub.len_information_elements); + meshid = find_ie(WLAN_EID_MESH_ID, res->pub.information_elements, + res->pub.len_information_elements); + meshcfg = find_ie(WLAN_EID_MESH_CONFIG, + res->pub.information_elements, + res->pub.len_information_elements); if (!meshid || !meshcfg || meshcfg[1] != sizeof(struct ieee80211_meshconf_ie)) { /* bogus mesh */ @@ -421,64 +418,28 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, found->pub.capability = res->pub.capability; found->ts = res->ts; - /* Update IEs */ - if (res->pub.proberesp_ies) { + /* overwrite IEs */ + if (overwrite) { size_t used = dev->wiphy.bss_priv_size + sizeof(*res); - size_t ielen = res->pub.len_proberesp_ies; - - if (found->pub.proberesp_ies && - !found->proberesp_ies_allocated && - ksize(found) >= used + ielen) { - memcpy(found->pub.proberesp_ies, - res->pub.proberesp_ies, ielen); - found->pub.len_proberesp_ies = ielen; - } else { - u8 *ies = found->pub.proberesp_ies; - - if (found->proberesp_ies_allocated) - ies = krealloc(ies, ielen, GFP_ATOMIC); - else - ies = kmalloc(ielen, GFP_ATOMIC); - - if (ies) { - memcpy(ies, res->pub.proberesp_ies, - ielen); - found->proberesp_ies_allocated = true; - found->pub.proberesp_ies = ies; - found->pub.len_proberesp_ies = ielen; - } - } + size_t ielen = res->pub.len_information_elements; - /* Override possible earlier Beacon frame IEs */ - found->pub.information_elements = - found->pub.proberesp_ies; - found->pub.len_information_elements = - found->pub.len_proberesp_ies; - } - if (res->pub.beacon_ies) { - size_t used = dev->wiphy.bss_priv_size + sizeof(*res); - size_t ielen = res->pub.len_beacon_ies; - - if (found->pub.beacon_ies && - !found->beacon_ies_allocated && - ksize(found) >= used + ielen) { - memcpy(found->pub.beacon_ies, - res->pub.beacon_ies, ielen); - found->pub.len_beacon_ies = ielen; + if (!found->ies_allocated && ksize(found) >= used + ielen) { + memcpy(found->pub.information_elements, + res->pub.information_elements, ielen); + found->pub.len_information_elements = ielen; } else { - u8 *ies = found->pub.beacon_ies; + u8 *ies = found->pub.information_elements; - if (found->beacon_ies_allocated) + if (found->ies_allocated) ies = krealloc(ies, ielen, GFP_ATOMIC); else ies = kmalloc(ielen, GFP_ATOMIC); if (ies) { - memcpy(ies, res->pub.beacon_ies, - ielen); - found->beacon_ies_allocated = true; - found->pub.beacon_ies = ies; - found->pub.len_beacon_ies = ielen; + memcpy(ies, res->pub.information_elements, ielen); + found->ies_allocated = true; + found->pub.information_elements = ies; + found->pub.len_information_elements = ielen; } } } @@ -528,26 +489,14 @@ cfg80211_inform_bss(struct wiphy *wiphy, res->pub.tsf = timestamp; res->pub.beacon_interval = beacon_interval; res->pub.capability = capability; - /* - * Since we do not know here whether the IEs are from a Beacon or Probe - * Response frame, we need to pick one of the options and only use it - * with the driver that does not provide the full Beacon/Probe Response - * frame. Use Beacon frame pointer to avoid indicating that this should - * override the information_elements pointer should we have received an - * earlier indication of Probe Response data. - * - * The initial buffer for the IEs is allocated with the BSS entry and - * is located after the private area. - */ - res->pub.beacon_ies = (u8 *)res + sizeof(*res) + privsz; - memcpy(res->pub.beacon_ies, ie, ielen); - res->pub.len_beacon_ies = ielen; - res->pub.information_elements = res->pub.beacon_ies; - res->pub.len_information_elements = res->pub.len_beacon_ies; + /* point to after the private area */ + res->pub.information_elements = (u8 *)res + sizeof(*res) + privsz; + memcpy(res->pub.information_elements, ie, ielen); + res->pub.len_information_elements = ielen; kref_init(&res->ref); - res = cfg80211_bss_update(wiphy_to_dev(wiphy), res); + res = cfg80211_bss_update(wiphy_to_dev(wiphy), res, 0); if (!res) return NULL; @@ -568,6 +517,7 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, struct cfg80211_internal_bss *res; size_t ielen = len - offsetof(struct ieee80211_mgmt, u.probe_resp.variable); + bool overwrite; size_t privsz = wiphy->bss_priv_size; if (WARN_ON(wiphy->signal_type == NL80211_BSS_SIGNAL_UNSPEC && @@ -588,28 +538,16 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, res->pub.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp); res->pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int); res->pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info); - /* - * The initial buffer for the IEs is allocated with the BSS entry and - * is located after the private area. - */ - if (ieee80211_is_probe_resp(mgmt->frame_control)) { - res->pub.proberesp_ies = (u8 *) res + sizeof(*res) + privsz; - memcpy(res->pub.proberesp_ies, mgmt->u.probe_resp.variable, - ielen); - res->pub.len_proberesp_ies = ielen; - res->pub.information_elements = res->pub.proberesp_ies; - res->pub.len_information_elements = res->pub.len_proberesp_ies; - } else { - res->pub.beacon_ies = (u8 *) res + sizeof(*res) + privsz; - memcpy(res->pub.beacon_ies, mgmt->u.beacon.variable, ielen); - res->pub.len_beacon_ies = ielen; - res->pub.information_elements = res->pub.beacon_ies; - res->pub.len_information_elements = res->pub.len_beacon_ies; - } + /* point to after the private area */ + res->pub.information_elements = (u8 *)res + sizeof(*res) + privsz; + memcpy(res->pub.information_elements, mgmt->u.probe_resp.variable, ielen); + res->pub.len_information_elements = ielen; kref_init(&res->ref); - res = cfg80211_bss_update(wiphy_to_dev(wiphy), res); + overwrite = ieee80211_is_probe_resp(mgmt->frame_control); + + res = cfg80211_bss_update(wiphy_to_dev(wiphy), res, overwrite); if (!res) return NULL; diff --git a/trunk/net/wireless/sme.c b/trunk/net/wireless/sme.c index 17fde0da1b08..dc0fc4989d54 100644 --- a/trunk/net/wireless/sme.c +++ b/trunk/net/wireless/sme.c @@ -34,44 +34,6 @@ struct cfg80211_conn { bool auto_auth, prev_bssid_valid; }; -bool cfg80211_is_all_idle(void) -{ - struct cfg80211_registered_device *rdev; - struct wireless_dev *wdev; - bool is_all_idle = true; - - mutex_lock(&cfg80211_mutex); - - /* - * All devices must be idle as otherwise if you are actively - * scanning some new beacon hints could be learned and would - * count as new regulatory hints. - */ - list_for_each_entry(rdev, &cfg80211_rdev_list, list) { - cfg80211_lock_rdev(rdev); - list_for_each_entry(wdev, &rdev->netdev_list, list) { - wdev_lock(wdev); - if (wdev->sme_state != CFG80211_SME_IDLE) - is_all_idle = false; - wdev_unlock(wdev); - } - cfg80211_unlock_rdev(rdev); - } - - mutex_unlock(&cfg80211_mutex); - - return is_all_idle; -} - -static void disconnect_work(struct work_struct *work) -{ - if (!cfg80211_is_all_idle()) - return; - - regulatory_hint_disconnect(); -} - -static DECLARE_WORK(cfg80211_disconnect_work, disconnect_work); static int cfg80211_conn_scan(struct wireless_dev *wdev) { @@ -492,7 +454,6 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, * - and country_ie[1] which is the IE length */ regulatory_hint_11d(wdev->wiphy, - bss->channel->band, country_ie + 2, country_ie[1]); } @@ -696,8 +657,6 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); wdev->wext.connect.ssid_len = 0; #endif - - schedule_work(&cfg80211_disconnect_work); } void cfg80211_disconnected(struct net_device *dev, u16 reason, diff --git a/trunk/net/wireless/sysfs.c b/trunk/net/wireless/sysfs.c index 9f2cef3e0ca0..efe3c5c92b2d 100644 --- a/trunk/net/wireless/sysfs.c +++ b/trunk/net/wireless/sysfs.c @@ -33,30 +33,10 @@ static ssize_t name ## _show(struct device *dev, \ SHOW_FMT(index, "%d", wiphy_idx); SHOW_FMT(macaddress, "%pM", wiphy.perm_addr); -SHOW_FMT(address_mask, "%pM", wiphy.addr_mask); - -static ssize_t addresses_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct wiphy *wiphy = &dev_to_rdev(dev)->wiphy; - char *start = buf; - int i; - - if (!wiphy->addresses) - return sprintf(buf, "%pM\n", wiphy->perm_addr); - - for (i = 0; i < wiphy->n_addresses; i++) - buf += sprintf(buf, "%pM\n", &wiphy->addresses[i].addr); - - return buf - start; -} static struct device_attribute ieee80211_dev_attrs[] = { __ATTR_RO(index), __ATTR_RO(macaddress), - __ATTR_RO(address_mask), - __ATTR_RO(addresses), {} }; diff --git a/trunk/net/wireless/util.c b/trunk/net/wireless/util.c index be2ab8c59e3a..59361fdcb5d0 100644 --- a/trunk/net/wireless/util.c +++ b/trunk/net/wireless/util.c @@ -227,11 +227,8 @@ unsigned int ieee80211_hdrlen(__le16 fc) if (ieee80211_is_data(fc)) { if (ieee80211_has_a4(fc)) hdrlen = 30; - if (ieee80211_is_data_qos(fc)) { + if (ieee80211_is_data_qos(fc)) hdrlen += IEEE80211_QOS_CTL_LEN; - if (ieee80211_has_order(fc)) - hdrlen += IEEE80211_HT_CTL_LEN; - } goto out; } @@ -288,7 +285,7 @@ static int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) } } -int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, +int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr, enum nl80211_iftype iftype) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; @@ -386,7 +383,7 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, } EXPORT_SYMBOL(ieee80211_data_to_8023); -int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr, +int ieee80211_data_from_8023(struct sk_buff *skb, u8 *addr, enum nl80211_iftype iftype, u8 *bssid, bool qos) { struct ieee80211_hdr hdr; @@ -500,101 +497,6 @@ int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr, } EXPORT_SYMBOL(ieee80211_data_from_8023); - -void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, - const u8 *addr, enum nl80211_iftype iftype, - const unsigned int extra_headroom) -{ - struct sk_buff *frame = NULL; - u16 ethertype; - u8 *payload; - const struct ethhdr *eth; - int remaining, err; - u8 dst[ETH_ALEN], src[ETH_ALEN]; - - err = ieee80211_data_to_8023(skb, addr, iftype); - if (err) - goto out; - - /* skip the wrapping header */ - eth = (struct ethhdr *) skb_pull(skb, sizeof(struct ethhdr)); - if (!eth) - goto out; - - while (skb != frame) { - u8 padding; - __be16 len = eth->h_proto; - unsigned int subframe_len = sizeof(struct ethhdr) + ntohs(len); - - remaining = skb->len; - memcpy(dst, eth->h_dest, ETH_ALEN); - memcpy(src, eth->h_source, ETH_ALEN); - - padding = (4 - subframe_len) & 0x3; - /* the last MSDU has no padding */ - if (subframe_len > remaining) - goto purge; - - skb_pull(skb, sizeof(struct ethhdr)); - /* reuse skb for the last subframe */ - if (remaining <= subframe_len + padding) - frame = skb; - else { - unsigned int hlen = ALIGN(extra_headroom, 4); - /* - * Allocate and reserve two bytes more for payload - * alignment since sizeof(struct ethhdr) is 14. - */ - frame = dev_alloc_skb(hlen + subframe_len + 2); - if (!frame) - goto purge; - - skb_reserve(frame, hlen + sizeof(struct ethhdr) + 2); - memcpy(skb_put(frame, ntohs(len)), skb->data, - ntohs(len)); - - eth = (struct ethhdr *)skb_pull(skb, ntohs(len) + - padding); - if (!eth) { - dev_kfree_skb(frame); - goto purge; - } - } - - skb_reset_network_header(frame); - frame->dev = skb->dev; - frame->priority = skb->priority; - - payload = frame->data; - ethertype = (payload[6] << 8) | payload[7]; - - if (likely((compare_ether_addr(payload, rfc1042_header) == 0 && - ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || - compare_ether_addr(payload, - bridge_tunnel_header) == 0)) { - /* remove RFC1042 or Bridge-Tunnel - * encapsulation and replace EtherType */ - skb_pull(frame, 6); - memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN); - memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN); - } else { - memcpy(skb_push(frame, sizeof(__be16)), &len, - sizeof(__be16)); - memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN); - memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN); - } - __skb_queue_tail(list, frame); - } - - return; - - purge: - __skb_queue_purge(list); - out: - dev_kfree_skb(skb); -} -EXPORT_SYMBOL(ieee80211_amsdu_to_8023s); - /* Given a data frame determine the 802.1p/1d tag to use. */ unsigned int cfg80211_classify8021d(struct sk_buff *skb) { @@ -818,36 +720,3 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, return err; } - -u16 cfg80211_calculate_bitrate(struct rate_info *rate) -{ - int modulation, streams, bitrate; - - if (!(rate->flags & RATE_INFO_FLAGS_MCS)) - return rate->legacy; - - /* the formula below does only work for MCS values smaller than 32 */ - if (rate->mcs >= 32) - return 0; - - modulation = rate->mcs & 7; - streams = (rate->mcs >> 3) + 1; - - bitrate = (rate->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) ? - 13500000 : 6500000; - - if (modulation < 4) - bitrate *= (modulation + 1); - else if (modulation == 4) - bitrate *= (modulation + 2); - else - bitrate *= (modulation + 3); - - bitrate *= streams; - - if (rate->flags & RATE_INFO_FLAGS_SHORT_GI) - bitrate = (bitrate / 9) * 10; - - /* do NOT round down here */ - return (bitrate + 50000) / 100000; -} diff --git a/trunk/net/wireless/wext-compat.c b/trunk/net/wireless/wext-compat.c index 9ab51838849e..54face3d4424 100644 --- a/trunk/net/wireless/wext-compat.c +++ b/trunk/net/wireless/wext-compat.c @@ -1099,8 +1099,8 @@ int cfg80211_wext_siwpower(struct net_device *dev, { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); - bool ps = wdev->ps; - int timeout = wdev->ps_timeout; + bool ps = wdev->wext.ps; + int timeout = wdev->wext.ps_timeout; int err; if (wdev->iftype != NL80211_IFTYPE_STATION) @@ -1133,8 +1133,8 @@ int cfg80211_wext_siwpower(struct net_device *dev, if (err) return err; - wdev->ps = ps; - wdev->ps_timeout = timeout; + wdev->wext.ps = ps; + wdev->wext.ps_timeout = timeout; return 0; @@ -1147,7 +1147,7 @@ int cfg80211_wext_giwpower(struct net_device *dev, { struct wireless_dev *wdev = dev->ieee80211_ptr; - wrq->disabled = !wdev->ps; + wrq->disabled = !wdev->wext.ps; return 0; } @@ -1204,47 +1204,21 @@ int cfg80211_wext_siwrate(struct net_device *dev, struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); struct cfg80211_bitrate_mask mask; - u32 fixed, maxrate; - struct ieee80211_supported_band *sband; - int band, ridx; - bool match = false; if (!rdev->ops->set_bitrate_mask) return -EOPNOTSUPP; - memset(&mask, 0, sizeof(mask)); - fixed = 0; - maxrate = (u32)-1; + mask.fixed = 0; + mask.maxrate = 0; if (rate->value < 0) { /* nothing */ } else if (rate->fixed) { - fixed = rate->value / 100000; + mask.fixed = rate->value / 1000; /* kbps */ } else { - maxrate = rate->value / 100000; + mask.maxrate = rate->value / 1000; /* kbps */ } - for (band = 0; band < IEEE80211_NUM_BANDS; band++) { - sband = wdev->wiphy->bands[band]; - if (sband == NULL) - continue; - for (ridx = 0; ridx < sband->n_bitrates; ridx++) { - struct ieee80211_rate *srate = &sband->bitrates[ridx]; - if (fixed == srate->bitrate) { - mask.control[band].legacy = 1 << ridx; - match = true; - break; - } - if (srate->bitrate <= maxrate) { - mask.control[band].legacy |= 1 << ridx; - match = true; - } - } - } - - if (!match) - return -EINVAL; - return rdev->ops->set_bitrate_mask(wdev->wiphy, dev, NULL, &mask); } EXPORT_SYMBOL_GPL(cfg80211_wext_siwrate); @@ -1283,7 +1257,10 @@ int cfg80211_wext_giwrate(struct net_device *dev, if (!(sinfo.filled & STATION_INFO_TX_BITRATE)) return -EOPNOTSUPP; - rate->value = 100000 * cfg80211_calculate_bitrate(&sinfo.txrate); + rate->value = 0; + + if (!(sinfo.txrate.flags & RATE_INFO_FLAGS_MCS)) + rate->value = 100000 * sinfo.txrate.legacy; return 0; }