From c4f7863eae6f580a0373cbd8dc2731d082570e69 Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Fri, 6 Apr 2012 13:35:48 -0700 Subject: [PATCH 01/31] ath6kl: handle concurrent AP-STA channel switches If an ath6kl AP vif is beaconing on one channel, and a STA vif associates on a different channel, a WMI_DISCONNECT event will be sent to the AP vif. Make the AP vif follow the STA interface, and notify userspace. kvalo: fix a sparse warning with vif->next_chan Signed-off-by: Thomas Pedersen Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 15 ++++++ drivers/net/wireless/ath/ath6kl/cfg80211.h | 2 + drivers/net/wireless/ath/ath6kl/core.h | 2 + drivers/net/wireless/ath/ath6kl/main.c | 55 +++++++++++++++++++++- drivers/net/wireless/ath/ath6kl/wmi.h | 12 +++++ 5 files changed, 85 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 28a65d3a03d0..6ea5ae54c160 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -1018,6 +1018,20 @@ void ath6kl_cfg80211_scan_complete_event(struct ath6kl_vif *vif, bool aborted) vif->scan_req = NULL; } +void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq, + enum wmi_phy_mode mode) +{ + enum nl80211_channel_type type; + + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, + "channel switch notify nw_type %d freq %d mode %d\n", + vif->nw_type, freq, mode); + + type = (mode == WMI_11G_HT20) ? NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT; + + cfg80211_ch_switch_notify(vif->ndev, freq, type); +} + static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_index, bool pairwise, const u8 *mac_addr, @@ -2766,6 +2780,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, return res; } + memcpy(&vif->profile, &p, sizeof(p)); res = ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, &p); if (res < 0) return res; diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.h b/drivers/net/wireless/ath/ath6kl/cfg80211.h index c5def436417f..5ea8cbb79f43 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.h +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.h @@ -28,6 +28,8 @@ enum ath6kl_cfg_suspend_mode { struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name, enum nl80211_iftype type, u8 fw_vif_idx, u8 nw_type); +void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq, + enum wmi_phy_mode mode); void ath6kl_cfg80211_scan_complete_event(struct ath6kl_vif *vif, bool aborted); void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel, diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index 9d67964a51dd..8ca393fc9f18 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -552,6 +552,7 @@ struct ath6kl_vif { u8 assoc_bss_dtim_period; struct net_device_stats net_stats; struct target_stats target_stats; + struct wmi_connect_cmd profile; struct list_head mc_filter; }; @@ -640,6 +641,7 @@ struct ath6kl { u8 sta_list_index; struct ath6kl_req_key ap_mode_bkey; struct sk_buff_head mcastpsq; + u32 want_ch_switch; /* * FIXME: protects access to mcastpsq but is actually useless as diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index 4d818f96c415..4602be7ce23b 100644 --- a/drivers/net/wireless/ath/ath6kl/main.c +++ b/drivers/net/wireless/ath/ath6kl/main.c @@ -436,6 +436,13 @@ void ath6kl_connect_ap_mode_bss(struct ath6kl_vif *vif, u16 channel) break; } + if (ar->want_ch_switch & (1 << vif->fw_vif_idx)) { + ar->want_ch_switch &= ~(1 << vif->fw_vif_idx); + /* we actually don't know the phymode, default to HT20 */ + ath6kl_cfg80211_ch_switch_notify(vif, channel, + WMI_11G_HT20); + } + ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, NONE_BSS_FILTER, 0); set_bit(CONNECTED, &vif->flags); netif_carrier_on(vif->ndev); @@ -584,6 +591,45 @@ void ath6kl_scan_complete_evt(struct ath6kl_vif *vif, int status) ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "scan complete: %d\n", status); } +static int ath6kl_commit_ch_switch(struct ath6kl_vif *vif, u16 channel) +{ + + struct ath6kl *ar = vif->ar; + + vif->next_chan = channel; + vif->profile.ch = cpu_to_le16(channel); + + switch (vif->nw_type) { + case AP_NETWORK: + return ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, + &vif->profile); + default: + ath6kl_err("won't switch channels nw_type=%d\n", vif->nw_type); + return -ENOTSUPP; + } +} + +static void ath6kl_check_ch_switch(struct ath6kl *ar, u16 channel) +{ + + struct ath6kl_vif *vif; + int res = 0; + + if (!ar->want_ch_switch) + return; + + spin_lock_bh(&ar->list_lock); + list_for_each_entry(vif, &ar->vif_list, list) { + if (ar->want_ch_switch & (1 << vif->fw_vif_idx)) + res = ath6kl_commit_ch_switch(vif, channel); + + if (res) + ath6kl_err("channel switch failed nw_type %d res %d\n", + vif->nw_type, res); + } + spin_unlock_bh(&ar->list_lock); +} + void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, u8 *bssid, u16 listen_int, u16 beacon_int, enum network_type net_type, u8 beacon_ie_len, @@ -601,9 +647,11 @@ void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, u8 *bssid, memcpy(vif->bssid, bssid, sizeof(vif->bssid)); vif->bss_ch = channel; - if ((vif->nw_type == INFRA_NETWORK)) + if ((vif->nw_type == INFRA_NETWORK)) { ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx, vif->listen_intvl_t, 0); + ath6kl_check_ch_switch(ar, channel); + } netif_wake_queue(vif->ndev); @@ -926,6 +974,11 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid, struct ath6kl *ar = vif->ar; if (vif->nw_type == AP_NETWORK) { + /* disconnect due to other STA vif switching channels */ + if (reason == BSS_DISCONNECTED && + prot_reason_status == WMI_AP_REASON_STA_ROAM) + ar->want_ch_switch |= 1 << vif->fw_vif_idx; + if (!ath6kl_remove_sta(ar, bssid, prot_reason_status)) return; diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index d3d2ab5c1689..190b2c4e382f 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -1151,6 +1151,7 @@ enum wmi_phy_mode { WMI_11AG_MODE = 0x3, WMI_11B_MODE = 0x4, WMI_11GONLY_MODE = 0x5, + WMI_11G_HT20 = 0x6, }; #define WMI_MAX_CHANNELS 32 @@ -1468,6 +1469,17 @@ enum wmi_disconnect_reason { IBSS_MERGE = 0xe, }; +/* AP mode disconnect proto_reasons */ +enum ap_disconnect_reason { + WMI_AP_REASON_STA_LEFT = 101, + WMI_AP_REASON_FROM_HOST = 102, + WMI_AP_REASON_COMM_TIMEOUT = 103, + WMI_AP_REASON_MAX_STA = 104, + WMI_AP_REASON_ACL = 105, + WMI_AP_REASON_STA_ROAM = 106, + WMI_AP_REASON_DFS_CHANNEL = 107, +}; + #define ATH6KL_COUNTRY_RD_SHIFT 16 struct ath6kl_wmi_regdomain { From 798985c688722479191f6d6f4e5ab1a473904f0a Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 10 Apr 2012 13:35:47 +0530 Subject: [PATCH 02/31] ath6kl: Fix possible unaligned memory access in ath6kl_get_rsn_capab() alignment is not taken care in accessing pairwise cipher and AKM suite count which are parsed from rsn ie. Fix this alignment issue. Reported-by: Joe Perches Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 6ea5ae54c160..6b6bf938feef 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -2591,14 +2591,14 @@ static int ath6kl_get_rsn_capab(struct cfg80211_beacon_data *beacon, /* skip pairwise cipher suite */ if (rsn_ie_len < 2) return -EINVAL; - cnt = *((u16 *) rsn_ie); + cnt = get_unaligned_le16(rsn_ie); rsn_ie += (2 + cnt * 4); rsn_ie_len -= (2 + cnt * 4); /* skip akm suite */ if (rsn_ie_len < 2) return -EINVAL; - cnt = *((u16 *) rsn_ie); + cnt = get_unaligned_le16(rsn_ie); rsn_ie += (2 + cnt * 4); rsn_ie_len -= (2 + cnt * 4); From 9e8b16dbd0f642e14adccf52af46853418cab331 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 10 Apr 2012 14:27:47 +0530 Subject: [PATCH 03/31] ath6kl: Configure 0 as rsn cap when it is not there in rsn ie Currently rsn capability is not set when it is not available in rsn IE. Set it to 0 in firmware when it is not there in the ie to make sure host and target are consistent. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 6b6bf938feef..12f2f616d380 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -2582,28 +2582,34 @@ static int ath6kl_get_rsn_capab(struct cfg80211_beacon_data *beacon, /* skip element id and length */ rsn_ie += 2; - /* skip version, group cipher */ - if (rsn_ie_len < 6) + /* skip version */ + if (rsn_ie_len < 2) return -EINVAL; - rsn_ie += 6; - rsn_ie_len -= 6; + rsn_ie += 2; + rsn_ie_len -= 2; + + /* skip group cipher suite */ + if (rsn_ie_len < 4) + return 0; + rsn_ie += 4; + rsn_ie_len -= 4; /* skip pairwise cipher suite */ if (rsn_ie_len < 2) - return -EINVAL; + return 0; cnt = get_unaligned_le16(rsn_ie); rsn_ie += (2 + cnt * 4); rsn_ie_len -= (2 + cnt * 4); /* skip akm suite */ if (rsn_ie_len < 2) - return -EINVAL; + return 0; cnt = get_unaligned_le16(rsn_ie); rsn_ie += (2 + cnt * 4); rsn_ie_len -= (2 + cnt * 4); if (rsn_ie_len < 2) - return -EINVAL; + return 0; memcpy(rsn_capab, rsn_ie, 2); From 6146ca69031e3ad697d801e7e242b554d7969de1 Mon Sep 17 00:00:00 2001 From: Ray Chen Date: Wed, 11 Apr 2012 10:03:13 +0800 Subject: [PATCH 04/31] ath6kl: Add AR6004 1.2 support for USB and SDIO Add the necessary change for AR6004 1.2 chip support Signed-off-by: Ray Chen Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/core.h | 8 ++++++++ drivers/net/wireless/ath/ath6kl/init.c | 18 ++++++++++++++++++ drivers/net/wireless/ath/ath6kl/sdio.c | 3 +++ drivers/net/wireless/ath/ath6kl/usb.c | 3 +++ 4 files changed, 32 insertions(+) diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index 8ca393fc9f18..b2ebd56ab9a9 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -159,6 +159,14 @@ struct ath6kl_fw_ie { #define AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE \ "ath6k/AR6004/hw1.1/bdata.DB132.bin" +/* AR6004 1.2 definitions */ +#define AR6004_HW_1_2_VERSION 0x300007e8 +#define AR6004_HW_1_2_FW_DIR "ath6k/AR6004/hw1.2" +#define AR6004_HW_1_2_FIRMWARE_FILE "fw.ram.bin" +#define AR6004_HW_1_2_BOARD_DATA_FILE "ath6k/AR6004/hw1.2/bdata.bin" +#define AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE \ + "ath6k/AR6004/hw1.2/bdata.bin" + /* Per STA data, used in AP mode */ #define STA_PS_AWAKE BIT(0) #define STA_PS_SLEEP BIT(1) diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index 29ef50ea07d5..0c4e3e335773 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -119,6 +119,24 @@ static const struct ath6kl_hw hw_list[] = { .fw_board = AR6004_HW_1_1_BOARD_DATA_FILE, .fw_default_board = AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE, }, + { + .id = AR6004_HW_1_2_VERSION, + .name = "ar6004 hw 1.2", + .dataset_patch_addr = 0x436ecc, + .app_load_addr = 0x1234, + .board_ext_data_addr = 0x437000, + .reserved_ram_size = 9216, + .board_addr = 0x435c00, + .refclk_hz = 40000000, + .uarttx_pin = 11, + + .fw = { + .dir = AR6004_HW_1_2_FW_DIR, + .fw = AR6004_HW_1_2_FIRMWARE_FILE, + }, + .fw_board = AR6004_HW_1_2_BOARD_DATA_FILE, + .fw_default_board = AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE, + }, }; /* diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c index 44ea7a742101..b41220d1e51e 100644 --- a/drivers/net/wireless/ath/ath6kl/sdio.c +++ b/drivers/net/wireless/ath/ath6kl/sdio.c @@ -1457,3 +1457,6 @@ MODULE_FIRMWARE(AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE); MODULE_FIRMWARE(AR6004_HW_1_1_FW_DIR "/" AR6004_HW_1_1_FIRMWARE_FILE); MODULE_FIRMWARE(AR6004_HW_1_1_BOARD_DATA_FILE); MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE); +MODULE_FIRMWARE(AR6004_HW_1_2_FW_DIR "/" AR6004_HW_1_2_FIRMWARE_FILE); +MODULE_FIRMWARE(AR6004_HW_1_2_BOARD_DATA_FILE); +MODULE_FIRMWARE(AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE); diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c index ec7f1f5fd1ca..73aacdd047ca 100644 --- a/drivers/net/wireless/ath/ath6kl/usb.c +++ b/drivers/net/wireless/ath/ath6kl/usb.c @@ -1207,3 +1207,6 @@ MODULE_FIRMWARE(AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE); MODULE_FIRMWARE(AR6004_HW_1_1_FIRMWARE_FILE); MODULE_FIRMWARE(AR6004_HW_1_1_BOARD_DATA_FILE); MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE); +MODULE_FIRMWARE(AR6004_HW_1_2_FIRMWARE_FILE); +MODULE_FIRMWARE(AR6004_HW_1_2_BOARD_DATA_FILE); +MODULE_FIRMWARE(AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE); From ae9a3405fd28ce05dc3d0b51d541fd5ec742b3b4 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Wed, 11 Apr 2012 22:41:36 +0200 Subject: [PATCH 05/31] ath6kl: fix memory leak in ath6kl_fwlog_block_read() If, in drivers/net/wireless/ath/ath6kl/debug.c::ath6kl_fwlog_block_read(), the call to wait_for_completion_interruptible() returns -ERESTARTSYS then we'll return without freeing the (as yet unused) memory we allocated for 'buf' - thus leaking it. Signed-off-by: Jesper Juhl Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/debug.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c index 2bcd45095eb9..496382f472de 100644 --- a/drivers/net/wireless/ath/ath6kl/debug.c +++ b/drivers/net/wireless/ath/ath6kl/debug.c @@ -407,8 +407,10 @@ static ssize_t ath6kl_fwlog_block_read(struct file *file, ret = wait_for_completion_interruptible( &ar->debug.fwlog_completion); - if (ret == -ERESTARTSYS) + if (ret == -ERESTARTSYS) { + vfree(buf); return ret; + } spin_lock(&ar->debug.fwlog_queue.lock); } From cdeb860252e66bdaf1ab70420274df879f243d3d Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Thu, 12 Apr 2012 11:02:18 +0300 Subject: [PATCH 06/31] ath6kl: merge split format strings into one Found by checkpatch: WARNING: quoted string split across lines Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 29 ++++----- drivers/net/wireless/ath/ath6kl/init.c | 11 ++-- drivers/net/wireless/ath/ath6kl/main.c | 8 +-- drivers/net/wireless/ath/ath6kl/sdio.c | 9 ++- drivers/net/wireless/ath/ath6kl/wmi.c | 69 ++++++++++++---------- 5 files changed, 64 insertions(+), 62 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 12f2f616d380..fffae8768bc7 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -693,8 +693,8 @@ ath6kl_add_bss_if_needed(struct ath6kl_vif *vif, ie, 2 + vif->ssid_len + beacon_ie_len, 0, GFP_KERNEL); if (bss) - ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "added bss %pM to " - "cfg80211\n", bssid); + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, + "added bss %pM to cfg80211\n", bssid); kfree(ie); } else ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss\n"); @@ -927,8 +927,7 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, WMI_FRAME_PROBE_REQ, request->ie, request->ie_len); if (ret) { - ath6kl_err("failed to set Probe Request appie for " - "scan"); + ath6kl_err("failed to set Probe Request appie for scan"); return ret; } @@ -945,8 +944,7 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, channels = kzalloc(n_channels * sizeof(u16), GFP_KERNEL); if (channels == NULL) { - ath6kl_warn("failed to set scan channels, " - "scan all channels"); + ath6kl_warn("failed to set scan channels, scan all channels"); n_channels = 0; } @@ -1125,9 +1123,8 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, ar->ap_mode_bkey.key_len = key->key_len; memcpy(ar->ap_mode_bkey.key, key->key, key->key_len); if (!test_bit(CONNECTED, &vif->flags)) { - ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay initial group " - "key configuration until AP mode has been " - "started\n"); + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, + "Delay initial group key configuration until AP mode has been started\n"); /* * The key will be set in ath6kl_connect_ap_mode() once * the connected event is received from the target. @@ -1143,8 +1140,8 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, * the AP mode has properly started * (ath6kl_install_statioc_wep_keys). */ - ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay WEP key configuration " - "until AP mode has been started\n"); + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, + "Delay WEP key configuration until AP mode has been started\n"); vif->wep_key_list[key_index].key_len = key->key_len; memcpy(vif->wep_key_list[key_index].key, key->key, key->key_len); @@ -1976,8 +1973,7 @@ static int ath6kl_wow_sta(struct ath6kl *ar, struct ath6kl_vif *vif) sizeof(discvr_pattern), discvr_offset, discvr_pattern, discvr_mask); if (ret) { - ath6kl_err("failed to add WOW mDNS/SSDP/LLMNR " - "pattern\n"); + ath6kl_err("failed to add WOW mDNS/SSDP/LLMNR pattern\n"); return ret; } } @@ -2161,8 +2157,8 @@ static int ath6kl_wow_resume(struct ath6kl *ar) ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, ATH6KL_HOST_MODE_AWAKE); if (ret) { - ath6kl_warn("Failed to configure host sleep mode for " - "wow resume: %d\n", ret); + ath6kl_warn("Failed to configure host sleep mode for wow resume: %d\n", + ret); ar->state = ATH6KL_STATE_WOW; return ret; } @@ -3292,8 +3288,7 @@ void ath6kl_cfg80211_stop_all(struct ath6kl *ar) ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode; if (ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER) != 0) - ath6kl_warn("ath6kl_deep_sleep_enable: " - "wmi_powermode_cmd failed\n"); + ath6kl_warn("ath6kl_deep_sleep_enable: wmi_powermode_cmd failed\n"); return; } diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index 0c4e3e335773..7eb0515f458a 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -463,9 +463,9 @@ static int ath6kl_target_config_wlan_params(struct ath6kl *ar, int idx) P2P_FLAG_MACADDR_REQ | P2P_FLAG_HMODEL_REQ); if (ret) { - ath6kl_dbg(ATH6KL_DBG_TRC, "failed to request P2P " - "capabilities (%d) - assuming P2P not " - "supported\n", ret); + ath6kl_dbg(ATH6KL_DBG_TRC, + "failed to request P2P capabilities (%d) - assuming P2P not supported\n", + ret); ar->p2p = false; } } @@ -474,8 +474,9 @@ static int ath6kl_target_config_wlan_params(struct ath6kl *ar, int idx) /* Enable Probe Request reporting for P2P */ ret = ath6kl_wmi_probe_report_req_cmd(ar->wmi, idx, true); if (ret) { - ath6kl_dbg(ATH6KL_DBG_TRC, "failed to enable Probe " - "Request reporting (%d)\n", ret); + ath6kl_dbg(ATH6KL_DBG_TRC, + "failed to enable Probe Request reporting (%d)\n", + ret); } } diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index 4602be7ce23b..4f3aab22008a 100644 --- a/drivers/net/wireless/ath/ath6kl/main.c +++ b/drivers/net/wireless/ath/ath6kl/main.c @@ -421,8 +421,8 @@ void ath6kl_connect_ap_mode_bss(struct ath6kl_vif *vif, u16 channel) if (!ik->valid) break; - ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delayed addkey for " - "the initial group key for AP mode\n"); + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, + "Delayed addkey for the initial group key for AP mode\n"); memset(key_rsc, 0, sizeof(key_rsc)); res = ath6kl_wmi_addkey_cmd( ar->wmi, vif->fw_vif_idx, ik->key_index, ik->key_type, @@ -430,8 +430,8 @@ void ath6kl_connect_ap_mode_bss(struct ath6kl_vif *vif, u16 channel) ik->key, KEY_OP_INIT_VAL, NULL, SYNC_BOTH_WMIFLAG); if (res) { - ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delayed " - "addkey failed: %d\n", res); + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, + "Delayed addkey failed: %d\n", res); } break; } diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c index b41220d1e51e..cfcc3216db15 100644 --- a/drivers/net/wireless/ath/ath6kl/sdio.c +++ b/drivers/net/wireless/ath/ath6kl/sdio.c @@ -985,9 +985,8 @@ static int ath6kl_set_addrwin_reg(struct ath6kl *ar, u32 reg_addr, u32 addr) } if (status) { - ath6kl_err("%s: failed to write initial bytes of 0x%x " - "to window reg: 0x%X\n", __func__, - addr, reg_addr); + ath6kl_err("%s: failed to write initial bytes of 0x%x to window reg: 0x%X\n", + __func__, addr, reg_addr); return status; } @@ -1076,8 +1075,8 @@ static int ath6kl_sdio_bmi_credits(struct ath6kl *ar) (u8 *)&ar->bmi.cmd_credits, 4, HIF_RD_SYNC_BYTE_INC); if (ret) { - ath6kl_err("Unable to decrement the command credit " - "count register: %d\n", ret); + ath6kl_err("Unable to decrement the command credit count register: %d\n", + ret); return ret; } diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 7c8a9977faf5..db688a2e1f6c 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -460,8 +460,9 @@ static int ath6kl_wmi_remain_on_chnl_event_rx(struct wmi *wmi, u8 *datap, freq, dur); chan = ieee80211_get_channel(ar->wiphy, freq); if (!chan) { - ath6kl_dbg(ATH6KL_DBG_WMI, "remain_on_chnl: Unknown channel " - "(freq=%u)\n", freq); + ath6kl_dbg(ATH6KL_DBG_WMI, + "remain_on_chnl: Unknown channel (freq=%u)\n", + freq); return -EINVAL; } id = vif->last_roc_id; @@ -488,12 +489,14 @@ static int ath6kl_wmi_cancel_remain_on_chnl_event_rx(struct wmi *wmi, ev = (struct wmi_cancel_remain_on_chnl_event *) datap; freq = le32_to_cpu(ev->freq); dur = le32_to_cpu(ev->duration); - ath6kl_dbg(ATH6KL_DBG_WMI, "cancel_remain_on_chnl: freq=%u dur=%u " - "status=%u\n", freq, dur, ev->status); + ath6kl_dbg(ATH6KL_DBG_WMI, + "cancel_remain_on_chnl: freq=%u dur=%u status=%u\n", + freq, dur, ev->status); chan = ieee80211_get_channel(ar->wiphy, freq); if (!chan) { - ath6kl_dbg(ATH6KL_DBG_WMI, "cancel_remain_on_chnl: Unknown " - "channel (freq=%u)\n", freq); + ath6kl_dbg(ATH6KL_DBG_WMI, + "cancel_remain_on_chnl: Unknown channel (freq=%u)\n", + freq); return -EINVAL; } if (vif->last_cancel_roc_id && @@ -548,12 +551,12 @@ static int ath6kl_wmi_rx_probe_req_event_rx(struct wmi *wmi, u8 *datap, int len, freq = le32_to_cpu(ev->freq); dlen = le16_to_cpu(ev->len); if (datap + len < ev->data + dlen) { - ath6kl_err("invalid wmi_p2p_rx_probe_req_event: " - "len=%d dlen=%u\n", len, dlen); + ath6kl_err("invalid wmi_p2p_rx_probe_req_event: len=%d dlen=%u\n", + len, dlen); return -EINVAL; } - ath6kl_dbg(ATH6KL_DBG_WMI, "rx_probe_req: len=%u freq=%u " - "probe_req_report=%d\n", + ath6kl_dbg(ATH6KL_DBG_WMI, + "rx_probe_req: len=%u freq=%u probe_req_report=%d\n", dlen, freq, vif->probe_req_report); if (vif->probe_req_report || vif->nw_type == AP_NETWORK) @@ -592,8 +595,8 @@ static int ath6kl_wmi_rx_action_event_rx(struct wmi *wmi, u8 *datap, int len, freq = le32_to_cpu(ev->freq); dlen = le16_to_cpu(ev->len); if (datap + len < ev->data + dlen) { - ath6kl_err("invalid wmi_rx_action_event: " - "len=%d dlen=%u\n", len, dlen); + ath6kl_err("invalid wmi_rx_action_event: len=%d dlen=%u\n", + len, dlen); return -EINVAL; } ath6kl_dbg(ATH6KL_DBG_WMI, "rx_action: len=%u freq=%u\n", dlen, freq); @@ -777,16 +780,15 @@ static int ath6kl_wmi_connect_event_rx(struct wmi *wmi, u8 *datap, int len, /* AP mode start/STA connected event */ struct net_device *dev = vif->ndev; if (memcmp(dev->dev_addr, ev->u.ap_bss.bssid, ETH_ALEN) == 0) { - ath6kl_dbg(ATH6KL_DBG_WMI, "%s: freq %d bssid %pM " - "(AP started)\n", + ath6kl_dbg(ATH6KL_DBG_WMI, + "%s: freq %d bssid %pM (AP started)\n", __func__, le16_to_cpu(ev->u.ap_bss.ch), ev->u.ap_bss.bssid); ath6kl_connect_ap_mode_bss( vif, le16_to_cpu(ev->u.ap_bss.ch)); } else { - ath6kl_dbg(ATH6KL_DBG_WMI, "%s: aid %u mac_addr %pM " - "auth=%u keymgmt=%u cipher=%u apsd_info=%u " - "(STA connected)\n", + ath6kl_dbg(ATH6KL_DBG_WMI, + "%s: aid %u mac_addr %pM auth=%u keymgmt=%u cipher=%u apsd_info=%u (STA connected)\n", __func__, ev->u.ap_sta.aid, ev->u.ap_sta.mac_addr, ev->u.ap_sta.auth, @@ -1229,8 +1231,9 @@ static int ath6kl_wmi_neighbor_report_event_rx(struct wmi *wmi, u8 *datap, ev = (struct wmi_neighbor_report_event *) datap; if (sizeof(*ev) + ev->num_neighbors * sizeof(struct wmi_neighbor_info) > len) { - ath6kl_dbg(ATH6KL_DBG_WMI, "truncated neighbor event " - "(num=%d len=%d)\n", ev->num_neighbors, len); + ath6kl_dbg(ATH6KL_DBG_WMI, + "truncated neighbor event (num=%d len=%d)\n", + ev->num_neighbors, len); return -EINVAL; } for (i = 0; i < ev->num_neighbors; i++) { @@ -2129,8 +2132,8 @@ int ath6kl_wmi_addkey_cmd(struct wmi *wmi, u8 if_idx, u8 key_index, struct wmi_add_cipher_key_cmd *cmd; int ret; - ath6kl_dbg(ATH6KL_DBG_WMI, "addkey cmd: key_index=%u key_type=%d " - "key_usage=%d key_len=%d key_op_ctrl=%d\n", + ath6kl_dbg(ATH6KL_DBG_WMI, + "addkey cmd: key_index=%u key_type=%d key_usage=%d key_len=%d key_op_ctrl=%d\n", key_index, key_type, key_usage, key_len, key_op_ctrl); if ((key_index > WMI_MAX_KEY_INDEX) || (key_len > WMI_MAX_KEY_LEN) || @@ -3047,8 +3050,8 @@ int ath6kl_wmi_ap_profile_commit(struct wmi *wmip, u8 if_idx, res = ath6kl_wmi_cmd_send(wmip, if_idx, skb, WMI_AP_CONFIG_COMMIT_CMDID, NO_SYNC_WMIFLAG); - ath6kl_dbg(ATH6KL_DBG_WMI, "%s: nw_type=%u auth_mode=%u ch=%u " - "ctrl_flags=0x%x-> res=%d\n", + ath6kl_dbg(ATH6KL_DBG_WMI, + "%s: nw_type=%u auth_mode=%u ch=%u ctrl_flags=0x%x-> res=%d\n", __func__, p->nw_type, p->auth_mode, le16_to_cpu(p->ch), le32_to_cpu(p->ctrl_flags), res); return res; @@ -3208,8 +3211,9 @@ int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type, if (!skb) return -ENOMEM; - ath6kl_dbg(ATH6KL_DBG_WMI, "set_appie_cmd: mgmt_frm_type=%u " - "ie_len=%u\n", mgmt_frm_type, ie_len); + ath6kl_dbg(ATH6KL_DBG_WMI, + "set_appie_cmd: mgmt_frm_type=%u ie_len=%u\n", + mgmt_frm_type, ie_len); p = (struct wmi_set_appie_cmd *) skb->data; p->mgmt_frm_type = mgmt_frm_type; p->ie_len = ie_len; @@ -3310,8 +3314,9 @@ static int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id, wmi->last_mgmt_tx_frame = buf; wmi->last_mgmt_tx_frame_len = data_len; - ath6kl_dbg(ATH6KL_DBG_WMI, "send_action_cmd: id=%u freq=%u wait=%u " - "len=%u\n", id, freq, wait, data_len); + ath6kl_dbg(ATH6KL_DBG_WMI, + "send_action_cmd: id=%u freq=%u wait=%u len=%u\n", + id, freq, wait, data_len); p = (struct wmi_send_action_cmd *) skb->data; p->id = cpu_to_le32(id); p->freq = cpu_to_le32(freq); @@ -3348,8 +3353,9 @@ static int __ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id, wmi->last_mgmt_tx_frame = buf; wmi->last_mgmt_tx_frame_len = data_len; - ath6kl_dbg(ATH6KL_DBG_WMI, "send_action_cmd: id=%u freq=%u wait=%u " - "len=%u\n", id, freq, wait, data_len); + ath6kl_dbg(ATH6KL_DBG_WMI, + "send_action_cmd: id=%u freq=%u wait=%u len=%u\n", + id, freq, wait, data_len); p = (struct wmi_send_mgmt_cmd *) skb->data; p->id = cpu_to_le32(id); p->freq = cpu_to_le32(freq); @@ -3402,8 +3408,9 @@ int ath6kl_wmi_send_probe_response_cmd(struct wmi *wmi, u8 if_idx, u32 freq, if (!skb) return -ENOMEM; - ath6kl_dbg(ATH6KL_DBG_WMI, "send_probe_response_cmd: freq=%u dst=%pM " - "len=%u\n", freq, dst, data_len); + ath6kl_dbg(ATH6KL_DBG_WMI, + "send_probe_response_cmd: freq=%u dst=%pM len=%u\n", + freq, dst, data_len); p = (struct wmi_p2p_probe_response_cmd *) skb->data; p->freq = cpu_to_le32(freq); memcpy(p->destination_addr, dst, ETH_ALEN); From 08c6100967103a26f4cf58b404205747733a8018 Mon Sep 17 00:00:00 2001 From: Ray Chen Date: Thu, 12 Apr 2012 20:48:34 +0800 Subject: [PATCH 07/31] ath6kl: Fix system crash sometimes for USB hotplug System crash because of NULL pointer reference due to cleanup_scatter is not implemented for USB. Signed-off-by: Ray Chen Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/usb.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c index 73aacdd047ca..dfbbe9e7ff75 100644 --- a/drivers/net/wireless/ath/ath6kl/usb.c +++ b/drivers/net/wireless/ath/ath6kl/usb.c @@ -1037,6 +1037,14 @@ static void ath6kl_usb_stop(struct ath6kl *ar) hif_stop(ar); } +static void ath6kl_usb_cleanup_scatter(struct ath6kl *ar) +{ + /* + * USB doesn't support it. Just return. + */ + return; +} + static const struct ath6kl_hif_ops ath6kl_usb_ops = { .diag_read32 = ath6kl_usb_diag_read32, .diag_write32 = ath6kl_usb_diag_write32, @@ -1049,6 +1057,7 @@ static const struct ath6kl_hif_ops ath6kl_usb_ops = { .pipe_get_default = ath6kl_usb_get_default_pipe, .pipe_map_service = ath6kl_usb_map_service_pipe, .pipe_get_free_queue_number = ath6kl_usb_get_free_queue_number, + .cleanup_scatter = ath6kl_usb_cleanup_scatter, }; /* ath6kl usb driver registered functions */ From 48f27587aad1e1630104672b9e20d9d721ea8718 Mon Sep 17 00:00:00 2001 From: Ming Jiang Date: Fri, 13 Apr 2012 21:09:25 +0800 Subject: [PATCH 08/31] ath6kl: allow deepsleep_suspend function when wlan interface down Aafter wlan interface is down WLAN_ENABLED flags will be cleared and deepsleep_suspend function will be blocked in this senario. This patch allows deepsleep_suspend function when wlan interface down by removed the WLAN_ENABLED flag checking. kvalo: fix commit log Signed-off-by: Ming Jiang Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index fffae8768bc7..c5e90d30c672 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -2196,8 +2196,10 @@ static int ath6kl_cfg80211_deepsleep_suspend(struct ath6kl *ar) if (!vif) return -EIO; - if (!ath6kl_cfg80211_ready(vif)) + if (!test_bit(WMI_READY, &ar->flag)) { + ath6kl_err("deepsleep failed as wmi is not ready\n"); return -EIO; + } ath6kl_cfg80211_stop_all(ar); From 2023dbb8310ab39ac1119a32ef52405f7a73f51f Mon Sep 17 00:00:00 2001 From: Tim Gardner Date: Fri, 13 Apr 2012 11:17:27 -0600 Subject: [PATCH 09/31] ath6kl: Normalize use of FW_DIR kvalo: do the same changes for ar6004 hw1.2 as well Cc: Kalle Valo Cc: "John W. Linville" Cc: linux-wireless@vger.kernel.org Cc: netdev@vger.kernel.org Signed-off-by: Tim Gardner Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/core.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index b2ebd56ab9a9..280f305e599d 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -126,9 +126,9 @@ struct ath6kl_fw_ie { #define AR6003_HW_2_0_FIRMWARE_FILE "athwlan.bin.z77" #define AR6003_HW_2_0_TCMD_FIRMWARE_FILE "athtcmd_ram.bin" #define AR6003_HW_2_0_PATCH_FILE "data.patch.bin" -#define AR6003_HW_2_0_BOARD_DATA_FILE "ath6k/AR6003/hw2.0/bdata.bin" +#define AR6003_HW_2_0_BOARD_DATA_FILE AR6003_HW_2_0_FW_DIR "/bdata.bin" #define AR6003_HW_2_0_DEFAULT_BOARD_DATA_FILE \ - "ath6k/AR6003/hw2.0/bdata.SD31.bin" + AR6003_HW_2_0_FW_DIR "/bdata.SD31.bin" /* AR6003 3.0 definitions */ #define AR6003_HW_2_1_1_VERSION 0x30000582 @@ -139,33 +139,33 @@ struct ath6kl_fw_ie { #define AR6003_HW_2_1_1_UTF_FIRMWARE_FILE "utf.bin" #define AR6003_HW_2_1_1_TESTSCRIPT_FILE "nullTestFlow.bin" #define AR6003_HW_2_1_1_PATCH_FILE "data.patch.bin" -#define AR6003_HW_2_1_1_BOARD_DATA_FILE "ath6k/AR6003/hw2.1.1/bdata.bin" +#define AR6003_HW_2_1_1_BOARD_DATA_FILE AR6003_HW_2_1_1_FW_DIR "/bdata.bin" #define AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE \ - "ath6k/AR6003/hw2.1.1/bdata.SD31.bin" + AR6003_HW_2_1_1_FW_DIR "/bdata.SD31.bin" /* AR6004 1.0 definitions */ #define AR6004_HW_1_0_VERSION 0x30000623 #define AR6004_HW_1_0_FW_DIR "ath6k/AR6004/hw1.0" #define AR6004_HW_1_0_FIRMWARE_FILE "fw.ram.bin" -#define AR6004_HW_1_0_BOARD_DATA_FILE "ath6k/AR6004/hw1.0/bdata.bin" +#define AR6004_HW_1_0_BOARD_DATA_FILE AR6004_HW_1_0_FW_DIR "/bdata.bin" #define AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE \ - "ath6k/AR6004/hw1.0/bdata.DB132.bin" + AR6004_HW_1_0_FW_DIR "/bdata.DB132.bin" /* AR6004 1.1 definitions */ #define AR6004_HW_1_1_VERSION 0x30000001 #define AR6004_HW_1_1_FW_DIR "ath6k/AR6004/hw1.1" #define AR6004_HW_1_1_FIRMWARE_FILE "fw.ram.bin" -#define AR6004_HW_1_1_BOARD_DATA_FILE "ath6k/AR6004/hw1.1/bdata.bin" +#define AR6004_HW_1_1_BOARD_DATA_FILE AR6004_HW_1_1_FW_DIR "/bdata.bin" #define AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE \ - "ath6k/AR6004/hw1.1/bdata.DB132.bin" + AR6004_HW_1_1_FW_DIR "/bdata.DB132.bin" /* AR6004 1.2 definitions */ #define AR6004_HW_1_2_VERSION 0x300007e8 #define AR6004_HW_1_2_FW_DIR "ath6k/AR6004/hw1.2" #define AR6004_HW_1_2_FIRMWARE_FILE "fw.ram.bin" -#define AR6004_HW_1_2_BOARD_DATA_FILE "ath6k/AR6004/hw1.2/bdata.bin" +#define AR6004_HW_1_2_BOARD_DATA_FILE AR6004_HW_1_2_FW_DIR "/bdata.bin" #define AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE \ - "ath6k/AR6004/hw1.2/bdata.bin" + AR6004_HW_1_2_FW_DIR "/bdata.bin" /* Per STA data, used in AP mode */ #define STA_PS_AWAKE BIT(0) From ebc6a5332f69c3ce2b071015817fb1cb149217c1 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 13 Apr 2012 22:27:18 +0300 Subject: [PATCH 10/31] ath6kl: list_first_entry() is never NULL We can remove the NULL check here. It triggers a Smatch warning because list_first_entry() never is NULL and people who check for it normally intend to check for list_empty() instead. In these cases however, we've already verified that the lists are not empty. Signed-off-by: Dan Carpenter Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/htc_pipe.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/htc_pipe.c b/drivers/net/wireless/ath/ath6kl/htc_pipe.c index b277b3446882..b21a69fb7f0f 100644 --- a/drivers/net/wireless/ath/ath6kl/htc_pipe.c +++ b/drivers/net/wireless/ath/ath6kl/htc_pipe.c @@ -108,8 +108,6 @@ static void get_htc_packet_credit_based(struct htc_target *target, /* get packet at head, but don't remove it */ packet = list_first_entry(&ep->txq, struct htc_packet, list); - if (packet == NULL) - break; ath6kl_dbg(ATH6KL_DBG_HTC, "%s: got head packet:0x%p , queue depth: %d\n", @@ -803,8 +801,6 @@ static int htc_send_packets_multiple(struct htc_target *target, /* get first packet to find out which ep the packets will go into */ packet = list_first_entry(pkt_queue, struct htc_packet, list); - if (packet == NULL) - return -EINVAL; if (packet->endpoint >= ENDPOINT_MAX) { WARN_ON_ONCE(1); @@ -1636,10 +1632,6 @@ static int ath6kl_htc_pipe_add_rxbuf_multiple(struct htc_target *target, return -EINVAL; first = list_first_entry(pkt_queue, struct htc_packet, list); - if (first == NULL) { - WARN_ON_ONCE(1); - return -EINVAL; - } if (first->endpoint >= ENDPOINT_MAX) { WARN_ON_ONCE(1); From eb38987e899369d936c55f93f631062c417435d2 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 16 Apr 2012 16:09:56 +0530 Subject: [PATCH 11/31] ath6kl: Retain bg scan period value modified by the user Added a new member bg_scan_period in struct ath6kl_vif to retain background scan period value configured via debugfs entry 'bgscan_interval'. This backup is needed in schedule scan path while configuring scan parameters. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 1 + drivers/net/wireless/ath/ath6kl/core.h | 1 + drivers/net/wireless/ath/ath6kl/debug.c | 7 +++++++ 3 files changed, 9 insertions(+) diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index c5e90d30c672..20881334da60 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -3370,6 +3370,7 @@ struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name, vif->next_mode = nw_type; vif->listen_intvl_t = ATH6KL_DEFAULT_LISTEN_INTVAL; vif->bmiss_time_t = ATH6KL_DEFAULT_BMISS_TIME; + vif->bg_scan_period = 0; vif->htcap.ht_enable = true; memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN); diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index 280f305e599d..a97cb836106a 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -557,6 +557,7 @@ struct ath6kl_vif { u16 assoc_bss_beacon_int; u16 listen_intvl_t; u16 bmiss_time_t; + u16 bg_scan_period; u8 assoc_bss_dtim_period; struct net_device_stats net_stats; struct target_stats target_stats; diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c index 496382f472de..acb6430d8e7e 100644 --- a/drivers/net/wireless/ath/ath6kl/debug.c +++ b/drivers/net/wireless/ath/ath6kl/debug.c @@ -1578,10 +1578,15 @@ static ssize_t ath6kl_bgscan_int_write(struct file *file, size_t count, loff_t *ppos) { struct ath6kl *ar = file->private_data; + struct ath6kl_vif *vif; u16 bgscan_int; char buf[32]; ssize_t len; + vif = ath6kl_vif_first(ar); + if (!vif) + return -EIO; + len = min(count, sizeof(buf) - 1); if (copy_from_user(buf, user_buf, len)) return -EFAULT; @@ -1593,6 +1598,8 @@ static ssize_t ath6kl_bgscan_int_write(struct file *file, if (bgscan_int == 0) bgscan_int = 0xffff; + vif->bg_scan_period = bgscan_int; + ath6kl_wmi_scanparams_cmd(ar->wmi, 0, 0, 0, bgscan_int, 0, 0, 0, 3, 0, 0, 0); From d472b5e43dadf7d819ec85464f2c93e696d8f109 Mon Sep 17 00:00:00 2001 From: Subramania Sharma Thandaveswaran Date: Mon, 16 Apr 2012 16:09:57 +0530 Subject: [PATCH 12/31] ath6kl: Fix bug in bg scan configuration in schedule scan Background scan interval should not be modified while starting schedule scanning as it changes the bg scan interval when connected to AP. Use the currently configured interval instead. kvalo: improve commit log Signed-off-by: Subramania Sharma Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 20881334da60..a5f4fd9ff467 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -3121,7 +3121,7 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy, ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, interval, interval, - 10, 0, 0, 0, 3, 0, 0, 0); + vif->bg_scan_period, 0, 0, 0, 3, 0, 0, 0); if (request->n_ssids && request->ssids[0].ssid_len) { for (i = 0; i < request->n_ssids; i++) { From a432e7cc4f3e59f2fd75bb2fd66580f16e8a7447 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 16 Apr 2012 19:25:35 +0300 Subject: [PATCH 13/31] ath6kl: Remove incorrect Probe Response offload support for Interworking ath6kl does not support Probe Response offloading for Interworking (IEEE 802.11u), so remove the incorrectly added capability flag for it. Signed-off-by: Jouni Malinen Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index a5f4fd9ff467..d8fb820f1c9a 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -3466,8 +3466,7 @@ int ath6kl_cfg80211_init(struct ath6kl *ar) ar->wiphy->probe_resp_offload = NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 | - NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P | - NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U; + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P; ret = wiphy_register(wiphy); if (ret < 0) { From 3b8ffc6a22ba05d5ce12f375b060c9e62ed8f016 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 16 Apr 2012 19:28:03 +0300 Subject: [PATCH 14/31] ath6kl: Configure probed SSID list consistently Set max_scan_ssids and max_sched_scan_ssids to same value. These use the same probed SSID list, so there is no point in using different maximum number of SSIDs. Clear probed SSID entries that are not used. This was already done for sched_scan, but not for scan. Be consistent and clear the table for both cases to avoid leaving bogus entries. In addition, share the same function for setting the probed SSIDs for scan and sched_scan paths. This fixes setting of wildcard SSID flag (ANY_SSID_FLAG) and changes the scan path to use probed SSID index consistently (i.e., start with 0 similarly to sched_scan; firmware will handle the needed internal mapping). Signed-off-by: Jouni Malinen Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 63 ++++++++++++---------- 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index d8fb820f1c9a..a8a7570e22a0 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -882,6 +882,32 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason, vif->sme_state = SME_DISCONNECTED; } +static int ath6kl_set_probed_ssids(struct ath6kl *ar, + struct ath6kl_vif *vif, + struct cfg80211_ssid *ssids, int n_ssids) +{ + u8 i; + + if (n_ssids > MAX_PROBED_SSID_INDEX) + return -EINVAL; + + for (i = 0; i < n_ssids; i++) { + ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx, i, + ssids[i].ssid_len ? + SPECIFIC_SSID_FLAG : ANY_SSID_FLAG, + ssids[i].ssid_len, + ssids[i].ssid); + } + + /* Make sure no old entries are left behind */ + for (i = n_ssids; i < MAX_PROBED_SSID_INDEX; i++) { + ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx, i, + DISABLE_SSID_FLAG, 0, NULL); + } + + return 0; +} + static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_scan_request *request) { @@ -909,18 +935,10 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, } } - if (request->n_ssids && request->ssids[0].ssid_len) { - u8 i; - - if (request->n_ssids > (MAX_PROBED_SSID_INDEX - 1)) - request->n_ssids = MAX_PROBED_SSID_INDEX - 1; - - for (i = 0; i < request->n_ssids; i++) - ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx, - i + 1, SPECIFIC_SSID_FLAG, - request->ssids[i].ssid_len, - request->ssids[i].ssid); - } + ret = ath6kl_set_probed_ssids(ar, vif, request->ssids, + request->n_ssids); + if (ret < 0) + return ret; /* this also clears IE in fw if it's not set */ ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, @@ -3100,7 +3118,6 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy, struct ath6kl_vif *vif = netdev_priv(dev); u16 interval; int ret; - u8 i; if (ar->state != ATH6KL_STATE_ON) return -EIO; @@ -3110,11 +3127,10 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy, ath6kl_cfg80211_scan_complete_event(vif, true); - for (i = 0; i < ar->wiphy->max_sched_scan_ssids; i++) { - ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx, - i, DISABLE_SSID_FLAG, - 0, NULL); - } + ret = ath6kl_set_probed_ssids(ar, vif, request->ssids, + request->n_ssids); + if (ret < 0) + return ret; /* fw uses seconds, also make sure that it's >0 */ interval = max_t(u16, 1, request->interval / 1000); @@ -3123,15 +3139,6 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy, interval, interval, vif->bg_scan_period, 0, 0, 0, 3, 0, 0, 0); - if (request->n_ssids && request->ssids[0].ssid_len) { - for (i = 0; i < request->n_ssids; i++) { - ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx, - i, SPECIFIC_SSID_FLAG, - request->ssids[i].ssid_len, - request->ssids[i].ssid); - } - } - ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx, ATH6KL_WOW_MODE_ENABLE, WOW_FILTER_SSID, @@ -3449,7 +3456,7 @@ int ath6kl_cfg80211_init(struct ath6kl *ar) wiphy->wowlan.pattern_min_len = 1; wiphy->wowlan.pattern_max_len = WOW_PATTERN_SIZE; - wiphy->max_sched_scan_ssids = 10; + wiphy->max_sched_scan_ssids = MAX_PROBED_SSID_INDEX; ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM | WIPHY_FLAG_HAVE_AP_SME | From 5699257f69f9584d10b53bb595ed58a434d64321 Mon Sep 17 00:00:00 2001 From: Ming Jiang Date: Wed, 18 Apr 2012 09:25:04 +0800 Subject: [PATCH 15/31] ath6kl clear the MMC_PM_KEEP_POWER for cutpower case ath6kl: If wow deepsleep pno suspend failure driver will choose cutpower. in this scenario MMC_PM_KEEP_POWER should be cleared so that mmc will power off the ar6000 kvalo: remove extra parenthesis Signed-off-by: Ming Jiang Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/sdio.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c index cfcc3216db15..0384a0fb654f 100644 --- a/drivers/net/wireless/ath/ath6kl/sdio.c +++ b/drivers/net/wireless/ath/ath6kl/sdio.c @@ -915,6 +915,9 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) } cut_pwr: + if (func->card && func->card->host) + func->card->host->pm_flags &= ~MMC_PM_KEEP_POWER; + return ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_CUTPOWER, NULL); } From d92917e4db2a9d6af9e362bda5151cadec9e1eeb Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Thu, 19 Apr 2012 15:31:56 -0700 Subject: [PATCH 16/31] ath6kl: support fw reporting phy capabilities Currently the supported bands are just hard coded in the driver. However, the ath6kl FW will include its 11n and band capabilites in a WMI_READY event. Handle this and report capabilites to cfg80211 accordingly. Signed-off-by: Thomas Pedersen Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 36 ++++++++++++++++++++-- drivers/net/wireless/ath/ath6kl/core.h | 4 ++- drivers/net/wireless/ath/ath6kl/main.c | 4 ++- drivers/net/wireless/ath/ath6kl/wmi.c | 2 +- drivers/net/wireless/ath/ath6kl/wmi.h | 10 ++++++ 5 files changed, 51 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index a8a7570e22a0..b8489772c373 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -3419,6 +3419,7 @@ struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name, int ath6kl_cfg80211_init(struct ath6kl *ar) { struct wiphy *wiphy = ar->wiphy; + bool band_2gig = false, band_5gig = false, ht = false; int ret; wiphy->mgmt_stypes = ath6kl_mgmt_stypes; @@ -3439,8 +3440,39 @@ int ath6kl_cfg80211_init(struct ath6kl *ar) /* max num of ssids that can be probed during scanning */ wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX; wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */ - wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz; - wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz; + switch (ar->hw.cap) { + case WMI_11AN_CAP: + ht = true; + case WMI_11A_CAP: + band_5gig = true; + break; + case WMI_11GN_CAP: + ht = true; + case WMI_11G_CAP: + band_2gig = true; + break; + case WMI_11AGN_CAP: + ht = true; + case WMI_11AG_CAP: + band_2gig = true; + band_5gig = true; + break; + default: + ath6kl_err("invalid phy capability!\n"); + return -EINVAL; + } + + if (!ht) { + ath6kl_band_2ghz.ht_cap.cap = 0; + ath6kl_band_2ghz.ht_cap.ht_supported = false; + ath6kl_band_5ghz.ht_cap.cap = 0; + ath6kl_band_5ghz.ht_cap.ht_supported = false; + } + if (band_2gig) + wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz; + if (band_5gig) + wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz; + wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; wiphy->cipher_suites = cipher_suites; diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index a97cb836106a..c26f0a269168 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -683,6 +683,7 @@ struct ath6kl { u32 refclk_hz; u32 uarttx_pin; u32 testscript_addr; + enum wmi_phy_cap cap; struct ath6kl_hw_fw { const char *dir; @@ -816,7 +817,8 @@ void aggr_reset_state(struct aggr_info_conn *aggr_conn); struct ath6kl_sta *ath6kl_find_sta(struct ath6kl_vif *vif, u8 *node_addr); struct ath6kl_sta *ath6kl_find_sta_by_aid(struct ath6kl *ar, u8 aid); -void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver); +void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver, + enum wmi_phy_cap cap); int ath6kl_control_tx(void *devt, struct sk_buff *skb, enum htc_endpoint_id eid); void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index 4f3aab22008a..ff0b999f6f66 100644 --- a/drivers/net/wireless/ath/ath6kl/main.c +++ b/drivers/net/wireless/ath/ath6kl/main.c @@ -548,7 +548,8 @@ void ath6kl_disconnect(struct ath6kl_vif *vif) /* WMI Event handlers */ -void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver) +void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver, + enum wmi_phy_cap cap) { struct ath6kl *ar = devt; @@ -558,6 +559,7 @@ void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver) ar->version.wlan_ver = sw_ver; ar->version.abi_ver = abi_ver; + ar->hw.cap = cap; snprintf(ar->wiphy->fw_version, sizeof(ar->wiphy->fw_version), diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index db688a2e1f6c..2eb771aa88f3 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -690,7 +690,7 @@ static int ath6kl_wmi_ready_event_rx(struct wmi *wmi, u8 *datap, int len) ath6kl_ready_event(wmi->parent_dev, ev->mac_addr, le32_to_cpu(ev->sw_version), - le32_to_cpu(ev->abi_version)); + le32_to_cpu(ev->abi_version), ev->phy_cap); return 0; } diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index 190b2c4e382f..996614038fd4 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -1417,6 +1417,16 @@ struct wmi_ready_event_2 { u8 phy_cap; } __packed; +/* WMI_PHY_CAPABILITY */ +enum wmi_phy_cap { + WMI_11A_CAP = 0x01, + WMI_11G_CAP = 0x02, + WMI_11AG_CAP = 0x03, + WMI_11AN_CAP = 0x04, + WMI_11GN_CAP = 0x05, + WMI_11AGN_CAP = 0x06, +}; + /* Connect Event */ struct wmi_connect_event { union { From 37a2f950acc08cce6532138625de0b7caed21476 Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Thu, 19 Apr 2012 15:31:57 -0700 Subject: [PATCH 17/31] ath6kl: only restore supported HT caps Now that we know the supported PHY capabilities, only restore supported bands / HT capabilities in firmware when stopping AP. Signed-off-by: Thomas Pedersen Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 26 ++++++++++++++++------ 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index b8489772c373..c8147b953be8 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -2477,6 +2477,24 @@ static int ath6kl_set_htcap(struct ath6kl_vif *vif, enum ieee80211_band band, band, htcap); } +static int ath6kl_restore_htcap(struct ath6kl_vif *vif) +{ + struct wiphy *wiphy = vif->ar->wiphy; + int band, ret = 0; + + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + if (!wiphy->bands[band]) + continue; + + ret = ath6kl_set_htcap(vif, band, + wiphy->bands[band]->ht_cap.ht_supported); + if (ret) + return ret; + } + + return ret; +} + static bool ath6kl_is_p2p_ie(const u8 *pos) { return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && @@ -2838,13 +2856,7 @@ static int ath6kl_stop_ap(struct wiphy *wiphy, struct net_device *dev) clear_bit(CONNECTED, &vif->flags); /* Restore ht setting in firmware */ - if (ath6kl_set_htcap(vif, IEEE80211_BAND_2GHZ, true)) - return -EIO; - - if (ath6kl_set_htcap(vif, IEEE80211_BAND_5GHZ, true)) - return -EIO; - - return 0; + return ath6kl_restore_htcap(vif); } static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; From 77ed4e45833fc12f3178a65853687b60e952eddd Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Thu, 19 Apr 2012 16:29:19 -0700 Subject: [PATCH 18/31] ath6kl: disallow WoW with multiple vifs The ath6kl fw does not have enough memory to support the WoW filters of more than one vif. Disallow WoW suspend if this is the case. Signed-off-by: Thomas Pedersen Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index c8147b953be8..d4172137499a 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -2059,6 +2059,10 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) u8 index = 0; __be32 ips[MAX_IP_ADDRS]; + /* The FW currently can't support multi-vif WoW properly. */ + if (ar->num_vif > 1) + return -EIO; + vif = ath6kl_vif_first(ar); if (!vif) return -EIO; @@ -3137,6 +3141,10 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy, if (vif->sme_state != SME_DISCONNECTED) return -EBUSY; + /* The FW currently can't support multi-vif WoW properly. */ + if (ar->num_vif > 1) + return -EIO; + ath6kl_cfg80211_scan_complete_event(vif, true); ret = ath6kl_set_probed_ssids(ar, vif, request->ssids, From 3acabc88072341a0ef6ad8ce5aee3af7429ac522 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 20 Apr 2012 09:43:28 +0300 Subject: [PATCH 19/31] ath6kl: change || to && The original conditions are always true. I think && was intended here, but I don't have the hardware to test. Could you take a look? kvalo: Chilam confirmed that the fix is valid Signed-off-by: Dan Carpenter Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/htc_mbox.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/htc_mbox.c b/drivers/net/wireless/ath/ath6kl/htc_mbox.c index 065e61516d7a..086a8e194700 100644 --- a/drivers/net/wireless/ath/ath6kl/htc_mbox.c +++ b/drivers/net/wireless/ath/ath6kl/htc_mbox.c @@ -758,7 +758,7 @@ static void ath6kl_htc_tx_bundle(struct htc_endpoint *endpoint, u32 txb_mask; u8 ac = WMM_NUM_AC; - if ((HTC_CTRL_RSVD_SVC != endpoint->svc_id) || + if ((HTC_CTRL_RSVD_SVC != endpoint->svc_id) && (WMI_CONTROL_SVC != endpoint->svc_id)) ac = target->dev->ar->ep2ac_map[endpoint->eid]; @@ -866,7 +866,7 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target, */ INIT_LIST_HEAD(&txq); - if ((HTC_CTRL_RSVD_SVC != endpoint->svc_id) || + if ((HTC_CTRL_RSVD_SVC != endpoint->svc_id) && (WMI_CONTROL_SVC != endpoint->svc_id)) ac = target->dev->ar->ep2ac_map[endpoint->eid]; From b86aeb502af956894612b3f726ca75790238b84e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 20 Apr 2012 09:44:44 +0300 Subject: [PATCH 20/31] ath6kl: fix an indenting issue This is supposed to be pushed in one indent level. Signed-off-by: Dan Carpenter Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/htc_mbox.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/htc_mbox.c b/drivers/net/wireless/ath/ath6kl/htc_mbox.c index 086a8e194700..65310d5ae46a 100644 --- a/drivers/net/wireless/ath/ath6kl/htc_mbox.c +++ b/drivers/net/wireless/ath/ath6kl/htc_mbox.c @@ -793,16 +793,17 @@ static void ath6kl_htc_tx_bundle(struct htc_endpoint *endpoint, * itself */ txb_mask = ((1 << ac) - 1); - /* - * when the scatter request resources drop below a - * certain threshold, disable Tx bundling for all - * AC's with priority lower than the current requesting - * AC. Otherwise re-enable Tx bundling for them - */ - if (scat_req->scat_q_depth < ATH6KL_SCATTER_REQS) - target->tx_bndl_mask &= ~txb_mask; - else - target->tx_bndl_mask |= txb_mask; + + /* + * when the scatter request resources drop below a + * certain threshold, disable Tx bundling for all + * AC's with priority lower than the current requesting + * AC. Otherwise re-enable Tx bundling for them + */ + if (scat_req->scat_q_depth < ATH6KL_SCATTER_REQS) + target->tx_bndl_mask &= ~txb_mask; + else + target->tx_bndl_mask |= txb_mask; } ath6kl_dbg(ATH6KL_DBG_HTC, "htc tx pkts to scatter: %d\n", From 92ada0468c50eba6546618a643ecd0af7af7435a Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Fri, 20 Apr 2012 11:33:07 -0700 Subject: [PATCH 21/31] ath6kl: unblock fwlog_block_read() on exit Complete the waiting fwlog_block_read on debugfs cleanup, otherwise userspace and module unload might softlock. Signed-off-by: Thomas Pedersen Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/debug.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c index acb6430d8e7e..ced6c6fe5470 100644 --- a/drivers/net/wireless/ath/ath6kl/debug.c +++ b/drivers/net/wireless/ath/ath6kl/debug.c @@ -1824,6 +1824,7 @@ int ath6kl_debug_init_fs(struct ath6kl *ar) void ath6kl_debug_cleanup(struct ath6kl *ar) { skb_queue_purge(&ar->debug.fwlog_queue); + complete(&ar->debug.fwlog_completion); kfree(ar->debug.roam_tbl); } From 1560ac7d304fdbe603e2fe9cf9564dc81dcccc98 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 23 Apr 2012 19:58:50 -0700 Subject: [PATCH 22/31] ath6kl: include in.h explicitly Do not assume anyone before us includes it for us. Signed-off-by: Luis R. Rodriguez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/wmi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 2eb771aa88f3..bb802e49919c 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -16,6 +16,7 @@ */ #include +#include #include "core.h" #include "debug.h" #include "testmode.h" From 03e2084a843a700089a479e0ffdf5876c7059411 Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Tue, 24 Apr 2012 12:50:41 -0700 Subject: [PATCH 23/31] ath6kl: check for sband existence when creating scan cmd The patch "ath6kl: support fw reporting phy capabilities" gave the firmware the ability to disable certain wiphy supported bands. Check if this is the case in ath6kl_wmi_beginscan_cmd to avoid dereferencing a NULL pointer. kvalo: change the patch so that there's no code between declarations Signed-off-by: Thomas Pedersen Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/wmi.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index bb802e49919c..102477d5900f 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -1818,12 +1818,14 @@ int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx, u32 home_dwell_time, u32 force_scan_interval, s8 num_chan, u16 *ch_list, u32 no_cck, u32 *rates) { + struct ieee80211_supported_band *sband; struct sk_buff *skb; struct wmi_begin_scan_cmd *sc; - s8 size; + s8 size, *supp_rates; int i, band, ret; struct ath6kl *ar = wmi->parent_dev; int num_rates; + u32 ratemask; size = sizeof(struct wmi_begin_scan_cmd); @@ -1850,10 +1852,13 @@ int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx, sc->num_ch = num_chan; for (band = 0; band < IEEE80211_NUM_BANDS; band++) { - struct ieee80211_supported_band *sband = - ar->wiphy->bands[band]; - u32 ratemask = rates[band]; - u8 *supp_rates = sc->supp_rates[band].rates; + sband = ar->wiphy->bands[band]; + + if (!sband) + continue; + + ratemask = rates[band]; + supp_rates = sc->supp_rates[band].rates; num_rates = 0; for (i = 0; i < sband->n_bitrates; i++) { From 6251d8012dbc49869f2453942089c4df82de0c80 Mon Sep 17 00:00:00 2001 From: Naveen Gangadharan Date: Fri, 20 Apr 2012 12:46:56 -0700 Subject: [PATCH 24/31] ath6kl: Multicast filter support in wow suspend and non-suspend This patch enables all multicast packets in non suspend mode and enable multicast filtering in wow suspend mode. This also fixes a bug in multicast where the driver assumed disable multicast-all command disabled/filtered all multicast packets, which was wrong assumption, because firmware will apply the programmed filter. Multicast requirements - Enable forward all multicast packets(no filtering) in non suspend mode. - Enable multicast filtering in wow suspend mode for both AP and CLIENT. kvalo: fix a checkpatch warning and drop unrelated newline removal Signed-off-by: Naveen Gangadharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 14 ++++++++ drivers/net/wireless/ath/ath6kl/core.h | 2 ++ drivers/net/wireless/ath/ath6kl/main.c | 37 ++++++++++++++++------ 3 files changed, 43 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index d4172137499a..f4467733ff5b 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -2076,6 +2076,13 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) if (wow && (wow->n_patterns > WOW_MAX_FILTERS_PER_LIST)) return -EINVAL; + if (!test_bit(NETDEV_MCAST_ALL_ON, &vif->flags)) { + ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi, + vif->fw_vif_idx, false); + if (ret) + return ret; + } + /* Clear existing WOW patterns */ for (i = 0; i < WOW_MAX_FILTERS_PER_LIST; i++) ath6kl_wmi_del_wow_pattern_cmd(ar->wmi, vif->fw_vif_idx, @@ -2204,6 +2211,13 @@ static int ath6kl_wow_resume(struct ath6kl *ar) ar->state = ATH6KL_STATE_ON; + if (!test_bit(NETDEV_MCAST_ALL_OFF, &vif->flags)) { + ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi, + vif->fw_vif_idx, true); + if (ret) + return ret; + } + netif_wake_queue(vif->ndev); return 0; diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index c26f0a269168..4d9c6f142698 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -510,6 +510,8 @@ enum ath6kl_vif_state { WLAN_ENABLED, STATS_UPDATE_PEND, HOST_SLEEP_MODE_CMD_PROCESSED, + NETDEV_MCAST_ALL_ON, + NETDEV_MCAST_ALL_OFF, }; struct ath6kl_vif { diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index ff0b999f6f66..e5524470529c 100644 --- a/drivers/net/wireless/ath/ath6kl/main.c +++ b/drivers/net/wireless/ath/ath6kl/main.c @@ -1145,7 +1145,7 @@ static int ath6kl_set_features(struct net_device *dev, static void ath6kl_set_multicast_list(struct net_device *ndev) { struct ath6kl_vif *vif = netdev_priv(ndev); - bool mc_all_on = false, mc_all_off = false; + bool mc_all_on = false; int mc_count = netdev_mc_count(ndev); struct netdev_hw_addr *ha; bool found; @@ -1157,24 +1157,41 @@ static void ath6kl_set_multicast_list(struct net_device *ndev) !test_bit(WLAN_ENABLED, &vif->flags)) return; + /* Enable multicast-all filter. */ mc_all_on = !!(ndev->flags & IFF_PROMISC) || !!(ndev->flags & IFF_ALLMULTI) || !!(mc_count > ATH6K_MAX_MC_FILTERS_PER_LIST); - mc_all_off = !(ndev->flags & IFF_MULTICAST) || mc_count == 0; + if (mc_all_on) + set_bit(NETDEV_MCAST_ALL_ON, &vif->flags); + else + clear_bit(NETDEV_MCAST_ALL_ON, &vif->flags); - if (mc_all_on || mc_all_off) { - /* Enable/disable all multicast */ - ath6kl_dbg(ATH6KL_DBG_TRC, "%s multicast filter\n", - mc_all_on ? "enabling" : "disabling"); - ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi, vif->fw_vif_idx, + mc_all_on = mc_all_on || (vif->ar->state == ATH6KL_STATE_ON); + + if (!(ndev->flags & IFF_MULTICAST)) { + mc_all_on = false; + set_bit(NETDEV_MCAST_ALL_OFF, &vif->flags); + } else { + clear_bit(NETDEV_MCAST_ALL_OFF, &vif->flags); + } + + /* Enable/disable "multicast-all" filter*/ + ath6kl_dbg(ATH6KL_DBG_TRC, "%s multicast-all filter\n", + mc_all_on ? "enabling" : "disabling"); + + ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi, vif->fw_vif_idx, mc_all_on); - if (ret) - ath6kl_warn("Failed to %s multicast receive\n", - mc_all_on ? "enable" : "disable"); + if (ret) { + ath6kl_warn("Failed to %s multicast-all receive\n", + mc_all_on ? "enable" : "disable"); return; } + if (test_bit(NETDEV_MCAST_ALL_ON, &vif->flags)) + return; + + /* Keep the driver and firmware mcast list in sync. */ list_for_each_entry_safe(mc_filter, tmp, &vif->mc_filter, list) { found = false; netdev_for_each_mc_addr(ha, ndev) { From 7fd1ce7eafb8a68d75363e7500433b0ee4392843 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 25 Apr 2012 12:38:18 +0530 Subject: [PATCH 25/31] ath6kl: Don't advertise HT capability for incapable firmware With firmwares which do not support rsn capability override (ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE) from host would cause 4-way handshake failure when HT cap is advertised. To fix this, do not advertise HT cap with cfg80211 for those fw. kvalo: fix a checkpatch warning Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index f4467733ff5b..3404ef211952 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -3496,7 +3496,14 @@ int ath6kl_cfg80211_init(struct ath6kl *ar) return -EINVAL; } - if (!ht) { + /* + * Even if the fw has HT support, advertise HT cap only when + * the firmware has support to override RSN capability, otherwise + * 4-way handshake would fail. + */ + if (!(ht && + test_bit(ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE, + ar->fw_capabilities))) { ath6kl_band_2ghz.ht_cap.cap = 0; ath6kl_band_2ghz.ht_cap.ht_supported = false; ath6kl_band_5ghz.ht_cap.cap = 0; From 954e6ce54c0a251758a58a58d75ec63722ff036d Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 25 Apr 2012 12:39:06 +0530 Subject: [PATCH 26/31] ath6kl: Fix bss filter setting while scanning bss filter is configured to allow the frames from all the bss other than the currenly connected one, this is done when a scan is requested in connected state. There is no reason to filter out the currently connected bss, configure the filter to allow all the bss. This would fix the reporting of stale rssi of the current bss while scanning. Reported-by: Naveen singh Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 3404ef211952..b869a358ce43 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -925,10 +925,8 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, if (!ar->usr_bss_filter) { clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags); - ret = ath6kl_wmi_bssfilter_cmd( - ar->wmi, vif->fw_vif_idx, - (test_bit(CONNECTED, &vif->flags) ? - ALL_BUT_BSS_FILTER : ALL_BSS_FILTER), 0); + ret = ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, + ALL_BSS_FILTER, 0); if (ret) { ath6kl_err("couldn't set bss filtering\n"); return ret; From f5f7ba25de1bd591d109d2114620677f6af11d99 Mon Sep 17 00:00:00 2001 From: Kevin Fang Date: Fri, 27 Apr 2012 09:18:01 +0800 Subject: [PATCH 27/31] ath6kl: handle background(BK) stream properly on htc mbox layer When a STA sends huge BK QoS data frame first and then sends BE/VI/VO QoS data frame, the corresponding throughput becomes much lower than that without sends BK QoS data frame before. The root cause is that when station send BK stream, the tx credits of BK stream don't return back to higher priority QoS stream such as BE, VI, and VO stream. This patch will handle BK stream properly, when there is higher priority QoS stream, it will seek tx credits from BK stream properly. Signed-off-by: Kevin Fang Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/htc_mbox.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/htc_mbox.c b/drivers/net/wireless/ath/ath6kl/htc_mbox.c index 65310d5ae46a..89eccadd5386 100644 --- a/drivers/net/wireless/ath/ath6kl/htc_mbox.c +++ b/drivers/net/wireless/ath/ath6kl/htc_mbox.c @@ -83,10 +83,7 @@ static void ath6kl_credit_init(struct ath6kl_htc_credit_info *cred_info, * never goes inactive EVER. */ cur_ep_dist->dist_flags |= HTC_EP_ACTIVE; - } else if (cur_ep_dist->svc_id == WMI_DATA_BK_SVC) - /* this is the lowest priority data endpoint */ - /* FIXME: this looks fishy, check */ - cred_info->lowestpri_ep_dist = cur_ep_dist->list; + } /* * Streams have to be created (explicit | implicit) for all @@ -100,6 +97,13 @@ static void ath6kl_credit_init(struct ath6kl_htc_credit_info *cred_info, */ } + /* + * For ath6kl_credit_seek function, + * it use list_for_each_entry_reverse to walk around the whole ep list. + * Therefore assign this lowestpri_ep_dist after walk around the ep_list + */ + cred_info->lowestpri_ep_dist = cur_ep_dist->list; + WARN_ON(cred_info->cur_free_credits <= 0); list_for_each_entry(cur_ep_dist, ep_list, list) { From 096797abbd93730c98ce765a6fe0abee3afaa782 Mon Sep 17 00:00:00 2001 From: Kevin Fang Date: Fri, 27 Apr 2012 09:18:02 +0800 Subject: [PATCH 28/31] ath6kl: assign Tx packet drop threshold per endpoint on htc pipe layer On the htc mbox layer, it will assign each endpoint (AC) with a different Tx-packet-drop threshold, so lower priority AC is more likely to drop packets and the cookies become more available to higher priority AC. On the htc pipe layer, assign the tx packet drop threshold as well, it will let AC to drop packets when cookies below the tx packet drop threshold. Signed-off-by: Kevin Fang Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/htc_pipe.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/ath/ath6kl/htc_pipe.c b/drivers/net/wireless/ath/ath6kl/htc_pipe.c index b21a69fb7f0f..f9626c723693 100644 --- a/drivers/net/wireless/ath/ath6kl/htc_pipe.c +++ b/drivers/net/wireless/ath/ath6kl/htc_pipe.c @@ -1378,6 +1378,9 @@ static int ath6kl_htc_pipe_conn_service(struct htc_target *target, /* copy all the callbacks */ ep->ep_cb = conn_req->ep_cb; + /* initialize tx_drop_packet_threshold */ + ep->tx_drop_packet_threshold = MAX_HI_COOKIE_NUM; + status = ath6kl_hif_pipe_map_service(ar, ep->svc_id, &ep->pipe.pipeid_ul, &ep->pipe.pipeid_dl); From 1881ced5963520154aebb616ad7b2ff9c2c7f012 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Thu, 26 Apr 2012 20:26:13 +0530 Subject: [PATCH 29/31] ath6kl: Update netstats for some of the tx failrues in ath6kl_data_tx() There are few cases where the tx skb is dropped but netstats is not updated, fix this. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/txrx.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c index 82f2f5cb475b..67206aedea6c 100644 --- a/drivers/net/wireless/ath/ath6kl/txrx.c +++ b/drivers/net/wireless/ath/ath6kl/txrx.c @@ -362,15 +362,11 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev) skb, skb->data, skb->len); /* If target is not associated */ - if (!test_bit(CONNECTED, &vif->flags)) { - dev_kfree_skb(skb); - return 0; - } + if (!test_bit(CONNECTED, &vif->flags)) + goto fail_tx; - if (WARN_ON_ONCE(ar->state != ATH6KL_STATE_ON)) { - dev_kfree_skb(skb); - return 0; - } + if (WARN_ON_ONCE(ar->state != ATH6KL_STATE_ON)) + goto fail_tx; if (!test_bit(WMI_READY, &ar->flag)) goto fail_tx; From 93b42cae16d7af185ebdee0f4e85feccfd40d986 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Thu, 26 Apr 2012 20:26:14 +0530 Subject: [PATCH 30/31] ath6kl: Complete failed tx packet in ath6kl_htc_tx_from_queue() Return status of ath6kl_htc_tx_issue() is ignored in ath6kl_htc_tx_from_queue(), but failed tx packet is is not cleaned up. To fix memory leak in this case, call completion with error. Also, throw an error debug message when tx fails in ath6kl_sdio_write_async() due to shortage in bus request buffer. kvalo: change the error message to WARN_ON_ONCE() Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/htc_mbox.c | 8 +++++++- drivers/net/wireless/ath/ath6kl/sdio.c | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/htc_mbox.c b/drivers/net/wireless/ath/ath6kl/htc_mbox.c index 89eccadd5386..2798624d3a9d 100644 --- a/drivers/net/wireless/ath/ath6kl/htc_mbox.c +++ b/drivers/net/wireless/ath/ath6kl/htc_mbox.c @@ -854,6 +854,7 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target, int bundle_sent; int n_pkts_bundle; u8 ac = WMM_NUM_AC; + int status; spin_lock_bh(&target->tx_lock); @@ -915,7 +916,12 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target, ath6kl_htc_tx_prep_pkt(packet, packet->info.tx.flags, 0, packet->info.tx.seqno); - ath6kl_htc_tx_issue(target, packet); + status = ath6kl_htc_tx_issue(target, packet); + + if (status) { + packet->status = status; + packet->completion(packet->context, packet); + } } spin_lock_bh(&target->tx_lock); diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c index 0384a0fb654f..05b95405f7b5 100644 --- a/drivers/net/wireless/ath/ath6kl/sdio.c +++ b/drivers/net/wireless/ath/ath6kl/sdio.c @@ -552,7 +552,7 @@ static int ath6kl_sdio_write_async(struct ath6kl *ar, u32 address, u8 *buffer, bus_req = ath6kl_sdio_alloc_busreq(ar_sdio); - if (!bus_req) + if (WARN_ON_ONCE(!bus_req)) return -ENOMEM; bus_req->address = address; From f3740572512075839e1a7ebde970081106fed3f0 Mon Sep 17 00:00:00 2001 From: Vivek Natarajan Date: Wed, 2 May 2012 14:55:25 +0530 Subject: [PATCH 31/31] ath6kl_sdio: Fix the EAPOL out of order issue Send the EAPOL and management frames in the same AC_VO queue. The issue happens when the AP supports QOS, the management frames are sent to AC_VO queue and EAP frame goes to AC_BE queue. Even though the EAP frame is queued before the DEAUTH management frame, as they are queued on different h/w queues, order of delivery between these frames cannot be controlled. This fixes the connection failure seen in P2P case. Signed-off-by: Vivek Natarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/wmi.c | 7 +++++++ drivers/net/wireless/ath/ath6kl/wmi.h | 2 ++ 2 files changed, 9 insertions(+) diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 102477d5900f..ee8ec2394c2c 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -290,6 +290,13 @@ int ath6kl_wmi_implicit_create_pstream(struct wmi *wmi, u8 if_idx, layer2_priority); } else usr_pri = layer2_priority & 0x7; + + /* + * Queue the EAPOL frames in the same WMM_AC_VO queue + * as that of management frames. + */ + if (skb->protocol == cpu_to_be16(ETH_P_PAE)) + usr_pri = WMI_VOICE_USER_PRIORITY; } /* diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index 996614038fd4..9076bec3a2ba 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -106,6 +106,8 @@ struct wmi_data_sync_bufs { #define WMM_AC_VI 2 /* video */ #define WMM_AC_VO 3 /* voice */ +#define WMI_VOICE_USER_PRIORITY 0x7 + struct wmi { u16 stream_exist_for_ac[WMM_NUM_AC]; u8 fat_pipe_exist;