From 98d633b64a55d6f3e943951ca35f283b0901d7db Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Thu, 8 Jul 2010 06:27:38 +0300 Subject: wl1271: remove deprecated ACX definition As of Rev. 6.1.0.0.335, the ACX_SET_SMART_REFLEX_DEBUG command is deprecated. This patch removes it from the wl1271 driver (it wasn't used anyway). Signed-off-by: Luciano Coelho Reviewed-by: Saravanan Dhanabal --- drivers/net/wireless/wl12xx/wl1271_acx.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h index 4235bc56f750..5c8bb7fd2eb9 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.h +++ b/drivers/net/wireless/wl12xx/wl1271_acx.h @@ -1060,7 +1060,6 @@ enum { ACX_PEER_HT_CAP = 0x0057, ACX_HT_BSS_OPERATION = 0x0058, ACX_COEX_ACTIVITY = 0x0059, - ACX_SET_SMART_REFLEX_DEBUG = 0x005A, ACX_SET_DCO_ITRIM_PARAMS = 0x0061, DOT11_RX_MSDU_LIFE_TIME = 0x1004, DOT11_CUR_TX_PWR = 0x100D, -- cgit v1.2.3 From be86cbea1e9c3a4dd8faedcfa327495d09fe3531 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Thu, 27 May 2010 12:53:01 +0300 Subject: wl1271: Implement CMD_SET_STA_STATE to indicate connection completion to FW Implement the command function to send CMD_SET_STA_STATE to the firmware. This is used to indicate that association (and the related EAP negotiation) are complete. This is used to tune WLAN-BT coexistense priority towards BT, improving BT A2DP and SCO performance. Signed-off-by: Juuso Oikarinen Reviewed-by: Teemu Paasikivi Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271_cmd.c | 28 ++++++++++++++++++++++++++++ drivers/net/wireless/wl12xx/wl1271_cmd.h | 10 ++++++++++ 2 files changed, 38 insertions(+) diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index ce503ddd5a41..a338b1c93a29 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -746,3 +746,31 @@ out_free: out: return ret; } + +int wl1271_cmd_set_sta_state(struct wl1271 *wl) +{ + struct wl1271_cmd_set_sta_state *cmd; + int ret = 0; + + wl1271_debug(DEBUG_CMD, "cmd set sta state"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->state = WL1271_CMD_STA_STATE_CONNECTED; + + ret = wl1271_cmd_send(wl, CMD_SET_STA_STATE, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to send set STA state command"); + goto out_free; + } + +out_free: + kfree(cmd); + +out: + return ret; +} diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.h b/drivers/net/wireless/wl12xx/wl1271_cmd.h index af577ee8eb02..ce0476ceb84a 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.h +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.h @@ -55,6 +55,7 @@ int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, u8 key_size, const u8 *key, const u8 *addr, u32 tx_seq_32, u16 tx_seq_16); int wl1271_cmd_disconnect(struct wl1271 *wl); +int wl1271_cmd_set_sta_state(struct wl1271 *wl); enum wl1271_commands { CMD_INTERROGATE = 1, /*use this to read information elements*/ @@ -469,4 +470,13 @@ struct wl1271_cmd_disconnect { u8 padding; } __packed; +#define WL1271_CMD_STA_STATE_CONNECTED 1 + +struct wl1271_cmd_set_sta_state { + struct wl1271_cmd_header header; + + u8 state; + u8 padding[3]; +} __attribute__ ((packed)); + #endif /* __WL1271_CMD_H__ */ -- cgit v1.2.3 From c2c192ac6c16e2e8f5cc8cf54e02bb1d4e0e761d Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Tue, 27 Jul 2010 03:30:09 +0300 Subject: wl1271: Add trigger to net_device oper_state to change BT coex priority Add a trigger to net_device changes to monitor for oper_state changes in order to be able to inform the firmware when association is fully complete (including the EAP negotiation.) Signed-off-by: Juuso Oikarinen Reviewed-by: Teemu Paasikivi Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271.h | 1 + drivers/net/wireless/wl12xx/wl1271_main.c | 69 +++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index 4134f4495b95..1098d1689b0e 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -350,6 +350,7 @@ struct wl1271 { #define WL1271_FLAG_IDLE (10) #define WL1271_FLAG_IDLE_REQUESTED (11) #define WL1271_FLAG_PSPOLL_FAILURE (12) +#define WL1271_FLAG_STA_STATE_SENT (13) unsigned long flags; struct wl1271_partition_set part; diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 776cd7c41148..45d4ce36343c 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -277,6 +277,67 @@ static struct platform_device wl1271_device = { static LIST_HEAD(wl_list); +static int wl1271_dev_notify(struct notifier_block *me, unsigned long what, + void *arg) +{ + struct net_device *dev = arg; + struct wireless_dev *wdev; + struct wiphy *wiphy; + struct ieee80211_hw *hw; + struct wl1271 *wl; + struct wl1271 *wl_temp; + int ret = 0; + + /* Check that this notification is for us. */ + if (what != NETDEV_CHANGE) + return NOTIFY_DONE; + + wdev = dev->ieee80211_ptr; + if (wdev == NULL) + return NOTIFY_DONE; + + wiphy = wdev->wiphy; + if (wiphy == NULL) + return NOTIFY_DONE; + + hw = wiphy_priv(wiphy); + if (hw == NULL) + return NOTIFY_DONE; + + wl_temp = hw->priv; + list_for_each_entry(wl, &wl_list, list) { + if (wl == wl_temp) + break; + } + if (wl != wl_temp) + return NOTIFY_DONE; + + mutex_lock(&wl->mutex); + + if (wl->state == WL1271_STATE_OFF) + goto out; + + if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) + goto out; + + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + goto out; + + if ((dev->operstate == IF_OPER_UP) && + !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) { + wl1271_cmd_set_sta_state(wl); + wl1271_info("Association completed."); + } + + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); + + return NOTIFY_OK; +} + static void wl1271_conf_init(struct wl1271 *wl) { @@ -814,6 +875,10 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) return NETDEV_TX_OK; } +static struct notifier_block wl1271_dev_notifier = { + .notifier_call = wl1271_dev_notify, +}; + static int wl1271_op_start(struct ieee80211_hw *hw) { wl1271_debug(DEBUG_MAC80211, "mac80211 start"); @@ -1783,6 +1848,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, } } else { /* use defaults when not associated */ + clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags); clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags); wl->aid = 0; @@ -2307,6 +2373,8 @@ int wl1271_register_hw(struct wl1271 *wl) wl->mac80211_registered = true; + register_netdevice_notifier(&wl1271_dev_notifier); + wl1271_notice("loaded"); return 0; @@ -2315,6 +2383,7 @@ EXPORT_SYMBOL_GPL(wl1271_register_hw); void wl1271_unregister_hw(struct wl1271 *wl) { + unregister_netdevice_notifier(&wl1271_dev_notifier); ieee80211_unregister_hw(wl->hw); wl->mac80211_registered = false; -- cgit v1.2.3 From 76a029fbfb18c42f75c891842df26605ef87add0 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Thu, 29 Jul 2010 04:54:45 +0300 Subject: wl1271: Fix scan race condition In the scan state machine, the wl1271_mutex is unlocked first then relocked, and then the scan state variables are modified. This makes it possible for ieee80211_scan_complete to be called twice in some scenarios, as the scan completion event from the firmware may be processed while the mutex is unlocked. To fix the issue, move the ieee80211_scan_complete call last in the function. This is generally safer, but there still may be issues is functions calling the scan state machine rely on states checked before the unlocking of the global mutex. (forward ported from 2.6.32 -- this is not strictly needed anymore, because the mutex doesn't need to be unlocked anymore, but I'm applying this change anyway, so that the call to ieee80211_scan_complete is in the same place) Signed-off-by: Juuso Oikarinen Reviewed-by: Saravanan Dhanabal Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271_main.c | 2 +- drivers/net/wireless/wl12xx/wl1271_scan.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 45d4ce36343c..02ad6c648115 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -1015,10 +1015,10 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw, ieee80211_enable_dyn_ps(wl->vif); if (wl->scan.state != WL1271_SCAN_STATE_IDLE) { - ieee80211_scan_completed(wl->hw, true); wl->scan.state = WL1271_SCAN_STATE_IDLE; kfree(wl->scan.scanned_ch); wl->scan.scanned_ch = NULL; + ieee80211_scan_completed(wl->hw, true); } wl->state = WL1271_STATE_OFF; diff --git a/drivers/net/wireless/wl12xx/wl1271_scan.c b/drivers/net/wireless/wl12xx/wl1271_scan.c index 9c80ba9b6be0..8ceaabe26e64 100644 --- a/drivers/net/wireless/wl12xx/wl1271_scan.c +++ b/drivers/net/wireless/wl12xx/wl1271_scan.c @@ -215,12 +215,11 @@ void wl1271_scan_stm(struct wl1271 *wl) break; case WL1271_SCAN_STATE_DONE: - ieee80211_scan_completed(wl->hw, false); - kfree(wl->scan.scanned_ch); wl->scan.scanned_ch = NULL; wl->scan.state = WL1271_SCAN_STATE_IDLE; + ieee80211_scan_completed(wl->hw, false); break; default: -- cgit v1.2.3 From 5924f89d6597cd7ba014128ded64b2c7450c369c Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Wed, 4 Aug 2010 03:46:22 +0300 Subject: wl1271: remove useless 11a check when scanning This code was a leftover of the previous scanning mechanism. The if is totally unnecessary, since both branches do the same thing. Signed-off-by: Luciano Coelho Reviewed-by: Juuso Oikarinen --- drivers/net/wireless/wl12xx/wl1271_main.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 02ad6c648115..b42ee484a86f 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -1624,10 +1624,7 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw, if (ret < 0) goto out; - if (wl1271_11a_enabled()) - ret = wl1271_scan(hw->priv, ssid, len, req); - else - ret = wl1271_scan(hw->priv, ssid, len, req); + ret = wl1271_scan(hw->priv, ssid, len, req); wl1271_ps_elp_sleep(wl); -- cgit v1.2.3 From 4f35c0253ab7f32cf30eab5459e8256af1619ff1 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Wed, 4 Aug 2010 04:36:32 +0300 Subject: wl1271: fix forced passive scan When we get no SSIDs in the scan request, we should force a passive scan in all channels. This patch adds code to force the passive scan flag to be set in that case. Signed-off-by: Luciano Coelho Reviewed-by: Juuso Oikarinen --- drivers/net/wireless/wl12xx/wl1271_scan.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_scan.c b/drivers/net/wireless/wl12xx/wl1271_scan.c index 8ceaabe26e64..7f42ca9abab8 100644 --- a/drivers/net/wireless/wl12xx/wl1271_scan.c +++ b/drivers/net/wireless/wl12xx/wl1271_scan.c @@ -100,8 +100,11 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band, /* We always use high priority scans */ scan_options = WL1271_SCAN_OPT_PRIORITY_HIGH; - if(passive) + + /* No SSIDs means that we have a forced passive scan */ + if (passive || wl->scan.req->n_ssids == 0) scan_options |= WL1271_SCAN_OPT_PASSIVE; + cmd->params.scan_options = cpu_to_le16(scan_options); cmd->params.n_ch = wl1271_get_scan_channels(wl, wl->scan.req, -- cgit v1.2.3 From fa21c7a9e4be439e217fe72edbd39b643b643791 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Tue, 10 Aug 2010 08:22:02 +0200 Subject: wl1271: Change supported channel order for a more optimal scan The mac80211 inserts channels into a scan request in the same order the driver registers them. Use this fact to optimize scan by ordering the channels so that adjacent channels don't get scanned consecutively. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271_main.c | 86 +++++++++++++++++-------------- 1 file changed, 46 insertions(+), 40 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index b42ee484a86f..8ce891aa2273 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -2057,21 +2057,24 @@ static struct ieee80211_rate wl1271_rates[] = { .hw_value_short = CONF_HW_BIT_RATE_54MBPS, }, }; -/* can't be const, mac80211 writes to this */ +/* + * Can't be const, mac80211 writes to this. The order of the channels here + * is designed to improve scanning. + */ 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 = 4, .center_freq = 2427, .max_power = 25 }, + { .hw_value = 8, .center_freq = 2447, .max_power = 25 }, + { .hw_value = 12, .center_freq = 2467, .max_power = 25 }, + { .hw_value = 3, .center_freq = 2422, .max_power = 25 }, + { .hw_value = 7, .center_freq = 2442, .max_power = 25 }, + { .hw_value = 11, .center_freq = 2462, .max_power = 25 }, + { .hw_value = 2, .center_freq = 2417, .max_power = 25 }, + { .hw_value = 6, .center_freq = 2437, .max_power = 25 }, + { .hw_value = 10, .center_freq = 2457, .max_power = 25 }, }; /* mapping to indexes for wl1271_rates */ @@ -2140,49 +2143,52 @@ static struct ieee80211_rate wl1271_rates_5ghz[] = { .hw_value_short = CONF_HW_BIT_RATE_54MBPS, }, }; -/* 5 GHz band channels for WL1273 */ +/* + * 5 GHz band channels for WL1273 - can't be const, mac80211 writes to this. + * The order of the channels here is designed to improve scanning. + */ static struct ieee80211_channel wl1271_channels_5ghz[] = { { .hw_value = 183, .center_freq = 4915}, - { .hw_value = 184, .center_freq = 4920}, - { .hw_value = 185, .center_freq = 4925}, - { .hw_value = 187, .center_freq = 4935}, { .hw_value = 188, .center_freq = 4940}, - { .hw_value = 189, .center_freq = 4945}, - { .hw_value = 192, .center_freq = 4960}, - { .hw_value = 196, .center_freq = 4980}, - { .hw_value = 7, .center_freq = 5035}, { .hw_value = 8, .center_freq = 5040}, - { .hw_value = 9, .center_freq = 5045}, - { .hw_value = 11, .center_freq = 5055}, - { .hw_value = 12, .center_freq = 5060}, - { .hw_value = 16, .center_freq = 5080}, { .hw_value = 34, .center_freq = 5170}, - { .hw_value = 36, .center_freq = 5180}, - { .hw_value = 38, .center_freq = 5190}, - { .hw_value = 40, .center_freq = 5200}, - { .hw_value = 42, .center_freq = 5210}, { .hw_value = 44, .center_freq = 5220}, - { .hw_value = 46, .center_freq = 5230}, - { .hw_value = 48, .center_freq = 5240}, - { .hw_value = 52, .center_freq = 5260}, - { .hw_value = 56, .center_freq = 5280}, { .hw_value = 60, .center_freq = 5300}, - { .hw_value = 64, .center_freq = 5320}, - { .hw_value = 100, .center_freq = 5500}, - { .hw_value = 104, .center_freq = 5520}, - { .hw_value = 108, .center_freq = 5540}, { .hw_value = 112, .center_freq = 5560}, - { .hw_value = 116, .center_freq = 5580}, - { .hw_value = 120, .center_freq = 5600}, - { .hw_value = 124, .center_freq = 5620}, - { .hw_value = 128, .center_freq = 5640}, { .hw_value = 132, .center_freq = 5660}, + { .hw_value = 157, .center_freq = 5785}, + { .hw_value = 184, .center_freq = 4920}, + { .hw_value = 189, .center_freq = 4945}, + { .hw_value = 9, .center_freq = 5045}, + { .hw_value = 36, .center_freq = 5180}, + { .hw_value = 46, .center_freq = 5230}, + { .hw_value = 64, .center_freq = 5320}, + { .hw_value = 116, .center_freq = 5580}, { .hw_value = 136, .center_freq = 5680}, + { .hw_value = 192, .center_freq = 4960}, + { .hw_value = 11, .center_freq = 5055}, + { .hw_value = 38, .center_freq = 5190}, + { .hw_value = 48, .center_freq = 5240}, + { .hw_value = 100, .center_freq = 5500}, + { .hw_value = 120, .center_freq = 5600}, { .hw_value = 140, .center_freq = 5700}, + { .hw_value = 185, .center_freq = 4925}, + { .hw_value = 196, .center_freq = 4980}, + { .hw_value = 12, .center_freq = 5060}, + { .hw_value = 40, .center_freq = 5200}, + { .hw_value = 52, .center_freq = 5260}, + { .hw_value = 104, .center_freq = 5520}, + { .hw_value = 124, .center_freq = 5620}, { .hw_value = 149, .center_freq = 5745}, - { .hw_value = 153, .center_freq = 5765}, - { .hw_value = 157, .center_freq = 5785}, { .hw_value = 161, .center_freq = 5805}, + { .hw_value = 187, .center_freq = 4935}, + { .hw_value = 7, .center_freq = 5035}, + { .hw_value = 16, .center_freq = 5080}, + { .hw_value = 42, .center_freq = 5210}, + { .hw_value = 56, .center_freq = 5280}, + { .hw_value = 108, .center_freq = 5540}, + { .hw_value = 128, .center_freq = 5640}, + { .hw_value = 153, .center_freq = 5765}, { .hw_value = 165, .center_freq = 5825}, }; -- cgit v1.2.3 From 2f63b011b4a6d3c0572147be5756212f5558fff0 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Tue, 10 Aug 2010 06:38:35 +0200 Subject: wl1271: Remove outdated FIXME's Remove outdated FIXME's from the code. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271_boot.c | 17 +++++------------ drivers/net/wireless/wl12xx/wl1271_main.c | 7 ++----- drivers/net/wireless/wl12xx/wl1271_tx.c | 2 -- 3 files changed, 7 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.c b/drivers/net/wireless/wl12xx/wl1271_boot.c index e5a7f042645f..f750d5a79089 100644 --- a/drivers/net/wireless/wl12xx/wl1271_boot.c +++ b/drivers/net/wireless/wl12xx/wl1271_boot.c @@ -251,8 +251,10 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) burst_len = nvs_ptr[0]; dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8)); - /* FIXME: Due to our new wl1271_translate_reg_addr function, - we need to add the REGISTER_BASE to the destination */ + /* + * Due to our new wl1271_translate_reg_addr function, + * we need to add the REGISTER_BASE to the destination + */ dest_addr += REGISTERS_BASE; /* We move our pointer to the data */ @@ -280,8 +282,6 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) ALIGN(nvs_ptr - (u8 *)wl->nvs->nvs + 7, 4); nvs_len -= nvs_ptr - (u8 *)wl->nvs->nvs; - /* FIXME: The driver sets the partition here, but this is not needed, - since it sets to the same one as currently in use */ /* Now we must set the partition correctly */ wl1271_set_partition(wl, &part_table[PART_WORK]); @@ -291,9 +291,6 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) 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); kfree(nvs_aligned); @@ -491,10 +488,7 @@ int wl1271_boot(struct wl1271 *wl) wl1271_debug(DEBUG_BOOT, "pause1 0x%x", pause); - pause &= ~(WU_COUNTER_PAUSE_VAL); /* FIXME: This should probably be - * WU_COUNTER_PAUSE_VAL instead of - * 0x3ff (magic number ). How does - * this work?! */ + pause &= ~(WU_COUNTER_PAUSE_VAL); pause |= WU_COUNTER_PAUSE_VAL; wl1271_write32(wl, WU_COUNTER_PAUSE, pause); @@ -548,7 +542,6 @@ int wl1271_boot(struct wl1271 *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); diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 8ce891aa2273..bbd075a88f2d 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -251,7 +251,6 @@ static struct conf_drv_settings default_conf = { .host_fast_wakeup_support = false }, .roam_trigger = { - /* FIXME: due to firmware bug, must use value 1 for now */ .trigger_pacing = 1, .avg_weight_rssi_beacon = 20, .avg_weight_rssi_data = 10, @@ -2281,8 +2280,7 @@ static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev, struct wl1271 *wl = dev_get_drvdata(dev); ssize_t len; - /* FIXME: what's the maximum length of buf? page size?*/ - len = 500; + len = PAGE_SIZE; mutex_lock(&wl->mutex); len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n", @@ -2343,8 +2341,7 @@ static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev, struct wl1271 *wl = dev_get_drvdata(dev); ssize_t len; - /* FIXME: what's the maximum length of buf? page size?*/ - len = 500; + len = PAGE_SIZE; mutex_lock(&wl->mutex); if (wl->hw_pg_ver >= 0) diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c index dc0b46c93c4b..0f99eff3b7ef 100644 --- a/drivers/net/wireless/wl12xx/wl1271_tx.c +++ b/drivers/net/wireless/wl12xx/wl1271_tx.c @@ -422,8 +422,6 @@ void wl1271_tx_reset(struct wl1271 *wl) struct sk_buff *skb; /* TX failure */ -/* control->flags = 0; FIXME */ - while ((skb = skb_dequeue(&wl->tx_queue))) { wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb); ieee80211_tx_status(wl->hw, skb); -- cgit v1.2.3 From 03f06b7efc8cbc666bd096b68bdf955388e0b323 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Tue, 10 Aug 2010 06:38:36 +0200 Subject: wl1271: Move setting of wake-up conditions to ps.c from cmd.c This removes a fixme. Also, it removes a redundant setting of the wake-up conditions when exiting power save mode, which should improve performance. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271_cmd.c | 7 ------- drivers/net/wireless/wl12xx/wl1271_ps.c | 6 ++++++ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index a338b1c93a29..a516035350d5 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -395,13 +395,6 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, bool send) struct wl1271_cmd_ps_params *ps_params = NULL; int ret = 0; - /* FIXME: this should be in ps.c */ - ret = wl1271_acx_wake_up_conditions(wl); - if (ret < 0) { - wl1271_error("couldn't set wake up conditions"); - goto out; - } - wl1271_debug(DEBUG_CMD, "cmd set ps mode"); ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL); diff --git a/drivers/net/wireless/wl12xx/wl1271_ps.c b/drivers/net/wireless/wl12xx/wl1271_ps.c index a5e60e0403e5..52a60959bb9c 100644 --- a/drivers/net/wireless/wl12xx/wl1271_ps.c +++ b/drivers/net/wireless/wl12xx/wl1271_ps.c @@ -129,6 +129,12 @@ 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_acx_wake_up_conditions(wl); + if (ret < 0) { + wl1271_error("couldn't set wake up conditions"); + return ret; + } + ret = wl1271_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE, send); if (ret < 0) return ret; -- cgit v1.2.3 From 165530974504e21d79a43e5f964bd9284e45a8f1 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Tue, 17 Aug 2010 03:50:04 +0200 Subject: wl1271: Remove acx_fw_version function It's not used anywhere. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271_acx.c | 34 -------------------------------- drivers/net/wireless/wl12xx/wl1271_acx.h | 30 ---------------------------- 2 files changed, 64 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/wl1271_acx.c index f03ad088db8b..618993405262 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.c +++ b/drivers/net/wireless/wl12xx/wl1271_acx.c @@ -86,40 +86,6 @@ out: return ret; } -int wl1271_acx_fw_version(struct wl1271 *wl, char *buf, size_t len) -{ - struct acx_revision *rev; - int ret; - - wl1271_debug(DEBUG_ACX, "acx fw rev"); - - rev = kzalloc(sizeof(*rev), GFP_KERNEL); - if (!rev) { - ret = -ENOMEM; - goto out; - } - - ret = wl1271_cmd_interrogate(wl, ACX_FW_REV, rev, sizeof(*rev)); - if (ret < 0) { - wl1271_warning("ACX_FW_REV interrogate failed"); - goto out; - } - - /* be careful with the buffer sizes */ - strncpy(buf, rev->fw_version, min(len, sizeof(rev->fw_version))); - - /* - * if the firmware version string is exactly - * sizeof(rev->fw_version) long or fw_len is less than - * sizeof(rev->fw_version) it won't be null terminated - */ - buf[min(len, sizeof(rev->fw_version)) - 1] = '\0'; - -out: - kfree(rev); - return ret; -} - int wl1271_acx_tx_power(struct wl1271 *wl, int power) { struct acx_current_tx_power *acx; diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h index 5c8bb7fd2eb9..ebb341d36e8c 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.h +++ b/drivers/net/wireless/wl12xx/wl1271_acx.h @@ -100,35 +100,6 @@ struct acx_error_counter { __le32 seq_num_miss; } __packed; -struct acx_revision { - struct acx_header header; - - /* - * The WiLink firmware version, an ASCII string x.x.x.x, - * that uniquely identifies the current firmware. - * The left most digit is incremented each time a - * significant change is made to the firmware, such as - * code redesign or new platform support. - * The second digit is incremented when major enhancements - * are added or major fixes are made. - * The third digit is incremented for each GA release. - * The fourth digit is incremented for each build. - * The first two digits identify a firmware release version, - * in other words, a unique set of features. - * The first three digits identify a GA release. - */ - char fw_version[20]; - - /* - * This 4 byte field specifies the WiLink hardware version. - * bits 0 - 15: Reserved. - * bits 16 - 23: Version ID - The WiLink version ID - * (1 = first spin, 2 = second spin, and so on). - * bits 24 - 31: Chip ID - The WiLink chip ID. - */ - __le32 hw_version; -} __packed; - enum wl1271_psm_mode { /* Active mode */ WL1271_PSM_CAM = 0, @@ -1076,7 +1047,6 @@ enum { int wl1271_acx_wake_up_conditions(struct wl1271 *wl); int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth); -int wl1271_acx_fw_version(struct wl1271 *wl, char *buf, size_t len); int wl1271_acx_tx_power(struct wl1271 *wl, int power); int wl1271_acx_feature_cfg(struct wl1271 *wl); int wl1271_acx_mem_map(struct wl1271 *wl, -- cgit v1.2.3 From 4e23b11b08ed116664cce6114546d5a96eb94e8b Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Fri, 13 Aug 2010 04:46:48 +0200 Subject: wl1271: Release interrupt *after* releasing the driver context The current order causes driver releasing to fail in various ways, and causes possible instability. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271_sdio.c | 3 +-- drivers/net/wireless/wl12xx/wl1271_spi.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_sdio.c b/drivers/net/wireless/wl12xx/wl1271_sdio.c index f2f04663627c..4c250d7dc3fa 100644 --- a/drivers/net/wireless/wl12xx/wl1271_sdio.c +++ b/drivers/net/wireless/wl12xx/wl1271_sdio.c @@ -274,9 +274,8 @@ static void __devexit wl1271_remove(struct sdio_func *func) { struct wl1271 *wl = sdio_get_drvdata(func); - free_irq(wl->irq, wl); - wl1271_unregister_hw(wl); + free_irq(wl->irq, wl); wl1271_free_hw(wl); } diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.c b/drivers/net/wireless/wl12xx/wl1271_spi.c index ced0a9e2c7e1..75cbf36146e2 100644 --- a/drivers/net/wireless/wl12xx/wl1271_spi.c +++ b/drivers/net/wireless/wl12xx/wl1271_spi.c @@ -416,9 +416,8 @@ static int __devexit wl1271_remove(struct spi_device *spi) { struct wl1271 *wl = dev_get_drvdata(&spi->dev); - free_irq(wl->irq, wl); - wl1271_unregister_hw(wl); + free_irq(wl->irq, wl); wl1271_free_hw(wl); return 0; -- cgit v1.2.3 From 18c311b71899803de91f1ed41b9d87eb81017a91 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Tue, 17 Aug 2010 04:09:34 +0200 Subject: wl1271: Remove function cmd_read_memory The function is not used anywhere. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271_cmd.c | 35 ------------------------------ drivers/net/wireless/wl12xx/wl1271_cmd.h | 37 -------------------------------- 2 files changed, 72 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index a516035350d5..42e7d2f236c4 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -421,41 +421,6 @@ out: return ret; } -int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer, - size_t len) -{ - struct cmd_read_write_memory *cmd; - int ret = 0; - - wl1271_debug(DEBUG_CMD, "cmd read memory"); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - WARN_ON(len > MAX_READ_SIZE); - len = min_t(size_t, len, MAX_READ_SIZE); - - cmd->addr = cpu_to_le32(addr); - cmd->size = cpu_to_le32(len); - - ret = wl1271_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd), - sizeof(*cmd)); - if (ret < 0) { - wl1271_error("read memory command failed: %d", ret); - goto out; - } - - /* the read command got in */ - memcpy(answer, cmd->value, len); - -out: - kfree(cmd); - return ret; -} - int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, void *buf, size_t buf_len, int index, u32 rates) { diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.h b/drivers/net/wireless/wl12xx/wl1271_cmd.h index ce0476ceb84a..92747cece15e 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.h +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.h @@ -39,8 +39,6 @@ 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_read_memory(struct wl1271 *wl, u32 addr, void *answer, - size_t len); int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, void *buf, size_t buf_len, int index, u32 rates); int wl1271_cmd_build_null_data(struct wl1271 *wl); @@ -161,41 +159,6 @@ enum { MAX_COMMAND_STATUS = 0xff }; - -/* - * CMD_READ_MEMORY - * - * The host issues this command to read the WiLink device memory/registers. - * - * Note: The Base Band address has special handling (16 bits registers and - * addresses). For more information, see the hardware specification. - */ -/* - * CMD_WRITE_MEMORY - * - * The host issues this command to write the WiLink device memory/registers. - * - * The Base Band address has special handling (16 bits registers and - * addresses). For more information, see the hardware specification. - */ -#define MAX_READ_SIZE 256 - -struct cmd_read_write_memory { - struct wl1271_cmd_header header; - - /* The address of the memory to read from or write to.*/ - __le32 addr; - - /* The amount of data in bytes to read from or write to the WiLink - * device.*/ - __le32 size; - - /* The actual value read from or written to the Wilink. The source - of this field is the Host in WRITE command or the Wilink in READ - command. */ - u8 value[MAX_READ_SIZE]; -} __packed; - #define CMDMBOX_HEADER_LEN 4 #define CMDMBOX_INFO_ELEM_HEADER_LEN 4 -- cgit v1.2.3 From 02fabb0eafde901ae51532ad15fdd4737b7d71e3 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Thu, 19 Aug 2010 04:41:15 +0200 Subject: wl1271: Enable/disable 11a support based on INI configuration Instead of hardcoding 11a support, enable/disable driver support based on the dual-mode-select parameter in the nvs-file general paramters. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271.h | 18 +++--------------- drivers/net/wireless/wl12xx/wl1271_boot.c | 22 ++++++++++++++++++++++ drivers/net/wireless/wl12xx/wl1271_init.c | 2 +- drivers/net/wireless/wl12xx/wl1271_main.c | 18 +++--------------- drivers/net/wireless/wl12xx/wl1271_scan.c | 2 +- drivers/net/wireless/wl12xx/wl1271_testmode.c | 14 +------------- 6 files changed, 31 insertions(+), 45 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index 1098d1689b0e..763ece823c54 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -117,11 +117,6 @@ enum { #define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff)) #define WL1271_TX_SECURITY_HI32(s) ((u32)(((s) >> 16) & 0xffffffff)) -/* - * Enable/disable 802.11a support for WL1273 - */ -#undef WL1271_80211A_ENABLED - #define WL1271_BUSY_WORD_CNT 1 #define WL1271_BUSY_WORD_LEN (WL1271_BUSY_WORD_CNT * sizeof(u32)) @@ -363,6 +358,7 @@ struct wl1271 { u8 *fw; size_t fw_len; struct wl1271_nvs_file *nvs; + size_t nvs_len; s8 hw_pg_ver; @@ -476,6 +472,8 @@ struct wl1271 { bool sg_enabled; + bool enable_11a; + struct list_head list; /* Most recently reported noise in dBm */ @@ -499,14 +497,4 @@ int wl1271_plt_stop(struct wl1271 *wl); #define WL1271_PRE_POWER_ON_SLEEP 20 /* in miliseconds */ #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 - return false; -#endif -} - #endif diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.c b/drivers/net/wireless/wl12xx/wl1271_boot.c index f750d5a79089..b91021242098 100644 --- a/drivers/net/wireless/wl12xx/wl1271_boot.c +++ b/drivers/net/wireless/wl12xx/wl1271_boot.c @@ -225,6 +225,28 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) if (wl->nvs == NULL) return -ENODEV; + /* + * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz band + * configurations) can be removed when those NVS files stop floating + * around. + */ + if (wl->nvs_len == sizeof(struct wl1271_nvs_file) || + wl->nvs_len == WL1271_INI_LEGACY_NVS_FILE_SIZE) { + if (wl->nvs->general_params.dual_mode_select) + wl->enable_11a = true; + } + + if (wl->nvs_len != sizeof(struct wl1271_nvs_file) && + (wl->nvs_len != WL1271_INI_LEGACY_NVS_FILE_SIZE || + wl->enable_11a)) { + wl1271_error("nvs size is not as expected: %zu != %zu", + wl->nvs_len, sizeof(struct wl1271_nvs_file)); + kfree(wl->nvs); + wl->nvs = NULL; + wl->nvs_len = 0; + return -EILSEQ; + } + /* only the first part of the NVS needs to be uploaded */ nvs_len = sizeof(wl->nvs->nvs); nvs_ptr = (u8 *)wl->nvs->nvs; diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c index 4447af1557f5..879bae095a63 100644 --- a/drivers/net/wireless/wl12xx/wl1271_init.c +++ b/drivers/net/wireless/wl12xx/wl1271_init.c @@ -61,7 +61,7 @@ int wl1271_init_templates_config(struct wl1271 *wl) if (ret < 0) return ret; - if (wl1271_11a_enabled()) { + if (wl->enable_11a) { size_t size = sizeof(struct wl12xx_probe_req_template); ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5, NULL, size, 0, diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index bbd075a88f2d..11e112ff79d6 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -622,20 +622,6 @@ static int wl1271_fetch_nvs(struct wl1271 *wl) return ret; } - /* - * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz band - * configurations) can be removed when those NVS files stop floating - * around. - */ - if (fw->size != sizeof(struct wl1271_nvs_file) && - (fw->size != WL1271_INI_LEGACY_NVS_FILE_SIZE || - wl1271_11a_enabled())) { - wl1271_error("nvs size is not as expected: %zu != %zu", - fw->size, sizeof(struct wl1271_nvs_file)); - ret = -EILSEQ; - goto out; - } - wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL); if (!wl->nvs) { @@ -644,6 +630,8 @@ static int wl1271_fetch_nvs(struct wl1271 *wl) goto out; } + wl->nvs_len = fw->size; + out: release_firmware(fw); @@ -2414,7 +2402,7 @@ int wl1271_init_ieee80211(struct wl1271 *wl) wl->hw->wiphy->max_scan_ssids = 1; wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz; - if (wl1271_11a_enabled()) + if (wl->enable_11a) wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz; wl->hw->queues = 4; diff --git a/drivers/net/wireless/wl12xx/wl1271_scan.c b/drivers/net/wireless/wl12xx/wl1271_scan.c index 7f42ca9abab8..8d30150f3f46 100644 --- a/drivers/net/wireless/wl12xx/wl1271_scan.c +++ b/drivers/net/wireless/wl12xx/wl1271_scan.c @@ -188,7 +188,7 @@ void wl1271_scan_stm(struct wl1271 *wl) ret = wl1271_scan_send(wl, IEEE80211_BAND_2GHZ, true, wl->conf.tx.basic_rate); if (ret == WL1271_NOTHING_TO_SCAN) { - if (wl1271_11a_enabled()) + if (wl->enable_11a) wl->scan.state = WL1271_SCAN_STATE_5GHZ_ACTIVE; else wl->scan.state = WL1271_SCAN_STATE_DONE; diff --git a/drivers/net/wireless/wl12xx/wl1271_testmode.c b/drivers/net/wireless/wl12xx/wl1271_testmode.c index 6e0952f79e9a..a3aa84386c88 100644 --- a/drivers/net/wireless/wl12xx/wl1271_testmode.c +++ b/drivers/net/wireless/wl12xx/wl1271_testmode.c @@ -199,19 +199,6 @@ static int wl1271_tm_cmd_nvs_push(struct wl1271 *wl, struct nlattr *tb[]) buf = nla_data(tb[WL1271_TM_ATTR_DATA]); len = nla_len(tb[WL1271_TM_ATTR_DATA]); - /* - * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz band - * configurations) can be removed when those NVS files stop floating - * around. - */ - if (len != sizeof(struct wl1271_nvs_file) && - (len != WL1271_INI_LEGACY_NVS_FILE_SIZE || - wl1271_11a_enabled())) { - 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); @@ -224,6 +211,7 @@ static int wl1271_tm_cmd_nvs_push(struct wl1271 *wl, struct nlattr *tb[]) } memcpy(wl->nvs, buf, len); + wl->nvs_len = len; wl1271_debug(DEBUG_TESTMODE, "testmode pushed nvs"); -- cgit v1.2.3 From 65cddbf1353212f8ab00c6084e3063d85c419201 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Tue, 24 Aug 2010 06:28:03 +0300 Subject: wl1271: Reduce rate used for last PSM entry attempt This patch reduces the rate of the null-func used to enter PSM on the last retry as precaution. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271_cmd.c | 4 ++-- drivers/net/wireless/wl12xx/wl1271_cmd.h | 4 +++- drivers/net/wireless/wl12xx/wl1271_event.c | 17 ++++++++++++----- drivers/net/wireless/wl12xx/wl1271_main.c | 8 +++++--- drivers/net/wireless/wl12xx/wl1271_ps.c | 8 +++++--- drivers/net/wireless/wl12xx/wl1271_ps.h | 2 +- 6 files changed, 28 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index 42e7d2f236c4..06b14f2abf55 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -390,7 +390,7 @@ out: 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, u32 rates, bool send) { struct wl1271_cmd_ps_params *ps_params = NULL; int ret = 0; @@ -407,7 +407,7 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, bool send) ps_params->send_null_data = send; ps_params->retries = 5; ps_params->hang_over_period = 1; - ps_params->null_data_rate = cpu_to_le32(wl->basic_rate_set); + ps_params->null_data_rate = cpu_to_le32(rates); ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params, sizeof(*ps_params), 0); diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.h b/drivers/net/wireless/wl12xx/wl1271_cmd.h index 92747cece15e..ff8e35e87d98 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.h +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.h @@ -38,7 +38,9 @@ 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_ps_mode(struct wl1271 *wl, u8 ps_mode, u32 rates, bool send); +int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer, + size_t len); int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, void *buf, size_t buf_len, int index, u32 rates); int wl1271_cmd_build_null_data(struct wl1271 *wl); diff --git a/drivers/net/wireless/wl12xx/wl1271_event.c b/drivers/net/wireless/wl12xx/wl1271_event.c index 25ce2cd5e3f3..bced8296a251 100644 --- a/drivers/net/wireless/wl12xx/wl1271_event.c +++ b/drivers/net/wireless/wl12xx/wl1271_event.c @@ -52,7 +52,7 @@ void wl1271_pspoll_work(struct work_struct *work) * delivery failure occurred, and no-one changed state since, so * we should go back to powersave. */ - wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, true); + wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, wl->basic_rate, true); out: mutex_unlock(&wl->mutex); @@ -70,7 +70,8 @@ static void wl1271_event_pspoll_delivery_fail(struct wl1271 *wl) /* force active mode receive data from the AP */ if (test_bit(WL1271_FLAG_PSM, &wl->flags)) { - ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE, true); + ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE, + wl->basic_rate, true); if (ret < 0) return; set_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags); @@ -91,6 +92,8 @@ static int wl1271_event_ps_report(struct wl1271 *wl, bool *beacon_loss) { int ret = 0; + u32 total_retries = wl->conf.conn.psm_entry_retries; + u32 rates; wl1271_debug(DEBUG_EVENT, "ps_status: 0x%x", mbox->ps_status); @@ -104,10 +107,14 @@ static int wl1271_event_ps_report(struct wl1271 *wl, break; } - if (wl->psm_entry_retry < wl->conf.conn.psm_entry_retries) { + if (wl->psm_entry_retry < total_retries) { wl->psm_entry_retry++; + if (wl->psm_entry_retry == total_retries) + rates = wl->basic_rate; + else + rates = wl->basic_rate_set; ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, - true); + rates, true); } else { wl1271_info("No ack to nullfunc from AP."); wl->psm_entry_retry = 0; @@ -143,7 +150,7 @@ static int wl1271_event_ps_report(struct wl1271 *wl, /* 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); + wl->basic_rate, false); break; case EVENT_EXIT_POWER_SAVE_SUCCESS: default: diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 11e112ff79d6..81f92a0100d9 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -1341,7 +1341,7 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) { wl1271_debug(DEBUG_PSM, "psm enabled"); ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, - true); + wl->basic_rate_set, true); } } else if (!(conf->flags & IEEE80211_CONF_PS) && test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) { @@ -1351,7 +1351,7 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) if (test_bit(WL1271_FLAG_PSM, &wl->flags)) ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE, - true); + wl->basic_rate_set, true); } if (conf->power_level != wl->power_level) { @@ -1826,7 +1826,9 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) && !test_bit(WL1271_FLAG_PSM, &wl->flags)) { mode = STATION_POWER_SAVE_MODE; - ret = wl1271_ps_set_mode(wl, mode, true); + ret = wl1271_ps_set_mode(wl, mode, + wl->basic_rate_set, + true); if (ret < 0) goto out_sleep; } diff --git a/drivers/net/wireless/wl12xx/wl1271_ps.c b/drivers/net/wireless/wl12xx/wl1271_ps.c index 52a60959bb9c..f75668e413fd 100644 --- a/drivers/net/wireless/wl12xx/wl1271_ps.c +++ b/drivers/net/wireless/wl12xx/wl1271_ps.c @@ -121,7 +121,7 @@ out: } int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode, - bool send) + u32 rates, bool send) { int ret; @@ -135,7 +135,8 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode, return ret; } - ret = wl1271_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE, send); + ret = wl1271_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE, + rates, send); if (ret < 0) return ret; @@ -158,7 +159,8 @@ 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, + rates, send); if (ret < 0) return ret; diff --git a/drivers/net/wireless/wl12xx/wl1271_ps.h b/drivers/net/wireless/wl12xx/wl1271_ps.h index 940276f517a4..6ba7b032736f 100644 --- a/drivers/net/wireless/wl12xx/wl1271_ps.h +++ b/drivers/net/wireless/wl12xx/wl1271_ps.h @@ -28,7 +28,7 @@ #include "wl1271_acx.h" int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode, - bool send); + u32 rates, bool send); 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); -- cgit v1.2.3 From 11eb54298fa7197cb4187f8a3474ead0709f76ff Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Tue, 24 Aug 2010 06:28:03 +0300 Subject: wl1271: Enable 11a support always, prevent scanning for unsupporting chips This patch always enables 11a band towards the mac80211, but prevents scanning (and hence the usage of) 11a band channels if the chipset does not support it. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271_init.c | 15 +++++++-------- drivers/net/wireless/wl12xx/wl1271_main.c | 4 +--- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c index 879bae095a63..5614a352528b 100644 --- a/drivers/net/wireless/wl12xx/wl1271_init.c +++ b/drivers/net/wireless/wl12xx/wl1271_init.c @@ -53,6 +53,7 @@ static int wl1271_init_hwenc_config(struct wl1271 *wl) int wl1271_init_templates_config(struct wl1271 *wl) { int ret, i; + size_t size; /* send empty templates for fw memory reservation */ ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL, @@ -61,14 +62,12 @@ int wl1271_init_templates_config(struct wl1271 *wl) if (ret < 0) return ret; - if (wl->enable_11a) { - size_t size = sizeof(struct wl12xx_probe_req_template); - ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5, - NULL, size, 0, - WL1271_RATE_AUTOMATIC); - if (ret < 0) - return ret; - } + size = sizeof(struct wl12xx_probe_req_template); + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5, + NULL, size, 0, + WL1271_RATE_AUTOMATIC); + if (ret < 0) + return ret; ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, NULL, sizeof(struct wl12xx_null_data_template), diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 81f92a0100d9..f0c253213cd8 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -2403,9 +2403,7 @@ int wl1271_init_ieee80211(struct wl1271 *wl) BIT(NL80211_IFTYPE_ADHOC); wl->hw->wiphy->max_scan_ssids = 1; wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz; - - if (wl->enable_11a) - wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz; + wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz; wl->hw->queues = 4; wl->hw->max_rates = 1; -- cgit v1.2.3 From ed484a16b495ee7e13cb28fd6ff6053d10657633 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Wed, 1 Sep 2010 11:31:11 +0200 Subject: wl1271: Fix tid-configuration of TX frames Incorrect TID was configured for TX frames. This resulted in incorrect queues to be used for classes in transmission. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271_tx.c | 4 ++-- drivers/net/wireless/wl12xx/wl1271_tx.h | 17 ----------------- 2 files changed, 2 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c index 0f99eff3b7ef..1b8295c5dde4 100644 --- a/drivers/net/wireless/wl12xx/wl1271_tx.c +++ b/drivers/net/wireless/wl12xx/wl1271_tx.c @@ -110,9 +110,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 */ + /* queue (we use same identifiers for tid's and ac's */ ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); - desc->tid = wl1271_tx_ac_to_tid(ac); + desc->tid = ac; desc->aid = TX_HW_DEFAULT_AID; desc->reserved = 0; diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.h b/drivers/net/wireless/wl12xx/wl1271_tx.h index 48bf92621c03..d12a129ad11c 100644 --- a/drivers/net/wireless/wl12xx/wl1271_tx.h +++ b/drivers/net/wireless/wl12xx/wl1271_tx.h @@ -139,23 +139,6 @@ static inline int wl1271_tx_get_queue(int queue) } } -/* 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); void wl1271_tx_reset(struct wl1271 *wl); -- cgit v1.2.3 From 9987a9da3eda093ceeff14ad4926adb130a0d0ea Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Wed, 1 Sep 2010 11:31:12 +0200 Subject: wl1271: Fix AC/TID default configuration The WMM queue default configuration was incorrect, and caused uapsd mode problems (among possible others.) Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271_conf.h | 2 +- drivers/net/wireless/wl12xx/wl1271_init.c | 20 ++++---- drivers/net/wireless/wl12xx/wl1271_main.c | 84 +++++++++++-------------------- 3 files changed, 39 insertions(+), 67 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_conf.h b/drivers/net/wireless/wl12xx/wl1271_conf.h index 0435ffda8f73..feb493ebe5bd 100644 --- a/drivers/net/wireless/wl12xx/wl1271_conf.h +++ b/drivers/net/wireless/wl12xx/wl1271_conf.h @@ -595,7 +595,7 @@ struct conf_tx_ac_category { u16 tx_op_limit; }; -#define CONF_TX_MAX_TID_COUNT 7 +#define CONF_TX_MAX_TID_COUNT 8 enum { CONF_CHANNEL_TYPE_DCF = 0, /* DC/LEGACY*/ diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c index 5614a352528b..349571fe04b3 100644 --- a/drivers/net/wireless/wl12xx/wl1271_init.c +++ b/drivers/net/wireless/wl12xx/wl1271_init.c @@ -290,8 +290,16 @@ int wl1271_hw_init(struct wl1271 *wl) if (ret < 0) goto out_free_memmap; - /* Default TID configuration */ + /* Default TID/AC configuration */ + BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count); for (i = 0; i < wl->conf.tx.tid_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; + conf_tid = &wl->conf.tx.tid_conf[i]; ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id, conf_tid->channel_type, @@ -304,16 +312,6 @@ int wl1271_hw_init(struct wl1271 *wl) 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; - } - /* Configure TX rate classes */ ret = wl1271_acx_rate_policies(wl); if (ret < 0) diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index f0c253213cd8..4b8f3662101f 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -124,28 +124,28 @@ static struct conf_drv_settings default_conf = { }, .ac_conf_count = 4, .ac_conf = { - [0] = { + [CONF_TX_AC_BE] = { .ac = CONF_TX_AC_BE, .cw_min = 15, .cw_max = 63, .aifsn = 3, .tx_op_limit = 0, }, - [1] = { + [CONF_TX_AC_BK] = { .ac = CONF_TX_AC_BK, .cw_min = 15, .cw_max = 63, .aifsn = 7, .tx_op_limit = 0, }, - [2] = { + [CONF_TX_AC_VI] = { .ac = CONF_TX_AC_VI, .cw_min = 15, .cw_max = 63, .aifsn = CONF_TX_AIFS_PIFS, .tx_op_limit = 3008, }, - [3] = { + [CONF_TX_AC_VO] = { .ac = CONF_TX_AC_VO, .cw_min = 15, .cw_max = 63, @@ -153,64 +153,40 @@ static struct conf_drv_settings default_conf = { .tx_op_limit = 1504, }, }, - .tid_conf_count = 7, + .tid_conf_count = 4, .tid_conf = { - [0] = { - .queue_id = 0, - .channel_type = CONF_CHANNEL_TYPE_DCF, - .tsid = CONF_TX_AC_BE, - .ps_scheme = CONF_PS_SCHEME_LEGACY, - .ack_policy = CONF_ACK_POLICY_LEGACY, - .apsd_conf = {0, 0}, - }, - [1] = { - .queue_id = 1, - .channel_type = CONF_CHANNEL_TYPE_DCF, - .tsid = CONF_TX_AC_BE, - .ps_scheme = CONF_PS_SCHEME_LEGACY, - .ack_policy = CONF_ACK_POLICY_LEGACY, - .apsd_conf = {0, 0}, - }, - [2] = { - .queue_id = 2, - .channel_type = CONF_CHANNEL_TYPE_DCF, + [CONF_TX_AC_BE] = { + .queue_id = CONF_TX_AC_BE, + .channel_type = CONF_CHANNEL_TYPE_EDCF, .tsid = CONF_TX_AC_BE, .ps_scheme = CONF_PS_SCHEME_LEGACY, .ack_policy = CONF_ACK_POLICY_LEGACY, .apsd_conf = {0, 0}, }, - [3] = { - .queue_id = 3, - .channel_type = CONF_CHANNEL_TYPE_DCF, - .tsid = CONF_TX_AC_BE, + [CONF_TX_AC_BK] = { + .queue_id = CONF_TX_AC_BK, + .channel_type = CONF_CHANNEL_TYPE_EDCF, + .tsid = CONF_TX_AC_BK, .ps_scheme = CONF_PS_SCHEME_LEGACY, .ack_policy = CONF_ACK_POLICY_LEGACY, .apsd_conf = {0, 0}, }, - [4] = { - .queue_id = 4, - .channel_type = CONF_CHANNEL_TYPE_DCF, - .tsid = CONF_TX_AC_BE, + [CONF_TX_AC_VI] = { + .queue_id = CONF_TX_AC_VI, + .channel_type = CONF_CHANNEL_TYPE_EDCF, + .tsid = CONF_TX_AC_VI, .ps_scheme = CONF_PS_SCHEME_LEGACY, .ack_policy = CONF_ACK_POLICY_LEGACY, .apsd_conf = {0, 0}, }, - [5] = { - .queue_id = 5, - .channel_type = CONF_CHANNEL_TYPE_DCF, - .tsid = CONF_TX_AC_BE, + [CONF_TX_AC_VO] = { + .queue_id = CONF_TX_AC_VO, + .channel_type = CONF_CHANNEL_TYPE_EDCF, + .tsid = CONF_TX_AC_VO, .ps_scheme = CONF_PS_SCHEME_LEGACY, .ack_policy = CONF_ACK_POLICY_LEGACY, .apsd_conf = {0, 0}, }, - [6] = { - .queue_id = 6, - .channel_type = CONF_CHANNEL_TYPE_DCF, - .tsid = CONF_TX_AC_BE, - .ps_scheme = CONF_PS_SCHEME_LEGACY, - .ack_policy = CONF_ACK_POLICY_LEGACY, - .apsd_conf = {0, 0}, - } }, .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD, .tx_compl_timeout = 700, @@ -406,8 +382,16 @@ static int wl1271_plt_init(struct wl1271 *wl) if (ret < 0) goto out_free_memmap; - /* Default TID configuration */ + /* Default TID/AC configuration */ + BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count); for (i = 0; i < wl->conf.tx.tid_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; + conf_tid = &wl->conf.tx.tid_conf[i]; ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id, conf_tid->channel_type, @@ -420,16 +404,6 @@ static int wl1271_plt_init(struct wl1271 *wl) 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); if (ret < 0) -- cgit v1.2.3 From c454f1d9a896d3519c756355b37bb39941093233 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Tue, 24 Aug 2010 06:28:03 +0300 Subject: wl1271: Move scan complete invocation into work function The current scan implementation can jam, if the scan request ends up containing no work. This can especially happen if there is a scan request with only 11a band channels for HW that does not support 11a. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271.h | 1 + drivers/net/wireless/wl12xx/wl1271_main.c | 4 ++++ drivers/net/wireless/wl12xx/wl1271_scan.c | 23 ++++++++++++++++++----- drivers/net/wireless/wl12xx/wl1271_scan.h | 1 + 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index 763ece823c54..272cff44ab53 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -416,6 +416,7 @@ struct wl1271 { /* Are we currently scanning */ struct wl1271_scan scan; + struct work_struct scan_complete_work; /* Our association ID */ u16 aid; diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 4b8f3662101f..0026e775bb0d 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -634,6 +634,8 @@ static int wl1271_setup(struct wl1271 *wl) INIT_WORK(&wl->irq_work, wl1271_irq_work); INIT_WORK(&wl->tx_work, wl1271_tx_work); + INIT_WORK(&wl->scan_complete_work, wl1271_scan_complete_work); + return 0; } @@ -962,6 +964,8 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw, struct wl1271 *wl = hw->priv; int i; + cancel_work_sync(&wl->scan_complete_work); + mutex_lock(&wl->mutex); wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface"); diff --git a/drivers/net/wireless/wl12xx/wl1271_scan.c b/drivers/net/wireless/wl12xx/wl1271_scan.c index 8d30150f3f46..9f1da82ed8d6 100644 --- a/drivers/net/wireless/wl12xx/wl1271_scan.c +++ b/drivers/net/wireless/wl12xx/wl1271_scan.c @@ -28,6 +28,23 @@ #include "wl1271_scan.h" #include "wl1271_acx.h" +void wl1271_scan_complete_work(struct work_struct *work) +{ + struct wl1271 *wl = + container_of(work, struct wl1271, scan_complete_work); + + wl1271_debug(DEBUG_SCAN, "Scanning complete"); + + mutex_lock(&wl->mutex); + wl->scan.state = WL1271_SCAN_STATE_IDLE; + kfree(wl->scan.scanned_ch); + wl->scan.scanned_ch = NULL; + mutex_unlock(&wl->mutex); + + ieee80211_scan_completed(wl->hw, false); +} + + static int wl1271_get_scan_channels(struct wl1271 *wl, struct cfg80211_scan_request *req, struct basic_scan_channel_params *channels, @@ -218,11 +235,7 @@ void wl1271_scan_stm(struct wl1271 *wl) break; case WL1271_SCAN_STATE_DONE: - kfree(wl->scan.scanned_ch); - wl->scan.scanned_ch = NULL; - - wl->scan.state = WL1271_SCAN_STATE_IDLE; - ieee80211_scan_completed(wl->hw, false); + ieee80211_queue_work(wl->hw, &wl->scan_complete_work); break; default: diff --git a/drivers/net/wireless/wl12xx/wl1271_scan.h b/drivers/net/wireless/wl12xx/wl1271_scan.h index f1815700f5f9..1404e00dc963 100644 --- a/drivers/net/wireless/wl12xx/wl1271_scan.h +++ b/drivers/net/wireless/wl12xx/wl1271_scan.h @@ -32,6 +32,7 @@ int wl1271_scan_build_probe_req(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, const u8 *ie, size_t ie_len, u8 band); void wl1271_scan_stm(struct wl1271 *wl); +void wl1271_scan_complete_work(struct work_struct *work); #define WL1271_SCAN_MAX_CHANNELS 24 #define WL1271_SCAN_DEFAULT_TAG 1 -- cgit v1.2.3 From 8c7f4f3166e16bb350bfc53955ea6cf9bfd34aab Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Tue, 21 Sep 2010 06:23:29 +0200 Subject: wl1271: Fix work cancelling when shutting down the driver The work cancelling has had several hazards, ranging from potentially executing work after the driver is in OFF state, to executing work after the driver and relevant memory structures are already removed. Fix these. Signed-off-by: Juuso Oikarinen Reviewed-by: Teemu Paasikivi Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271_event.c | 3 +++ drivers/net/wireless/wl12xx/wl1271_main.c | 3 +++ drivers/net/wireless/wl12xx/wl1271_ps.c | 3 +++ 3 files changed, 9 insertions(+) diff --git a/drivers/net/wireless/wl12xx/wl1271_event.c b/drivers/net/wireless/wl12xx/wl1271_event.c index bced8296a251..e6c839af9038 100644 --- a/drivers/net/wireless/wl12xx/wl1271_event.c +++ b/drivers/net/wireless/wl12xx/wl1271_event.c @@ -41,6 +41,9 @@ void wl1271_pspoll_work(struct work_struct *work) mutex_lock(&wl->mutex); + if (unlikely(wl->state == WL1271_STATE_OFF)) + goto out; + if (!test_and_clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags)) goto out; diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 0026e775bb0d..9ab4fc4f7b4b 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -792,6 +792,8 @@ int wl1271_plt_stop(struct wl1271 *wl) out: mutex_unlock(&wl->mutex); + cancel_work_sync(&wl->irq_work); + return ret; } @@ -995,6 +997,7 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw, cancel_work_sync(&wl->irq_work); cancel_work_sync(&wl->tx_work); cancel_delayed_work_sync(&wl->pspoll_work); + cancel_delayed_work_sync(&wl->elp_work); mutex_lock(&wl->mutex); diff --git a/drivers/net/wireless/wl12xx/wl1271_ps.c b/drivers/net/wireless/wl12xx/wl1271_ps.c index f75668e413fd..150dc674d8b4 100644 --- a/drivers/net/wireless/wl12xx/wl1271_ps.c +++ b/drivers/net/wireless/wl12xx/wl1271_ps.c @@ -39,6 +39,9 @@ void wl1271_elp_work(struct work_struct *work) mutex_lock(&wl->mutex); + if (unlikely(wl->state == WL1271_STATE_OFF)) + goto out; + if (test_bit(WL1271_FLAG_IN_ELP, &wl->flags) || (!test_bit(WL1271_FLAG_PSM, &wl->flags) && !test_bit(WL1271_FLAG_IDLE, &wl->flags))) -- cgit v1.2.3 From 52a2a37550b604b3c3c7a044ff72d85b60165659 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Tue, 21 Sep 2010 06:23:30 +0200 Subject: wl1271: Separate interface removal to another function Do this so the interface removal can be triggered from an upcoming hardware failure recovery mechanism. Signed-off-by: Juuso Oikarinen Reviewed-by: Teemu Paasikivi Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271_main.c | 17 +++++++++++------ drivers/net/wireless/wl12xx/wl1271_scan.c | 6 ++++++ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 9ab4fc4f7b4b..e7f096fb6212 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -960,15 +960,10 @@ out: return ret; } -static void wl1271_op_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) +static void __wl1271_op_remove_interface(struct wl1271 *wl) { - struct wl1271 *wl = hw->priv; int i; - cancel_work_sync(&wl->scan_complete_work); - - mutex_lock(&wl->mutex); wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface"); wl1271_info("down"); @@ -994,6 +989,7 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw, mutex_unlock(&wl->mutex); + cancel_work_sync(&wl->scan_complete_work); cancel_work_sync(&wl->irq_work); cancel_work_sync(&wl->tx_work); cancel_delayed_work_sync(&wl->pspoll_work); @@ -1039,7 +1035,16 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw, wl->tx_res_if = NULL; kfree(wl->target_mem_map); wl->target_mem_map = NULL; +} +static void wl1271_op_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct wl1271 *wl = hw->priv; + + mutex_lock(&wl->mutex); + WARN_ON(wl->vif != vif); + __wl1271_op_remove_interface(wl); mutex_unlock(&wl->mutex); } diff --git a/drivers/net/wireless/wl12xx/wl1271_scan.c b/drivers/net/wireless/wl12xx/wl1271_scan.c index 9f1da82ed8d6..20caceba435e 100644 --- a/drivers/net/wireless/wl12xx/wl1271_scan.c +++ b/drivers/net/wireless/wl12xx/wl1271_scan.c @@ -36,6 +36,12 @@ void wl1271_scan_complete_work(struct work_struct *work) wl1271_debug(DEBUG_SCAN, "Scanning complete"); mutex_lock(&wl->mutex); + + if (wl->scan.state == WL1271_SCAN_STATE_IDLE) { + mutex_unlock(&wl->mutex); + return; + } + wl->scan.state = WL1271_SCAN_STATE_IDLE; kfree(wl->scan.scanned_ch); wl->scan.scanned_ch = NULL; -- cgit v1.2.3 From 52b0e7a61fd4b67fe8efe295297d8549f052f786 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Tue, 21 Sep 2010 06:23:31 +0200 Subject: wl1271: Add hardware recovery mechanism There is some probability of hardware failures, which currently go largely undetected. Attempt to recover from these failures by shutting down the hardware, and requesting mac80211 to reconfigure it. Signed-off-by: Juuso Oikarinen Reviewed-by: Teemu Paasikivi Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271.h | 3 +++ drivers/net/wireless/wl12xx/wl1271_cmd.c | 5 ++++- drivers/net/wireless/wl12xx/wl1271_main.c | 28 +++++++++++++++++++++++++++- drivers/net/wireless/wl12xx/wl1271_ps.c | 3 ++- 4 files changed, 36 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index 272cff44ab53..3576c1cb067f 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -408,6 +408,9 @@ struct wl1271 { /* The target interrupt mask */ struct work_struct irq_work; + /* Hardware recovery work */ + struct work_struct recovery_work; + /* The mbox event mask */ u32 event_mask; diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index 06b14f2abf55..170b5a8bdabc 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -94,6 +94,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, status = le16_to_cpu(cmd->status); if (status != CMD_STATUS_SUCCESS) { wl1271_error("command execute failure %d", status); + ieee80211_queue_work(wl->hw, &wl->recovery_work); ret = -EIO; } @@ -182,8 +183,10 @@ static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask) timeout = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT); do { - if (time_after(jiffies, timeout)) + if (time_after(jiffies, timeout)) { + ieee80211_queue_work(wl->hw, &wl->recovery_work); return -ETIMEDOUT; + } msleep(1); diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index e7f096fb6212..fecb0c313a1d 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -235,6 +235,9 @@ static struct conf_drv_settings default_conf = { } }; +static void __wl1271_op_remove_interface(struct wl1271 *wl); + + static void wl1271_device_release(struct device *dev) { @@ -612,6 +615,26 @@ out: return ret; } +static void wl1271_recovery_work(struct work_struct *work) +{ + struct wl1271 *wl = + container_of(work, struct wl1271, recovery_work); + + mutex_lock(&wl->mutex); + + if (wl->state != WL1271_STATE_ON) + goto out; + + wl1271_info("Hardware recovery in progress."); + + /* reboot the chipset */ + __wl1271_op_remove_interface(wl); + ieee80211_restart_hw(wl->hw); + +out: + mutex_unlock(&wl->mutex); +} + static void wl1271_fw_wakeup(struct wl1271 *wl) { u32 elp_reg; @@ -635,6 +658,7 @@ static int wl1271_setup(struct wl1271 *wl) INIT_WORK(&wl->irq_work, wl1271_irq_work); INIT_WORK(&wl->tx_work, wl1271_tx_work); INIT_WORK(&wl->scan_complete_work, wl1271_scan_complete_work); + INIT_WORK(&wl->recovery_work, wl1271_recovery_work); return 0; } @@ -793,11 +817,11 @@ out: mutex_unlock(&wl->mutex); cancel_work_sync(&wl->irq_work); + cancel_work_sync(&wl->recovery_work); return ret; } - static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct wl1271 *wl = hw->priv; @@ -1046,6 +1070,8 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw, WARN_ON(wl->vif != vif); __wl1271_op_remove_interface(wl); mutex_unlock(&wl->mutex); + + cancel_work_sync(&wl->recovery_work); } static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters) diff --git a/drivers/net/wireless/wl12xx/wl1271_ps.c b/drivers/net/wireless/wl12xx/wl1271_ps.c index 150dc674d8b4..e3c332e2f97c 100644 --- a/drivers/net/wireless/wl12xx/wl1271_ps.c +++ b/drivers/net/wireless/wl12xx/wl1271_ps.c @@ -64,7 +64,7 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl) test_bit(WL1271_FLAG_IDLE, &wl->flags)) { cancel_delayed_work(&wl->elp_work); ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, - msecs_to_jiffies(ELP_ENTRY_DELAY)); + msecs_to_jiffies(ELP_ENTRY_DELAY)); } } @@ -99,6 +99,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake) &compl, msecs_to_jiffies(WL1271_WAKEUP_TIMEOUT)); if (ret == 0) { wl1271_error("ELP wakeup timeout!"); + ieee80211_queue_work(wl->hw, &wl->recovery_work); ret = -ETIMEDOUT; goto err; } else if (ret < 0) { -- cgit v1.2.3 From 78abd3207438b20e099b41cbed58d640cbd237a6 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Tue, 21 Sep 2010 06:23:32 +0200 Subject: wl1271: Add handling for failing hardware scan command Currently, the driver does not handle a failing hardware command to scan in any way - effectively, the scan machine will jam until the driver is shut down, and future scan requests will just return -EBUSY to user space, resulting in a type of busy-loop. The same problem occurs if the firmware fails to deliver the scan completion event - add timeout for this. Signed-off-by: Juuso Oikarinen Reviewed-by: Teemu Paasikivi Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271.h | 3 ++- drivers/net/wireless/wl12xx/wl1271_main.c | 4 ++-- drivers/net/wireless/wl12xx/wl1271_scan.c | 30 ++++++++++++++++++++++++++---- drivers/net/wireless/wl12xx/wl1271_scan.h | 2 ++ 4 files changed, 32 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index 3576c1cb067f..cae489300e06 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -296,6 +296,7 @@ struct wl1271_rx_mem_pool_addr { struct wl1271_scan { struct cfg80211_scan_request *req; bool *scanned_ch; + bool failed; u8 state; u8 ssid[IW_ESSID_MAX_SIZE+1]; size_t ssid_len; @@ -419,7 +420,7 @@ struct wl1271 { /* Are we currently scanning */ struct wl1271_scan scan; - struct work_struct scan_complete_work; + struct delayed_work scan_complete_work; /* Our association ID */ u16 aid; diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index fecb0c313a1d..c13175892960 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -657,8 +657,8 @@ static int wl1271_setup(struct wl1271 *wl) INIT_WORK(&wl->irq_work, wl1271_irq_work); INIT_WORK(&wl->tx_work, wl1271_tx_work); - INIT_WORK(&wl->scan_complete_work, wl1271_scan_complete_work); INIT_WORK(&wl->recovery_work, wl1271_recovery_work); + INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work); return 0; } @@ -1013,7 +1013,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl) mutex_unlock(&wl->mutex); - cancel_work_sync(&wl->scan_complete_work); + cancel_delayed_work_sync(&wl->scan_complete_work); cancel_work_sync(&wl->irq_work); cancel_work_sync(&wl->tx_work); cancel_delayed_work_sync(&wl->pspoll_work); diff --git a/drivers/net/wireless/wl12xx/wl1271_scan.c b/drivers/net/wireless/wl12xx/wl1271_scan.c index 20caceba435e..37f9ccbe738f 100644 --- a/drivers/net/wireless/wl12xx/wl1271_scan.c +++ b/drivers/net/wireless/wl12xx/wl1271_scan.c @@ -30,8 +30,11 @@ void wl1271_scan_complete_work(struct work_struct *work) { - struct wl1271 *wl = - container_of(work, struct wl1271, scan_complete_work); + struct delayed_work *dwork; + struct wl1271 *wl; + + dwork = container_of(work, struct delayed_work, work); + wl = container_of(dwork, struct wl1271, scan_complete_work); wl1271_debug(DEBUG_SCAN, "Scanning complete"); @@ -48,6 +51,11 @@ void wl1271_scan_complete_work(struct work_struct *work) mutex_unlock(&wl->mutex); ieee80211_scan_completed(wl->hw, false); + + if (wl->scan.failed) { + wl1271_info("Scan completed due to error."); + ieee80211_queue_work(wl->hw, &wl->recovery_work); + } } @@ -191,7 +199,7 @@ out: void wl1271_scan_stm(struct wl1271 *wl) { - int ret; + int ret = 0; switch (wl->scan.state) { case WL1271_SCAN_STATE_IDLE: @@ -241,13 +249,22 @@ void wl1271_scan_stm(struct wl1271 *wl) break; case WL1271_SCAN_STATE_DONE: - ieee80211_queue_work(wl->hw, &wl->scan_complete_work); + wl->scan.failed = false; + cancel_delayed_work(&wl->scan_complete_work); + ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, + msecs_to_jiffies(0)); break; default: wl1271_error("invalid scan state"); break; } + + if (ret < 0) { + cancel_delayed_work(&wl->scan_complete_work); + ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, + msecs_to_jiffies(0)); + } } int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, @@ -270,6 +287,11 @@ int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, wl->scan.scanned_ch = kzalloc(req->n_channels * sizeof(*wl->scan.scanned_ch), GFP_KERNEL); + /* we assume failure so that timeout scenarios are handled correctly */ + wl->scan.failed = true; + ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, + msecs_to_jiffies(WL1271_SCAN_TIMEOUT)); + wl1271_scan_stm(wl); return 0; diff --git a/drivers/net/wireless/wl12xx/wl1271_scan.h b/drivers/net/wireless/wl12xx/wl1271_scan.h index 1404e00dc963..bb7af2a102fa 100644 --- a/drivers/net/wireless/wl12xx/wl1271_scan.h +++ b/drivers/net/wireless/wl12xx/wl1271_scan.h @@ -46,6 +46,8 @@ void wl1271_scan_complete_work(struct work_struct *work); #define WL1271_SCAN_BAND_5_GHZ 1 #define WL1271_SCAN_PROBE_REQS 3 +#define WL1271_SCAN_TIMEOUT 10000 /* msec */ + enum { WL1271_SCAN_STATE_IDLE, WL1271_SCAN_STATE_2GHZ_ACTIVE, -- cgit v1.2.3 From bea39d6a60b62f16e904be5a520bf55714d73021 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Tue, 21 Sep 2010 08:14:31 +0200 Subject: wl1271: Optimize scan duration Currently then dwell times for each channel in scans is set to an overly long value, and excessive number of probe-requests are transmitted on each channel (for active scans.) Based on testing, comparable results can be received with smaller dwell-time, and, with fever probe-requests - in fact, reducing the number of probe-requests to 2 seems to increase the number of found results. Configure more optimal values for per channel dwell times. Comparison for the different scan configurations (in my current office environment): dwell-time 60000 3x probe-req == ~60 results 40000 3x probe-req == ~50 results 30000 3x probe-req == ~40 results dwell-time 60000 2x probe-req == ~70 results 40000 2x probe-req == ~60 results 30000 2x probe-req == ~58 results The above are results for a cumulative 3 scan run. For individual scans, the number of results drop slightly more. Signed-off-by: Juuso Oikarinen Reviewed-by: Teemu Paasikivi Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271_conf.h | 39 +++++++++++++++++++++++++++++++ drivers/net/wireless/wl12xx/wl1271_main.c | 9 ++++++- drivers/net/wireless/wl12xx/wl1271_scan.c | 18 ++++++++++---- drivers/net/wireless/wl12xx/wl1271_scan.h | 3 --- 4 files changed, 60 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_conf.h b/drivers/net/wireless/wl12xx/wl1271_conf.h index feb493ebe5bd..ab716f517553 100644 --- a/drivers/net/wireless/wl12xx/wl1271_conf.h +++ b/drivers/net/wireless/wl12xx/wl1271_conf.h @@ -1016,6 +1016,44 @@ struct conf_roam_trigger_settings { u8 avg_weight_snr_data; }; +struct conf_scan_settings { + /* + * The minimum time to wait on each channel for active scans + * + * Range: 0 - 65536 tu + */ + u16 min_dwell_time_active; + + /* + * The maximum time to wait on each channel for active scans + * + * Range: 0 - 65536 tu + */ + u16 max_dwell_time_active; + + /* + * The maximum time to wait on each channel for passive scans + * + * Range: 0 - 65536 tu + */ + u16 min_dwell_time_passive; + + /* + * The maximum time to wait on each channel for passive scans + * + * Range: 0 - 65536 tu + */ + u16 max_dwell_time_passive; + + /* + * Number of probe requests to transmit on each active scan channel + * + * Range: u8 + */ + u16 num_probe_reqs; + +}; + struct conf_drv_settings { struct conf_sg_settings sg; struct conf_rx_settings rx; @@ -1024,6 +1062,7 @@ struct conf_drv_settings { struct conf_itrim_settings itrim; struct conf_pm_config_settings pm_config; struct conf_roam_trigger_settings roam_trigger; + struct conf_scan_settings scan; }; #endif diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index c13175892960..b2f2d457f28c 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -232,7 +232,14 @@ static struct conf_drv_settings default_conf = { .avg_weight_rssi_data = 10, .avg_weight_snr_beacon = 20, .avg_weight_snr_data = 10 - } + }, + .scan = { + .min_dwell_time_active = 7500, + .max_dwell_time_active = 30000, + .min_dwell_time_passive = 30000, + .max_dwell_time_passive = 60000, + .num_probe_reqs = 2, + }, }; static void __wl1271_op_remove_interface(struct wl1271 *wl); diff --git a/drivers/net/wireless/wl12xx/wl1271_scan.c b/drivers/net/wireless/wl12xx/wl1271_scan.c index 37f9ccbe738f..5c76b79a96bf 100644 --- a/drivers/net/wireless/wl12xx/wl1271_scan.c +++ b/drivers/net/wireless/wl12xx/wl1271_scan.c @@ -64,6 +64,7 @@ static int wl1271_get_scan_channels(struct wl1271 *wl, struct basic_scan_channel_params *channels, enum ieee80211_band band, bool passive) { + struct conf_scan_settings *c = &wl->conf.scan; int i, j; u32 flags; @@ -91,10 +92,17 @@ static int wl1271_get_scan_channels(struct wl1271 *wl, wl1271_debug(DEBUG_SCAN, "beacon_found %d", req->channels[i]->beacon_found); - channels[j].min_duration = - cpu_to_le32(WL1271_SCAN_CHAN_MIN_DURATION); - channels[j].max_duration = - cpu_to_le32(WL1271_SCAN_CHAN_MAX_DURATION); + if (!passive) { + channels[j].min_duration = + cpu_to_le32(c->min_dwell_time_active); + channels[j].max_duration = + cpu_to_le32(c->max_dwell_time_active); + } else { + channels[j].min_duration = + cpu_to_le32(c->min_dwell_time_passive); + channels[j].max_duration = + cpu_to_le32(c->max_dwell_time_passive); + } channels[j].early_termination = 0; channels[j].tx_power_att = req->channels[i]->max_power; channels[j].channel = req->channels[i]->hw_value; @@ -151,7 +159,7 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band, cmd->params.rx_filter_options = cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN); - cmd->params.n_probe_reqs = WL1271_SCAN_PROBE_REQS; + cmd->params.n_probe_reqs = wl->conf.scan.num_probe_reqs; cmd->params.tx_rate = cpu_to_le32(basic_rate); cmd->params.tid_trigger = 0; cmd->params.scan_tag = WL1271_SCAN_DEFAULT_TAG; diff --git a/drivers/net/wireless/wl12xx/wl1271_scan.h b/drivers/net/wireless/wl12xx/wl1271_scan.h index bb7af2a102fa..6d57127b5e6b 100644 --- a/drivers/net/wireless/wl12xx/wl1271_scan.h +++ b/drivers/net/wireless/wl12xx/wl1271_scan.h @@ -40,11 +40,8 @@ void wl1271_scan_complete_work(struct work_struct *work); #define WL1271_SCAN_OPT_ACTIVE 0 #define WL1271_SCAN_OPT_PASSIVE 1 #define WL1271_SCAN_OPT_PRIORITY_HIGH 4 -#define WL1271_SCAN_CHAN_MIN_DURATION 30000 /* TU */ -#define WL1271_SCAN_CHAN_MAX_DURATION 60000 /* TU */ #define WL1271_SCAN_BAND_2_4_GHZ 0 #define WL1271_SCAN_BAND_5_GHZ 1 -#define WL1271_SCAN_PROBE_REQS 3 #define WL1271_SCAN_TIMEOUT 10000 /* msec */ -- cgit v1.2.3 From 8eab7b4708b5ef4701ecbe5d659f99743b77b668 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Fri, 24 Sep 2010 03:10:11 +0200 Subject: wl1271: Increase connection reliability This patch improves connection reliability by choosing the lowest basic rate for null-func frames (which increases their range, as the firmware does not do rate fall-back for null-func frames.) Also, increase the PSM entry retry-counter. Signed-off-by: Juuso Oikarinen Reviewed-by: Teemu Paasikivi Tested-by: Tuomas Katila Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271_cmd.c | 10 +++++----- drivers/net/wireless/wl12xx/wl1271_conf.h | 16 ++++++++++++++++ drivers/net/wireless/wl12xx/wl1271_event.c | 7 +------ drivers/net/wireless/wl12xx/wl1271_main.c | 10 ++++++---- 4 files changed, 28 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index 170b5a8bdabc..4a56ab05e736 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -408,8 +408,8 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, u32 rates, bool send) ps_params->ps_mode = ps_mode; ps_params->send_null_data = send; - ps_params->retries = 5; - ps_params->hang_over_period = 1; + ps_params->retries = wl->conf.conn.psm_entry_nullfunc_retries; + ps_params->hang_over_period = wl->conf.conn.psm_entry_hangover_period; ps_params->null_data_rate = cpu_to_le32(rates); ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params, @@ -484,7 +484,7 @@ int wl1271_cmd_build_null_data(struct wl1271 *wl) } ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, ptr, size, 0, - WL1271_RATE_AUTOMATIC); + wl->basic_rate); out: dev_kfree_skb(skb); @@ -507,7 +507,7 @@ int wl1271_cmd_build_klv_null_data(struct wl1271 *wl) ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV, skb->data, skb->len, CMD_TEMPL_KLV_IDX_NULL_DATA, - WL1271_RATE_AUTOMATIC); + wl->basic_rate); out: dev_kfree_skb(skb); @@ -584,7 +584,7 @@ int wl1271_build_qos_null_data(struct wl1271 *wl) return wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, &template, sizeof(template), 0, - WL1271_RATE_AUTOMATIC); + wl->basic_rate); } int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id) diff --git a/drivers/net/wireless/wl12xx/wl1271_conf.h b/drivers/net/wireless/wl12xx/wl1271_conf.h index ab716f517553..60c50d1a9835 100644 --- a/drivers/net/wireless/wl12xx/wl1271_conf.h +++ b/drivers/net/wireless/wl12xx/wl1271_conf.h @@ -911,6 +911,22 @@ struct conf_conn_settings { */ u8 psm_entry_retries; + /* + * Specifies the maximum number of times to try transmit the PSM entry + * null-func frame for each PSM entry attempt + * + * Range 0 - 255 + */ + u8 psm_entry_nullfunc_retries; + + /* + * Specifies the time to linger in active mode after successfully + * transmitting the PSM entry null-func frame. + * + * Range 0 - 255 TU's + */ + u8 psm_entry_hangover_period; + /* * * Specifies the interval of the connection keep-alive null-func diff --git a/drivers/net/wireless/wl12xx/wl1271_event.c b/drivers/net/wireless/wl12xx/wl1271_event.c index e6c839af9038..7b3f50382963 100644 --- a/drivers/net/wireless/wl12xx/wl1271_event.c +++ b/drivers/net/wireless/wl12xx/wl1271_event.c @@ -96,7 +96,6 @@ static int wl1271_event_ps_report(struct wl1271 *wl, { int ret = 0; u32 total_retries = wl->conf.conn.psm_entry_retries; - u32 rates; wl1271_debug(DEBUG_EVENT, "ps_status: 0x%x", mbox->ps_status); @@ -112,12 +111,8 @@ static int wl1271_event_ps_report(struct wl1271 *wl, if (wl->psm_entry_retry < total_retries) { wl->psm_entry_retry++; - if (wl->psm_entry_retry == total_retries) - rates = wl->basic_rate; - else - rates = wl->basic_rate_set; ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, - rates, true); + wl->basic_rate, true); } else { wl1271_info("No ack to nullfunc from AP."); wl->psm_entry_retry = 0; diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index b2f2d457f28c..b7e9c69f3772 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -214,7 +214,9 @@ static struct conf_drv_settings default_conf = { .ps_poll_recovery_period = 700, .bet_enable = CONF_BET_MODE_ENABLE, .bet_max_consecutive = 10, - .psm_entry_retries = 3, + .psm_entry_retries = 5, + .psm_entry_nullfunc_retries = 3, + .psm_entry_hangover_period = 1, .keep_alive_interval = 55000, .max_listen_interval = 20, }, @@ -1360,7 +1362,7 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) { wl1271_debug(DEBUG_PSM, "psm enabled"); ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, - wl->basic_rate_set, true); + wl->basic_rate, true); } } else if (!(conf->flags & IEEE80211_CONF_PS) && test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) { @@ -1370,7 +1372,7 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) if (test_bit(WL1271_FLAG_PSM, &wl->flags)) ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE, - wl->basic_rate_set, true); + wl->basic_rate, true); } if (conf->power_level != wl->power_level) { @@ -1846,7 +1848,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, !test_bit(WL1271_FLAG_PSM, &wl->flags)) { mode = STATION_POWER_SAVE_MODE; ret = wl1271_ps_set_mode(wl, mode, - wl->basic_rate_set, + wl->basic_rate, true); if (ret < 0) goto out_sleep; -- cgit v1.2.3 From 7a55724e0dc24cadaeb58f8306222a7802a24ff1 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Mon, 27 Sep 2010 12:42:07 +0200 Subject: wl1271: Add support for hardware GEM cipher This patch adds support for the hardware GEM cipher suite. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271.h | 2 ++ drivers/net/wireless/wl12xx/wl1271_cmd.h | 2 +- drivers/net/wireless/wl12xx/wl1271_main.c | 16 ++++++++++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index cae489300e06..779b130fdb3e 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -117,6 +117,8 @@ enum { #define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff)) #define WL1271_TX_SECURITY_HI32(s) ((u32)(((s) >> 16) & 0xffffffff)) +#define WL1271_CIPHER_SUITE_GEM 0x00147201 + #define WL1271_BUSY_WORD_CNT 1 #define WL1271_BUSY_WORD_LEN (WL1271_BUSY_WORD_CNT * sizeof(u32)) diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.h b/drivers/net/wireless/wl12xx/wl1271_cmd.h index ff8e35e87d98..33b946b4cb07 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.h +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.h @@ -279,7 +279,7 @@ enum wl1271_cmd_key_type { KEY_WEP = 1, KEY_TKIP = 2, KEY_AES = 3, - KEY_GEM = 4 + KEY_GEM = 4, }; /* FIXME: Add description for key-types */ diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index b7e9c69f3772..cb18f22bbc5c 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -1549,6 +1549,11 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq); tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq); break; + case WL1271_CIPHER_SUITE_GEM: + key_type = KEY_GEM; + tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq); + tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq); + break; default: wl1271_error("Unknown key algo 0x%x", key_conf->cipher); @@ -2403,6 +2408,14 @@ EXPORT_SYMBOL_GPL(wl1271_unregister_hw); int wl1271_init_ieee80211(struct wl1271 *wl) { + static const u32 cipher_suites[] = { + WLAN_CIPHER_SUITE_WEP40, + WLAN_CIPHER_SUITE_WEP104, + WLAN_CIPHER_SUITE_TKIP, + WLAN_CIPHER_SUITE_CCMP, + WL1271_CIPHER_SUITE_GEM, + }; + /* The tx descriptor buffer and the TKIP space. */ wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE + sizeof(struct wl1271_tx_hw_descr); @@ -2420,6 +2433,9 @@ int wl1271_init_ieee80211(struct wl1271 *wl) IEEE80211_HW_CONNECTION_MONITOR | IEEE80211_HW_SUPPORTS_CQM_RSSI; + wl->hw->wiphy->cipher_suites = cipher_suites; + wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); + wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); wl->hw->wiphy->max_scan_ssids = 1; -- cgit v1.2.3 From 381bd10aff491216383291879b29461efb575119 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Tue, 28 Sep 2010 09:54:27 +0300 Subject: MAINTAINERS: Update git url for the wl1271 driver We are integrating wl1271 commits via a new git tree now and wl1271 development should be made on top of the new tree. Update the repository url accordingly. Cc: John W. Linville Signed-off-by: Luciano Coelho --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 6cb1c759eeaa..529bfee8c4b2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6321,7 +6321,7 @@ WL1271 WIRELESS DRIVER M: Luciano Coelho 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 +T: git git://git.kernel.org/pub/scm/linux/kernel/git/luca/wl12xx.git S: Maintained F: drivers/net/wireless/wl12xx/wl1271* F: include/linux/wl12xx.h -- cgit v1.2.3 From 1de19eccb3fe634e939cb40f30fdfda93a67fe93 Mon Sep 17 00:00:00 2001 From: Jay Sternberg Date: Tue, 14 Sep 2010 15:21:20 -0700 Subject: iwlwifi: define 100 devices add new structures and defines need to identify 100 devices. Signed-off-by: Jay Sternberg Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-1000.c | 73 +++++++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-agn.c | 6 +++ drivers/net/wireless/iwlwifi/iwl-agn.h | 2 + 3 files changed, 81 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 56ef4ed0db47..19dbef06d52c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -50,14 +50,20 @@ /* Highest firmware API version supported */ #define IWL1000_UCODE_API_MAX 3 +#define IWL100_UCODE_API_MAX 5 /* Lowest firmware API version supported */ #define IWL1000_UCODE_API_MIN 1 +#define IWL100_UCODE_API_MIN 5 #define IWL1000_FW_PRE "iwlwifi-1000-" #define _IWL1000_MODULE_FIRMWARE(api) IWL1000_FW_PRE #api ".ucode" #define IWL1000_MODULE_FIRMWARE(api) _IWL1000_MODULE_FIRMWARE(api) +#define IWL100_FW_PRE "iwlwifi-100-" +#define _IWL100_MODULE_FIRMWARE(api) IWL100_FW_PRE #api ".ucode" +#define IWL100_MODULE_FIRMWARE(api) _IWL100_MODULE_FIRMWARE(api) + /* * For 1000, use advance thermal throttling critical temperature threshold, @@ -310,4 +316,71 @@ struct iwl_cfg iwl1000_bg_cfg = { .chain_noise_calib_by_driver = true, }; +struct iwl_cfg iwl100_bgn_cfg = { + .name = "Intel(R) 100 Series 1x1 BGN", + .fw_name_pre = IWL100_FW_PRE, + .ucode_api_max = IWL100_UCODE_API_MAX, + .ucode_api_min = IWL100_UCODE_API_MIN, + .sku = IWL_SKU_G|IWL_SKU_N, + .ops = &iwl1000_ops, + .eeprom_size = OTP_LOW_IMAGE_SIZE, + .eeprom_ver = EEPROM_1000_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION, + .num_of_queues = IWLAGN_NUM_QUEUES, + .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, + .mod_params = &iwlagn_mod_params, + .valid_tx_ant = ANT_A, + .valid_rx_ant = ANT_A, + .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, + .set_l0s = true, + .use_bsm = false, + .max_ll_items = OTP_MAX_LL_ITEMS_1000, + .shadow_ram_support = false, + .ht_greenfield_support = true, + .led_compensation = 51, + .use_rts_for_aggregation = 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, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, + .max_event_log_size = 128, + .ucode_tracing = true, + .sensitivity_calib_by_driver = true, + .chain_noise_calib_by_driver = true, +}; + +struct iwl_cfg iwl100_bg_cfg = { + .name = "Intel(R) 100 Series 1x1 BG", + .fw_name_pre = IWL100_FW_PRE, + .ucode_api_max = IWL100_UCODE_API_MAX, + .ucode_api_min = IWL100_UCODE_API_MIN, + .sku = IWL_SKU_G, + .ops = &iwl1000_ops, + .eeprom_size = OTP_LOW_IMAGE_SIZE, + .eeprom_ver = EEPROM_1000_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION, + .num_of_queues = IWLAGN_NUM_QUEUES, + .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, + .mod_params = &iwlagn_mod_params, + .valid_tx_ant = ANT_A, + .valid_rx_ant = ANT_A, + .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, + .set_l0s = true, + .use_bsm = false, + .max_ll_items = OTP_MAX_LL_ITEMS_1000, + .shadow_ram_support = false, + .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, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, + .max_event_log_size = 128, + .ucode_tracing = true, + .sensitivity_calib_by_driver = true, + .chain_noise_calib_by_driver = true, +}; + MODULE_FIRMWARE(IWL1000_MODULE_FIRMWARE(IWL1000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL100_MODULE_FIRMWARE(IWL100_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 646864a26eaf..005b07bea1e0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -4788,6 +4788,12 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { {IWL_PCI_DEVICE(0x0083, 0x1326, iwl1000_bg_cfg)}, {IWL_PCI_DEVICE(0x0084, 0x1216, iwl1000_bg_cfg)}, {IWL_PCI_DEVICE(0x0084, 0x1316, iwl1000_bg_cfg)}, + + {IWL_PCI_DEVICE(0x08AE, 0x1005, iwl100_bgn_cfg)}, + {IWL_PCI_DEVICE(0x08AF, 0x1015, iwl100_bgn_cfg)}, + {IWL_PCI_DEVICE(0x08AE, 0x1025, iwl100_bgn_cfg)}, + {IWL_PCI_DEVICE(0x08AE, 0x1007, iwl100_bg_cfg)}, + {IWL_PCI_DEVICE(0x08AE, 0x1017, iwl100_bg_cfg)}, #endif /* CONFIG_IWL5000 */ {0} diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index a372184ac210..d5dc824ebbfb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -92,6 +92,8 @@ extern struct iwl_cfg iwl6050_2abg_cfg; extern struct iwl_cfg iwl6050g2_bgn_cfg; extern struct iwl_cfg iwl1000_bgn_cfg; extern struct iwl_cfg iwl1000_bg_cfg; +extern struct iwl_cfg iwl100_bgn_cfg; +extern struct iwl_cfg iwl100_bg_cfg; extern struct iwl_mod_params iwlagn_mod_params; extern struct iwl_hcmd_ops iwlagn_hcmd; -- cgit v1.2.3 From 6b5ce501428942d9dec864a41ee223307f421574 Mon Sep 17 00:00:00 2001 From: Shanyu Zhao Date: Tue, 14 Sep 2010 16:23:32 -0700 Subject: iwlwifi: add iwl_nic_ops structure to iwl_ops iwlwifi driver supports multiple devices. Since some device needs special configuration we create a new iwl_nic_ops structure which is configurable per device. Currently there is only one function pointer inside this structure: additional_nic_config(). The iwl_nic_ops structure is added to the top level in struct iwl_ops, making it easier to change per device. Duplication of the iwl_lib_ops structure is no longer needed. With this new ops the previous function pointer set_calib_version is no longer needed since it is just a per device nic configuration. As part of the code restructuring, a bug is addressed. Indication of calib version to uCode is only needed for 6050 devices, however, current implementation set calib version for all 6000 devices for which DC calib is needed. To fix this, create iwl6050_ops for 6050 devices and only populate iwl_nic_ops in this structure. Signed-off-by: Shanyu Zhao Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-6000.c | 35 ++++++++++++++++++++++----------- drivers/net/wireless/iwlwifi/iwl-core.h | 7 ++++++- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 9f43f2770c96..8256034285a6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -83,11 +83,10 @@ 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 iwl6000_set_calib_version(struct iwl_priv *priv) +static void iwl6050_additional_nic_config(struct iwl_priv *priv) { - if (priv->cfg->need_dc_calib && - (priv->cfg->ops->lib->eeprom_ops.calib_version(priv) >= 6)) + /* Indicate calibration version to uCode. */ + 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); } @@ -117,9 +116,11 @@ static void iwl6000_nic_config(struct iwl_priv *priv) iwl_write32(priv, CSR_GP_DRIVER_REG, 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); + /* do additional nic configuration if needed */ + if (priv->cfg->ops->nic && + priv->cfg->ops->nic->additional_nic_config) { + priv->cfg->ops->nic->additional_nic_config(priv); + } } static struct iwl_sensitivity_ranges iwl6000_sensitivity = { @@ -320,7 +321,6 @@ static struct iwl_lib_ops iwl6000_lib = { .temp_ops = { .temperature = iwlagn_temperature, .set_ct_kill = iwl6000_set_ct_threshold, - .set_calib_version = iwl6000_set_calib_version, }, .manage_ibss_station = iwlagn_manage_ibss_station, .update_bcast_stations = iwl_update_bcast_stations, @@ -396,7 +396,6 @@ static struct iwl_lib_ops iwl6000g2b_lib = { .temp_ops = { .temperature = iwlagn_temperature, .set_ct_kill = iwl6000_set_ct_threshold, - .set_calib_version = iwl6000_set_calib_version, }, .manage_ibss_station = iwlagn_manage_ibss_station, .update_bcast_stations = iwl_update_bcast_stations, @@ -419,6 +418,10 @@ static struct iwl_lib_ops iwl6000g2b_lib = { } }; +static struct iwl_nic_ops iwl6050_nic_ops = { + .additional_nic_config = &iwl6050_additional_nic_config, +}; + static const struct iwl_ops iwl6000_ops = { .lib = &iwl6000_lib, .hcmd = &iwlagn_hcmd, @@ -426,6 +429,14 @@ static const struct iwl_ops iwl6000_ops = { .led = &iwlagn_led_ops, }; +static const struct iwl_ops iwl6050_ops = { + .lib = &iwl6000_lib, + .hcmd = &iwlagn_hcmd, + .utils = &iwlagn_hcmd_utils, + .led = &iwlagn_led_ops, + .nic = &iwl6050_nic_ops, +}; + static const struct iwl_ops iwl6000g2b_ops = { .lib = &iwl6000g2b_lib, .hcmd = &iwlagn_bt_hcmd, @@ -909,7 +920,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { .ucode_api_max = IWL6050_UCODE_API_MAX, .ucode_api_min = IWL6050_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, - .ops = &iwl6000_ops, + .ops = &iwl6050_ops, .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_6050_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION, @@ -947,7 +958,7 @@ struct iwl_cfg iwl6050g2_bgn_cfg = { .ucode_api_max = IWL6050_UCODE_API_MAX, .ucode_api_min = IWL6050_UCODE_API_MIN, .sku = IWL_SKU_G|IWL_SKU_N, - .ops = &iwl6000_ops, + .ops = &iwl6050_ops, .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_6050G2_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_6050G2_TX_POWER_VERSION, @@ -985,7 +996,7 @@ struct iwl_cfg iwl6050_2abg_cfg = { .ucode_api_max = IWL6050_UCODE_API_MAX, .ucode_api_min = IWL6050_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G, - .ops = &iwl6000_ops, + .ops = &iwl6050_ops, .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_6050_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index f0302bfe85f5..5daa1893fd03 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -137,7 +137,6 @@ struct iwl_debugfs_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_tt_ops { @@ -233,11 +232,17 @@ struct iwl_led_ops { int (*off)(struct iwl_priv *priv); }; +/* NIC specific ops */ +struct iwl_nic_ops { + void (*additional_nic_config)(struct iwl_priv *priv); +}; + struct iwl_ops { const struct iwl_lib_ops *lib; const struct iwl_hcmd_ops *hcmd; const struct iwl_hcmd_utils_ops *utils; const struct iwl_led_ops *led; + const struct iwl_nic_ops *nic; }; struct iwl_mod_params { -- cgit v1.2.3 From 02796d77cb4cfb64b9465eabbdb13b3b7d1679e9 Mon Sep 17 00:00:00 2001 From: Shanyu Zhao Date: Tue, 14 Sep 2010 16:23:42 -0700 Subject: iwlagn: set CSR register for 6050g2 devices For 6050g2 devices driver needs to set a special bit to CSR register so that uCode can do things correctly in calibration routines. Signed-off-by: Shanyu Zhao Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-6000.c | 24 +++++++++++++++++++++++- drivers/net/wireless/iwlwifi/iwl-csr.h | 3 ++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 8256034285a6..83a5262d8bd8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -91,6 +91,16 @@ static void iwl6050_additional_nic_config(struct iwl_priv *priv) CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6); } +static void iwl6050g2_additional_nic_config(struct iwl_priv *priv) +{ + /* Indicate calibration version to uCode. */ + 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); + iwl_set_bit(priv, CSR_GP_DRIVER_REG, + CSR_GP_DRIVER_REG_BIT_6050_1x2); +} + /* NIC configuration for 6000 series */ static void iwl6000_nic_config(struct iwl_priv *priv) { @@ -422,6 +432,10 @@ static struct iwl_nic_ops iwl6050_nic_ops = { .additional_nic_config = &iwl6050_additional_nic_config, }; +static struct iwl_nic_ops iwl6050g2_nic_ops = { + .additional_nic_config = &iwl6050g2_additional_nic_config, +}; + static const struct iwl_ops iwl6000_ops = { .lib = &iwl6000_lib, .hcmd = &iwlagn_hcmd, @@ -437,6 +451,14 @@ static const struct iwl_ops iwl6050_ops = { .nic = &iwl6050_nic_ops, }; +static const struct iwl_ops iwl6050g2_ops = { + .lib = &iwl6000_lib, + .hcmd = &iwlagn_hcmd, + .utils = &iwlagn_hcmd_utils, + .led = &iwlagn_led_ops, + .nic = &iwl6050g2_nic_ops, +}; + static const struct iwl_ops iwl6000g2b_ops = { .lib = &iwl6000g2b_lib, .hcmd = &iwlagn_bt_hcmd, @@ -958,7 +980,7 @@ struct iwl_cfg iwl6050g2_bgn_cfg = { .ucode_api_max = IWL6050_UCODE_API_MAX, .ucode_api_min = IWL6050_UCODE_API_MIN, .sku = IWL_SKU_G|IWL_SKU_N, - .ops = &iwl6050_ops, + .ops = &iwl6050g2_ops, .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_6050G2_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_6050G2_TX_POWER_VERSION, diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index ecf98e7ac4ed..2aa15ab13892 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -371,7 +371,8 @@ #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) +#define CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6 (0x00000004) +#define CSR_GP_DRIVER_REG_BIT_6050_1x2 (0x00000008) /* GIO Chicken Bits (PCI Express bus link power management) */ #define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX (0x00800000) -- cgit v1.2.3 From 6d6a1afdc591e3f3ee66c39206923def43044ab6 Mon Sep 17 00:00:00 2001 From: Shanyu Zhao Date: Tue, 14 Sep 2010 18:13:31 -0700 Subject: iwlwifi: send DC calib config to runtime ucode Since uCode is responsible for doing DC calibration, there's no need to let init uCode to do initial DC calibration then send results back to driver, then driver sends the results to runtime uCode. Driver can simply tell runtime uCode to do DC calibration. Actually, this patch does not disable DC calib for init uCode. It just prevent driver from saving and sending the DC calib results (from init ucode) to runtime uCode. The driver still uses 0xffffffff in CALIB_CFG_CMD for init ucode. Signed-off-by: Shanyu Zhao Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-6000.c | 2 +- drivers/net/wireless/iwlwifi/iwl-agn.c | 23 +++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-commands.h | 15 +++++++++++++++ drivers/net/wireless/iwlwifi/iwl-dev.h | 2 ++ 4 files changed, 41 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 83a5262d8bd8..51444c8e69ae 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -199,7 +199,7 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv) BIT(IWL_CALIB_TX_IQ) | BIT(IWL_CALIB_BASE_BAND); if (priv->cfg->need_dc_calib) - priv->hw_params.calib_init_cfg |= BIT(IWL_CALIB_DC); + priv->hw_params.calib_rt_cfg |= BIT(IWL_CALIB_CFG_DC_IDX); priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 005b07bea1e0..e23c554b73a8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2765,6 +2765,25 @@ static void iwl_rf_kill_ct_config(struct iwl_priv *priv) } } +static int iwlagn_send_calib_cfg_rt(struct iwl_priv *priv, u32 cfg) +{ + struct iwl_calib_cfg_cmd calib_cfg_cmd; + struct iwl_host_cmd cmd = { + .id = CALIBRATION_CFG_CMD, + .len = sizeof(struct iwl_calib_cfg_cmd), + .data = &calib_cfg_cmd, + }; + + memset(&calib_cfg_cmd, 0, sizeof(calib_cfg_cmd)); + calib_cfg_cmd.ucd_calib_cfg.once.is_enable = IWL_CALIB_INIT_CFG_ALL; + calib_cfg_cmd.ucd_calib_cfg.once.start = cfg; + calib_cfg_cmd.ucd_calib_cfg.once.send_res = 0; + calib_cfg_cmd.ucd_calib_cfg.flags = 0; + + return iwl_send_cmd(priv, &cmd); +} + + /** * iwl_alive_start - called after REPLY_ALIVE notification received * from protocol/runtime uCode (initialization uCode's @@ -2801,6 +2820,10 @@ static void iwl_alive_start(struct iwl_priv *priv) goto restart; } + if (priv->hw_params.calib_rt_cfg) + iwlagn_send_calib_cfg_rt(priv, priv->hw_params.calib_rt_cfg); + + /* After the ALIVE response, we can send host commands to the uCode */ set_bit(STATUS_ALIVE, &priv->status); diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 27e250c8d4b5..27350eebb132 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -3800,6 +3800,21 @@ enum { #define IWL_CALIB_INIT_CFG_ALL cpu_to_le32(0xffffffff) +/* This enum defines the bitmap of various calibrations to enable in both + * init ucode and runtime ucode through CALIBRATION_CFG_CMD. + */ +enum iwl_ucode_calib_cfg { + IWL_CALIB_CFG_RX_BB_IDX, + IWL_CALIB_CFG_DC_IDX, + IWL_CALIB_CFG_TX_IQ_IDX, + IWL_CALIB_CFG_RX_IQ_IDX, + IWL_CALIB_CFG_NOISE_IDX, + IWL_CALIB_CFG_CRYSTAL_IDX, + IWL_CALIB_CFG_TEMPERATURE_IDX, + IWL_CALIB_CFG_PAPD_IDX, +}; + + struct iwl_calib_cfg_elmnt_s { __le32 is_enable; __le32 start; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 74d25bcbfcb2..90a37a94c698 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -684,6 +684,7 @@ struct iwl_sensitivity_ranges { * @ct_kill_threshold: temperature threshold * @beacon_time_tsf_bits: number of valid tsf bits for beacon time * @calib_init_cfg: setup initial calibrations for the hw + * @calib_rt_cfg: setup runtime calibrations for the hw * @struct iwl_sensitivity_ranges: range of sensitivity values */ struct iwl_hw_params { @@ -710,6 +711,7 @@ struct iwl_hw_params { /* for 1000, 6000 series and up */ u16 beacon_time_tsf_bits; u32 calib_init_cfg; + u32 calib_rt_cfg; const struct iwl_sensitivity_ranges *sens; }; -- cgit v1.2.3 From 62cb3c6ac47a5ab7d8c67dbbf8cbdcd5ae735410 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Tue, 28 Sep 2010 17:43:10 -0700 Subject: iwlagn: API v5 for 6050 series device For 6050 series device, change the supported API version Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-6000.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 51444c8e69ae..4d45932e901e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -51,7 +51,7 @@ /* Highest firmware API version supported */ #define IWL6000_UCODE_API_MAX 4 -#define IWL6050_UCODE_API_MAX 4 +#define IWL6050_UCODE_API_MAX 5 #define IWL6000G2_UCODE_API_MAX 5 /* Lowest firmware API version supported */ -- cgit v1.2.3 From 65836112fc24bdf009554481b36b6ba0a690b855 Mon Sep 17 00:00:00 2001 From: Ohad Ben-Cohen Date: Tue, 28 Sep 2010 20:20:28 +0200 Subject: wl12xx: fix non-wl12xx build scenarios Support building wl1271-equipped boards without building the wl1271 driver itself, e.g.: CONFIG_MACH_OMAP_ZOOM3=y CONFIG_WL12XX is not set Reported-by: John W. Linville Signed-off-by: Ohad Ben-Cohen Signed-off-by: Luciano Coelho --- include/linux/wl12xx.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/include/linux/wl12xx.h b/include/linux/wl12xx.h index 95deae3968f4..4f902e1908aa 100644 --- a/include/linux/wl12xx.h +++ b/include/linux/wl12xx.h @@ -32,7 +32,20 @@ struct wl12xx_platform_data { int board_ref_clock; }; +#ifdef CONFIG_WL12XX_PLATFORM_DATA + int wl12xx_set_platform_data(const struct wl12xx_platform_data *data); + +#else + +static inline +int wl12xx_set_platform_data(const struct wl12xx_platform_data *data) +{ + return -ENOSYS; +} + +#endif + const struct wl12xx_platform_data *wl12xx_get_platform_data(void); #endif -- cgit v1.2.3 From 5c57a901dc96fc81d0041282269b43542f170d2a Mon Sep 17 00:00:00 2001 From: Ido Yariv Date: Thu, 30 Sep 2010 13:28:26 +0200 Subject: wl1271: Handle large SPI transfers The HW supports up to 4095 bytes transfers via SPI. The SPI read & write operations do not handle larger transfers, causing the HW to stall in such cases. Fix this by fragmenting large transfers into smaller chunks, and transferring each one separately. Signed-off-by: Ido Yariv Tested-by: Juuso Oikarinen Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271_spi.c | 140 +++++++++++++++++++------------ 1 file changed, 86 insertions(+), 54 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.c b/drivers/net/wireless/wl12xx/wl1271_spi.c index 75cbf36146e2..ef801680773f 100644 --- a/drivers/net/wireless/wl12xx/wl1271_spi.c +++ b/drivers/net/wireless/wl12xx/wl1271_spi.c @@ -63,6 +63,11 @@ ((WL1271_BUSY_WORD_LEN - 4) / sizeof(u32)) #define HW_ACCESS_WSPI_INIT_CMD_MASK 0 +/* HW limitation: maximum possible chunk size is 4095 bytes */ +#define WSPI_MAX_CHUNK_SIZE 4092 + +#define WSPI_MAX_NUM_OF_CHUNKS (WL1271_AGGR_BUFFER_SIZE / WSPI_MAX_CHUNK_SIZE) + static inline struct spi_device *wl_to_spi(struct wl1271 *wl) { return wl->if_priv; @@ -202,90 +207,117 @@ static int wl1271_spi_read_busy(struct wl1271 *wl) static void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf, size_t len, bool fixed) { - struct spi_transfer t[3]; + struct spi_transfer t[2]; struct spi_message m; u32 *busy_buf; u32 *cmd; + u32 chunk_len; - cmd = &wl->buffer_cmd; - busy_buf = wl->buffer_busyword; + while (len > 0) { + chunk_len = min((size_t)WSPI_MAX_CHUNK_SIZE, len); - *cmd = 0; - *cmd |= WSPI_CMD_READ; - *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; - *cmd |= addr & WSPI_CMD_BYTE_ADDR; + cmd = &wl->buffer_cmd; + busy_buf = wl->buffer_busyword; - if (fixed) - *cmd |= WSPI_CMD_FIXED; + *cmd = 0; + *cmd |= WSPI_CMD_READ; + *cmd |= (chunk_len << WSPI_CMD_BYTE_LENGTH_OFFSET) & + WSPI_CMD_BYTE_LENGTH; + *cmd |= addr & WSPI_CMD_BYTE_ADDR; - spi_message_init(&m); - memset(t, 0, sizeof(t)); + if (fixed) + *cmd |= WSPI_CMD_FIXED; - t[0].tx_buf = cmd; - t[0].len = 4; - t[0].cs_change = true; - spi_message_add_tail(&t[0], &m); + spi_message_init(&m); + memset(t, 0, sizeof(t)); - /* Busy and non busy words read */ - t[1].rx_buf = busy_buf; - t[1].len = WL1271_BUSY_WORD_LEN; - t[1].cs_change = true; - spi_message_add_tail(&t[1], &m); + t[0].tx_buf = cmd; + t[0].len = 4; + t[0].cs_change = true; + spi_message_add_tail(&t[0], &m); - spi_sync(wl_to_spi(wl), &m); + /* Busy and non busy words read */ + t[1].rx_buf = busy_buf; + t[1].len = WL1271_BUSY_WORD_LEN; + t[1].cs_change = true; + spi_message_add_tail(&t[1], &m); - if (!(busy_buf[WL1271_BUSY_WORD_CNT - 1] & 0x1) && - wl1271_spi_read_busy(wl)) { - memset(buf, 0, len); - return; - } + spi_sync(wl_to_spi(wl), &m); - spi_message_init(&m); - memset(t, 0, sizeof(t)); + if (!(busy_buf[WL1271_BUSY_WORD_CNT - 1] & 0x1) && + wl1271_spi_read_busy(wl)) { + memset(buf, 0, chunk_len); + return; + } - t[0].rx_buf = buf; - t[0].len = len; - t[0].cs_change = true; - spi_message_add_tail(&t[0], &m); + spi_message_init(&m); + memset(t, 0, sizeof(t)); - spi_sync(wl_to_spi(wl), &m); + t[0].rx_buf = buf; + t[0].len = chunk_len; + t[0].cs_change = true; + spi_message_add_tail(&t[0], &m); + + spi_sync(wl_to_spi(wl), &m); - wl1271_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd)); - wl1271_dump(DEBUG_SPI, "spi_read buf <- ", buf, len); + wl1271_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd)); + wl1271_dump(DEBUG_SPI, "spi_read buf <- ", buf, chunk_len); + + if (!fixed) + addr += chunk_len; + buf += chunk_len; + len -= chunk_len; + } } static void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf, size_t len, bool fixed) { - struct spi_transfer t[2]; + struct spi_transfer t[2 * WSPI_MAX_NUM_OF_CHUNKS]; struct spi_message m; + u32 commands[WSPI_MAX_NUM_OF_CHUNKS]; u32 *cmd; + u32 chunk_len; + int i; - cmd = &wl->buffer_cmd; - - *cmd = 0; - *cmd |= WSPI_CMD_WRITE; - *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; - *cmd |= addr & WSPI_CMD_BYTE_ADDR; - - if (fixed) - *cmd |= WSPI_CMD_FIXED; + WARN_ON(len > WL1271_AGGR_BUFFER_SIZE); spi_message_init(&m); memset(t, 0, sizeof(t)); - t[0].tx_buf = cmd; - t[0].len = sizeof(*cmd); - spi_message_add_tail(&t[0], &m); + cmd = &commands[0]; + i = 0; + while (len > 0) { + chunk_len = min((size_t)WSPI_MAX_CHUNK_SIZE, len); - t[1].tx_buf = buf; - t[1].len = len; - spi_message_add_tail(&t[1], &m); + *cmd = 0; + *cmd |= WSPI_CMD_WRITE; + *cmd |= (chunk_len << WSPI_CMD_BYTE_LENGTH_OFFSET) & + WSPI_CMD_BYTE_LENGTH; + *cmd |= addr & WSPI_CMD_BYTE_ADDR; - spi_sync(wl_to_spi(wl), &m); + if (fixed) + *cmd |= WSPI_CMD_FIXED; + + t[i].tx_buf = cmd; + t[i].len = sizeof(*cmd); + spi_message_add_tail(&t[i++], &m); + + t[i].tx_buf = buf; + t[i].len = chunk_len; + spi_message_add_tail(&t[i++], &m); - wl1271_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); - wl1271_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); + wl1271_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); + wl1271_dump(DEBUG_SPI, "spi_write buf -> ", buf, chunk_len); + + if (!fixed) + addr += chunk_len; + buf += chunk_len; + len -= chunk_len; + cmd++; + } + + spi_sync(wl_to_spi(wl), &m); } static irqreturn_t wl1271_irq(int irq, void *cookie) -- cgit v1.2.3 From 1f37cbc9363462c99794699442da39f36be0aaf7 Mon Sep 17 00:00:00 2001 From: Ido Yariv Date: Thu, 30 Sep 2010 13:28:27 +0200 Subject: wl1271: Support firmware RX packet aggregation Instead of retrieving one packet at a time from the firmware, try to retrieve all available packets at once. This optimization decreases the number of transactions, which saves CPU cycles and increases network throughput. Signed-off-by: Ido Yariv Tested-by: Juuso Oikarinen Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271.h | 5 +++ drivers/net/wireless/wl12xx/wl1271_main.c | 15 +++++++- drivers/net/wireless/wl12xx/wl1271_rx.c | 63 +++++++++++++++++++++++-------- 3 files changed, 66 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index 779b130fdb3e..8a4cd763e5a2 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -130,6 +130,8 @@ enum { #define ACX_TX_DESCRIPTORS 32 +#define WL1271_AGGR_BUFFER_SIZE (4 * PAGE_SIZE) + enum wl1271_state { WL1271_STATE_OFF, WL1271_STATE_ON, @@ -408,6 +410,9 @@ struct wl1271 { /* Rx memory pool address */ struct wl1271_rx_mem_pool_addr rx_mem_pool_addr; + /* Intermediate buffer, used for packet aggregation */ + u8 *aggr_buf; + /* The target interrupt mask */ struct work_struct irq_work; diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index cb18f22bbc5c..8071da10dbc9 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -2459,6 +2459,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void) struct platform_device *plat_dev = NULL; struct wl1271 *wl; int i, ret; + unsigned int order; hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops); if (!hw) { @@ -2517,11 +2518,18 @@ struct ieee80211_hw *wl1271_alloc_hw(void) wl1271_debugfs_init(wl); + order = get_order(WL1271_AGGR_BUFFER_SIZE); + wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order); + if (!wl->aggr_buf) { + ret = -ENOMEM; + goto err_hw; + } + /* Register platform device */ ret = platform_device_register(wl->plat_dev); if (ret) { wl1271_error("couldn't register platform device"); - goto err_hw; + goto err_aggr; } dev_set_drvdata(&wl->plat_dev->dev, wl); @@ -2547,6 +2555,9 @@ err_bt_coex_state: err_platform: platform_device_unregister(wl->plat_dev); +err_aggr: + free_pages((unsigned long)wl->aggr_buf, order); + err_hw: wl1271_debugfs_exit(wl); kfree(plat_dev); @@ -2563,6 +2574,8 @@ EXPORT_SYMBOL_GPL(wl1271_alloc_hw); int wl1271_free_hw(struct wl1271 *wl) { platform_device_unregister(wl->plat_dev); + free_pages((unsigned long)wl->aggr_buf, + get_order(WL1271_AGGR_BUFFER_SIZE)); kfree(wl->plat_dev); wl1271_debugfs_exit(wl); diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.c b/drivers/net/wireless/wl12xx/wl1271_rx.c index 94da5dd7723c..bea133b6e489 100644 --- a/drivers/net/wireless/wl12xx/wl1271_rx.c +++ b/drivers/net/wireless/wl12xx/wl1271_rx.c @@ -74,7 +74,7 @@ static void wl1271_rx_status(struct wl1271 *wl, } } -static void wl1271_rx_handle_data(struct wl1271 *wl, u32 length) +static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length) { struct wl1271_rx_descriptor *desc; struct sk_buff *skb; @@ -87,16 +87,16 @@ static void wl1271_rx_handle_data(struct wl1271 *wl, u32 length) * workaround this by not retrieving them at all. */ if (unlikely(wl->state == WL1271_STATE_PLT)) - return; + return -EINVAL; skb = __dev_alloc_skb(length, GFP_KERNEL); if (!skb) { wl1271_error("Couldn't allocate RX frame"); - return; + return -ENOMEM; } buf = skb_put(skb, length); - wl1271_read(wl, WL1271_SLV_MEM_DATA, buf, length, true); + memcpy(buf, data, length); /* the data read starts with the descriptor */ desc = (struct wl1271_rx_descriptor *) buf; @@ -116,6 +116,8 @@ static void wl1271_rx_handle_data(struct wl1271 *wl, u32 length) skb_trim(skb, skb->len - desc->pad_len); ieee80211_rx_ni(wl->hw, skb); + + return 0; } void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status) @@ -124,31 +126,60 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status) u32 buf_size; u32 fw_rx_counter = status->fw_rx_counter & NUM_RX_PKT_DESC_MOD_MASK; u32 drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK; + u32 rx_counter; u32 mem_block; + u32 pkt_length; + u32 pkt_offset; while (drv_rx_counter != fw_rx_counter) { - mem_block = wl1271_rx_get_mem_block(status, drv_rx_counter); - buf_size = wl1271_rx_get_buf_size(status, drv_rx_counter); + buf_size = 0; + rx_counter = drv_rx_counter; + while (rx_counter != fw_rx_counter) { + pkt_length = wl1271_rx_get_buf_size(status, rx_counter); + if (buf_size + pkt_length > WL1271_AGGR_BUFFER_SIZE) + break; + buf_size += pkt_length; + rx_counter++; + rx_counter &= NUM_RX_PKT_DESC_MOD_MASK; + } if (buf_size == 0) { wl1271_warning("received empty data"); break; } + /* + * Choose the block we want to read + * For aggregated packets, only the first memory block should + * be retrieved. The FW takes care of the rest. + */ + mem_block = wl1271_rx_get_mem_block(status, drv_rx_counter); wl->rx_mem_pool_addr.addr = (mem_block << 8) + le32_to_cpu(wl_mem_map->packet_memory_pool_start); wl->rx_mem_pool_addr.addr_extra = 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_rx_handle_data(wl, buf_size); - - wl->rx_counter++; - drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK; + sizeof(wl->rx_mem_pool_addr), false); + + /* Read all available packets at once */ + wl1271_read(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf, + buf_size, true); + + /* Split data into separate packets */ + pkt_offset = 0; + while (pkt_offset < buf_size) { + pkt_length = wl1271_rx_get_buf_size(status, + drv_rx_counter); + if (wl1271_rx_handle_data(wl, + wl->aggr_buf + pkt_offset, + pkt_length) < 0) + break; + wl->rx_counter++; + drv_rx_counter++; + drv_rx_counter &= NUM_RX_PKT_DESC_MOD_MASK; + pkt_offset += pkt_length; + } } - - wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter); + wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, + cpu_to_le32(wl->rx_counter)); } -- cgit v1.2.3 From a19606b4333ff34e9b2863f37c20fe86b42be14c Mon Sep 17 00:00:00 2001 From: Ido Yariv Date: Thu, 30 Sep 2010 13:28:28 +0200 Subject: wl1271: Support firmware TX packet aggregation Instead of sending one packet at a time to the firmware, try to send all available packets at once. This optimization decreases the number of transactions, which saves CPU cycles and increases network throughput. Signed-off-by: Ido Yariv Tested-by: Juuso Oikarinen Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271_tx.c | 99 ++++++++++++--------------------- 1 file changed, 37 insertions(+), 62 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c index 1b8295c5dde4..e3dc13c4d01a 100644 --- a/drivers/net/wireless/wl12xx/wl1271_tx.c +++ b/drivers/net/wireless/wl12xx/wl1271_tx.c @@ -43,13 +43,17 @@ static int wl1271_tx_id(struct wl1271 *wl, struct sk_buff *skb) return -EBUSY; } -static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra) +static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, + u32 buf_offset) { struct wl1271_tx_hw_descr *desc; u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra; u32 total_blocks; int id, ret = -EBUSY; + if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE) + return -EBUSY; + /* allocate free identifier for the packet */ id = wl1271_tx_id(wl, skb); if (id < 0) @@ -82,7 +86,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra) return ret; } -static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, +static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, u32 extra, struct ieee80211_tx_info *control) { struct timespec ts; @@ -133,59 +137,17 @@ static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, desc->tx_attr = cpu_to_le16(tx_attr); wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d", pad); - return 0; -} - -static int wl1271_tx_send_packet(struct wl1271 *wl, struct sk_buff *skb, - struct ieee80211_tx_info *control) -{ - - struct wl1271_tx_hw_descr *desc; - int len; - - /* FIXME: This is a workaround for getting non-aligned packets. - This happens at least with EAPOL packets from the user space. - Our DMA requires packets to be aligned on a 4-byte boundary. - */ - if (unlikely((long)skb->data & 0x03)) { - int offset = (4 - (long)skb->data) & 0x03; - wl1271_debug(DEBUG_TX, "skb offset %d", offset); - - /* check whether the current skb can be used */ - if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) { - unsigned char *src = skb->data; - - /* align the buffer on a 4-byte boundary */ - skb_reserve(skb, offset); - memmove(skb->data, src, skb->len); - } else { - wl1271_info("No handler, fixme!"); - return -EINVAL; - } - } - - 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); - - /* write packet new counter into the write access register */ - 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)", - desc->id, skb, len, desc->length); - - return 0; } /* caller must hold wl->mutex */ -static int wl1271_tx_frame(struct wl1271 *wl, struct sk_buff *skb) +static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb, + u32 buf_offset) { struct ieee80211_tx_info *info; u32 extra = 0; int ret = 0; u8 idx; + u32 total_len; if (!skb) return -EINVAL; @@ -208,19 +170,22 @@ static int wl1271_tx_frame(struct wl1271 *wl, struct sk_buff *skb) } } - ret = wl1271_tx_allocate(wl, skb, extra); + ret = wl1271_tx_allocate(wl, skb, extra, buf_offset); if (ret < 0) return ret; - ret = wl1271_tx_fill_hdr(wl, skb, extra, info); - if (ret < 0) - return ret; + wl1271_tx_fill_hdr(wl, skb, extra, info); - ret = wl1271_tx_send_packet(wl, skb, info); - if (ret < 0) - return ret; + /* + * The length of each packet is stored in terms of words. Thus, we must + * pad the skb data to make sure its length is aligned. + * The number of padding bytes is computed and set in wl1271_tx_fill_hdr + */ + total_len = WL1271_TX_ALIGN(skb->len); + memcpy(wl->aggr_buf + buf_offset, skb->data, skb->len); + memset(wl->aggr_buf + buf_offset + skb->len, 0, total_len - skb->len); - return ret; + return total_len; } u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set) @@ -245,7 +210,7 @@ void wl1271_tx_work(struct work_struct *work) struct sk_buff *skb; bool woken_up = false; u32 sta_rates = 0; - u32 prev_tx_packets_count; + u32 buf_offset; int ret; /* check if the rates supported by the AP have changed */ @@ -262,14 +227,15 @@ void wl1271_tx_work(struct work_struct *work) if (unlikely(wl->state == WL1271_STATE_OFF)) goto out; - prev_tx_packets_count = wl->tx_packets_count; - /* 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); } + /* Prepare the transfer buffer, by aggregating all + * available packets */ + buf_offset = 0; while ((skb = skb_dequeue(&wl->tx_queue))) { if (!woken_up) { ret = wl1271_ps_elp_wakeup(wl, false); @@ -278,21 +244,30 @@ void wl1271_tx_work(struct work_struct *work) woken_up = true; } - ret = wl1271_tx_frame(wl, skb); + ret = wl1271_prepare_tx_frame(wl, skb, buf_offset); if (ret == -EBUSY) { - /* firmware buffer is full, lets stop transmitting. */ + /* + * Either the firmware buffer is full, or the + * aggregation buffer is. + * Queue back last skb, and stop aggregating. + */ skb_queue_head(&wl->tx_queue, skb); goto out_ack; } else if (ret < 0) { dev_kfree_skb(skb); goto out_ack; } + buf_offset += ret; + wl->tx_packets_count++; } out_ack: - /* interrupt the firmware with the new packets */ - if (prev_tx_packets_count != wl->tx_packets_count) + if (buf_offset) { + wl1271_write(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf, + buf_offset, true); + /* interrupt the firmware with the new packets */ wl1271_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count); + } out: if (woken_up) -- cgit v1.2.3 From 117b38d0b9d3efb0adc3e636e73fc67bb53a13d1 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Thu, 30 Sep 2010 10:43:28 +0200 Subject: wl1271: Move work-init calls to hw allocation Due to legacy reason, dating back to when the wl1251 and wl1271 still were a unified driver, some work-structures are initialized on hardware startup. The hardware recovery code creates a scenario in which it is possible for a workstruct to be re-initialized while the work-function itself is running, which causes a kernel WARNing and a subsequent reboot. To remedy this, move the work initialization calls to the hw allocation, which is the logically correct place for them anyway. Signed-off-by: Juuso Oikarinen Tested-by: Tuomas Katila Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271_main.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 8071da10dbc9..760a5814d4a4 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -664,11 +664,6 @@ static int wl1271_setup(struct wl1271 *wl) return -ENOMEM; } - INIT_WORK(&wl->irq_work, wl1271_irq_work); - INIT_WORK(&wl->tx_work, wl1271_tx_work); - INIT_WORK(&wl->recovery_work, wl1271_recovery_work); - INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work); - return 0; } @@ -2487,6 +2482,10 @@ struct ieee80211_hw *wl1271_alloc_hw(void) INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work); INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work); + INIT_WORK(&wl->irq_work, wl1271_irq_work); + INIT_WORK(&wl->tx_work, wl1271_tx_work); + INIT_WORK(&wl->recovery_work, wl1271_recovery_work); + INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work); wl->channel = WL1271_DEFAULT_CHANNEL; wl->beacon_int = WL1271_DEFAULT_BEACON_INT; wl->default_key = 0; -- cgit v1.2.3 From d25611da0c75c4b0f72c73d66887d0470aacef40 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Thu, 30 Sep 2010 10:43:27 +0200 Subject: wl1271: Indicate disconnection on hardware failure In the event of a hardware failure, reconfiguring a live connection back with the wl1271 chip does not work as expected. The chip has management features which require setting up the association from scratch to work correctly. To ensure this is done every time, in managed mode, when associated, indicate connection loss to the mac80211 before asking to reconfigure the hardware. Signed-off-by: Juuso Oikarinen Tested-by: Tuomas Katila Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271_main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 760a5814d4a4..d826b6684e39 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -636,6 +636,9 @@ static void wl1271_recovery_work(struct work_struct *work) wl1271_info("Hardware recovery in progress."); + if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) + ieee80211_connection_loss(wl->vif); + /* reboot the chipset */ __wl1271_op_remove_interface(wl); ieee80211_restart_hw(wl->hw); -- cgit v1.2.3 From 644a48607cd40954b6fb095b39a3ccaa0204191e Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Tue, 5 Oct 2010 13:11:56 +0200 Subject: wl1271: Add extended radio parameter initialization Currently a command to initialize extended radio parameter tables in the hardware is missing. Add the initialization Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271_cmd.c | 33 +++++++++++++++++++++++++++++++ drivers/net/wireless/wl12xx/wl1271_cmd.h | 24 ++++++++++++++++------ drivers/net/wireless/wl12xx/wl1271_conf.h | 21 ++++++++++++++++++++ drivers/net/wireless/wl12xx/wl1271_init.c | 4 ++++ drivers/net/wireless/wl12xx/wl1271_main.c | 14 +++++++++++++ 5 files changed, 90 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index 4a56ab05e736..596e333919ae 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -171,6 +171,39 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl) return ret; } +int wl1271_cmd_ext_radio_parms(struct wl1271 *wl) +{ + struct wl1271_ext_radio_parms_cmd *ext_radio_parms; + struct conf_rf_settings *rf = &wl->conf.rf; + int ret; + + if (!wl->nvs) + return -ENODEV; + + ext_radio_parms = kzalloc(sizeof(*ext_radio_parms), GFP_KERNEL); + if (!ext_radio_parms) + return -ENOMEM; + + ext_radio_parms->test.id = TEST_CMD_INI_FILE_RF_EXTENDED_PARAM; + + memcpy(ext_radio_parms->tx_per_channel_power_compensation_2, + rf->tx_per_channel_power_compensation_2, + CONF_TX_PWR_COMPENSATION_LEN_2); + memcpy(ext_radio_parms->tx_per_channel_power_compensation_5, + rf->tx_per_channel_power_compensation_5, + CONF_TX_PWR_COMPENSATION_LEN_5); + + wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_EXT_RADIO_PARAM: ", + ext_radio_parms, sizeof(*ext_radio_parms)); + + ret = wl1271_cmd_test(wl, ext_radio_parms, sizeof(*ext_radio_parms), 0); + if (ret < 0) + wl1271_warning("TEST_CMD_INI_FILE_RF_EXTENDED_PARAM failed"); + + kfree(ext_radio_parms); + return ret; +} + /* * Poll the mailbox event field until any of the bits in the mask is set or a * timeout occurs (WL1271_EVENT_TIMEOUT in msecs) diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.h b/drivers/net/wireless/wl12xx/wl1271_cmd.h index 33b946b4cb07..ed80bec1aea4 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.h +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.h @@ -33,6 +33,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, size_t res_len); int wl1271_cmd_general_parms(struct wl1271 *wl); int wl1271_cmd_radio_parms(struct wl1271 *wl); +int wl1271_cmd_ext_radio_parms(struct wl1271 *wl); int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type); 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); @@ -324,13 +325,14 @@ enum wl1271_channel_tune_bands { WL1271_CHANNEL_TUNE_BAND_4_9 }; -#define WL1271_PD_REFERENCE_POINT_BAND_B_G 0 +#define WL1271_PD_REFERENCE_POINT_BAND_B_G 0 -#define TEST_CMD_P2G_CAL 0x02 -#define TEST_CMD_CHANNEL_TUNE 0x0d -#define TEST_CMD_UPDATE_PD_REFERENCE_POINT 0x1d -#define TEST_CMD_INI_FILE_RADIO_PARAM 0x19 -#define TEST_CMD_INI_FILE_GENERAL_PARAM 0x1E +#define TEST_CMD_P2G_CAL 0x02 +#define TEST_CMD_CHANNEL_TUNE 0x0d +#define TEST_CMD_UPDATE_PD_REFERENCE_POINT 0x1d +#define TEST_CMD_INI_FILE_RADIO_PARAM 0x19 +#define TEST_CMD_INI_FILE_GENERAL_PARAM 0x1E +#define TEST_CMD_INI_FILE_RF_EXTENDED_PARAM 0x26 struct wl1271_general_parms_cmd { struct wl1271_cmd_header header; @@ -363,6 +365,16 @@ struct wl1271_radio_parms_cmd { u8 padding3[2]; } __packed; +struct wl1271_ext_radio_parms_cmd { + struct wl1271_cmd_header header; + + struct wl1271_cmd_test_header test; + + u8 tx_per_channel_power_compensation_2[CONF_TX_PWR_COMPENSATION_LEN_2]; + u8 tx_per_channel_power_compensation_5[CONF_TX_PWR_COMPENSATION_LEN_5]; + u8 padding[3]; +} __packed; + struct wl1271_cmd_cal_channel_tune { struct wl1271_cmd_header header; diff --git a/drivers/net/wireless/wl12xx/wl1271_conf.h b/drivers/net/wireless/wl12xx/wl1271_conf.h index 60c50d1a9835..5f78a6cb1433 100644 --- a/drivers/net/wireless/wl12xx/wl1271_conf.h +++ b/drivers/net/wireless/wl12xx/wl1271_conf.h @@ -1070,6 +1070,26 @@ struct conf_scan_settings { }; +/* these are number of channels on the band divided by two, rounded up */ +#define CONF_TX_PWR_COMPENSATION_LEN_2 7 +#define CONF_TX_PWR_COMPENSATION_LEN_5 18 + +struct conf_rf_settings { + /* + * Per channel power compensation for 2.4GHz + * + * Range: s8 + */ + u8 tx_per_channel_power_compensation_2[CONF_TX_PWR_COMPENSATION_LEN_2]; + + /* + * Per channel power compensation for 5GHz + * + * Range: s8 + */ + u8 tx_per_channel_power_compensation_5[CONF_TX_PWR_COMPENSATION_LEN_5]; +}; + struct conf_drv_settings { struct conf_sg_settings sg; struct conf_rx_settings rx; @@ -1079,6 +1099,7 @@ struct conf_drv_settings { struct conf_pm_config_settings pm_config; struct conf_roam_trigger_settings roam_trigger; struct conf_scan_settings scan; + struct conf_rf_settings rf; }; #endif diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c index 349571fe04b3..8044bba70ee7 100644 --- a/drivers/net/wireless/wl12xx/wl1271_init.c +++ b/drivers/net/wireless/wl12xx/wl1271_init.c @@ -222,6 +222,10 @@ int wl1271_hw_init(struct wl1271 *wl) if (ret < 0) return ret; + ret = wl1271_cmd_ext_radio_parms(wl); + if (ret < 0) + return ret; + /* Template settings */ ret = wl1271_init_templates_config(wl); if (ret < 0) diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index d826b6684e39..48a4b9961ae6 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -242,6 +242,16 @@ static struct conf_drv_settings default_conf = { .max_dwell_time_passive = 60000, .num_probe_reqs = 2, }, + .rf = { + .tx_per_channel_power_compensation_2 = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .tx_per_channel_power_compensation_5 = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + }, }; static void __wl1271_op_remove_interface(struct wl1271 *wl); @@ -357,6 +367,10 @@ static int wl1271_plt_init(struct wl1271 *wl) if (ret < 0) return ret; + ret = wl1271_cmd_ext_radio_parms(wl); + if (ret < 0) + return ret; + ret = wl1271_init_templates_config(wl); if (ret < 0) return ret; -- cgit v1.2.3 From 5082b823f3b0c781fdbc52910af579e940f6f18e Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Tue, 5 Oct 2010 14:58:49 +0300 Subject: wl1271: remove deprecated __attribute__ ((packed)) One __attribute__ ((packed)) has been accidentally introduced in commit be86cbea1e9c3a4dd8faedcfa327495d09fe3531. This patch changes it to __packed. Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271_cmd.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.h b/drivers/net/wireless/wl12xx/wl1271_cmd.h index ed80bec1aea4..a0caf4fc37b1 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.h +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.h @@ -454,6 +454,6 @@ struct wl1271_cmd_set_sta_state { u8 state; u8 padding[3]; -} __attribute__ ((packed)); +} __packed; #endif /* __WL1271_CMD_H__ */ -- cgit v1.2.3 From 4b48e6876b641e1138f37a0fc11fb6a4fc3e24e1 Mon Sep 17 00:00:00 2001 From: ext Anand Gadiyar Date: Fri, 1 Oct 2010 22:33:26 +0200 Subject: omap: zoom2/3: fix build caused by wl1271 support Patch "omap: zoom: add mmc3/wl1271 device support" in the wireless tree still uses .wires in struct omap2_hsmmc_info. .wires has now been replaced with .caps in patch "omap: mmc: extended to pass host capabilities from board file" in the OMAP tree. This causes linux-next as of 20101001 build to break as below. Fix this. CC arch/arm/mach-omap2/board-zoom-peripherals.o arch/arm/mach-omap2/board-zoom-peripherals.c:217: error: unknown field 'wires' specified in initializer make[1]: *** [arch/arm/mach-omap2/board-zoom-peripherals.o] Error 1 make: *** [arch/arm/mach-omap2] Error 2 Signed-off-by: Anand Gadiyar Cc: Ohad Ben-Cohen Cc: Tony Lindgren Acked-by: Tony Lindgren Signed-off-by: Luciano Coelho --- arch/arm/mach-omap2/board-zoom-peripherals.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-omap2/board-zoom-peripherals.c b/arch/arm/mach-omap2/board-zoom-peripherals.c index 6aa0728fa15d..189a6d1600b2 100644 --- a/arch/arm/mach-omap2/board-zoom-peripherals.c +++ b/arch/arm/mach-omap2/board-zoom-peripherals.c @@ -213,7 +213,7 @@ static struct omap2_hsmmc_info mmc[] __initdata = { { .name = "wl1271", .mmc = 3, - .wires = 4, + .caps = MMC_CAP_4_BIT_DATA, .gpio_wp = -EINVAL, .gpio_cd = -EINVAL, .nonremovable = true, -- cgit v1.2.3 From 5a254ffe3ffdfa84fe076009bd8e88da412180d2 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Mon, 27 Sep 2010 09:07:26 -0700 Subject: wireless: Use first phyX name available when registering phy devices. Choose first available phyX name when creating phy devices. This means that reloading a wifi driver will not cause a change in the name of it's phy device. Also, allow users to rename a phy to any un-used name, including phy%d. Signed-off-by: Ben Greear Signed-off-by: John W. Linville --- net/wireless/core.c | 54 +++++++++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/net/wireless/core.c b/net/wireless/core.c index 9c21ebf9780e..1684ad91763c 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -178,26 +178,10 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, char *newname) { struct cfg80211_registered_device *rdev2; - int wiphy_idx, taken = -1, result, digits; + int result; assert_cfg80211_lock(); - /* prohibit calling the thing phy%d when %d is not its number */ - sscanf(newname, PHY_NAME "%d%n", &wiphy_idx, &taken); - if (taken == strlen(newname) && wiphy_idx != rdev->wiphy_idx) { - /* count number of places needed to print wiphy_idx */ - digits = 1; - while (wiphy_idx /= 10) - digits++; - /* - * deny the name if it is phy where is printed - * without leading zeroes. taken == strlen(newname) here - */ - if (taken == strlen(PHY_NAME) + digits) - return -EINVAL; - } - - /* Ignore nop renames */ if (strcmp(newname, dev_name(&rdev->wiphy.dev)) == 0) return 0; @@ -205,7 +189,7 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, /* Ensure another device does not already have this name. */ list_for_each_entry(rdev2, &cfg80211_rdev_list, list) if (strcmp(newname, dev_name(&rdev2->wiphy.dev)) == 0) - return -EINVAL; + return -EEXIST; result = device_rename(&rdev->wiphy.dev, newname); if (result) @@ -320,9 +304,11 @@ static void cfg80211_event_work(struct work_struct *work) struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) { static int wiphy_counter; - - struct cfg80211_registered_device *rdev; + int i; + struct cfg80211_registered_device *rdev, *rdev2; int alloc_size; + char nname[IFNAMSIZ + 1]; + bool found = false; WARN_ON(ops->add_key && (!ops->del_key || !ops->set_default_key)); WARN_ON(ops->auth && (!ops->assoc || !ops->deauth || !ops->disassoc)); @@ -346,16 +332,36 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) if (unlikely(!wiphy_idx_valid(rdev->wiphy_idx))) { wiphy_counter--; + goto too_many_devs; + } + + /* 64k wiphy devices is enough for anyone! */ + for (i = 0; i < 0xFFFF; i++) { + found = false; + snprintf(nname, sizeof(nname)-1, PHY_NAME "%d", i); + nname[sizeof(nname)-1] = 0; + list_for_each_entry(rdev2, &cfg80211_rdev_list, list) + if (strcmp(nname, dev_name(&rdev2->wiphy.dev)) == 0) { + found = true; + break; + } + + if (!found) + break; + } + + if (unlikely(found)) { +too_many_devs: mutex_unlock(&cfg80211_mutex); - /* ugh, wrapped! */ + /* ugh, too many devices already! */ kfree(rdev); return NULL; } - mutex_unlock(&cfg80211_mutex); - /* give it a proper name */ - dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx); + dev_set_name(&rdev->wiphy.dev, "%s", nname); + + mutex_unlock(&cfg80211_mutex); mutex_init(&rdev->mtx); mutex_init(&rdev->devlist_mtx); -- cgit v1.2.3 From 85416a4fa193754ef36e12b20bb02fe661cb7f17 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 2 Oct 2010 13:17:07 +0200 Subject: mac80211: fix rx monitor filter refcounters This patch fixes an refcounting bug. Previously it was possible to corrupt the per-device recv. filter and monitor management counters when: iw dev wlanX set monitor [new flags] was issued on an active monitor interface. Acked-by: Johannes Berg Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 32 ++++++++++++++++++++++++++++++-- net/mac80211/ieee80211_i.h | 2 ++ net/mac80211/iface.c | 44 ++++++++++++++++++++++---------------------- 3 files changed, 54 insertions(+), 24 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index c981604b71e6..9e63fc28f859 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -68,8 +68,36 @@ static int ieee80211_change_iface(struct wiphy *wiphy, params && params->use_4addr >= 0) sdata->u.mgd.use_4addr = params->use_4addr; - if (sdata->vif.type == NL80211_IFTYPE_MONITOR && flags) - sdata->u.mntr_flags = *flags; + if (sdata->vif.type == NL80211_IFTYPE_MONITOR && flags) { + struct ieee80211_local *local = sdata->local; + + if (ieee80211_sdata_running(sdata)) { + /* + * Prohibit MONITOR_FLAG_COOK_FRAMES to be + * changed while the interface is up. + * Else we would need to add a lot of cruft + * to update everything: + * cooked_mntrs, monitor and all fif_* counters + * reconfigure hardware + */ + if ((*flags & MONITOR_FLAG_COOK_FRAMES) != + (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES)) + return -EBUSY; + + ieee80211_adjust_monitor_flags(sdata, -1); + sdata->u.mntr_flags = *flags; + ieee80211_adjust_monitor_flags(sdata, 1); + + ieee80211_configure_filter(local); + } else { + /* + * Because the interface is down, ieee80211_do_stop + * and ieee80211_do_open take care of "everything" + * mentioned in the comment above. + */ + sdata->u.mntr_flags = *flags; + } + } return 0; } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 945fbf29719d..f6a6d78efcf0 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1132,6 +1132,8 @@ void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata); void ieee80211_remove_interfaces(struct ieee80211_local *local); u32 __ieee80211_recalc_idle(struct ieee80211_local *local); void ieee80211_recalc_idle(struct ieee80211_local *local); +void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata, + const int offset); static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata) { diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 66785739dad3..1300e8859ea7 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -148,6 +148,26 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata, return 0; } +void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata, + const int offset) +{ + struct ieee80211_local *local = sdata->local; + u32 flags = sdata->u.mntr_flags; + +#define ADJUST(_f, _s) do { \ + if (flags & MONITOR_FLAG_##_f) \ + local->fif_##_s += offset; \ + } while (0) + + ADJUST(FCSFAIL, fcsfail); + ADJUST(PLCPFAIL, plcpfail); + ADJUST(CONTROL, control); + ADJUST(CONTROL, pspoll); + ADJUST(OTHER_BSS, other_bss); + +#undef ADJUST +} + /* * NOTE: Be very careful when changing this function, it must NOT return * an error on interface type changes that have been pre-checked, so most @@ -240,17 +260,7 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR; } - if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL) - local->fif_fcsfail++; - if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL) - local->fif_plcpfail++; - if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL) { - local->fif_control++; - local->fif_pspoll++; - } - if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) - local->fif_other_bss++; - + ieee80211_adjust_monitor_flags(sdata, 1); ieee80211_configure_filter(local); netif_carrier_on(dev); @@ -477,17 +487,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR; } - if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL) - local->fif_fcsfail--; - if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL) - local->fif_plcpfail--; - if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL) { - local->fif_pspoll--; - local->fif_control--; - } - if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) - local->fif_other_bss--; - + ieee80211_adjust_monitor_flags(sdata, -1); ieee80211_configure_filter(local); break; case NL80211_IFTYPE_MESH_POINT: -- cgit v1.2.3 From 5c895691944862e782c285a871f5d3466797b4ef Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Tue, 28 Sep 2010 23:00:59 +0200 Subject: carl9170: support firmware-based rx filter The hardware rx-filter was essentially disabled, because of a serve, yet unidentifiable problem with iwlagn. Due to these circumstances the driver and mac80211 were left with the job of filtering. This is very unfortunate and has proven to be expensive in terms of latency, memory and load. Therefore the new 1.8.8.3 firmware introduces a flexible filtering infrastructure which allows the driver to offload some of the checks (FCS & PLCP crc check, RA match, control frame filter, etc...) whenever possible. Note: This patch also includes all changes to the shared headers files since the inclusion. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/carl9170/carl9170.h | 2 ++ drivers/net/wireless/ath/carl9170/cmd.h | 10 ++++++++++ drivers/net/wireless/ath/carl9170/fw.c | 7 +++++++ drivers/net/wireless/ath/carl9170/fwcmd.h | 16 +++++++++++++++ drivers/net/wireless/ath/carl9170/fwdesc.h | 6 +++++- drivers/net/wireless/ath/carl9170/hw.h | 3 +++ drivers/net/wireless/ath/carl9170/main.c | 30 ++++++++++++++++++++++++++-- drivers/net/wireless/ath/carl9170/phy.h | 5 +---- drivers/net/wireless/ath/carl9170/version.h | 6 +++--- 9 files changed, 75 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h index 20f2a77e54d2..6cf0c9ef47aa 100644 --- a/drivers/net/wireless/ath/carl9170/carl9170.h +++ b/drivers/net/wireless/ath/carl9170/carl9170.h @@ -279,6 +279,7 @@ struct ar9170 { unsigned int beacon_max_len; bool rx_stream; bool tx_stream; + bool rx_filter; unsigned int mem_blocks; unsigned int mem_block_size; unsigned int rx_size; @@ -314,6 +315,7 @@ struct ar9170 { u64 cur_mc_hash; u32 cur_filter; unsigned int filter_state; + unsigned int rx_filter_caps; bool sniffer_enabled; /* MAC */ diff --git a/drivers/net/wireless/ath/carl9170/cmd.h b/drivers/net/wireless/ath/carl9170/cmd.h index 0fc83d2336fd..f78728c38294 100644 --- a/drivers/net/wireless/ath/carl9170/cmd.h +++ b/drivers/net/wireless/ath/carl9170/cmd.h @@ -59,6 +59,16 @@ static inline int carl9170_flush_cab(struct ar9170 *ar, return carl9170_bcn_ctrl(ar, vif_id, CARL9170_BCN_CTRL_DRAIN, 0, 0); } +static inline int carl9170_rx_filter(struct ar9170 *ar, + const unsigned int _rx_filter) +{ + __le32 rx_filter = cpu_to_le32(_rx_filter); + + return carl9170_exec_cmd(ar, CARL9170_CMD_RX_FILTER, + sizeof(rx_filter), (u8 *)&rx_filter, + 0, NULL); +} + struct carl9170_cmd *carl9170_cmd_buf(struct ar9170 *ar, const enum carl9170_cmd_oids cmd, const unsigned int len); diff --git a/drivers/net/wireless/ath/carl9170/fw.c b/drivers/net/wireless/ath/carl9170/fw.c index 36615462b87a..ae6c006bbc56 100644 --- a/drivers/net/wireless/ath/carl9170/fw.c +++ b/drivers/net/wireless/ath/carl9170/fw.c @@ -257,6 +257,13 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len) if (SUPP(CARL9170FW_USB_UP_STREAM)) ar->fw.rx_stream = true; + if (SUPP(CARL9170FW_RX_FILTER)) { + ar->fw.rx_filter = true; + ar->rx_filter_caps = FIF_FCSFAIL | FIF_PLCPFAIL | + FIF_CONTROL | FIF_PSPOLL | FIF_OTHER_BSS | + FIF_PROMISC_IN_BSS; + } + ar->fw.vif_num = otus_desc->vif_num; ar->fw.cmd_bufs = otus_desc->cmd_bufs; ar->fw.address = le32_to_cpu(otus_desc->fw_address); diff --git a/drivers/net/wireless/ath/carl9170/fwcmd.h b/drivers/net/wireless/ath/carl9170/fwcmd.h index d4a4e1dbef06..d552166db505 100644 --- a/drivers/net/wireless/ath/carl9170/fwcmd.h +++ b/drivers/net/wireless/ath/carl9170/fwcmd.h @@ -53,6 +53,7 @@ enum carl9170_cmd_oids { CARL9170_CMD_REBOOT = 0x04, CARL9170_CMD_BCN_CTRL = 0x05, CARL9170_CMD_READ_TSF = 0x06, + CARL9170_CMD_RX_FILTER = 0x07, /* CAM */ CARL9170_CMD_EKEY = 0x10, @@ -153,6 +154,20 @@ struct carl9170_psm { } __packed; #define CARL9170_PSM_SIZE 4 +struct carl9170_rx_filter_cmd { + __le32 rx_filter; +} __packed; +#define CARL9170_RX_FILTER_CMD_SIZE 4 + +#define CARL9170_RX_FILTER_BAD 0x01 +#define CARL9170_RX_FILTER_OTHER_RA 0x02 +#define CARL9170_RX_FILTER_DECRY_FAIL 0x04 +#define CARL9170_RX_FILTER_CTL_OTHER 0x08 +#define CARL9170_RX_FILTER_CTL_PSPOLL 0x10 +#define CARL9170_RX_FILTER_CTL_BACKR 0x20 +#define CARL9170_RX_FILTER_MGMT 0x40 +#define CARL9170_RX_FILTER_DATA 0x80 + struct carl9170_bcn_ctrl_cmd { __le32 vif_id; __le32 mode; @@ -188,6 +203,7 @@ struct carl9170_cmd { struct carl9170_rf_init rf_init; struct carl9170_psm psm; struct carl9170_bcn_ctrl_cmd bcn_ctrl; + struct carl9170_rx_filter_cmd rx_filter; u8 data[CARL9170_MAX_CMD_PAYLOAD_LEN]; } __packed; } __packed; diff --git a/drivers/net/wireless/ath/carl9170/fwdesc.h b/drivers/net/wireless/ath/carl9170/fwdesc.h index 7cd811708fe5..71f3821f6058 100644 --- a/drivers/net/wireless/ath/carl9170/fwdesc.h +++ b/drivers/net/wireless/ath/carl9170/fwdesc.h @@ -66,6 +66,9 @@ enum carl9170fw_feature_list { /* Firmware PSM support | CARL9170_CMD_PSM */ CARL9170FW_PSM, + /* Firmware RX filter | CARL9170_CMD_RX_FILTER */ + CARL9170FW_RX_FILTER, + /* KEEP LAST */ __CARL9170FW_FEATURE_NUM }; @@ -142,7 +145,7 @@ struct carl9170fw_fix_desc { (sizeof(struct carl9170fw_fix_desc)) #define CARL9170FW_DBG_DESC_MIN_VER 1 -#define CARL9170FW_DBG_DESC_CUR_VER 2 +#define CARL9170FW_DBG_DESC_CUR_VER 3 struct carl9170fw_dbg_desc { struct carl9170fw_desc_head head; @@ -150,6 +153,7 @@ struct carl9170fw_dbg_desc { __le32 counter_addr; __le32 rx_total_addr; __le32 rx_overrun_addr; + __le32 rx_filter; /* Put your debugging definitions here */ } __packed; diff --git a/drivers/net/wireless/ath/carl9170/hw.h b/drivers/net/wireless/ath/carl9170/hw.h index b1292ac5b703..2f471b3f05af 100644 --- a/drivers/net/wireless/ath/carl9170/hw.h +++ b/drivers/net/wireless/ath/carl9170/hw.h @@ -731,6 +731,9 @@ struct ar9170_stream { #define SET_VAL(reg, value, newvalue) \ (value = ((value) & ~reg) | (((newvalue) << reg##_S) & reg)) +#define SET_CONSTVAL(reg, newvalue) \ + (((newvalue) << reg##_S) & reg) + #define MOD_VAL(reg, value, newvalue) \ (((value) & ~reg) | (((newvalue) << reg##_S) & reg)) #endif /* __CARL9170_SHARED_HW_H */ diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 84bd38e9961c..3cc99f3f7ab5 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -380,6 +380,13 @@ static int carl9170_op_start(struct ieee80211_hw *hw) if (err) goto out; + if (ar->fw.rx_filter) { + err = carl9170_rx_filter(ar, CARL9170_RX_FILTER_OTHER_RA | + CARL9170_RX_FILTER_CTL_OTHER | CARL9170_RX_FILTER_BAD); + if (err) + goto out; + } + err = carl9170_write_reg(ar, AR9170_MAC_REG_DMA_TRIGGER, AR9170_DMA_TRIGGER_RXQ); if (err) @@ -840,8 +847,7 @@ static void carl9170_op_configure_filter(struct ieee80211_hw *hw, struct ar9170 *ar = hw->priv; /* mask supported flags */ - *new_flags &= FIF_ALLMULTI | FIF_FCSFAIL | FIF_PLCPFAIL | - FIF_OTHER_BSS | FIF_PROMISC_IN_BSS; + *new_flags &= FIF_ALLMULTI | ar->rx_filter_caps; if (!IS_ACCEPTING_CMD(ar)) return; @@ -867,6 +873,26 @@ static void carl9170_op_configure_filter(struct ieee80211_hw *hw, WARN_ON(carl9170_set_operating_mode(ar)); } + if (ar->fw.rx_filter && changed_flags & ar->rx_filter_caps) { + u32 rx_filter = 0; + + if (!(*new_flags & (FIF_FCSFAIL | FIF_PLCPFAIL))) + rx_filter |= CARL9170_RX_FILTER_BAD; + + if (!(*new_flags & FIF_CONTROL)) + rx_filter |= CARL9170_RX_FILTER_CTL_OTHER; + + if (!(*new_flags & FIF_PSPOLL)) + rx_filter |= CARL9170_RX_FILTER_CTL_PSPOLL; + + if (!(*new_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS))) { + rx_filter |= CARL9170_RX_FILTER_OTHER_RA; + rx_filter |= CARL9170_RX_FILTER_DECRY_FAIL; + } + + WARN_ON(carl9170_rx_filter(ar, rx_filter)); + } + mutex_unlock(&ar->mutex); } diff --git a/drivers/net/wireless/ath/carl9170/phy.h b/drivers/net/wireless/ath/carl9170/phy.h index 53c18d34ffcc..02c34eb4ebde 100644 --- a/drivers/net/wireless/ath/carl9170/phy.h +++ b/drivers/net/wireless/ath/carl9170/phy.h @@ -423,8 +423,8 @@ #define AR9170_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV 0x2000 #define AR9170_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV_S 13 -#define AR9170_PHY_REG_GAIN_2GHZ_CHAIN_2 (AR9170_PHY_REG_BASE + 0x2a0c) #define AR9170_PHY_REG_GAIN_2GHZ (AR9170_PHY_REG_BASE + 0x0a0c) +#define AR9170_PHY_REG_GAIN_2GHZ_CHAIN_2 (AR9170_PHY_REG_BASE + 0x2a0c) #define AR9170_PHY_GAIN_2GHZ_RXTX_MARGIN 0x00fc0000 #define AR9170_PHY_GAIN_2GHZ_RXTX_MARGIN_S 18 #define AR9170_PHY_GAIN_2GHZ_BSW_MARGIN 0x00003c00 @@ -561,7 +561,4 @@ #define AR9170_PHY_CH2_EXT_MINCCA_PWR 0xff800000 #define AR9170_PHY_CH2_EXT_MINCCA_PWR_S 23 -#define REDUCE_CHAIN_0 0x00000050 -#define REDUCE_CHAIN_1 0x00000051 - #endif /* __CARL9170_SHARED_PHY_H */ diff --git a/drivers/net/wireless/ath/carl9170/version.h b/drivers/net/wireless/ath/carl9170/version.h index 0e917f80eab4..ff53f078a0b5 100644 --- a/drivers/net/wireless/ath/carl9170/version.h +++ b/drivers/net/wireless/ath/carl9170/version.h @@ -1,7 +1,7 @@ #ifndef __CARL9170_SHARED_VERSION_H #define __CARL9170_SHARED_VERSION_H #define CARL9170FW_VERSION_YEAR 10 -#define CARL9170FW_VERSION_MONTH 8 -#define CARL9170FW_VERSION_DAY 30 -#define CARL9170FW_VERSION_GIT "1.8.8.1" +#define CARL9170FW_VERSION_MONTH 9 +#define CARL9170FW_VERSION_DAY 28 +#define CARL9170FW_VERSION_GIT "1.8.8.3" #endif /* __CARL9170_SHARED_VERSION_H */ -- cgit v1.2.3 From 35ecfe03d96b7cdaf6e50aba13af37e2c99deb57 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 29 Sep 2010 17:15:26 +0200 Subject: ath9k_htc: remove use of common->ani.noise_floor It is unused aside from a single redundant debug message Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/htc_drv_main.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 5124d04b240b..f12591f5d02a 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -760,23 +760,12 @@ void ath9k_ani_work(struct work_struct *work) ath9k_hw_ani_monitor(ah, ah->curchan); /* Perform calibration if necessary */ - if (longcal || shortcal) { + if (longcal || shortcal) common->ani.caldone = ath9k_hw_calibrate(ah, ah->curchan, common->rx_chainmask, longcal); - if (longcal) - common->ani.noise_floor = - ath9k_hw_getchan_noise(ah, ah->curchan); - - ath_print(common, ATH_DBG_ANI, - " calibrate chan %u/%x nf: %d\n", - ah->curchan->channel, - ah->curchan->channelFlags, - common->ani.noise_floor); - } - ath9k_htc_ps_restore(priv); } -- cgit v1.2.3 From d9891c7804f27c5b0ea9eb51f42bf473b24338a0 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 29 Sep 2010 17:15:27 +0200 Subject: ath9k_hw: keep calibrated noise floor values per channel Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/calib.c | 40 +++++++++++++++++----------------- drivers/net/wireless/ath/ath9k/hw.c | 2 +- drivers/net/wireless/ath/ath9k/hw.h | 2 +- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index 67ee5d735cc1..6351e76792a6 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -346,34 +346,34 @@ bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan) struct ieee80211_channel *c = chan->chan; struct ath9k_hw_cal_data *caldata = ah->caldata; - if (!caldata) - return false; - chan->channelFlags &= (~CHANNEL_CW_INT); if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) { ath_print(common, ATH_DBG_CALIBRATE, "NF did not complete in calibration window\n"); - nf = 0; - caldata->rawNoiseFloor = nf; return false; - } else { - ath9k_hw_do_getnf(ah, nfarray); - ath9k_hw_nf_sanitize(ah, nfarray); - nf = nfarray[0]; - if (ath9k_hw_get_nf_thresh(ah, c->band, &nfThresh) - && nf > nfThresh) { - ath_print(common, ATH_DBG_CALIBRATE, - "noise floor failed detected; " - "detected %d, threshold %d\n", - nf, nfThresh); - chan->channelFlags |= CHANNEL_CW_INT; - } + } + + ath9k_hw_do_getnf(ah, nfarray); + ath9k_hw_nf_sanitize(ah, nfarray); + nf = nfarray[0]; + if (ath9k_hw_get_nf_thresh(ah, c->band, &nfThresh) + && nf > nfThresh) { + ath_print(common, ATH_DBG_CALIBRATE, + "noise floor failed detected; " + "detected %d, threshold %d\n", + nf, nfThresh); + chan->channelFlags |= CHANNEL_CW_INT; + } + + if (!caldata) { + chan->noisefloor = nf; + return false; } h = caldata->nfCalHist; caldata->nfcal_pending = false; ath9k_hw_update_nfcal_hist_buffer(ah, caldata, nfarray); - caldata->rawNoiseFloor = h[0].privNF; + chan->noisefloor = h[0].privNF; return true; } @@ -401,10 +401,10 @@ void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah, s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan) { - if (!ah->caldata || !ah->caldata->rawNoiseFloor) + if (!ah->curchan || !ah->curchan->noisefloor) return ath9k_hw_get_default_nf(ah, chan); - return ah->caldata->rawNoiseFloor; + return ah->curchan->noisefloor; } EXPORT_SYMBOL(ath9k_hw_getchan_noise); diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 25ed65ac992c..1b066043d6cb 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1239,7 +1239,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) return -EIO; - if (curchan && !ah->chip_fullsleep && ah->caldata) + if (curchan && !ah->chip_fullsleep) ath9k_hw_getnf(ah, curchan); ah->caldata = caldata; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index df47f792cf4e..1b6739bd93ff 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -342,7 +342,6 @@ struct ath9k_hw_cal_data { int32_t CalValid; int8_t iCoff; int8_t qCoff; - int16_t rawNoiseFloor; bool paprd_done; bool nfcal_pending; bool nfcal_interference; @@ -356,6 +355,7 @@ struct ath9k_channel { u16 channel; u32 channelFlags; u32 chanmode; + s16 noisefloor; }; #define IS_CHAN_G(_c) ((((_c)->channelFlags & (CHANNEL_G)) == CHANNEL_G) || \ -- cgit v1.2.3 From 4f1a5a4b62c5335aafd5830866320c8918103a3a Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 29 Sep 2010 17:15:28 +0200 Subject: ath9k: do not return default noise floor values via survey Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index a13387882636..fcba402d5a1e 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2004,15 +2004,17 @@ static int ath9k_get_survey(struct ieee80211_hw *hw, int idx, struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_conf *conf = &hw->conf; if (idx != 0) return -ENOENT; survey->channel = conf->channel; - survey->filled = SURVEY_INFO_NOISE_DBM; - survey->noise = common->ani.noise_floor; + survey->filled = 0; + if (ah->curchan && ah->curchan->noisefloor) { + survey->filled |= SURVEY_INFO_NOISE_DBM; + survey->noise = ah->curchan->noisefloor; + } return 0; } -- cgit v1.2.3 From 0bda652300dff8136c9d889f1133462c7c7d332c Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 29 Sep 2010 17:15:29 +0200 Subject: ath9k: remove the noise floor value in the ani struct common->ani.noise_floor is now only used for a similar redundant debug message similar to the one that was removed from ath9k_htc in an earlier patch. Remove it from ath9k as well now. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath.h | 1 - drivers/net/wireless/ath/ath9k/init.c | 1 - drivers/net/wireless/ath/ath9k/main.c | 10 ---------- 3 files changed, 12 deletions(-) diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index dd236c3b52f6..5894fcc2c628 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -35,7 +35,6 @@ static const u8 ath_bcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; struct ath_ani { bool caldone; - int16_t noise_floor; unsigned int longcal_timer; unsigned int shortcal_timer; unsigned int resetcal_timer; diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index de3393867e37..11dc3ac20cd6 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -506,7 +506,6 @@ 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; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index fcba402d5a1e..a801a08c4da2 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -459,16 +459,6 @@ void ath_ani_calibrate(unsigned long data) ah->curchan, common->rx_chainmask, longcal); - - if (longcal) - common->ani.noise_floor = ath9k_hw_getchan_noise(ah, - ah->curchan); - - ath_print(common, ATH_DBG_ANI, - " calibrate chan %u/%x nf: %d\n", - ah->curchan->channel, - ah->curchan->channelFlags, - common->ani.noise_floor); } } -- cgit v1.2.3 From 17e5a8082894a4b66cb69e7ec16074f0f01281e1 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 29 Sep 2010 17:15:30 +0200 Subject: nl80211: allow drivers to indicate whether the survey data channel is in use Some user space applications only want to display survey data for the operating channel, however there is no API to get that yet. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- include/linux/nl80211.h | 2 ++ include/net/cfg80211.h | 2 ++ net/wireless/nl80211.c | 2 ++ 3 files changed, 6 insertions(+) diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index f0518b0278a9..edd21ae6acf7 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -1400,6 +1400,7 @@ enum nl80211_reg_rule_flags { * @__NL80211_SURVEY_INFO_INVALID: attribute number 0 is reserved * @NL80211_SURVEY_INFO_FREQUENCY: center frequency of channel * @NL80211_SURVEY_INFO_NOISE: noise level of channel (u8, dBm) + * @NL80211_SURVEY_INFO_IN_USE: channel is currently being used * @NL80211_SURVEY_INFO_MAX: highest survey info attribute number * currently defined * @__NL80211_SURVEY_INFO_AFTER_LAST: internal use @@ -1408,6 +1409,7 @@ enum nl80211_survey_info { __NL80211_SURVEY_INFO_INVALID, NL80211_SURVEY_INFO_FREQUENCY, NL80211_SURVEY_INFO_NOISE, + NL80211_SURVEY_INFO_IN_USE, /* keep last */ __NL80211_SURVEY_INFO_AFTER_LAST, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index a0613ff62c97..ecc0403b918a 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -293,12 +293,14 @@ struct key_params { * enum survey_info_flags - survey information flags * * @SURVEY_INFO_NOISE_DBM: noise (in dBm) was filled in + * @SURVEY_INFO_IN_USE: channel is currently being used * * Used by the driver to indicate which info in &struct survey_info * it has filled in during the get_survey(). */ enum survey_info_flags { SURVEY_INFO_NOISE_DBM = 1<<0, + SURVEY_INFO_IN_USE = 1<<1, }; /** diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 9c84825803ce..0087c4323c53 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3489,6 +3489,8 @@ static int nl80211_send_survey(struct sk_buff *msg, u32 pid, u32 seq, if (survey->filled & SURVEY_INFO_NOISE_DBM) NLA_PUT_U8(msg, NL80211_SURVEY_INFO_NOISE, survey->noise); + if (survey->filled & SURVEY_INFO_IN_USE) + NLA_PUT_FLAG(msg, NL80211_SURVEY_INFO_IN_USE); nla_nest_end(msg, infoattr); -- cgit v1.2.3 From 39162dbe813a2c90b7b9018a74dc1befb9ff4205 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 29 Sep 2010 19:12:06 +0200 Subject: ath9k: return survey data for all channels instead of just the current one Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index a801a08c4da2..49ea45896b89 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1994,16 +1994,31 @@ static int ath9k_get_survey(struct ieee80211_hw *hw, int idx, struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; struct ath_hw *ah = sc->sc_ah; - struct ieee80211_conf *conf = &hw->conf; + struct ieee80211_supported_band *sband; + struct ath9k_channel *chan; + + sband = hw->wiphy->bands[IEEE80211_BAND_2GHZ]; + if (sband && idx >= sband->n_channels) { + idx -= sband->n_channels; + sband = NULL; + } - if (idx != 0) - return -ENOENT; + if (!sband) + sband = hw->wiphy->bands[IEEE80211_BAND_5GHZ]; - survey->channel = conf->channel; + if (!sband || idx >= sband->n_channels) + return -ENOENT; + + survey->channel = &sband->channels[idx]; + chan = &ah->channels[survey->channel->hw_value]; survey->filled = 0; - if (ah->curchan && ah->curchan->noisefloor) { + + if (chan == ah->curchan) + survey->filled |= SURVEY_INFO_IN_USE; + + if (chan->noisefloor) { survey->filled |= SURVEY_INFO_NOISE_DBM; - survey->noise = ah->curchan->noisefloor; + survey->noise = chan->noisefloor; } return 0; -- cgit v1.2.3 From e32ee80b855914e48b1beb53e13203bc874288d8 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 30 Sep 2010 02:44:56 +0100 Subject: ar9170: Remove MODULE_FIRMWARE references to two-stage firmware The combined firmware ar9170.fw is preferred and supports all devices. References to the older two-stage firmware are unnecessary. Signed-off-by: Ben Hutchings Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ar9170/usb.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c index a93dc18a45c3..5dbb5361fd51 100644 --- a/drivers/net/wireless/ath/ar9170/usb.c +++ b/drivers/net/wireless/ath/ar9170/usb.c @@ -54,8 +54,6 @@ MODULE_AUTHOR("Christian Lamparter "); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Atheros AR9170 802.11n USB wireless"); MODULE_FIRMWARE("ar9170.fw"); -MODULE_FIRMWARE("ar9170-1.fw"); -MODULE_FIRMWARE("ar9170-2.fw"); enum ar9170_requirements { AR9170_REQ_FW1_ONLY = 1, -- cgit v1.2.3 From 4bd530f3ab51c7d656bca29d927a50e5aa87175e Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Thu, 30 Sep 2010 16:27:35 +0200 Subject: iwlwifi: change WARN_ON to IWL_WARN in iwl_mac_add_interface We can start restarting firmware or RF kill switch can be turned on during call to iwl_mac_add_interface(). That are normal working conditions, so do not print call trace, just print simple message instead. Signed-off-by: Stanislaw Gruszka Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 5c568933ce48..b7adcf87280d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2003,7 +2003,8 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) mutex_lock(&priv->mutex); - if (WARN_ON(!iwl_is_ready_rf(priv))) { + if (!iwl_is_ready_rf(priv)) { + IWL_WARN(priv, "Try to add interface when device not ready\n"); err = -EINVAL; goto out; } -- cgit v1.2.3 From 663fcafd977f13e6483f7d4cf2ccdbc4fae81ed0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 30 Sep 2010 21:06:09 +0200 Subject: cfg80211/mac80211: allow management frame TX in AP mode Enable management frame transmission and subscribing to management frames through nl80211 in both cfg80211 and mac80211. Also update a few places that I forgot to update for P2P-client mode previously, and fix a small bug with non-action frames in this API. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 7 ++++++- net/wireless/mlme.c | 54 ++++++++++++++++++++++++++++++++++++++++---------- net/wireless/nl80211.c | 10 ++++++++-- 3 files changed, 57 insertions(+), 14 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 9e63fc28f859..a7a78f28ff6f 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1549,7 +1549,11 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, switch (sdata->vif.type) { case NL80211_IFTYPE_ADHOC: - if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_P2P_GO: + if (!ieee80211_is_action(mgmt->frame_control) || + mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) break; rcu_read_lock(); sta = sta_info_get(sdata, mgmt->da); @@ -1558,6 +1562,7 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, return -ENOLINK; break; case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: break; default: return -EOPNOTSUPP; diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 46f371160896..caf11a427507 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -876,21 +876,53 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, if (ieee80211_is_action(mgmt->frame_control) && mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) { - /* Verify that we are associated with the destination AP */ + int err = 0; + wdev_lock(wdev); - if (!wdev->current_bss || - memcmp(wdev->current_bss->pub.bssid, mgmt->bssid, - ETH_ALEN) != 0 || - ((wdev->iftype == NL80211_IFTYPE_STATION || - wdev->iftype == NL80211_IFTYPE_P2P_CLIENT) && - memcmp(wdev->current_bss->pub.bssid, mgmt->da, - ETH_ALEN) != 0)) { - wdev_unlock(wdev); - return -ENOTCONN; - } + switch (wdev->iftype) { + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + if (!wdev->current_bss) { + err = -ENOTCONN; + break; + } + + if (memcmp(wdev->current_bss->pub.bssid, + mgmt->bssid, ETH_ALEN)) { + err = -ENOTCONN; + break; + } + + /* + * check for IBSS DA must be done by driver as + * cfg80211 doesn't track the stations + */ + if (wdev->iftype == NL80211_IFTYPE_ADHOC) + break; + /* for station, check that DA is the AP */ + if (memcmp(wdev->current_bss->pub.bssid, + mgmt->da, ETH_ALEN)) { + err = -ENOTCONN; + break; + } + break; + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + case NL80211_IFTYPE_AP_VLAN: + if (memcmp(mgmt->bssid, dev->dev_addr, ETH_ALEN)) + err = -EINVAL; + break; + default: + err = -EOPNOTSUPP; + break; + } wdev_unlock(wdev); + + if (err) + return err; } if (memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 0087c4323c53..cbbbe9ab452f 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -4828,7 +4828,10 @@ static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { err = -EOPNOTSUPP; goto out; } @@ -4881,7 +4884,10 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { err = -EOPNOTSUPP; goto out; } -- cgit v1.2.3 From ea229e682633a18c1fa2c408400a6923cfc47910 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 30 Sep 2010 21:21:25 +0200 Subject: cfg80211: remove spurious __KERNEL__ ifdef The net/cfg80211.h header file isn't exported to userspace, so there's no need for any kind of __KERNEL__ protection in it. If it was exported, everything else in it would need protection as well, not just the logging stuff ... Cc:Joe Perches Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/net/cfg80211.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index ecc0403b918a..5f4d8acf7abb 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2553,8 +2553,6 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev, enum nl80211_cqm_rssi_threshold_event rssi_event, gfp_t gfp); -#ifdef __KERNEL__ - /* Logging, debugging and troubleshooting/diagnostic helpers. */ /* wiphy_printk helpers, similar to dev_printk */ @@ -2601,6 +2599,4 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev, #define wiphy_WARN(wiphy, format, args...) \ WARN(1, "wiphy: %s\n" format, wiphy_name(wiphy), ##args); -#endif - #endif /* __NET_CFG80211_H */ -- cgit v1.2.3 From b1ae1edf9e9872d3aa657cc34ae40c9aadfbc72f Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Thu, 30 Sep 2010 12:22:58 -0700 Subject: ath5k: Allow ath5k to support virtual STA and AP interfaces. Support up to 4 virtual APs and as many virtual STA interfaces as desired. This patch is ported forward from a patch that Patrick McHardy did for me against 2.6.31. Signed-off-by: Ben Greear Acked-by: Bruno Randolf Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/base.c | 275 +++++++++++++++++++++++++++------ drivers/net/wireless/ath/ath5k/base.h | 19 ++- drivers/net/wireless/ath/ath5k/reset.c | 4 +- 3 files changed, 249 insertions(+), 49 deletions(-) diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 94cc3354f3a6..2ed327a8d690 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -52,6 +52,7 @@ #include #include #include +#include #include @@ -509,8 +510,71 @@ ath5k_setcurmode(struct ath5k_softc *sc, unsigned int mode) } } +struct ath_vif_iter_data { + const u8 *hw_macaddr; + u8 mask[ETH_ALEN]; + u8 active_mac[ETH_ALEN]; /* first active MAC */ + bool need_set_hw_addr; + bool found_active; + bool any_assoc; +}; + +static void ath_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) +{ + struct ath_vif_iter_data *iter_data = data; + int i; + + if (iter_data->hw_macaddr) + for (i = 0; i < ETH_ALEN; i++) + iter_data->mask[i] &= + ~(iter_data->hw_macaddr[i] ^ mac[i]); + + if (!iter_data->found_active) { + iter_data->found_active = true; + memcpy(iter_data->active_mac, mac, ETH_ALEN); + } + + if (iter_data->need_set_hw_addr && iter_data->hw_macaddr) + if (compare_ether_addr(iter_data->hw_macaddr, mac) == 0) + iter_data->need_set_hw_addr = false; + + if (!iter_data->any_assoc) { + struct ath5k_vif *avf = (void *)vif->drv_priv; + if (avf->assoc) + iter_data->any_assoc = true; + } +} + +void ath5k_update_bssid_mask(struct ath5k_softc *sc, struct ieee80211_vif *vif) +{ + struct ath_common *common = ath5k_hw_common(sc->ah); + struct ath_vif_iter_data iter_data; + + /* + * Use the hardware MAC address as reference, the hardware uses it + * together with the BSSID mask when matching addresses. + */ + iter_data.hw_macaddr = common->macaddr; + memset(&iter_data.mask, 0xff, ETH_ALEN); + iter_data.found_active = false; + iter_data.need_set_hw_addr = true; + + if (vif) + ath_vif_iter(&iter_data, vif->addr, vif); + + /* Get list of all active MAC addresses */ + ieee80211_iterate_active_interfaces_atomic(sc->hw, ath_vif_iter, + &iter_data); + memcpy(sc->bssidmask, iter_data.mask, ETH_ALEN); + + if (iter_data.need_set_hw_addr && iter_data.found_active) + ath5k_hw_set_lladdr(sc->ah, iter_data.active_mac); + + ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask); +} + static void -ath5k_mode_setup(struct ath5k_softc *sc) +ath5k_mode_setup(struct ath5k_softc *sc, struct ieee80211_vif *vif) { struct ath5k_hw *ah = sc->ah; u32 rfilt; @@ -520,7 +584,7 @@ ath5k_mode_setup(struct ath5k_softc *sc) ath5k_hw_set_rx_filter(ah, rfilt); if (ath5k_hw_hasbssidmask(ah)) - ath5k_hw_set_bssid_mask(ah, sc->bssidmask); + ath5k_update_bssid_mask(sc, vif); /* configure operational mode */ ath5k_hw_set_opmode(ah, sc->opmode); @@ -698,13 +762,13 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, flags |= AR5K_TXDESC_RTSENA; cts_rate = ieee80211_get_rts_cts_rate(sc->hw, info)->hw_value; duration = le16_to_cpu(ieee80211_rts_duration(sc->hw, - sc->vif, pktlen, info)); + info->control.vif, pktlen, info)); } if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { flags |= AR5K_TXDESC_CTSENA; cts_rate = ieee80211_get_rts_cts_rate(sc->hw, info)->hw_value; duration = le16_to_cpu(ieee80211_ctstoself_duration(sc->hw, - sc->vif, pktlen, info)); + info->control.vif, pktlen, info)); } ret = ah->ah_setup_tx_desc(ah, ds, pktlen, ieee80211_get_hdrlen_from_skb(skb), padsize, @@ -806,10 +870,13 @@ ath5k_desc_alloc(struct ath5k_softc *sc, struct pci_dev *pdev) list_add_tail(&bf->list, &sc->txbuf); } - /* beacon buffer */ - bf->desc = ds; - bf->daddr = da; - sc->bbuf = bf; + /* beacon buffers */ + INIT_LIST_HEAD(&sc->bcbuf); + for (i = 0; i < ATH_BCBUF; i++, bf++, ds++, da += sizeof(*ds)) { + bf->desc = ds; + bf->daddr = da; + list_add_tail(&bf->list, &sc->bcbuf); + } return 0; err_free: @@ -824,11 +891,12 @@ ath5k_desc_free(struct ath5k_softc *sc, struct pci_dev *pdev) { struct ath5k_buf *bf; - ath5k_txbuf_free_skb(sc, sc->bbuf); list_for_each_entry(bf, &sc->txbuf, list) ath5k_txbuf_free_skb(sc, bf); list_for_each_entry(bf, &sc->rxbuf, list) ath5k_rxbuf_free_skb(sc, bf); + list_for_each_entry(bf, &sc->bcbuf, list) + ath5k_txbuf_free_skb(sc, bf); /* Free memory associated with all descriptors */ pci_free_consistent(pdev, sc->desc_len, sc->desc, sc->desc_daddr); @@ -837,7 +905,6 @@ ath5k_desc_free(struct ath5k_softc *sc, struct pci_dev *pdev) kfree(sc->bufptr); sc->bufptr = NULL; - sc->bbuf = NULL; } @@ -1083,7 +1150,7 @@ ath5k_rx_start(struct ath5k_softc *sc) spin_unlock_bh(&sc->rxbuflock); ath5k_hw_start_rx_dma(ah); /* enable recv descriptors */ - ath5k_mode_setup(sc); /* set filters, etc. */ + ath5k_mode_setup(sc, NULL); /* set filters, etc. */ ath5k_hw_start_rx_pcu(ah); /* re-enable PCU/DMA engine */ return 0; @@ -1750,6 +1817,7 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { int ret; struct ath5k_softc *sc = hw->priv; + struct ath5k_vif *avf = (void *)vif->drv_priv; struct sk_buff *skb; if (WARN_ON(!vif)) { @@ -1766,11 +1834,11 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif) ath5k_debug_dump_skb(sc, skb, "BC ", 1); - ath5k_txbuf_free_skb(sc, sc->bbuf); - sc->bbuf->skb = skb; - ret = ath5k_beacon_setup(sc, sc->bbuf); + ath5k_txbuf_free_skb(sc, avf->bbuf); + avf->bbuf->skb = skb; + ret = ath5k_beacon_setup(sc, avf->bbuf); if (ret) - sc->bbuf->skb = NULL; + avf->bbuf->skb = NULL; out: return ret; } @@ -1786,16 +1854,14 @@ out: static void ath5k_beacon_send(struct ath5k_softc *sc) { - struct ath5k_buf *bf = sc->bbuf; struct ath5k_hw *ah = sc->ah; + struct ieee80211_vif *vif; + struct ath5k_vif *avf; + struct ath5k_buf *bf; struct sk_buff *skb; ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, "in beacon_send\n"); - if (unlikely(bf->skb == NULL || sc->opmode == NL80211_IFTYPE_STATION)) { - ATH5K_WARN(sc, "bf=%p bf_skb=%p\n", bf, bf ? bf->skb : NULL); - return; - } /* * Check if the previous beacon has gone out. If * not, don't don't try to post another: skip this @@ -1824,6 +1890,28 @@ ath5k_beacon_send(struct ath5k_softc *sc) sc->bmisscount = 0; } + if (sc->opmode == NL80211_IFTYPE_AP && sc->num_ap_vifs > 1) { + u64 tsf = ath5k_hw_get_tsf64(ah); + u32 tsftu = TSF_TO_TU(tsf); + int slot = ((tsftu % sc->bintval) * ATH_BCBUF) / sc->bintval; + vif = sc->bslot[(slot + 1) % ATH_BCBUF]; + ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, + "tsf %llx tsftu %x intval %u slot %u vif %p\n", + (unsigned long long)tsf, tsftu, sc->bintval, slot, vif); + } else /* only one interface */ + vif = sc->bslot[0]; + + if (!vif) + return; + + avf = (void *)vif->drv_priv; + bf = avf->bbuf; + if (unlikely(bf->skb == NULL || sc->opmode == NL80211_IFTYPE_STATION || + sc->opmode == NL80211_IFTYPE_MONITOR)) { + ATH5K_WARN(sc, "bf=%p bf_skb=%p\n", bf, bf ? bf->skb : NULL); + return; + } + /* * Stop any current dma and put the new frame on the queue. * This should never fail since we check above that no frames @@ -1836,17 +1924,17 @@ ath5k_beacon_send(struct ath5k_softc *sc) /* refresh the beacon for AP mode */ if (sc->opmode == NL80211_IFTYPE_AP) - ath5k_beacon_update(sc->hw, sc->vif); + ath5k_beacon_update(sc->hw, vif); ath5k_hw_set_txdp(ah, sc->bhalq, bf->daddr); ath5k_hw_start_tx_dma(ah, sc->bhalq); ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "TXDP[%u] = %llx (%p)\n", sc->bhalq, (unsigned long long)bf->daddr, bf->desc); - skb = ieee80211_get_buffered_bc(sc->hw, sc->vif); + skb = ieee80211_get_buffered_bc(sc->hw, vif); while (skb) { ath5k_tx_queue(sc->hw, skb, sc->cabq); - skb = ieee80211_get_buffered_bc(sc->hw, sc->vif); + skb = ieee80211_get_buffered_bc(sc->hw, vif); } sc->bsent++; @@ -1876,6 +1964,12 @@ ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf) u64 hw_tsf; intval = sc->bintval & AR5K_BEACON_PERIOD; + if (sc->opmode == NL80211_IFTYPE_AP && sc->num_ap_vifs > 1) { + intval /= ATH_BCBUF; /* staggered multi-bss beacons */ + if (intval < 15) + ATH5K_WARN(sc, "intval %u is too low, min 15\n", + intval); + } if (WARN_ON(!intval)) return; @@ -2323,6 +2417,10 @@ ath5k_init(struct ath5k_softc *sc) ath_hw_keyreset(common, (u16) i); ath5k_hw_set_ack_bitrate_high(ah, true); + + for (i = 0; i < ARRAY_SIZE(sc->bslot); i++) + sc->bslot[i] = NULL; + ret = 0; done: mmiowb(); @@ -2382,7 +2480,6 @@ ath5k_stop_hw(struct ath5k_softc *sc) ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "putting device to sleep\n"); } - ath5k_txbuf_free_skb(sc, sc->bbuf); mmiowb(); mutex_unlock(&sc->lock); @@ -2587,9 +2684,9 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) } SET_IEEE80211_PERM_ADDR(hw, mac); + memcpy(&sc->lladdr, mac, ETH_ALEN); /* All MAC address bits matter for ACKs */ - memcpy(sc->bssidmask, ath_bcast_mac, ETH_ALEN); - ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask); + ath5k_update_bssid_mask(sc, NULL); regulatory->current_rd = ah->ah_capabilities.cap_eeprom.ee_regdomain; ret = ath_regd_init(regulatory, hw->wiphy, ath5k_reg_notifier); @@ -2687,31 +2784,91 @@ static int ath5k_add_interface(struct ieee80211_hw *hw, { struct ath5k_softc *sc = hw->priv; int ret; + struct ath5k_hw *ah = sc->ah; + struct ath5k_vif *avf = (void *)vif->drv_priv; mutex_lock(&sc->lock); - if (sc->vif) { - ret = 0; + + if ((vif->type == NL80211_IFTYPE_AP || + vif->type == NL80211_IFTYPE_ADHOC) + && (sc->num_ap_vifs + sc->num_adhoc_vifs) >= ATH_BCBUF) { + ret = -ELNRNG; goto end; } - sc->vif = vif; + /* Don't allow other interfaces if one ad-hoc is configured. + * TODO: Fix the problems with ad-hoc and multiple other interfaces. + * We would need to operate the HW in ad-hoc mode to allow TSF updates + * for the IBSS, but this breaks with additional AP or STA interfaces + * at the moment. */ + if (sc->num_adhoc_vifs || + (sc->nvifs && vif->type == NL80211_IFTYPE_ADHOC)) { + ATH5K_ERR(sc, "Only one single ad-hoc interface is allowed.\n"); + ret = -ELNRNG; + goto end; + } switch (vif->type) { case NL80211_IFTYPE_AP: case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_MESH_POINT: - sc->opmode = vif->type; + avf->opmode = vif->type; break; default: ret = -EOPNOTSUPP; goto end; } - ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "add interface mode %d\n", sc->opmode); + sc->nvifs++; + ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "add interface mode %d\n", avf->opmode); + /* Assign the vap/adhoc to a beacon xmit slot. */ + if ((avf->opmode == NL80211_IFTYPE_AP) || + (avf->opmode == NL80211_IFTYPE_ADHOC)) { + int slot; + + WARN_ON(list_empty(&sc->bcbuf)); + avf->bbuf = list_first_entry(&sc->bcbuf, struct ath5k_buf, + list); + list_del(&avf->bbuf->list); + + avf->bslot = 0; + for (slot = 0; slot < ATH_BCBUF; slot++) { + if (!sc->bslot[slot]) { + avf->bslot = slot; + break; + } + } + BUG_ON(sc->bslot[avf->bslot] != NULL); + sc->bslot[avf->bslot] = vif; + if (avf->opmode == NL80211_IFTYPE_AP) + sc->num_ap_vifs++; + else + sc->num_adhoc_vifs++; + } + + /* Set combined mode - when APs are configured, operate in AP mode. + * Otherwise use the mode of the new interface. This can currently + * only deal with combinations of APs and STAs. Only one ad-hoc + * interfaces is allowed above. + */ + if (sc->num_ap_vifs) + sc->opmode = NL80211_IFTYPE_AP; + else + sc->opmode = vif->type; + + ath5k_hw_set_opmode(ah, sc->opmode); + + /* Any MAC address is fine, all others are included through the + * filter. + */ + memcpy(&sc->lladdr, vif->addr, ETH_ALEN); ath5k_hw_set_lladdr(sc->ah, vif->addr); - ath5k_mode_setup(sc); + + memcpy(&avf->lladdr, vif->addr, ETH_ALEN); + + ath5k_mode_setup(sc, vif); ret = 0; end: @@ -2724,15 +2881,29 @@ ath5k_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct ath5k_softc *sc = hw->priv; - u8 mac[ETH_ALEN] = {}; + struct ath5k_vif *avf = (void *)vif->drv_priv; + unsigned int i; mutex_lock(&sc->lock); - if (sc->vif != vif) - goto end; + sc->nvifs--; + + if (avf->bbuf) { + ath5k_txbuf_free_skb(sc, avf->bbuf); + list_add_tail(&avf->bbuf->list, &sc->bcbuf); + for (i = 0; i < ATH_BCBUF; i++) { + if (sc->bslot[i] == vif) { + sc->bslot[i] = NULL; + break; + } + } + avf->bbuf = NULL; + } + if (avf->opmode == NL80211_IFTYPE_AP) + sc->num_ap_vifs--; + else if (avf->opmode == NL80211_IFTYPE_ADHOC) + sc->num_adhoc_vifs--; - ath5k_hw_set_lladdr(sc->ah, mac); - sc->vif = NULL; -end: + ath5k_update_bssid_mask(sc, NULL); mutex_unlock(&sc->lock); } @@ -2815,6 +2986,19 @@ static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw, return ((u64)(mfilt[1]) << 32) | mfilt[0]; } +static bool ath_any_vif_assoc(struct ath5k_softc *sc) +{ + struct ath_vif_iter_data iter_data; + iter_data.hw_macaddr = NULL; + iter_data.any_assoc = false; + iter_data.need_set_hw_addr = false; + iter_data.found_active = true; + + ieee80211_iterate_active_interfaces_atomic(sc->hw, ath_vif_iter, + &iter_data); + return iter_data.any_assoc; +} + #define SUPPORTED_FIF_FLAGS \ FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | \ FIF_PLCPFAIL | FIF_CONTROL | FIF_OTHER_BSS | \ @@ -2885,7 +3069,7 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw, /* FIF_BCN_PRBRESP_PROMISC really means to enable beacons * and probes for any BSSID */ - if (*new_flags & FIF_BCN_PRBRESP_PROMISC) + if ((*new_flags & FIF_BCN_PRBRESP_PROMISC) || (sc->nvifs > 1)) rfilt |= AR5K_RX_FILTER_BEACON; /* FIF_CONTROL doc says that if FIF_PROMISC_IN_BSS is not @@ -3070,14 +3254,13 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_bss_conf *bss_conf, u32 changes) { + struct ath5k_vif *avf = (void *)vif->drv_priv; struct ath5k_softc *sc = hw->priv; struct ath5k_hw *ah = sc->ah; struct ath_common *common = ath5k_hw_common(ah); unsigned long flags; mutex_lock(&sc->lock); - if (WARN_ON(sc->vif != vif)) - goto unlock; if (changes & BSS_CHANGED_BSSID) { /* Cache for later use during resets */ @@ -3091,7 +3274,12 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw, sc->bintval = bss_conf->beacon_int; if (changes & BSS_CHANGED_ASSOC) { - sc->assoc = bss_conf->assoc; + avf->assoc = bss_conf->assoc; + if (bss_conf->assoc) + sc->assoc = bss_conf->assoc; + else + sc->assoc = ath_any_vif_assoc(sc); + if (sc->opmode == NL80211_IFTYPE_STATION) set_beacon_filter(hw, sc->assoc); ath5k_hw_set_ledstate(sc->ah, sc->assoc ? @@ -3119,7 +3307,6 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw, BSS_CHANGED_BEACON_INT)) ath5k_beacon_config(sc); - unlock: mutex_unlock(&sc->lock); } @@ -3394,6 +3581,8 @@ ath5k_pci_probe(struct pci_dev *pdev, hw->max_rate_tries = 11; } + hw->vif_data_size = sizeof(struct ath5k_vif); + /* Finish private driver data initialization */ ret = ath5k_attach(pdev, hw); if (ret) diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h index 7f9d0d3018e8..b9f6d13b7675 100644 --- a/drivers/net/wireless/ath/ath5k/base.h +++ b/drivers/net/wireless/ath/ath5k/base.h @@ -58,8 +58,7 @@ #define ATH_RXBUF 40 /* number of RX buffers */ #define ATH_TXBUF 200 /* number of TX buffers */ -#define ATH_BCBUF 1 /* number of beacon buffers */ - +#define ATH_BCBUF 4 /* number of beacon buffers */ #define ATH5K_TXQ_LEN_MAX (ATH_TXBUF / 4) /* bufs per queue */ #define ATH5K_TXQ_LEN_LOW (ATH5K_TXQ_LEN_MAX / 2) /* low mark */ @@ -152,6 +151,14 @@ struct ath5k_statistics { #define ATH_CHAN_MAX (14+14+14+252+20) #endif +struct ath5k_vif { + bool assoc; /* are we associated or not */ + enum nl80211_iftype opmode; + int bslot; + struct ath5k_buf *bbuf; /* beacon buffer */ + u8 lladdr[ETH_ALEN]; +}; + /* Software Carrier, keeps track of the driver state * associated with an instance of a device */ struct ath5k_softc { @@ -188,10 +195,11 @@ struct ath5k_softc { unsigned int curmode; /* current phy mode */ struct ieee80211_channel *curchan; /* current h/w channel */ - struct ieee80211_vif *vif; + u16 nvifs; enum ath5k_int imask; /* interrupt mask copy */ + u8 lladdr[ETH_ALEN]; u8 bssidmask[ETH_ALEN]; unsigned int led_pin, /* GPIO pin for driving LED */ @@ -219,7 +227,10 @@ struct ath5k_softc { spinlock_t block; /* protects beacon */ struct tasklet_struct beacontq; /* beacon intr tasklet */ - struct ath5k_buf *bbuf; /* beacon buffer */ + struct list_head bcbuf; /* beacon buffer */ + struct ieee80211_vif *bslot[ATH_BCBUF]; + u16 num_ap_vifs; + u16 num_adhoc_vifs; unsigned int bhalq, /* SW q for outgoing beacons */ bmisscount, /* missed beacon transmits */ bintval, /* beacon interval in TU */ diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index 58912cd762d9..5b179d01f97d 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -167,7 +167,7 @@ static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah, * ieee80211_duration() for a brief description of * what rate we should choose to TX ACKs. */ tx_time = le16_to_cpu(ieee80211_generic_frame_duration(sc->hw, - sc->vif, 10, rate)); + NULL, 10, rate)); ath5k_hw_reg_write(ah, tx_time, reg); @@ -1060,7 +1060,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, * XXX: rethink this after new mode changes to * mac80211 are integrated */ if (ah->ah_version == AR5K_AR5212 && - ah->ah_sc->vif != NULL) + ah->ah_sc->nvifs) ath5k_hw_write_rate_duration(ah, mode); /* -- cgit v1.2.3 From 2234362c427e2ef667595b9b81c0125003ac5607 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 30 Sep 2010 22:17:43 +0200 Subject: cfg80211: fix locking Add missing unlocking of the wiphy in set_channel, and don't try to unlock a non-existing wiphy in set_cqm. Cc: stable@kernel.org [2.6.35+] Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/nl80211.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index cbbbe9ab452f..21061ccee557 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -821,11 +821,13 @@ static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info) result = get_rdev_dev_by_info_ifindex(info, &rdev, &netdev); if (result) - goto unlock; + goto unlock_rtnl; result = __nl80211_set_channel(rdev, netdev->ieee80211_ptr, info); - unlock: + dev_put(netdev); + cfg80211_unlock_rdev(rdev); + unlock_rtnl: rtnl_unlock(); return result; @@ -5097,7 +5099,7 @@ static int nl80211_set_cqm_rssi(struct genl_info *info, err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) - goto unlock_rdev; + goto unlock_rtnl; wdev = dev->ieee80211_ptr; @@ -5115,9 +5117,10 @@ static int nl80211_set_cqm_rssi(struct genl_info *info, err = rdev->ops->set_cqm_rssi_config(wdev->wiphy, dev, threshold, hysteresis); -unlock_rdev: + unlock_rdev: cfg80211_unlock_rdev(rdev); dev_put(dev); + unlock_rtnl: rtnl_unlock(); return err; -- cgit v1.2.3 From f209f5298217cf54cd5a9163e18b08d093faf8d9 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 1 Oct 2010 01:06:53 +0200 Subject: ath9k: fix channel flag / regd issues with multiple cards Since the regulatory code touches the channel array, it needs to be copied for each device instance. That way the original channel array can also be made const. Signed-off-by: Felix Fietkau Cc: stable@kernel.org [all] Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/init.c | 37 +++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 11dc3ac20cd6..282bb482424f 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -56,7 +56,7 @@ MODULE_PARM_DESC(blink, "Enable LED blink on activity"); * 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[] = { +static const struct ieee80211_channel ath9k_2ghz_chantable[] = { CHAN2G(2412, 0), /* Channel 1 */ CHAN2G(2417, 1), /* Channel 2 */ CHAN2G(2422, 2), /* Channel 3 */ @@ -77,7 +77,7 @@ static struct ieee80211_channel ath9k_2ghz_chantable[] = { * 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[] = { +static const struct ieee80211_channel ath9k_5ghz_chantable[] = { /* _We_ call this UNII 1 */ CHAN5G(5180, 14), /* Channel 36 */ CHAN5G(5200, 15), /* Channel 40 */ @@ -477,10 +477,17 @@ err: return -EIO; } -static void ath9k_init_channels_rates(struct ath_softc *sc) +static int ath9k_init_channels_rates(struct ath_softc *sc) { + void *channels; + if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes)) { - sc->sbands[IEEE80211_BAND_2GHZ].channels = ath9k_2ghz_chantable; + channels = kmemdup(ath9k_2ghz_chantable, + sizeof(ath9k_2ghz_chantable), GFP_KERNEL); + if (!channels) + return -ENOMEM; + + sc->sbands[IEEE80211_BAND_2GHZ].channels = channels; sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; sc->sbands[IEEE80211_BAND_2GHZ].n_channels = ARRAY_SIZE(ath9k_2ghz_chantable); @@ -490,7 +497,15 @@ static void ath9k_init_channels_rates(struct ath_softc *sc) } if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) { - sc->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_chantable; + channels = kmemdup(ath9k_5ghz_chantable, + sizeof(ath9k_5ghz_chantable), GFP_KERNEL); + if (!channels) { + if (sc->sbands[IEEE80211_BAND_2GHZ].channels) + kfree(sc->sbands[IEEE80211_BAND_2GHZ].channels); + return -ENOMEM; + } + + sc->sbands[IEEE80211_BAND_5GHZ].channels = channels; sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ; sc->sbands[IEEE80211_BAND_5GHZ].n_channels = ARRAY_SIZE(ath9k_5ghz_chantable); @@ -499,6 +514,7 @@ static void ath9k_init_channels_rates(struct ath_softc *sc) sc->sbands[IEEE80211_BAND_5GHZ].n_bitrates = ARRAY_SIZE(ath9k_legacy_rates) - 4; } + return 0; } static void ath9k_init_misc(struct ath_softc *sc) @@ -594,8 +610,11 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, if (ret) goto err_btcoex; + ret = ath9k_init_channels_rates(sc); + if (ret) + goto err_btcoex; + ath9k_init_crypto(sc); - ath9k_init_channels_rates(sc); ath9k_init_misc(sc); return 0; @@ -755,6 +774,12 @@ static void ath9k_deinit_softc(struct ath_softc *sc) { int i = 0; + if (sc->sbands[IEEE80211_BAND_2GHZ].channels) + kfree(sc->sbands[IEEE80211_BAND_2GHZ].channels); + + if (sc->sbands[IEEE80211_BAND_5GHZ].channels) + kfree(sc->sbands[IEEE80211_BAND_5GHZ].channels); + 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); -- cgit v1.2.3 From 9094a086f24bfb1d1f244883020c4d9453ffc0b6 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 1 Oct 2010 01:46:13 +0200 Subject: ath9k_hw: remove some useless calibration data The percal struct and bitmask for the initial DC calibration are not used anywhere, so they can be removed. Signed-off-by: Felix Fietkau --- drivers/net/wireless/ath/ath9k/ar9002_calib.c | 16 ---------------- drivers/net/wireless/ath/ath9k/ar9003_calib.c | 1 - drivers/net/wireless/ath/ath9k/calib.h | 1 - drivers/net/wireless/ath/ath9k/hw.h | 1 - 4 files changed, 19 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c index d7d1d55362e6..f2da119bbf02 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c @@ -45,11 +45,6 @@ static void ar9002_hw_setup_calibration(struct ath_hw *ah, ath_print(common, ATH_DBG_CALIBRATE, "starting ADC DC Calibration\n"); break; - case ADC_DC_INIT_CAL: - REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_INIT); - ath_print(common, ATH_DBG_CALIBRATE, - "starting Init ADC DC Calibration\n"); - break; case TEMP_COMP_CAL: break; /* Not supported */ } @@ -950,13 +945,6 @@ static const struct ath9k_percal_data adc_dc_cal_single_sample = { ar9002_hw_adc_dccal_collect, ar9002_hw_adc_dccal_calibrate }; -static const struct ath9k_percal_data adc_init_dc_cal = { - ADC_DC_INIT_CAL, - MIN_CAL_SAMPLES, - INIT_LOG_COUNT, - ar9002_hw_adc_dccal_collect, - ar9002_hw_adc_dccal_calibrate -}; static void ar9002_hw_init_cal_settings(struct ath_hw *ah) { @@ -973,16 +961,12 @@ static void ar9002_hw_init_cal_settings(struct ath_hw *ah) &adc_gain_cal_single_sample; ah->adcdc_caldata.calData = &adc_dc_cal_single_sample; - ah->adcdc_calinitdata.calData = - &adc_init_dc_cal; } else { ah->iq_caldata.calData = &iq_cal_multi_sample; ah->adcgain_caldata.calData = &adc_gain_cal_multi_sample; ah->adcdc_caldata.calData = &adc_dc_cal_multi_sample; - ah->adcdc_calinitdata.calData = - &adc_init_dc_cal; } ah->supp_cals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL; } diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index 4674ea8c9c99..b41f5cda824b 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -50,7 +50,6 @@ static void ar9003_hw_setup_calibration(struct ath_hw *ah, ath_print(common, ATH_DBG_CALIBRATE, "starting Temperature Compensation Calibration\n"); break; - case ADC_DC_INIT_CAL: case ADC_GAIN_CAL: case ADC_DC_CAL: /* Not yet */ diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h index 5b053a6260b2..1fa56c91a894 100644 --- a/drivers/net/wireless/ath/ath9k/calib.h +++ b/drivers/net/wireless/ath/ath9k/calib.h @@ -59,7 +59,6 @@ struct ar5416IniArray { } while (0) enum ath9k_cal_types { - ADC_DC_INIT_CAL = 0x1, ADC_GAIN_CAL = 0x2, ADC_DC_CAL = 0x4, IQ_MISMATCH_CAL = 0x8, diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 1b6739bd93ff..235cb5357a22 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -692,7 +692,6 @@ struct ath_hw { enum ath9k_cal_types supp_cals; struct ath9k_cal_list iq_caldata; struct ath9k_cal_list adcgain_caldata; - struct ath9k_cal_list adcdc_calinitdata; struct ath9k_cal_list adcdc_caldata; struct ath9k_cal_list tempCompCalData; struct ath9k_cal_list *cal_list; -- cgit v1.2.3 From 8e0167a4bdce4adcea64d2197378673d332cda28 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Fri, 1 Oct 2010 15:25:05 +0530 Subject: ath9k : Fix for displaying the channel number In the ath9k debugging feature 'wiphy' the current channel used by the station is incorrectly displayed.This is because the channels available are sequentially mapped from numbers 0 to 37.This mapping cannot be changed as the channel number is also used as an array index This fix solves the above problem by calculating the channel number from center frequency. Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/debug.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index d65a896a421d..7a5932a6691a 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -488,6 +488,8 @@ static ssize_t read_file_wiphy(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct ath_softc *sc = file->private_data; + struct ath_wiphy *aphy = sc->pri_wiphy; + struct ieee80211_channel *chan = aphy->hw->conf.channel; char buf[512]; unsigned int len = 0; int i; @@ -498,7 +500,8 @@ static ssize_t read_file_wiphy(struct file *file, char __user *user_buf, "primary: %s (%s chan=%d ht=%d)\n", wiphy_name(sc->pri_wiphy->hw->wiphy), ath_wiphy_state_str(sc->pri_wiphy->state), - sc->pri_wiphy->chan_idx, sc->pri_wiphy->chan_is_ht); + ieee80211_frequency_to_channel(chan->center_freq), + aphy->chan_is_ht); put_unaligned_le32(REG_READ_D(sc->sc_ah, AR_STA_ID0), addr); put_unaligned_le16(REG_READ_D(sc->sc_ah, AR_STA_ID1) & 0xffff, addr + 4); @@ -545,11 +548,13 @@ static ssize_t read_file_wiphy(struct file *file, char __user *user_buf, struct ath_wiphy *aphy = sc->sec_wiphy[i]; if (aphy == NULL) continue; + chan = aphy->hw->conf.channel; len += snprintf(buf + len, sizeof(buf) - len, - "secondary: %s (%s chan=%d ht=%d)\n", - wiphy_name(aphy->hw->wiphy), - ath_wiphy_state_str(aphy->state), - aphy->chan_idx, aphy->chan_is_ht); + "secondary: %s (%s chan=%d ht=%d)\n", + wiphy_name(aphy->hw->wiphy), + ath_wiphy_state_str(aphy->state), + ieee80211_frequency_to_channel(chan->center_freq), + aphy->chan_is_ht); } if (len > sizeof(buf)) len = sizeof(buf); -- cgit v1.2.3 From bc86863de63e6ae7ec6f9f524604631608c6cb02 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Fri, 1 Oct 2010 14:05:27 +0200 Subject: mac80211: perform scan cancel in hw reset work Move ieee80211_scan_cancel() and all other related code to ieee80211_restart_work() as ieee80211_restart_hw() is intended to be callable from any context. Fix a bug that RTNL lock is not taken during ieee80211_cancel_scan(). Take local->mtx before WARN(test_bit(SCAN_HW_SCANNING, &local->scanning) to prevent the race condition with __ieee80211_start_scan() described here: http://marc.info/?l=linux-wireless&m=128516716810537&w=2 Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville --- net/mac80211/main.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/net/mac80211/main.c b/net/mac80211/main.c index e24fa5be4264..494dba1b46a5 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -295,7 +295,17 @@ static void ieee80211_restart_work(struct work_struct *work) struct ieee80211_local *local = container_of(work, struct ieee80211_local, restart_work); + /* wait for scan work complete */ + flush_workqueue(local->workqueue); + + mutex_lock(&local->mtx); + WARN(test_bit(SCAN_HW_SCANNING, &local->scanning), + "%s called with hardware scan in progress\n", __func__); + mutex_unlock(&local->mtx); + rtnl_lock(); + if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning))) + ieee80211_scan_cancel(local); ieee80211_reconfig(local); rtnl_unlock(); } @@ -306,15 +316,6 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw) trace_api_restart_hw(local); - /* wait for scan work complete */ - flush_workqueue(local->workqueue); - - WARN(test_bit(SCAN_HW_SCANNING, &local->scanning), - "%s called with hardware scan in progress\n", __func__); - - if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning))) - ieee80211_scan_cancel(local); - /* use this reason, ieee80211_reconfig will unblock it */ ieee80211_stop_queues_by_reason(hw, IEEE80211_QUEUE_STOP_REASON_SUSPEND); -- cgit v1.2.3 From d8ec44335c974cc8bf67ce70c63071d4e0702509 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Fri, 1 Oct 2010 16:02:31 +0300 Subject: mac80211: Add validity check for beacon_crc value On association to an AP, after receiving beacons, the beacon_crc value is set. The beacon_crc value is not reset in disassociation, but the BSS data may be expired at a later point. When associating again, it's possible that a beacon for the AP is not received, resulting in the beacon_ies to remain NULL. After association, further beacons will not update the beacon data, as the crc value of the beacon has not changed, and the beacon_crc still holds a value matching the beacon. The beacon_ies will remain forever null. One of the results of this is that WLAN power save cannot be entered, the STA will remain foreven in active mode. Fix this by adding a validation flag for the beacon_crc, which is cleared on association. Signed-off-by: Juuso Oikarinen Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 1 + net/mac80211/mlme.c | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index f6a6d78efcf0..55d79db985fc 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -369,6 +369,7 @@ struct ieee80211_if_managed { unsigned int flags; + bool beacon_crc_valid; u32 beacon_crc; enum { diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 77913a15f537..c37086a12f51 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1639,7 +1639,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, directed_tim = ieee80211_check_tim(elems.tim, elems.tim_len, ifmgd->aid); - if (ncrc != ifmgd->beacon_crc) { + if (ncrc != ifmgd->beacon_crc || !ifmgd->beacon_crc_valid) { ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, true); @@ -1670,9 +1670,10 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, } } - if (ncrc == ifmgd->beacon_crc) + if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) return; ifmgd->beacon_crc = ncrc; + ifmgd->beacon_crc_valid = true; if (elems.erp_info && elems.erp_info_len >= 1) { erp_valid = true; @@ -2214,6 +2215,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N; ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED; + ifmgd->beacon_crc_valid = false; + for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 || req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP || -- cgit v1.2.3 From e51f3eff9a7e17ddd749799d4291f7e33e9883b9 Mon Sep 17 00:00:00 2001 From: Bill Jordan Date: Fri, 1 Oct 2010 11:20:39 -0400 Subject: ath9k: add WDS interfaces to ath9k Enable WDS for the ath9k driver. Signed-off-by: Bill Jordan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/init.c | 1 + drivers/net/wireless/ath/ath9k/main.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 282bb482424f..d76003c06fe4 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -657,6 +657,7 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_WDS) | BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_MESH_POINT); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 49ea45896b89..e6ddf45506be 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1374,6 +1374,9 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, case NL80211_IFTYPE_STATION: ic_opmode = NL80211_IFTYPE_STATION; break; + case NL80211_IFTYPE_WDS: + ic_opmode = NL80211_IFTYPE_WDS; + break; case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_AP: case NL80211_IFTYPE_MESH_POINT: -- cgit v1.2.3 From e8347ebad2f1b15bddb6ed3ed5f767531eb52dc3 Mon Sep 17 00:00:00 2001 From: Bill Jordan Date: Fri, 1 Oct 2010 13:54:28 -0400 Subject: cfg80211: patches to allow setting the WDS peer Added a nl interface to set the peer bssid of a WDS interface. Signed-off-by: Bill Jordan Signed-off-by: John W. Linville --- include/linux/nl80211.h | 3 +++ net/wireless/nl80211.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index edd21ae6acf7..73d9390d4ddb 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -387,6 +387,8 @@ * of any other interfaces, and other interfaces will again take * precedence when they are used. * + * @NL80211_CMD_SET_WDS_PEER: Set the MAC address of the peer on a WDS interface. + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -489,6 +491,7 @@ enum nl80211_commands { NL80211_CMD_NOTIFY_CQM, NL80211_CMD_SET_CHANNEL, + NL80211_CMD_SET_WDS_PEER, /* add new commands above here */ diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 21061ccee557..fd92b6b7ff04 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -603,6 +603,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); } CMD(set_channel, SET_CHANNEL); + CMD(set_wds_peer, SET_WDS_PEER); #undef CMD @@ -833,6 +834,53 @@ static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info) return result; } +static int nl80211_set_wds_peer(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev; + struct wireless_dev *wdev; + struct net_device *dev; + u8 *bssid; + int err; + + if (!info->attrs[NL80211_ATTR_MAC]) + return -EINVAL; + + rtnl_lock(); + + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); + if (err) + goto unlock_rtnl; + + wdev = dev->ieee80211_ptr; + + if (netif_running(dev)) { + err = -EBUSY; + goto out; + } + + if (!rdev->ops->set_wds_peer) { + err = -EOPNOTSUPP; + goto out; + } + + if (wdev->iftype != NL80211_IFTYPE_WDS) { + err = -EOPNOTSUPP; + goto out; + } + + bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); + err = rdev->ops->set_wds_peer(wdev->wiphy, dev, bssid); + +out: + cfg80211_unlock_rdev(rdev); + dev_put(dev); +unlock_rtnl: + rtnl_unlock(); + + return err; +} + + static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev; @@ -5473,6 +5521,12 @@ static struct genl_ops nl80211_ops[] = { .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, }, + { + .cmd = NL80211_CMD_SET_WDS_PEER, + .doit = nl80211_set_wds_peer, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, }; static struct genl_multicast_group nl80211_mlme_mcgrp = { -- cgit v1.2.3 From 1be7fe8de9f25e173282f8f989f83bc5b5decfe9 Mon Sep 17 00:00:00 2001 From: Bill Jordan Date: Fri, 1 Oct 2010 11:20:41 -0400 Subject: mac80211: fix for WDS interfaces Initialize the rate table for WDS interfaces, and add cases to allow WDS packets to pass the xmit and receive tests. Signed-off-by: Bill Jordan Signed-off-by: John W. Linville --- net/mac80211/iface.c | 3 +++ net/mac80211/main.c | 3 +++ net/mac80211/rx.c | 1 + net/mac80211/tx.c | 3 +++ 4 files changed, 10 insertions(+) diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 1300e8859ea7..438a2f51420e 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -24,6 +24,7 @@ #include "led.h" #include "driver-ops.h" #include "wme.h" +#include "rate.h" /** * DOC: Interface list locking @@ -311,6 +312,8 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) /* STA has been freed */ goto err_del_interface; } + + rate_control_rate_init(sta); } /* diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 494dba1b46a5..e127fbb8424e 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -201,6 +201,8 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, 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; + else if (sdata->vif.type == NL80211_IFTYPE_WDS) + sdata->vif.bss_conf.bssid = NULL; else if (ieee80211_vif_is_mesh(&sdata->vif)) { sdata->vif.bss_conf.bssid = zero; } else { @@ -211,6 +213,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, switch (sdata->vif.type) { case NL80211_IFTYPE_AP: case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_WDS: case NL80211_IFTYPE_MESH_POINT: break; default: diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 0b0e83ebe3d5..b3e161ffa4b3 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -819,6 +819,7 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx) if (unlikely((ieee80211_is_data(hdr->frame_control) || ieee80211_is_pspoll(hdr->frame_control)) && rx->sdata->vif.type != NL80211_IFTYPE_ADHOC && + rx->sdata->vif.type != NL80211_IFTYPE_WDS && (!rx->sta || !test_sta_flags(rx->sta, WLAN_STA_ASSOC)))) { if ((!ieee80211_has_fromds(hdr->frame_control) && !ieee80211_has_tods(hdr->frame_control) && diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index e1733dcb58a7..258fbdbedbdf 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -273,6 +273,9 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) */ return TX_DROP; + if (tx->sdata->vif.type == NL80211_IFTYPE_WDS) + return TX_CONTINUE; + if (tx->sdata->vif.type == NL80211_IFTYPE_MESH_POINT) return TX_CONTINUE; -- cgit v1.2.3 From b72acddbbe521d1372e7e9106e9d72e1cbab3010 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Fri, 1 Oct 2010 10:54:04 -0700 Subject: ath5k: Print rx/tx bytes in debugfs This adds counters for tx and rx bytes, including any errored packets as well as all wireless headers. Signed-off-by: Ben Greear Acked-by: Bruno Randolf Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/base.c | 2 ++ drivers/net/wireless/ath/ath5k/base.h | 7 +++++++ drivers/net/wireless/ath/ath5k/debug.c | 4 ++++ 3 files changed, 13 insertions(+) diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 2ed327a8d690..d914a31cb0b6 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1433,6 +1433,7 @@ static bool ath5k_receive_frame_ok(struct ath5k_softc *sc, struct ath5k_rx_status *rs) { sc->stats.rx_all_count++; + sc->stats.rx_bytes_count += rs->rs_datalen; if (unlikely(rs->rs_status)) { if (rs->rs_status & AR5K_RXERR_CRC) @@ -1611,6 +1612,7 @@ ath5k_tx_frame_completed(struct ath5k_softc *sc, struct sk_buff *skb, int i; sc->stats.tx_all_count++; + sc->stats.tx_bytes_count += skb->len; info = IEEE80211_SKB_CB(skb); ieee80211_tx_info_clear_status(info); diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h index b9f6d13b7675..9a79773cdc2a 100644 --- a/drivers/net/wireless/ath/ath5k/base.h +++ b/drivers/net/wireless/ath/ath5k/base.h @@ -121,6 +121,13 @@ struct ath5k_statistics { /* frame errors */ unsigned int rx_all_count; /* all RX frames, including errors */ unsigned int tx_all_count; /* all TX frames, including errors */ + unsigned int rx_bytes_count; /* all RX bytes, including errored pks + * and the MAC headers for each packet + */ + unsigned int tx_bytes_count; /* all TX bytes, including errored pkts + * and the MAC headers and padding for + * each packet. + */ unsigned int rxerr_crc; unsigned int rxerr_phy; unsigned int rxerr_phy_code[32]; diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c index 0f06e8490314..c2d549f871f9 100644 --- a/drivers/net/wireless/ath/ath5k/debug.c +++ b/drivers/net/wireless/ath/ath5k/debug.c @@ -587,6 +587,8 @@ static ssize_t read_file_frameerrors(struct file *file, char __user *user_buf, st->rxerr_jumbo*100/st->rx_all_count : 0); len += snprintf(buf+len, sizeof(buf)-len, "[RX all\t%d]\n", st->rx_all_count); + len += snprintf(buf+len, sizeof(buf)-len, "RX-all-bytes\t%d\n", + st->rx_bytes_count); len += snprintf(buf+len, sizeof(buf)-len, "\nTX\n---------------------\n"); @@ -604,6 +606,8 @@ static ssize_t read_file_frameerrors(struct file *file, char __user *user_buf, st->txerr_filt*100/st->tx_all_count : 0); len += snprintf(buf+len, sizeof(buf)-len, "[TX all\t%d]\n", st->tx_all_count); + len += snprintf(buf+len, sizeof(buf)-len, "TX-all-bytes\t%d\n", + st->tx_bytes_count); if (len > sizeof(buf)) len = sizeof(buf); -- cgit v1.2.3 From 99c15bf575b18e12c9373304a6a09a78f9c8a017 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Fri, 1 Oct 2010 12:26:30 -0700 Subject: ath9k: Report total tx/rx bytes and packets in debugfs. Includes pkts/bytes that may have had errors, and includes wireless headers when counting bytes. Signed-off-by: Ben Greear Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/debug.c | 15 +++++++++++++++ drivers/net/wireless/ath/ath9k/debug.h | 12 ++++++++++++ 2 files changed, 27 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 7a5932a6691a..74a4570dc87f 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -701,6 +701,8 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf, PR("DESC CFG Error: ", desc_cfg_err); PR("DATA Underrun: ", data_underrun); PR("DELIM Underrun: ", delim_underrun); + PR("TX-Pkts-All: ", tx_pkts_all); + PR("TX-Bytes-All: ", tx_bytes_all); if (len > size) len = size; @@ -714,6 +716,9 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf, void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq, struct ath_buf *bf, struct ath_tx_status *ts) { + TX_STAT_INC(txq->axq_qnum, tx_pkts_all); + sc->debug.stats.txstats[txq->axq_qnum].tx_bytes_all += bf->bf_mpdu->len; + if (bf_isampdu(bf)) { if (bf_isxretried(bf)) TX_STAT_INC(txq->axq_qnum, a_xretries); @@ -808,6 +813,13 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf, PHY_ERR("HT-LENGTH", ATH9K_PHYERR_HT_LENGTH_ILLEGAL); PHY_ERR("HT-RATE", ATH9K_PHYERR_HT_RATE_ILLEGAL); + len += snprintf(buf + len, size - len, + "%18s : %10u\n", "RX-Pkts-All", + sc->debug.stats.rxstats.rx_pkts_all); + len += snprintf(buf + len, size - len, + "%18s : %10u\n", "RX-Bytes-All", + sc->debug.stats.rxstats.rx_bytes_all); + if (len > size) len = size; @@ -826,6 +838,9 @@ void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs) u32 phyerr; + RX_STAT_INC(rx_pkts_all); + sc->debug.stats.rxstats.rx_bytes_all += rs->rs_datalen; + if (rs->rs_status & ATH9K_RXERR_CRC) RX_STAT_INC(crc_err); if (rs->rs_status & ATH9K_RXERR_DECRYPT) diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index 5d21704e87ff..822b6f3f23c5 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -89,6 +89,10 @@ struct ath_rc_stats { /** * struct ath_tx_stats - Statistics about TX + * @tx_pkts_all: No. of total frames transmitted, including ones that + may have had errors. + * @tx_bytes_all: No. of total bytes transmitted, including ones that + may have had errors. * @queued: Total MPDUs (non-aggr) queued * @completed: Total MPDUs (non-aggr) completed * @a_aggr: Total no. of aggregates queued @@ -107,6 +111,8 @@ struct ath_rc_stats { * @delim_urn: TX delimiter underrun errors */ struct ath_tx_stats { + u32 tx_pkts_all; + u32 tx_bytes_all; u32 queued; u32 completed; u32 a_aggr; @@ -124,6 +130,10 @@ struct ath_tx_stats { /** * struct ath_rx_stats - RX Statistics + * @rx_pkts_all: No. of total frames received, including ones that + may have had errors. + * @rx_bytes_all: No. of total bytes received, including ones that + may have had errors. * @crc_err: No. of frames with incorrect CRC value * @decrypt_crc_err: No. of frames whose CRC check failed after decryption process completed @@ -136,6 +146,8 @@ struct ath_tx_stats { * @phy_err_stats: Individual PHY error statistics */ struct ath_rx_stats { + u32 rx_pkts_all; + u32 rx_bytes_all; u32 crc_err; u32 decrypt_crc_err; u32 phy_err; -- cgit v1.2.3 From 1a92795dac419128eb511dce30a6aad672064b88 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Fri, 1 Oct 2010 22:01:24 +0200 Subject: p54usb: add five more USBIDs Source: http://www.wikidevi.com/wiki/Intersil/p54/usb/windows Cc: Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54usb.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index 063248b35069..d5bc21e5a02c 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -33,8 +33,17 @@ MODULE_ALIAS("prism54usb"); MODULE_FIRMWARE("isl3886usb"); MODULE_FIRMWARE("isl3887usb"); +/* + * Note: + * + * Always update our wiki's device list (located at: + * http://wireless.kernel.org/en/users/Drivers/p54/devices ), + * whenever you add a new device. + */ + static struct usb_device_id p54u_table[] __devinitdata = { /* Version 1 devices (pci chip + net2280) */ + {USB_DEVICE(0x045e, 0x00c2)}, /* Microsoft MN-710 */ {USB_DEVICE(0x0506, 0x0a11)}, /* 3COM 3CRWE254G72 */ {USB_DEVICE(0x06b9, 0x0120)}, /* Thomson SpeedTouch 120g */ {USB_DEVICE(0x0707, 0xee06)}, /* SMC 2862W-G */ @@ -47,7 +56,9 @@ static struct usb_device_id p54u_table[] __devinitdata = { {USB_DEVICE(0x0846, 0x4220)}, /* Netgear WG111 */ {USB_DEVICE(0x09aa, 0x1000)}, /* Spinnaker Proto board */ {USB_DEVICE(0x0cde, 0x0006)}, /* Medion 40900, Roper Europe */ + {USB_DEVICE(0x107b, 0x55f2)}, /* Gateway WGU-210 (Gemtek) */ {USB_DEVICE(0x124a, 0x4023)}, /* Shuttle PN15, Airvast WM168g, IOGear GWU513 */ + {USB_DEVICE(0x1630, 0x0005)}, /* 2Wire 802.11g USB (v1) / Z-Com */ {USB_DEVICE(0x1915, 0x2234)}, /* Linksys WUSB54G OEM */ {USB_DEVICE(0x1915, 0x2235)}, /* Linksys WUSB54G Portable OEM */ {USB_DEVICE(0x2001, 0x3701)}, /* DLink DWL-G120 Spinnaker */ @@ -60,6 +71,7 @@ static struct usb_device_id p54u_table[] __devinitdata = { {USB_DEVICE(0x050d, 0x7050)}, /* Belkin F5D7050 ver 1000 */ {USB_DEVICE(0x0572, 0x2000)}, /* Cohiba Proto board */ {USB_DEVICE(0x0572, 0x2002)}, /* Cohiba Proto board */ + {USB_DEVICE(0x06a9, 0x000e)}, /* Westell 802.11g USB (A90-211WG-01) */ {USB_DEVICE(0x06b9, 0x0121)}, /* Thomson SpeedTouch 121g */ {USB_DEVICE(0x0707, 0xee13)}, /* SMC 2862W-G version 2 */ {USB_DEVICE(0x083a, 0x4521)}, /* Siemens Gigaset USB Adapter 54 version 2 */ @@ -80,6 +92,7 @@ static struct usb_device_id p54u_table[] __devinitdata = { {USB_DEVICE(0x13B1, 0x000C)}, /* Linksys WUSB54AG */ {USB_DEVICE(0x1413, 0x5400)}, /* Telsey 802.11g USB2.0 Adapter */ {USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */ + {USB_DEVICE(0x1668, 0x1050)}, /* Actiontec 802UIG-1 */ {USB_DEVICE(0x2001, 0x3704)}, /* DLink DWL-G122 rev A2 */ {USB_DEVICE(0x413c, 0x5513)}, /* Dell WLA3310 USB Wireless Adapter */ {USB_DEVICE(0x413c, 0x8102)}, /* Spinnaker DUT */ -- cgit v1.2.3 From 2a0cfeb826df6751933fd95a797ac18371992c3b Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Sat, 2 Oct 2010 11:26:17 +0200 Subject: rt2x00: Don't overwrite beacon buffers in pairwise key setup rt2800 devices use parts of the pariwise key table to store the beacon frames for beacon 6 and 7. To not overwrite the beacon frame buffers limit the number of entries we store in the pairwise key table to 222. Also add some descriptive comments about this shared memory usage. Signed-off-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800.h | 21 ++++++++++++++++++++- drivers/net/wireless/rt2x00/rt2800lib.c | 6 +++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index 2edc7742a7e9..e1583cf5894b 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -1435,6 +1435,24 @@ /* * Security key table memory. + * + * The pairwise key table shares some memory with the beacon frame + * buffers 6 and 7. That basically means that when beacon 6 & 7 + * are used we should only use the reduced pairwise key table which + * has a maximum of 222 entries. + * + * --------------------------------------------- + * |0x4000 | Pairwise Key | Reduced Pairwise | + * | | Table | Key Table | + * | | Size: 256 * 32 | Size: 222 * 32 | + * |0x5BC0 | |------------------- + * | | | Beacon 6 | + * |0x5DC0 | |------------------- + * | | | Beacon 7 | + * |0x5FC0 | |------------------- + * |0x5FFF | | + * -------------------------- + * * MAC_WCID_BASE: 8-bytes (use only 6 bytes) * 256 entry * PAIRWISE_KEY_TABLE_BASE: 32-byte * 256 entry * MAC_IVEIV_TABLE_BASE: 8-byte * 256-entry @@ -1584,7 +1602,8 @@ struct mac_iveiv_entry { * 2. Extract memory from FCE table for BCN 4~5 * 3. Extract memory from Pair-wise key table for BCN 6~7 * It occupied those memory of wcid 238~253 for BCN 6 - * and wcid 222~237 for BCN 7 + * and wcid 222~237 for BCN 7 (see Security key table memory + * for more info). * * IMPORTANT NOTE: Not sure why legacy driver does this, * but HW_BEACON_BASE7 is 0x0200 bytes below HW_BEACON_BASE6. diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index c7076deaecea..daa32ae42866 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -1031,8 +1031,12 @@ int rt2800_config_pairwise_key(struct rt2x00_dev *rt2x00dev, * 1 pairwise key is possible per AID, this means that the AID * equals our hw_key_idx. Make sure the WCID starts _after_ the * last possible shared key entry. + * + * Since parts of the pairwise key table might be shared with + * the beacon frame buffers 6 & 7 we should only write into the + * first 222 entries. */ - if (crypto->aid > (256 - 32)) + if (crypto->aid > (222 - 32)) return -ENOSPC; key->hw_key_idx = 32 + crypto->aid; -- cgit v1.2.3 From 144333313b156a9e99d80e39e034a3cba00adeaf Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Sat, 2 Oct 2010 11:27:03 +0200 Subject: rt2x00: Split out parts of the rt2800_txdone function for easier reuse Signed-off-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 100 +++++++++++++++++--------------- drivers/net/wireless/rt2x00/rt2800lib.h | 1 + 2 files changed, 54 insertions(+), 47 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index daa32ae42866..19534f272d76 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -630,15 +630,63 @@ static bool rt2800_txdone_entry_check(struct queue_entry *entry, u32 reg) return true; } +void rt2800_txdone_entry(struct queue_entry *entry, u32 status) +{ + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; + struct txdone_entry_desc txdesc; + u32 word; + u16 mcs, real_mcs; + __le32 *txwi; + + /* + * Obtain the status about this packet. + */ + txdesc.flags = 0; + txwi = rt2800_drv_get_txwi(entry); + rt2x00_desc_read(txwi, 0, &word); + mcs = rt2x00_get_field32(word, TXWI_W0_MCS); + real_mcs = rt2x00_get_field32(status, TX_STA_FIFO_MCS); + + /* + * Ralink has a retry mechanism using a global fallback + * table. We setup this fallback table to try the immediate + * lower rate for all rates. In the TX_STA_FIFO, the MCS field + * always contains the MCS used for the last transmission, be + * it successful or not. + */ + if (rt2x00_get_field32(status, TX_STA_FIFO_TX_SUCCESS)) { + /* + * Transmission succeeded. The number of retries is + * mcs - real_mcs + */ + __set_bit(TXDONE_SUCCESS, &txdesc.flags); + txdesc.retry = ((mcs > real_mcs) ? mcs - real_mcs : 0); + } else { + /* + * Transmission failed. The number of retries is + * always 7 in this case (for a total number of 8 + * frames sent). + */ + __set_bit(TXDONE_FAILURE, &txdesc.flags); + txdesc.retry = rt2x00dev->long_retry; + } + + /* + * the frame was retried at least once + * -> hw used fallback rates + */ + if (txdesc.retry) + __set_bit(TXDONE_FALLBACK, &txdesc.flags); + + rt2x00lib_txdone(entry, &txdesc); +} +EXPORT_SYMBOL_GPL(rt2800_txdone_entry); + void rt2800_txdone(struct rt2x00_dev *rt2x00dev) { struct data_queue *queue; struct queue_entry *entry; - __le32 *txwi; - struct txdone_entry_desc txdesc; - u32 word; u32 reg; - u16 mcs, real_mcs; u8 pid; int i; @@ -673,7 +721,6 @@ void rt2800_txdone(struct rt2x00_dev *rt2x00dev) * order. We first check that the queue is not empty. */ entry = NULL; - txwi = NULL; while (!rt2x00queue_empty(queue)) { entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); if (rt2800_txdone_entry_check(entry, reg)) @@ -683,48 +730,7 @@ void rt2800_txdone(struct rt2x00_dev *rt2x00dev) if (!entry || rt2x00queue_empty(queue)) break; - - /* - * Obtain the status about this packet. - */ - txdesc.flags = 0; - txwi = rt2800_drv_get_txwi(entry); - rt2x00_desc_read(txwi, 0, &word); - mcs = rt2x00_get_field32(word, TXWI_W0_MCS); - real_mcs = rt2x00_get_field32(reg, TX_STA_FIFO_MCS); - - /* - * Ralink has a retry mechanism using a global fallback - * table. We setup this fallback table to try the immediate - * lower rate for all rates. In the TX_STA_FIFO, the MCS field - * always contains the MCS used for the last transmission, be - * it successful or not. - */ - if (rt2x00_get_field32(reg, TX_STA_FIFO_TX_SUCCESS)) { - /* - * Transmission succeeded. The number of retries is - * mcs - real_mcs - */ - __set_bit(TXDONE_SUCCESS, &txdesc.flags); - txdesc.retry = ((mcs > real_mcs) ? mcs - real_mcs : 0); - } else { - /* - * Transmission failed. The number of retries is - * always 7 in this case (for a total number of 8 - * frames sent). - */ - __set_bit(TXDONE_FAILURE, &txdesc.flags); - txdesc.retry = rt2x00dev->long_retry; - } - - /* - * the frame was retried at least once - * -> hw used fallback rates - */ - if (txdesc.retry) - __set_bit(TXDONE_FALLBACK, &txdesc.flags); - - rt2x00lib_txdone(entry, &txdesc); + rt2800_txdone_entry(entry, reg); } } EXPORT_SYMBOL_GPL(rt2800_txdone); diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h index 600c5eb25c41..81cbc92e7857 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/rt2x00/rt2800lib.h @@ -153,6 +153,7 @@ void rt2800_write_tx_data(struct queue_entry *entry, void rt2800_process_rxwi(struct queue_entry *entry, struct rxdone_entry_desc *txdesc); void rt2800_txdone(struct rt2x00_dev *rt2x00dev); +void rt2800_txdone_entry(struct queue_entry *entry, u32 status); void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc); -- cgit v1.2.3 From 96c3da7d7d7c37ee308ad6813947f48a71cca573 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Sat, 2 Oct 2010 11:27:35 +0200 Subject: rt2x00: rework tx status handling in rt2800pci This patch changes the way tx status reports are handled by rt2800pci. Previously rt2800pci would sometimes lose tx status reports as the TX_STA_FIFO register is a fifo of 16 entries that can overflow in case we don't read it often/fast enough. Since interrupts are disabled in the device during the execution of the interrupt thread it happend sometimes under high network and CPU load that processing took too long and a few tx status reports were dropped by the hw. To fix this issue the TX_STA_FIFO register is read directly in the interrupt handler and stored in a kfifo which is large enough to hold all status reports of all used tx queues. To process the status reports a new tasklet txstatus_tasklet is used. Using the already used interrupt thread is not possible since we don't want to disable the TX_FIFO_STATUS interrupt while processing them and it is not possible to schedule the interrupt thread multiple times for execution. A tasklet instead can be scheduled multiple times which allows to leave the TX_FIFO_STATUS interrupt enabled while a previously scheduled tasklet is still executing. In short: All other interrupts are handled in the interrupt thread as before. Only the TX_FIFO_STATUS interrupt is partly handled in the interrupt handler and finished in the according tasklet. One drawback of this patch is that it duplicates some code from rt2800lib. However, that can be cleaned up in the future once the rt2800usb and rt2800pci tx status handling converge more. Using this patch on a Ralink RT3052 embedded board gives me a reliable wireless connection even under high CPU and network load. I've transferred several gigabytes without any queue lockups. Signed-off-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800pci.c | 150 +++++++++++++++++++++++++++++--- drivers/net/wireless/rt2x00/rt2x00.h | 17 ++++ drivers/net/wireless/rt2x00/rt2x00dev.c | 34 ++++++++ 3 files changed, 188 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 005ee153e0cc..3806454b827b 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -660,6 +660,63 @@ static void rt2800pci_wakeup(struct rt2x00_dev *rt2x00dev) rt2800_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS); } +static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev) +{ + struct data_queue *queue; + struct queue_entry *entry; + u32 status; + u8 qid; + + while (!kfifo_is_empty(&rt2x00dev->txstatus_fifo)) { + /* Now remove the tx status from the FIFO */ + if (kfifo_out(&rt2x00dev->txstatus_fifo, &status, + sizeof(status)) != sizeof(status)) { + WARN_ON(1); + break; + } + + qid = rt2x00_get_field32(status, TX_STA_FIFO_PID_TYPE) - 1; + if (qid >= QID_RX) { + /* + * Unknown queue, this shouldn't happen. Just drop + * this tx status. + */ + WARNING(rt2x00dev, "Got TX status report with " + "unexpected pid %u, dropping", qid); + break; + } + + queue = rt2x00queue_get_queue(rt2x00dev, qid); + if (unlikely(queue == NULL)) { + /* + * The queue is NULL, this shouldn't happen. Stop + * processing here and drop the tx status + */ + WARNING(rt2x00dev, "Got TX status for an unavailable " + "queue %u, dropping", qid); + break; + } + + if (rt2x00queue_empty(queue)) { + /* + * The queue is empty. Stop processing here + * and drop the tx status. + */ + WARNING(rt2x00dev, "Got TX status for an empty " + "queue %u, dropping", qid); + break; + } + + entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); + rt2800_txdone_entry(entry, status); + } +} + +static void rt2800pci_txstatus_tasklet(unsigned long data) +{ + rt2800pci_txdone((struct rt2x00_dev *)data); +} + static irqreturn_t rt2800pci_interrupt_thread(int irq, void *dev_instance) { struct rt2x00_dev *rt2x00dev = dev_instance; @@ -684,13 +741,7 @@ static irqreturn_t rt2800pci_interrupt_thread(int irq, void *dev_instance) rt2x00pci_rxdone(rt2x00dev); /* - * 4 - Tx done interrupt. - */ - if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS)) - rt2800_txdone(rt2x00dev); - - /* - * 5 - Auto wakeup interrupt. + * 4 - Auto wakeup interrupt. */ if (rt2x00_get_field32(reg, INT_SOURCE_CSR_AUTO_WAKEUP)) rt2800pci_wakeup(rt2x00dev); @@ -702,10 +753,58 @@ static irqreturn_t rt2800pci_interrupt_thread(int irq, void *dev_instance) return IRQ_HANDLED; } +static void rt2800pci_txstatus_interrupt(struct rt2x00_dev *rt2x00dev) +{ + u32 status; + int i; + + /* + * The TX_FIFO_STATUS interrupt needs special care. We should + * read TX_STA_FIFO but we should do it immediately as otherwise + * the register can overflow and we would lose status reports. + * + * Hence, read the TX_STA_FIFO register and copy all tx status + * reports into a kernel FIFO which is handled in the txstatus + * tasklet. We use a tasklet to process the tx status reports + * because we can schedule the tasklet multiple times (when the + * interrupt fires again during tx status processing). + * + * Furthermore we don't disable the TX_FIFO_STATUS + * interrupt here but leave it enabled so that the TX_STA_FIFO + * can also be read while the interrupt thread gets executed. + * + * Since we have only one producer and one consumer we don't + * need to lock the kfifo. + */ + for (i = 0; i < TX_ENTRIES; i++) { + rt2800_register_read(rt2x00dev, TX_STA_FIFO, &status); + + if (!rt2x00_get_field32(status, TX_STA_FIFO_VALID)) + break; + + if (kfifo_is_full(&rt2x00dev->txstatus_fifo)) { + WARNING(rt2x00dev, "TX status FIFO overrun," + " drop tx status report.\n"); + break; + } + + if (kfifo_in(&rt2x00dev->txstatus_fifo, &status, + sizeof(status)) != sizeof(status)) { + WARNING(rt2x00dev, "TX status FIFO overrun," + "drop tx status report.\n"); + break; + } + } + + /* Schedule the tasklet for processing the tx status. */ + tasklet_schedule(&rt2x00dev->txstatus_tasklet); +} + static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance) { struct rt2x00_dev *rt2x00dev = dev_instance; u32 reg; + irqreturn_t ret = IRQ_HANDLED; /* Read status and ACK all interrupts */ rt2800_register_read(rt2x00dev, INT_SOURCE_CSR, ®); @@ -717,15 +816,38 @@ static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance) if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) return IRQ_HANDLED; - /* Store irqvalue for use in the interrupt thread. */ - rt2x00dev->irqvalue[0] = reg; + if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS)) + rt2800pci_txstatus_interrupt(rt2x00dev); + + if (rt2x00_get_field32(reg, INT_SOURCE_CSR_PRE_TBTT) || + rt2x00_get_field32(reg, INT_SOURCE_CSR_TBTT) || + rt2x00_get_field32(reg, INT_SOURCE_CSR_RX_DONE) || + rt2x00_get_field32(reg, INT_SOURCE_CSR_AUTO_WAKEUP)) { + /* + * All other interrupts are handled in the interrupt thread. + * Store irqvalue for use in the interrupt thread. + */ + rt2x00dev->irqvalue[0] = reg; - /* Disable interrupts, will be enabled again in the interrupt thread. */ - rt2x00dev->ops->lib->set_device_state(rt2x00dev, - STATE_RADIO_IRQ_OFF_ISR); + /* + * Disable interrupts, will be enabled again in the + * interrupt thread. + */ + rt2x00dev->ops->lib->set_device_state(rt2x00dev, + STATE_RADIO_IRQ_OFF_ISR); + /* + * Leave the TX_FIFO_STATUS interrupt enabled to not lose any + * tx status reports. + */ + rt2800_register_read(rt2x00dev, INT_MASK_CSR, ®); + rt2x00_set_field32(®, INT_MASK_CSR_TX_FIFO_STATUS, 1); + rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg); - return IRQ_WAKE_THREAD; + ret = IRQ_WAKE_THREAD; + } + + return ret; } /* @@ -788,6 +910,7 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev) __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags); + __set_bit(DRIVER_REQUIRE_TXSTATUS_FIFO, &rt2x00dev->flags); if (!modparam_nohwcrypt) __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags); @@ -837,6 +960,7 @@ static const struct rt2800_ops rt2800pci_rt2800_ops = { static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = { .irq_handler = rt2800pci_interrupt, .irq_handler_thread = rt2800pci_interrupt_thread, + .txstatus_tasklet = rt2800pci_txstatus_tasklet, .probe_hw = rt2800pci_probe_hw, .get_firmware_name = rt2800pci_get_firmware_name, .check_firmware = rt2800_check_firmware, diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 7832a5996a8c..bab10adae537 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -36,6 +36,7 @@ #include #include #include +#include #include @@ -521,6 +522,11 @@ struct rt2x00lib_ops { */ irq_handler_t irq_handler_thread; + /* + * TX status tasklet handler. + */ + void (*txstatus_tasklet) (unsigned long data); + /* * Device init handlers. */ @@ -651,6 +657,7 @@ enum rt2x00_flags { DRIVER_REQUIRE_DMA, DRIVER_REQUIRE_COPY_IV, DRIVER_REQUIRE_L2PAD, + DRIVER_REQUIRE_TXSTATUS_FIFO, /* * Driver features @@ -884,6 +891,16 @@ struct rt2x00_dev { * and interrupt thread routine. */ u32 irqvalue[2]; + + /* + * FIFO for storing tx status reports between isr and tasklet. + */ + struct kfifo txstatus_fifo; + + /* + * Tasklet for processing tx status reports (rt2800pci). + */ + struct tasklet_struct txstatus_tasklet; }; /* diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 053fdd3bd720..b03e6e41dc1e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -812,6 +812,30 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev) else if (test_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags)) rt2x00dev->hw->extra_tx_headroom += RT2X00_ALIGN_SIZE; + /* + * Allocate tx status FIFO for driver use. + */ + if (test_bit(DRIVER_REQUIRE_TXSTATUS_FIFO, &rt2x00dev->flags) && + rt2x00dev->ops->lib->txstatus_tasklet) { + /* + * Allocate txstatus fifo and tasklet, we use a size of 512 + * for the kfifo which is big enough to store 512/4=128 tx + * status reports. In the worst case (tx status for all tx + * queues gets reported before we've got a chance to handle + * them) 24*4=384 tx status reports need to be cached. + */ + status = kfifo_alloc(&rt2x00dev->txstatus_fifo, 512, + GFP_KERNEL); + if (status) + return status; + + /* tasklet for processing the tx status reports. */ + tasklet_init(&rt2x00dev->txstatus_tasklet, + rt2x00dev->ops->lib->txstatus_tasklet, + (unsigned long)rt2x00dev); + + } + /* * Register HW. */ @@ -1027,6 +1051,16 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) cancel_work_sync(&rt2x00dev->rxdone_work); cancel_work_sync(&rt2x00dev->txdone_work); + /* + * Free the tx status fifo. + */ + kfifo_free(&rt2x00dev->txstatus_fifo); + + /* + * Kill the tx status tasklet. + */ + tasklet_kill(&rt2x00dev->txstatus_tasklet); + /* * Uninitialize device. */ -- cgit v1.2.3 From a13ac9df0a2125507295da02444cd88bebf0df36 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Sat, 2 Oct 2010 11:28:02 +0200 Subject: rt2x00: Fix SM PS check Fix a check for dynamic SM PS mode in the STAs HT caps. Since a value of 3 means "SM PS disabled" the previous check assumed in that case that "dynamic SM PS" was enabled and as such prefixed every MCS>7 frame with a unnecessary RTS/CTS exchange. Also, the bit shift was done in the wrong direction. Signed-off-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00ht.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2x00ht.c b/drivers/net/wireless/rt2x00/rt2x00ht.c index ad3c7ff4837b..48b6ed426da5 100644 --- a/drivers/net/wireless/rt2x00/rt2x00ht.c +++ b/drivers/net/wireless/rt2x00/rt2x00ht.c @@ -60,9 +60,10 @@ void rt2x00ht_create_tx_descriptor(struct queue_entry *entry, * when using more then one tx stream (>MCS7). */ if (tx_info->control.sta && txdesc->mcs > 7 && - (tx_info->control.sta->ht_cap.cap & - (WLAN_HT_CAP_SM_PS_DYNAMIC << - IEEE80211_HT_CAP_SM_PS_SHIFT))) + ((tx_info->control.sta->ht_cap.cap & + IEEE80211_HT_CAP_SM_PS) >> + IEEE80211_HT_CAP_SM_PS_SHIFT) == + WLAN_HT_CAP_SM_PS_DYNAMIC) __set_bit(ENTRY_TXD_HT_MIMO_PS, &txdesc->flags); } else { txdesc->mcs = rt2x00_get_rate_mcs(hwrate->mcs); -- cgit v1.2.3 From 87c1915d2c271a8998a79f16bcf5353e2c28db45 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Sat, 2 Oct 2010 11:28:34 +0200 Subject: rt2x00: Implement HT protection for rt2800 Update the HT operation mode when mac80211 sends it to us and set the different HT protection modes and rates accordingly. For now only use CTS-to-self with OFDM 24M or CCK 11M when protection is required. Signed-off-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 99 ++++++++++++++++++++++++++++++ drivers/net/wireless/rt2x00/rt2x00.h | 1 + drivers/net/wireless/rt2x00/rt2x00config.c | 3 + drivers/net/wireless/rt2x00/rt2x00mac.c | 2 +- 4 files changed, 104 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 19534f272d76..4ecacea677ac 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -1169,6 +1169,102 @@ void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf, } EXPORT_SYMBOL_GPL(rt2800_config_intf); +static void rt2800_config_ht_opmode(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_erp *erp) +{ + bool any_sta_nongf = !!(erp->ht_opmode & + IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); + u8 protection = erp->ht_opmode & IEEE80211_HT_OP_MODE_PROTECTION; + u8 mm20_mode, mm40_mode, gf20_mode, gf40_mode; + u16 mm20_rate, mm40_rate, gf20_rate, gf40_rate; + u32 reg; + + /* default protection rate for HT20: OFDM 24M */ + mm20_rate = gf20_rate = 0x4004; + + /* default protection rate for HT40: duplicate OFDM 24M */ + mm40_rate = gf40_rate = 0x4084; + + switch (protection) { + case IEEE80211_HT_OP_MODE_PROTECTION_NONE: + /* + * All STAs in this BSS are HT20/40 but there might be + * STAs not supporting greenfield mode. + * => Disable protection for HT transmissions. + */ + mm20_mode = mm40_mode = gf20_mode = gf40_mode = 0; + + break; + case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: + /* + * All STAs in this BSS are HT20 or HT20/40 but there + * might be STAs not supporting greenfield mode. + * => Protect all HT40 transmissions. + */ + mm20_mode = gf20_mode = 0; + mm40_mode = gf40_mode = 2; + + break; + case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER: + /* + * Nonmember protection: + * According to 802.11n we _should_ protect all + * HT transmissions (but we don't have to). + * + * But if cts_protection is enabled we _shall_ protect + * all HT transmissions using a CCK rate. + * + * And if any station is non GF we _shall_ protect + * GF transmissions. + * + * We decide to protect everything + * -> fall through to mixed mode. + */ + case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED: + /* + * Legacy STAs are present + * => Protect all HT transmissions. + */ + mm20_mode = mm40_mode = gf20_mode = gf40_mode = 2; + + /* + * If erp protection is needed we have to protect HT + * transmissions with CCK 11M long preamble. + */ + if (erp->cts_protection) { + /* don't duplicate RTS/CTS in CCK mode */ + mm20_rate = mm40_rate = 0x0003; + gf20_rate = gf40_rate = 0x0003; + } + break; + }; + + /* check for STAs not supporting greenfield mode */ + if (any_sta_nongf) + gf20_mode = gf40_mode = 2; + + /* Update HT protection config */ + rt2800_register_read(rt2x00dev, MM20_PROT_CFG, ®); + rt2x00_set_field32(®, MM20_PROT_CFG_PROTECT_RATE, mm20_rate); + rt2x00_set_field32(®, MM20_PROT_CFG_PROTECT_CTRL, mm20_mode); + rt2800_register_write(rt2x00dev, MM20_PROT_CFG, reg); + + rt2800_register_read(rt2x00dev, MM40_PROT_CFG, ®); + rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_RATE, mm40_rate); + rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_CTRL, mm40_mode); + rt2800_register_write(rt2x00dev, MM40_PROT_CFG, reg); + + rt2800_register_read(rt2x00dev, GF20_PROT_CFG, ®); + rt2x00_set_field32(®, GF20_PROT_CFG_PROTECT_RATE, gf20_rate); + rt2x00_set_field32(®, GF20_PROT_CFG_PROTECT_CTRL, gf20_mode); + rt2800_register_write(rt2x00dev, GF20_PROT_CFG, reg); + + rt2800_register_read(rt2x00dev, GF40_PROT_CFG, ®); + rt2x00_set_field32(®, GF40_PROT_CFG_PROTECT_RATE, gf40_rate); + rt2x00_set_field32(®, GF40_PROT_CFG_PROTECT_CTRL, gf40_mode); + rt2800_register_write(rt2x00dev, GF40_PROT_CFG, reg); +} + void rt2800_config_erp(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_erp *erp, u32 changed) { @@ -1213,6 +1309,9 @@ void rt2800_config_erp(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_erp *erp, erp->beacon_int * 16); rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); } + + if (changed & BSS_CHANGED_HT) + rt2800_config_ht_opmode(rt2x00dev, erp); } EXPORT_SYMBOL_GPL(rt2800_config_erp); diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index bab10adae537..75ac6624bf9e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -458,6 +458,7 @@ struct rt2x00lib_erp { short eifs; u16 beacon_int; + u16 ht_opmode; }; /* diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index 4c7ff765a8bf..54ffb5aeb34e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -103,6 +103,9 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev, /* Update global beacon interval time, this is needed for PS support */ rt2x00dev->beacon_int = bss_conf->beacon_int; + if (changed & BSS_CHANGED_HT) + erp.ht_opmode = bss_conf->ht_operation_mode; + rt2x00dev->ops->lib->config_erp(rt2x00dev, &erp, changed); } diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 7862a840984a..c3c206a97d54 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -671,7 +671,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, */ if (changes & (BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_ERP_PREAMBLE | BSS_CHANGED_ERP_SLOT | BSS_CHANGED_BASIC_RATES | - BSS_CHANGED_BEACON_INT)) + BSS_CHANGED_BEACON_INT | BSS_CHANGED_HT)) rt2x00lib_config_erp(rt2x00dev, intf, bss_conf, changes); } EXPORT_SYMBOL_GPL(rt2x00mac_bss_info_changed); -- cgit v1.2.3 From d13a97f07d86f462096007dbf0f2e0338692abc0 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Sat, 2 Oct 2010 11:29:08 +0200 Subject: rt2x00: Don't initialize MM40 HT protection to RTS/CTS on PCI devices Since HT protection is now configurable via mac80211 we don't need this special case for PCI devices anymore. The HT protection config will be overwritten as soon as mac80211 sends us a HT operation mode. Hence, bring the HT MM40 protection config in sync with the other HT protection registers and initialize it to no protection. Signed-off-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 4ecacea677ac..76b8783c5639 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -2016,8 +2016,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2800_register_read(rt2x00dev, MM40_PROT_CFG, ®); rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_RATE, 0x4084); - rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_CTRL, - !rt2x00_is_usb(rt2x00dev)); + rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_CTRL, 0); rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_NAV, 1); rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_CCK, 1); rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_OFDM, 1); -- cgit v1.2.3 From 95192339c2de1e1a61baf289af3e3332403371c9 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Sat, 2 Oct 2010 11:29:30 +0200 Subject: rt2x00: Fix race between dma mapping and clearing rx entries in rt2800pci During rx, rt2x00lib calls rt2800pci_fill_rxdone to read the RX descriptor. At that time the skb is already dma unmapped but no new skb was dma mapped for this entry again. However, rt2800pci_fill_rxdone also moves the hw rx queue index, marking this entry to be available for reuse. Since no new skb was dma mapped and also the previous skb was unmapped this might lead to strange hw behavior. To fix this issue move the hw rx queue index increment to rt2800pci_clear_entry where a new skb was already dma mapped and can be safely used by the hw. Signed-off-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800pci.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 3806454b827b..85a134cd62bf 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -241,6 +241,7 @@ static void rt2800pci_clear_entry(struct queue_entry *entry) { struct queue_entry_priv_pci *entry_priv = entry->priv_data; struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; u32 word; if (entry->queue->qid == QID_RX) { @@ -251,6 +252,13 @@ static void rt2800pci_clear_entry(struct queue_entry *entry) rt2x00_desc_read(entry_priv->desc, 1, &word); rt2x00_set_field32(&word, RXD_W1_DMA_DONE, 0); rt2x00_desc_write(entry_priv->desc, 1, word); + + /* + * Set RX IDX in register to inform hardware that we have + * handled this entry and it is available for reuse again. + */ + rt2800_register_write(rt2x00dev, RX_CRX_IDX, + entry->entry_idx); } else { rt2x00_desc_read(entry_priv->desc, 1, &word); rt2x00_set_field32(&word, TXD_W1_DMA_DONE, 1); @@ -599,7 +607,6 @@ static void rt2800pci_kill_tx_queue(struct data_queue *queue) static void rt2800pci_fill_rxdone(struct queue_entry *entry, struct rxdone_entry_desc *rxdesc) { - struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct queue_entry_priv_pci *entry_priv = entry->priv_data; __le32 *rxd = entry_priv->desc; u32 word; @@ -641,12 +648,6 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry, * Process the RXWI structure that is at the start of the buffer. */ rt2800_process_rxwi(entry, rxdesc); - - /* - * Set RX IDX in register to inform hardware that we have handled - * this entry and it is available for reuse again. - */ - rt2800_register_write(rt2x00dev, RX_CRX_IDX, entry->entry_idx); } /* -- cgit v1.2.3 From cb753b7253548b950e84843a00b4db8d0c54f578 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Sat, 2 Oct 2010 11:29:59 +0200 Subject: rt2x00: Allow tx duplication for legacy rates in HT40 mode Make use of the IEEE80211_TX_RC_DUP_DATA flag to duplicate a transmission with legacy rates to both 20Mhz channels if set. Also update the related comment in rt2800.h to describe the behavior of the BW_40 flag for legacy rates. Signed-off-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800.h | 3 ++- drivers/net/wireless/rt2x00/rt2x00ht.c | 8 +++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index e1583cf5894b..9bf50a1c48d0 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -1982,7 +1982,8 @@ struct mac_iveiv_entry { * FRAG: 1 To inform TKIP engine this is a fragment. * MIMO_PS: The remote peer is in dynamic MIMO-PS mode * TX_OP: 0:HT TXOP rule , 1:PIFS TX ,2:Backoff, 3:sifs - * BW: Channel bandwidth 20MHz or 40 MHz + * BW: Channel bandwidth 0:20MHz, 1:40 MHz (for legacy rates this will + * duplicate the frame to both channels). * STBC: 1: STBC support MCS =0-7, 2,3 : RESERVED * AMPDU: 1: this frame is eligible for AMPDU aggregation, the hw will * aggregate consecutive frames with the same RA and QoS TID. diff --git a/drivers/net/wireless/rt2x00/rt2x00ht.c b/drivers/net/wireless/rt2x00/rt2x00ht.c index 48b6ed426da5..2023419ce0bd 100644 --- a/drivers/net/wireless/rt2x00/rt2x00ht.c +++ b/drivers/net/wireless/rt2x00/rt2x00ht.c @@ -85,7 +85,13 @@ void rt2x00ht_create_tx_descriptor(struct queue_entry *entry, txdesc->rate_mode = RATE_MODE_HT_MIX; if (txrate->flags & IEEE80211_TX_RC_GREEN_FIELD) txdesc->rate_mode = RATE_MODE_HT_GREENFIELD; - if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) + + /* + * Set 40Mhz mode if necessary (for legacy rates this will + * duplicate the frame to both channels). + */ + if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH || + txrate->flags & IEEE80211_TX_RC_DUP_DATA) __set_bit(ENTRY_TXD_HT_BW_40, &txdesc->flags); if (txrate->flags & IEEE80211_TX_RC_SHORT_GI) __set_bit(ENTRY_TXD_HT_SHORT_GI, &txdesc->flags); -- cgit v1.2.3 From b1ef7252f491b6dc09ffc4584da0f3cf564e05e5 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 2 Oct 2010 11:30:19 +0200 Subject: rt2x00: Add rt73usb device ID Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt73usb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index cc6a72b09f46..f78bc2a29328 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -2365,6 +2365,7 @@ static struct usb_device_id rt73usb_device_table[] = { { 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) }, + { USB_DEVICE(0x0411, 0x0137), USB_DEVICE_DATA(&rt73usb_ops) }, /* CEIVA */ { USB_DEVICE(0x178d, 0x02be), USB_DEVICE_DATA(&rt73usb_ops) }, /* CNet */ -- cgit v1.2.3 From d4ce3a5ea16f82d73922b7bfb8a177e371493ffb Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Sat, 2 Oct 2010 11:30:42 +0200 Subject: rt2x00: Add register definition for busy time on secondary channel Add the register definition CH_BUSY_STA_SEC for reading the busy time on the secondary channel in HT40 mode. Also update the comments about channel busy/idle time registers to express the used unit. Signed-off-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index 9bf50a1c48d0..f02ea129680e 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -747,15 +747,20 @@ #define INT_TIMER_EN_GP_TIMER FIELD32(0x00000002) /* - * CH_IDLE_STA: channel idle time + * CH_IDLE_STA: channel idle time (in us) */ #define CH_IDLE_STA 0x1130 /* - * CH_BUSY_STA: channel busy time + * CH_BUSY_STA: channel busy time on primary channel (in us) */ #define CH_BUSY_STA 0x1134 +/* + * CH_BUSY_STA_SEC: channel busy time on secondary channel in HT40 mode (in us) + */ +#define CH_BUSY_STA_SEC 0x1138 + /* * MAC_STATUS_CFG: * BBP_RF_BUSY: When set to 0, BBP and RF are stable. -- cgit v1.2.3 From c4c18a9dc16095fc8ada423f1e6ff3830d56d37c Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Sat, 2 Oct 2010 11:31:05 +0200 Subject: rt2x00: add field definitions for the TBTT_SYNC_CFG register Signed-off-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index f02ea129680e..4930d29e1377 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -710,8 +710,14 @@ /* * TBTT_SYNC_CFG: + * BCN_AIFSN: Beacon AIFSN after TBTT interrupt in slots + * BCN_CWMIN: Beacon CWMin after TBTT interrupt in slots */ #define TBTT_SYNC_CFG 0x1118 +#define TBTT_SYNC_CFG_TBTT_ADJUST FIELD32(0x000000ff) +#define TBTT_SYNC_CFG_BCN_EXP_WIN FIELD32(0x0000ff00) +#define TBTT_SYNC_CFG_BCN_AIFSN FIELD32(0x000f0000) +#define TBTT_SYNC_CFG_BCN_CWMIN FIELD32(0x00f00000) /* * TSF_TIMER_DW0: Local lsb TSF timer, read-only -- cgit v1.2.3 From 5a5b6ed6ce46be128f2a5a9e56f47193c3ac3e32 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Sat, 2 Oct 2010 11:31:33 +0200 Subject: rt2x00: Don't enable broad- and multicast buffering on USB devices Since rt2x00 USB devices have no chance to know when a beacon was sent out in AP mode currently all broad- and multicast traffic is buffered in mac80211 but never sent out at all. Unfortunately we have no chance in sending the traffic out after a DTIM beacon due to hw limitations. Hence, instead of never sending the buffered traffic out better send it out immediately. Signed-off-by: Helmut Schaa Reported-by: Lauri Hintsala Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2500usb.c | 7 ++++++- drivers/net/wireless/rt2x00/rt2800lib.c | 11 ++++++++++- drivers/net/wireless/rt2x00/rt73usb.c | 7 ++++++- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 5843a6d8b627..103396495065 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1674,10 +1674,15 @@ static int rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) /* * Initialize all hw fields. + * + * Don't set IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING unless we are + * capable of sending the buffered frames out after the DTIM + * transmission using rt2x00lib_beacondone. This will send out + * multicast and broadcast traffic immediately instead of buffering it + * infinitly and thus dropping it after some time. */ rt2x00dev->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; diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 76b8783c5639..99b505f8e717 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -3164,11 +3164,20 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) * Initialize all hw fields. */ rt2x00dev->hw->flags = - IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_PS_NULLFUNC_STACK | IEEE80211_HW_AMPDU_AGGREGATION; + /* + * Don't set IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING for USB devices + * unless we are capable of sending the buffered frames out after the + * DTIM transmission using rt2x00lib_beacondone. This will send out + * multicast and broadcast traffic immediately instead of buffering it + * infinitly and thus dropping it after some time. + */ + if (!rt2x00_is_usb(rt2x00dev)) + rt2x00dev->hw->flags |= + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev); SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index f78bc2a29328..66939fd8689d 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -2063,9 +2063,14 @@ static int rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) /* * Initialize all hw fields. + * + * Don't set IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING unless we are + * capable of sending the buffered frames out after the DTIM + * transmission using rt2x00lib_beacondone. This will send out + * multicast and broadcast traffic immediately instead of buffering it + * infinitly and thus dropping it after some time. */ rt2x00dev->hw->flags = - IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_PS_NULLFUNC_STACK; -- cgit v1.2.3 From 78be49ec2a0df34de9441930fdced20311fd709f Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Sat, 2 Oct 2010 11:31:55 +0200 Subject: mac80211: distinct between max rates and the number of rates the hw can report Some drivers cannot handle multiple retry rates specified by the rc algorithm but instead use their own retry table (for example rt2800). However, if such a device registers itself with a max_rates value of 1 the rc algorithm cannot make use of the extended information the device can provide about retried rates. On the other hand, if a device registers itself with a max_rates value > 1 the rc algorithm assumes that the device can handle multi rate retries. Fix this issue by introducing another hw parameter max_report_rates that can be set to a different value then max_rates to indicate if a device is capable of reporting more rates then specified in max_rates. Signed-off-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- include/net/mac80211.h | 6 +++++- net/mac80211/main.c | 4 ++++ net/mac80211/status.c | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index fe8b9dae4dee..47316a653ae1 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1109,7 +1109,10 @@ enum ieee80211_hw_flags { * @sta_data_size: size (in bytes) of the drv_priv data area * within &struct ieee80211_sta. * - * @max_rates: maximum number of alternate rate retry stages + * @max_rates: maximum number of alternate rate retry stages the hw + * can handle. + * @max_report_rates: maximum number of alternate rate retry stages + * the hw can report back. * @max_rate_tries: maximum number of tries for each stage * * @napi_weight: weight used for NAPI polling. You must specify an @@ -1131,6 +1134,7 @@ struct ieee80211_hw { u16 max_listen_interval; s8 max_signal; u8 max_rates; + u8 max_report_rates; u8 max_rate_tries; }; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index e127fbb8424e..9c2f3f934c74 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -537,6 +537,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, /* set up some defaults */ local->hw.queues = 1; local->hw.max_rates = 1; + local->hw.max_report_rates = 0; 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; @@ -612,6 +613,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) WLAN_CIPHER_SUITE_AES_CMAC }; + if (hw->max_report_rates == 0) + hw->max_report_rates = hw->max_rates; + /* * generic code guarantees at least one band, * set this very early because much code assumes diff --git a/net/mac80211/status.c b/net/mac80211/status.c index dd85006c4fe8..95763e036975 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -176,7 +176,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { /* the HW cannot have attempted that rate */ - if (i >= hw->max_rates) { + if (i >= hw->max_report_rates) { info->status.rates[i].idx = -1; info->status.rates[i].count = 0; } else if (info->status.rates[i].idx >= 0) { -- cgit v1.2.3 From ba3b9e5e8c7a12d8ea46cb4a8217c2e9b0720e9c Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Sat, 2 Oct 2010 11:32:16 +0200 Subject: rt2x00: correctly set max_report_rates in rt61pci and rt2800 rt61pci and rt2800 devices can use up to 7 different rates per tx frame. However, the device uses a global fallback table. Hence, the rc algortihm cannot specify multiple rates to try but the device is able to report multiple rates (based on the retry table). Specify that behavior by correctly setting max_report_rates and max_rates. This makes rt2x00 and minstrel play nicer together. Signed-off-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 5 +++-- drivers/net/wireless/rt2x00/rt61pci.c | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 99b505f8e717..403e2ed0f44f 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -3188,12 +3188,13 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) * As rt2800 has a global fallback table we cannot specify * more then one tx rate per frame but since the hw will * try several rates (based on the fallback table) we should - * still initialize max_rates to the maximum number of rates + * initialize max_report_rates to the maximum number of rates * we are going to try. Otherwise mac80211 will truncate our * reported tx rates and the rc algortihm will end up with * incorrect data. */ - rt2x00dev->hw->max_rates = 7; + rt2x00dev->hw->max_rates = 1; + rt2x00dev->hw->max_report_rates = 7; rt2x00dev->hw->max_rate_tries = 1; rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 8940070fe2a2..ac370f11e74f 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2630,12 +2630,13 @@ static int rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) * As rt61 has a global fallback table we cannot specify * more then one tx rate per frame but since the hw will * try several rates (based on the fallback table) we should - * still initialize max_rates to the maximum number of rates + * initialize max_report_rates to the maximum number of rates * we are going to try. Otherwise mac80211 will truncate our * reported tx rates and the rc algortihm will end up with * incorrect data. */ - rt2x00dev->hw->max_rates = 7; + rt2x00dev->hw->max_rates = 1; + rt2x00dev->hw->max_report_rates = 7; rt2x00dev->hw->max_rate_tries = 1; /* -- cgit v1.2.3 From bc8a979e2d85c2bdd507a8b6b09fdafc11ebd73a Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 2 Oct 2010 11:32:43 +0200 Subject: rt2x00: Improve TX status entry validation The TX_STA_FIFO contains some information for identifying a outgoing frame, however matching by WCID and ACK status is not sufficient to 100% identify the macthing queue_entry structure (containing the SKB buffer) which belongs to the status report. Within TX_STA_FIFO we have a 4-bit field named PACKETID, which is currently used to encode the queue id. The queue ID is however limited to values from 0 to 3, which means 2 bits are sufficient to encode the value. With the remaining 2 bits we can encode a partial queue_entry index number. The value of PACKETID is not allowed to become 0, with the queue ID ranging from 0 to 3, at least one of the bits for the entry identification must be 1. That leaves us with 3 possible values we can still encode in the bits. Altough this doesn't allow 100% accurate matching of the TX_STA_FIFO queue to a queue_entry structure, it at least improves the accuracy. This allows us to better detect if we have missed the TX_STA_FIFO report, which in turn reduces the number of watchdog warnings regarding the TX status timeout. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800.h | 14 +++++++++++++- drivers/net/wireless/rt2x00/rt2800lib.c | 5 +++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index 4930d29e1377..2a9f4020af1e 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -1,5 +1,6 @@ /* - Copyright (C) 2004 - 2009 Ivo van Doorn + Copyright (C) 2004 - 2010 Ivo van Doorn + Copyright (C) 2010 Willow Garage Copyright (C) 2009 Alban Browaeys Copyright (C) 2009 Felix Fietkau Copyright (C) 2009 Luis Correia @@ -1353,6 +1354,9 @@ * PID_TYPE: The PID latched from the PID field in the TXWI, can be used * to match a frame with its tx result (even though the PID is * only 4 bits wide). + * PID_QUEUE: Part of PID_TYPE, this is the queue index number (0-3) + * PID_ENTRY: Part of PID_TYPE, this is the queue entry index number (1-3) + * This identification number is calculated by ((idx % 3) + 1). * TX_SUCCESS: Indicates tx success (1) or failure (0) * TX_AGGRE: Indicates if the frame was part of an aggregate (1) or not (0) * TX_ACK_REQUIRED: Indicates if the frame needed to get ack'ed (1) or not (0) @@ -1364,6 +1368,8 @@ #define TX_STA_FIFO 0x1718 #define TX_STA_FIFO_VALID FIELD32(0x00000001) #define TX_STA_FIFO_PID_TYPE FIELD32(0x0000001e) +#define TX_STA_FIFO_PID_QUEUE FIELD32(0x00000006) +#define TX_STA_FIFO_PID_ENTRY FIELD32(0x00000018) #define TX_STA_FIFO_TX_SUCCESS FIELD32(0x00000020) #define TX_STA_FIFO_TX_AGGRE FIELD32(0x00000040) #define TX_STA_FIFO_TX_ACK_REQUIRED FIELD32(0x00000080) @@ -2024,6 +2030,10 @@ struct mac_iveiv_entry { * frame was processed. If multiple frames are aggregated together * (AMPDU==1) the reported tx status will always contain the packet * id of the first frame. 0: Don't report tx status for this frame. + * PACKETID_QUEUE: Part of PACKETID, This is the queue index (0-3) + * PACKETID_ENTRY: Part of PACKETID, THis is the queue entry index (1-3) + * This identification number is calculated by ((idx % 3) + 1). + * The (+1) is required to prevent PACKETID to become 0. */ #define TXWI_W1_ACK FIELD32(0x00000001) #define TXWI_W1_NSEQ FIELD32(0x00000002) @@ -2031,6 +2041,8 @@ struct mac_iveiv_entry { #define TXWI_W1_WIRELESS_CLI_ID FIELD32(0x0000ff00) #define TXWI_W1_MPDU_TOTAL_BYTE_COUNT FIELD32(0x0fff0000) #define TXWI_W1_PACKETID FIELD32(0xf0000000) +#define TXWI_W1_PACKETID_QUEUE FIELD32(0x30000000) +#define TXWI_W1_PACKETID_ENTRY FIELD32(0xc0000000) /* * Word2 diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 403e2ed0f44f..8e507d0b5789 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -483,7 +483,8 @@ void rt2800_write_tx_data(struct queue_entry *entry, txdesc->key_idx : 0xff); rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT, txdesc->length); - rt2x00_set_field32(&word, TXWI_W1_PACKETID, txdesc->qid + 1); + rt2x00_set_field32(&word, TXWI_W1_PACKETID_QUEUE, txdesc->qid); + rt2x00_set_field32(&word, TXWI_W1_PACKETID_ENTRY, (entry->entry_idx % 3) + 1); rt2x00_desc_write(txwi, 1, word); /* @@ -708,7 +709,7 @@ void rt2800_txdone(struct rt2x00_dev *rt2x00dev) * Skip this entry when it contains an invalid * queue identication number. */ - pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE) - 1; + pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_QUEUE); if (pid >= QID_RX) continue; -- cgit v1.2.3 From 58ed826e5fb6db429c688284623ca62cb45b9d5c Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Sat, 2 Oct 2010 11:33:17 +0200 Subject: rt2x00: Enable rx aggregation in rt2800 Signed-off-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 8e507d0b5789..028715730b2c 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -3452,8 +3452,12 @@ int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, switch (action) { case IEEE80211_AMPDU_RX_START: case IEEE80211_AMPDU_RX_STOP: - /* we don't support RX aggregation yet */ - ret = -ENOTSUPP; + /* + * The hw itself takes care of setting up BlockAck mechanisms. + * So, we only have to allow mac80211 to nagotiate a BlockAck + * agreement. Once that is done, the hw will BlockAck incoming + * AMPDUs without further setup. + */ break; case IEEE80211_AMPDU_TX_START: ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); -- cgit v1.2.3 From 74ee3802c0021c1387795af234b3e4dc511a9bb3 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Sat, 2 Oct 2010 11:33:42 +0200 Subject: rt2x00: Update comment about the AMPDU flag in the TXWI During testing with AMPDUs it turned out that the rt2800 hw will aggregate consecutive frames with the same RA and TID when the first frame in a possible aggregate has set AMPDU=1 in the TXWI. If a following frame has set AMPDU=0 in its TXWI it might sill end up in the aggregate of the previous frame. Update the comment accordingly. Signed-off-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index 2a9f4020af1e..eb8b6cab9925 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -2003,7 +2003,13 @@ struct mac_iveiv_entry { * duplicate the frame to both channels). * STBC: 1: STBC support MCS =0-7, 2,3 : RESERVED * AMPDU: 1: this frame is eligible for AMPDU aggregation, the hw will - * aggregate consecutive frames with the same RA and QoS TID. + * aggregate consecutive frames with the same RA and QoS TID. If + * a frame A with the same RA and QoS TID but AMPDU=0 is queued + * directly after a frame B with AMPDU=1, frame A might still + * get aggregated into the AMPDU started by frame B. So, setting + * AMPDU to 0 does _not_ necessarily mean the frame is sent as + * MPDU, it can still end up in an AMPDU if the previous frame + * was tagged as AMPDU. */ #define TXWI_W0_FRAG FIELD32(0x00000001) #define TXWI_W0_MIMO_PS FIELD32(0x00000002) -- cgit v1.2.3 From 1f0280cb35ae252d6db3ce8f56b7a1dc174460e5 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Sat, 2 Oct 2010 11:34:05 +0200 Subject: rt2x00: Fix oops caused by error path in rt2x00lib_start When rt2x00lib_enable_radio fails to enable the radio, rt2x00lib_start will call rt2x00queue_uninitialize to uninitialize the queues. Since, the queues are not initialized here but already in rt2x00lib_initialize we shouldn't uninitialize the queues here. Otherwise, a consecutive call to rt2x00lib_start will oops (see below) because it assumes the queues are already initialized. BUG: unable to handle kernel NULL pointer dereference at 00000010 IP: [] :rt2800pci:rt2800pci_clear_entry+0x1/0x40 *pde = 00000000 Oops: 0000 [#1] SMP Modules linked in: ... rt2800pci ... Pid: 5995, comm: hostapd Not tainted (2.6.27.8 #1) EIP: 0060:[] EFLAGS: 00210246 CPU: 3 EIP is at rt2800pci_clear_entry+0x1/0x40 [rt2800pci] EAX: 00000000 EBX: f698863c ECX: 00200296 EDX: f8d2dee0 ESI: f6988600 EDI: f5b6f000 EBP: 00000000 ESP: f6d75e4c DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068 Process hostapd (pid: 5995, ti=f6d74000 task=f6ce2300 task.ti=f6d74000) Stack: f698863c fa00eaec 00000000 f5b6f000 00000000 f7b67000 f5b6e280 fa00c629 f5b6f000 00000000 fa00ca3d f7b67480 00000001 fa177d4c 01b6e890 f7b67000 00000000 f7b67000 00000001 00001003 00001002 c066c366 f7b67000 c0668ad0 Call Trace: [] rt2x00queue_init_queues+0x5c/0x90 [rt2x00lib] [] rt2x00lib_enable_radio+0x29/0xa0 [rt2x00lib] [] rt2x00lib_start+0x5d/0xd0 [rt2x00lib] [] ieee80211_do_open+0x21c/0x510 [mac80211] [] dev_open+0x56/0xb0 [] dev_set_rx_mode+0x20/0x40 [] dev_change_flags+0x7f/0x190 [] devinet_ioctl+0x515/0x690 [] __dev_get_by_name+0x74/0x90 [] sock_ioctl+0xd0/0x240 [] sock_ioctl+0x0/0x240 [] vfs_ioctl+0x2b/0x90 [] do_vfs_ioctl+0x25b/0x2a0 [] sys_ioctl+0x56/0x70 [] syscall_call+0x7/0xb [] add_card+0xad0/0xba0 ======================= Code: 83 78 08 0e 74 14 8b 02 8b 48 04 85 c9 0f 99 c0 0f b6 c0 c3 8d b6 00 00 00 00 8b 02 8b 40 04 85 c0 0f 99 c0 0f b6 c0 c3 66 90 53 <8b> 48 10 8b 58 08 8b 40 04 83 78 08 0e 74 15 8b 11 83 c2 04 8b EIP: [] rt2800pci_clear_entry+0x1/0x40 [rt2800pci] SS:ESP 0068:f6d75e4c ---[ end trace cff9a5c094bb8837 ]--- Reported-by: Joshua Smith Signed-off-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00dev.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index b03e6e41dc1e..6f442b02b83e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -933,10 +933,8 @@ int rt2x00lib_start(struct rt2x00_dev *rt2x00dev) /* Enable the radio */ retval = rt2x00lib_enable_radio(rt2x00dev); - if (retval) { - rt2x00queue_uninitialize(rt2x00dev); + if (retval) return retval; - } set_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags); -- cgit v1.2.3 From 01e946f22ae4bafe370d263f2ef499b8b232aec1 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Sat, 2 Oct 2010 11:34:26 +0200 Subject: rt2x00: Improve cooperation between rt2800pci and minstrel In order to lower the impact of probe rates don't send a frame as AMPDU if the rate control algorithm sets IEEE80211_TX_CTL_RATE_CTRL_PROBE. Otherwise a whole aggregate would be send with a probe rate which might lead to numerous retries. Signed-off-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00ht.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2x00ht.c b/drivers/net/wireless/rt2x00/rt2x00ht.c index 2023419ce0bd..c637bcaec5f8 100644 --- a/drivers/net/wireless/rt2x00/rt2x00ht.c +++ b/drivers/net/wireless/rt2x00/rt2x00ht.c @@ -73,9 +73,11 @@ void rt2x00ht_create_tx_descriptor(struct queue_entry *entry, /* - * Convert flags + * This frame is eligible for an AMPDU, however, don't aggregate + * frames that are intended to probe a specific tx rate. */ - if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) + if (tx_info->flags & IEEE80211_TX_CTL_AMPDU && + !(tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)) __set_bit(ENTRY_TXD_HT_AMPDU, &txdesc->flags); /* -- cgit v1.2.3 From b34793ee27aa547fc9b4213f89036c9a0ecaad5d Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Sat, 2 Oct 2010 11:34:56 +0200 Subject: rt2x00: Work around hw aggregation oddity in rt2800 If a frame is not meant to be sent as AMPDU or part of it the hw might still decide to aggregate this frame if a previous frame started an AMPDU. However, this will limit the usefulness of the reported tx rate since the reported rate will be the one specified in the TXWI of the first frame and thus it is not possible to reliably caculate the number of retrys by substracting the reported tx rate from the tx rate in the TXWI. To fix this issue, only report the successful rate for frames that were not meant to be aggregated but ended up in an aggregate. Example: Frame A (MCS7, AMPDU=1) B (MCS7, AMPDU=1) C (MCS12, AMDPU=0, PROBE_RATE) Although frame C shoudn't be aggregated the hw might sill put it into an AMPDU together with A and B. If the transmission succeeds the tx status will contain MCS7 for all three frames. In that case we should only report MCS7 as success rate and avoid reporting MCS12-MCS8 as failed tx attempts as this will affect the future rate control decisions. This oddity might strike us in other scenarious as well but the most common "wrong" report happened for frames used to probe a different tx rate. This improves the rate control decisions notable. Signed-off-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 028715730b2c..7f040b0eac36 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -634,9 +634,11 @@ static bool rt2800_txdone_entry_check(struct queue_entry *entry, u32 reg) void rt2800_txdone_entry(struct queue_entry *entry, u32 status) { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); struct txdone_entry_desc txdesc; u32 word; u16 mcs, real_mcs; + int aggr, ampdu; __le32 *txwi; /* @@ -645,8 +647,33 @@ void rt2800_txdone_entry(struct queue_entry *entry, u32 status) txdesc.flags = 0; txwi = rt2800_drv_get_txwi(entry); rt2x00_desc_read(txwi, 0, &word); + mcs = rt2x00_get_field32(word, TXWI_W0_MCS); + ampdu = rt2x00_get_field32(word, TXWI_W0_AMPDU); + real_mcs = rt2x00_get_field32(status, TX_STA_FIFO_MCS); + aggr = rt2x00_get_field32(status, TX_STA_FIFO_TX_AGGRE); + + /* + * If a frame was meant to be sent as a single non-aggregated MPDU + * but ended up in an aggregate the used tx rate doesn't correlate + * with the one specified in the TXWI as the whole aggregate is sent + * with the same rate. + * + * For example: two frames are sent to rt2x00, the first one sets + * AMPDU=1 and requests MCS7 whereas the second frame sets AMDPU=0 + * and requests MCS15. If the hw aggregates both frames into one + * AMDPU the tx status for both frames will contain MCS7 although + * the frame was sent successfully. + * + * Hence, replace the requested rate with the real tx rate to not + * confuse the rate control algortihm by providing clearly wrong + * data. + */ + if (aggr == 1 && ampdu == 0 && real_mcs != mcs) { + skbdesc->tx_rate_idx = real_mcs; + mcs = real_mcs; + } /* * Ralink has a retry mechanism using a global fallback -- cgit v1.2.3 From 9eba612549f575d7dccda672ce932e15e7392d83 Mon Sep 17 00:00:00 2001 From: Bruno Randolf Date: Mon, 4 Oct 2010 11:17:30 +0900 Subject: mac80211: Add WME information element for IBSS Enable WME QoS in IBSS mode by adding a WME information element to beacons and probe respones and by checking for it and marking stations as WME capable if it is present. Signed-off-by: Bruno Randolf Signed-off-by: John W. Linville --- net/mac80211/ibss.c | 65 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 43 insertions(+), 22 deletions(-) diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 1a3aae54f0cf..ff60c022f51d 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -173,6 +173,19 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, memcpy(skb_put(skb, ifibss->ie_len), ifibss->ie, ifibss->ie_len); + if (local->hw.queues >= 4) { + 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; /* U-APSD no in use */ + } + rcu_assign_pointer(ifibss->presp, skb); sdata->vif.bss_conf.beacon_int = beacon_int; @@ -266,37 +279,45 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) return; - if (sdata->vif.type == NL80211_IFTYPE_ADHOC && elems->supp_rates && + if (sdata->vif.type == NL80211_IFTYPE_ADHOC && memcmp(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN) == 0) { - supp_rates = ieee80211_sta_get_rates(local, elems, band); rcu_read_lock(); - sta = sta_info_get(sdata, mgmt->sa); - if (sta) { - u32 prev_rates; - prev_rates = sta->sta.supp_rates[band]; - /* make sure mandatory rates are always added */ - sta->sta.supp_rates[band] = supp_rates | - ieee80211_mandatory_rates(local, band); + if (elems->supp_rates) { + supp_rates = ieee80211_sta_get_rates(local, elems, + band); + if (sta) { + u32 prev_rates; - if (sta->sta.supp_rates[band] != prev_rates) { + prev_rates = sta->sta.supp_rates[band]; + /* make sure mandatory rates are always added */ + sta->sta.supp_rates[band] = supp_rates | + ieee80211_mandatory_rates(local, band); + + if (sta->sta.supp_rates[band] != prev_rates) { #ifdef CONFIG_MAC80211_IBSS_DEBUG - printk(KERN_DEBUG "%s: updated supp_rates set " - "for %pM based on beacon/probe_response " - "(0x%x -> 0x%x)\n", - sdata->name, sta->sta.addr, - prev_rates, sta->sta.supp_rates[band]); + printk(KERN_DEBUG + "%s: updated supp_rates set " + "for %pM based on beacon" + "/probe_resp (0x%x -> 0x%x)\n", + sdata->name, sta->sta.addr, + prev_rates, + sta->sta.supp_rates[band]); #endif - rate_control_rate_init(sta); - } - rcu_read_unlock(); - } else { - rcu_read_unlock(); - ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, - supp_rates, GFP_KERNEL); + rate_control_rate_init(sta); + } + } else + sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid, + mgmt->sa, supp_rates, + GFP_ATOMIC); } + + if (sta && elems->wmm_info) + set_sta_flags(sta, WLAN_STA_WME); + + rcu_read_unlock(); } bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, -- cgit v1.2.3 From 2ee4e27cf25ab647137713ca16377d8d9e138ea2 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 4 Oct 2010 14:31:46 +0200 Subject: ipw2200: check for allocation failures If kzalloc() fails then return should return with -ENOMEM. Signed-off-by: Dan Carpenter Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2x00/ipw2200.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index cb2552a6777c..d04d76082777 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -11470,6 +11470,10 @@ static int ipw_net_init(struct net_device *dev) bg_band->channels = kzalloc(geo->bg_channels * sizeof(struct ieee80211_channel), GFP_KERNEL); + if (!bg_band->channels) { + rc = -ENOMEM; + goto out; + } /* translate geo->bg to bg_band.channels */ for (i = 0; i < geo->bg_channels; i++) { bg_band->channels[i].band = IEEE80211_BAND_2GHZ; @@ -11505,6 +11509,10 @@ static int ipw_net_init(struct net_device *dev) a_band->channels = kzalloc(geo->a_channels * sizeof(struct ieee80211_channel), GFP_KERNEL); + if (!a_band->channels) { + rc = -ENOMEM; + goto out; + } /* translate geo->bg to a_band.channels */ for (i = 0; i < geo->a_channels; i++) { a_band->channels[i].band = IEEE80211_BAND_2GHZ; -- cgit v1.2.3 From ff4c92d85c6f2777d2067f8552e7fefb4d1754ae Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 4 Oct 2010 21:14:03 +0200 Subject: genetlink: introduce pre_doit/post_doit hooks Each family may have some amount of boilerplate locking code that applies to most, or even all, commands. This allows a family to handle such things in a more generic way, by allowing it to a) include private flags in each operation b) specify a pre_doit hook that is called, before an operation's doit() callback and may return an error directly, c) specify a post_doit hook that can undo locking or similar things done by pre_doit, and finally d) include two private pointers in each info struct passed between all these operations including doit(). (It's two because I'll need two in nl80211 -- can be extended.) Signed-off-by: Johannes Berg Acked-by: David S. Miller Signed-off-by: John W. Linville --- include/net/genetlink.h | 18 ++++++++++++++++++ net/netlink/genetlink.c | 14 +++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/include/net/genetlink.h b/include/net/genetlink.h index f7dcd2c70412..8a64b811a39a 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h @@ -20,6 +20,9 @@ struct genl_multicast_group { u32 id; }; +struct genl_ops; +struct genl_info; + /** * struct genl_family - generic netlink family * @id: protocol family idenfitier @@ -29,6 +32,10 @@ struct genl_multicast_group { * @maxattr: maximum number of attributes supported * @netnsok: set to true if the family can handle network * namespaces and should be presented in all of them + * @pre_doit: called before an operation's doit callback, it may + * do additional, common, filtering and return an error + * @post_doit: called after an operation's doit callback, it may + * undo operations done by pre_doit, for example release locks * @attrbuf: buffer to store parsed attributes * @ops_list: list of all assigned operations * @family_list: family list @@ -41,6 +48,12 @@ struct genl_family { unsigned int version; unsigned int maxattr; bool netnsok; + int (*pre_doit)(struct genl_ops *ops, + struct sk_buff *skb, + struct genl_info *info); + void (*post_doit)(struct genl_ops *ops, + struct sk_buff *skb, + struct genl_info *info); struct nlattr ** attrbuf; /* private */ struct list_head ops_list; /* private */ struct list_head family_list; /* private */ @@ -55,6 +68,8 @@ struct genl_family { * @genlhdr: generic netlink message header * @userhdr: user specific header * @attrs: netlink attributes + * @_net: network namespace + * @user_ptr: user pointers */ struct genl_info { u32 snd_seq; @@ -66,6 +81,7 @@ struct genl_info { #ifdef CONFIG_NET_NS struct net * _net; #endif + void * user_ptr[2]; }; static inline struct net *genl_info_net(struct genl_info *info) @@ -81,6 +97,7 @@ static inline void genl_info_net_set(struct genl_info *info, struct net *net) /** * struct genl_ops - generic netlink operations * @cmd: command identifier + * @internal_flags: flags used by the family * @flags: flags * @policy: attribute validation policy * @doit: standard command callback @@ -90,6 +107,7 @@ static inline void genl_info_net_set(struct genl_info *info, struct net *net) */ struct genl_ops { u8 cmd; + u8 internal_flags; unsigned int flags; const struct nla_policy *policy; int (*doit)(struct sk_buff *skb, diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index 26ed3e8587c2..1781d99145e2 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -547,8 +547,20 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) info.userhdr = nlmsg_data(nlh) + GENL_HDRLEN; info.attrs = family->attrbuf; genl_info_net_set(&info, net); + memset(&info.user_ptr, 0, sizeof(info.user_ptr)); - return ops->doit(skb, &info); + if (family->pre_doit) { + err = family->pre_doit(ops, skb, &info); + if (err) + return err; + } + + err = ops->doit(skb, &info); + + if (family->post_doit) + family->post_doit(ops, skb, &info); + + return err; } static void genl_rcv(struct sk_buff *skb) -- cgit v1.2.3 From 4c476991062a0a59523c2bf193f09087f469686a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 4 Oct 2010 21:36:35 +0200 Subject: nl80211: use the new genetlink pre/post_doit hooks This makes nl80211 use the new genetlink pre_doit/post_doit hooks for locking and checking the interface/wiphy index. This significantly reduces the code size and the likelihood of locking errors. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/nl80211.c | 1737 +++++++++++++++--------------------------------- 1 file changed, 533 insertions(+), 1204 deletions(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index fd92b6b7ff04..a96da47d0640 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -23,6 +23,11 @@ #include "nl80211.h" #include "reg.h" +static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, + struct genl_info *info); +static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb, + struct genl_info *info); + /* the netlink family */ static struct genl_family nl80211_fam = { .id = GENL_ID_GENERATE, /* don't bother with a hardcoded ID */ @@ -31,6 +36,8 @@ static struct genl_family nl80211_fam = { .version = 1, /* no particular meaning now */ .maxattr = NL80211_ATTR_MAX, .netnsok = true, + .pre_doit = nl80211_pre_doit, + .post_doit = nl80211_post_doit, }; /* internal helper: get rdev and dev */ @@ -704,28 +711,18 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info) { struct sk_buff *msg; - struct cfg80211_registered_device *dev; - - dev = cfg80211_get_dev_from_info(info); - if (IS_ERR(dev)) - return PTR_ERR(dev); + struct cfg80211_registered_device *dev = info->user_ptr[0]; msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) - goto out_err; - - if (nl80211_send_wiphy(msg, info->snd_pid, info->snd_seq, 0, dev) < 0) - goto out_free; + return -ENOMEM; - cfg80211_unlock_rdev(dev); + if (nl80211_send_wiphy(msg, info->snd_pid, info->snd_seq, 0, dev) < 0) { + nlmsg_free(msg); + return -ENOBUFS; + } return genlmsg_reply(msg, info); - - out_free: - nlmsg_free(msg); - out_err: - cfg80211_unlock_rdev(dev); - return -ENOBUFS; } static const struct nla_policy txq_params_policy[NL80211_TXQ_ATTR_MAX + 1] = { @@ -814,24 +811,10 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - struct net_device *netdev; - int result; - - rtnl_lock(); - - result = get_rdev_dev_by_info_ifindex(info, &rdev, &netdev); - if (result) - goto unlock_rtnl; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *netdev = info->user_ptr[1]; - result = __nl80211_set_channel(rdev, netdev->ieee80211_ptr, info); - - dev_put(netdev); - cfg80211_unlock_rdev(rdev); - unlock_rtnl: - rtnl_unlock(); - - return result; + return __nl80211_set_channel(rdev, netdev->ieee80211_ptr, info); } static int nl80211_set_wds_peer(struct sk_buff *skb, struct genl_info *info) @@ -893,8 +876,6 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) u32 frag_threshold = 0, rts_threshold = 0; u8 coverage_class = 0; - rtnl_lock(); - /* * Try to find the wiphy and netdev. Normally this * function shouldn't need the netdev, but this is @@ -921,8 +902,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) rdev = __cfg80211_rdev_from_info(info); if (IS_ERR(rdev)) { mutex_unlock(&cfg80211_mutex); - result = PTR_ERR(rdev); - goto unlock; + return PTR_ERR(rdev); } wdev = NULL; netdev = NULL; @@ -1104,8 +1084,6 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) mutex_unlock(&rdev->mtx); if (netdev) dev_put(netdev); - unlock: - rtnl_unlock(); return result; } @@ -1185,33 +1163,20 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) { struct sk_buff *msg; - struct cfg80211_registered_device *dev; - struct net_device *netdev; - int err; - - err = get_rdev_dev_by_info_ifindex(info, &dev, &netdev); - if (err) - return err; + struct cfg80211_registered_device *dev = info->user_ptr[0]; + struct net_device *netdev = info->user_ptr[1]; msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) - goto out_err; + return -ENOMEM; if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, - dev, netdev) < 0) - goto out_free; - - dev_put(netdev); - cfg80211_unlock_rdev(dev); + dev, netdev) < 0) { + nlmsg_free(msg); + return -ENOBUFS; + } return genlmsg_reply(msg, info); - - out_free: - nlmsg_free(msg); - out_err: - dev_put(netdev); - cfg80211_unlock_rdev(dev); - return -ENOBUFS; } static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = { @@ -1271,39 +1236,29 @@ static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev, static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct vif_params params; int err; enum nl80211_iftype otype, ntype; - struct net_device *dev; + struct net_device *dev = info->user_ptr[1]; u32 _flags, *flags = NULL; bool change = false; memset(¶ms, 0, sizeof(params)); - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rtnl; - otype = ntype = dev->ieee80211_ptr->iftype; if (info->attrs[NL80211_ATTR_IFTYPE]) { ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); if (otype != ntype) change = true; - if (ntype > NL80211_IFTYPE_MAX) { - err = -EINVAL; - goto unlock; - } + if (ntype > NL80211_IFTYPE_MAX) + return -EINVAL; } if (info->attrs[NL80211_ATTR_MESH_ID]) { - if (ntype != NL80211_IFTYPE_MESH_POINT) { - err = -EINVAL; - goto unlock; - } + if (ntype != NL80211_IFTYPE_MESH_POINT) + return -EINVAL; params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); change = true; @@ -1314,20 +1269,18 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) change = true; err = nl80211_valid_4addr(rdev, dev, params.use_4addr, ntype); if (err) - goto unlock; + return err; } else { params.use_4addr = -1; } if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) { - if (ntype != NL80211_IFTYPE_MONITOR) { - err = -EINVAL; - goto unlock; - } + if (ntype != NL80211_IFTYPE_MONITOR) + return -EINVAL; err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS], &_flags); if (err) - goto unlock; + return err; flags = &_flags; change = true; @@ -1341,17 +1294,12 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) if (!err && params.use_4addr != -1) dev->ieee80211_ptr->use_4addr = params.use_4addr; - unlock: - dev_put(dev); - cfg80211_unlock_rdev(rdev); - unlock_rtnl: - rtnl_unlock(); return err; } static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct vif_params params; int err; enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; @@ -1368,19 +1316,9 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) return -EINVAL; } - rtnl_lock(); - - rdev = cfg80211_get_dev_from_info(info); - if (IS_ERR(rdev)) { - err = PTR_ERR(rdev); - goto unlock_rtnl; - } - if (!rdev->ops->add_virtual_intf || - !(rdev->wiphy.interface_modes & (1 << type))) { - err = -EOPNOTSUPP; - goto unlock; - } + !(rdev->wiphy.interface_modes & (1 << type))) + return -EOPNOTSUPP; if (type == NL80211_IFTYPE_MESH_POINT && info->attrs[NL80211_ATTR_MESH_ID]) { @@ -1392,7 +1330,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type); if (err) - goto unlock; + return err; } err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? @@ -1402,38 +1340,18 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) nla_data(info->attrs[NL80211_ATTR_IFNAME]), type, err ? NULL : &flags, ¶ms); - unlock: - cfg80211_unlock_rdev(rdev); - unlock_rtnl: - rtnl_unlock(); return err; } static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - int err; - struct net_device *dev; - - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rtnl; - - if (!rdev->ops->del_virtual_intf) { - err = -EOPNOTSUPP; - goto out; - } + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; - err = rdev->ops->del_virtual_intf(&rdev->wiphy, dev); + if (!rdev->ops->del_virtual_intf) + return -EOPNOTSUPP; - out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - unlock_rtnl: - rtnl_unlock(); - return err; + return rdev->ops->del_virtual_intf(&rdev->wiphy, dev); } struct get_key_cookie { @@ -1486,9 +1404,9 @@ static void get_key_callback(void *c, struct key_params *params) static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; int err; - struct net_device *dev; + struct net_device *dev = info->user_ptr[1]; u8 key_idx = 0; u8 *mac_addr = NULL; struct get_key_cookie cookie = { @@ -1506,30 +1424,17 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_MAC]) mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rtnl; - - if (!rdev->ops->get_key) { - err = -EOPNOTSUPP; - goto out; - } + if (!rdev->ops->get_key) + return -EOPNOTSUPP; msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); - if (!msg) { - err = -ENOMEM; - goto out; - } + if (!msg) + return -ENOMEM; hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, NL80211_CMD_NEW_KEY); - - if (IS_ERR(hdr)) { - err = PTR_ERR(hdr); - goto free_msg; - } + if (IS_ERR(hdr)) + return PTR_ERR(hdr); cookie.msg = msg; cookie.idx = key_idx; @@ -1549,28 +1454,21 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) goto nla_put_failure; genlmsg_end(msg, hdr); - err = genlmsg_reply(msg, info); - goto out; + return genlmsg_reply(msg, info); 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_key(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct key_parse key; int err; - struct net_device *dev; + struct net_device *dev = info->user_ptr[1]; int (*func)(struct wiphy *wiphy, struct net_device *netdev, u8 key_index); @@ -1585,21 +1483,13 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) if (!key.def && !key.defmgmt) return -EINVAL; - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rtnl; - if (key.def) func = rdev->ops->set_default_key; else func = rdev->ops->set_default_mgmt_key; - if (!func) { - err = -EOPNOTSUPP; - goto out; - } + if (!func) + return -EOPNOTSUPP; wdev_lock(dev->ieee80211_ptr); err = nl80211_key_allowed(dev->ieee80211_ptr); @@ -1616,21 +1506,14 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) #endif wdev_unlock(dev->ieee80211_ptr); - out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - - unlock_rtnl: - rtnl_unlock(); - return err; } static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; int err; - struct net_device *dev; + struct net_device *dev = info->user_ptr[1]; struct key_parse key; u8 *mac_addr = NULL; @@ -1644,21 +1527,11 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_MAC]) mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rtnl; - - if (!rdev->ops->add_key) { - err = -EOPNOTSUPP; - goto out; - } + if (!rdev->ops->add_key) + return -EOPNOTSUPP; - if (cfg80211_validate_key_settings(rdev, &key.p, key.idx, mac_addr)) { - err = -EINVAL; - goto out; - } + if (cfg80211_validate_key_settings(rdev, &key.p, key.idx, mac_addr)) + return -EINVAL; wdev_lock(dev->ieee80211_ptr); err = nl80211_key_allowed(dev->ieee80211_ptr); @@ -1667,20 +1540,14 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) mac_addr, &key.p); wdev_unlock(dev->ieee80211_ptr); - out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - unlock_rtnl: - rtnl_unlock(); - return err; } static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; int err; - struct net_device *dev; + struct net_device *dev = info->user_ptr[1]; u8 *mac_addr = NULL; struct key_parse key; @@ -1691,16 +1558,8 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_MAC]) mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rtnl; - - if (!rdev->ops->del_key) { - err = -EOPNOTSUPP; - goto out; - } + if (!rdev->ops->del_key) + return -EOPNOTSUPP; wdev_lock(dev->ieee80211_ptr); err = nl80211_key_allowed(dev->ieee80211_ptr); @@ -1717,13 +1576,6 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) #endif wdev_unlock(dev->ieee80211_ptr); - out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - - unlock_rtnl: - rtnl_unlock(); - return err; } @@ -1731,36 +1583,25 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) { int (*call)(struct wiphy *wiphy, struct net_device *dev, struct beacon_parameters *info); - struct cfg80211_registered_device *rdev; - int err; - struct net_device *dev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; struct beacon_parameters params; int haveinfo = 0; if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL])) 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_AP && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { - err = -EOPNOTSUPP; - goto out; - } + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) + return -EOPNOTSUPP; switch (info->genlhdr->cmd) { case NL80211_CMD_NEW_BEACON: /* these are required for NEW_BEACON */ if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] || !info->attrs[NL80211_ATTR_DTIM_PERIOD] || - !info->attrs[NL80211_ATTR_BEACON_HEAD]) { - err = -EINVAL; - goto out; - } + !info->attrs[NL80211_ATTR_BEACON_HEAD]) + return -EINVAL; call = rdev->ops->add_beacon; break; @@ -1769,14 +1610,11 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) break; default: WARN_ON(1); - err = -EOPNOTSUPP; - goto out; + return -EOPNOTSUPP; } - if (!call) { - err = -EOPNOTSUPP; - goto out; - } + if (!call) + return -EOPNOTSUPP; memset(¶ms, 0, sizeof(params)); @@ -1806,53 +1644,25 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) haveinfo = 1; } - if (!haveinfo) { - err = -EINVAL; - goto out; - } - - err = call(&rdev->wiphy, dev, ¶ms); - - out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - unlock_rtnl: - rtnl_unlock(); + if (!haveinfo) + return -EINVAL; - return err; + return call(&rdev->wiphy, dev, ¶ms); } static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - int err; - struct net_device *dev; - - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rtnl; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; - if (!rdev->ops->del_beacon) { - err = -EOPNOTSUPP; - goto out; - } + if (!rdev->ops->del_beacon) + return -EOPNOTSUPP; if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { - err = -EOPNOTSUPP; - goto out; - } - err = rdev->ops->del_beacon(&rdev->wiphy, dev); - - out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - unlock_rtnl: - rtnl_unlock(); + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) + return -EOPNOTSUPP; - return err; + return rdev->ops->del_beacon(&rdev->wiphy, dev); } static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { @@ -2049,12 +1859,12 @@ static int nl80211_dump_station(struct sk_buff *skb, static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - int err; - struct net_device *dev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; struct station_info sinfo; struct sk_buff *msg; u8 *mac_addr = NULL; + int err; memset(&sinfo, 0, sizeof(sinfo)); @@ -2063,41 +1873,24 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); - rtnl_lock(); + if (!rdev->ops->get_station) + return -EOPNOTSUPP; - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); + err = rdev->ops->get_station(&rdev->wiphy, dev, mac_addr, &sinfo); if (err) - goto out_rtnl; - - if (!rdev->ops->get_station) { - err = -EOPNOTSUPP; - goto out; - } - - err = rdev->ops->get_station(&rdev->wiphy, dev, mac_addr, &sinfo); - if (err) - goto out; + return err; msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) - goto out; + return -ENOMEM; if (nl80211_send_station(msg, info->snd_pid, info->snd_seq, 0, - dev, mac_addr, &sinfo) < 0) - goto out_free; - - err = genlmsg_reply(msg, info); - goto out; - - out_free: - nlmsg_free(msg); - out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - out_rtnl: - rtnl_unlock(); + dev, mac_addr, &sinfo) < 0) { + nlmsg_free(msg); + return -ENOBUFS; + } - return err; + return genlmsg_reply(msg, info); } /* @@ -2127,9 +1920,9 @@ static int get_vlan(struct genl_info *info, static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; int err; - struct net_device *dev; + struct net_device *dev = info->user_ptr[1]; struct station_parameters params; u8 *mac_addr = NULL; @@ -2167,12 +1960,6 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) params.plink_action = nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto out_rtnl; - err = get_vlan(info, rdev, ¶ms.vlan); if (err) goto out; @@ -2234,19 +2021,15 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) out: if (params.vlan) dev_put(params.vlan); - cfg80211_unlock_rdev(rdev); - dev_put(dev); - out_rtnl: - rtnl_unlock(); return err; } static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; int err; - struct net_device *dev; + struct net_device *dev = info->user_ptr[1]; struct station_parameters params; u8 *mac_addr = NULL; @@ -2283,18 +2066,10 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) if (parse_station_flags(info, ¶ms)) return -EINVAL; - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - 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_P2P_GO) { - err = -EINVAL; - goto out; - } + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) + return -EINVAL; err = get_vlan(info, rdev, ¶ms.vlan); if (err) @@ -2318,52 +2093,28 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) out: if (params.vlan) dev_put(params.vlan); - cfg80211_unlock_rdev(rdev); - dev_put(dev); - out_rtnl: - rtnl_unlock(); - return err; } static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - int err; - struct net_device *dev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; u8 *mac_addr = NULL; if (info->attrs[NL80211_ATTR_MAC]) mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - 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_MESH_POINT && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { - err = -EINVAL; - goto out; - } - - if (!rdev->ops->del_station) { - err = -EOPNOTSUPP; - goto out; - } - - err = rdev->ops->del_station(&rdev->wiphy, dev, mac_addr); + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) + return -EINVAL; - out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - out_rtnl: - rtnl_unlock(); + if (!rdev->ops->del_station) + return -EOPNOTSUPP; - return err; + return rdev->ops->del_station(&rdev->wiphy, dev, mac_addr); } static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq, @@ -2490,9 +2241,9 @@ static int nl80211_dump_mpath(struct sk_buff *skb, static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; int err; - struct net_device *dev; + struct net_device *dev = info->user_ptr[1]; struct mpath_info pinfo; struct sk_buff *msg; u8 *dst = NULL; @@ -2505,53 +2256,33 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) dst = nla_data(info->attrs[NL80211_ATTR_MAC]); - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto out_rtnl; - - if (!rdev->ops->get_mpath) { - err = -EOPNOTSUPP; - goto out; - } + if (!rdev->ops->get_mpath) + return -EOPNOTSUPP; - if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { - err = -EOPNOTSUPP; - goto out; - } + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) + return -EOPNOTSUPP; err = rdev->ops->get_mpath(&rdev->wiphy, dev, dst, next_hop, &pinfo); if (err) - goto out; + return err; msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) - goto out; + return -ENOMEM; if (nl80211_send_mpath(msg, info->snd_pid, info->snd_seq, 0, - dev, dst, next_hop, &pinfo) < 0) - goto out_free; - - err = genlmsg_reply(msg, info); - goto out; - - out_free: - nlmsg_free(msg); - out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - out_rtnl: - rtnl_unlock(); + dev, dst, next_hop, &pinfo) < 0) { + nlmsg_free(msg); + return -ENOBUFS; + } - return err; + return genlmsg_reply(msg, info); } static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - int err; - struct net_device *dev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; u8 *dst = NULL; u8 *next_hop = NULL; @@ -2564,42 +2295,22 @@ static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info) dst = nla_data(info->attrs[NL80211_ATTR_MAC]); next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto out_rtnl; - - if (!rdev->ops->change_mpath) { - err = -EOPNOTSUPP; - goto out; - } - - if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { - err = -EOPNOTSUPP; - goto out; - } - - if (!netif_running(dev)) { - err = -ENETDOWN; - goto out; - } + if (!rdev->ops->change_mpath) + return -EOPNOTSUPP; - err = rdev->ops->change_mpath(&rdev->wiphy, dev, dst, next_hop); + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) + return -EOPNOTSUPP; - out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - out_rtnl: - rtnl_unlock(); + if (!netif_running(dev)) + return -ENETDOWN; - return err; + return rdev->ops->change_mpath(&rdev->wiphy, dev, dst, next_hop); } + static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - int err; - struct net_device *dev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; u8 *dst = NULL; u8 *next_hop = NULL; @@ -2612,75 +2323,37 @@ static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) dst = nla_data(info->attrs[NL80211_ATTR_MAC]); next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto out_rtnl; - - if (!rdev->ops->add_mpath) { - err = -EOPNOTSUPP; - goto out; - } - - if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { - err = -EOPNOTSUPP; - goto out; - } - - if (!netif_running(dev)) { - err = -ENETDOWN; - goto out; - } + if (!rdev->ops->add_mpath) + return -EOPNOTSUPP; - err = rdev->ops->add_mpath(&rdev->wiphy, dev, dst, next_hop); + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) + return -EOPNOTSUPP; - out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - out_rtnl: - rtnl_unlock(); + if (!netif_running(dev)) + return -ENETDOWN; - return err; + return rdev->ops->add_mpath(&rdev->wiphy, dev, dst, next_hop); } static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - int err; - struct net_device *dev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; u8 *dst = NULL; if (info->attrs[NL80211_ATTR_MAC]) dst = nla_data(info->attrs[NL80211_ATTR_MAC]); - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto out_rtnl; - - if (!rdev->ops->del_mpath) { - err = -EOPNOTSUPP; - goto out; - } - - err = rdev->ops->del_mpath(&rdev->wiphy, dev, dst); - - out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - out_rtnl: - rtnl_unlock(); + if (!rdev->ops->del_mpath) + return -EOPNOTSUPP; - return err; + return rdev->ops->del_mpath(&rdev->wiphy, dev, dst); } static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - int err; - struct net_device *dev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; struct bss_parameters params; memset(¶ms, 0, sizeof(params)); @@ -2708,32 +2381,14 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_AP_ISOLATE]) params.ap_isolate = !!nla_get_u8(info->attrs[NL80211_ATTR_AP_ISOLATE]); - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto out_rtnl; - - if (!rdev->ops->change_bss) { - err = -EOPNOTSUPP; - goto out; - } + if (!rdev->ops->change_bss) + return -EOPNOTSUPP; if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { - err = -EOPNOTSUPP; - goto out; - } - - err = rdev->ops->change_bss(&rdev->wiphy, dev, ¶ms); - - out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - out_rtnl: - rtnl_unlock(); + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) + return -EOPNOTSUPP; - return err; + return rdev->ops->change_bss(&rdev->wiphy, dev, ¶ms); } static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = { @@ -2812,37 +2467,26 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) static int nl80211_get_mesh_params(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct mesh_config cur_params; int err; - struct net_device *dev; + struct net_device *dev = info->user_ptr[1]; void *hdr; struct nlattr *pinfoattr; struct sk_buff *msg; - rtnl_lock(); - - /* Look up our device */ - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto out_rtnl; - - if (!rdev->ops->get_mesh_params) { - err = -EOPNOTSUPP; - goto out; - } + if (!rdev->ops->get_mesh_params) + return -EOPNOTSUPP; /* Get the mesh params */ err = rdev->ops->get_mesh_params(&rdev->wiphy, dev, &cur_params); if (err) - goto out; + return err; /* Draw up a netlink message to send back */ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); - if (!msg) { - err = -ENOBUFS; - goto out; - } + if (!msg) + return -ENOMEM; hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, NL80211_CMD_GET_MESH_PARAMS); if (!hdr) @@ -2881,22 +2525,13 @@ static int nl80211_get_mesh_params(struct sk_buff *skb, cur_params.dot11MeshHWMPRootMode); nla_nest_end(msg, pinfoattr); genlmsg_end(msg, hdr); - err = genlmsg_reply(msg, info); - goto out; + return genlmsg_reply(msg, info); nla_put_failure: genlmsg_cancel(msg, hdr); nlmsg_free(msg); - err = -EMSGSIZE; - out: - /* Cleanup */ - cfg80211_unlock_rdev(rdev); - dev_put(dev); - out_rtnl: - rtnl_unlock(); - - return err; -} + return -ENOBUFS; +} #define FILL_IN_MESH_PARAM_IF_SET(table, cfg, param, mask, attr_num, nla_fn) \ do {\ @@ -2925,10 +2560,9 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) { - int err; u32 mask; - struct cfg80211_registered_device *rdev; - struct net_device *dev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; struct mesh_config cfg; struct nlattr *tb[NL80211_MESHCONF_ATTR_MAX + 1]; struct nlattr *parent_attr; @@ -2940,16 +2574,8 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) parent_attr, nl80211_meshconf_params_policy)) return -EINVAL; - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto out_rtnl; - - if (!rdev->ops->set_mesh_params) { - err = -EOPNOTSUPP; - goto out; - } + if (!rdev->ops->set_mesh_params) + return -EOPNOTSUPP; /* This makes sure that there aren't more than 32 mesh config * parameters (otherwise our bitfield scheme would not work.) */ @@ -2995,16 +2621,7 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) nla_get_u8); /* Apply changes */ - err = rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask); - - out: - /* cleanup */ - cfg80211_unlock_rdev(rdev); - dev_put(dev); - out_rtnl: - rtnl_unlock(); - - return err; + return rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask); } #undef FILL_IN_MESH_PARAM_IF_SET @@ -3187,8 +2804,8 @@ static int validate_scan_freqs(struct nlattr *freqs) static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - struct net_device *dev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; struct cfg80211_scan_request *request; struct cfg80211_ssid *ssid; struct ieee80211_channel *channel; @@ -3201,36 +2818,22 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) return -EINVAL; - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto out_rtnl; - wiphy = &rdev->wiphy; - if (!rdev->ops->scan) { - err = -EOPNOTSUPP; - goto out; - } + if (!rdev->ops->scan) + return -EOPNOTSUPP; - if (!netif_running(dev)) { - err = -ENETDOWN; - goto out; - } + if (!netif_running(dev)) + return -ENETDOWN; - if (rdev->scan_req) { - err = -EBUSY; - goto out; - } + if (rdev->scan_req) + return -EBUSY; if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { n_channels = validate_scan_freqs( info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]); - if (!n_channels) { - err = -EINVAL; - goto out; - } + if (!n_channels) + return -EINVAL; } else { n_channels = 0; @@ -3243,29 +2846,23 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) n_ssids++; - if (n_ssids > wiphy->max_scan_ssids) { - err = -EINVAL; - goto out; - } + if (n_ssids > wiphy->max_scan_ssids) + return -EINVAL; if (info->attrs[NL80211_ATTR_IE]) ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); else ie_len = 0; - if (ie_len > wiphy->max_scan_ie_len) { - err = -EINVAL; - goto out; - } + if (ie_len > wiphy->max_scan_ie_len) + return -EINVAL; request = kzalloc(sizeof(*request) + sizeof(*ssid) * n_ssids + sizeof(channel) * n_channels + ie_len, GFP_KERNEL); - if (!request) { - err = -ENOMEM; - goto out; - } + if (!request) + return -ENOMEM; if (n_ssids) request->ssids = (void *)&request->channels[n_channels]; @@ -3353,18 +2950,11 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) if (!err) { nl80211_send_scan_start(rdev, dev); dev_hold(dev); - } - + } else { out_free: - if (err) { rdev->scan_req = NULL; kfree(request); } - out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - out_rtnl: - rtnl_unlock(); return err; } @@ -3643,8 +3233,8 @@ static bool nl80211_valid_cipher_suite(u32 cipher) static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - struct net_device *dev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; struct ieee80211_channel *chan; const u8 *bssid, *ssid, *ie = NULL; int err, ssid_len, ie_len = 0; @@ -3686,12 +3276,6 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) key.p.key = NULL; } - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rtnl; - if (key.idx >= 0) { int i; bool ok = false; @@ -3701,35 +3285,25 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) break; } } - if (!ok) { - err = -EINVAL; - goto out; - } + if (!ok) + return -EINVAL; } - if (!rdev->ops->auth) { - err = -EOPNOTSUPP; - goto out; - } + if (!rdev->ops->auth) + return -EOPNOTSUPP; if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { - err = -EOPNOTSUPP; - goto out; - } + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) + return -EOPNOTSUPP; - if (!netif_running(dev)) { - err = -ENETDOWN; - goto out; - } + if (!netif_running(dev)) + return -ENETDOWN; bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); chan = ieee80211_get_channel(&rdev->wiphy, nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); - if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) { - err = -EINVAL; - goto out; - } + if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) + return -EINVAL; ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); @@ -3740,24 +3314,15 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) } auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]); - if (!nl80211_valid_auth_type(auth_type)) { - err = -EINVAL; - goto out; - } + if (!nl80211_valid_auth_type(auth_type)) + return -EINVAL; local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; - err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, - ssid, ssid_len, ie, ie_len, - key.p.key, key.p.key_len, key.idx, - local_state_change); - -out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); -unlock_rtnl: - rtnl_unlock(); - return err; + return cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, + ssid, ssid_len, ie, ie_len, + key.p.key, key.p.key_len, key.idx, + local_state_change); } static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev, @@ -3841,8 +3406,8 @@ static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev, static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - struct net_device *dev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; struct cfg80211_crypto_settings crypto; struct ieee80211_channel *chan; const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL; @@ -3857,36 +3422,22 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) !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->assoc) { - err = -EOPNOTSUPP; - goto out; - } + if (!rdev->ops->assoc) + return -EOPNOTSUPP; if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { - err = -EOPNOTSUPP; - goto out; - } + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) + return -EOPNOTSUPP; - if (!netif_running(dev)) { - err = -ENETDOWN; - goto out; - } + if (!netif_running(dev)) + return -ENETDOWN; bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); chan = ieee80211_get_channel(&rdev->wiphy, nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); - if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) { - err = -EINVAL; - goto out; - } + if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) + return -EINVAL; ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); @@ -3901,10 +3452,8 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]); if (mfp == NL80211_MFP_REQUIRED) use_mfp = true; - else if (mfp != NL80211_MFP_NO) { - err = -EINVAL; - goto out; - } + else if (mfp != NL80211_MFP_NO) + return -EINVAL; } if (info->attrs[NL80211_ATTR_PREV_BSSID]) @@ -3916,20 +3465,15 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) ssid, ssid_len, ie, ie_len, use_mfp, &crypto); -out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); -unlock_rtnl: - rtnl_unlock(); return err; } static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - struct net_device *dev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; const u8 *ie = NULL, *bssid; - int err, ie_len = 0; + int ie_len = 0; u16 reason_code; bool local_state_change; @@ -3942,35 +3486,22 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) if (!info->attrs[NL80211_ATTR_REASON_CODE]) return -EINVAL; - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rtnl; - - if (!rdev->ops->deauth) { - err = -EOPNOTSUPP; - goto out; - } + if (!rdev->ops->deauth) + return -EOPNOTSUPP; if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { - err = -EOPNOTSUPP; - goto out; - } + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) + return -EOPNOTSUPP; - if (!netif_running(dev)) { - err = -ENETDOWN; - goto out; - } + if (!netif_running(dev)) + return -ENETDOWN; bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); if (reason_code == 0) { /* Reason Code 0 is reserved */ - err = -EINVAL; - goto out; + return -EINVAL; } if (info->attrs[NL80211_ATTR_IE]) { @@ -3980,23 +3511,16 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; - err = cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code, - local_state_change); - -out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); -unlock_rtnl: - rtnl_unlock(); - return err; + return cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code, + local_state_change); } static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - struct net_device *dev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; const u8 *ie = NULL, *bssid; - int err, ie_len = 0; + int ie_len = 0; u16 reason_code; bool local_state_change; @@ -4009,35 +3533,22 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) if (!info->attrs[NL80211_ATTR_REASON_CODE]) return -EINVAL; - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rtnl; - - if (!rdev->ops->disassoc) { - err = -EOPNOTSUPP; - goto out; - } + if (!rdev->ops->disassoc) + return -EOPNOTSUPP; if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { - err = -EOPNOTSUPP; - goto out; - } + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) + return -EOPNOTSUPP; - if (!netif_running(dev)) { - err = -ENETDOWN; - goto out; - } + if (!netif_running(dev)) + return -ENETDOWN; bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); if (reason_code == 0) { /* Reason Code 0 is reserved */ - err = -EINVAL; - goto out; + return -EINVAL; } if (info->attrs[NL80211_ATTR_IE]) { @@ -4047,21 +3558,14 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; - err = cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code, - local_state_change); - -out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); -unlock_rtnl: - rtnl_unlock(); - return err; + return cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code, + local_state_change); } static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - struct net_device *dev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; struct cfg80211_ibss_params ibss; struct wiphy *wiphy; struct cfg80211_cached_keys *connkeys = NULL; @@ -4086,26 +3590,14 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) return -EINVAL; } - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rtnl; - - if (!rdev->ops->join_ibss) { - err = -EOPNOTSUPP; - goto out; - } + if (!rdev->ops->join_ibss) + return -EOPNOTSUPP; - if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) { - err = -EOPNOTSUPP; - goto out; - } + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) + return -EOPNOTSUPP; - if (!netif_running(dev)) { - err = -ENETDOWN; - goto out; - } + if (!netif_running(dev)) + return -ENETDOWN; wiphy = &rdev->wiphy; @@ -4123,24 +3615,12 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); if (!ibss.channel || ibss.channel->flags & IEEE80211_CHAN_NO_IBSS || - ibss.channel->flags & IEEE80211_CHAN_DISABLED) { - err = -EINVAL; - goto out; - } + ibss.channel->flags & IEEE80211_CHAN_DISABLED) + return -EINVAL; ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED]; ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY]; - if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) { - connkeys = nl80211_parse_connkeys(rdev, - info->attrs[NL80211_ATTR_KEYS]); - if (IS_ERR(connkeys)) { - err = PTR_ERR(connkeys); - connkeys = NULL; - goto out; - } - } - if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) { u8 *rates = nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); @@ -4150,10 +3630,8 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) wiphy->bands[ibss.channel->band]; int i, j; - if (n_rates == 0) { - err = -EINVAL; - goto out; - } + if (n_rates == 0) + return -EINVAL; for (i = 0; i < n_rates; i++) { int rate = (rates[i] & 0x7f) * 5; @@ -4166,60 +3644,39 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) break; } } - if (!found) { - err = -EINVAL; - goto out; - } + if (!found) + return -EINVAL; } } - err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys); + if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) { + connkeys = nl80211_parse_connkeys(rdev, + info->attrs[NL80211_ATTR_KEYS]); + if (IS_ERR(connkeys)) + return PTR_ERR(connkeys); + } -out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); -unlock_rtnl: + err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys); if (err) kfree(connkeys); - rtnl_unlock(); return err; } static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - struct net_device *dev; - int err; - - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rtnl; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; - if (!rdev->ops->leave_ibss) { - err = -EOPNOTSUPP; - goto out; - } - - if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) { - err = -EOPNOTSUPP; - goto out; - } + if (!rdev->ops->leave_ibss) + return -EOPNOTSUPP; - if (!netif_running(dev)) { - err = -ENETDOWN; - goto out; - } + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) + return -EOPNOTSUPP; - err = cfg80211_leave_ibss(rdev, dev, false); + if (!netif_running(dev)) + return -ENETDOWN; -out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); -unlock_rtnl: - rtnl_unlock(); - return err; + return cfg80211_leave_ibss(rdev, dev, false); } #ifdef CONFIG_NL80211_TESTMODE @@ -4229,20 +3686,12 @@ static struct genl_multicast_group nl80211_testmode_mcgrp = { static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; int err; if (!info->attrs[NL80211_ATTR_TESTDATA]) return -EINVAL; - rtnl_lock(); - - rdev = cfg80211_get_dev_from_info(info); - if (IS_ERR(rdev)) { - err = PTR_ERR(rdev); - goto unlock_rtnl; - } - err = -EOPNOTSUPP; if (rdev->ops->testmode_cmd) { rdev->testmode_info = info; @@ -4252,10 +3701,6 @@ static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info) rdev->testmode_info = NULL; } - cfg80211_unlock_rdev(rdev); - - unlock_rtnl: - rtnl_unlock(); return err; } @@ -4346,8 +3791,8 @@ EXPORT_SYMBOL(cfg80211_testmode_event); static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - struct net_device *dev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; struct cfg80211_connect_params connect; struct wiphy *wiphy; struct cfg80211_cached_keys *connkeys = NULL; @@ -4376,22 +3821,13 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) NL80211_MAX_NR_CIPHER_SUITES); if (err) return err; - 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 && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { - err = -EOPNOTSUPP; - goto out; - } + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) + return -EOPNOTSUPP; - if (!netif_running(dev)) { - err = -ENETDOWN; - goto out; - } + if (!netif_running(dev)) + return -ENETDOWN; wiphy = &rdev->wiphy; @@ -4410,39 +3846,27 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) ieee80211_get_channel(wiphy, nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); if (!connect.channel || - connect.channel->flags & IEEE80211_CHAN_DISABLED) { - err = -EINVAL; - goto out; - } + connect.channel->flags & IEEE80211_CHAN_DISABLED) + return -EINVAL; } if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) { connkeys = nl80211_parse_connkeys(rdev, info->attrs[NL80211_ATTR_KEYS]); - if (IS_ERR(connkeys)) { - err = PTR_ERR(connkeys); - connkeys = NULL; - goto out; - } + if (IS_ERR(connkeys)) + return PTR_ERR(connkeys); } err = cfg80211_connect(rdev, dev, &connect, connkeys); - -out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); -unlock_rtnl: if (err) kfree(connkeys); - rtnl_unlock(); return err; } static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - struct net_device *dev; - int err; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; u16 reason; if (!info->attrs[NL80211_ATTR_REASON_CODE]) @@ -4453,36 +3877,19 @@ static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info) if (reason == 0) 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 && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { - err = -EOPNOTSUPP; - goto out; - } - - if (!netif_running(dev)) { - err = -ENETDOWN; - goto out; - } + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) + return -EOPNOTSUPP; - err = cfg80211_disconnect(rdev, dev, reason, true); + if (!netif_running(dev)) + return -ENETDOWN; -out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); -unlock_rtnl: - rtnl_unlock(); - return err; + return cfg80211_disconnect(rdev, dev, reason, true); } static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct net *net; int err; u32 pid; @@ -4492,43 +3899,26 @@ static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info) pid = nla_get_u32(info->attrs[NL80211_ATTR_PID]); - rtnl_lock(); - - rdev = cfg80211_get_dev_from_info(info); - if (IS_ERR(rdev)) { - err = PTR_ERR(rdev); - goto out_rtnl; - } - net = get_net_ns_by_pid(pid); - if (IS_ERR(net)) { - err = PTR_ERR(net); - goto out; - } + if (IS_ERR(net)) + return PTR_ERR(net); err = 0; /* check if anything to do */ - if (net_eq(wiphy_net(&rdev->wiphy), net)) - goto out_put_net; + if (!net_eq(wiphy_net(&rdev->wiphy), net)) + err = cfg80211_switch_netns(rdev, net); - err = cfg80211_switch_netns(rdev, net); - out_put_net: put_net(net); - out: - cfg80211_unlock_rdev(rdev); - out_rtnl: - rtnl_unlock(); return err; } static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; int (*rdev_ops)(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_pmksa *pmksa) = NULL; - int err; - struct net_device *dev; + struct net_device *dev = info->user_ptr[1]; struct cfg80211_pmksa pmksa; memset(&pmksa, 0, sizeof(struct cfg80211_pmksa)); @@ -4539,20 +3929,12 @@ static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info) if (!info->attrs[NL80211_ATTR_PMKID]) return -EINVAL; - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto out_rtnl; - pmksa.pmkid = nla_data(info->attrs[NL80211_ATTR_PMKID]); pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { - err = -EOPNOTSUPP; - goto out; - } + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) + return -EOPNOTSUPP; switch (info->genlhdr->cmd) { case NL80211_CMD_SET_PMKSA: @@ -4566,62 +3948,32 @@ static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info) break; } - if (!rdev_ops) { - err = -EOPNOTSUPP; - goto out; - } - - err = rdev_ops(&rdev->wiphy, dev, &pmksa); - - out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - out_rtnl: - rtnl_unlock(); + if (!rdev_ops) + return -EOPNOTSUPP; - return err; + return rdev_ops(&rdev->wiphy, dev, &pmksa); } static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - int err; - struct net_device *dev; - - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto out_rtnl; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { - err = -EOPNOTSUPP; - goto out; - } - - if (!rdev->ops->flush_pmksa) { - err = -EOPNOTSUPP; - goto out; - } - - err = rdev->ops->flush_pmksa(&rdev->wiphy, dev); - - out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - out_rtnl: - rtnl_unlock(); + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) + return -EOPNOTSUPP; - return err; + if (!rdev->ops->flush_pmksa) + return -EOPNOTSUPP; + return rdev->ops->flush_pmksa(&rdev->wiphy, dev); } static int nl80211_remain_on_channel(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - struct net_device *dev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; struct ieee80211_channel *chan; struct sk_buff *msg; void *hdr; @@ -4643,21 +3995,11 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, 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 (!rdev->ops->remain_on_channel) + return -EOPNOTSUPP; - if (!netif_running(dev)) { - err = -ENETDOWN; - goto out; - } + if (!netif_running(dev)) + return -ENETDOWN; if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { channel_type = nla_get_u32( @@ -4665,24 +4007,18 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, 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; - } + channel_type != NL80211_CHAN_HT40MINUS) + return -EINVAL; } 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; - } + if (chan == NULL) + return -EINVAL; msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); - if (!msg) { - err = -ENOMEM; - goto out; - } + if (!msg) + return -ENOMEM; hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, NL80211_CMD_REMAIN_ON_CHANNEL); @@ -4701,58 +4037,35 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); genlmsg_end(msg, hdr); - err = genlmsg_reply(msg, info); - goto out; + + return genlmsg_reply(msg, info); 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; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; 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 (!rdev->ops->cancel_remain_on_channel) + return -EOPNOTSUPP; - if (!netif_running(dev)) { - err = -ENETDOWN; - goto out; - } + if (!netif_running(dev)) + return -ENETDOWN; 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; + return rdev->ops->cancel_remain_on_channel(&rdev->wiphy, dev, cookie); } static u32 rateset_to_mask(struct ieee80211_supported_band *sband, @@ -4788,26 +4101,18 @@ 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_registered_device *rdev = info->user_ptr[0]; struct cfg80211_bitrate_mask mask; - int err, rem, i; - struct net_device *dev; + int rem, i; + struct net_device *dev = info->user_ptr[1]; 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; - } + if (!rdev->ops->set_bitrate_mask) + return -EOPNOTSUPP; memset(&mask, 0, sizeof(mask)); /* Default to all rates enabled */ @@ -4824,15 +4129,11 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, 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; - } + if (band < 0 || band >= IEEE80211_NUM_BANDS) + return -EINVAL; sband = rdev->wiphy.bands[band]; - if (sband == NULL) { - err = -EINVAL; - goto unlock; - } + if (sband == NULL) + return -EINVAL; nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates), nla_len(tx_rates), nl80211_txattr_policy); if (tb[NL80211_TXRATE_LEGACY]) { @@ -4840,29 +4141,19 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, sband, nla_data(tb[NL80211_TXRATE_LEGACY]), nla_len(tb[NL80211_TXRATE_LEGACY])); - if (mask.control[band].legacy == 0) { - err = -EINVAL; - goto unlock; - } + if (mask.control[band].legacy == 0) + return -EINVAL; } } - 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; + return rdev->ops->set_bitrate_mask(&rdev->wiphy, dev, NULL, &mask); } static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - struct net_device *dev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; u16 frame_type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION; - int err; if (!info->attrs[NL80211_ATTR_FRAME_MATCH]) return -EINVAL; @@ -4870,44 +4161,28 @@ static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_FRAME_TYPE]) frame_type = nla_get_u16(info->attrs[NL80211_ATTR_FRAME_TYPE]); - 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 && dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { - err = -EOPNOTSUPP; - goto out; - } + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) + return -EOPNOTSUPP; /* not much point in registering if we can't reply */ - if (!rdev->ops->mgmt_tx) { - err = -EOPNOTSUPP; - goto out; - } + if (!rdev->ops->mgmt_tx) + return -EOPNOTSUPP; - err = cfg80211_mlme_register_mgmt(dev->ieee80211_ptr, info->snd_pid, + return cfg80211_mlme_register_mgmt(dev->ieee80211_ptr, info->snd_pid, frame_type, 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_tx_mgmt(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - struct net_device *dev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; struct ieee80211_channel *chan; enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; bool channel_type_valid = false; @@ -4921,31 +4196,19 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) !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->mgmt_tx) { - err = -EOPNOTSUPP; - goto out; - } + if (!rdev->ops->mgmt_tx) + return -EOPNOTSUPP; if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { - err = -EOPNOTSUPP; - goto out; - } + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) + return -EOPNOTSUPP; - if (!netif_running(dev)) { - err = -ENETDOWN; - goto out; - } + if (!netif_running(dev)) + return -ENETDOWN; if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { channel_type = nla_get_u32( @@ -4953,25 +4216,19 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) 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; - } + channel_type != NL80211_CHAN_HT40MINUS) + return -EINVAL; channel_type_valid = true; } 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; - } + if (chan == NULL) + return -EINVAL; msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); - if (!msg) { - err = -ENOMEM; - goto out; - } + if (!msg) + return -ENOMEM; hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, NL80211_CMD_FRAME); @@ -4991,110 +4248,72 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); genlmsg_end(msg, hdr); - err = genlmsg_reply(msg, info); - goto out; + return genlmsg_reply(msg, info); 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 cfg80211_registered_device *rdev = info->user_ptr[0]; struct wireless_dev *wdev; - struct net_device *dev; + struct net_device *dev = info->user_ptr[1]; u8 ps_state; bool state; int err; - if (!info->attrs[NL80211_ATTR_PS_STATE]) { - err = -EINVAL; - goto out; - } + if (!info->attrs[NL80211_ATTR_PS_STATE]) + return -EINVAL; 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_rtnl; + if (ps_state != NL80211_PS_DISABLED && ps_state != NL80211_PS_ENABLED) + return -EINVAL; wdev = dev->ieee80211_ptr; - if (!rdev->ops->set_power_mgmt) { - err = -EOPNOTSUPP; - goto unlock_rdev; - } + if (!rdev->ops->set_power_mgmt) + return -EOPNOTSUPP; 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); -unlock_rtnl: - rtnl_unlock(); + return 0; -out: + err = rdev->ops->set_power_mgmt(wdev->wiphy, dev, state, + wdev->ps_timeout); + if (!err) + wdev->ps = state; return err; } static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; enum nl80211_ps_state ps_state; struct wireless_dev *wdev; - struct net_device *dev; + struct net_device *dev = info->user_ptr[1]; 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; - } + if (!rdev->ops->set_power_mgmt) + return -EOPNOTSUPP; msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); - if (!msg) { - err = -ENOMEM; - goto out; - } + if (!msg) + return -ENOMEM; hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, NL80211_CMD_GET_POWER_SAVE); if (!hdr) { - err = -ENOMEM; + err = -ENOBUFS; goto free_msg; } @@ -5106,22 +4325,12 @@ static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info) NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE, ps_state); genlmsg_end(msg, hdr); - err = genlmsg_reply(msg, info); - goto out; + return genlmsg_reply(msg, info); -nla_put_failure: + nla_put_failure: err = -ENOBUFS; - -free_msg: + free_msg: nlmsg_free(msg); - -out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - -unlock_rtnl: - rtnl_unlock(); - return err; } @@ -5135,43 +4344,24 @@ nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] __read_mostly = { static int nl80211_set_cqm_rssi(struct genl_info *info, s32 threshold, u32 hysteresis) { - struct cfg80211_registered_device *rdev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct wireless_dev *wdev; - struct net_device *dev; - int err; + struct net_device *dev = info->user_ptr[1]; if (threshold > 0) return -EINVAL; - 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_cqm_rssi_config) { - err = -EOPNOTSUPP; - goto unlock_rdev; - } + if (!rdev->ops->set_cqm_rssi_config) + return -EOPNOTSUPP; if (wdev->iftype != NL80211_IFTYPE_STATION && - wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) { - err = -EOPNOTSUPP; - goto unlock_rdev; - } - - err = rdev->ops->set_cqm_rssi_config(wdev->wiphy, dev, - threshold, hysteresis); - - unlock_rdev: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - unlock_rtnl: - rtnl_unlock(); + wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) + return -EOPNOTSUPP; - return err; + return rdev->ops->set_cqm_rssi_config(wdev->wiphy, dev, + threshold, hysteresis); } static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info) @@ -5205,6 +4395,54 @@ out: return err; } +#define NL80211_FLAG_NEED_WIPHY 0x01 +#define NL80211_FLAG_NEED_NETDEV 0x02 +#define NL80211_FLAG_NEED_RTNL 0x04 + +static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, + struct genl_info *info) +{ + struct cfg80211_registered_device *rdev; + struct net_device *dev; + int err; + bool rtnl = ops->internal_flags & NL80211_FLAG_NEED_RTNL; + + if (rtnl) + rtnl_lock(); + + if (ops->internal_flags & NL80211_FLAG_NEED_WIPHY) { + rdev = cfg80211_get_dev_from_info(info); + if (IS_ERR(rdev)) { + if (rtnl) + rtnl_unlock(); + return PTR_ERR(rdev); + } + info->user_ptr[0] = rdev; + } else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) { + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); + if (err) { + if (rtnl) + rtnl_unlock(); + return err; + } + info->user_ptr[0] = rdev; + info->user_ptr[1] = dev; + } + + return 0; +} + +static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb, + struct genl_info *info) +{ + if (info->user_ptr[0]) + cfg80211_unlock_rdev(info->user_ptr[0]); + if (info->user_ptr[1]) + dev_put(info->user_ptr[1]); + if (ops->internal_flags & NL80211_FLAG_NEED_RTNL) + rtnl_unlock(); +} + static struct genl_ops nl80211_ops[] = { { .cmd = NL80211_CMD_GET_WIPHY, @@ -5212,12 +4450,14 @@ static struct genl_ops nl80211_ops[] = { .dumpit = nl80211_dump_wiphy, .policy = nl80211_policy, /* can be retrieved by unprivileged users */ + .internal_flags = NL80211_FLAG_NEED_WIPHY, }, { .cmd = NL80211_CMD_SET_WIPHY, .doit = nl80211_set_wiphy, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_GET_INTERFACE, @@ -5225,90 +4465,119 @@ static struct genl_ops nl80211_ops[] = { .dumpit = nl80211_dump_interface, .policy = nl80211_policy, /* can be retrieved by unprivileged users */ + .internal_flags = NL80211_FLAG_NEED_NETDEV, }, { .cmd = NL80211_CMD_SET_INTERFACE, .doit = nl80211_set_interface, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_NEW_INTERFACE, .doit = nl80211_new_interface, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_WIPHY | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_DEL_INTERFACE, .doit = nl80211_del_interface, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_GET_KEY, .doit = nl80211_get_key, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_SET_KEY, .doit = nl80211_set_key, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_NEW_KEY, .doit = nl80211_new_key, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_DEL_KEY, .doit = nl80211_del_key, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_SET_BEACON, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, .doit = nl80211_addset_beacon, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_NEW_BEACON, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, .doit = nl80211_addset_beacon, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_DEL_BEACON, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, .doit = nl80211_del_beacon, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_GET_STATION, .doit = nl80211_get_station, .dumpit = nl80211_dump_station, .policy = nl80211_policy, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_SET_STATION, .doit = nl80211_set_station, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_NEW_STATION, .doit = nl80211_new_station, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_DEL_STATION, .doit = nl80211_del_station, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_GET_MPATH, @@ -5316,30 +4585,40 @@ static struct genl_ops nl80211_ops[] = { .dumpit = nl80211_dump_mpath, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_SET_MPATH, .doit = nl80211_set_mpath, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_NEW_MPATH, .doit = nl80211_new_mpath, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_DEL_MPATH, .doit = nl80211_del_mpath, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_SET_BSS, .doit = nl80211_set_bss, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_GET_REG, @@ -5364,18 +4643,24 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_get_mesh_params, .policy = nl80211_policy, /* can be retrieved by unprivileged users */ + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_SET_MESH_PARAMS, .doit = nl80211_set_mesh_params, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_TRIGGER_SCAN, .doit = nl80211_trigger_scan, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_GET_SCAN, @@ -5387,36 +4672,48 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_authenticate, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_ASSOCIATE, .doit = nl80211_associate, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_DEAUTHENTICATE, .doit = nl80211_deauthenticate, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_DISASSOCIATE, .doit = nl80211_disassociate, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_JOIN_IBSS, .doit = nl80211_join_ibss, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_LEAVE_IBSS, .doit = nl80211_leave_ibss, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, #ifdef CONFIG_NL80211_TESTMODE { @@ -5424,6 +4721,8 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_testmode_do, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_WIPHY | + NL80211_FLAG_NEED_RTNL, }, #endif { @@ -5431,18 +4730,24 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_connect, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_DISCONNECT, .doit = nl80211_disconnect, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_SET_WIPHY_NETNS, .doit = nl80211_wiphy_netns, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_WIPHY | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_GET_SURVEY, @@ -5454,72 +4759,96 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_setdel_pmksa, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_DEL_PMKSA, .doit = nl80211_setdel_pmksa, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_FLUSH_PMKSA, .doit = nl80211_flush_pmksa, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_REMAIN_ON_CHANNEL, .doit = nl80211_remain_on_channel, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, .doit = nl80211_cancel_remain_on_channel, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_SET_TX_BITRATE_MASK, .doit = nl80211_set_tx_bitrate_mask, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_REGISTER_FRAME, .doit = nl80211_register_mgmt, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_FRAME, .doit = nl80211_tx_mgmt, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_SET_POWER_SAVE, .doit = nl80211_set_power_save, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_GET_POWER_SAVE, .doit = nl80211_get_power_save, .policy = nl80211_policy, /* can be retrieved by unprivileged users */ + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_SET_CQM, .doit = nl80211_set_cqm, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_SET_CHANNEL, .doit = nl80211_set_channel, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_SET_WDS_PEER, -- cgit v1.2.3 From 41265714810e20d91ddd7aaca30043b0f12190ad Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 4 Oct 2010 21:14:05 +0200 Subject: nl80211: use generic check for netif_running Use a new flag that requires the netdev to be UP and use it to check instead of coding the check into all functions that require it. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/nl80211.c | 97 +++++++++++++++----------------------------------- 1 file changed, 28 insertions(+), 69 deletions(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index a96da47d0640..ca8d04cb172f 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -411,9 +411,6 @@ static int nl80211_key_allowed(struct wireless_dev *wdev) { ASSERT_WDEV_LOCK(wdev); - if (!netif_running(wdev->netdev)) - return -ENETDOWN; - switch (wdev->iftype) { case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP_VLAN: @@ -2083,11 +2080,6 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) goto out; } - if (!netif_running(dev)) { - err = -ENETDOWN; - goto out; - } - err = rdev->ops->add_station(&rdev->wiphy, dev, mac_addr, ¶ms); out: @@ -2301,9 +2293,6 @@ static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info) if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) return -EOPNOTSUPP; - if (!netif_running(dev)) - return -ENETDOWN; - return rdev->ops->change_mpath(&rdev->wiphy, dev, dst, next_hop); } @@ -2329,9 +2318,6 @@ static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) return -EOPNOTSUPP; - if (!netif_running(dev)) - return -ENETDOWN; - return rdev->ops->add_mpath(&rdev->wiphy, dev, dst, next_hop); } @@ -2823,9 +2809,6 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) if (!rdev->ops->scan) return -EOPNOTSUPP; - if (!netif_running(dev)) - return -ENETDOWN; - if (rdev->scan_req) return -EBUSY; @@ -3296,9 +3279,6 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) return -EOPNOTSUPP; - if (!netif_running(dev)) - return -ENETDOWN; - bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); chan = ieee80211_get_channel(&rdev->wiphy, nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); @@ -3429,9 +3409,6 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) return -EOPNOTSUPP; - if (!netif_running(dev)) - return -ENETDOWN; - bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); chan = ieee80211_get_channel(&rdev->wiphy, @@ -3493,9 +3470,6 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) return -EOPNOTSUPP; - if (!netif_running(dev)) - return -ENETDOWN; - bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); @@ -3540,9 +3514,6 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) return -EOPNOTSUPP; - if (!netif_running(dev)) - return -ENETDOWN; - bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); @@ -3596,9 +3567,6 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) return -EOPNOTSUPP; - if (!netif_running(dev)) - return -ENETDOWN; - wiphy = &rdev->wiphy; if (info->attrs[NL80211_ATTR_MAC]) @@ -3673,9 +3641,6 @@ static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info) if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) return -EOPNOTSUPP; - if (!netif_running(dev)) - return -ENETDOWN; - return cfg80211_leave_ibss(rdev, dev, false); } @@ -3826,9 +3791,6 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) return -EOPNOTSUPP; - if (!netif_running(dev)) - return -ENETDOWN; - wiphy = &rdev->wiphy; if (info->attrs[NL80211_ATTR_MAC]) @@ -3881,9 +3843,6 @@ static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info) dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) return -EOPNOTSUPP; - if (!netif_running(dev)) - return -ENETDOWN; - return cfg80211_disconnect(rdev, dev, reason, true); } @@ -3998,9 +3957,6 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, if (!rdev->ops->remain_on_channel) return -EOPNOTSUPP; - if (!netif_running(dev)) - return -ENETDOWN; - if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { channel_type = nla_get_u32( info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]); @@ -4060,9 +4016,6 @@ static int nl80211_cancel_remain_on_channel(struct sk_buff *skb, if (!rdev->ops->cancel_remain_on_channel) return -EOPNOTSUPP; - if (!netif_running(dev)) - return -ENETDOWN; - cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]); return rdev->ops->cancel_remain_on_channel(&rdev->wiphy, dev, cookie); @@ -4207,9 +4160,6 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) return -EOPNOTSUPP; - if (!netif_running(dev)) - return -ENETDOWN; - if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { channel_type = nla_get_u32( info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]); @@ -4398,6 +4348,9 @@ out: #define NL80211_FLAG_NEED_WIPHY 0x01 #define NL80211_FLAG_NEED_NETDEV 0x02 #define NL80211_FLAG_NEED_RTNL 0x04 +#define NL80211_FLAG_CHECK_NETDEV_UP 0x08 +#define NL80211_FLAG_NEED_NETDEV_UP (NL80211_FLAG_NEED_NETDEV |\ + NL80211_FLAG_CHECK_NETDEV_UP) static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, struct genl_info *info) @@ -4425,6 +4378,12 @@ static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, rtnl_unlock(); return err; } + if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP && + !netif_running(dev)) { + if (rtnl) + rtnl_unlock(); + return -ENETDOWN; + } info->user_ptr[0] = rdev; info->user_ptr[1] = dev; } @@ -4504,7 +4463,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_set_key, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -4512,7 +4471,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_new_key, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -4520,7 +4479,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_del_key, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -4568,7 +4527,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_new_station, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -4585,7 +4544,7 @@ static struct genl_ops nl80211_ops[] = { .dumpit = nl80211_dump_mpath, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -4593,7 +4552,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_set_mpath, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -4601,7 +4560,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_new_mpath, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -4659,7 +4618,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_trigger_scan, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -4672,7 +4631,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_authenticate, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -4680,7 +4639,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_associate, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -4688,7 +4647,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_deauthenticate, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -4696,7 +4655,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_disassociate, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -4704,7 +4663,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_join_ibss, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -4712,7 +4671,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_leave_ibss, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, #ifdef CONFIG_NL80211_TESTMODE @@ -4730,7 +4689,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_connect, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -4738,7 +4697,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_disconnect, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -4783,7 +4742,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_remain_on_channel, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -4791,7 +4750,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_cancel_remain_on_channel, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -4815,7 +4774,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_tx_mgmt, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { -- cgit v1.2.3 From 6774889314ba507483e63c014fcb81adfc127202 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 4 Oct 2010 21:14:06 +0200 Subject: nl80211: reduce dumping boilerplate Consolidate boilerplate code needed for .dumpit calls operating on netdevs. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/nl80211.c | 151 +++++++++++++++++++------------------------------ 1 file changed, 59 insertions(+), 92 deletions(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index ca8d04cb172f..0c9497170f1f 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -198,6 +198,47 @@ static int nl80211_get_ifidx(struct netlink_callback *cb) return res; } +static int nl80211_prepare_netdev_dump(struct sk_buff *skb, + struct netlink_callback *cb, + struct cfg80211_registered_device **rdev, + struct net_device **dev) +{ + int ifidx = cb->args[0]; + int err; + + if (!ifidx) + ifidx = nl80211_get_ifidx(cb); + if (ifidx < 0) + return ifidx; + + cb->args[0] = ifidx; + + rtnl_lock(); + + *dev = __dev_get_by_index(sock_net(skb->sk), ifidx); + if (!*dev) { + err = -ENODEV; + goto out_rtnl; + } + + *rdev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); + if (IS_ERR(dev)) { + err = PTR_ERR(dev); + goto out_rtnl; + } + + return 0; + out_rtnl: + rtnl_unlock(); + return err; +} + +static void nl80211_finish_netdev_dump(struct cfg80211_registered_device *rdev) +{ + cfg80211_unlock_rdev(rdev); + rtnl_unlock(); +} + /* IE validation */ static bool is_valid_ie_attr(const struct nlattr *attr) { @@ -1796,28 +1837,12 @@ static int nl80211_dump_station(struct sk_buff *skb, struct cfg80211_registered_device *dev; struct net_device *netdev; u8 mac_addr[ETH_ALEN]; - int ifidx = cb->args[0]; int sta_idx = cb->args[1]; int err; - if (!ifidx) - ifidx = nl80211_get_ifidx(cb); - if (ifidx < 0) - return ifidx; - - rtnl_lock(); - - netdev = __dev_get_by_index(sock_net(skb->sk), ifidx); - if (!netdev) { - err = -ENODEV; - goto out_rtnl; - } - - dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); - if (IS_ERR(dev)) { - err = PTR_ERR(dev); - goto out_rtnl; - } + err = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev); + if (err) + return err; if (!dev->ops->dump_station) { err = -EOPNOTSUPP; @@ -1847,9 +1872,7 @@ static int nl80211_dump_station(struct sk_buff *skb, cb->args[1] = sta_idx; err = skb->len; out_err: - cfg80211_unlock_rdev(dev); - out_rtnl: - rtnl_unlock(); + nl80211_finish_netdev_dump(dev); return err; } @@ -2169,28 +2192,12 @@ static int nl80211_dump_mpath(struct sk_buff *skb, struct net_device *netdev; u8 dst[ETH_ALEN]; u8 next_hop[ETH_ALEN]; - int ifidx = cb->args[0]; int path_idx = cb->args[1]; int err; - if (!ifidx) - ifidx = nl80211_get_ifidx(cb); - if (ifidx < 0) - return ifidx; - - rtnl_lock(); - - netdev = __dev_get_by_index(sock_net(skb->sk), ifidx); - if (!netdev) { - err = -ENODEV; - goto out_rtnl; - } - - dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); - if (IS_ERR(dev)) { - err = PTR_ERR(dev); - goto out_rtnl; - } + err = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev); + if (err) + return err; if (!dev->ops->dump_mpath) { err = -EOPNOTSUPP; @@ -2224,10 +2231,7 @@ static int nl80211_dump_mpath(struct sk_buff *skb, cb->args[1] = path_idx; err = skb->len; out_err: - cfg80211_unlock_rdev(dev); - out_rtnl: - rtnl_unlock(); - + nl80211_finish_netdev_dump(dev); return err; } @@ -3034,25 +3038,12 @@ static int nl80211_dump_scan(struct sk_buff *skb, struct net_device *dev; struct cfg80211_internal_bss *scan; struct wireless_dev *wdev; - int ifidx = cb->args[0]; int start = cb->args[1], idx = 0; int err; - if (!ifidx) - ifidx = nl80211_get_ifidx(cb); - if (ifidx < 0) - return ifidx; - cb->args[0] = ifidx; - - dev = dev_get_by_index(sock_net(skb->sk), ifidx); - if (!dev) - return -ENODEV; - - rdev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); - if (IS_ERR(rdev)) { - err = PTR_ERR(rdev); - goto out_put_netdev; - } + err = nl80211_prepare_netdev_dump(skb, cb, &rdev, &dev); + if (err) + return err; wdev = dev->ieee80211_ptr; @@ -3068,21 +3059,17 @@ static int nl80211_dump_scan(struct sk_buff *skb, cb->nlh->nlmsg_seq, NLM_F_MULTI, rdev, wdev, scan) < 0) { idx--; - goto out; + break; } } - out: spin_unlock_bh(&rdev->bss_lock); wdev_unlock(wdev); cb->args[1] = idx; - err = skb->len; - cfg80211_unlock_rdev(rdev); - out_put_netdev: - dev_put(dev); + nl80211_finish_netdev_dump(rdev); - return err; + return skb->len; } static int nl80211_send_survey(struct sk_buff *msg, u32 pid, u32 seq, @@ -3130,29 +3117,12 @@ static int nl80211_dump_survey(struct sk_buff *skb, struct survey_info survey; struct cfg80211_registered_device *dev; struct net_device *netdev; - int ifidx = cb->args[0]; int survey_idx = cb->args[1]; int res; - if (!ifidx) - ifidx = nl80211_get_ifidx(cb); - if (ifidx < 0) - return ifidx; - cb->args[0] = ifidx; - - rtnl_lock(); - - netdev = __dev_get_by_index(sock_net(skb->sk), ifidx); - if (!netdev) { - res = -ENODEV; - goto out_rtnl; - } - - dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); - if (IS_ERR(dev)) { - res = PTR_ERR(dev); - goto out_rtnl; - } + res = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev); + if (res) + return res; if (!dev->ops->dump_survey) { res = -EOPNOTSUPP; @@ -3180,10 +3150,7 @@ static int nl80211_dump_survey(struct sk_buff *skb, cb->args[1] = survey_idx; res = skb->len; out_err: - cfg80211_unlock_rdev(dev); - out_rtnl: - rtnl_unlock(); - + nl80211_finish_netdev_dump(dev); return res; } -- cgit v1.2.3 From 025e6be220e448c02045e8499c7db8ce4bc8eea2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 5 Oct 2010 10:41:47 +0200 Subject: mac80211: fix deadlock with multiple interfaces The locking around ieee80211_recalc_smps is buggy -- it cannot acquire another interface's mutex while the iflist mutex is held because another code path could be holding the iface mutex and trying to acquire the iflist mutex. But the locking is also unnecessary, we only check "ifmgd->associated" as a bool, and don't use the pointer (in check_mgd_smps). Reported-by: Ben Greear Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 2 +- net/mac80211/ieee80211_i.h | 3 +-- net/mac80211/main.c | 2 +- net/mac80211/mlme.c | 2 +- net/mac80211/util.c | 20 +++----------------- 5 files changed, 7 insertions(+), 22 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index a7a78f28ff6f..94bf550bd4c9 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1394,7 +1394,7 @@ int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, if (!sdata->u.mgd.associated || sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) { mutex_lock(&sdata->local->iflist_mtx); - ieee80211_recalc_smps(sdata->local, sdata); + ieee80211_recalc_smps(sdata->local); mutex_unlock(&sdata->local->iflist_mtx); return 0; } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 55d79db985fc..08509e212841 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1297,8 +1297,7 @@ u32 ieee80211_sta_get_rates(struct ieee80211_local *local, 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); +void ieee80211_recalc_smps(struct ieee80211_local *local); size_t ieee80211_ie_split(const u8 *ies, size_t ielen, const u8 *ids, int n_ids, size_t offset); diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 9c2f3f934c74..e3717092115f 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -333,7 +333,7 @@ static void ieee80211_recalc_smps_work(struct work_struct *work) container_of(work, struct ieee80211_local, recalc_smps); mutex_lock(&local->iflist_mtx); - ieee80211_recalc_smps(local, NULL); + ieee80211_recalc_smps(local); mutex_unlock(&local->iflist_mtx); } diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index c37086a12f51..2b2982782bcd 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -913,7 +913,7 @@ 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); + ieee80211_recalc_smps(local); mutex_unlock(&local->iflist_mtx); netif_tx_start_all_queues(sdata->dev); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index aba025d748e9..4ee8f2b53cb7 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1297,16 +1297,12 @@ static int check_mgd_smps(struct ieee80211_if_managed *ifmgd, } /* must hold iflist_mtx */ -void ieee80211_recalc_smps(struct ieee80211_local *local, - struct ieee80211_sub_if_data *forsdata) +void ieee80211_recalc_smps(struct ieee80211_local *local) { struct ieee80211_sub_if_data *sdata; enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_OFF; int count = 0; - if (forsdata) - lockdep_assert_held(&forsdata->u.mgd.mtx); - lockdep_assert_held(&local->iflist_mtx); /* @@ -1324,18 +1320,8 @@ void ieee80211_recalc_smps(struct ieee80211_local *local, 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); + + count += check_mgd_smps(&sdata->u.mgd, &smps_mode); if (count > 1) { smps_mode = IEEE80211_SMPS_OFF; -- cgit v1.2.3 From 4198a8d036c998ca8cec1b08116ab9f6a3a9ffff Mon Sep 17 00:00:00 2001 From: Bruno Randolf Date: Tue, 5 Oct 2010 13:27:17 +0900 Subject: ath5k: Don't wake internal queues We should only wake up queues which mac80211 knows about (queues 0-3). We have another internal queue ("CAB", queue number 6) which we use for power-saved frames. When transmitted frames are processed from this queue, we have to make sure we don't bother mac80211 with waking a queue it doesn't know about. this fixes: WARNING: at /home/br1/ath/wireless-testing/net/mac80211/util.c:275 __ieee80211_wake_queue+0xd6/0xe0 [mac80211]() Signed-off-by: Bruno Randolf Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index d914a31cb0b6..dad726585637 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1711,7 +1711,7 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) } } spin_unlock(&txq->lock); - if (txq->txq_len < ATH5K_TXQ_LEN_LOW) + if (txq->txq_len < ATH5K_TXQ_LEN_LOW && txq->qnum < 4) ieee80211_wake_queue(sc->hw, txq->qnum); } -- cgit v1.2.3 From 970bf9d40c03e48cc34ee2c1a70693a0e0fca3f6 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Tue, 5 Oct 2010 11:32:17 +0200 Subject: ath9k: get correct tx gain type in ath9k_hw_4k_get_eeprom The base_eep_header_4k structure contains information that the device supports high power tx gain table or not. However the ath9k_hw_4k_get_eeprom function does not return that value when it is called with EEP_TXGAIN_TYPE. This leads to that the tx gain initialization will use the init values from the original tx gain table even if the device inidicates that the high power table should be used. Changes-licensed-under: ISC Signed-off-by: Gabor Juhos Signed-off-by: Shu Hwa Shen Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/eeprom_4k.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index d6eed1f02e84..872e75b0b574 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -179,6 +179,9 @@ static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah, struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; struct modal_eep_4k_header *pModal = &eep->modalHeader; struct base_eep_header_4k *pBase = &eep->baseEepHeader; + u16 ver_minor; + + ver_minor = pBase->version & AR5416_EEP_VER_MINOR_MASK; switch (param) { case EEP_NFTHRESH_2: @@ -204,7 +207,7 @@ static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah, case EEP_DB_2: return pModal->db1_1; case EEP_MINOR_REV: - return pBase->version & AR5416_EEP_VER_MINOR_MASK; + return ver_minor; case EEP_TX_MASK: return pBase->txMask; case EEP_RX_MASK: @@ -217,6 +220,11 @@ static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah, return pModal->version; case EEP_ANT_DIV_CTL1: return pModal->antdiv_ctl1; + case EEP_TXGAIN_TYPE: + if (ver_minor >= AR5416_EEP_MINOR_VER_19) + return pBase->txGainType; + else + return AR5416_EEP_TXGAIN_ORIGINAL; default: return 0; } -- cgit v1.2.3 From 691895e7e2204be9a717809fb78d6ff7c10b470a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 5 Oct 2010 16:19:42 +0200 Subject: nl80211: fix remain-on-channel documentation The documentation for NL80211_CMD_REMAIN_ON_CHANNEL isn't accurate, an interface index is required by the command. Update it accordingly. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/linux/nl80211.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 73d9390d4ddb..c4efdfa24ed8 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -315,8 +315,8 @@ * 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 + * %NL80211_ATTR_IFINDEX is used to specify which interface (and thus + * 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 -- cgit v1.2.3 From e7480bbb926c5816e4fbfca70748096bbe0e4978 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Fri, 1 Oct 2010 17:05:19 -0400 Subject: mac80211: fix channel assumption for association done work Be consistent and use the wk->chan instead of the local->hw.conf.channel for the association done work. This prevents any possible races against channel changes while we run this work. In the case that the race did happen we would be initializing the bit rates for the new AP under the assumption of a wrong channel and in the worst case, wrong band. This could lead to trying to assuming we could use CCK frames on 5 GHz, for example. This patch has a fix for kernels >= v2.6.34 Cc: stable@kernel.org Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 2b2982782bcd..cd13aa82f835 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1291,7 +1291,7 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, rates = 0; basic_rates = 0; - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + sband = local->hw.wiphy->bands[wk->chan->band]; for (i = 0; i < elems.supp_rates_len; i++) { int rate = (elems.supp_rates[i] & 0x7f) * 5; @@ -1327,11 +1327,11 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, } } - sta->sta.supp_rates[local->hw.conf.channel->band] = rates; + sta->sta.supp_rates[wk->chan->band] = rates; sdata->vif.bss_conf.basic_rates = basic_rates; /* cf. IEEE 802.11 9.2.12 */ - if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && + if (wk->chan->band == IEEE80211_BAND_2GHZ && have_higher_than_11mbit) sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; else -- cgit v1.2.3 From 72645eff4b2ad6cf2b016b54f9d6817cca0a621d Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Wed, 6 Oct 2010 07:42:43 -0700 Subject: iwlwifi: schedule to deprecate software scan support Hardware scan is the prefer method for all iwlwifi devices; especially for dual-mode functions. Schedule to deprecate the software scan support in kernel 2.6.40 Signed-off-by: Wey-Yi Guy --- Documentation/feature-removal-schedule.txt | 10 ++++++++++ drivers/net/wireless/iwlwifi/iwl-agn.c | 8 ++++---- drivers/net/wireless/iwlwifi/iwl3945-base.c | 5 +++-- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index be7030e4dd73..cd89d1e5a6a8 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -563,3 +563,13 @@ Why: superseded by acpi_sleep=nonvs Who: Rafael J. Wysocki ---------------------------- + +What: iwlwifi disable_hw_scan module parameters +When: 2.6.40 +Why: Hareware scan is the prefer method for iwlwifi devices for + scanning operation. Remove software scan support for all the + iwlwifi devices. + +Who: Wey-Yi Guy + +---------------------------- diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index e23c554b73a8..e7dc8b92db66 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -4296,9 +4296,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* Disabling hardware scan means that mac80211 will perform scans * "the hard way", rather than using device's scan. */ if (cfg->mod_params->disable_hw_scan) { - if (iwl_debug_level & IWL_DL_INFO) - dev_printk(KERN_DEBUG, &(pdev->dev), - "Disabling hw_scan\n"); + dev_printk(KERN_DEBUG, &(pdev->dev), + "sw scan support is deprecated\n"); iwl_hw_ops.hw_scan = NULL; } @@ -4905,7 +4904,8 @@ module_param_named(fw_restart, iwlagn_mod_params.restart_fw, int, S_IRUGO); MODULE_PARM_DESC(fw_restart, "restart firmware in case of error"); module_param_named( disable_hw_scan, iwlagn_mod_params.disable_hw_scan, int, S_IRUGO); -MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)"); +MODULE_PARM_DESC(disable_hw_scan, + "disable hardware scanning (default 0) (deprecated)"); module_param_named(ucode_alternative, iwlagn_wanted_ucode_alternative, int, S_IRUGO); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 116777122a79..8b6aa3d38db0 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -3966,7 +3966,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e * "the hard way", rather than using device's scan. */ if (iwl3945_mod_params.disable_hw_scan) { - IWL_DEBUG_INFO(priv, "Disabling hw_scan\n"); + IWL_ERR(priv, "sw scan support is deprecated\n"); iwl3945_hw_ops.hw_scan = NULL; } @@ -4291,7 +4291,8 @@ MODULE_PARM_DESC(debug, "debug output mask"); #endif module_param_named(disable_hw_scan, iwl3945_mod_params.disable_hw_scan, int, S_IRUGO); -MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)"); +MODULE_PARM_DESC(disable_hw_scan, + "disable hardware scanning (default 0) (deprecated)"); module_param_named(fw_restart3945, iwl3945_mod_params.restart_fw, int, S_IRUGO); MODULE_PARM_DESC(fw_restart3945, "restart firmware in case of error"); -- cgit v1.2.3 From 7cb1b0887fcc61918e3d64827fbef968bb67a57a Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Wed, 6 Oct 2010 08:10:00 -0700 Subject: iwlagn: reduce redundant parameter definitions move paramater definitions to a device paramater structure only leaving the device name, which antennas are used and what firmware file to use in the iwl_cfg structure. this will not completely remove the redundancies but greatly reduce them for devices that only vary by name or antennas. the parameters that are more likely to change within a given device family are left in iwl_cfg. also separate bt param structure added to help reduce more. Signed-off-by: Jay Sternberg Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-1000.c | 121 ++---- drivers/net/wireless/iwlwifi/iwl-3945.c | 43 +- drivers/net/wireless/iwlwifi/iwl-4965.c | 47 +-- drivers/net/wireless/iwlwifi/iwl-5000.c | 191 +++------ drivers/net/wireless/iwlwifi/iwl-6000.c | 523 ++++++------------------- drivers/net/wireless/iwlwifi/iwl-agn-calib.c | 40 +- drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c | 12 +- drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c | 5 +- drivers/net/wireless/iwlwifi/iwl-agn-ict.c | 2 +- drivers/net/wireless/iwlwifi/iwl-agn-lib.c | 27 +- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 11 +- drivers/net/wireless/iwlwifi/iwl-agn-rx.c | 33 +- drivers/net/wireless/iwlwifi/iwl-agn-tt.c | 6 +- drivers/net/wireless/iwlwifi/iwl-agn-tx.c | 19 +- drivers/net/wireless/iwlwifi/iwl-agn-ucode.c | 5 +- drivers/net/wireless/iwlwifi/iwl-agn.c | 43 +- drivers/net/wireless/iwlwifi/iwl-core.c | 95 +++-- drivers/net/wireless/iwlwifi/iwl-core.h | 129 +++--- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 58 +-- drivers/net/wireless/iwlwifi/iwl-eeprom.c | 12 +- drivers/net/wireless/iwlwifi/iwl-led.c | 6 +- drivers/net/wireless/iwlwifi/iwl-power.c | 4 +- drivers/net/wireless/iwlwifi/iwl-scan.c | 3 +- drivers/net/wireless/iwlwifi/iwl3945-base.c | 17 +- 24 files changed, 565 insertions(+), 887 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 19dbef06d52c..134f54541330 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -126,13 +126,13 @@ 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 <= IWLAGN_NUM_QUEUES) - priv->cfg->num_of_queues = + priv->cfg->base_params->num_of_queues = priv->cfg->mod_params->num_of_queues; - priv->hw_params.max_txq_num = priv->cfg->num_of_queues; + priv->hw_params.max_txq_num = priv->cfg->base_params->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 * + priv->cfg->base_params->num_of_queues * sizeof(struct iwlagn_scd_bc_tbl); priv->hw_params.tfd_size = sizeof(struct iwl_tfd); priv->hw_params.max_stations = IWLAGN_STATION_COUNT; @@ -250,29 +250,16 @@ static const struct iwl_ops iwl1000_ops = { .led = &iwlagn_led_ops, }; -struct iwl_cfg iwl1000_bgn_cfg = { - .name = "Intel(R) Centrino(R) Wireless-N 1000 BGN", - .fw_name_pre = IWL1000_FW_PRE, - .ucode_api_max = IWL1000_UCODE_API_MAX, - .ucode_api_min = IWL1000_UCODE_API_MIN, - .sku = IWL_SKU_G|IWL_SKU_N, - .ops = &iwl1000_ops, - .eeprom_size = OTP_LOW_IMAGE_SIZE, - .eeprom_ver = EEPROM_1000_EEPROM_VERSION, - .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION, +static struct iwl_base_params iwl1000_base_params = { .num_of_queues = IWLAGN_NUM_QUEUES, .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, - .mod_params = &iwlagn_mod_params, - .valid_tx_ant = ANT_A, - .valid_rx_ant = ANT_AB, + .eeprom_size = OTP_LOW_IMAGE_SIZE, .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, .set_l0s = true, .use_bsm = false, .max_ll_items = OTP_MAX_LL_ITEMS_1000, .shadow_ram_support = false, - .ht_greenfield_support = true, .led_compensation = 51, - .use_rts_for_aggregation = 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, @@ -283,6 +270,26 @@ struct iwl_cfg iwl1000_bgn_cfg = { .sensitivity_calib_by_driver = true, .chain_noise_calib_by_driver = true, }; +static struct iwl_ht_params iwl1000_ht_params = { + .ht_greenfield_support = true, + .use_rts_for_aggregation = true, /* use rts/cts protection */ +}; + +struct iwl_cfg iwl1000_bgn_cfg = { + .name = "Intel(R) Centrino(R) Wireless-N 1000 BGN", + .fw_name_pre = IWL1000_FW_PRE, + .ucode_api_max = IWL1000_UCODE_API_MAX, + .ucode_api_min = IWL1000_UCODE_API_MIN, + .sku = IWL_SKU_G|IWL_SKU_N, + .valid_tx_ant = ANT_A, + .valid_rx_ant = ANT_AB, + .eeprom_ver = EEPROM_1000_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION, + .ops = &iwl1000_ops, + .mod_params = &iwlagn_mod_params, + .base_params = &iwl1000_base_params, + .ht_params = &iwl1000_ht_params, +}; struct iwl_cfg iwl1000_bg_cfg = { .name = "Intel(R) Centrino(R) Wireless-N 1000 BG", @@ -290,30 +297,13 @@ struct iwl_cfg iwl1000_bg_cfg = { .ucode_api_max = IWL1000_UCODE_API_MAX, .ucode_api_min = IWL1000_UCODE_API_MIN, .sku = IWL_SKU_G, - .ops = &iwl1000_ops, - .eeprom_size = OTP_LOW_IMAGE_SIZE, + .valid_tx_ant = ANT_A, + .valid_rx_ant = ANT_AB, .eeprom_ver = EEPROM_1000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION, - .num_of_queues = IWLAGN_NUM_QUEUES, - .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, + .ops = &iwl1000_ops, .mod_params = &iwlagn_mod_params, - .valid_tx_ant = ANT_A, - .valid_rx_ant = ANT_AB, - .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, - .set_l0s = true, - .use_bsm = false, - .max_ll_items = OTP_MAX_LL_ITEMS_1000, - .shadow_ram_support = false, - .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, - .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, - .max_event_log_size = 128, - .ucode_tracing = true, - .sensitivity_calib_by_driver = true, - .chain_noise_calib_by_driver = true, + .base_params = &iwl1000_base_params, }; struct iwl_cfg iwl100_bgn_cfg = { @@ -322,32 +312,14 @@ struct iwl_cfg iwl100_bgn_cfg = { .ucode_api_max = IWL100_UCODE_API_MAX, .ucode_api_min = IWL100_UCODE_API_MIN, .sku = IWL_SKU_G|IWL_SKU_N, - .ops = &iwl1000_ops, - .eeprom_size = OTP_LOW_IMAGE_SIZE, + .valid_tx_ant = ANT_A, + .valid_rx_ant = ANT_A, .eeprom_ver = EEPROM_1000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION, - .num_of_queues = IWLAGN_NUM_QUEUES, - .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, + .ops = &iwl1000_ops, .mod_params = &iwlagn_mod_params, - .valid_tx_ant = ANT_A, - .valid_rx_ant = ANT_A, - .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, - .set_l0s = true, - .use_bsm = false, - .max_ll_items = OTP_MAX_LL_ITEMS_1000, - .shadow_ram_support = false, - .ht_greenfield_support = true, - .led_compensation = 51, - .use_rts_for_aggregation = 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, - .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, - .max_event_log_size = 128, - .ucode_tracing = true, - .sensitivity_calib_by_driver = true, - .chain_noise_calib_by_driver = true, + .base_params = &iwl1000_base_params, + .ht_params = &iwl1000_ht_params, }; struct iwl_cfg iwl100_bg_cfg = { @@ -356,30 +328,13 @@ struct iwl_cfg iwl100_bg_cfg = { .ucode_api_max = IWL100_UCODE_API_MAX, .ucode_api_min = IWL100_UCODE_API_MIN, .sku = IWL_SKU_G, - .ops = &iwl1000_ops, - .eeprom_size = OTP_LOW_IMAGE_SIZE, + .valid_tx_ant = ANT_A, + .valid_rx_ant = ANT_A, .eeprom_ver = EEPROM_1000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION, - .num_of_queues = IWLAGN_NUM_QUEUES, - .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, + .ops = &iwl1000_ops, .mod_params = &iwlagn_mod_params, - .valid_tx_ant = ANT_A, - .valid_rx_ant = ANT_A, - .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, - .set_l0s = true, - .use_bsm = false, - .max_ll_items = OTP_MAX_LL_ITEMS_1000, - .shadow_ram_support = false, - .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, - .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, - .max_event_log_size = 128, - .ucode_tracing = true, - .sensitivity_calib_by_driver = true, - .chain_noise_calib_by_driver = true, + .base_params = &iwl1000_base_params, }; MODULE_FIRMWARE(IWL1000_MODULE_FIRMWARE(IWL1000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 5d09686c3389..cfdff5487e3c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -406,7 +406,7 @@ static bool iwl3945_good_plcp_health(struct iwl_priv *priv, unsigned int plcp_msec; unsigned long plcp_received_jiffies; - if (priv->cfg->plcp_delta_threshold == + if (priv->cfg->base_params->plcp_delta_threshold == IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE) { IWL_DEBUG_RADIO(priv, "plcp_err check disabled\n"); return rc; @@ -432,7 +432,7 @@ static bool iwl3945_good_plcp_health(struct iwl_priv *priv, if ((combined_plcp_delta > 0) && ((combined_plcp_delta * 100) / plcp_msec) > - priv->cfg->plcp_delta_threshold) { + priv->cfg->base_params->plcp_delta_threshold) { /* * if plcp_err exceed the threshold, the following * data is printed in csv format: @@ -444,7 +444,7 @@ static bool iwl3945_good_plcp_health(struct iwl_priv *priv, */ IWL_DEBUG_RADIO(priv, "plcp_err exceeded %u, " "%u, %d, %u mSecs\n", - priv->cfg->plcp_delta_threshold, + priv->cfg->base_params->plcp_delta_threshold, le32_to_cpu(current_stat.rx.ofdm.plcp_err), combined_plcp_delta, plcp_msec); /* @@ -2421,7 +2421,7 @@ int iwl3945_hw_set_hw_params(struct iwl_priv *priv) } /* Assign number of Usable TX queues */ - priv->hw_params.max_txq_num = priv->cfg->num_of_queues; + priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues; priv->hw_params.tfd_size = sizeof(struct iwl3945_tfd); priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_3K); @@ -2722,22 +2722,12 @@ static const struct iwl_ops iwl3945_ops = { .led = &iwl3945_led_ops, }; -static struct iwl_cfg iwl3945_bg_cfg = { - .name = "3945BG", - .fw_name_pre = IWL3945_FW_PRE, - .ucode_api_max = IWL3945_UCODE_API_MAX, - .ucode_api_min = IWL3945_UCODE_API_MIN, - .sku = IWL_SKU_G, +static struct iwl_base_params iwl3945_base_params = { .eeprom_size = IWL3945_EEPROM_IMG_SIZE, - .eeprom_ver = EEPROM_3945_EEPROM_VERSION, - .ops = &iwl3945_ops, - .num_of_queues = IWL39_NUM_QUEUES, - .mod_params = &iwl3945_mod_params, .pll_cfg_val = CSR39_ANA_PLL_CFG_VAL, .set_l0s = false, .use_bsm = true, .use_isr_legacy = true, - .ht_greenfield_support = false, .led_compensation = 64, .broken_powersave = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, @@ -2746,25 +2736,28 @@ static struct iwl_cfg iwl3945_bg_cfg = { .tx_power_by_driver = true, }; +static struct iwl_cfg iwl3945_bg_cfg = { + .name = "3945BG", + .fw_name_pre = IWL3945_FW_PRE, + .ucode_api_max = IWL3945_UCODE_API_MAX, + .ucode_api_min = IWL3945_UCODE_API_MIN, + .sku = IWL_SKU_G, + .eeprom_ver = EEPROM_3945_EEPROM_VERSION, + .ops = &iwl3945_ops, + .mod_params = &iwl3945_mod_params, + .base_params = &iwl3945_base_params, +}; + static struct iwl_cfg iwl3945_abg_cfg = { .name = "3945ABG", .fw_name_pre = IWL3945_FW_PRE, .ucode_api_max = IWL3945_UCODE_API_MAX, .ucode_api_min = IWL3945_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G, - .eeprom_size = IWL3945_EEPROM_IMG_SIZE, .eeprom_ver = EEPROM_3945_EEPROM_VERSION, .ops = &iwl3945_ops, - .num_of_queues = IWL39_NUM_QUEUES, .mod_params = &iwl3945_mod_params, - .use_isr_legacy = true, - .ht_greenfield_support = false, - .led_compensation = 64, - .broken_powersave = true, - .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, - .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, - .max_event_log_size = 512, - .tx_power_by_driver = true, + .base_params = &iwl3945_base_params, }; DEFINE_PCI_DEVICE_TABLE(iwl3945_hw_card_ids) = { diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 943a9c7bfa7f..834c2f9c15d7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -647,13 +647,13 @@ static int iwl4965_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 <= IWL49_NUM_QUEUES) - priv->cfg->num_of_queues = + priv->cfg->base_params->num_of_queues = priv->cfg->mod_params->num_of_queues; - priv->hw_params.max_txq_num = priv->cfg->num_of_queues; + priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues; priv->hw_params.dma_chnl_num = FH49_TCSR_CHNL_NUM; priv->hw_params.scd_bc_tbls_size = - priv->cfg->num_of_queues * + priv->cfg->base_params->num_of_queues * sizeof(struct iwl4965_scd_bc_tbl); priv->hw_params.tfd_size = sizeof(struct iwl_tfd); priv->hw_params.max_stations = IWL4965_STATION_COUNT; @@ -1724,13 +1724,13 @@ static int iwl4965_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, u16 ssn_idx, u8 tx_fifo) { if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) || - (IWL49_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues - <= txq_id)) { + (IWL49_FIRST_AMPDU_QUEUE + + priv->cfg->base_params->num_of_ampdu_queues <= txq_id)) { IWL_WARN(priv, "queue number out of range: %d, must be %d to %d\n", txq_id, IWL49_FIRST_AMPDU_QUEUE, IWL49_FIRST_AMPDU_QUEUE + - priv->cfg->num_of_ampdu_queues - 1); + priv->cfg->base_params->num_of_ampdu_queues - 1); return -EINVAL; } @@ -1792,13 +1792,13 @@ static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id, int ret; if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) || - (IWL49_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues - <= txq_id)) { + (IWL49_FIRST_AMPDU_QUEUE + + priv->cfg->base_params->num_of_ampdu_queues <= txq_id)) { IWL_WARN(priv, "queue number out of range: %d, must be %d to %d\n", txq_id, IWL49_FIRST_AMPDU_QUEUE, IWL49_FIRST_AMPDU_QUEUE + - priv->cfg->num_of_ampdu_queues - 1); + priv->cfg->base_params->num_of_ampdu_queues - 1); return -EINVAL; } @@ -2302,26 +2302,14 @@ static const struct iwl_ops iwl4965_ops = { .led = &iwlagn_led_ops, }; -struct iwl_cfg iwl4965_agn_cfg = { - .name = "Intel(R) Wireless WiFi Link 4965AGN", - .fw_name_pre = IWL4965_FW_PRE, - .ucode_api_max = IWL4965_UCODE_API_MAX, - .ucode_api_min = IWL4965_UCODE_API_MIN, - .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, +static struct iwl_base_params iwl4965_base_params = { .eeprom_size = IWL4965_EEPROM_IMG_SIZE, - .eeprom_ver = EEPROM_4965_EEPROM_VERSION, - .eeprom_calib_ver = EEPROM_4965_TX_POWER_VERSION, - .ops = &iwl4965_ops, .num_of_queues = IWL49_NUM_QUEUES, .num_of_ampdu_queues = IWL49_NUM_AMPDU_QUEUES, - .mod_params = &iwlagn_mod_params, - .valid_tx_ant = ANT_AB, - .valid_rx_ant = ANT_ABC, .pll_cfg_val = 0, .set_l0s = true, .use_bsm = true, .use_isr_legacy = true, - .ht_greenfield_support = false, .broken_powersave = true, .led_compensation = 61, .chain_noise_num_beacons = IWL4965_CAL_NUM_BEACONS, @@ -2333,6 +2321,21 @@ struct iwl_cfg iwl4965_agn_cfg = { .ucode_tracing = true, .sensitivity_calib_by_driver = true, .chain_noise_calib_by_driver = true, +}; + +struct iwl_cfg iwl4965_agn_cfg = { + .name = "Intel(R) Wireless WiFi Link 4965AGN", + .fw_name_pre = IWL4965_FW_PRE, + .ucode_api_max = IWL4965_UCODE_API_MAX, + .ucode_api_min = IWL4965_UCODE_API_MIN, + .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, + .valid_tx_ant = ANT_AB, + .valid_rx_ant = ANT_ABC, + .eeprom_ver = EEPROM_4965_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_4965_TX_POWER_VERSION, + .ops = &iwl4965_ops, + .mod_params = &iwlagn_mod_params, + .base_params = &iwl4965_base_params, /* * Force use of chains B and C for scan RX on 5 GHz band * because the device has off-channel reception on chain A. diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 21b4b23368e6..1b25ad63b5c1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -170,13 +170,13 @@ static int iwl5000_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 <= IWLAGN_NUM_QUEUES) - priv->cfg->num_of_queues = + priv->cfg->base_params->num_of_queues = priv->cfg->mod_params->num_of_queues; - priv->hw_params.max_txq_num = priv->cfg->num_of_queues; + priv->hw_params.max_txq_num = priv->cfg->base_params->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 * + priv->cfg->base_params->num_of_queues * sizeof(struct iwlagn_scd_bc_tbl); priv->hw_params.tfd_size = sizeof(struct iwl_tfd); priv->hw_params.max_stations = IWLAGN_STATION_COUNT; @@ -217,13 +217,13 @@ static int iwl5150_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 <= IWLAGN_NUM_QUEUES) - priv->cfg->num_of_queues = + priv->cfg->base_params->num_of_queues = priv->cfg->mod_params->num_of_queues; - priv->hw_params.max_txq_num = priv->cfg->num_of_queues; + priv->hw_params.max_txq_num = priv->cfg->base_params->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 * + priv->cfg->base_params->num_of_queues * sizeof(struct iwlagn_scd_bc_tbl); priv->hw_params.tfd_size = sizeof(struct iwl_tfd); priv->hw_params.max_stations = IWLAGN_STATION_COUNT; @@ -504,27 +504,14 @@ static const struct iwl_ops iwl5150_ops = { .led = &iwlagn_led_ops, }; -struct iwl_cfg iwl5300_agn_cfg = { - .name = "Intel(R) Ultimate N WiFi Link 5300 AGN", - .fw_name_pre = IWL5000_FW_PRE, - .ucode_api_max = IWL5000_UCODE_API_MAX, - .ucode_api_min = IWL5000_UCODE_API_MIN, - .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, - .ops = &iwl5000_ops, +static struct iwl_base_params iwl5000_base_params = { .eeprom_size = IWLAGN_EEPROM_IMG_SIZE, - .eeprom_ver = EEPROM_5000_EEPROM_VERSION, - .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .num_of_queues = IWLAGN_NUM_QUEUES, .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, - .mod_params = &iwlagn_mod_params, - .valid_tx_ant = ANT_ABC, - .valid_rx_ant = ANT_ABC, .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, .set_l0s = true, .use_bsm = false, - .ht_greenfield_support = true, .led_compensation = 51, - .use_rts_for_aggregation = 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, @@ -534,6 +521,26 @@ struct iwl_cfg iwl5300_agn_cfg = { .sensitivity_calib_by_driver = true, .chain_noise_calib_by_driver = true, }; +static struct iwl_ht_params iwl5000_ht_params = { + .ht_greenfield_support = true, + .use_rts_for_aggregation = true, /* use rts/cts protection */ +}; + +struct iwl_cfg iwl5300_agn_cfg = { + .name = "Intel(R) Ultimate N WiFi Link 5300 AGN", + .fw_name_pre = IWL5000_FW_PRE, + .ucode_api_max = IWL5000_UCODE_API_MAX, + .ucode_api_min = IWL5000_UCODE_API_MIN, + .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, + .valid_tx_ant = ANT_ABC, + .valid_rx_ant = ANT_ABC, + .eeprom_ver = EEPROM_5000_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .ops = &iwl5000_ops, + .mod_params = &iwlagn_mod_params, + .base_params = &iwl5000_base_params, + .ht_params = &iwl5000_ht_params, +}; struct iwl_cfg iwl5100_bgn_cfg = { .name = "Intel(R) WiFi Link 5100 BGN", @@ -541,29 +548,14 @@ struct iwl_cfg iwl5100_bgn_cfg = { .ucode_api_max = IWL5000_UCODE_API_MAX, .ucode_api_min = IWL5000_UCODE_API_MIN, .sku = IWL_SKU_G|IWL_SKU_N, - .ops = &iwl5000_ops, - .eeprom_size = IWLAGN_EEPROM_IMG_SIZE, + .valid_tx_ant = ANT_B, + .valid_rx_ant = ANT_AB, .eeprom_ver = EEPROM_5000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, - .num_of_queues = IWLAGN_NUM_QUEUES, - .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, + .ops = &iwl5000_ops, .mod_params = &iwlagn_mod_params, - .valid_tx_ant = ANT_B, - .valid_rx_ant = ANT_AB, - .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, - .set_l0s = true, - .use_bsm = false, - .ht_greenfield_support = true, - .led_compensation = 51, - .use_rts_for_aggregation = 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, - .monitor_recover_period = IWL_LONG_MONITORING_PERIOD, - .max_event_log_size = 512, - .ucode_tracing = true, - .sensitivity_calib_by_driver = true, - .chain_noise_calib_by_driver = true, + .base_params = &iwl5000_base_params, + .ht_params = &iwl5000_ht_params, }; struct iwl_cfg iwl5100_abg_cfg = { @@ -572,27 +564,13 @@ struct iwl_cfg iwl5100_abg_cfg = { .ucode_api_max = IWL5000_UCODE_API_MAX, .ucode_api_min = IWL5000_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G, - .ops = &iwl5000_ops, - .eeprom_size = IWLAGN_EEPROM_IMG_SIZE, + .valid_tx_ant = ANT_B, + .valid_rx_ant = ANT_AB, .eeprom_ver = EEPROM_5000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, - .num_of_queues = IWLAGN_NUM_QUEUES, - .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, + .ops = &iwl5000_ops, .mod_params = &iwlagn_mod_params, - .valid_tx_ant = ANT_B, - .valid_rx_ant = ANT_AB, - .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, - .set_l0s = true, - .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, - .monitor_recover_period = IWL_LONG_MONITORING_PERIOD, - .max_event_log_size = 512, - .ucode_tracing = true, - .sensitivity_calib_by_driver = true, - .chain_noise_calib_by_driver = true, + .base_params = &iwl5000_base_params, }; struct iwl_cfg iwl5100_agn_cfg = { @@ -601,29 +579,14 @@ struct iwl_cfg iwl5100_agn_cfg = { .ucode_api_max = IWL5000_UCODE_API_MAX, .ucode_api_min = IWL5000_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, - .ops = &iwl5000_ops, - .eeprom_size = IWLAGN_EEPROM_IMG_SIZE, + .valid_tx_ant = ANT_B, + .valid_rx_ant = ANT_AB, .eeprom_ver = EEPROM_5000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, - .num_of_queues = IWLAGN_NUM_QUEUES, - .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, + .ops = &iwl5000_ops, .mod_params = &iwlagn_mod_params, - .valid_tx_ant = ANT_B, - .valid_rx_ant = ANT_AB, - .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, - .set_l0s = true, - .use_bsm = false, - .ht_greenfield_support = true, - .led_compensation = 51, - .use_rts_for_aggregation = 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, - .monitor_recover_period = IWL_LONG_MONITORING_PERIOD, - .max_event_log_size = 512, - .ucode_tracing = true, - .sensitivity_calib_by_driver = true, - .chain_noise_calib_by_driver = true, + .base_params = &iwl5000_base_params, + .ht_params = &iwl5000_ht_params, }; struct iwl_cfg iwl5350_agn_cfg = { @@ -632,29 +595,14 @@ struct iwl_cfg iwl5350_agn_cfg = { .ucode_api_max = IWL5000_UCODE_API_MAX, .ucode_api_min = IWL5000_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, - .ops = &iwl5000_ops, - .eeprom_size = IWLAGN_EEPROM_IMG_SIZE, + .valid_tx_ant = ANT_ABC, + .valid_rx_ant = ANT_ABC, .eeprom_ver = EEPROM_5050_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, - .num_of_queues = IWLAGN_NUM_QUEUES, - .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, + .ops = &iwl5000_ops, .mod_params = &iwlagn_mod_params, - .valid_tx_ant = ANT_ABC, - .valid_rx_ant = ANT_ABC, - .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, - .set_l0s = true, - .use_bsm = false, - .ht_greenfield_support = true, - .led_compensation = 51, - .use_rts_for_aggregation = 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, - .monitor_recover_period = IWL_LONG_MONITORING_PERIOD, - .max_event_log_size = 512, - .ucode_tracing = true, - .sensitivity_calib_by_driver = true, - .chain_noise_calib_by_driver = true, + .base_params = &iwl5000_base_params, + .ht_params = &iwl5000_ht_params, }; struct iwl_cfg iwl5150_agn_cfg = { @@ -663,29 +611,14 @@ struct iwl_cfg iwl5150_agn_cfg = { .ucode_api_max = IWL5150_UCODE_API_MAX, .ucode_api_min = IWL5150_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, - .ops = &iwl5150_ops, - .eeprom_size = IWLAGN_EEPROM_IMG_SIZE, + .valid_tx_ant = ANT_A, + .valid_rx_ant = ANT_AB, .eeprom_ver = EEPROM_5050_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, - .num_of_queues = IWLAGN_NUM_QUEUES, - .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, + .ops = &iwl5150_ops, .mod_params = &iwlagn_mod_params, - .valid_tx_ant = ANT_A, - .valid_rx_ant = ANT_AB, - .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, - .set_l0s = true, - .use_bsm = false, - .ht_greenfield_support = true, - .led_compensation = 51, - .use_rts_for_aggregation = 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, - .monitor_recover_period = IWL_LONG_MONITORING_PERIOD, - .max_event_log_size = 512, - .ucode_tracing = true, - .sensitivity_calib_by_driver = true, - .chain_noise_calib_by_driver = true, + .base_params = &iwl5000_base_params, + .ht_params = &iwl5000_ht_params, .need_dc_calib = true, }; @@ -695,27 +628,13 @@ struct iwl_cfg iwl5150_abg_cfg = { .ucode_api_max = IWL5150_UCODE_API_MAX, .ucode_api_min = IWL5150_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G, - .ops = &iwl5150_ops, - .eeprom_size = IWLAGN_EEPROM_IMG_SIZE, + .valid_tx_ant = ANT_A, + .valid_rx_ant = ANT_AB, .eeprom_ver = EEPROM_5050_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, - .num_of_queues = IWLAGN_NUM_QUEUES, - .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, + .ops = &iwl5150_ops, .mod_params = &iwlagn_mod_params, - .valid_tx_ant = ANT_A, - .valid_rx_ant = ANT_AB, - .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, - .set_l0s = true, - .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, - .monitor_recover_period = IWL_LONG_MONITORING_PERIOD, - .max_event_log_size = 512, - .ucode_tracing = true, - .sensitivity_calib_by_driver = true, - .chain_noise_calib_by_driver = true, + .base_params = &iwl5000_base_params, .need_dc_calib = true, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 4d45932e901e..5866ad868c32 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -162,13 +162,13 @@ static int iwl6000_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 <= IWLAGN_NUM_QUEUES) - priv->cfg->num_of_queues = + priv->cfg->base_params->num_of_queues = priv->cfg->mod_params->num_of_queues; - priv->hw_params.max_txq_num = priv->cfg->num_of_queues; + priv->hw_params.max_txq_num = priv->cfg->base_params->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 * + priv->cfg->base_params->num_of_queues * sizeof(struct iwlagn_scd_bc_tbl); priv->hw_params.tfd_size = sizeof(struct iwl_tfd); priv->hw_params.max_stations = IWLAGN_STATION_COUNT; @@ -466,30 +466,16 @@ static const struct iwl_ops iwl6000g2b_ops = { .led = &iwlagn_led_ops, }; -struct iwl_cfg iwl6000g2a_2agn_cfg = { - .name = "6000 Series 2x2 AGN Gen2a", - .fw_name_pre = IWL6000G2A_FW_PRE, - .ucode_api_max = IWL6000G2_UCODE_API_MAX, - .ucode_api_min = IWL6000G2_UCODE_API_MIN, - .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, - .ops = &iwl6000_ops, +static struct iwl_base_params iwl6000_base_params = { .eeprom_size = OTP_LOW_IMAGE_SIZE, - .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION, - .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION, .num_of_queues = IWLAGN_NUM_QUEUES, .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, - .mod_params = &iwlagn_mod_params, - .valid_tx_ant = ANT_AB, - .valid_rx_ant = ANT_AB, .pll_cfg_val = 0, .set_l0s = true, .use_bsm = false, - .pa_type = IWL_PA_SYSTEM, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, - .ht_greenfield_support = true, .led_compensation = 51, - .use_rts_for_aggregation = true, /* use rts/cts protection */ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .supports_idle = true, .adv_thermal_throttle = true, @@ -501,29 +487,16 @@ struct iwl_cfg iwl6000g2a_2agn_cfg = { .ucode_tracing = true, .sensitivity_calib_by_driver = true, .chain_noise_calib_by_driver = true, - .need_dc_calib = true, }; -struct iwl_cfg iwl6000g2a_2abg_cfg = { - .name = "6000 Series 2x2 ABG Gen2a", - .fw_name_pre = IWL6000G2A_FW_PRE, - .ucode_api_max = IWL6000G2_UCODE_API_MAX, - .ucode_api_min = IWL6000G2_UCODE_API_MIN, - .sku = IWL_SKU_A|IWL_SKU_G, - .ops = &iwl6000_ops, +static struct iwl_base_params iwl6050_base_params = { .eeprom_size = OTP_LOW_IMAGE_SIZE, - .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION, - .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION, .num_of_queues = IWLAGN_NUM_QUEUES, .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, - .mod_params = &iwlagn_mod_params, - .valid_tx_ant = ANT_AB, - .valid_rx_ant = ANT_AB, .pll_cfg_val = 0, .set_l0s = true, .use_bsm = false, - .pa_type = IWL_PA_SYSTEM, - .max_ll_items = OTP_MAX_LL_ITEMS_6x00, + .max_ll_items = OTP_MAX_LL_ITEMS_6x50, .shadow_ram_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, @@ -531,11 +504,57 @@ struct iwl_cfg iwl6000g2a_2abg_cfg = { .adv_thermal_throttle = true, .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, - .chain_noise_scale = 1000, + .chain_noise_scale = 1500, .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, - .max_event_log_size = 512, + .max_event_log_size = 1024, + .ucode_tracing = true, .sensitivity_calib_by_driver = true, .chain_noise_calib_by_driver = true, +}; + +static struct iwl_ht_params iwl6000_ht_params = { + .ht_greenfield_support = true, + .use_rts_for_aggregation = true, /* use rts/cts protection */ +}; + +static struct iwl_bt_params iwl6000_bt_params = { + .bt_statistics = true, + /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ + .advanced_bt_coexist = true, + .bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE, + .bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT, +}; + +struct iwl_cfg iwl6000g2a_2agn_cfg = { + .name = "6000 Series 2x2 AGN Gen2a", + .fw_name_pre = IWL6000G2A_FW_PRE, + .ucode_api_max = IWL6000G2_UCODE_API_MAX, + .ucode_api_min = IWL6000G2_UCODE_API_MIN, + .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, + .valid_tx_ant = ANT_AB, + .valid_rx_ant = ANT_AB, + .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION, + .ops = &iwl6000_ops, + .mod_params = &iwlagn_mod_params, + .base_params = &iwl6000_base_params, + .ht_params = &iwl6000_ht_params, + .need_dc_calib = true, +}; + +struct iwl_cfg iwl6000g2a_2abg_cfg = { + .name = "6000 Series 2x2 ABG Gen2a", + .fw_name_pre = IWL6000G2A_FW_PRE, + .ucode_api_max = IWL6000G2_UCODE_API_MAX, + .ucode_api_min = IWL6000G2_UCODE_API_MIN, + .sku = IWL_SKU_A|IWL_SKU_G, + .valid_tx_ant = ANT_AB, + .valid_rx_ant = ANT_AB, + .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION, + .ops = &iwl6000_ops, + .mod_params = &iwlagn_mod_params, + .base_params = &iwl6000_base_params, .need_dc_calib = true, }; @@ -545,32 +564,13 @@ struct iwl_cfg iwl6000g2a_2bg_cfg = { .ucode_api_max = IWL6000G2_UCODE_API_MAX, .ucode_api_min = IWL6000G2_UCODE_API_MIN, .sku = IWL_SKU_G, - .ops = &iwl6000_ops, - .eeprom_size = OTP_LOW_IMAGE_SIZE, + .valid_tx_ant = ANT_AB, + .valid_rx_ant = ANT_AB, .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION, - .num_of_queues = IWLAGN_NUM_QUEUES, - .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, + .ops = &iwl6000_ops, .mod_params = &iwlagn_mod_params, - .valid_tx_ant = ANT_AB, - .valid_rx_ant = ANT_AB, - .pll_cfg_val = 0, - .set_l0s = true, - .use_bsm = false, - .pa_type = IWL_PA_SYSTEM, - .max_ll_items = OTP_MAX_LL_ITEMS_6x00, - .shadow_ram_support = true, - .led_compensation = 51, - .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, - .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, - .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, - .max_event_log_size = 512, - .sensitivity_calib_by_driver = true, - .chain_noise_calib_by_driver = true, + .base_params = &iwl6000_base_params, .need_dc_calib = true, }; @@ -580,41 +580,18 @@ struct iwl_cfg iwl6000g2b_2agn_cfg = { .ucode_api_max = IWL6000G2_UCODE_API_MAX, .ucode_api_min = IWL6000G2_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, - .ops = &iwl6000g2b_ops, - .eeprom_size = OTP_LOW_IMAGE_SIZE, + .valid_tx_ant = ANT_AB, + .valid_rx_ant = ANT_AB, .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION, - .num_of_queues = IWLAGN_NUM_QUEUES, - .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, + .ops = &iwl6000g2b_ops, .mod_params = &iwlagn_mod_params, - .valid_tx_ant = ANT_AB, - .valid_rx_ant = ANT_AB, - .pll_cfg_val = 0, - .set_l0s = true, - .use_bsm = false, - .pa_type = IWL_PA_SYSTEM, - .max_ll_items = OTP_MAX_LL_ITEMS_6x00, - .shadow_ram_support = true, - .ht_greenfield_support = true, - .led_compensation = 51, - .use_rts_for_aggregation = true, /* use rts/cts protection */ - .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, - .supports_idle = true, - .adv_thermal_throttle = true, - .support_ct_kill_exit = true, - .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE, - .chain_noise_scale = 1000, - .monitor_recover_period = IWL_LONG_MONITORING_PERIOD, - .max_event_log_size = 512, - .sensitivity_calib_by_driver = true, - .chain_noise_calib_by_driver = true, + .base_params = &iwl6000_base_params, + .bt_params = &iwl6000_bt_params, + .ht_params = &iwl6000_ht_params, .need_dc_calib = true, - .bt_statistics = true, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A, - .advanced_bt_coexist = true, - .bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE, - .bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT, }; struct iwl_cfg iwl6000g2b_2abg_cfg = { @@ -623,39 +600,17 @@ struct iwl_cfg iwl6000g2b_2abg_cfg = { .ucode_api_max = IWL6000G2_UCODE_API_MAX, .ucode_api_min = IWL6000G2_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G, - .ops = &iwl6000g2b_ops, - .eeprom_size = OTP_LOW_IMAGE_SIZE, + .valid_tx_ant = ANT_AB, + .valid_rx_ant = ANT_AB, .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION, - .num_of_queues = IWLAGN_NUM_QUEUES, - .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, + .ops = &iwl6000g2b_ops, .mod_params = &iwlagn_mod_params, - .valid_tx_ant = ANT_AB, - .valid_rx_ant = ANT_AB, - .pll_cfg_val = 0, - .set_l0s = true, - .use_bsm = false, - .pa_type = IWL_PA_SYSTEM, - .max_ll_items = OTP_MAX_LL_ITEMS_6x00, - .shadow_ram_support = true, - .led_compensation = 51, - .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, - .supports_idle = true, - .adv_thermal_throttle = true, - .support_ct_kill_exit = true, - .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE, - .chain_noise_scale = 1000, - .monitor_recover_period = IWL_LONG_MONITORING_PERIOD, - .max_event_log_size = 512, - .sensitivity_calib_by_driver = true, - .chain_noise_calib_by_driver = true, + .base_params = &iwl6000_base_params, + .bt_params = &iwl6000_bt_params, .need_dc_calib = true, - .bt_statistics = true, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A, - .advanced_bt_coexist = true, - .bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE, - .bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT, }; struct iwl_cfg iwl6000g2b_2bgn_cfg = { @@ -664,41 +619,18 @@ struct iwl_cfg iwl6000g2b_2bgn_cfg = { .ucode_api_max = IWL6000G2_UCODE_API_MAX, .ucode_api_min = IWL6000G2_UCODE_API_MIN, .sku = IWL_SKU_G|IWL_SKU_N, - .ops = &iwl6000g2b_ops, - .eeprom_size = OTP_LOW_IMAGE_SIZE, + .valid_tx_ant = ANT_AB, + .valid_rx_ant = ANT_AB, .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION, - .num_of_queues = IWLAGN_NUM_QUEUES, - .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, + .ops = &iwl6000g2b_ops, .mod_params = &iwlagn_mod_params, - .valid_tx_ant = ANT_AB, - .valid_rx_ant = ANT_AB, - .pll_cfg_val = 0, - .set_l0s = true, - .use_bsm = false, - .pa_type = IWL_PA_SYSTEM, - .max_ll_items = OTP_MAX_LL_ITEMS_6x00, - .shadow_ram_support = true, - .ht_greenfield_support = true, - .led_compensation = 51, - .use_rts_for_aggregation = true, /* use rts/cts protection */ - .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, - .supports_idle = true, - .adv_thermal_throttle = true, - .support_ct_kill_exit = true, - .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE, - .chain_noise_scale = 1000, - .monitor_recover_period = IWL_LONG_MONITORING_PERIOD, - .max_event_log_size = 512, - .sensitivity_calib_by_driver = true, - .chain_noise_calib_by_driver = true, + .base_params = &iwl6000_base_params, + .bt_params = &iwl6000_bt_params, + .ht_params = &iwl6000_ht_params, .need_dc_calib = true, - .bt_statistics = true, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A, - .advanced_bt_coexist = true, - .bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE, - .bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT, }; struct iwl_cfg iwl6000g2b_2bg_cfg = { @@ -707,39 +639,17 @@ struct iwl_cfg iwl6000g2b_2bg_cfg = { .ucode_api_max = IWL6000G2_UCODE_API_MAX, .ucode_api_min = IWL6000G2_UCODE_API_MIN, .sku = IWL_SKU_G, - .ops = &iwl6000g2b_ops, - .eeprom_size = OTP_LOW_IMAGE_SIZE, + .valid_tx_ant = ANT_AB, + .valid_rx_ant = ANT_AB, .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION, - .num_of_queues = IWLAGN_NUM_QUEUES, - .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, + .ops = &iwl6000g2b_ops, .mod_params = &iwlagn_mod_params, - .valid_tx_ant = ANT_AB, - .valid_rx_ant = ANT_AB, - .pll_cfg_val = 0, - .set_l0s = true, - .use_bsm = false, - .pa_type = IWL_PA_SYSTEM, - .max_ll_items = OTP_MAX_LL_ITEMS_6x00, - .shadow_ram_support = true, - .led_compensation = 51, - .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, - .supports_idle = true, - .adv_thermal_throttle = true, - .support_ct_kill_exit = true, - .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE, - .chain_noise_scale = 1000, - .monitor_recover_period = IWL_LONG_MONITORING_PERIOD, - .max_event_log_size = 512, - .sensitivity_calib_by_driver = true, - .chain_noise_calib_by_driver = true, + .base_params = &iwl6000_base_params, + .bt_params = &iwl6000_bt_params, .need_dc_calib = true, - .bt_statistics = true, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A, - .advanced_bt_coexist = true, - .bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE, - .bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT, }; struct iwl_cfg iwl6000g2b_bgn_cfg = { @@ -748,41 +658,18 @@ struct iwl_cfg iwl6000g2b_bgn_cfg = { .ucode_api_max = IWL6000G2_UCODE_API_MAX, .ucode_api_min = IWL6000G2_UCODE_API_MIN, .sku = IWL_SKU_G|IWL_SKU_N, - .ops = &iwl6000g2b_ops, - .eeprom_size = OTP_LOW_IMAGE_SIZE, + .valid_tx_ant = ANT_A, + .valid_rx_ant = ANT_AB, .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION, - .num_of_queues = IWLAGN_NUM_QUEUES, - .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, + .ops = &iwl6000g2b_ops, .mod_params = &iwlagn_mod_params, - .valid_tx_ant = ANT_A, - .valid_rx_ant = ANT_AB, - .pll_cfg_val = 0, - .set_l0s = true, - .use_bsm = false, - .pa_type = IWL_PA_SYSTEM, - .max_ll_items = OTP_MAX_LL_ITEMS_6x00, - .shadow_ram_support = true, - .ht_greenfield_support = true, - .led_compensation = 51, - .use_rts_for_aggregation = true, /* use rts/cts protection */ - .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, - .supports_idle = true, - .adv_thermal_throttle = true, - .support_ct_kill_exit = true, - .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE, - .chain_noise_scale = 1000, - .monitor_recover_period = IWL_LONG_MONITORING_PERIOD, - .max_event_log_size = 512, - .sensitivity_calib_by_driver = true, - .chain_noise_calib_by_driver = true, + .base_params = &iwl6000_base_params, + .bt_params = &iwl6000_bt_params, + .ht_params = &iwl6000_ht_params, .need_dc_calib = true, - .bt_statistics = true, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A, - .advanced_bt_coexist = true, - .bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE, - .bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT, }; struct iwl_cfg iwl6000g2b_bg_cfg = { @@ -791,39 +678,17 @@ struct iwl_cfg iwl6000g2b_bg_cfg = { .ucode_api_max = IWL6000G2_UCODE_API_MAX, .ucode_api_min = IWL6000G2_UCODE_API_MIN, .sku = IWL_SKU_G, - .ops = &iwl6000g2b_ops, - .eeprom_size = OTP_LOW_IMAGE_SIZE, + .valid_tx_ant = ANT_A, + .valid_rx_ant = ANT_AB, .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION, - .num_of_queues = IWLAGN_NUM_QUEUES, - .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, + .ops = &iwl6000g2b_ops, .mod_params = &iwlagn_mod_params, - .valid_tx_ant = ANT_A, - .valid_rx_ant = ANT_AB, - .pll_cfg_val = 0, - .set_l0s = true, - .use_bsm = false, - .pa_type = IWL_PA_SYSTEM, - .max_ll_items = OTP_MAX_LL_ITEMS_6x00, - .shadow_ram_support = true, - .led_compensation = 51, - .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, - .supports_idle = true, - .adv_thermal_throttle = true, - .support_ct_kill_exit = true, - .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE, - .chain_noise_scale = 1000, - .monitor_recover_period = IWL_LONG_MONITORING_PERIOD, - .max_event_log_size = 512, - .sensitivity_calib_by_driver = true, - .chain_noise_calib_by_driver = true, + .base_params = &iwl6000_base_params, + .bt_params = &iwl6000_bt_params, .need_dc_calib = true, - .bt_statistics = true, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A, - .advanced_bt_coexist = true, - .bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE, - .bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT, }; /* @@ -835,35 +700,15 @@ struct iwl_cfg iwl6000i_2agn_cfg = { .ucode_api_max = IWL6000_UCODE_API_MAX, .ucode_api_min = IWL6000_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, - .ops = &iwl6000_ops, - .eeprom_size = OTP_LOW_IMAGE_SIZE, + .valid_tx_ant = ANT_BC, + .valid_rx_ant = ANT_BC, .eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION, - .num_of_queues = IWLAGN_NUM_QUEUES, - .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, + .ops = &iwl6000_ops, .mod_params = &iwlagn_mod_params, - .valid_tx_ant = ANT_BC, - .valid_rx_ant = ANT_BC, - .pll_cfg_val = 0, - .set_l0s = true, - .use_bsm = false, + .base_params = &iwl6000_base_params, + .ht_params = &iwl6000_ht_params, .pa_type = IWL_PA_INTERNAL, - .max_ll_items = OTP_MAX_LL_ITEMS_6x00, - .shadow_ram_support = true, - .ht_greenfield_support = true, - .led_compensation = 51, - .use_rts_for_aggregation = true, /* use rts/cts protection */ - .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, - .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, - .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, - .max_event_log_size = 1024, - .ucode_tracing = true, - .sensitivity_calib_by_driver = true, - .chain_noise_calib_by_driver = true, }; struct iwl_cfg iwl6000i_2abg_cfg = { @@ -872,33 +717,14 @@ struct iwl_cfg iwl6000i_2abg_cfg = { .ucode_api_max = IWL6000_UCODE_API_MAX, .ucode_api_min = IWL6000_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G, - .ops = &iwl6000_ops, - .eeprom_size = OTP_LOW_IMAGE_SIZE, + .valid_tx_ant = ANT_BC, + .valid_rx_ant = ANT_BC, .eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION, - .num_of_queues = IWLAGN_NUM_QUEUES, - .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, + .ops = &iwl6000_ops, .mod_params = &iwlagn_mod_params, - .valid_tx_ant = ANT_BC, - .valid_rx_ant = ANT_BC, - .pll_cfg_val = 0, - .set_l0s = true, - .use_bsm = false, + .base_params = &iwl6000_base_params, .pa_type = IWL_PA_INTERNAL, - .max_ll_items = OTP_MAX_LL_ITEMS_6x00, - .shadow_ram_support = true, - .led_compensation = 51, - .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, - .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, - .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, - .max_event_log_size = 1024, - .ucode_tracing = true, - .sensitivity_calib_by_driver = true, - .chain_noise_calib_by_driver = true, }; struct iwl_cfg iwl6000i_2bg_cfg = { @@ -907,33 +733,14 @@ struct iwl_cfg iwl6000i_2bg_cfg = { .ucode_api_max = IWL6000_UCODE_API_MAX, .ucode_api_min = IWL6000_UCODE_API_MIN, .sku = IWL_SKU_G, - .ops = &iwl6000_ops, - .eeprom_size = OTP_LOW_IMAGE_SIZE, + .valid_tx_ant = ANT_BC, + .valid_rx_ant = ANT_BC, .eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION, - .num_of_queues = IWLAGN_NUM_QUEUES, - .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, + .ops = &iwl6000_ops, .mod_params = &iwlagn_mod_params, - .valid_tx_ant = ANT_BC, - .valid_rx_ant = ANT_BC, - .pll_cfg_val = 0, - .set_l0s = true, - .use_bsm = false, + .base_params = &iwl6000_base_params, .pa_type = IWL_PA_INTERNAL, - .max_ll_items = OTP_MAX_LL_ITEMS_6x00, - .shadow_ram_support = true, - .led_compensation = 51, - .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, - .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, - .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, - .max_event_log_size = 1024, - .ucode_tracing = true, - .sensitivity_calib_by_driver = true, - .chain_noise_calib_by_driver = true, }; struct iwl_cfg iwl6050_2agn_cfg = { @@ -942,35 +749,14 @@ struct iwl_cfg iwl6050_2agn_cfg = { .ucode_api_max = IWL6050_UCODE_API_MAX, .ucode_api_min = IWL6050_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, - .ops = &iwl6050_ops, - .eeprom_size = OTP_LOW_IMAGE_SIZE, + .valid_tx_ant = ANT_AB, + .valid_rx_ant = ANT_AB, + .ops = &iwl6000_ops, .eeprom_ver = EEPROM_6050_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION, - .num_of_queues = IWLAGN_NUM_QUEUES, - .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .mod_params = &iwlagn_mod_params, - .valid_tx_ant = ANT_AB, - .valid_rx_ant = ANT_AB, - .pll_cfg_val = 0, - .set_l0s = true, - .use_bsm = false, - .pa_type = IWL_PA_SYSTEM, - .max_ll_items = OTP_MAX_LL_ITEMS_6x50, - .shadow_ram_support = true, - .ht_greenfield_support = true, - .led_compensation = 51, - .use_rts_for_aggregation = true, /* use rts/cts protection */ - .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, - .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, - .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, - .max_event_log_size = 1024, - .ucode_tracing = true, - .sensitivity_calib_by_driver = true, - .chain_noise_calib_by_driver = true, + .base_params = &iwl6050_base_params, + .ht_params = &iwl6000_ht_params, .need_dc_calib = true, }; @@ -980,35 +766,14 @@ struct iwl_cfg iwl6050g2_bgn_cfg = { .ucode_api_max = IWL6050_UCODE_API_MAX, .ucode_api_min = IWL6050_UCODE_API_MIN, .sku = IWL_SKU_G|IWL_SKU_N, - .ops = &iwl6050g2_ops, - .eeprom_size = OTP_LOW_IMAGE_SIZE, + .valid_tx_ant = ANT_A, + .valid_rx_ant = ANT_AB, .eeprom_ver = EEPROM_6050G2_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_6050G2_TX_POWER_VERSION, - .num_of_queues = IWLAGN_NUM_QUEUES, - .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, + .ops = &iwl6050g2_ops, .mod_params = &iwlagn_mod_params, - .valid_tx_ant = ANT_A, - .valid_rx_ant = ANT_AB, - .pll_cfg_val = 0, - .set_l0s = true, - .use_bsm = false, - .pa_type = IWL_PA_SYSTEM, - .max_ll_items = OTP_MAX_LL_ITEMS_6x50, - .shadow_ram_support = true, - .ht_greenfield_support = true, - .led_compensation = 51, - .use_rts_for_aggregation = true, /* use rts/cts protection */ - .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, - .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, - .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, - .max_event_log_size = 1024, - .ucode_tracing = true, - .sensitivity_calib_by_driver = true, - .chain_noise_calib_by_driver = true, + .base_params = &iwl6050_base_params, + .ht_params = &iwl6000_ht_params, .need_dc_calib = true, }; @@ -1018,33 +783,13 @@ struct iwl_cfg iwl6050_2abg_cfg = { .ucode_api_max = IWL6050_UCODE_API_MAX, .ucode_api_min = IWL6050_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G, - .ops = &iwl6050_ops, - .eeprom_size = OTP_LOW_IMAGE_SIZE, + .valid_tx_ant = ANT_AB, + .valid_rx_ant = ANT_AB, .eeprom_ver = EEPROM_6050_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION, - .num_of_queues = IWLAGN_NUM_QUEUES, - .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, + .ops = &iwl6050_ops, .mod_params = &iwlagn_mod_params, - .valid_tx_ant = ANT_AB, - .valid_rx_ant = ANT_AB, - .pll_cfg_val = 0, - .set_l0s = true, - .use_bsm = false, - .pa_type = IWL_PA_SYSTEM, - .max_ll_items = OTP_MAX_LL_ITEMS_6x50, - .shadow_ram_support = true, - .led_compensation = 51, - .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, - .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, - .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, - .max_event_log_size = 1024, - .ucode_tracing = true, - .sensitivity_calib_by_driver = true, - .chain_noise_calib_by_driver = true, + .base_params = &iwl6050_base_params, .need_dc_calib = true, }; @@ -1054,35 +799,15 @@ struct iwl_cfg iwl6000_3agn_cfg = { .ucode_api_max = IWL6000_UCODE_API_MAX, .ucode_api_min = IWL6000_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, - .ops = &iwl6000_ops, - .eeprom_size = OTP_LOW_IMAGE_SIZE, + .valid_tx_ant = ANT_ABC, + .valid_rx_ant = ANT_ABC, .eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION, - .num_of_queues = IWLAGN_NUM_QUEUES, - .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, + .ops = &iwl6000_ops, .mod_params = &iwlagn_mod_params, - .valid_tx_ant = ANT_ABC, - .valid_rx_ant = ANT_ABC, - .pll_cfg_val = 0, - .set_l0s = true, - .use_bsm = false, - .pa_type = IWL_PA_SYSTEM, - .max_ll_items = OTP_MAX_LL_ITEMS_6x00, - .shadow_ram_support = true, - .ht_greenfield_support = true, - .led_compensation = 51, - .use_rts_for_aggregation = true, /* use rts/cts protection */ - .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, - .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, - .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, - .max_event_log_size = 1024, - .ucode_tracing = true, - .sensitivity_calib_by_driver = true, - .chain_noise_calib_by_driver = true, + .base_params = &iwl6000_base_params, + .ht_params = &iwl6000_ht_params, + .need_dc_calib = true, }; MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c index 84ad62958535..4c5ab783737f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c @@ -631,7 +631,8 @@ void iwl_sensitivity_calibration(struct iwl_priv *priv, void *resp) } spin_lock_irqsave(&priv->lock, flags); - if (priv->cfg->bt_statistics) { + if (priv->cfg->bt_params && + priv->cfg->bt_params->bt_statistics) { rx_info = &(((struct iwl_bt_notif_statistics *)resp)-> rx.general.common); ofdm = &(((struct iwl_bt_notif_statistics *)resp)->rx.ofdm); @@ -786,7 +787,8 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp) } spin_lock_irqsave(&priv->lock, flags); - if (priv->cfg->bt_statistics) { + if (priv->cfg->bt_params && + priv->cfg->bt_params->bt_statistics) { rx_info = &(((struct iwl_bt_notif_statistics *)stat_resp)-> rx.general.common); } else { @@ -801,7 +803,8 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp) rxon_band24 = !!(ctx->staging.flags & RXON_FLG_BAND_24G_MSK); rxon_chnum = le16_to_cpu(ctx->staging.channel); - if (priv->cfg->bt_statistics) { + if (priv->cfg->bt_params && + priv->cfg->bt_params->bt_statistics) { stat_band24 = !!(((struct iwl_bt_notif_statistics *) stat_resp)->flag & STATISTICS_REPLY_FLG_BAND_24G_MSK); @@ -861,16 +864,17 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp) /* If this is the "chain_noise_num_beacons", determine: * 1) Disconnected antennas (using signal strengths) * 2) Differential gain (using silence noise) to balance receivers */ - if (data->beacon_count != priv->cfg->chain_noise_num_beacons) + if (data->beacon_count != + priv->cfg->base_params->chain_noise_num_beacons) return; /* Analyze signal for disconnected antenna */ - average_sig[0] = - (data->chain_signal_a) / priv->cfg->chain_noise_num_beacons; - average_sig[1] = - (data->chain_signal_b) / priv->cfg->chain_noise_num_beacons; - average_sig[2] = - (data->chain_signal_c) / priv->cfg->chain_noise_num_beacons; + average_sig[0] = data->chain_signal_a / + priv->cfg->base_params->chain_noise_num_beacons; + average_sig[1] = data->chain_signal_b / + priv->cfg->base_params->chain_noise_num_beacons; + average_sig[2] = data->chain_signal_c / + priv->cfg->base_params->chain_noise_num_beacons; if (average_sig[0] >= average_sig[1]) { max_average_sig = average_sig[0]; @@ -920,7 +924,9 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp) * To be safe, simply mask out any chains that we know * are not on the device. */ - if (priv->cfg->advanced_bt_coexist && priv->bt_full_concurrent) { + if (priv->cfg->bt_params && + priv->cfg->bt_params->advanced_bt_coexist && + priv->bt_full_concurrent) { /* operated as 1x1 in full concurrency mode */ active_chains &= first_antenna(priv->hw_params.valid_rx_ant); } else @@ -967,12 +973,12 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp) active_chains); /* Analyze noise for rx balance */ - average_noise[0] = - ((data->chain_noise_a) / priv->cfg->chain_noise_num_beacons); - average_noise[1] = - ((data->chain_noise_b) / priv->cfg->chain_noise_num_beacons); - average_noise[2] = - ((data->chain_noise_c) / priv->cfg->chain_noise_num_beacons); + average_noise[0] = data->chain_noise_a / + priv->cfg->base_params->chain_noise_num_beacons; + average_noise[1] = data->chain_noise_b / + priv->cfg->base_params->chain_noise_num_beacons; + average_noise[2] = data->chain_noise_c / + priv->cfg->base_params->chain_noise_num_beacons; for (i = 0; i < NUM_RX_CHAINS; i++) { if (!(data->disconn_array[i]) && diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c index 5391b4627397..a358d4334a1a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c @@ -39,7 +39,8 @@ static int iwl_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz) int p = 0; u32 flag; - if (priv->cfg->bt_statistics) + if (priv->cfg->bt_params && + priv->cfg->bt_params->bt_statistics) flag = le32_to_cpu(priv->_agn.statistics_bt.flag); else flag = le32_to_cpu(priv->_agn.statistics.flag); @@ -88,7 +89,8 @@ ssize_t iwl_ucode_rx_stats_read(struct file *file, char __user *user_buf, * the last statistics notification from uCode * might not reflect the current uCode activity */ - if (priv->cfg->bt_statistics) { + if (priv->cfg->bt_params && + priv->cfg->bt_params->bt_statistics) { ofdm = &priv->_agn.statistics_bt.rx.ofdm; cck = &priv->_agn.statistics_bt.rx.cck; general = &priv->_agn.statistics_bt.rx.general.common; @@ -534,7 +536,8 @@ ssize_t iwl_ucode_tx_stats_read(struct file *file, * the last statistics notification from uCode * might not reflect the current uCode activity */ - if (priv->cfg->bt_statistics) { + if (priv->cfg->bt_params && + priv->cfg->bt_params->bt_statistics) { tx = &priv->_agn.statistics_bt.tx; accum_tx = &priv->_agn.accum_statistics_bt.tx; delta_tx = &priv->_agn.delta_statistics_bt.tx; @@ -734,7 +737,8 @@ ssize_t iwl_ucode_general_stats_read(struct file *file, char __user *user_buf, * the last statistics notification from uCode * might not reflect the current uCode activity */ - if (priv->cfg->bt_statistics) { + if (priv->cfg->bt_params && + priv->cfg->bt_params->bt_statistics) { general = &priv->_agn.statistics_bt.general.common; dbg = &priv->_agn.statistics_bt.general.common.dbg; div = &priv->_agn.statistics_bt.general.common.div; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c index d86902b83630..9ca6c91eaae6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c @@ -137,7 +137,7 @@ static void iwlagn_gain_computation(struct iwl_priv *priv, continue; } - delta_g = (priv->cfg->chain_noise_scale * + delta_g = (priv->cfg->base_params->chain_noise_scale * ((s32)average_noise[default_chain] - (s32)average_noise[i])) / 1500; @@ -222,7 +222,8 @@ static void iwlagn_tx_cmd_protection(struct iwl_priv *priv, return; } - if (priv->cfg->use_rts_for_aggregation && + if (priv->cfg->ht_params && + priv->cfg->ht_params->use_rts_for_aggregation && info->flags & IEEE80211_TX_CTL_AMPDU) { *tx_flags |= TX_CMD_FLG_PROT_REQUIRE_MSK; return; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ict.c b/drivers/net/wireless/iwlwifi/iwl-agn-ict.c index c92b2c0cbd91..a5dbfea1bfad 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ict.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-ict.c @@ -59,7 +59,7 @@ void iwl_free_isr_ict(struct iwl_priv *priv) int iwl_alloc_isr_ict(struct iwl_priv *priv) { - if (priv->cfg->use_isr_legacy) + if (priv->cfg->base_params->use_isr_legacy) return 0; /* allocate shrared data table */ priv->_agn.ict_tbl_vir = diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 299fd9d59604..29ed6049c0f7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -422,7 +422,8 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv, * notification again. */ if (tx_resp->bt_kill_count && tx_resp->frame_count == 1 && - priv->cfg->advanced_bt_coexist) { + priv->cfg->bt_params && + priv->cfg->bt_params->advanced_bt_coexist) { IWL_WARN(priv, "receive reply tx with bt_kill\n"); } iwlagn_tx_status_reply_tx(priv, agg, tx_resp, txq_id, index); @@ -589,7 +590,7 @@ const u8 *iwlagn_eeprom_query_addr(const struct iwl_priv *priv, size_t offset) { u32 address = eeprom_indirect_address(priv, offset); - BUG_ON(address >= priv->cfg->eeprom_size); + BUG_ON(address >= priv->cfg->base_params->eeprom_size); return &priv->eeprom[address]; } @@ -637,7 +638,7 @@ int iwlagn_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */ u32 rb_timeout = 0; /* FIXME: RX_RB_TIMEOUT for all devices? */ - if (!priv->cfg->use_isr_legacy) + if (!priv->cfg->base_params->use_isr_legacy) rb_timeout = RX_RB_TIMEOUT; if (priv->cfg->mod_params->amsdu_size_8K) @@ -1424,7 +1425,8 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) * Internal scans are passive, so we can indiscriminately set * the BT ignore flag on 2.4 GHz since it applies to TX only. */ - if (priv->cfg->advanced_bt_coexist) + if (priv->cfg->bt_params && + priv->cfg->bt_params->advanced_bt_coexist) scan->tx_cmd.tx_flags |= TX_CMD_FLG_IGNORE_BT; scan->good_CRC_th = IWL_GOOD_CRC_TH_DISABLED; break; @@ -1463,10 +1465,12 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) if (priv->cfg->scan_tx_antennas[band]) scan_tx_antennas = priv->cfg->scan_tx_antennas[band]; - if (priv->cfg->advanced_bt_coexist && priv->bt_full_concurrent) { + if (priv->cfg->bt_params && + priv->cfg->bt_params->advanced_bt_coexist && + priv->bt_full_concurrent) { /* operated as 1x1 in full concurrency mode */ - scan_tx_antennas = - first_antenna(priv->cfg->scan_tx_antennas[band]); + scan_tx_antennas = first_antenna( + priv->cfg->scan_tx_antennas[band]); } priv->scan_tx_ant[band] = iwl_toggle_tx_ant(priv, priv->scan_tx_ant[band], @@ -1487,7 +1491,9 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) rx_ant = first_antenna(active_chains); } - if (priv->cfg->advanced_bt_coexist && priv->bt_full_concurrent) { + if (priv->cfg->bt_params && + priv->cfg->bt_params->advanced_bt_coexist && + priv->bt_full_concurrent) { /* operated as 1x1 in full concurrency mode */ rx_ant = first_antenna(rx_ant); } @@ -1777,7 +1783,10 @@ void iwlagn_send_advance_bt_config(struct iwl_priv *priv) BUILD_BUG_ON(sizeof(iwlagn_def_3w_lookup) != sizeof(bt_cmd.bt3_lookup_table)); - bt_cmd.prio_boost = priv->cfg->bt_prio_boost; + if (priv->cfg->bt_params) + bt_cmd.prio_boost = priv->cfg->bt_params->bt_prio_boost; + else + bt_cmd.prio_boost = 0; bt_cmd.kill_ack_mask = priv->kill_ack_mask; bt_cmd.kill_cts_mask = priv->kill_cts_mask; bt_cmd.valid = priv->bt_valid; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 57629fba3a7d..f865685fd5f5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -2939,11 +2939,14 @@ static void rs_fill_link_cmd(struct iwl_priv *priv, * overwrite if needed, pass aggregation time limit * to uCode in uSec */ - if (priv && priv->cfg->agg_time_limit && - priv->cfg->agg_time_limit >= LINK_QUAL_AGG_TIME_LIMIT_MIN && - priv->cfg->agg_time_limit <= LINK_QUAL_AGG_TIME_LIMIT_MAX) + if (priv && priv->cfg->bt_params && + priv->cfg->bt_params->agg_time_limit && + priv->cfg->bt_params->agg_time_limit >= + LINK_QUAL_AGG_TIME_LIMIT_MIN && + priv->cfg->bt_params->agg_time_limit <= + LINK_QUAL_AGG_TIME_LIMIT_MAX) lq_cmd->agg_params.agg_time_limit = - cpu_to_le16(priv->cfg->agg_time_limit); + cpu_to_le16(priv->cfg->bt_params->agg_time_limit); } static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c index 9490eced1198..1e08eb455474 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c @@ -73,7 +73,8 @@ static void iwl_rx_calc_noise(struct iwl_priv *priv) int bcn_silence_a, bcn_silence_b, bcn_silence_c; int last_rx_noise; - if (priv->cfg->bt_statistics) + if (priv->cfg->bt_params && + priv->cfg->bt_params->bt_statistics) rx_info = &(priv->_agn.statistics_bt.rx.general.common); else rx_info = &(priv->_agn.statistics.rx.general); @@ -124,7 +125,8 @@ static void iwl_accumulative_statistics(struct iwl_priv *priv, struct statistics_general_common *general, *accum_general; struct statistics_tx *tx, *accum_tx; - if (priv->cfg->bt_statistics) { + if (priv->cfg->bt_params && + priv->cfg->bt_params->bt_statistics) { prev_stats = (__le32 *)&priv->_agn.statistics_bt; accum_stats = (u32 *)&priv->_agn.accum_statistics_bt; size = sizeof(struct iwl_bt_notif_statistics); @@ -183,7 +185,7 @@ bool iwl_good_plcp_health(struct iwl_priv *priv, unsigned int plcp_msec; unsigned long plcp_received_jiffies; - if (priv->cfg->plcp_delta_threshold == + if (priv->cfg->base_params->plcp_delta_threshold == IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE) { IWL_DEBUG_RADIO(priv, "plcp_err check disabled\n"); return rc; @@ -205,7 +207,8 @@ bool iwl_good_plcp_health(struct iwl_priv *priv, struct statistics_rx_phy *ofdm; struct statistics_rx_ht_phy *ofdm_ht; - if (priv->cfg->bt_statistics) { + if (priv->cfg->bt_params && + priv->cfg->bt_params->bt_statistics) { ofdm = &pkt->u.stats_bt.rx.ofdm; ofdm_ht = &pkt->u.stats_bt.rx.ofdm_ht; combined_plcp_delta = @@ -229,7 +232,7 @@ bool iwl_good_plcp_health(struct iwl_priv *priv, if ((combined_plcp_delta > 0) && ((combined_plcp_delta * 100) / plcp_msec) > - priv->cfg->plcp_delta_threshold) { + priv->cfg->base_params->plcp_delta_threshold) { /* * if plcp_err exceed the threshold, * the following data is printed in csv format: @@ -242,13 +245,13 @@ bool iwl_good_plcp_health(struct iwl_priv *priv, * plcp_msec */ IWL_DEBUG_RADIO(priv, "plcp_err exceeded %u, " - "%u, %u, %u, %u, %d, %u mSecs\n", - priv->cfg->plcp_delta_threshold, - le32_to_cpu(ofdm->plcp_err), - le32_to_cpu(ofdm->plcp_err), - le32_to_cpu(ofdm_ht->plcp_err), - le32_to_cpu(ofdm_ht->plcp_err), - combined_plcp_delta, plcp_msec); + "%u, %u, %u, %u, %d, %u mSecs\n", + priv->cfg->base_params->plcp_delta_threshold, + le32_to_cpu(ofdm->plcp_err), + le32_to_cpu(ofdm->plcp_err), + le32_to_cpu(ofdm_ht->plcp_err), + le32_to_cpu(ofdm_ht->plcp_err), + combined_plcp_delta, plcp_msec); rc = false; } @@ -262,7 +265,8 @@ void iwl_rx_statistics(struct iwl_priv *priv, int change; struct iwl_rx_packet *pkt = rxb_addr(rxb); - if (priv->cfg->bt_statistics) { + if (priv->cfg->bt_params && + priv->cfg->bt_params->bt_statistics) { IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n", (int)sizeof(struct iwl_bt_notif_statistics), @@ -300,7 +304,8 @@ void iwl_rx_statistics(struct iwl_priv *priv, iwl_recover_from_statistics(priv, pkt); - if (priv->cfg->bt_statistics) + if (priv->cfg->bt_params && + priv->cfg->bt_params->bt_statistics) memcpy(&priv->_agn.statistics_bt, &pkt->u.stats_bt, sizeof(priv->_agn.statistics_bt)); else diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tt.c b/drivers/net/wireless/iwlwifi/iwl-agn-tt.c index 07b2c6cadf51..0c6c4d969706 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tt.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tt.c @@ -114,7 +114,7 @@ static bool iwl_within_ct_kill_margin(struct iwl_priv *priv) s32 temp = priv->temperature; /* degrees CELSIUS except specified */ bool within_margin = false; - if (priv->cfg->temperature_kelvin) + if (priv->cfg->base_params->temperature_kelvin) temp = KELVIN_TO_CELSIUS(priv->temperature); if (!priv->thermal_throttle.advanced_tt) @@ -591,7 +591,7 @@ static void iwl_bg_tt_work(struct work_struct *work) if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; - if (priv->cfg->temperature_kelvin) + if (priv->cfg->base_params->temperature_kelvin) temp = KELVIN_TO_CELSIUS(priv->temperature); if (!priv->thermal_throttle.advanced_tt) @@ -640,7 +640,7 @@ void iwl_tt_initialize(struct iwl_priv *priv) INIT_WORK(&priv->ct_enter, iwl_bg_ct_enter); INIT_WORK(&priv->ct_exit, iwl_bg_ct_exit); - if (priv->cfg->adv_thermal_throttle) { + if (priv->cfg->base_params->adv_thermal_throttle) { IWL_DEBUG_POWER(priv, "Advanced Thermal Throttling\n"); tt->restriction = kzalloc(sizeof(struct iwl_tt_restriction) * IWL_TI_STATE_MAX, GFP_KERNEL); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index 5950184d9860..77753b72f236 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c @@ -224,13 +224,13 @@ int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, int ret; if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) || - (IWLAGN_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues - <= txq_id)) { + (IWLAGN_FIRST_AMPDU_QUEUE + + priv->cfg->base_params->num_of_ampdu_queues <= txq_id)) { IWL_WARN(priv, "queue number out of range: %d, must be %d to %d\n", txq_id, IWLAGN_FIRST_AMPDU_QUEUE, IWLAGN_FIRST_AMPDU_QUEUE + - priv->cfg->num_of_ampdu_queues - 1); + priv->cfg->base_params->num_of_ampdu_queues - 1); return -EINVAL; } @@ -286,13 +286,13 @@ int iwlagn_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, u16 ssn_idx, u8 tx_fifo) { if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) || - (IWLAGN_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues - <= txq_id)) { + (IWLAGN_FIRST_AMPDU_QUEUE + + priv->cfg->base_params->num_of_ampdu_queues <= txq_id)) { IWL_ERR(priv, "queue number out of range: %d, must be %d to %d\n", txq_id, IWLAGN_FIRST_AMPDU_QUEUE, IWLAGN_FIRST_AMPDU_QUEUE + - priv->cfg->num_of_ampdu_queues - 1); + priv->cfg->base_params->num_of_ampdu_queues - 1); return -EINVAL; } @@ -350,7 +350,8 @@ static void iwlagn_tx_cmd_build_basic(struct iwl_priv *priv, if (ieee80211_is_back_req(fc)) tx_flags |= TX_CMD_FLG_ACK_MSK | TX_CMD_FLG_IMM_BA_RSP_MASK; else if (info->band == IEEE80211_BAND_2GHZ && - priv->cfg->advanced_bt_coexist && + priv->cfg->bt_params && + priv->cfg->bt_params->advanced_bt_coexist && (ieee80211_is_auth(fc) || ieee80211_is_assoc_req(fc) || ieee80211_is_reassoc_req(fc) || skb->protocol == cpu_to_be16(ETH_P_PAE))) @@ -444,7 +445,9 @@ static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv, rate_flags |= RATE_MCS_CCK_MSK; /* Set up antennas */ - if (priv->cfg->advanced_bt_coexist && priv->bt_full_concurrent) { + if (priv->cfg->bt_params && + priv->cfg->bt_params->advanced_bt_coexist && + priv->bt_full_concurrent) { /* operated as 1x1 in full concurrency mode */ priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant, first_antenna(priv->hw_params.valid_tx_ant)); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c index 8bfb0495a76b..e1dd76267dca 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c @@ -307,7 +307,8 @@ void iwlagn_init_alive_start(struct iwl_priv *priv) goto restart; } - if (priv->cfg->advanced_bt_coexist) { + if (priv->cfg->bt_params && + priv->cfg->bt_params->advanced_bt_coexist) { /* * Tell uCode we are ready to perform calibration * need to perform this before any calibration @@ -330,7 +331,7 @@ static int iwlagn_send_wimax_coex(struct iwl_priv *priv) { struct iwl_wimax_coex_cmd coex_cmd; - if (priv->cfg->support_wimax_coexist) { + if (priv->cfg->base_params->support_wimax_coexist) { /* UnMask wake up src at associated sleep */ coex_cmd.flags = COEX_FLAGS_ASSOC_WA_UNMASK_MSK; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index e7dc8b92db66..080121d3a3ae 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2256,13 +2256,15 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) if (pieces.init_evtlog_size) priv->_agn.init_evtlog_size = (pieces.init_evtlog_size - 16)/12; else - priv->_agn.init_evtlog_size = priv->cfg->max_event_log_size; + priv->_agn.init_evtlog_size = + priv->cfg->base_params->max_event_log_size; priv->_agn.init_errlog_ptr = pieces.init_errlog_ptr; priv->_agn.inst_evtlog_ptr = pieces.inst_evtlog_ptr; if (pieces.inst_evtlog_size) priv->_agn.inst_evtlog_size = (pieces.inst_evtlog_size - 16)/12; else - priv->_agn.inst_evtlog_size = priv->cfg->max_event_log_size; + priv->_agn.inst_evtlog_size = + priv->cfg->base_params->max_event_log_size; priv->_agn.inst_errlog_ptr = pieces.inst_errlog_ptr; if (ucode_capa.pan) { @@ -2732,7 +2734,7 @@ static void iwl_rf_kill_ct_config(struct iwl_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); priv->thermal_throttle.ct_kill_toggle = false; - if (priv->cfg->support_ct_kill_exit) { + if (priv->cfg->base_params->support_ct_kill_exit) { adv_cmd.critical_temperature_enter = cpu_to_le32(priv->hw_params.ct_kill_threshold); adv_cmd.critical_temperature_exit = @@ -2776,9 +2778,7 @@ static int iwlagn_send_calib_cfg_rt(struct iwl_priv *priv, u32 cfg) memset(&calib_cfg_cmd, 0, sizeof(calib_cfg_cmd)); calib_cfg_cmd.ucd_calib_cfg.once.is_enable = IWL_CALIB_INIT_CFG_ALL; - calib_cfg_cmd.ucd_calib_cfg.once.start = cfg; - calib_cfg_cmd.ucd_calib_cfg.once.send_res = 0; - calib_cfg_cmd.ucd_calib_cfg.flags = 0; + calib_cfg_cmd.ucd_calib_cfg.once.start = cpu_to_le32(cfg); return iwl_send_cmd(priv, &cmd); } @@ -2831,13 +2831,15 @@ static void iwl_alive_start(struct iwl_priv *priv) /* Enable timer to monitor the driver queues */ mod_timer(&priv->monitor_recover, jiffies + - msecs_to_jiffies(priv->cfg->monitor_recover_period)); + msecs_to_jiffies( + priv->cfg->base_params->monitor_recover_period)); } if (iwl_is_rfkill(priv)) return; - if (priv->cfg->advanced_bt_coexist) { + if (priv->cfg->bt_params && + priv->cfg->bt_params->advanced_bt_coexist) { /* Configure Bluetooth device coexistence support */ priv->bt_valid = IWLAGN_BT_ALL_VALID_MSK; priv->kill_ack_mask = IWLAGN_BT_KILL_ACK_MASK_DEFAULT; @@ -2877,7 +2879,8 @@ static void iwl_alive_start(struct iwl_priv *priv) priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx); } - if (!priv->cfg->advanced_bt_coexist) { + if (priv->cfg->bt_params && + !priv->cfg->bt_params->advanced_bt_coexist) { /* Configure Bluetooth device coexistence support */ priv->cfg->ops->hcmd->send_bt_config(priv); } @@ -2930,7 +2933,11 @@ static void __iwl_down(struct iwl_priv *priv) /* reset BT coex data */ priv->bt_status = 0; - priv->bt_traffic_load = priv->cfg->bt_init_traffic_load; + if (priv->cfg->bt_params) + priv->bt_traffic_load = + priv->cfg->bt_params->bt_init_traffic_load; + else + priv->bt_traffic_load = 0; priv->bt_sco_active = false; priv->bt_full_concurrent = false; priv->bt_ci_compliance = 0; @@ -3224,7 +3231,8 @@ static void iwl_bg_run_time_calib_work(struct work_struct *work) } if (priv->start_calib) { - if (priv->cfg->bt_statistics) { + if (priv->cfg->bt_params && + priv->cfg->bt_params->bt_statistics) { iwl_chain_noise_calibration(priv, (void *)&priv->_agn.statistics_bt); iwl_sensitivity_calibration(priv, @@ -3423,7 +3431,7 @@ static int iwl_mac_setup_register(struct iwl_priv *priv, IEEE80211_HW_NEED_DTIM_PERIOD | IEEE80211_HW_SPECTRUM_MGMT; - if (!priv->cfg->broken_powersave) + if (!priv->cfg->base_params->broken_powersave) hw->flags |= IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_SUPPORTS_DYNAMIC_PS; @@ -3748,7 +3756,8 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw, } if (test_bit(STATUS_EXIT_PENDING, &priv->status)) ret = 0; - if (priv->cfg->use_rts_for_aggregation) { + if (priv->cfg->ht_params && + priv->cfg->ht_params->use_rts_for_aggregation) { struct iwl_station_priv *sta_priv = (void *) sta->drv_priv; /* @@ -3762,7 +3771,8 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw, } break; case IEEE80211_AMPDU_TX_OPERATIONAL: - if (priv->cfg->use_rts_for_aggregation) { + if (priv->cfg->ht_params && + priv->cfg->ht_params->use_rts_for_aggregation) { struct iwl_station_priv *sta_priv = (void *) sta->drv_priv; @@ -4080,7 +4090,7 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) priv->cfg->ops->lib->recover_from_tx_stall; } - if (!priv->cfg->use_isr_legacy) + if (!priv->cfg->base_params->use_isr_legacy) tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) iwl_irq_tasklet, (unsigned long)priv); else @@ -4165,7 +4175,8 @@ static int iwl_init_drv(struct iwl_priv *priv) iwl_init_scan_params(priv); /* init bt coex */ - if (priv->cfg->advanced_bt_coexist) { + if (priv->cfg->bt_params && + priv->cfg->bt_params->advanced_bt_coexist) { priv->kill_ack_mask = IWLAGN_BT_KILL_ACK_MASK_DEFAULT; priv->kill_cts_mask = IWLAGN_BT_KILL_CTS_MASK_DEFAULT; priv->bt_valid = IWLAGN_BT_ALL_VALID_MSK; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index b7adcf87280d..95cbc55a7a65 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -232,7 +232,8 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, ht_info->ht_supported = true; - if (priv->cfg->ht_greenfield_support) + if (priv->cfg->ht_params && + priv->cfg->ht_params->ht_greenfield_support) ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD; ht_info->cap |= IEEE80211_HT_CAP_SGI_20; max_bit_rate = MAX_BIT_RATE_20_MHZ; @@ -247,11 +248,11 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU; ht_info->ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF; - if (priv->cfg->ampdu_factor) - ht_info->ampdu_factor = priv->cfg->ampdu_factor; + if (priv->cfg->bt_params && priv->cfg->bt_params->ampdu_factor) + ht_info->ampdu_factor = priv->cfg->bt_params->ampdu_factor; ht_info->ampdu_density = CFG_HT_MPDU_DENSITY_DEF; - if (priv->cfg->ampdu_density) - ht_info->ampdu_density = priv->cfg->ampdu_density; + if (priv->cfg->bt_params && priv->cfg->bt_params->ampdu_density) + ht_info->ampdu_density = priv->cfg->bt_params->ampdu_density; ht_info->mcs.rx_mask[0] = 0xFF; if (rx_chains_num >= 2) @@ -850,8 +851,10 @@ EXPORT_SYMBOL(iwl_set_rxon_ht); */ static int iwl_get_active_rx_chain_count(struct iwl_priv *priv) { - if (priv->cfg->advanced_bt_coexist && (priv->bt_full_concurrent || - priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)) { + if (priv->cfg->bt_params && + priv->cfg->bt_params->advanced_bt_coexist && + (priv->bt_full_concurrent || + priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)) { /* * only use chain 'A' in bt high traffic load or * full concurrency mode @@ -919,8 +922,10 @@ void iwl_set_rxon_chain(struct iwl_priv *priv, struct iwl_rxon_context *ctx) else active_chains = priv->hw_params.valid_rx_ant; - if (priv->cfg->advanced_bt_coexist && (priv->bt_full_concurrent || - priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)) { + if (priv->cfg->bt_params && + priv->cfg->bt_params->advanced_bt_coexist && + (priv->bt_full_concurrent || + priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)) { /* * only use chain 'A' in bt high traffic load or * full concurrency mode @@ -1362,7 +1367,7 @@ int iwl_apm_init(struct iwl_priv *priv) * If not (unlikely), enable L0S, so there is at least some * power savings, even without L1. */ - if (priv->cfg->set_l0s) { + if (priv->cfg->base_params->set_l0s) { lctl = iwl_pcie_link_ctl(priv); if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) == PCI_CFG_LINK_CTRL_VAL_L1_EN) { @@ -1379,8 +1384,9 @@ int iwl_apm_init(struct iwl_priv *priv) } /* Configure analog phase-lock-loop before activating to D0A */ - if (priv->cfg->pll_cfg_val) - iwl_set_bit(priv, CSR_ANA_PLL_CFG, priv->cfg->pll_cfg_val); + if (priv->cfg->base_params->pll_cfg_val) + iwl_set_bit(priv, CSR_ANA_PLL_CFG, + priv->cfg->base_params->pll_cfg_val); /* * Set "initialization complete" bit to move adapter from @@ -1411,7 +1417,7 @@ int iwl_apm_init(struct iwl_priv *priv) * do not disable clocks. This preserves any hardware bits already * set by default in "CLK_CTRL_REG" after reset. */ - if (priv->cfg->use_bsm) + if (priv->cfg->base_params->use_bsm) iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT | APMG_CLK_VAL_BSM_CLK_RQT); else @@ -2054,7 +2060,8 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) goto out_err; } - if (priv->cfg->advanced_bt_coexist && + if (priv->cfg->bt_params && + priv->cfg->bt_params->advanced_bt_coexist && vif->type == NL80211_IFTYPE_ADHOC) { /* * pretend to have high BT traffic as long as we @@ -2317,7 +2324,8 @@ int iwl_alloc_txq_mem(struct iwl_priv *priv) { if (!priv->txq) priv->txq = kzalloc( - sizeof(struct iwl_tx_queue) * priv->cfg->num_of_queues, + sizeof(struct iwl_tx_queue) * + priv->cfg->base_params->num_of_queues, GFP_KERNEL); if (!priv->txq) { IWL_ERR(priv, "Not enough memory for txq\n"); @@ -2828,33 +2836,34 @@ static int iwl_check_stuck_queue(struct iwl_priv *priv, int cnt) txq = &priv->txq[cnt]; q = &txq->q; /* queue is empty, skip */ - if (q->read_ptr != q->write_ptr) { - if (q->read_ptr == q->last_read_ptr) { - /* a queue has not been read from last time */ - if (q->repeat_same_read_ptr > MAX_REPEAT) { - IWL_ERR(priv, - "queue %d stuck %d time. Fw reload.\n", - q->id, q->repeat_same_read_ptr); - q->repeat_same_read_ptr = 0; - iwl_force_reset(priv, IWL_FW_RESET, false); - } else { - q->repeat_same_read_ptr++; - IWL_DEBUG_RADIO(priv, - "queue %d, not read %d time\n", - q->id, - q->repeat_same_read_ptr); - if (!priv->cfg->advanced_bt_coexist) { - mod_timer(&priv->monitor_recover, - jiffies + msecs_to_jiffies( - IWL_ONE_HUNDRED_MSECS)); - return 1; - } - } - return 0; - } else { - q->last_read_ptr = q->read_ptr; + if (q->read_ptr == q->write_ptr) + return 0; + + if (q->read_ptr == q->last_read_ptr) { + /* a queue has not been read from last time */ + if (q->repeat_same_read_ptr > MAX_REPEAT) { + IWL_ERR(priv, + "queue %d stuck %d time. Fw reload.\n", + q->id, q->repeat_same_read_ptr); q->repeat_same_read_ptr = 0; + iwl_force_reset(priv, IWL_FW_RESET, false); + } else { + q->repeat_same_read_ptr++; + IWL_DEBUG_RADIO(priv, + "queue %d, not read %d time\n", + q->id, + q->repeat_same_read_ptr); + if (priv->cfg->bt_params && + !priv->cfg->bt_params->advanced_bt_coexist) { + mod_timer(&priv->monitor_recover, + jiffies + msecs_to_jiffies( + IWL_ONE_HUNDRED_MSECS)); + return 1; + } } + } else { + q->last_read_ptr = q->read_ptr; + q->repeat_same_read_ptr = 0; } return 0; } @@ -2881,13 +2890,13 @@ void iwl_bg_monitor_recover(unsigned long data) return; } } - if (priv->cfg->monitor_recover_period) { + if (priv->cfg->base_params->monitor_recover_period) { /* * Reschedule the timer to occur in - * priv->cfg->monitor_recover_period + * priv->cfg->base_params->monitor_recover_period */ mod_timer(&priv->monitor_recover, jiffies + msecs_to_jiffies( - priv->cfg->monitor_recover_period)); + priv->cfg->base_params->monitor_recover_period)); } } EXPORT_SYMBOL(iwl_bg_monitor_recover); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 5daa1893fd03..6228b1c2ec96 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -255,20 +255,12 @@ struct iwl_mod_params { int restart_fw; /* def: 1 = restart firmware */ }; -/** - * struct iwl_cfg - * @fw_name_pre: Firmware filename prefix. The api version and extension - * (.ucode) will be added to filename before loading from disk. The - * filename is constructed as fw_name_pre.ucode. - * @ucode_api_max: Highest version of uCode API supported by driver. - * @ucode_api_min: Lowest version of uCode API supported by driver. - * @pa_type: used by 6000 series only to identify the type of Power Amplifier +/* * @max_ll_items: max number of OTP blocks * @shadow_ram_support: shadow support for OTP memory * @led_compensation: compensate on the led on/off time per HW according * to the deviation to achieve the desired led frequency. * The detail algorithm is described in iwl-led.c - * @use_rts_for_aggregation: use rts/cts protection for HT traffic * @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 @@ -286,15 +278,73 @@ struct iwl_mod_params { * sensitivity calibration operation * @chain_noise_calib_by_driver: driver has the capability to perform * chain noise calibration operation - * @scan_antennas: available antenna for scan operation +*/ +struct iwl_base_params { + int eeprom_size; + int num_of_queues; /* def: HW dependent */ + int num_of_ampdu_queues;/* def: HW dependent */ + /* for iwl_apm_init() */ + u32 pll_cfg_val; + bool set_l0s; + bool use_bsm; + + bool use_isr_legacy; + const u16 max_ll_items; + const bool shadow_ram_support; + u16 led_compensation; + const bool broken_powersave; + int chain_noise_num_beacons; + const bool supports_idle; + bool adv_thermal_throttle; + bool support_ct_kill_exit; + const bool support_wimax_coexist; + u8 plcp_delta_threshold; + s32 chain_noise_scale; + /* timer period for monitor the driver queues */ + u32 monitor_recover_period; + bool temperature_kelvin; + u32 max_event_log_size; + const bool tx_power_by_driver; + const bool ucode_tracing; + const bool sensitivity_calib_by_driver; + const bool chain_noise_calib_by_driver; +}; +/* * @advanced_bt_coexist: support advanced bt coexist * @bt_init_traffic_load: specify initial bt traffic load * @bt_prio_boost: default bt priority boost value - * @need_dc_calib: need to perform init dc calibration * @bt_statistics: use BT version of statistics notification * @agg_time_limit: maximum number of uSec in aggregation * @ampdu_factor: Maximum A-MPDU length factor * @ampdu_density: Minimum A-MPDU spacing +*/ +struct iwl_bt_params { + bool advanced_bt_coexist; + u8 bt_init_traffic_load; + u8 bt_prio_boost; + const bool bt_statistics; + u16 agg_time_limit; + u8 ampdu_factor; + u8 ampdu_density; +}; +/* + * @use_rts_for_aggregation: use rts/cts protection for HT traffic +*/ +struct iwl_ht_params { + const bool ht_greenfield_support; /* if used set to true */ + bool use_rts_for_aggregation; +}; + +/** + * struct iwl_cfg + * @fw_name_pre: Firmware filename prefix. The api version and extension + * (.ucode) will be added to filename before loading from disk. The + * filename is constructed as fw_name_pre.ucode. + * @ucode_api_max: Highest version of uCode API supported by driver. + * @ucode_api_min: Lowest version of uCode API supported by driver. + * @pa_type: used by 6000 series only to identify the type of Power Amplifier + * @need_dc_calib: need to perform init dc calibration + * @scan_antennas: available antenna for scan operation * * We enable the driver to be backward compatible wrt API version. The * driver specifies which APIs it supports (with @ucode_api_max being the @@ -305,9 +355,9 @@ struct iwl_mod_params { * * For example, * if (IWL_UCODE_API(priv->ucode_ver) >= 2) { - * Driver interacts with Firmware API version >= 2. + * Driver interacts with Firmware API version >= 2. * } else { - * Driver interacts with Firmware API version 1. + * Driver interacts with Firmware API version 1. * } * * The ideal usage of this infrastructure is to treat a new ucode API @@ -318,59 +368,28 @@ struct iwl_mod_params { * */ struct iwl_cfg { + /* params specific to an individual device within a device family */ const char *name; const char *fw_name_pre; const unsigned int ucode_api_max; const unsigned int ucode_api_min; + u8 valid_tx_ant; + u8 valid_rx_ant; unsigned int sku; - int eeprom_size; u16 eeprom_ver; u16 eeprom_calib_ver; - int num_of_queues; /* def: HW dependent */ - int num_of_ampdu_queues;/* def: HW dependent */ const struct iwl_ops *ops; + /* module based parameters which can be set from modprobe cmd */ const struct iwl_mod_params *mod_params; - u8 valid_tx_ant; - u8 valid_rx_ant; - - /* for iwl_apm_init() */ - u32 pll_cfg_val; - bool set_l0s; - bool use_bsm; - - bool use_isr_legacy; - enum iwl_pa_type pa_type; - const u16 max_ll_items; - const bool shadow_ram_support; - const bool ht_greenfield_support; - u16 led_compensation; - const bool broken_powersave; - bool use_rts_for_aggregation; - int chain_noise_num_beacons; - const bool supports_idle; - bool adv_thermal_throttle; - bool support_ct_kill_exit; - const bool support_wimax_coexist; - u8 plcp_delta_threshold; - s32 chain_noise_scale; - /* timer period for monitor the driver queues */ - u32 monitor_recover_period; - bool temperature_kelvin; - u32 max_event_log_size; - const bool tx_power_by_driver; - const bool ucode_tracing; - const bool sensitivity_calib_by_driver; - const bool chain_noise_calib_by_driver; + /* params not likely to change within a device family */ + struct iwl_base_params *base_params; + /* params likely to change within a device family */ + struct iwl_ht_params *ht_params; + struct iwl_bt_params *bt_params; + enum iwl_pa_type pa_type; /* if used set to IWL_PA_SYSTEM */ + const bool need_dc_calib; /* if used set to true */ u8 scan_rx_antennas[IEEE80211_NUM_BANDS]; u8 scan_tx_antennas[IEEE80211_NUM_BANDS]; - bool advanced_bt_coexist; - u8 bt_init_traffic_load; - u8 bt_prio_boost; - const bool need_dc_calib; - const bool bt_statistics; - u16 agg_time_limit; - u8 ampdu_factor; - u8 ampdu_density; }; /*************************** diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 265ad01a443f..fc340311ea0a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -356,7 +356,7 @@ static ssize_t iwl_dbgfs_nvm_read(struct file *file, const u8 *ptr; char *buf; u16 eeprom_ver; - size_t eeprom_len = priv->cfg->eeprom_size; + size_t eeprom_len = priv->cfg->base_params->eeprom_size; buf_size = 4 * eeprom_len + 256; if (eeprom_len % 16) { @@ -872,7 +872,7 @@ static ssize_t iwl_dbgfs_traffic_log_read(struct file *file, struct iwl_rx_queue *rxq = &priv->rxq; char *buf; int bufsz = ((IWL_TRAFFIC_ENTRIES * IWL_TRAFFIC_ENTRY_SIZE * 64) * 2) + - (priv->cfg->num_of_queues * 32 * 8) + 400; + (priv->cfg->base_params->num_of_queues * 32 * 8) + 400; const u8 *ptr; ssize_t ret; @@ -971,7 +971,8 @@ static ssize_t iwl_dbgfs_tx_queue_read(struct file *file, int pos = 0; int cnt; int ret; - const size_t bufsz = sizeof(char) * 64 * priv->cfg->num_of_queues; + const size_t bufsz = sizeof(char) * 64 * + priv->cfg->base_params->num_of_queues; if (!priv->txq) { IWL_ERR(priv, "txq not ready\n"); @@ -1415,7 +1416,7 @@ static ssize_t iwl_dbgfs_plcp_delta_read(struct file *file, const size_t bufsz = sizeof(buf); pos += scnprintf(buf + pos, bufsz - pos, "%u\n", - priv->cfg->plcp_delta_threshold); + priv->cfg->base_params->plcp_delta_threshold); return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } @@ -1437,10 +1438,10 @@ static ssize_t iwl_dbgfs_plcp_delta_write(struct file *file, return -EINVAL; if ((plcp < IWL_MAX_PLCP_ERR_THRESHOLD_MIN) || (plcp > IWL_MAX_PLCP_ERR_THRESHOLD_MAX)) - priv->cfg->plcp_delta_threshold = + priv->cfg->base_params->plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE; else - priv->cfg->plcp_delta_threshold = plcp; + priv->cfg->base_params->plcp_delta_threshold = plcp; return count; } @@ -1550,13 +1551,14 @@ static ssize_t iwl_dbgfs_monitor_period_write(struct file *file, if (sscanf(buf, "%d", &period) != 1) return -EINVAL; if (period < 0 || period > IWL_MAX_MONITORING_PERIOD) - priv->cfg->monitor_recover_period = IWL_DEF_MONITORING_PERIOD; + priv->cfg->base_params->monitor_recover_period = + IWL_DEF_MONITORING_PERIOD; else - priv->cfg->monitor_recover_period = period; + priv->cfg->base_params->monitor_recover_period = period; - if (priv->cfg->monitor_recover_period) + if (priv->cfg->base_params->monitor_recover_period) mod_timer(&priv->monitor_recover, jiffies + msecs_to_jiffies( - priv->cfg->monitor_recover_period)); + priv->cfg->base_params->monitor_recover_period)); else del_timer_sync(&priv->monitor_recover); return count; @@ -1614,9 +1616,14 @@ static ssize_t iwl_dbgfs_protection_mode_read(struct file *file, char buf[40]; const size_t bufsz = sizeof(buf); - pos += scnprintf(buf + pos, bufsz - pos, "use %s for aggregation\n", - (priv->cfg->use_rts_for_aggregation) ? "rts/cts" : - "cts-to-self"); + if (priv->cfg->ht_params) + pos += scnprintf(buf + pos, bufsz - pos, + "use %s for aggregation\n", + (priv->cfg->ht_params->use_rts_for_aggregation) ? + "rts/cts" : "cts-to-self"); + else + pos += scnprintf(buf + pos, bufsz - pos, "N/A"); + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } @@ -1629,6 +1636,9 @@ static ssize_t iwl_dbgfs_protection_mode_write(struct file *file, int buf_size; int rts; + if (!priv->cfg->ht_params) + return -EINVAL; + memset(buf, 0, sizeof(buf)); buf_size = min(count, sizeof(buf) - 1); if (copy_from_user(buf, user_buf, buf_size)) @@ -1636,9 +1646,9 @@ static ssize_t iwl_dbgfs_protection_mode_write(struct file *file, if (sscanf(buf, "%d", &rts) != 1) return -EINVAL; if (rts) - priv->cfg->use_rts_for_aggregation = true; + priv->cfg->ht_params->use_rts_for_aggregation = true; else - priv->cfg->use_rts_for_aggregation = false; + priv->cfg->ht_params->use_rts_for_aggregation = false; return count; } @@ -1716,7 +1726,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) 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); - if (!priv->cfg->broken_powersave) { + if (!priv->cfg->base_params->broken_powersave) { DEBUGFS_ADD_FILE(sleep_level_override, dir_data, S_IWUSR | S_IRUSR); DEBUGFS_ADD_FILE(current_sleep_command, dir_data, S_IRUSR); @@ -1743,27 +1753,27 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(txfifo_flush, dir_debug, S_IWUSR); DEBUGFS_ADD_FILE(protection_mode, dir_debug, S_IWUSR | S_IRUSR); - if (priv->cfg->sensitivity_calib_by_driver) + if (priv->cfg->base_params->sensitivity_calib_by_driver) DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR); - if (priv->cfg->chain_noise_calib_by_driver) + if (priv->cfg->base_params->chain_noise_calib_by_driver) DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR); - if (priv->cfg->ucode_tracing) + if (priv->cfg->base_params->ucode_tracing) DEBUGFS_ADD_FILE(ucode_tracing, dir_debug, S_IWUSR | S_IRUSR); - if (priv->cfg->bt_statistics) + if (priv->cfg->bt_params && priv->cfg->bt_params->bt_statistics) DEBUGFS_ADD_FILE(ucode_bt_stats, dir_debug, S_IRUSR); DEBUGFS_ADD_FILE(reply_tx_error, dir_debug, S_IRUSR); DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR); DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR); DEBUGFS_ADD_FILE(monitor_period, dir_debug, S_IWUSR); - if (priv->cfg->advanced_bt_coexist) + if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist) DEBUGFS_ADD_FILE(bt_traffic, dir_debug, S_IRUSR); - if (priv->cfg->sensitivity_calib_by_driver) + if (priv->cfg->base_params->sensitivity_calib_by_driver) DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf, &priv->disable_sens_cal); - if (priv->cfg->chain_noise_calib_by_driver) + if (priv->cfg->base_params->chain_noise_calib_by_driver) DEBUGFS_ADD_BOOL(disable_chain_noise, dir_rf, &priv->disable_chain_noise_cal); - if (priv->cfg->tx_power_by_driver) + if (priv->cfg->base_params->tx_power_by_driver) DEBUGFS_ADD_BOOL(disable_tx_power, dir_rf, &priv->disable_tx_power_cal); return 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index a45d02e555cf..88f4a80d4733 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -332,7 +332,7 @@ EXPORT_SYMBOL(iwlcore_eeprom_release_semaphore); const u8 *iwlcore_eeprom_query_addr(const struct iwl_priv *priv, size_t offset) { - BUG_ON(offset >= priv->cfg->eeprom_size); + BUG_ON(offset >= priv->cfg->base_params->eeprom_size); return &priv->eeprom[offset]; } EXPORT_SYMBOL(iwlcore_eeprom_query_addr); @@ -364,7 +364,7 @@ static int iwl_init_otp_access(struct iwl_priv *priv) * CSR auto clock gate disable bit - * this is only applicable for HW with OTP shadow RAM */ - if (priv->cfg->shadow_ram_support) + if (priv->cfg->base_params->shadow_ram_support) iwl_set_bit(priv, CSR_DBG_LINK_PWR_MGMT_REG, CSR_RESET_LINK_PWR_MGMT_DISABLED); } @@ -484,7 +484,7 @@ static int iwl_find_otp_image(struct iwl_priv *priv, } /* more in the link list, continue */ usedblocks++; - } while (usedblocks <= priv->cfg->max_ll_items); + } while (usedblocks <= priv->cfg->base_params->max_ll_items); /* OTP has no valid blocks */ IWL_DEBUG_INFO(priv, "OTP has no valid blocks\n"); @@ -512,8 +512,8 @@ int iwl_eeprom_init(struct iwl_priv *priv) if (priv->nvm_device_type == -ENOENT) return -ENOENT; /* allocate eeprom */ - IWL_DEBUG_INFO(priv, "NVM size = %d\n", priv->cfg->eeprom_size); - sz = priv->cfg->eeprom_size; + sz = priv->cfg->base_params->eeprom_size; + IWL_DEBUG_INFO(priv, "NVM size = %d\n", sz); priv->eeprom = kzalloc(sz, GFP_KERNEL); if (!priv->eeprom) { ret = -ENOMEM; @@ -554,7 +554,7 @@ int iwl_eeprom_init(struct iwl_priv *priv) CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK | CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK); /* traversing the linked list if no shadow ram supported */ - if (!priv->cfg->shadow_ram_support) { + if (!priv->cfg->base_params->shadow_ram_support) { if (iwl_find_otp_image(priv, &validblockaddr)) { ret = -ENOENT; goto done; diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index db5bfcb036ca..86c2b6fed0c6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -108,13 +108,13 @@ static int iwl_led_pattern(struct iwl_priv *priv, unsigned int idx) BUG_ON(idx > IWL_MAX_BLINK_TBL); IWL_DEBUG_LED(priv, "Led blink time compensation= %u\n", - priv->cfg->led_compensation); + priv->cfg->base_params->led_compensation); led_cmd.on = iwl_blink_compensation(priv, blink_tbl[idx].on_time, - priv->cfg->led_compensation); + priv->cfg->base_params->led_compensation); led_cmd.off = iwl_blink_compensation(priv, blink_tbl[idx].off_time, - priv->cfg->led_compensation); + priv->cfg->base_params->led_compensation); return priv->cfg->ops->led->cmd(priv, &led_cmd); } diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 63c0ab46261f..49d7788937a9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -278,9 +278,9 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) dtimper = priv->hw->conf.ps_dtim_period ?: 1; - if (priv->cfg->broken_powersave) + if (priv->cfg->base_params->broken_powersave) iwl_power_sleep_cam_cmd(priv, &cmd); - else if (priv->cfg->supports_idle && + else if (priv->cfg->base_params->supports_idle && priv->hw->conf.flags & IEEE80211_CONF_IDLE) iwl_static_sleep_cmd(priv, &cmd, IWL_POWER_INDEX_5, 20); else if (priv->cfg->ops->lib->tt_ops.lower_power_detection && diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index c54c20023e7c..eaae49ee0c60 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -259,7 +259,8 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv, queue_work(priv->workqueue, &priv->scan_completed); if (priv->iw_mode != NL80211_IFTYPE_ADHOC && - priv->cfg->advanced_bt_coexist && + priv->cfg->bt_params && + priv->cfg->bt_params->advanced_bt_coexist && priv->bt_status != scan_notif->bt_status) { if (scan_notif->bt_status) { /* BT on */ diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 8b6aa3d38db0..43db5f38e3e6 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1581,16 +1581,16 @@ int iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log, num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32))); next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32))); - if (capacity > priv->cfg->max_event_log_size) { + if (capacity > priv->cfg->base_params->max_event_log_size) { IWL_ERR(priv, "Log capacity %d is bogus, limit to %d entries\n", - capacity, priv->cfg->max_event_log_size); - capacity = priv->cfg->max_event_log_size; + capacity, priv->cfg->base_params->max_event_log_size); + capacity = priv->cfg->base_params->max_event_log_size; } - if (next_entry > priv->cfg->max_event_log_size) { + if (next_entry > priv->cfg->base_params->max_event_log_size) { IWL_ERR(priv, "Log write index %d is bogus, limit to %d\n", - next_entry, priv->cfg->max_event_log_size); - next_entry = priv->cfg->max_event_log_size; + next_entry, priv->cfg->base_params->max_event_log_size); + next_entry = priv->cfg->base_params->max_event_log_size; } size = num_wraps ? capacity : next_entry; @@ -2519,7 +2519,8 @@ static void iwl3945_alive_start(struct iwl_priv *priv) /* Enable timer to monitor the driver queues */ mod_timer(&priv->monitor_recover, jiffies + - msecs_to_jiffies(priv->cfg->monitor_recover_period)); + msecs_to_jiffies( + priv->cfg->base_params->monitor_recover_period)); } if (iwl_is_rfkill(priv)) @@ -3881,7 +3882,7 @@ static int iwl3945_setup_mac(struct iwl_priv *priv) hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SPECTRUM_MGMT; - if (!priv->cfg->broken_powersave) + if (!priv->cfg->base_params->broken_powersave) hw->flags |= IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_SUPPORTS_DYNAMIC_PS; -- cgit v1.2.3 From ab63c68adaabb670f0513d5b63f3b233b16ea8b4 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Mon, 20 Sep 2010 09:12:31 -0700 Subject: iwlagn: rename iwl5000_tx_power_dbm_cmd iwl5000_tx_power_dbm_cmd really should be iwlagn_tx_power_dbm_cmd, so rename it. Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-agn-lib.c | 6 +++--- drivers/net/wireless/iwlwifi/iwl-commands.h | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 29ed6049c0f7..48c48f1fac37 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -491,7 +491,7 @@ int iwlagn_hw_valid_rtc_data_addr(u32 addr) int iwlagn_send_tx_power(struct iwl_priv *priv) { - struct iwl5000_tx_power_dbm_cmd tx_power_cmd; + struct iwlagn_tx_power_dbm_cmd tx_power_cmd; u8 tx_ant_cfg_cmd; /* half dBm need to multiply */ @@ -512,8 +512,8 @@ int iwlagn_send_tx_power(struct iwl_priv *priv) */ tx_power_cmd.global_lmt = priv->tx_power_lmt_in_half_dbm; } - tx_power_cmd.flags = IWL50_TX_POWER_NO_CLOSED; - tx_power_cmd.srv_chan_lmt = IWL50_TX_POWER_AUTO; + tx_power_cmd.flags = IWLAGN_TX_POWER_NO_CLOSED; + tx_power_cmd.srv_chan_lmt = IWLAGN_TX_POWER_AUTO; if (IWL_UCODE_API(priv->ucode_ver) == 1) tx_ant_cfg_cmd = REPLY_TX_POWER_DBM_CMD_V1; diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 27350eebb132..16dda2dce615 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -420,12 +420,12 @@ struct iwl4965_tx_power_db { /** * Command REPLY_TX_POWER_DBM_CMD = 0x98 - * struct iwl5000_tx_power_dbm_cmd + * struct iwlagn_tx_power_dbm_cmd */ -#define IWL50_TX_POWER_AUTO 0x7f -#define IWL50_TX_POWER_NO_CLOSED (0x1 << 6) +#define IWLAGN_TX_POWER_AUTO 0x7f +#define IWLAGN_TX_POWER_NO_CLOSED (0x1 << 6) -struct iwl5000_tx_power_dbm_cmd { +struct iwlagn_tx_power_dbm_cmd { s8 global_lmt; /*in half-dBm (e.g. 30 = 15 dBm) */ u8 flags; s8 srv_chan_lmt; /*in half-dBm (e.g. 30 = 15 dBm) */ -- cgit v1.2.3 From a8029bb79ec6de4acab5a6d3b931990152e8d5c1 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Mon, 20 Sep 2010 09:12:32 -0700 Subject: iwlwifi: remove uncorrect comments some structure belong to _agn devices, not just 5000. Fix it. Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-commands.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 16dda2dce615..953e536fe072 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -1042,7 +1042,7 @@ struct iwl4965_keyinfo { u8 key[16]; /* 16-byte unicast decryption key */ } __packed; -/* 5000 */ +/* agn */ struct iwl_keyinfo { __le16 key_flags; u8 tkip_rx_tsc_byte2; /* TSC[2] for key mix ph1 detection */ @@ -1168,7 +1168,7 @@ struct iwl4965_addsta_cmd { __le16 reserved2; } __packed; -/* 5000 */ +/* agn */ struct iwl_addsta_cmd { u8 mode; /* 1: modify existing, 0: add new station */ u8 reserved[3]; -- cgit v1.2.3 From 898dade1162970fe7af45e47062f9d1d999c46e6 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Mon, 20 Sep 2010 09:12:33 -0700 Subject: iwlagn: rename iwl5000_tx_resp iwl5000_tx_resp really should be iwlagn_tx_resp, rename it. Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-agn-lib.c | 14 ++++++++------ drivers/net/wireless/iwlwifi/iwl-commands.h | 10 +++++----- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 48c48f1fac37..f5445d575fec 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -40,7 +40,7 @@ #include "iwl-agn.h" #include "iwl-sta.h" -static inline u32 iwlagn_get_scd_ssn(struct iwl5000_tx_resp *tx_resp) +static inline u32 iwlagn_get_scd_ssn(struct iwlagn_tx_resp *tx_resp) { return le32_to_cpup((__le32 *)&tx_resp->status + tx_resp->frame_count) & MAX_SN; @@ -172,7 +172,7 @@ static void iwlagn_count_agg_tx_err_status(struct iwl_priv *priv, u16 status) static void iwlagn_set_tx_status(struct iwl_priv *priv, struct ieee80211_tx_info *info, - struct iwl5000_tx_resp *tx_resp, + struct iwlagn_tx_resp *tx_resp, int txq_id, bool is_agg) { u16 status = le16_to_cpu(tx_resp->status.status); @@ -223,7 +223,7 @@ const char *iwl_get_agg_tx_fail_reason(u16 status) static int iwlagn_tx_status_reply_tx(struct iwl_priv *priv, struct iwl_ht_agg *agg, - struct iwl5000_tx_resp *tx_resp, + struct iwlagn_tx_resp *tx_resp, int txq_id, u16 start_idx) { u16 status; @@ -390,7 +390,7 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv, int index = SEQ_TO_INDEX(sequence); struct iwl_tx_queue *txq = &priv->txq[txq_id]; struct ieee80211_tx_info *info; - struct iwl5000_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; + struct iwlagn_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; u32 status = le16_to_cpu(tx_resp->status.status); int tid; int sta_id; @@ -408,8 +408,10 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv, info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb); memset(&info->status, 0, sizeof(info->status)); - tid = (tx_resp->ra_tid & IWL50_TX_RES_TID_MSK) >> IWL50_TX_RES_TID_POS; - sta_id = (tx_resp->ra_tid & IWL50_TX_RES_RA_MSK) >> IWL50_TX_RES_RA_POS; + tid = (tx_resp->ra_tid & IWLAGN_TX_RES_TID_MSK) >> + IWLAGN_TX_RES_TID_POS; + sta_id = (tx_resp->ra_tid & IWLAGN_TX_RES_RA_MSK) >> + IWLAGN_TX_RES_RA_POS; spin_lock_irqsave(&priv->sta_lock, flags); if (txq->sched_retry) { diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 953e536fe072..fe652568fec7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -1959,12 +1959,12 @@ struct iwl4965_tx_resp { #define IWL50_TX_RES_INV_RATE_INDEX_MSK 0x80 /* refer to ra_tid */ -#define IWL50_TX_RES_TID_POS 0 -#define IWL50_TX_RES_TID_MSK 0x0f -#define IWL50_TX_RES_RA_POS 4 -#define IWL50_TX_RES_RA_MSK 0xf0 +#define IWLAGN_TX_RES_TID_POS 0 +#define IWLAGN_TX_RES_TID_MSK 0x0f +#define IWLAGN_TX_RES_RA_POS 4 +#define IWLAGN_TX_RES_RA_MSK 0xf0 -struct iwl5000_tx_resp { +struct iwlagn_tx_resp { u8 frame_count; /* 1 no aggregation, >1 aggregation */ u8 bt_kill_count; /* # blocked by bluetooth (unused for agg) */ u8 failure_rts; /* # failures due to unsuccessful RTS */ -- cgit v1.2.3 From 58a39090a13cf296afc17ed8fd793a55340b63db Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Wed, 6 Oct 2010 08:14:21 -0700 Subject: iwlagn: define 130 series of WiFi/BT combo devices add new structures and defines need to identify 130 devices. Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-6000.c | 44 +++++++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-agn.c | 10 ++++++++ drivers/net/wireless/iwlwifi/iwl-agn.h | 2 ++ 3 files changed, 56 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 5866ad868c32..43ec8988feb0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -53,11 +53,13 @@ #define IWL6000_UCODE_API_MAX 4 #define IWL6050_UCODE_API_MAX 5 #define IWL6000G2_UCODE_API_MAX 5 +#define IWL130_UCODE_API_MAX 5 /* Lowest firmware API version supported */ #define IWL6000_UCODE_API_MIN 4 #define IWL6050_UCODE_API_MIN 4 #define IWL6000G2_UCODE_API_MIN 4 +#define IWL130_UCODE_API_MIN 5 #define IWL6000_FW_PRE "iwlwifi-6000-" #define _IWL6000_MODULE_FIRMWARE(api) IWL6000_FW_PRE #api ".ucode" @@ -75,6 +77,9 @@ #define _IWL6000G2B_MODULE_FIRMWARE(api) IWL6000G2B_FW_PRE #api ".ucode" #define IWL6000G2B_MODULE_FIRMWARE(api) _IWL6000G2B_MODULE_FIRMWARE(api) +#define IWL130_FW_PRE "iwlwifi-130-" +#define _IWL100_MODULE_FIRMWARE(api) IWL130_FW_PRE #api ".ucode" +#define IWL100_MODULE_FIRMWARE(api) _IWL130_MODULE_FIRMWARE(api) static void iwl6000_set_ct_threshold(struct iwl_priv *priv) { @@ -810,6 +815,45 @@ struct iwl_cfg iwl6000_3agn_cfg = { .need_dc_calib = true, }; +struct iwl_cfg iwl130_bgn_cfg = { + .name = "Intel(R) 130 Series 1x1 BGN", + .fw_name_pre = IWL6000G2B_FW_PRE, + .ucode_api_max = IWL130_UCODE_API_MAX, + .ucode_api_min = IWL130_UCODE_API_MIN, + .sku = IWL_SKU_G|IWL_SKU_N, + .valid_tx_ant = ANT_A, + .valid_rx_ant = ANT_A, + .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION, + .ops = &iwl6000g2b_ops, + .mod_params = &iwlagn_mod_params, + .base_params = &iwl6000_base_params, + .bt_params = &iwl6000_bt_params, + .ht_params = &iwl6000_ht_params, + .need_dc_calib = true, + /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ + .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A, +}; + +struct iwl_cfg iwl130_bg_cfg = { + .name = "Intel(R) 130 Series 1x2 BG", + .fw_name_pre = IWL6000G2B_FW_PRE, + .ucode_api_max = IWL130_UCODE_API_MAX, + .ucode_api_min = IWL130_UCODE_API_MIN, + .sku = IWL_SKU_G, + .valid_tx_ant = ANT_A, + .valid_rx_ant = ANT_A, + .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION, + .ops = &iwl6000g2b_ops, + .mod_params = &iwlagn_mod_params, + .base_params = &iwl6000_base_params, + .bt_params = &iwl6000_bt_params, + .need_dc_calib = true, + /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ + .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A, +}; + MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL6050_MODULE_FIRMWARE(IWL6050_UCODE_API_MAX)); MODULE_FIRMWARE(IWL6000G2A_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 080121d3a3ae..a6dce616ee3c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -4822,11 +4822,21 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { {IWL_PCI_DEVICE(0x0084, 0x1216, iwl1000_bg_cfg)}, {IWL_PCI_DEVICE(0x0084, 0x1316, iwl1000_bg_cfg)}, +/* 100 Series WiFi */ {IWL_PCI_DEVICE(0x08AE, 0x1005, iwl100_bgn_cfg)}, {IWL_PCI_DEVICE(0x08AF, 0x1015, iwl100_bgn_cfg)}, {IWL_PCI_DEVICE(0x08AE, 0x1025, iwl100_bgn_cfg)}, {IWL_PCI_DEVICE(0x08AE, 0x1007, iwl100_bg_cfg)}, {IWL_PCI_DEVICE(0x08AE, 0x1017, iwl100_bg_cfg)}, + +/* 130 Series WiFi */ + {IWL_PCI_DEVICE(0x0896, 0x5005, iwl130_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0896, 0x5007, iwl130_bg_cfg)}, + {IWL_PCI_DEVICE(0x0897, 0x5015, iwl130_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0897, 0x5017, iwl130_bg_cfg)}, + {IWL_PCI_DEVICE(0x0896, 0x5025, iwl130_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0896, 0x5027, iwl130_bg_cfg)}, + #endif /* CONFIG_IWL5000 */ {0} diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index d5dc824ebbfb..eb3812a35862 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -94,6 +94,8 @@ extern struct iwl_cfg iwl1000_bgn_cfg; extern struct iwl_cfg iwl1000_bg_cfg; extern struct iwl_cfg iwl100_bgn_cfg; extern struct iwl_cfg iwl100_bg_cfg; +extern struct iwl_cfg iwl130_bgn_cfg; +extern struct iwl_cfg iwl130_bg_cfg; extern struct iwl_mod_params iwlagn_mod_params; extern struct iwl_hcmd_ops iwlagn_hcmd; -- cgit v1.2.3 From 918df629d6a558ab9eb53350493f618812239a4c Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 3 Oct 2010 19:07:19 +0200 Subject: ath9k_hw: fix regression in ANI listen time calculation wireless-testing commit 37e5bf6535a4d697fb9fa6f268a8354a612cbc00 Author: Luis R. Rodriguez Date: Sat Jun 12 00:33:40 2010 -0400 ath9k_hw: fix clock rate calculations for ANI This commit accidentally broke clock rate calculation by doubling the calculated clock rate Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ani.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index cc648b6ae31c..a3d95cca8f0c 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -543,7 +543,7 @@ static u8 ath9k_hw_chan_2_clockrate_mhz(struct ath_hw *ah) if (conf_is_ht40(conf)) return clockrate * 2; - return clockrate * 2; + return clockrate; } static int32_t ath9k_hw_ani_get_listen_time(struct ath_hw *ah) -- cgit v1.2.3 From 44271488b91c9eecf249e075a1805dd887e222d2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 5 Oct 2010 21:40:33 +0200 Subject: mac80211: delete AddBA response timer We never delete the addBA response timer, which is typically fine, but if the station it belongs to is deleted very quickly after starting the BA session, before the peer had a chance to reply, the timer may fire after the station struct has been freed already. Therefore, we need to delete the timer in a suitable spot -- best when the session is being stopped (which will happen even then) in which case the delete will be a no-op most of the time. I've reproduced the scenario and tested the fix. This fixes the crash reported at http://mid.gmane.org/4CAB6F96.6090701@candelatech.com Cc: stable@kernel.org Reported-by: Ben Greear Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/agg-tx.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index c893f236acea..8f23401832b7 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -175,6 +175,8 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, set_bit(HT_AGG_STATE_STOPPING, &tid_tx->state); + del_timer_sync(&tid_tx->addba_resp_timer); + /* * After this packets are no longer handed right through * to the driver but are put onto tid_tx->pending instead, -- cgit v1.2.3 From 6497827f53eb90dcf30c5d6414c83238f722e8ae Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 3 Oct 2010 19:07:16 +0200 Subject: ath9k_hw: clean up calibration flags The calibration actual calibration flags are only used by the per chip family source files, so it makes more sense to define them in those files instead of globally. That way the code has to test for less flags. Also instead of using a separate callback for testing whether a particular calibration type is supported, simply adjust ah->supp_cals in the calibration init which is called right after the hardware reset, before any of the calibrations are run. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9002_calib.c | 51 +++++++++++---------------- drivers/net/wireless/ath/ath9k/ar9003_calib.c | 36 +++++-------------- drivers/net/wireless/ath/ath9k/calib.c | 2 +- drivers/net/wireless/ath/ath9k/calib.h | 9 +---- drivers/net/wireless/ath/ath9k/hw-ops.h | 6 ---- drivers/net/wireless/ath/ath9k/hw.h | 4 +-- 6 files changed, 31 insertions(+), 77 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c index f2da119bbf02..f0525fb62a2c 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c @@ -20,6 +20,13 @@ #define AR9285_CLCAL_REDO_THRESH 1 +enum ar9002_cal_types { + ADC_GAIN_CAL = BIT(0), + ADC_DC_CAL = BIT(1), + IQ_MISMATCH_CAL = BIT(2), +}; + + static void ar9002_hw_setup_calibration(struct ath_hw *ah, struct ath9k_cal_list *currCal) { @@ -45,8 +52,6 @@ static void ar9002_hw_setup_calibration(struct ath_hw *ah, ath_print(common, ATH_DBG_CALIBRATE, "starting ADC DC Calibration\n"); break; - case TEMP_COMP_CAL: - break; /* Not supported */ } REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0), @@ -91,25 +96,6 @@ static bool ar9002_hw_per_calibration(struct ath_hw *ah, return iscaldone; } -/* Assumes you are talking about the currently configured channel */ -static bool ar9002_hw_iscal_supported(struct ath_hw *ah, - enum ath9k_cal_types calType) -{ - struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; - - switch (calType & ah->supp_cals) { - case IQ_MISMATCH_CAL: /* Both 2 GHz and 5 GHz support OFDM */ - return true; - case ADC_GAIN_CAL: - case ADC_DC_CAL: - if (!(conf->channel->band == IEEE80211_BAND_2GHZ && - conf_is_ht20(conf))) - return true; - break; - } - return false; -} - static void ar9002_hw_iqcal_collect(struct ath_hw *ah) { int i; @@ -872,24 +858,28 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) /* Enable IQ, ADC Gain and ADC DC offset CALs */ if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) { - if (ar9002_hw_iscal_supported(ah, ADC_GAIN_CAL)) { + ah->supp_cals = IQ_MISMATCH_CAL; + + if (AR_SREV_9160_10_OR_LATER(ah) && + !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan))) { + ah->supp_cals |= ADC_GAIN_CAL | ADC_DC_CAL; + + INIT_CAL(&ah->adcgain_caldata); INSERT_CAL(ah, &ah->adcgain_caldata); ath_print(common, ATH_DBG_CALIBRATE, "enabling ADC Gain Calibration.\n"); - } - if (ar9002_hw_iscal_supported(ah, ADC_DC_CAL)) { + INIT_CAL(&ah->adcdc_caldata); INSERT_CAL(ah, &ah->adcdc_caldata); ath_print(common, ATH_DBG_CALIBRATE, "enabling ADC DC Calibration.\n"); } - if (ar9002_hw_iscal_supported(ah, IQ_MISMATCH_CAL)) { - INIT_CAL(&ah->iq_caldata); - INSERT_CAL(ah, &ah->iq_caldata); - ath_print(common, ATH_DBG_CALIBRATE, - "enabling IQ Calibration.\n"); - } + + INIT_CAL(&ah->iq_caldata); + INSERT_CAL(ah, &ah->iq_caldata); + ath_print(common, ATH_DBG_CALIBRATE, + "enabling IQ Calibration.\n"); ah->cal_list_curr = ah->cal_list; @@ -980,7 +970,6 @@ void ar9002_hw_attach_calib_ops(struct ath_hw *ah) priv_ops->init_cal_settings = ar9002_hw_init_cal_settings; priv_ops->init_cal = ar9002_hw_init_cal; priv_ops->setup_calibration = ar9002_hw_setup_calibration; - priv_ops->iscal_supported = ar9002_hw_iscal_supported; ops->calibrate = ar9002_hw_calibrate; } diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index b41f5cda824b..9e6edffe0bd1 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -18,6 +18,11 @@ #include "hw-ops.h" #include "ar9003_phy.h" +enum ar9003_cal_types { + IQ_MISMATCH_CAL = BIT(0), + TEMP_COMP_CAL = BIT(1), +}; + static void ar9003_hw_setup_calibration(struct ath_hw *ah, struct ath9k_cal_list *currCal) { @@ -50,10 +55,6 @@ static void ar9003_hw_setup_calibration(struct ath_hw *ah, ath_print(common, ATH_DBG_CALIBRATE, "starting Temperature Compensation Calibration\n"); break; - case ADC_GAIN_CAL: - case ADC_DC_CAL: - /* Not yet */ - break; } } @@ -313,27 +314,6 @@ static const struct ath9k_percal_data iq_cal_single_sample = { static void ar9003_hw_init_cal_settings(struct ath_hw *ah) { ah->iq_caldata.calData = &iq_cal_single_sample; - ah->supp_cals = IQ_MISMATCH_CAL; -} - -static bool ar9003_hw_iscal_supported(struct ath_hw *ah, - enum ath9k_cal_types calType) -{ - switch (calType & ah->supp_cals) { - case IQ_MISMATCH_CAL: - /* - * XXX: Run IQ Mismatch for non-CCK only - * Note that CHANNEL_B is never set though. - */ - return true; - case ADC_GAIN_CAL: - case ADC_DC_CAL: - return false; - case TEMP_COMP_CAL: - return true; - } - - return false; } /* @@ -772,15 +752,16 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah, /* Initialize list pointers */ ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; + ah->supp_cals = IQ_MISMATCH_CAL; - if (ar9003_hw_iscal_supported(ah, IQ_MISMATCH_CAL)) { + if (ah->supp_cals & IQ_MISMATCH_CAL) { INIT_CAL(&ah->iq_caldata); INSERT_CAL(ah, &ah->iq_caldata); ath_print(common, ATH_DBG_CALIBRATE, "enabling IQ Calibration.\n"); } - if (ar9003_hw_iscal_supported(ah, TEMP_COMP_CAL)) { + if (ah->supp_cals & TEMP_COMP_CAL) { INIT_CAL(&ah->tempCompCalData); INSERT_CAL(ah, &ah->tempCompCalData); ath_print(common, ATH_DBG_CALIBRATE, @@ -807,7 +788,6 @@ void ar9003_hw_attach_calib_ops(struct ath_hw *ah) priv_ops->init_cal_settings = ar9003_hw_init_cal_settings; priv_ops->init_cal = ar9003_hw_init_cal; priv_ops->setup_calibration = ar9003_hw_setup_calibration; - priv_ops->iscal_supported = ar9003_hw_iscal_supported; ops->calibrate = ar9003_hw_calibrate; } diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index 6351e76792a6..6c38c72915c1 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -186,7 +186,7 @@ bool ath9k_hw_reset_calvalid(struct ath_hw *ah) return true; } - if (!ath9k_hw_iscal_supported(ah, currCal->calData->calType)) + if (!(ah->supp_cals & currCal->calData->calType)) return true; ath_print(common, ATH_DBG_CALIBRATE, diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h index 1fa56c91a894..b8973eb8d858 100644 --- a/drivers/net/wireless/ath/ath9k/calib.h +++ b/drivers/net/wireless/ath/ath9k/calib.h @@ -58,13 +58,6 @@ struct ar5416IniArray { } \ } while (0) -enum ath9k_cal_types { - ADC_GAIN_CAL = 0x2, - ADC_DC_CAL = 0x4, - IQ_MISMATCH_CAL = 0x8, - TEMP_COMP_CAL = 0x10, -}; - enum ath9k_cal_state { CAL_INACTIVE, CAL_WAITING, @@ -79,7 +72,7 @@ enum ath9k_cal_state { #define PER_MAX_LOG_COUNT 10 struct ath9k_percal_data { - enum ath9k_cal_types calType; + u32 calType; u32 calNumSamples; u32 calCountMax; void (*calCollect) (struct ath_hw *); diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h index ffecbadaea4a..9c4dd0ec9a15 100644 --- a/drivers/net/wireless/ath/ath9k/hw-ops.h +++ b/drivers/net/wireless/ath/ath9k/hw-ops.h @@ -276,12 +276,6 @@ static inline void ath9k_hw_setup_calibration(struct ath_hw *ah, ath9k_hw_private_ops(ah)->setup_calibration(ah, currCal); } -static inline bool ath9k_hw_iscal_supported(struct ath_hw *ah, - enum ath9k_cal_types calType) -{ - return ath9k_hw_private_ops(ah)->iscal_supported(ah, calType); -} - static inline void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning) { ath9k_hw_private_ops(ah)->ani_reset(ah, is_scanning); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 235cb5357a22..246c707cea00 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -535,8 +535,6 @@ struct ath_hw_private_ops { bool (*macversion_supported)(u32 macversion); void (*setup_calibration)(struct ath_hw *ah, struct ath9k_cal_list *currCal); - bool (*iscal_supported)(struct ath_hw *ah, - enum ath9k_cal_types calType); /* PHY ops */ int (*rf_set_freq)(struct ath_hw *ah, @@ -689,7 +687,7 @@ struct ath_hw { u32 atim_window; /* Calibration */ - enum ath9k_cal_types supp_cals; + u32 supp_cals; struct ath9k_cal_list iq_caldata; struct ath9k_cal_list adcgain_caldata; struct ath9k_cal_list adcdc_caldata; -- cgit v1.2.3 From 9dbebc7fd07ab66341dce8d001272db400c11e03 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 3 Oct 2010 19:07:17 +0200 Subject: ath9k_hw: merge codepaths that access the cycle counter registers The cycle counters are used by ANI to determine the amount of time that the radio spent not receiving or transmitting. They're also used for debugging purposes if the baseband watchdog on AR9003 detects a lockup. In the future, we want to use these counters to determine the medium utilization and export this information via survey. For that, we need to make sure that the counter is only accessed from one place, which also ensures that wraparounds won't occur at inconvenient points in time. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ani.c | 119 +++++++++++----------------- drivers/net/wireless/ath/ath9k/ani.h | 13 +-- drivers/net/wireless/ath/ath9k/ar5008_phy.c | 9 +-- drivers/net/wireless/ath/ath9k/ar9003_phy.c | 14 ++-- drivers/net/wireless/ath/ath9k/hw.h | 2 + 5 files changed, 65 insertions(+), 92 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index 45f477ad7608..3fba81e3a61f 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -549,47 +549,15 @@ static u8 ath9k_hw_chan_2_clockrate_mhz(struct ath_hw *ah) static int32_t ath9k_hw_ani_get_listen_time(struct ath_hw *ah) { - struct ar5416AniState *aniState; - struct ath_common *common = ath9k_hw_common(ah); - u32 txFrameCount, rxFrameCount, cycleCount; - int32_t listenTime; - - txFrameCount = REG_READ(ah, AR_TFCNT); - rxFrameCount = REG_READ(ah, AR_RFCNT); - cycleCount = REG_READ(ah, AR_CCCNT); - - aniState = ah->curani; - if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) { - listenTime = 0; - ah->stats.ast_ani_lzero++; - ath_print(common, ATH_DBG_ANI, - "1st call: aniState->cycleCount=%d\n", - aniState->cycleCount); - } else { - int32_t ccdelta = cycleCount - aniState->cycleCount; - int32_t rfdelta = rxFrameCount - aniState->rxFrameCount; - int32_t tfdelta = txFrameCount - aniState->txFrameCount; - int32_t clock_rate; - - /* - * convert HW counter values to ms using mode - * specifix clock rate - */ - clock_rate = ath9k_hw_chan_2_clockrate_mhz(ah) * 1000;; + int32_t listen_time; + int32_t clock_rate; - listenTime = (ccdelta - rfdelta - tfdelta) / clock_rate; + ath9k_hw_update_cycle_counters(ah); + clock_rate = ath9k_hw_chan_2_clockrate_mhz(ah) * 1000; + listen_time = ah->listen_time / clock_rate; + ah->listen_time = 0; - ath_print(common, ATH_DBG_ANI, - "cyclecount=%d, rfcount=%d, " - "tfcount=%d, listenTime=%d CLOCK_RATE=%d\n", - ccdelta, rfdelta, tfdelta, listenTime, clock_rate); - } - - aniState->cycleCount = cycleCount; - aniState->txFrameCount = txFrameCount; - aniState->rxFrameCount = rxFrameCount; - - return listenTime; + return listen_time; } static void ath9k_ani_reset_old(struct ath_hw *ah, bool is_scanning) @@ -1041,45 +1009,52 @@ void ath9k_hw_disable_mib_counters(struct ath_hw *ah) } EXPORT_SYMBOL(ath9k_hw_disable_mib_counters); -u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, - u32 *rxc_pcnt, - u32 *rxf_pcnt, - u32 *txf_pcnt) +void ath9k_hw_update_cycle_counters(struct ath_hw *ah) { - struct ath_common *common = ath9k_hw_common(ah); - static u32 cycles, rx_clear, rx_frame, tx_frame; - u32 good = 1; + struct ath_cycle_counters cc; + bool clear; - u32 rc = REG_READ(ah, AR_RCCNT); - u32 rf = REG_READ(ah, AR_RFCNT); - u32 tf = REG_READ(ah, AR_TFCNT); - u32 cc = REG_READ(ah, AR_CCCNT); + memcpy(&cc, &ah->cc, sizeof(cc)); - if (cycles == 0 || cycles > cc) { - ath_print(common, ATH_DBG_ANI, - "cycle counter wrap. ExtBusy = 0\n"); - good = 0; - } else { - u32 cc_d = cc - cycles; - u32 rc_d = rc - rx_clear; - u32 rf_d = rf - rx_frame; - u32 tf_d = tf - tx_frame; - - if (cc_d != 0) { - *rxc_pcnt = rc_d * 100 / cc_d; - *rxf_pcnt = rf_d * 100 / cc_d; - *txf_pcnt = tf_d * 100 / cc_d; - } else { - good = 0; - } + /* freeze counters */ + REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC); + + ah->cc.cycles = REG_READ(ah, AR_CCCNT); + if (ah->cc.cycles < cc.cycles) { + clear = true; + goto skip; } - cycles = cc; - rx_frame = rf; - rx_clear = rc; - tx_frame = tf; + ah->cc.rx_clear = REG_READ(ah, AR_RCCNT); + ah->cc.rx_frame = REG_READ(ah, AR_RFCNT); + ah->cc.tx_frame = REG_READ(ah, AR_TFCNT); + + /* prevent wraparound */ + if (ah->cc.cycles & BIT(31)) + clear = true; + +#define CC_DELTA(_field, _reg) ah->cc_delta._field += ah->cc._field - cc._field + CC_DELTA(cycles, AR_CCCNT); + CC_DELTA(rx_frame, AR_RFCNT); + CC_DELTA(rx_clear, AR_RCCNT); + CC_DELTA(tx_frame, AR_TFCNT); +#undef CC_DELTA + + ah->listen_time += (ah->cc.cycles - cc.cycles) - + ((ah->cc.rx_frame - cc.rx_frame) + + (ah->cc.tx_frame - cc.tx_frame)); + +skip: + if (clear) { + REG_WRITE(ah, AR_CCCNT, 0); + REG_WRITE(ah, AR_RFCNT, 0); + REG_WRITE(ah, AR_RCCNT, 0); + REG_WRITE(ah, AR_TFCNT, 0); + memset(&ah->cc, 0, sizeof(ah->cc)); + } - return good; + /* unfreeze counters */ + REG_WRITE(ah, AR_MIBC, 0); } /* diff --git a/drivers/net/wireless/ath/ath9k/ani.h b/drivers/net/wireless/ath/ath9k/ani.h index f4d0a4d48b37..15f9d67a18c8 100644 --- a/drivers/net/wireless/ath/ath9k/ani.h +++ b/drivers/net/wireless/ath/ath9k/ani.h @@ -93,6 +93,13 @@ struct ath9k_mib_stats { u32 beacons; }; +struct ath_cycle_counters { + u32 cycles; + u32 rx_frame; + u32 rx_clear; + u32 tx_frame; +}; + /* INI default values for ANI registers */ struct ath9k_ani_default { u16 m1ThreshLow; @@ -130,9 +137,6 @@ struct ar5416AniState { int32_t rssiThrLow; int32_t rssiThrHigh; u32 noiseFloor; - u32 txFrameCount; - u32 rxFrameCount; - u32 cycleCount; u32 ofdmPhyErrCount; u32 cckPhyErrCount; u32 ofdmPhyErrBase; @@ -166,8 +170,7 @@ struct ar5416Stats { void ath9k_enable_mib_counters(struct ath_hw *ah); void ath9k_hw_disable_mib_counters(struct ath_hw *ah); -u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, u32 *rxc_pcnt, - u32 *rxf_pcnt, u32 *txf_pcnt); +void ath9k_hw_update_cycle_counters(struct ath_hw *ah); void ath9k_hw_ani_setup(struct ath_hw *ah); void ath9k_hw_ani_init(struct ath_hw *ah); int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah, diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index 525671f52b45..a11ca0247793 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -1225,8 +1225,7 @@ static bool ar5008_hw_ani_control_old(struct ath_hw *ah, aniState->firstepLevel, aniState->listenTime); ath_print(common, ATH_DBG_ANI, - "cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n", - aniState->cycleCount, + "ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n", aniState->ofdmPhyErrCount, aniState->cckPhyErrCount); @@ -1478,15 +1477,13 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, ath_print(common, ATH_DBG_ANI, "ANI parameters: SI=%d, ofdmWS=%s FS=%d " - "MRCcck=%s listenTime=%d CC=%d listen=%d " + "MRCcck=%s listenTime=%d " "ofdmErrs=%d cckErrs=%d\n", aniState->spurImmunityLevel, !aniState->ofdmWeakSigDetectOff ? "on" : "off", aniState->firstepLevel, !aniState->mrcCCKOff ? "on" : "off", aniState->listenTime, - aniState->cycleCount, - aniState->listenTime, aniState->ofdmPhyErrCount, aniState->cckPhyErrCount); return true; @@ -1579,8 +1576,6 @@ static void ar5008_hw_ani_cache_ini_regs(struct ath_hw *ah) aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_NEW; aniState->ofdmWeakSigDetectOff = !ATH9K_ANI_USE_OFDM_WEAK_SIG; aniState->mrcCCKOff = true; /* not available on pre AR9003 */ - - aniState->cycleCount = 0; } static void ar5008_hw_set_nf_limits(struct ath_hw *ah) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index a491854fa38a..e15574caf61a 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -1005,15 +1005,13 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah, ath_print(common, ATH_DBG_ANI, "ANI parameters: SI=%d, ofdmWS=%s FS=%d " - "MRCcck=%s listenTime=%d CC=%d listen=%d " + "MRCcck=%s listenTime=%d " "ofdmErrs=%d cckErrs=%d\n", aniState->spurImmunityLevel, !aniState->ofdmWeakSigDetectOff ? "on" : "off", aniState->firstepLevel, !aniState->mrcCCKOff ? "on" : "off", aniState->listenTime, - aniState->cycleCount, - aniState->listenTime, aniState->ofdmPhyErrCount, aniState->cckPhyErrCount); return true; @@ -1116,8 +1114,6 @@ static void ar9003_hw_ani_cache_ini_regs(struct ath_hw *ah) aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_NEW; aniState->ofdmWeakSigDetectOff = !ATH9K_ANI_USE_OFDM_WEAK_SIG; aniState->mrcCCKOff = !ATH9K_ANI_ENABLE_MRC_CCK; - - aniState->cycleCount = 0; } void ar9003_hw_attach_phy_ops(struct ath_hw *ah) @@ -1232,7 +1228,7 @@ void ar9003_hw_bb_watchdog_read(struct ath_hw *ah) void ar9003_hw_bb_watchdog_dbg_info(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); - u32 rxc_pcnt = 0, rxf_pcnt = 0, txf_pcnt = 0, status; + u32 status; if (likely(!(common->debug_mask & ATH_DBG_RESET))) return; @@ -1261,11 +1257,13 @@ void ar9003_hw_bb_watchdog_dbg_info(struct ath_hw *ah) "** BB mode: BB_gen_controls=0x%08x **\n", REG_READ(ah, AR_PHY_GEN_CTRL)); - if (ath9k_hw_GetMibCycleCountsPct(ah, &rxc_pcnt, &rxf_pcnt, &txf_pcnt)) + ath9k_hw_update_cycle_counters(ah); +#define PCT(_field) (ah->cc_delta._field * 100 / ah->cc_delta.cycles) + if (ah->cc_delta.cycles) ath_print(common, ATH_DBG_RESET, "** BB busy times: rx_clear=%d%%, " "rx_frame=%d%%, tx_frame=%d%% **\n", - rxc_pcnt, rxf_pcnt, txf_pcnt); + PCT(rx_clear), PCT(rx_frame), PCT(tx_frame)); ath_print(common, ATH_DBG_RESET, "==== BB update: done ====\n\n"); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 246c707cea00..87dbb8502469 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -765,6 +765,8 @@ struct ath_hw { int coarse_low[5]; int firpwr[5]; enum ath9k_ani_cmd ani_function; + struct ath_cycle_counters cc, cc_delta; + int32_t listen_time; /* Bluetooth coexistance */ struct ath_btcoex_hw btcoex_hw; -- cgit v1.2.3 From 435c1610f46dc4d86a6633adb037b18109e6ffdc Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 5 Oct 2010 12:03:42 +0200 Subject: ath9k_hw: clean up register write buffering Throughout the code, DISABLE_REGWRITE_BUFFER is always called right after REGWRITE_BUFFER_FLUSH. Since that's unlikely to change any time soon, that makes keeping those ops separate rather pointless, as it only increases code size and line number counts. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath.h | 4 +--- drivers/net/wireless/ath/ath9k/ani.c | 6 ------ drivers/net/wireless/ath/ath9k/ar5008_phy.c | 9 ++------- drivers/net/wireless/ath/ath9k/ar9002_calib.c | 1 - drivers/net/wireless/ath/ath9k/ar9002_hw.c | 4 ---- drivers/net/wireless/ath/ath9k/ar9002_phy.c | 1 - drivers/net/wireless/ath/ath9k/calib.c | 1 - drivers/net/wireless/ath/ath9k/eeprom_4k.c | 2 -- drivers/net/wireless/ath/ath9k/htc_drv_init.c | 12 ++---------- drivers/net/wireless/ath/ath9k/hw.c | 14 -------------- drivers/net/wireless/ath/ath9k/hw.h | 10 ++-------- drivers/net/wireless/ath/ath9k/mac.c | 4 ---- 12 files changed, 7 insertions(+), 61 deletions(-) diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index 5894fcc2c628..cee0191704f5 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -102,14 +102,12 @@ enum ath_cipher { * @read: Register read * @write: Register write * @enable_write_buffer: Enable multiple register writes - * @disable_write_buffer: Disable multiple register writes - * @write_flush: Flush buffered register writes + * @write_flush: flush buffered register writes and disable buffering */ struct ath_ops { unsigned int (*read)(void *, u32 reg_offset); void (*write)(void *, u32 val, u32 reg_offset); void (*enable_write_buffer)(void *); - void (*disable_write_buffer)(void *); void (*write_flush) (void *); }; diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index 3fba81e3a61f..a1894d240773 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -180,7 +180,6 @@ static void ath9k_ani_restart_old(struct ath_hw *ah) REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); REGWRITE_BUFFER_FLUSH(ah); - DISABLE_REGWRITE_BUFFER(ah); ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); @@ -215,7 +214,6 @@ static void ath9k_ani_restart_new(struct ath_hw *ah) REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); REGWRITE_BUFFER_FLUSH(ah); - DISABLE_REGWRITE_BUFFER(ah); ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); @@ -643,7 +641,6 @@ static void ath9k_ani_reset_old(struct ath_hw *ah, bool is_scanning) REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); REGWRITE_BUFFER_FLUSH(ah); - DISABLE_REGWRITE_BUFFER(ah); } /* @@ -737,7 +734,6 @@ static void ath9k_ani_reset_new(struct ath_hw *ah, bool is_scanning) REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); REGWRITE_BUFFER_FLUSH(ah); - DISABLE_REGWRITE_BUFFER(ah); } static void ath9k_hw_ani_monitor_old(struct ath_hw *ah, @@ -991,7 +987,6 @@ void ath9k_enable_mib_counters(struct ath_hw *ah) REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); REGWRITE_BUFFER_FLUSH(ah); - DISABLE_REGWRITE_BUFFER(ah); } /* Freeze the MIB counters, get the stats and then clear them */ @@ -1261,7 +1256,6 @@ void ath9k_hw_ani_init(struct ath_hw *ah) REG_WRITE(ah, AR_PHY_ERR_2, ah->ani[0].cckPhyErrBase); REGWRITE_BUFFER_FLUSH(ah); - DISABLE_REGWRITE_BUFFER(ah); ath9k_enable_mib_counters(ah); diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index a11ca0247793..7b26292daf35 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -613,14 +613,11 @@ static void ar5008_hw_init_chain_masks(struct ath_hw *ah) rx_chainmask = ah->rxchainmask; tx_chainmask = ah->txchainmask; - ENABLE_REGWRITE_BUFFER(ah); switch (rx_chainmask) { case 0x5: - DISABLE_REGWRITE_BUFFER(ah); REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, AR_PHY_SWAP_ALT_CHAIN); - ENABLE_REGWRITE_BUFFER(ah); case 0x3: if (ah->hw_version.macVersion == AR_SREV_REVISION_5416_10) { REG_WRITE(ah, AR_PHY_RX_CHAINMASK, 0x7); @@ -630,17 +627,18 @@ static void ar5008_hw_init_chain_masks(struct ath_hw *ah) case 0x1: case 0x2: case 0x7: + ENABLE_REGWRITE_BUFFER(ah); REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask); REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask); break; default: + ENABLE_REGWRITE_BUFFER(ah); break; } REG_WRITE(ah, AR_SELFGEN_MASK, tx_chainmask); REGWRITE_BUFFER_FLUSH(ah); - DISABLE_REGWRITE_BUFFER(ah); if (tx_chainmask == 0x5) { REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, @@ -726,7 +724,6 @@ static void ar5008_hw_set_channel_regs(struct ath_hw *ah, REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S); REGWRITE_BUFFER_FLUSH(ah); - DISABLE_REGWRITE_BUFFER(ah); } @@ -818,7 +815,6 @@ static int ar5008_hw_process_ini(struct ath_hw *ah, } REGWRITE_BUFFER_FLUSH(ah); - DISABLE_REGWRITE_BUFFER(ah); if (AR_SREV_9280(ah) || AR_SREV_9287_11_OR_LATER(ah)) REG_WRITE_ARRAY(&ah->iniModesRxGain, modesIndex, regWrites); @@ -849,7 +845,6 @@ static int ar5008_hw_process_ini(struct ath_hw *ah, } REGWRITE_BUFFER_FLUSH(ah); - DISABLE_REGWRITE_BUFFER(ah); if (AR_SREV_9271(ah)) { if (ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE) == 1) diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c index f0525fb62a2c..15f62cd0cc38 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c @@ -522,7 +522,6 @@ static void ar9271_hw_pa_cal(struct ath_hw *ah, bool is_reset) REG_WRITE(ah, regList[i][0], regList[i][1]); REGWRITE_BUFFER_FLUSH(ah); - DISABLE_REGWRITE_BUFFER(ah); } static inline void ar9285_hw_pa_cal(struct ath_hw *ah, bool is_reset) diff --git a/drivers/net/wireless/ath/ath9k/ar9002_hw.c b/drivers/net/wireless/ath/ath9k/ar9002_hw.c index fde45082a13b..78bdf0cec5f0 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c @@ -371,7 +371,6 @@ static void ar9002_hw_configpcipowersave(struct ath_hw *ah, REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000); REGWRITE_BUFFER_FLUSH(ah); - DISABLE_REGWRITE_BUFFER(ah); } udelay(1000); @@ -468,7 +467,6 @@ static int ar9002_hw_get_radiorev(struct ath_hw *ah) REG_WRITE(ah, AR_PHY(0x20), 0x00010000); REGWRITE_BUFFER_FLUSH(ah); - DISABLE_REGWRITE_BUFFER(ah); val = (REG_READ(ah, AR_PHY(256)) >> 24) & 0xff; val = ((val & 0xf0) >> 4) | ((val & 0x0f) << 4); @@ -627,6 +625,4 @@ void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan) } REGWRITE_BUFFER_FLUSH(ah); - DISABLE_REGWRITE_BUFFER(ah); - } diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.c b/drivers/net/wireless/ath/ath9k/ar9002_phy.c index cd56c8692705..c00cdc67b55b 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c @@ -415,7 +415,6 @@ static void ar9002_hw_spur_mitigate(struct ath_hw *ah, REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); REGWRITE_BUFFER_FLUSH(ah); - DISABLE_REGWRITE_BUFFER(ah); } static void ar9002_olc_init(struct ath_hw *ah) diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index 6c38c72915c1..6d509484b5f6 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -300,7 +300,6 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) } } REGWRITE_BUFFER_FLUSH(ah); - DISABLE_REGWRITE_BUFFER(ah); } diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index 872e75b0b574..4fa4d8e28c64 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -508,7 +508,6 @@ static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah, } REGWRITE_BUFFER_FLUSH(ah); - DISABLE_REGWRITE_BUFFER(ah); } } @@ -840,7 +839,6 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, } REGWRITE_BUFFER_FLUSH(ah); - DISABLE_REGWRITE_BUFFER(ah); } static void ath9k_hw_4k_set_addac(struct ath_hw *ah, diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index b100db2766cf..bbb54bc28a44 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -380,15 +380,6 @@ static void ath9k_enable_regwrite_buffer(void *hw_priv) atomic_inc(&priv->wmi->mwrite_cnt); } -static void ath9k_disable_regwrite_buffer(void *hw_priv) -{ - struct ath_hw *ah = (struct ath_hw *) hw_priv; - struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; - - atomic_dec(&priv->wmi->mwrite_cnt); -} - static void ath9k_regwrite_flush(void *hw_priv) { struct ath_hw *ah = (struct ath_hw *) hw_priv; @@ -397,6 +388,8 @@ static void ath9k_regwrite_flush(void *hw_priv) u32 rsp_status; int r; + atomic_dec(&priv->wmi->mwrite_cnt); + mutex_lock(&priv->wmi->multi_write_mutex); if (priv->wmi->multi_write_idx) { @@ -420,7 +413,6 @@ static const struct ath_ops ath9k_common_ops = { .read = ath9k_regread, .write = ath9k_regwrite, .enable_write_buffer = ath9k_enable_regwrite_buffer, - .disable_write_buffer = ath9k_disable_regwrite_buffer, .write_flush = ath9k_regwrite_flush, }; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 1b066043d6cb..98c97653c21b 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -299,7 +299,6 @@ static void ath9k_hw_disablepcie(struct ath_hw *ah) REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000); REGWRITE_BUFFER_FLUSH(ah); - DISABLE_REGWRITE_BUFFER(ah); } /* This should work for all families including legacy */ @@ -676,7 +675,6 @@ static void ath9k_hw_init_qos(struct ath_hw *ah) REG_WRITE(ah, AR_TXOP_12_15, 0xFFFFFFFF); REGWRITE_BUFFER_FLUSH(ah); - DISABLE_REGWRITE_BUFFER(ah); } static void ath9k_hw_init_pll(struct ath_hw *ah, @@ -741,7 +739,6 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah, } REGWRITE_BUFFER_FLUSH(ah); - DISABLE_REGWRITE_BUFFER(ah); if (AR_SREV_9300_20_OR_LATER(ah)) { REG_WRITE(ah, AR_INTR_PRIO_ASYNC_ENABLE, 0); @@ -885,7 +882,6 @@ static inline void ath9k_hw_set_dma(struct ath_hw *ah) REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B); REGWRITE_BUFFER_FLUSH(ah); - DISABLE_REGWRITE_BUFFER(ah); /* * Restore TX Trigger Level to its pre-reset value. @@ -933,7 +929,6 @@ static inline void ath9k_hw_set_dma(struct ath_hw *ah) } REGWRITE_BUFFER_FLUSH(ah); - DISABLE_REGWRITE_BUFFER(ah); if (AR_SREV_9300_20_OR_LATER(ah)) ath9k_hw_reset_txstatus_ring(ah); @@ -1031,7 +1026,6 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type) REG_WRITE(ah, AR_RTC_RC, rst_flags); REGWRITE_BUFFER_FLUSH(ah); - DISABLE_REGWRITE_BUFFER(ah); udelay(50); @@ -1070,7 +1064,6 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah) udelay(2); REGWRITE_BUFFER_FLUSH(ah); - DISABLE_REGWRITE_BUFFER(ah); if (!AR_SREV_9300_20_OR_LATER(ah)) udelay(2); @@ -1374,7 +1367,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR); REGWRITE_BUFFER_FLUSH(ah); - DISABLE_REGWRITE_BUFFER(ah); r = ath9k_hw_rf_set_freq(ah, chan); if (r) @@ -1386,7 +1378,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, REG_WRITE(ah, AR_DQCUMASK(i), 1 << i); REGWRITE_BUFFER_FLUSH(ah); - DISABLE_REGWRITE_BUFFER(ah); ah->intr_txqs = 0; for (i = 0; i < ah->caps.total_queues; i++) @@ -1434,7 +1425,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, REG_WRITE(ah, AR_CFG_LED, saveLedState | AR_CFG_SCLK_32KHZ); REGWRITE_BUFFER_FLUSH(ah); - DISABLE_REGWRITE_BUFFER(ah); /* * For big endian systems turn on swapping for descriptors @@ -1684,7 +1674,6 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period) REG_WRITE(ah, AR_NDP_PERIOD, TU_TO_USEC(beacon_period)); REGWRITE_BUFFER_FLUSH(ah); - DISABLE_REGWRITE_BUFFER(ah); beacon_period &= ~ATH9K_BEACON_ENA; if (beacon_period & ATH9K_BEACON_RESET_TSF) { @@ -1712,7 +1701,6 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, TU_TO_USEC(bs->bs_intval & ATH9K_BEACON_PERIOD)); REGWRITE_BUFFER_FLUSH(ah); - DISABLE_REGWRITE_BUFFER(ah); REG_RMW_FIELD(ah, AR_RSSI_THR, AR_RSSI_THR_BM_THR, bs->bs_bmissthreshold); @@ -1758,7 +1746,6 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, REG_WRITE(ah, AR_DTIM_PERIOD, TU_TO_USEC(dtimperiod)); REGWRITE_BUFFER_FLUSH(ah); - DISABLE_REGWRITE_BUFFER(ah); REG_SET_BIT(ah, AR_TIMER_MODE, AR_TBTT_TIMER_EN | AR_TIM_TIMER_EN | @@ -2176,7 +2163,6 @@ void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits) REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_ZLFDMA); REGWRITE_BUFFER_FLUSH(ah); - DISABLE_REGWRITE_BUFFER(ah); } EXPORT_SYMBOL(ath9k_hw_setrxfilter); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 87dbb8502469..d558c51236f9 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -70,19 +70,13 @@ #define ENABLE_REGWRITE_BUFFER(_ah) \ do { \ - if (AR_SREV_9271(_ah)) \ + if (ath9k_hw_common(_ah)->ops->enable_write_buffer) \ ath9k_hw_common(_ah)->ops->enable_write_buffer((_ah)); \ } while (0) -#define DISABLE_REGWRITE_BUFFER(_ah) \ - do { \ - if (AR_SREV_9271(_ah)) \ - ath9k_hw_common(_ah)->ops->disable_write_buffer((_ah)); \ - } while (0) - #define REGWRITE_BUFFER_FLUSH(_ah) \ do { \ - if (AR_SREV_9271(_ah)) \ + if (ath9k_hw_common(_ah)->ops->write_flush) \ ath9k_hw_common(_ah)->ops->write_flush((_ah)); \ } while (0) diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 3efda8a8a3c1..e5784595bd0f 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -40,7 +40,6 @@ static void ath9k_hw_set_txq_interrupts(struct ath_hw *ah, REG_WRITE(ah, AR_IMR_S2, ah->imrs2_reg); REGWRITE_BUFFER_FLUSH(ah); - DISABLE_REGWRITE_BUFFER(ah); } u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q) @@ -530,7 +529,6 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) } REGWRITE_BUFFER_FLUSH(ah); - DISABLE_REGWRITE_BUFFER(ah); if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) { REG_WRITE(ah, AR_DMISC(q), @@ -553,7 +551,6 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) | AR_D_MISC_POST_FR_BKOFF_DIS); REGWRITE_BUFFER_FLUSH(ah); - DISABLE_REGWRITE_BUFFER(ah); /* * cwmin and cwmax should be 0 for beacon queue @@ -585,7 +582,6 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) AR_D_MISC_ARB_LOCKOUT_CNTRL_S)); REGWRITE_BUFFER_FLUSH(ah); - DISABLE_REGWRITE_BUFFER(ah); break; case ATH9K_TX_QUEUE_PSPOLL: -- cgit v1.2.3 From 71ea420992149294e74da3fa34ca8f111326bb6d Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 4 Oct 2010 20:09:46 +0200 Subject: ath9k_hw: add a helper function to check for the new ANI implementation Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ani.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index a1894d240773..9856a1b0ca2d 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -109,6 +109,11 @@ static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah) ath9k_hw_private_ops(ah)->ani_lower_immunity(ah); } +static bool use_new_ani(struct ath_hw *ah) +{ + return AR_SREV_9300_20_OR_LATER(ah) || modparam_force_new_ani; +} + int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah, struct ath9k_channel *chan) { @@ -1178,7 +1183,7 @@ void ath9k_hw_ani_init(struct ath_hw *ah) memset(ah->ani, 0, sizeof(ah->ani)); for (i = 0; i < ARRAY_SIZE(ah->ani); i++) { - if (AR_SREV_9300_20_OR_LATER(ah) || modparam_force_new_ani) { + if (use_new_ani(ah)) { ah->ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH_NEW; ah->ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW_NEW; @@ -1230,7 +1235,7 @@ void ath9k_hw_ani_init(struct ath_hw *ah) * since we expect some ongoing maintenance on the tables, let's sanity * check here default level should not modify INI setting. */ - if (AR_SREV_9300_20_OR_LATER(ah) || modparam_force_new_ani) { + if (use_new_ani(ah)) { const struct ani_ofdm_level_entry *entry_ofdm; const struct ani_cck_level_entry *entry_cck; -- cgit v1.2.3 From 093115b7fd641f03d89404252044c976928764cb Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 4 Oct 2010 20:09:47 +0200 Subject: ath9k_hw: clean up ANI state handling ANI state is kept per channel, so instead of keeping an array of ANI states with an arbitrary size of 255, move the ANI state into the channel struct. Move some config settings that are not per-channel out of the per-channel struct to save some memory. With those changes, ath9k_ani_restart_old and ath9k_ani_restart_new can be merged into a single function. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ani.c | 338 +++++++++------------------- drivers/net/wireless/ath/ath9k/ani.h | 8 +- drivers/net/wireless/ath/ath9k/ar5008_phy.c | 10 +- drivers/net/wireless/ath/ath9k/ar9003_phy.c | 7 +- drivers/net/wireless/ath/ath9k/hw.c | 4 - drivers/net/wireless/ath/ath9k/hw.h | 3 +- 6 files changed, 110 insertions(+), 260 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index 9856a1b0ca2d..6bae601c63a3 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -114,27 +114,6 @@ static bool use_new_ani(struct ath_hw *ah) return AR_SREV_9300_20_OR_LATER(ah) || modparam_force_new_ani; } -int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah, - struct ath9k_channel *chan) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(ah->ani); i++) { - if (ah->ani[i].c && - ah->ani[i].c->channel == chan->channel) - return i; - if (ah->ani[i].c == NULL) { - ah->ani[i].c = chan; - return i; - } - } - - ath_print(ath9k_hw_common(ah), ATH_DBG_ANI, - "No more channel states left. Using channel 0\n"); - - return 0; -} - static void ath9k_hw_update_mibstats(struct ath_hw *ah, struct ath9k_mib_stats *stats) { @@ -145,76 +124,30 @@ static void ath9k_hw_update_mibstats(struct ath_hw *ah, stats->beacons += REG_READ(ah, AR_BEACON_CNT); } -static void ath9k_ani_restart_old(struct ath_hw *ah) +static void ath9k_ani_restart(struct ath_hw *ah) { struct ar5416AniState *aniState; struct ath_common *common = ath9k_hw_common(ah); + u32 ofdm_base = 0, cck_base = 0; if (!DO_ANI(ah)) return; - aniState = ah->curani; + aniState = &ah->curchan->ani; aniState->listenTime = 0; - if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) { - aniState->ofdmPhyErrBase = 0; - ath_print(common, ATH_DBG_ANI, - "OFDM Trigger is too high for hw counters\n"); - } else { - aniState->ofdmPhyErrBase = - AR_PHY_COUNTMAX - aniState->ofdmTrigHigh; + if (!use_new_ani(ah)) { + ofdm_base = AR_PHY_COUNTMAX - ah->config.ofdm_trig_high; + cck_base = AR_PHY_COUNTMAX - ah->config.cck_trig_high; } - if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) { - aniState->cckPhyErrBase = 0; - ath_print(common, ATH_DBG_ANI, - "CCK Trigger is too high for hw counters\n"); - } else { - aniState->cckPhyErrBase = - AR_PHY_COUNTMAX - aniState->cckTrigHigh; - } - ath_print(common, ATH_DBG_ANI, - "Writing ofdmbase=%u cckbase=%u\n", - aniState->ofdmPhyErrBase, - aniState->cckPhyErrBase); - - ENABLE_REGWRITE_BUFFER(ah); - - REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); - REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); - - REGWRITE_BUFFER_FLUSH(ah); - - ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); - - aniState->ofdmPhyErrCount = 0; - aniState->cckPhyErrCount = 0; -} - -static void ath9k_ani_restart_new(struct ath_hw *ah) -{ - struct ar5416AniState *aniState; - struct ath_common *common = ath9k_hw_common(ah); - - if (!DO_ANI(ah)) - return; - - aniState = ah->curani; - aniState->listenTime = 0; - - aniState->ofdmPhyErrBase = 0; - aniState->cckPhyErrBase = 0; ath_print(common, ATH_DBG_ANI, - "Writing ofdmbase=%08x cckbase=%08x\n", - aniState->ofdmPhyErrBase, - aniState->cckPhyErrBase); + "Writing ofdmbase=%u cckbase=%u\n", ofdm_base, cck_base); ENABLE_REGWRITE_BUFFER(ah); - REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_1, ofdm_base); + REG_WRITE(ah, AR_PHY_ERR_2, cck_base); REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); @@ -235,7 +168,7 @@ static void ath9k_hw_ani_ofdm_err_trigger_old(struct ath_hw *ah) if (!DO_ANI(ah)) return; - aniState = ah->curani; + aniState = &ah->curchan->ani; if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) { if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, @@ -307,7 +240,7 @@ static void ath9k_hw_ani_cck_err_trigger_old(struct ath_hw *ah) if (!DO_ANI(ah)) return; - aniState = ah->curani; + aniState = &ah->curchan->ani; if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) { if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, aniState->noiseImmunityLevel + 1)) { @@ -339,7 +272,7 @@ static void ath9k_hw_ani_cck_err_trigger_old(struct ath_hw *ah) /* Adjust the OFDM Noise Immunity Level */ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel) { - struct ar5416AniState *aniState = ah->curani; + struct ar5416AniState *aniState = &ah->curchan->ani; struct ath_common *common = ath9k_hw_common(ah); const struct ani_ofdm_level_entry *entry_ofdm; const struct ani_cck_level_entry *entry_cck; @@ -391,7 +324,7 @@ static void ath9k_hw_ani_ofdm_err_trigger_new(struct ath_hw *ah) if (!DO_ANI(ah)) return; - aniState = ah->curani; + aniState = &ah->curchan->ani; if (aniState->ofdmNoiseImmunityLevel < ATH9K_ANI_OFDM_MAX_LEVEL) ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel + 1); @@ -402,7 +335,7 @@ static void ath9k_hw_ani_ofdm_err_trigger_new(struct ath_hw *ah) */ static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel) { - struct ar5416AniState *aniState = ah->curani; + struct ar5416AniState *aniState = &ah->curchan->ani; struct ath_common *common = ath9k_hw_common(ah); const struct ani_ofdm_level_entry *entry_ofdm; const struct ani_cck_level_entry *entry_cck; @@ -448,7 +381,7 @@ static void ath9k_hw_ani_cck_err_trigger_new(struct ath_hw *ah) if (!DO_ANI(ah)) return; - aniState = ah->curani; + aniState = &ah->curchan->ani; if (aniState->cckNoiseImmunityLevel < ATH9K_ANI_CCK_MAX_LEVEL) ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel + 1); @@ -459,7 +392,7 @@ static void ath9k_hw_ani_lower_immunity_old(struct ath_hw *ah) struct ar5416AniState *aniState; int32_t rssi; - aniState = ah->curani; + aniState = &ah->curchan->ani; if (ah->opmode == NL80211_IFTYPE_AP) { if (aniState->firstepLevel > 0) { @@ -515,7 +448,7 @@ static void ath9k_hw_ani_lower_immunity_new(struct ath_hw *ah) { struct ar5416AniState *aniState; - aniState = ah->curani; + aniState = &ah->curchan->ani; /* lower OFDM noise immunity */ if (aniState->ofdmNoiseImmunityLevel > 0 && @@ -568,16 +501,13 @@ static void ath9k_ani_reset_old(struct ath_hw *ah, bool is_scanning) struct ar5416AniState *aniState; struct ath9k_channel *chan = ah->curchan; struct ath_common *common = ath9k_hw_common(ah); - int index; if (!DO_ANI(ah)) return; - index = ath9k_hw_get_ani_channel_idx(ah, chan); - aniState = &ah->ani[index]; - ah->curani = aniState; + aniState = &ah->curchan->ani; - if (DO_ANI(ah) && ah->opmode != NL80211_IFTYPE_STATION + if (ah->opmode != NL80211_IFTYPE_STATION && ah->opmode != NL80211_IFTYPE_ADHOC) { ath_print(common, ATH_DBG_ANI, "Reset ANI state opmode %u\n", ah->opmode); @@ -606,17 +536,7 @@ static void ath9k_ani_reset_old(struct ath_hw *ah, bool is_scanning) ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) | ATH9K_RX_FILTER_PHYERR); - if (ah->opmode == NL80211_IFTYPE_AP) { - ah->curani->ofdmTrigHigh = - ah->config.ofdm_trig_high; - ah->curani->ofdmTrigLow = - ah->config.ofdm_trig_low; - ah->curani->cckTrigHigh = - ah->config.cck_trig_high; - ah->curani->cckTrigLow = - ah->config.cck_trig_low; - } - ath9k_ani_restart_old(ah); + ath9k_ani_restart(ah); return; } @@ -638,7 +558,7 @@ static void ath9k_ani_reset_old(struct ath_hw *ah, bool is_scanning) ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) & ~ATH9K_RX_FILTER_PHYERR); - ath9k_ani_restart_old(ah); + ath9k_ani_restart(ah); ENABLE_REGWRITE_BUFFER(ah); @@ -655,7 +575,7 @@ static void ath9k_ani_reset_old(struct ath_hw *ah, bool is_scanning) */ static void ath9k_ani_reset_new(struct ath_hw *ah, bool is_scanning) { - struct ar5416AniState *aniState = ah->curani; + struct ar5416AniState *aniState = &ah->curchan->ani; struct ath9k_channel *chan = ah->curchan; struct ath_common *common = ath9k_hw_common(ah); @@ -731,7 +651,7 @@ static void ath9k_ani_reset_new(struct ath_hw *ah, bool is_scanning) * enable phy counters if hw supports or if not, enable phy * interrupts (so we can count each one) */ - ath9k_ani_restart_new(ah); + ath9k_ani_restart(ah); ENABLE_REGWRITE_BUFFER(ah); @@ -749,16 +669,18 @@ static void ath9k_hw_ani_monitor_old(struct ath_hw *ah, int32_t listenTime; u32 phyCnt1, phyCnt2; u32 ofdmPhyErrCnt, cckPhyErrCnt; + u32 ofdm_base = AR_PHY_COUNTMAX - ah->config.ofdm_trig_high; + u32 cck_base = AR_PHY_COUNTMAX - ah->config.cck_trig_high; if (!DO_ANI(ah)) return; - aniState = ah->curani; + aniState = &ah->curchan->ani; listenTime = ath9k_hw_ani_get_listen_time(ah); if (listenTime < 0) { ah->stats.ast_ani_lneg++; - ath9k_ani_restart_old(ah); + ath9k_ani_restart(ah); return; } @@ -769,60 +691,55 @@ static void ath9k_hw_ani_monitor_old(struct ath_hw *ah, phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); - if (phyCnt1 < aniState->ofdmPhyErrBase || - phyCnt2 < aniState->cckPhyErrBase) { - if (phyCnt1 < aniState->ofdmPhyErrBase) { + if (phyCnt1 < ofdm_base || phyCnt2 < cck_base) { + if (phyCnt1 < ofdm_base) { ath_print(common, ATH_DBG_ANI, "phyCnt1 0x%x, resetting " "counter value to 0x%x\n", - phyCnt1, - aniState->ofdmPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_1, - aniState->ofdmPhyErrBase); + phyCnt1, ofdm_base); + REG_WRITE(ah, AR_PHY_ERR_1, ofdm_base); REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); } - if (phyCnt2 < aniState->cckPhyErrBase) { + if (phyCnt2 < cck_base) { ath_print(common, ATH_DBG_ANI, "phyCnt2 0x%x, resetting " "counter value to 0x%x\n", - phyCnt2, - aniState->cckPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_2, - aniState->cckPhyErrBase); + phyCnt2, cck_base); + REG_WRITE(ah, AR_PHY_ERR_2, cck_base); REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); } return; } - ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; + ofdmPhyErrCnt = phyCnt1 - ofdm_base; ah->stats.ast_ani_ofdmerrs += ofdmPhyErrCnt - aniState->ofdmPhyErrCount; aniState->ofdmPhyErrCount = ofdmPhyErrCnt; - cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase; + cckPhyErrCnt = phyCnt2 - cck_base; ah->stats.ast_ani_cckerrs += cckPhyErrCnt - aniState->cckPhyErrCount; aniState->cckPhyErrCount = cckPhyErrCnt; if (aniState->listenTime > 5 * ah->aniperiod) { if (aniState->ofdmPhyErrCount <= aniState->listenTime * - aniState->ofdmTrigLow / 1000 && + ah->config.ofdm_trig_low / 1000 && aniState->cckPhyErrCount <= aniState->listenTime * - aniState->cckTrigLow / 1000) + ah->config.cck_trig_low / 1000) ath9k_hw_ani_lower_immunity(ah); - ath9k_ani_restart_old(ah); + ath9k_ani_restart(ah); } else if (aniState->listenTime > ah->aniperiod) { if (aniState->ofdmPhyErrCount > aniState->listenTime * - aniState->ofdmTrigHigh / 1000) { + ah->config.ofdm_trig_high / 1000) { ath9k_hw_ani_ofdm_err_trigger_old(ah); - ath9k_ani_restart_old(ah); + ath9k_ani_restart(ah); } else if (aniState->cckPhyErrCount > - aniState->listenTime * aniState->cckTrigHigh / + aniState->listenTime * ah->config.cck_trig_high / 1000) { ath9k_hw_ani_cck_err_trigger_old(ah); - ath9k_ani_restart_old(ah); + ath9k_ani_restart(ah); } } } @@ -833,14 +750,13 @@ static void ath9k_hw_ani_monitor_new(struct ath_hw *ah, struct ar5416AniState *aniState; struct ath_common *common = ath9k_hw_common(ah); int32_t listenTime; - u32 phyCnt1, phyCnt2; u32 ofdmPhyErrCnt, cckPhyErrCnt; u32 ofdmPhyErrRate, cckPhyErrRate; if (!DO_ANI(ah)) return; - aniState = ah->curani; + aniState = &ah->curchan->ani; if (WARN_ON(!aniState)) return; @@ -851,7 +767,7 @@ static void ath9k_hw_ani_monitor_new(struct ath_hw *ah, ath_print(common, ATH_DBG_ANI, "listenTime=%d - on new ani monitor\n", listenTime); - ath9k_ani_restart_new(ah); + ath9k_ani_restart(ah); return; } @@ -859,55 +775,20 @@ static void ath9k_hw_ani_monitor_new(struct ath_hw *ah, ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); - phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); - phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); - - if (phyCnt1 < aniState->ofdmPhyErrBase || - phyCnt2 < aniState->cckPhyErrBase) { - if (phyCnt1 < aniState->ofdmPhyErrBase) { - ath_print(common, ATH_DBG_ANI, - "phyCnt1 0x%x, resetting " - "counter value to 0x%x\n", - phyCnt1, - aniState->ofdmPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_1, - aniState->ofdmPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_MASK_1, - AR_PHY_ERR_OFDM_TIMING); - } - if (phyCnt2 < aniState->cckPhyErrBase) { - ath_print(common, ATH_DBG_ANI, - "phyCnt2 0x%x, resetting " - "counter value to 0x%x\n", - phyCnt2, - aniState->cckPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_2, - aniState->cckPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_MASK_2, - AR_PHY_ERR_CCK_TIMING); - } - return; - } + ofdmPhyErrCnt = REG_READ(ah, AR_PHY_ERR_1); + cckPhyErrCnt = REG_READ(ah, AR_PHY_ERR_2); - ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; ah->stats.ast_ani_ofdmerrs += ofdmPhyErrCnt - aniState->ofdmPhyErrCount; aniState->ofdmPhyErrCount = ofdmPhyErrCnt; - cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase; ah->stats.ast_ani_cckerrs += cckPhyErrCnt - aniState->cckPhyErrCount; aniState->cckPhyErrCount = cckPhyErrCnt; ath_print(common, ATH_DBG_ANI, - "Errors: OFDM=0x%08x-0x%08x=%d " - "CCK=0x%08x-0x%08x=%d\n", - phyCnt1, - aniState->ofdmPhyErrBase, - ofdmPhyErrCnt, - phyCnt2, - aniState->cckPhyErrBase, - cckPhyErrCnt); + "Errors: OFDM=%d, CCK=%d\n", + ofdmPhyErrCnt, cckPhyErrCnt); ofdmPhyErrRate = aniState->ofdmPhyErrCount * 1000 / aniState->listenTime; @@ -922,8 +803,8 @@ static void ath9k_hw_ani_monitor_new(struct ath_hw *ah, cckPhyErrRate, aniState->ofdmsTurn); if (aniState->listenTime > 5 * ah->aniperiod) { - if (ofdmPhyErrRate <= aniState->ofdmTrigLow && - cckPhyErrRate <= aniState->cckTrigLow) { + if (ofdmPhyErrRate <= ah->config.ofdm_trig_low && + cckPhyErrRate <= ah->config.cck_trig_low) { ath_print(common, ATH_DBG_ANI, "1. listenTime=%d OFDM:%d errs=%d/s(<%d) " "CCK:%d errs=%d/s(<%d) -> " @@ -931,22 +812,22 @@ static void ath9k_hw_ani_monitor_new(struct ath_hw *ah, aniState->listenTime, aniState->ofdmNoiseImmunityLevel, ofdmPhyErrRate, - aniState->ofdmTrigLow, + ah->config.ofdm_trig_low, aniState->cckNoiseImmunityLevel, cckPhyErrRate, - aniState->cckTrigLow); + ah->config.cck_trig_low); ath9k_hw_ani_lower_immunity(ah); aniState->ofdmsTurn = !aniState->ofdmsTurn; } ath_print(common, ATH_DBG_ANI, "1 listenTime=%d ofdm=%d/s cck=%d/s - " - "calling ath9k_ani_restart_new()\n", + "calling ath9k_ani_restart()\n", aniState->listenTime, ofdmPhyErrRate, cckPhyErrRate); - ath9k_ani_restart_new(ah); + ath9k_ani_restart(ah); } else if (aniState->listenTime > ah->aniperiod) { /* check to see if need to raise immunity */ - if (ofdmPhyErrRate > aniState->ofdmTrigHigh && - (cckPhyErrRate <= aniState->cckTrigHigh || + if (ofdmPhyErrRate > ah->config.ofdm_trig_high && + (cckPhyErrRate <= ah->config.cck_trig_high || aniState->ofdmsTurn)) { ath_print(common, ATH_DBG_ANI, "2 listenTime=%d OFDM:%d errs=%d/s(>%d) -> " @@ -954,20 +835,20 @@ static void ath9k_hw_ani_monitor_new(struct ath_hw *ah, aniState->listenTime, aniState->ofdmNoiseImmunityLevel, ofdmPhyErrRate, - aniState->ofdmTrigHigh); + ah->config.ofdm_trig_high); ath9k_hw_ani_ofdm_err_trigger_new(ah); - ath9k_ani_restart_new(ah); + ath9k_ani_restart(ah); aniState->ofdmsTurn = false; - } else if (cckPhyErrRate > aniState->cckTrigHigh) { + } else if (cckPhyErrRate > ah->config.cck_trig_high) { ath_print(common, ATH_DBG_ANI, "3 listenTime=%d CCK:%d errs=%d/s(>%d) -> " "ath9k_hw_ani_cck_err_trigger_new()\n", aniState->listenTime, aniState->cckNoiseImmunityLevel, cckPhyErrRate, - aniState->cckTrigHigh); + ah->config.cck_trig_high); ath9k_hw_ani_cck_err_trigger_new(ah); - ath9k_ani_restart_new(ah); + ath9k_ani_restart(ah); aniState->ofdmsTurn = true; } } @@ -1064,6 +945,8 @@ skip: */ static void ath9k_hw_proc_mib_event_old(struct ath_hw *ah) { + u32 ofdm_base = AR_PHY_COUNTMAX - ah->config.ofdm_trig_high; + u32 cck_base = AR_PHY_COUNTMAX - ah->config.cck_trig_high; u32 phyCnt1, phyCnt2; /* Reset these counters regardless */ @@ -1090,16 +973,16 @@ static void ath9k_hw_proc_mib_event_old(struct ath_hw *ah) phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) || ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) { - struct ar5416AniState *aniState = ah->curani; + struct ar5416AniState *aniState = &ah->curchan->ani; u32 ofdmPhyErrCnt, cckPhyErrCnt; /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */ - ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; + ofdmPhyErrCnt = phyCnt1 - ofdm_base; ah->stats.ast_ani_ofdmerrs += ofdmPhyErrCnt - aniState->ofdmPhyErrCount; aniState->ofdmPhyErrCount = ofdmPhyErrCnt; - cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase; + cckPhyErrCnt = phyCnt2 - cck_base; ah->stats.ast_ani_cckerrs += cckPhyErrCnt - aniState->cckPhyErrCount; aniState->cckPhyErrCount = cckPhyErrCnt; @@ -1110,12 +993,12 @@ static void ath9k_hw_proc_mib_event_old(struct ath_hw *ah) * clobbers the error counter so the trigger threshold * check will never be true. */ - if (aniState->ofdmPhyErrCount > aniState->ofdmTrigHigh) + if (aniState->ofdmPhyErrCount > ah->config.ofdm_trig_high) ath9k_hw_ani_ofdm_err_trigger_new(ah); - if (aniState->cckPhyErrCount > aniState->cckTrigHigh) + if (aniState->cckPhyErrCount > ah->config.cck_trig_high) ath9k_hw_ani_cck_err_trigger_old(ah); /* NB: always restart to insure the h/w counters are reset */ - ath9k_ani_restart_old(ah); + ath9k_ani_restart(ah); } } @@ -1154,7 +1037,7 @@ static void ath9k_hw_proc_mib_event_new(struct ath_hw *ah) /* NB: always restart to insure the h/w counters are reset */ if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) || ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) - ath9k_ani_restart_new(ah); + ath9k_ani_restart(ah); } void ath9k_hw_ani_setup(struct ath_hw *ah) @@ -1181,54 +1064,51 @@ void ath9k_hw_ani_init(struct ath_hw *ah) ath_print(common, ATH_DBG_ANI, "Initialize ANI\n"); - memset(ah->ani, 0, sizeof(ah->ani)); - for (i = 0; i < ARRAY_SIZE(ah->ani); i++) { - if (use_new_ani(ah)) { - ah->ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH_NEW; - ah->ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW_NEW; + if (use_new_ani(ah)) { + ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_NEW; + ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_NEW; - ah->ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH_NEW; - ah->ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW_NEW; + ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH_NEW; + ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW_NEW; + } else { + ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_OLD; + ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_OLD; - ah->ani[i].spurImmunityLevel = - ATH9K_ANI_SPUR_IMMUNE_LVL_NEW; + ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH_OLD; + ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW_OLD; + } - ah->ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL_NEW; + for (i = 0; i < ARRAY_SIZE(ah->channels); i++) { + struct ath9k_channel *chan = &ah->channels[i]; + struct ar5416AniState *ani = &chan->ani; + + if (use_new_ani(ah)) { + ani->spurImmunityLevel = + ATH9K_ANI_SPUR_IMMUNE_LVL_NEW; - ah->ani[i].ofdmPhyErrBase = 0; - ah->ani[i].cckPhyErrBase = 0; + ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_NEW; if (AR_SREV_9300_20_OR_LATER(ah)) - ah->ani[i].mrcCCKOff = + ani->mrcCCKOff = !ATH9K_ANI_ENABLE_MRC_CCK; else - ah->ani[i].mrcCCKOff = true; + ani->mrcCCKOff = true; - ah->ani[i].ofdmsTurn = true; + ani->ofdmsTurn = true; } else { - ah->ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH_OLD; - ah->ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW_OLD; - - ah->ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH_OLD; - ah->ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW_OLD; - - ah->ani[i].spurImmunityLevel = + ani->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL_OLD; - ah->ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL_OLD; + ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_OLD; - ah->ani[i].ofdmPhyErrBase = - AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH_OLD; - ah->ani[i].cckPhyErrBase = - AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH_OLD; - ah->ani[i].cckWeakSigThreshold = + ani->cckWeakSigThreshold = ATH9K_ANI_CCK_WEAK_SIG_THR; } - ah->ani[i].rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH; - ah->ani[i].rssiThrLow = ATH9K_ANI_RSSI_THR_LOW; - ah->ani[i].ofdmWeakSigDetectOff = + ani->rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH; + ani->rssiThrLow = ATH9K_ANI_RSSI_THR_LOW; + ani->ofdmWeakSigDetectOff = !ATH9K_ANI_USE_OFDM_WEAK_SIG; - ah->ani[i].cckNoiseImmunityLevel = ATH9K_ANI_CCK_DEF_LEVEL; + ani->cckNoiseImmunityLevel = ATH9K_ANI_CCK_DEF_LEVEL; } /* @@ -1249,23 +1129,11 @@ void ath9k_hw_ani_init(struct ath_hw *ah) ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL_OLD; } - ath_print(common, ATH_DBG_ANI, - "Setting OfdmErrBase = 0x%08x\n", - ah->ani[0].ofdmPhyErrBase); - ath_print(common, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n", - ah->ani[0].cckPhyErrBase); - - ENABLE_REGWRITE_BUFFER(ah); - - REG_WRITE(ah, AR_PHY_ERR_1, ah->ani[0].ofdmPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_2, ah->ani[0].cckPhyErrBase); - - REGWRITE_BUFFER_FLUSH(ah); - - ath9k_enable_mib_counters(ah); - if (ah->config.enable_ani) ah->proc_phyerr |= HAL_PROCESS_ANI; + + ath9k_ani_restart(ah); + ath9k_enable_mib_counters(ah); } void ath9k_hw_attach_ani_ops_old(struct ath_hw *ah) diff --git a/drivers/net/wireless/ath/ath9k/ani.h b/drivers/net/wireless/ath/ath9k/ani.h index 15f9d67a18c8..98cfd8154c71 100644 --- a/drivers/net/wireless/ath/ath9k/ani.h +++ b/drivers/net/wireless/ath/ath9k/ani.h @@ -19,7 +19,7 @@ #define HAL_PROCESS_ANI 0x00000001 -#define DO_ANI(ah) (((ah)->proc_phyerr & HAL_PROCESS_ANI)) +#define DO_ANI(ah) (((ah)->proc_phyerr & HAL_PROCESS_ANI) && ah->curchan) #define BEACON_RSSI(ahp) (ahp->stats.avgbrssi) @@ -130,17 +130,11 @@ struct ar5416AniState { u8 ofdmWeakSigDetectOff; u8 cckWeakSigThreshold; u32 listenTime; - u32 ofdmTrigHigh; - u32 ofdmTrigLow; - int32_t cckTrigHigh; - int32_t cckTrigLow; int32_t rssiThrLow; int32_t rssiThrHigh; u32 noiseFloor; u32 ofdmPhyErrCount; u32 cckPhyErrCount; - u32 ofdmPhyErrBase; - u32 cckPhyErrBase; int16_t pktRssi[2]; int16_t ofdmErrRssi[2]; int16_t cckErrRssi[2]; diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index 7b26292daf35..ea9f4497f58c 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -1048,7 +1048,7 @@ static bool ar5008_hw_ani_control_old(struct ath_hw *ah, enum ath9k_ani_cmd cmd, int param) { - struct ar5416AniState *aniState = ah->curani; + struct ar5416AniState *aniState = &ah->curchan->ani; struct ath_common *common = ath9k_hw_common(ah); switch (cmd & ah->ani_function) { @@ -1231,9 +1231,9 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, enum ath9k_ani_cmd cmd, int param) { - struct ar5416AniState *aniState = ah->curani; struct ath_common *common = ath9k_hw_common(ah); struct ath9k_channel *chan = ah->curchan; + struct ar5416AniState *aniState = &chan->ani; s32 value, value2; switch (cmd & ah->ani_function) { @@ -1518,16 +1518,12 @@ static void ar5008_hw_do_getnf(struct ath_hw *ah, */ static void ar5008_hw_ani_cache_ini_regs(struct ath_hw *ah) { - struct ar5416AniState *aniState; struct ath_common *common = ath9k_hw_common(ah); struct ath9k_channel *chan = ah->curchan; + struct ar5416AniState *aniState = &chan->ani; struct ath9k_ani_default *iniDef; - int index; u32 val; - index = ath9k_hw_get_ani_channel_idx(ah, chan); - aniState = &ah->ani[index]; - ah->curani = aniState; iniDef = &aniState->iniDef; ath_print(common, ATH_DBG_ANI, diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index e15574caf61a..efb05599b84c 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -747,9 +747,9 @@ static void ar9003_hw_set_diversity(struct ath_hw *ah, bool value) static bool ar9003_hw_ani_control(struct ath_hw *ah, enum ath9k_ani_cmd cmd, int param) { - struct ar5416AniState *aniState = ah->curani; struct ath_common *common = ath9k_hw_common(ah); struct ath9k_channel *chan = ah->curchan; + struct ar5416AniState *aniState = &chan->ani; s32 value, value2; switch (cmd & ah->ani_function) { @@ -1065,12 +1065,9 @@ static void ar9003_hw_ani_cache_ini_regs(struct ath_hw *ah) struct ath_common *common = ath9k_hw_common(ah); struct ath9k_channel *chan = ah->curchan; struct ath9k_ani_default *iniDef; - int index; u32 val; - index = ath9k_hw_get_ani_channel_idx(ah, chan); - aniState = &ah->ani[index]; - ah->curani = aniState; + aniState = &ah->curchan->ani; iniDef = &aniState->iniDef; ath_print(common, ATH_DBG_ANI, diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 98c97653c21b..05e9935ef160 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -370,10 +370,6 @@ 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.ofdm_trig_low = 200; - ah->config.ofdm_trig_high = 500; - ah->config.cck_trig_high = 200; - ah->config.cck_trig_low = 100; ah->config.enable_ani = true; for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index d558c51236f9..506346384c4f 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -346,6 +346,7 @@ struct ath9k_hw_cal_data { struct ath9k_channel { struct ieee80211_channel *chan; + struct ar5416AniState ani; u16 channel; u32 channelFlags; u32 chanmode; @@ -752,8 +753,6 @@ struct ath_hw { /* ANI */ u32 proc_phyerr; u32 aniperiod; - struct ar5416AniState *curani; - struct ar5416AniState ani[255]; int totalSizeDesired[5]; int coarse_high[5]; int coarse_low[5]; -- cgit v1.2.3 From bfc472bb736bf309158ea76897d255a283d0d31c Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 4 Oct 2010 20:09:48 +0200 Subject: ath9k_hw: remove code duplication in phy error counter handling Split out the PHY error counter update from ath9k_hw_ani_monitor_*, reuse it in ath9k_hw_proc_mib_event (merged from ath9k_hw_proc_mib_event_old and ath9k_hw_proc_mib_event_new). Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ani.c | 142 +++++++------------------------- drivers/net/wireless/ath/ath9k/hw-ops.h | 5 -- drivers/net/wireless/ath/ath9k/hw.h | 4 +- drivers/net/wireless/ath/ath9k/main.c | 2 +- 4 files changed, 34 insertions(+), 119 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index 6bae601c63a3..d5c9df5c4569 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -661,21 +661,15 @@ static void ath9k_ani_reset_new(struct ath_hw *ah, bool is_scanning) REGWRITE_BUFFER_FLUSH(ah); } -static void ath9k_hw_ani_monitor_old(struct ath_hw *ah, - struct ath9k_channel *chan) +static void ath9k_hw_ani_read_counters(struct ath_hw *ah) { - struct ar5416AniState *aniState; struct ath_common *common = ath9k_hw_common(ah); - int32_t listenTime; - u32 phyCnt1, phyCnt2; + struct ar5416AniState *aniState = &ah->curchan->ani; + u32 ofdm_base = 0; + u32 cck_base = 0; u32 ofdmPhyErrCnt, cckPhyErrCnt; - u32 ofdm_base = AR_PHY_COUNTMAX - ah->config.ofdm_trig_high; - u32 cck_base = AR_PHY_COUNTMAX - ah->config.cck_trig_high; - - if (!DO_ANI(ah)) - return; - - aniState = &ah->curchan->ani; + u32 phyCnt1, phyCnt2; + int32_t listenTime; listenTime = ath9k_hw_ani_get_listen_time(ah); if (listenTime < 0) { @@ -684,6 +678,11 @@ static void ath9k_hw_ani_monitor_old(struct ath_hw *ah, return; } + if (!use_new_ani(ah)) { + ofdm_base = AR_PHY_COUNTMAX - ah->config.ofdm_trig_high; + cck_base = AR_PHY_COUNTMAX - ah->config.cck_trig_high; + } + aniState->listenTime += listenTime; ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); @@ -691,7 +690,7 @@ static void ath9k_hw_ani_monitor_old(struct ath_hw *ah, phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); - if (phyCnt1 < ofdm_base || phyCnt2 < cck_base) { + if (use_new_ani(ah) && (phyCnt1 < ofdm_base || phyCnt2 < cck_base)) { if (phyCnt1 < ofdm_base) { ath_print(common, ATH_DBG_ANI, "phyCnt1 0x%x, resetting " @@ -723,6 +722,19 @@ static void ath9k_hw_ani_monitor_old(struct ath_hw *ah, cckPhyErrCnt - aniState->cckPhyErrCount; aniState->cckPhyErrCount = cckPhyErrCnt; +} + +static void ath9k_hw_ani_monitor_old(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + struct ar5416AniState *aniState; + + if (!DO_ANI(ah)) + return; + + aniState = &ah->curchan->ani; + ath9k_hw_ani_read_counters(ah); + if (aniState->listenTime > 5 * ah->aniperiod) { if (aniState->ofdmPhyErrCount <= aniState->listenTime * ah->config.ofdm_trig_low / 1000 && @@ -749,8 +761,6 @@ static void ath9k_hw_ani_monitor_new(struct ath_hw *ah, { struct ar5416AniState *aniState; struct ath_common *common = ath9k_hw_common(ah); - int32_t listenTime; - u32 ofdmPhyErrCnt, cckPhyErrCnt; u32 ofdmPhyErrRate, cckPhyErrRate; if (!DO_ANI(ah)) @@ -760,35 +770,7 @@ static void ath9k_hw_ani_monitor_new(struct ath_hw *ah, if (WARN_ON(!aniState)) return; - listenTime = ath9k_hw_ani_get_listen_time(ah); - if (listenTime <= 0) { - ah->stats.ast_ani_lneg++; - /* restart ANI period if listenTime is invalid */ - ath_print(common, ATH_DBG_ANI, - "listenTime=%d - on new ani monitor\n", - listenTime); - ath9k_ani_restart(ah); - return; - } - - aniState->listenTime += listenTime; - - ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); - - ofdmPhyErrCnt = REG_READ(ah, AR_PHY_ERR_1); - cckPhyErrCnt = REG_READ(ah, AR_PHY_ERR_2); - - ah->stats.ast_ani_ofdmerrs += - ofdmPhyErrCnt - aniState->ofdmPhyErrCount; - aniState->ofdmPhyErrCount = ofdmPhyErrCnt; - - ah->stats.ast_ani_cckerrs += - cckPhyErrCnt - aniState->cckPhyErrCount; - aniState->cckPhyErrCount = cckPhyErrCnt; - - ath_print(common, ATH_DBG_ANI, - "Errors: OFDM=%d, CCK=%d\n", - ofdmPhyErrCnt, cckPhyErrCnt); + ath9k_hw_ani_read_counters(ah); ofdmPhyErrRate = aniState->ofdmPhyErrCount * 1000 / aniState->listenTime; @@ -798,7 +780,8 @@ static void ath9k_hw_ani_monitor_new(struct ath_hw *ah, ath_print(common, ATH_DBG_ANI, "listenTime=%d OFDM:%d errs=%d/s CCK:%d " "errs=%d/s ofdm_turn=%d\n", - listenTime, aniState->ofdmNoiseImmunityLevel, + aniState->listenTime, + aniState->ofdmNoiseImmunityLevel, ofdmPhyErrRate, aniState->cckNoiseImmunityLevel, cckPhyErrRate, aniState->ofdmsTurn); @@ -943,10 +926,8 @@ skip: * any of the MIB counters overflow/trigger so don't assume we're * here because a PHY error counter triggered. */ -static void ath9k_hw_proc_mib_event_old(struct ath_hw *ah) +void ath9k_hw_proc_mib_event(struct ath_hw *ah) { - u32 ofdm_base = AR_PHY_COUNTMAX - ah->config.ofdm_trig_high; - u32 cck_base = AR_PHY_COUNTMAX - ah->config.cck_trig_high; u32 phyCnt1, phyCnt2; /* Reset these counters regardless */ @@ -973,72 +954,15 @@ static void ath9k_hw_proc_mib_event_old(struct ath_hw *ah) phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) || ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) { - struct ar5416AniState *aniState = &ah->curchan->ani; - u32 ofdmPhyErrCnt, cckPhyErrCnt; - - /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */ - ofdmPhyErrCnt = phyCnt1 - ofdm_base; - ah->stats.ast_ani_ofdmerrs += - ofdmPhyErrCnt - aniState->ofdmPhyErrCount; - aniState->ofdmPhyErrCount = ofdmPhyErrCnt; - cckPhyErrCnt = phyCnt2 - cck_base; - ah->stats.ast_ani_cckerrs += - cckPhyErrCnt - aniState->cckPhyErrCount; - aniState->cckPhyErrCount = cckPhyErrCnt; + if (!use_new_ani(ah)) + ath9k_hw_ani_read_counters(ah); - /* - * NB: figure out which counter triggered. If both - * trigger we'll only deal with one as the processing - * clobbers the error counter so the trigger threshold - * check will never be true. - */ - if (aniState->ofdmPhyErrCount > ah->config.ofdm_trig_high) - ath9k_hw_ani_ofdm_err_trigger_new(ah); - if (aniState->cckPhyErrCount > ah->config.cck_trig_high) - ath9k_hw_ani_cck_err_trigger_old(ah); /* NB: always restart to insure the h/w counters are reset */ ath9k_ani_restart(ah); } } - -/* - * Process a MIB interrupt. We may potentially be invoked because - * any of the MIB counters overflow/trigger so don't assume we're - * here because a PHY error counter triggered. - */ -static void ath9k_hw_proc_mib_event_new(struct ath_hw *ah) -{ - u32 phyCnt1, phyCnt2; - - /* Reset these counters regardless */ - REG_WRITE(ah, AR_FILT_OFDM, 0); - REG_WRITE(ah, AR_FILT_CCK, 0); - if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING)) - REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR); - - /* Clear the mib counters and save them in the stats */ - ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); - - if (!DO_ANI(ah)) { - /* - * We must always clear the interrupt cause by - * resetting the phy error regs. - */ - REG_WRITE(ah, AR_PHY_ERR_1, 0); - REG_WRITE(ah, AR_PHY_ERR_2, 0); - return; - } - - /* NB: these are not reset-on-read */ - phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); - phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); - - /* NB: always restart to insure the h/w counters are reset */ - if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) || - ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) - ath9k_ani_restart(ah); -} +EXPORT_SYMBOL(ath9k_hw_proc_mib_event); void ath9k_hw_ani_setup(struct ath_hw *ah) { @@ -1144,7 +1068,6 @@ void ath9k_hw_attach_ani_ops_old(struct ath_hw *ah) priv_ops->ani_reset = ath9k_ani_reset_old; priv_ops->ani_lower_immunity = ath9k_hw_ani_lower_immunity_old; - ops->ani_proc_mib_event = ath9k_hw_proc_mib_event_old; ops->ani_monitor = ath9k_hw_ani_monitor_old; ath_print(ath9k_hw_common(ah), ATH_DBG_ANY, "Using ANI v1\n"); @@ -1158,7 +1081,6 @@ void ath9k_hw_attach_ani_ops_new(struct ath_hw *ah) priv_ops->ani_reset = ath9k_ani_reset_new; priv_ops->ani_lower_immunity = ath9k_hw_ani_lower_immunity_new; - ops->ani_proc_mib_event = ath9k_hw_proc_mib_event_new; ops->ani_monitor = ath9k_hw_ani_monitor_new; ath_print(ath9k_hw_common(ah), ATH_DBG_ANY, "Using ANI v2\n"); diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h index 9c4dd0ec9a15..f42c1980e654 100644 --- a/drivers/net/wireless/ath/ath9k/hw-ops.h +++ b/drivers/net/wireless/ath/ath9k/hw-ops.h @@ -128,11 +128,6 @@ static inline void ath9k_hw_set11n_virtualmorefrag(struct ath_hw *ah, void *ds, ath9k_hw_ops(ah)->set11n_virtualmorefrag(ah, ds, vmf); } -static inline void ath9k_hw_procmibevent(struct ath_hw *ah) -{ - ath9k_hw_ops(ah)->ani_proc_mib_event(ah); -} - static inline void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan) { diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 506346384c4f..a87840bab2ad 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -575,8 +575,6 @@ struct ath_hw_private_ops { * @config_pci_powersave: * @calibrate: periodic calibration for NF, ANI, IQ, ADC gain, ADC-DC * - * @ani_proc_mib_event: process MIB events, this would happen upon specific ANI - * thresholds being reached or having overflowed. * @ani_monitor: called periodically by the core driver to collect * MIB stats and adjust ANI if specific thresholds have been reached. */ @@ -620,7 +618,6 @@ struct ath_hw_ops { void (*set11n_virtualmorefrag)(struct ath_hw *ah, void *ds, u32 vmf); - void (*ani_proc_mib_event)(struct ath_hw *ah); void (*ani_monitor)(struct ath_hw *ah, struct ath9k_channel *chan); }; @@ -980,6 +977,7 @@ void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan); * older families (AR5008, AR9001, AR9002) by using modparam_force_new_ani. */ extern int modparam_force_new_ani; +void ath9k_hw_proc_mib_event(struct ath_hw *ah); void ath9k_hw_attach_ani_ops_old(struct ath_hw *ah); void ath9k_hw_attach_ani_ops_new(struct ath_hw *ah); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index e6ddf45506be..d9c2e2d93136 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -713,7 +713,7 @@ irqreturn_t ath_isr(int irq, void *dev) * it will clear whatever condition caused * the interrupt. */ - ath9k_hw_procmibevent(ah); + ath9k_hw_proc_mib_event(ah); ath9k_hw_set_interrupts(ah, ah->imask); } -- cgit v1.2.3 From 8eb4980c33c35e97a0a226fdbc07e38da0f1f4aa Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 4 Oct 2010 20:09:49 +0200 Subject: ath9k_hw: remove function pointer abstraction for internal ANI ops The code gets more concise and readable when making the new ANI functions fall back to the old ones if ANI v2 is disabled. This also makes further code cleanup easier. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ani.c | 58 ++++++++++++++++----------------- drivers/net/wireless/ath/ath9k/hw-ops.h | 5 --- drivers/net/wireless/ath/ath9k/hw.h | 11 +------ 3 files changed, 29 insertions(+), 45 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index d5c9df5c4569..b9595647810a 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -103,12 +103,6 @@ static const struct ani_cck_level_entry cck_level_table[] = { #define ATH9K_ANI_CCK_DEF_LEVEL \ 2 /* default level - matches the INI settings */ -/* Private to ani.c */ -static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah) -{ - ath9k_hw_private_ops(ah)->ani_lower_immunity(ah); -} - static bool use_new_ani(struct ath_hw *ah) { return AR_SREV_9300_20_OR_LATER(ah) || modparam_force_new_ani; @@ -165,9 +159,6 @@ static void ath9k_hw_ani_ofdm_err_trigger_old(struct ath_hw *ah) struct ar5416AniState *aniState; int32_t rssi; - if (!DO_ANI(ah)) - return; - aniState = &ah->curchan->ani; if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) { @@ -237,9 +228,6 @@ static void ath9k_hw_ani_cck_err_trigger_old(struct ath_hw *ah) struct ar5416AniState *aniState; int32_t rssi; - if (!DO_ANI(ah)) - return; - aniState = &ah->curchan->ani; if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) { if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, @@ -317,13 +305,18 @@ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel) } } -static void ath9k_hw_ani_ofdm_err_trigger_new(struct ath_hw *ah) +static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah) { struct ar5416AniState *aniState; if (!DO_ANI(ah)) return; + if (!use_new_ani(ah)) { + ath9k_hw_ani_ofdm_err_trigger_old(ah); + return; + } + aniState = &ah->curchan->ani; if (aniState->ofdmNoiseImmunityLevel < ATH9K_ANI_OFDM_MAX_LEVEL) @@ -374,13 +367,18 @@ static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel) entry_cck->mrc_cck_on); } -static void ath9k_hw_ani_cck_err_trigger_new(struct ath_hw *ah) +static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah) { struct ar5416AniState *aniState; if (!DO_ANI(ah)) return; + if (!use_new_ani(ah)) { + ath9k_hw_ani_cck_err_trigger_old(ah); + return; + } + aniState = &ah->curchan->ani; if (aniState->cckNoiseImmunityLevel < ATH9K_ANI_CCK_MAX_LEVEL) @@ -444,12 +442,17 @@ static void ath9k_hw_ani_lower_immunity_old(struct ath_hw *ah) * only lower either OFDM or CCK errors per turn * we lower the other one next time */ -static void ath9k_hw_ani_lower_immunity_new(struct ath_hw *ah) +static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah) { struct ar5416AniState *aniState; aniState = &ah->curchan->ani; + if (!use_new_ani(ah)) { + ath9k_hw_ani_lower_immunity_old(ah); + return; + } + /* lower OFDM noise immunity */ if (aniState->ofdmNoiseImmunityLevel > 0 && (aniState->ofdmsTurn || aniState->cckNoiseImmunityLevel == 0)) { @@ -573,7 +576,7 @@ static void ath9k_ani_reset_old(struct ath_hw *ah, bool is_scanning) * This routine should be called for every hardware reset and for * every channel change. */ -static void ath9k_ani_reset_new(struct ath_hw *ah, bool is_scanning) +void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning) { struct ar5416AniState *aniState = &ah->curchan->ani; struct ath9k_channel *chan = ah->curchan; @@ -582,6 +585,9 @@ static void ath9k_ani_reset_new(struct ath_hw *ah, bool is_scanning) if (!DO_ANI(ah)) return; + if (!use_new_ani(ah)) + return ath9k_ani_reset_old(ah, is_scanning); + BUG_ON(aniState == NULL); ah->stats.ast_ani_reset++; @@ -745,12 +751,12 @@ static void ath9k_hw_ani_monitor_old(struct ath_hw *ah, } else if (aniState->listenTime > ah->aniperiod) { if (aniState->ofdmPhyErrCount > aniState->listenTime * ah->config.ofdm_trig_high / 1000) { - ath9k_hw_ani_ofdm_err_trigger_old(ah); + ath9k_hw_ani_ofdm_err_trigger(ah); ath9k_ani_restart(ah); } else if (aniState->cckPhyErrCount > aniState->listenTime * ah->config.cck_trig_high / 1000) { - ath9k_hw_ani_cck_err_trigger_old(ah); + ath9k_hw_ani_cck_err_trigger(ah); ath9k_ani_restart(ah); } } @@ -814,23 +820,23 @@ static void ath9k_hw_ani_monitor_new(struct ath_hw *ah, aniState->ofdmsTurn)) { ath_print(common, ATH_DBG_ANI, "2 listenTime=%d OFDM:%d errs=%d/s(>%d) -> " - "ath9k_hw_ani_ofdm_err_trigger_new()\n", + "ath9k_hw_ani_ofdm_err_trigger()\n", aniState->listenTime, aniState->ofdmNoiseImmunityLevel, ofdmPhyErrRate, ah->config.ofdm_trig_high); - ath9k_hw_ani_ofdm_err_trigger_new(ah); + ath9k_hw_ani_ofdm_err_trigger(ah); ath9k_ani_restart(ah); aniState->ofdmsTurn = false; } else if (cckPhyErrRate > ah->config.cck_trig_high) { ath_print(common, ATH_DBG_ANI, "3 listenTime=%d CCK:%d errs=%d/s(>%d) -> " - "ath9k_hw_ani_cck_err_trigger_new()\n", + "ath9k_hw_ani_cck_err_trigger()\n", aniState->listenTime, aniState->cckNoiseImmunityLevel, cckPhyErrRate, ah->config.cck_trig_high); - ath9k_hw_ani_cck_err_trigger_new(ah); + ath9k_hw_ani_cck_err_trigger(ah); ath9k_ani_restart(ah); aniState->ofdmsTurn = true; } @@ -1062,12 +1068,8 @@ void ath9k_hw_ani_init(struct ath_hw *ah) void ath9k_hw_attach_ani_ops_old(struct ath_hw *ah) { - struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); struct ath_hw_ops *ops = ath9k_hw_ops(ah); - priv_ops->ani_reset = ath9k_ani_reset_old; - priv_ops->ani_lower_immunity = ath9k_hw_ani_lower_immunity_old; - ops->ani_monitor = ath9k_hw_ani_monitor_old; ath_print(ath9k_hw_common(ah), ATH_DBG_ANY, "Using ANI v1\n"); @@ -1075,12 +1077,8 @@ void ath9k_hw_attach_ani_ops_old(struct ath_hw *ah) void ath9k_hw_attach_ani_ops_new(struct ath_hw *ah) { - struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); struct ath_hw_ops *ops = ath9k_hw_ops(ah); - priv_ops->ani_reset = ath9k_ani_reset_new; - priv_ops->ani_lower_immunity = ath9k_hw_ani_lower_immunity_new; - ops->ani_monitor = ath9k_hw_ani_monitor_new; ath_print(ath9k_hw_common(ah), ATH_DBG_ANY, "Using ANI v2\n"); diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h index f42c1980e654..6564d1f0ffb1 100644 --- a/drivers/net/wireless/ath/ath9k/hw-ops.h +++ b/drivers/net/wireless/ath/ath9k/hw-ops.h @@ -271,9 +271,4 @@ static inline void ath9k_hw_setup_calibration(struct ath_hw *ah, ath9k_hw_private_ops(ah)->setup_calibration(ah, currCal); } -static inline void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning) -{ - ath9k_hw_private_ops(ah)->ani_reset(ah, is_scanning); -} - #endif /* ATH9K_HW_OPS_H */ diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index a87840bab2ad..c982a24146d2 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -509,14 +509,6 @@ struct ath_hw_antcomb_conf { * @setup_calibration: set up calibration * @iscal_supported: used to query if a type of calibration is supported * - * @ani_reset: reset ANI parameters to default values - * @ani_lower_immunity: lower the noise immunity level. The level controls - * the power-based packet detection on hardware. If a power jump is - * detected the adapter takes it as an indication that a packet has - * arrived. The level ranges from 0-5. Each level corresponds to a - * few dB more of noise immunity. If you have a strong time-varying - * interference that is causing false detections (OFDM timing errors or - * CCK timing errors) the level can be increased. * @ani_cache_ini_regs: cache the values for ANI from the initial * register settings through the register initialization. */ @@ -561,8 +553,6 @@ struct ath_hw_private_ops { void (*do_getnf)(struct ath_hw *ah, int16_t nfarray[NUM_NF_READINGS]); /* ANI */ - void (*ani_reset)(struct ath_hw *ah, bool is_scanning); - void (*ani_lower_immunity)(struct ath_hw *ah); void (*ani_cache_ini_regs)(struct ath_hw *ah); }; @@ -977,6 +967,7 @@ void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan); * older families (AR5008, AR9001, AR9002) by using modparam_force_new_ani. */ extern int modparam_force_new_ani; +void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning); void ath9k_hw_proc_mib_event(struct ath_hw *ah); void ath9k_hw_attach_ani_ops_old(struct ath_hw *ah); void ath9k_hw_attach_ani_ops_new(struct ath_hw *ah); -- cgit v1.2.3 From 95792178a58716a6afaeb5ab9654f1a0f17a5e8e Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 4 Oct 2010 20:09:50 +0200 Subject: ath9k_hw: merge ath9k_hw_ani_monitor_old and ath9k_hw_ani_monitor_new After the last rounds of cleanup, these functions are now functionally equivalent and can thus be merged. Also get rid of some excessive (and redundant) debug messages. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ani.c | 83 +----------------------------- drivers/net/wireless/ath/ath9k/ar9002_hw.c | 5 -- drivers/net/wireless/ath/ath9k/ar9003_hw.c | 2 - drivers/net/wireless/ath/ath9k/hw-ops.h | 6 --- drivers/net/wireless/ath/ath9k/hw.h | 8 +-- 5 files changed, 3 insertions(+), 101 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index b9595647810a..f2a907b4acb8 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -730,40 +730,7 @@ static void ath9k_hw_ani_read_counters(struct ath_hw *ah) } -static void ath9k_hw_ani_monitor_old(struct ath_hw *ah, - struct ath9k_channel *chan) -{ - struct ar5416AniState *aniState; - - if (!DO_ANI(ah)) - return; - - aniState = &ah->curchan->ani; - ath9k_hw_ani_read_counters(ah); - - if (aniState->listenTime > 5 * ah->aniperiod) { - if (aniState->ofdmPhyErrCount <= aniState->listenTime * - ah->config.ofdm_trig_low / 1000 && - aniState->cckPhyErrCount <= aniState->listenTime * - ah->config.cck_trig_low / 1000) - ath9k_hw_ani_lower_immunity(ah); - ath9k_ani_restart(ah); - } else if (aniState->listenTime > ah->aniperiod) { - if (aniState->ofdmPhyErrCount > aniState->listenTime * - ah->config.ofdm_trig_high / 1000) { - ath9k_hw_ani_ofdm_err_trigger(ah); - ath9k_ani_restart(ah); - } else if (aniState->cckPhyErrCount > - aniState->listenTime * ah->config.cck_trig_high / - 1000) { - ath9k_hw_ani_cck_err_trigger(ah); - ath9k_ani_restart(ah); - } - } -} - -static void ath9k_hw_ani_monitor_new(struct ath_hw *ah, - struct ath9k_channel *chan) +void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan) { struct ar5416AniState *aniState; struct ath_common *common = ath9k_hw_common(ah); @@ -794,54 +761,26 @@ static void ath9k_hw_ani_monitor_new(struct ath_hw *ah, if (aniState->listenTime > 5 * ah->aniperiod) { if (ofdmPhyErrRate <= ah->config.ofdm_trig_low && cckPhyErrRate <= ah->config.cck_trig_low) { - ath_print(common, ATH_DBG_ANI, - "1. listenTime=%d OFDM:%d errs=%d/s(<%d) " - "CCK:%d errs=%d/s(<%d) -> " - "ath9k_hw_ani_lower_immunity()\n", - aniState->listenTime, - aniState->ofdmNoiseImmunityLevel, - ofdmPhyErrRate, - ah->config.ofdm_trig_low, - aniState->cckNoiseImmunityLevel, - cckPhyErrRate, - ah->config.cck_trig_low); ath9k_hw_ani_lower_immunity(ah); aniState->ofdmsTurn = !aniState->ofdmsTurn; } - ath_print(common, ATH_DBG_ANI, - "1 listenTime=%d ofdm=%d/s cck=%d/s - " - "calling ath9k_ani_restart()\n", - aniState->listenTime, ofdmPhyErrRate, cckPhyErrRate); ath9k_ani_restart(ah); } else if (aniState->listenTime > ah->aniperiod) { /* check to see if need to raise immunity */ if (ofdmPhyErrRate > ah->config.ofdm_trig_high && (cckPhyErrRate <= ah->config.cck_trig_high || aniState->ofdmsTurn)) { - ath_print(common, ATH_DBG_ANI, - "2 listenTime=%d OFDM:%d errs=%d/s(>%d) -> " - "ath9k_hw_ani_ofdm_err_trigger()\n", - aniState->listenTime, - aniState->ofdmNoiseImmunityLevel, - ofdmPhyErrRate, - ah->config.ofdm_trig_high); ath9k_hw_ani_ofdm_err_trigger(ah); ath9k_ani_restart(ah); aniState->ofdmsTurn = false; } else if (cckPhyErrRate > ah->config.cck_trig_high) { - ath_print(common, ATH_DBG_ANI, - "3 listenTime=%d CCK:%d errs=%d/s(>%d) -> " - "ath9k_hw_ani_cck_err_trigger()\n", - aniState->listenTime, - aniState->cckNoiseImmunityLevel, - cckPhyErrRate, - ah->config.cck_trig_high); ath9k_hw_ani_cck_err_trigger(ah); ath9k_ani_restart(ah); aniState->ofdmsTurn = true; } } } +EXPORT_SYMBOL(ath9k_hw_ani_monitor); void ath9k_enable_mib_counters(struct ath_hw *ah) { @@ -1065,21 +1004,3 @@ void ath9k_hw_ani_init(struct ath_hw *ah) ath9k_ani_restart(ah); ath9k_enable_mib_counters(ah); } - -void ath9k_hw_attach_ani_ops_old(struct ath_hw *ah) -{ - struct ath_hw_ops *ops = ath9k_hw_ops(ah); - - ops->ani_monitor = ath9k_hw_ani_monitor_old; - - ath_print(ath9k_hw_common(ah), ATH_DBG_ANY, "Using ANI v1\n"); -} - -void ath9k_hw_attach_ani_ops_new(struct ath_hw *ah) -{ - struct ath_hw_ops *ops = ath9k_hw_ops(ah); - - ops->ani_monitor = ath9k_hw_ani_monitor_new; - - ath_print(ath9k_hw_common(ah), ATH_DBG_ANY, "Using ANI v2\n"); -} diff --git a/drivers/net/wireless/ath/ath9k/ar9002_hw.c b/drivers/net/wireless/ath/ath9k/ar9002_hw.c index 78bdf0cec5f0..a0471f2e1c7a 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c @@ -572,11 +572,6 @@ void ar9002_hw_attach_ops(struct ath_hw *ah) ar9002_hw_attach_calib_ops(ah); ar9002_hw_attach_mac_ops(ah); - - if (modparam_force_new_ani) - ath9k_hw_attach_ani_ops_new(ah); - else - ath9k_hw_attach_ani_ops_old(ah); } void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index 064168909108..02c970819f79 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -333,6 +333,4 @@ void ar9003_hw_attach_ops(struct ath_hw *ah) ar9003_hw_attach_phy_ops(ah); ar9003_hw_attach_calib_ops(ah); ar9003_hw_attach_mac_ops(ah); - - ath9k_hw_attach_ani_ops_new(ah); } diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h index 6564d1f0ffb1..0a4ad348b699 100644 --- a/drivers/net/wireless/ath/ath9k/hw-ops.h +++ b/drivers/net/wireless/ath/ath9k/hw-ops.h @@ -128,12 +128,6 @@ static inline void ath9k_hw_set11n_virtualmorefrag(struct ath_hw *ah, void *ds, ath9k_hw_ops(ah)->set11n_virtualmorefrag(ah, ds, vmf); } -static inline void ath9k_hw_ani_monitor(struct ath_hw *ah, - struct ath9k_channel *chan) -{ - ath9k_hw_ops(ah)->ani_monitor(ah, chan); -} - /* Private hardware call ops */ /* PHY ops */ diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index c982a24146d2..87627dd63463 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -564,9 +564,6 @@ struct ath_hw_private_ops { * * @config_pci_powersave: * @calibrate: periodic calibration for NF, ANI, IQ, ADC gain, ADC-DC - * - * @ani_monitor: called periodically by the core driver to collect - * MIB stats and adjust ANI if specific thresholds have been reached. */ struct ath_hw_ops { void (*config_pci_powersave)(struct ath_hw *ah, @@ -607,8 +604,6 @@ struct ath_hw_ops { u32 burstDuration); void (*set11n_virtualmorefrag)(struct ath_hw *ah, void *ds, u32 vmf); - - void (*ani_monitor)(struct ath_hw *ah, struct ath9k_channel *chan); }; struct ath_nf_limits { @@ -969,8 +964,7 @@ void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan); extern int modparam_force_new_ani; void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning); void ath9k_hw_proc_mib_event(struct ath_hw *ah); -void ath9k_hw_attach_ani_ops_old(struct ath_hw *ah); -void ath9k_hw_attach_ani_ops_new(struct ath_hw *ah); +void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan); #define ATH_PCIE_CAP_LINK_CTRL 0x70 #define ATH_PCIE_CAP_LINK_L0S 1 -- cgit v1.2.3 From fbab7390f954e3517c72d12cfd9a1502699aa368 Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Tue, 5 Oct 2010 20:36:40 +0530 Subject: ath9k: remove unnecessary power save flags. drv_config callback is called only after the ack for the nullframe is received and so driver need not do anything special for this. So remove NULLFUNC_COMPLETED, PS_ENABLED flags and bf_isnullfunc flags from ath9k as mac80211 already handles them properly. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 4 ---- drivers/net/wireless/ath/ath9k/main.c | 18 ++++-------------- drivers/net/wireless/ath/ath9k/xmit.c | 30 ------------------------------ 3 files changed, 4 insertions(+), 48 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 9f8e542ef47e..de2b18ee7f77 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -241,7 +241,6 @@ struct ath_buf { dma_addr_t bf_daddr; /* physical addr of desc */ dma_addr_t bf_buf_addr; /* physical addr of data buffer */ bool bf_stale; - bool bf_isnullfunc; bool bf_tx_aborted; u16 bf_flags; struct ath_buf_state bf_state; @@ -349,7 +348,6 @@ int 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 */ @@ -573,8 +571,6 @@ struct ath_ant_comb { #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) struct ath_wiphy; struct ath_rate_table; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index d9c2e2d93136..d0694cb685fa 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1484,7 +1484,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, mutex_unlock(&sc->mutex); } -void ath9k_enable_ps(struct ath_softc *sc) +static void ath9k_enable_ps(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; @@ -1551,20 +1551,10 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) if (changed & IEEE80211_CONF_CHANGE_PS) { unsigned long flags; spin_lock_irqsave(&sc->sc_pm_lock, flags); - if (conf->flags & IEEE80211_CONF_PS) { - sc->ps_flags |= PS_ENABLED; - /* - * 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); - } - } else { + if (conf->flags & IEEE80211_CONF_PS) + ath9k_enable_ps(sc); + else { sc->ps_enabled = false; - sc->ps_flags &= ~(PS_ENABLED | - PS_NULLFUNC_COMPLETED); ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index f7da6b20a925..aa447770eb2b 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1648,13 +1648,6 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf, bf->bf_buf_addr = bf->bf_dmacontext; - /* 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; - } else - bf->bf_isnullfunc = false; - bf->bf_tx_aborted = false; return 0; @@ -2081,18 +2074,6 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) break; } - /* - * We now know the nullfunc frame has been ACKed so we - * can disable RX. - */ - if (bf->bf_isnullfunc && - (ts.ts_status & ATH9K_TX_ACKED)) { - if ((sc->ps_flags & PS_ENABLED)) - ath9k_enable_ps(sc); - else - sc->ps_flags |= PS_NULLFUNC_COMPLETED; - } - /* * Remove ath_buf's of the same transmit unit from txq, * however leave the last descriptor back as the holding @@ -2236,17 +2217,6 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) txok = !(txs.ts_status & ATH9K_TXERR_MASK); - /* - * Make sure null func frame is acked before configuring - * hw into ps mode. - */ - if (bf->bf_isnullfunc && txok) { - if ((sc->ps_flags & PS_ENABLED)) - ath9k_enable_ps(sc); - else - sc->ps_flags |= PS_NULLFUNC_COMPLETED; - } - if (!bf_isampdu(bf)) { if (txs.ts_status & ATH9K_TXERR_XRETRY) bf->bf_state.bf_type |= BUF_XRETRY; -- cgit v1.2.3 From 845d708e62f08a45ff716fdb270c52585cad31d0 Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Tue, 5 Oct 2010 20:36:41 +0530 Subject: ath9k: Introduce a wrapper for power save disable. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 40 +++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index d0694cb685fa..74c2dc8a8b8a 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1498,13 +1498,32 @@ static void ath9k_enable_ps(struct ath_softc *sc) } } +static void ath9k_disable_ps(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + + sc->ps_enabled = false; + ath9k_hw_setpower(ah, ATH9K_PM_AWAKE); + if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { + ath9k_hw_setrxabort(ah, 0); + sc->ps_flags &= ~(PS_WAIT_FOR_BEACON | + PS_WAIT_FOR_CAB | + PS_WAIT_FOR_PSPOLL_DATA | + PS_WAIT_FOR_TX_ACK); + if (ah->imask & ATH9K_INT_TIM_TIMER) { + ah->imask &= ~ATH9K_INT_TIM_TIMER; + ath9k_hw_set_interrupts(ah, ah->imask); + } + } + +} + static int ath9k_config(struct ieee80211_hw *hw, u32 changed) { struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ieee80211_conf *conf = &hw->conf; - struct ath_hw *ah = sc->sc_ah; bool disable_radio; mutex_lock(&sc->mutex); @@ -1553,23 +1572,8 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) spin_lock_irqsave(&sc->sc_pm_lock, flags); if (conf->flags & IEEE80211_CONF_PS) ath9k_enable_ps(sc); - else { - sc->ps_enabled = false; - ath9k_hw_setpower(sc->sc_ah, 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); - if (ah->imask & ATH9K_INT_TIM_TIMER) { - ah->imask &= ~ATH9K_INT_TIM_TIMER; - ath9k_hw_set_interrupts(sc->sc_ah, - ah->imask); - } - } - } + else + ath9k_disable_ps(sc); spin_unlock_irqrestore(&sc->sc_pm_lock, flags); } -- cgit v1.2.3 From 53f73c09d64f1fa7d7e6e8b6bb7468d42eddc92d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 5 Oct 2010 19:37:40 +0200 Subject: mac80211: avoid transmitting delBA to old AP When roaming while we have active BA session, we can end up transmitting delBA frames to the old AP while we're already on the new AP's channel, which can cause warnings. Simply avoid sending those frames, but still tear down the internal session state, since they are not really necessary anyway as we will implicitly disassociate when sending the association to the new AP. Signed-off-by: Johannes Berg Acked-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- net/mac80211/agg-rx.c | 8 ++++---- net/mac80211/agg-tx.c | 14 +++++++++----- net/mac80211/debugfs_sta.c | 3 ++- net/mac80211/ht.c | 17 ++++++++++------- net/mac80211/ieee80211_i.h | 12 +++++++----- net/mac80211/iface.c | 3 ++- net/mac80211/mlme.c | 18 +++++++++--------- net/mac80211/pm.c | 2 +- net/mac80211/sta_info.c | 2 +- net/mac80211/sta_info.h | 2 ++ net/mac80211/util.c | 2 +- 11 files changed, 48 insertions(+), 35 deletions(-) diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index 58eab9e8e4ee..720b7a84af59 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c @@ -56,7 +56,7 @@ static void ieee80211_free_tid_rx(struct rcu_head *h) } void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, - u16 initiator, u16 reason) + u16 initiator, u16 reason, bool tx) { struct ieee80211_local *local = sta->local; struct tid_ampdu_rx *tid_rx; @@ -81,7 +81,7 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, "aggregation for tid %d\n", tid); /* check if this is a self generated aggregation halt */ - if (initiator == WLAN_BACK_RECIPIENT) + if (initiator == WLAN_BACK_RECIPIENT && tx) ieee80211_send_delba(sta->sdata, sta->sta.addr, tid, 0, reason); @@ -92,10 +92,10 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, } void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, - u16 initiator, u16 reason) + u16 initiator, u16 reason, bool tx) { mutex_lock(&sta->ampdu_mlme.mtx); - ___ieee80211_stop_rx_ba_session(sta, tid, initiator, reason); + ___ieee80211_stop_rx_ba_session(sta, tid, initiator, reason, tx); mutex_unlock(&sta->ampdu_mlme.mtx); } diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 8f23401832b7..d4679b265ba8 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -145,7 +145,8 @@ static void kfree_tid_tx(struct rcu_head *rcu_head) } int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, - enum ieee80211_back_parties initiator) + enum ieee80211_back_parties initiator, + bool tx) { struct ieee80211_local *local = sta->local; struct tid_ampdu_tx *tid_tx = sta->ampdu_mlme.tid_tx[tid]; @@ -185,6 +186,7 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, clear_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state); tid_tx->stop_initiator = initiator; + tid_tx->tx_stop = tx; ret = drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_TX_STOP, @@ -577,13 +579,14 @@ void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe); int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, - enum ieee80211_back_parties initiator) + enum ieee80211_back_parties initiator, + bool tx) { int ret; mutex_lock(&sta->ampdu_mlme.mtx); - ret = ___ieee80211_stop_tx_ba_session(sta, tid, initiator); + ret = ___ieee80211_stop_tx_ba_session(sta, tid, initiator, tx); mutex_unlock(&sta->ampdu_mlme.mtx); @@ -672,7 +675,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid) goto unlock_sta; } - if (tid_tx->stop_initiator == WLAN_BACK_INITIATOR) + if (tid_tx->stop_initiator == WLAN_BACK_INITIATOR && tid_tx->tx_stop) ieee80211_send_delba(sta->sdata, ra, tid, WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE); @@ -772,7 +775,8 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, sta->ampdu_mlme.addba_req_num[tid] = 0; } else { - ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR); + ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR, + true); } out: diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 6b7ff9fb4604..50c40ea3cb4d 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -196,7 +196,8 @@ static ssize_t sta_agg_status_write(struct file *file, const char __user *userbu else ret = ieee80211_stop_tx_ba_session(&sta->sta, tid); } else { - __ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT, 3); + __ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT, + 3, true); ret = 0; } diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 11f74f5f7b2f..4214bb6e12fc 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c @@ -101,16 +101,16 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband, ht_cap->mcs.rx_mask[32/8] |= 1; } -void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta) +void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, bool tx) { int i; cancel_work_sync(&sta->ampdu_mlme.work); for (i = 0; i < STA_TID_NUM; i++) { - __ieee80211_stop_tx_ba_session(sta, i, WLAN_BACK_INITIATOR); + __ieee80211_stop_tx_ba_session(sta, i, WLAN_BACK_INITIATOR, tx); __ieee80211_stop_rx_ba_session(sta, i, WLAN_BACK_RECIPIENT, - WLAN_REASON_QSTA_LEAVE_QBSS); + WLAN_REASON_QSTA_LEAVE_QBSS, tx); } } @@ -135,7 +135,7 @@ void ieee80211_ba_session_work(struct work_struct *work) if (test_and_clear_bit(tid, sta->ampdu_mlme.tid_rx_timer_expired)) ___ieee80211_stop_rx_ba_session( sta, tid, WLAN_BACK_RECIPIENT, - WLAN_REASON_QSTA_TIMEOUT); + WLAN_REASON_QSTA_TIMEOUT, true); tid_tx = sta->ampdu_mlme.tid_tx[tid]; if (!tid_tx) @@ -146,7 +146,8 @@ void ieee80211_ba_session_work(struct work_struct *work) else if (test_and_clear_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state)) ___ieee80211_stop_tx_ba_session(sta, tid, - WLAN_BACK_INITIATOR); + WLAN_BACK_INITIATOR, + true); } mutex_unlock(&sta->ampdu_mlme.mtx); } @@ -214,9 +215,11 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, #endif /* CONFIG_MAC80211_HT_DEBUG */ if (initiator == WLAN_BACK_INITIATOR) - __ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_INITIATOR, 0); + __ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_INITIATOR, 0, + true); else - __ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_RECIPIENT); + __ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_RECIPIENT, + true); } int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 08509e212841..76c2b50ec6f8 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1175,10 +1175,10 @@ int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata, void ieee80211_request_smps_work(struct work_struct *work); void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, - u16 initiator, u16 reason); + u16 initiator, u16 reason, bool stop); void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, - u16 initiator, u16 reason); -void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta); + u16 initiator, u16 reason, bool stop); +void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, bool tx); void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, struct sta_info *sta, struct ieee80211_mgmt *mgmt, size_t len); @@ -1192,9 +1192,11 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, size_t len); int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, - enum ieee80211_back_parties initiator); + enum ieee80211_back_parties initiator, + bool tx); int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, - enum ieee80211_back_parties initiator); + enum ieee80211_back_parties initiator, + bool tx); void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid); void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid); void ieee80211_ba_session_work(struct work_struct *work); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 438a2f51420e..e99d1b60557c 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -796,7 +796,8 @@ static void ieee80211_iface_work(struct work_struct *work) __ieee80211_stop_rx_ba_session( sta, tid, WLAN_BACK_RECIPIENT, - WLAN_REASON_QSTA_REQUIRE_SETUP); + WLAN_REASON_QSTA_REQUIRE_SETUP, + true); } mutex_unlock(&local->sta_mtx); } else switch (sdata->vif.type) { diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index cd13aa82f835..5695c94c49aa 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -921,7 +921,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, } static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, - bool remove_sta) + bool remove_sta, bool tx) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; @@ -960,7 +960,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, sta = sta_info_get(sdata, bssid); if (sta) { set_sta_flags(sta, WLAN_STA_BLOCK_BA); - ieee80211_sta_tear_down_BA_sessions(sta); + ieee80211_sta_tear_down_BA_sessions(sta, tx); } mutex_unlock(&local->sta_mtx); @@ -1124,7 +1124,7 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) printk(KERN_DEBUG "Connection to AP %pM lost.\n", bssid); - ieee80211_set_disassoc(sdata, true); + ieee80211_set_disassoc(sdata, true, true); mutex_unlock(&ifmgd->mtx); mutex_lock(&local->mtx); @@ -1197,7 +1197,7 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, printk(KERN_DEBUG "%s: deauthenticated from %pM (Reason: %u)\n", sdata->name, bssid, reason_code); - ieee80211_set_disassoc(sdata, true); + ieee80211_set_disassoc(sdata, true, false); mutex_lock(&sdata->local->mtx); ieee80211_recalc_idle(sdata->local); mutex_unlock(&sdata->local->mtx); @@ -1229,7 +1229,7 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, printk(KERN_DEBUG "%s: disassociated from %pM (Reason: %u)\n", sdata->name, mgmt->sa, reason_code); - ieee80211_set_disassoc(sdata, true); + ieee80211_set_disassoc(sdata, true, false); mutex_lock(&sdata->local->mtx); ieee80211_recalc_idle(sdata->local); mutex_unlock(&sdata->local->mtx); @@ -1880,7 +1880,7 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) printk(KERN_DEBUG "No probe response from AP %pM" " after %dms, disconnecting.\n", bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); - ieee80211_set_disassoc(sdata, true); + ieee80211_set_disassoc(sdata, true, true); mutex_unlock(&ifmgd->mtx); mutex_lock(&local->mtx); ieee80211_recalc_idle(local); @@ -2204,7 +2204,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, } /* Trying to reassociate - clear previous association state */ - ieee80211_set_disassoc(sdata, true); + ieee80211_set_disassoc(sdata, true, false); } mutex_unlock(&ifmgd->mtx); @@ -2318,7 +2318,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, memcpy(bssid, req->bss->bssid, ETH_ALEN); if (ifmgd->associated == req->bss) { - ieee80211_set_disassoc(sdata, false); + ieee80211_set_disassoc(sdata, false, true); mutex_unlock(&ifmgd->mtx); assoc_bss = true; } else { @@ -2401,7 +2401,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, sdata->name, req->bss->bssid, req->reason_code); memcpy(bssid, req->bss->bssid, ETH_ALEN); - ieee80211_set_disassoc(sdata, false); + ieee80211_set_disassoc(sdata, false, true); mutex_unlock(&ifmgd->mtx); diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index ce671dfd238c..e3e2bce3bb41 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c @@ -46,7 +46,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) list_for_each_entry(sta, &local->sta_list, list) { if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { set_sta_flags(sta, WLAN_STA_BLOCK_BA); - ieee80211_sta_tear_down_BA_sessions(sta); + ieee80211_sta_tear_down_BA_sessions(sta, true); } if (sta->uploaded) { diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index ca2cba9cea87..aeaf2d6fccc8 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -633,7 +633,7 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) * will be sufficient. */ set_sta_flags(sta, WLAN_STA_BLOCK_BA); - ieee80211_sta_tear_down_BA_sessions(sta); + ieee80211_sta_tear_down_BA_sessions(sta, true); spin_lock_irqsave(&local->sta_lock, flags); ret = sta_info_hash_del(local, sta); diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 810c5ce98316..cf21a2e8134f 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -79,6 +79,7 @@ enum ieee80211_sta_info_flags { * @dialog_token: dialog token for aggregation session * @state: session state (see above) * @stop_initiator: initiator of a session stop + * @tx_stop: TX DelBA frame when stopping * * This structure is protected by RCU and the per-station * spinlock. Assignments to the array holding it must hold @@ -95,6 +96,7 @@ struct tid_ampdu_tx { unsigned long state; u8 dialog_token; u8 stop_initiator; + bool tx_stop; }; /** diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 4ee8f2b53cb7..0b6fc92bc0d7 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1221,7 +1221,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) mutex_lock(&local->sta_mtx); list_for_each_entry(sta, &local->sta_list, list) { - ieee80211_sta_tear_down_BA_sessions(sta); + ieee80211_sta_tear_down_BA_sessions(sta, true); clear_sta_flags(sta, WLAN_STA_BLOCK_BA); } -- cgit v1.2.3 From e31b82136d1adc7a599b6e99d3321e5831841f5a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 5 Oct 2010 19:39:30 +0200 Subject: cfg80211/mac80211: allow per-station GTKs This adds API to allow adding per-station GTKs, updates mac80211 to support it, and also allows drivers to remove a key from hwaccel again when this may be necessary due to multiple GTKs. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/cfg80211.c | 7 +- drivers/net/wireless/libertas/cfg.c | 4 +- drivers/net/wireless/rndis_wlan.c | 12 ++-- include/linux/nl80211.h | 12 ++++ include/net/cfg80211.h | 9 ++- include/net/mac80211.h | 24 +++++++ net/mac80211/cfg.c | 32 +++++++--- net/mac80211/ieee80211_i.h | 2 - net/mac80211/key.c | 95 ++++++++++++++++++---------- net/mac80211/key.h | 3 + net/mac80211/rx.c | 41 +++++++----- net/mac80211/sta_info.c | 10 +-- net/mac80211/sta_info.h | 6 +- net/mac80211/tx.c | 2 +- net/wireless/core.h | 2 +- net/wireless/ibss.c | 2 +- net/wireless/nl80211.c | 87 ++++++++++++++++++++++--- net/wireless/sme.c | 2 +- net/wireless/util.c | 12 +++- net/wireless/wext-compat.c | 38 +++++++---- 20 files changed, 293 insertions(+), 109 deletions(-) diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index 60619678f4ec..c6c0eff9b5ed 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -161,7 +161,7 @@ static int iwm_key_init(struct iwm_key *key, u8 key_index, } static int iwm_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, - u8 key_index, const u8 *mac_addr, + u8 key_index, bool pairwise, const u8 *mac_addr, struct key_params *params) { struct iwm_priv *iwm = ndev_to_iwm(ndev); @@ -181,7 +181,8 @@ static int iwm_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, } static int iwm_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev, - u8 key_index, const u8 *mac_addr, void *cookie, + u8 key_index, bool pairwise, const u8 *mac_addr, + void *cookie, void (*callback)(void *cookie, struct key_params*)) { @@ -206,7 +207,7 @@ static int iwm_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev, static int iwm_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, - u8 key_index, const u8 *mac_addr) + u8 key_index, bool pairwise, const u8 *mac_addr) { struct iwm_priv *iwm = ndev_to_iwm(ndev); struct iwm_key *key = &iwm->keys[key_index]; diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c index cb3b855d949c..1dc44bc6511f 100644 --- a/drivers/net/wireless/libertas/cfg.c +++ b/drivers/net/wireless/libertas/cfg.c @@ -1438,7 +1438,7 @@ static int lbs_cfg_set_default_key(struct wiphy *wiphy, static int lbs_cfg_add_key(struct wiphy *wiphy, struct net_device *netdev, - u8 idx, const u8 *mac_addr, + u8 idx, bool pairwise, const u8 *mac_addr, struct key_params *params) { struct lbs_private *priv = wiphy_priv(wiphy); @@ -1498,7 +1498,7 @@ static int lbs_cfg_add_key(struct wiphy *wiphy, struct net_device *netdev, static int lbs_cfg_del_key(struct wiphy *wiphy, struct net_device *netdev, - u8 key_index, const u8 *mac_addr) + u8 key_index, bool pairwise, const u8 *mac_addr) { lbs_deb_enter(LBS_DEB_CFG80211); diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 719573bbbf81..71b5971da597 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -540,11 +540,11 @@ static int rndis_set_channel(struct wiphy *wiphy, struct net_device *dev, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type); static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev, - u8 key_index, const u8 *mac_addr, - struct key_params *params); + u8 key_index, bool pairwise, const u8 *mac_addr, + struct key_params *params); static int rndis_del_key(struct wiphy *wiphy, struct net_device *netdev, - u8 key_index, const u8 *mac_addr); + u8 key_index, bool pairwise, const u8 *mac_addr); static int rndis_set_default_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index); @@ -2308,8 +2308,8 @@ static int rndis_set_channel(struct wiphy *wiphy, struct net_device *netdev, } static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev, - u8 key_index, const u8 *mac_addr, - struct key_params *params) + u8 key_index, bool pairwise, const u8 *mac_addr, + struct key_params *params) { struct rndis_wlan_private *priv = wiphy_priv(wiphy); struct usbnet *usbdev = priv->usbdev; @@ -2344,7 +2344,7 @@ static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev, } static int rndis_del_key(struct wiphy *wiphy, struct net_device *netdev, - u8 key_index, const u8 *mac_addr) + u8 key_index, bool pairwise, const u8 *mac_addr) { struct rndis_wlan_private *priv = wiphy_priv(wiphy); struct usbnet *usbdev = priv->usbdev; diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index c4efdfa24ed8..e451f176e662 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -801,6 +801,9 @@ enum nl80211_commands { * This is used in association with @NL80211_ATTR_WIPHY_TX_POWER_SETTING * for non-automatic settings. * + * @NL80211_ATTR_SUPPORT_IBSS_RSN: The device supports IBSS RSN, which mostly + * means support for per-station GTKs. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -968,6 +971,8 @@ enum nl80211_attrs { NL80211_ATTR_CONTROL_PORT_ETHERTYPE, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT, + NL80211_ATTR_SUPPORT_IBSS_RSN, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -1659,11 +1664,14 @@ enum nl80211_auth_type { * @NL80211_KEYTYPE_GROUP: Group (broadcast/multicast) key * @NL80211_KEYTYPE_PAIRWISE: Pairwise (unicast/individual) key * @NL80211_KEYTYPE_PEERKEY: PeerKey (DLS) + * @NUM_NL80211_KEYTYPES: number of defined key types */ enum nl80211_key_type { NL80211_KEYTYPE_GROUP, NL80211_KEYTYPE_PAIRWISE, NL80211_KEYTYPE_PEERKEY, + + NUM_NL80211_KEYTYPES }; /** @@ -1694,6 +1702,9 @@ enum nl80211_wpa_versions { * CCMP keys, each six bytes in little endian * @NL80211_KEY_DEFAULT: flag indicating default key * @NL80211_KEY_DEFAULT_MGMT: flag indicating default management key + * @NL80211_KEY_TYPE: the key type from enum nl80211_key_type, if not + * specified the default depends on whether a MAC address was + * given with the command using the key or not (u32) * @__NL80211_KEY_AFTER_LAST: internal * @NL80211_KEY_MAX: highest key attribute */ @@ -1705,6 +1716,7 @@ enum nl80211_key_attributes { NL80211_KEY_SEQ, NL80211_KEY_DEFAULT, NL80211_KEY_DEFAULT_MGMT, + NL80211_KEY_TYPE, /* keep last */ __NL80211_KEY_AFTER_LAST, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 5f4d8acf7abb..0f77515266b8 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1130,13 +1130,14 @@ struct cfg80211_ops { struct vif_params *params); int (*add_key)(struct wiphy *wiphy, struct net_device *netdev, - u8 key_index, const u8 *mac_addr, + u8 key_index, bool pairwise, const u8 *mac_addr, struct key_params *params); int (*get_key)(struct wiphy *wiphy, struct net_device *netdev, - u8 key_index, const u8 *mac_addr, void *cookie, + u8 key_index, bool pairwise, const u8 *mac_addr, + void *cookie, void (*callback)(void *cookie, struct key_params*)); int (*del_key)(struct wiphy *wiphy, struct net_device *netdev, - u8 key_index, const u8 *mac_addr); + u8 key_index, bool pairwise, const u8 *mac_addr); int (*set_default_key)(struct wiphy *wiphy, struct net_device *netdev, u8 key_index); @@ -1304,6 +1305,7 @@ struct cfg80211_ops { * @WIPHY_FLAG_CONTROL_PORT_PROTOCOL: This device supports setting the * control port protocol ethertype. The device also honours the * control_port_no_encrypt flag. + * @WIPHY_FLAG_IBSS_RSN: The device supports IBSS RSN. */ enum wiphy_flags { WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0), @@ -1314,6 +1316,7 @@ enum wiphy_flags { WIPHY_FLAG_4ADDR_AP = BIT(5), WIPHY_FLAG_4ADDR_STATION = BIT(6), WIPHY_FLAG_CONTROL_PORT_PROTOCOL = BIT(7), + WIPHY_FLAG_IBSS_RSN = BIT(7), }; struct mac_address { diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 47316a653ae1..33aa2e39147b 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1041,6 +1041,13 @@ enum ieee80211_tkip_key_type { * @IEEE80211_HW_NEED_DTIM_PERIOD: * This device needs to know the DTIM period for the BSS before * associating. + * + * @IEEE80211_HW_SUPPORTS_PER_STA_GTK: The device's crypto engine supports + * per-station GTKs as used by IBSS RSN or during fast transition. If + * the device doesn't support per-station GTKs, but can be asked not + * to decrypt group addressed frames, then IBSS RSN support is still + * possible but software crypto will be used. Advertise the wiphy flag + * only in that case. */ enum ieee80211_hw_flags { IEEE80211_HW_HAS_RATE_CONTROL = 1<<0, @@ -1064,6 +1071,7 @@ enum ieee80211_hw_flags { IEEE80211_HW_REPORTS_TX_ACK_STATUS = 1<<18, IEEE80211_HW_CONNECTION_MONITOR = 1<<19, IEEE80211_HW_SUPPORTS_CQM_RSSI = 1<<20, + IEEE80211_HW_SUPPORTS_PER_STA_GTK = 1<<21, }; /** @@ -2582,6 +2590,22 @@ void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success); void ieee80211_request_smps(struct ieee80211_vif *vif, enum ieee80211_smps_mode smps_mode); +/** + * ieee80211_key_removed - disable hw acceleration for key + * @key_conf: The key hw acceleration should be disabled for + * + * This allows drivers to indicate that the given key has been + * removed from hardware acceleration, due to a new key that + * was added. Don't use this if the key can continue to be used + * for TX, if the key restriction is on RX only it is permitted + * to keep the key for TX only and not call this function. + * + * Due to locking constraints, it may only be called during + * @set_key. This function must be allowed to sleep, and the + * key it tries to disable may still be used until it returns. + */ +void ieee80211_key_removed(struct ieee80211_key_conf *key_conf); + /* Rate control API */ /** diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 94bf550bd4c9..8b0e874a3d65 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -103,7 +103,7 @@ static int ieee80211_change_iface(struct wiphy *wiphy, } static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, - u8 key_idx, const u8 *mac_addr, + u8 key_idx, bool pairwise, const u8 *mac_addr, struct key_params *params) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); @@ -131,6 +131,9 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, if (IS_ERR(key)) return PTR_ERR(key); + if (pairwise) + key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE; + mutex_lock(&sdata->local->sta_mtx); if (mac_addr) { @@ -153,7 +156,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, } static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, - u8 key_idx, const u8 *mac_addr) + u8 key_idx, bool pairwise, const u8 *mac_addr) { struct ieee80211_sub_if_data *sdata; struct sta_info *sta; @@ -170,10 +173,17 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, if (!sta) goto out_unlock; - if (sta->key) { - ieee80211_key_free(sdata->local, sta->key); - WARN_ON(sta->key); - ret = 0; + if (pairwise) { + if (sta->ptk) { + ieee80211_key_free(sdata->local, sta->ptk); + ret = 0; + } + } else { + if (sta->gtk[key_idx]) { + ieee80211_key_free(sdata->local, + sta->gtk[key_idx]); + ret = 0; + } } goto out_unlock; @@ -195,7 +205,8 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, } static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, - u8 key_idx, const u8 *mac_addr, void *cookie, + u8 key_idx, bool pairwise, const u8 *mac_addr, + void *cookie, void (*callback)(void *cookie, struct key_params *params)) { @@ -203,7 +214,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, struct sta_info *sta = NULL; u8 seq[6] = {0}; struct key_params params; - struct ieee80211_key *key; + struct ieee80211_key *key = NULL; u32 iv32; u16 iv16; int err = -ENOENT; @@ -217,7 +228,10 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, if (!sta) goto out; - key = sta->key; + if (pairwise) + key = sta->ptk; + else if (key_idx < NUM_DEFAULT_KEYS) + key = sta->gtk[key_idx]; } else key = sdata->keys[key_idx]; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 76c2b50ec6f8..f0610fa4fbe0 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -549,8 +549,6 @@ struct ieee80211_sub_if_data { struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX]; unsigned int fragment_next; -#define NUM_DEFAULT_KEYS 4 -#define NUM_DEFAULT_MGMT_KEYS 2 struct ieee80211_key *keys[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; struct ieee80211_key *default_key; struct ieee80211_key *default_mgmt_key; diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 6a63d1abd14d..ccd676b2f599 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -68,15 +68,21 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) might_sleep(); - if (!key->local->ops->set_key) { - ret = -EOPNOTSUPP; + if (!key->local->ops->set_key) goto out_unsupported; - } assert_key_lock(key->local); sta = get_sta_for_key(key); + /* + * If this is a per-STA GTK, check if it + * is supported; if not, return. + */ + if (sta && !(key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE) && + !(key->local->hw.flags & IEEE80211_HW_SUPPORTS_PER_STA_GTK)) + goto out_unsupported; + sdata = key->sdata; if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) sdata = container_of(sdata->bss, @@ -85,31 +91,28 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) ret = drv_set_key(key->local, SET_KEY, sdata, sta, &key->conf); - if (!ret) + if (!ret) { key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; + return 0; + } - if (ret && ret != -ENOSPC && ret != -EOPNOTSUPP) + if (ret != -ENOSPC && ret != -EOPNOTSUPP) wiphy_err(key->local->hw.wiphy, "failed to set key (%d, %pM) to hardware (%d)\n", key->conf.keyidx, sta ? sta->addr : bcast_addr, ret); -out_unsupported: - if (ret) { - switch (key->conf.cipher) { - case WLAN_CIPHER_SUITE_WEP40: - case WLAN_CIPHER_SUITE_WEP104: - case WLAN_CIPHER_SUITE_TKIP: - case WLAN_CIPHER_SUITE_CCMP: - case WLAN_CIPHER_SUITE_AES_CMAC: - /* all of these we can do in software */ - ret = 0; - break; - default: - ret = -EINVAL; - } + out_unsupported: + switch (key->conf.cipher) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + case WLAN_CIPHER_SUITE_TKIP: + case WLAN_CIPHER_SUITE_CCMP: + case WLAN_CIPHER_SUITE_AES_CMAC: + /* all of these we can do in software */ + return 0; + default: + return -EINVAL; } - - return ret; } static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) @@ -147,6 +150,26 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; } +void ieee80211_key_removed(struct ieee80211_key_conf *key_conf) +{ + struct ieee80211_key *key; + + key = container_of(key_conf, struct ieee80211_key, conf); + + might_sleep(); + assert_key_lock(key->local); + + key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; + + /* + * Flush TX path to avoid attempts to use this key + * after this function returns. Until then, drivers + * must be prepared to handle the key. + */ + synchronize_rcu(); +} +EXPORT_SYMBOL_GPL(ieee80211_key_removed); + static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx) { @@ -202,6 +225,7 @@ void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, struct sta_info *sta, + bool pairwise, struct ieee80211_key *old, struct ieee80211_key *new) { @@ -210,8 +234,14 @@ static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, if (new) list_add(&new->list, &sdata->key_list); - if (sta) { - rcu_assign_pointer(sta->key, new); + if (sta && pairwise) { + rcu_assign_pointer(sta->ptk, new); + } else if (sta) { + if (old) + idx = old->conf.keyidx; + else + idx = new->conf.keyidx; + rcu_assign_pointer(sta->gtk[idx], new); } else { WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx); @@ -355,6 +385,7 @@ int ieee80211_key_link(struct ieee80211_key *key, { struct ieee80211_key *old_key; int idx, ret; + bool pairwise = key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE; BUG_ON(!sdata); BUG_ON(!key); @@ -371,13 +402,6 @@ int ieee80211_key_link(struct ieee80211_key *key, */ if (test_sta_flags(sta, WLAN_STA_WME)) key->conf.flags |= IEEE80211_KEY_FLAG_WMM_STA; - - /* - * This key is for a specific sta interface, - * inform the driver that it should try to store - * this key as pairwise key. - */ - key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE; } else { if (sdata->vif.type == NL80211_IFTYPE_STATION) { struct sta_info *ap; @@ -399,12 +423,14 @@ int ieee80211_key_link(struct ieee80211_key *key, mutex_lock(&sdata->local->key_mtx); - if (sta) - old_key = sta->key; + if (sta && pairwise) + old_key = sta->ptk; + else if (sta) + old_key = sta->gtk[idx]; else old_key = sdata->keys[idx]; - __ieee80211_key_replace(sdata, sta, old_key, key); + __ieee80211_key_replace(sdata, sta, pairwise, old_key, key); __ieee80211_key_destroy(old_key); ieee80211_debugfs_key_add(key); @@ -423,7 +449,8 @@ static void __ieee80211_key_free(struct ieee80211_key *key) */ if (key->sdata) __ieee80211_key_replace(key->sdata, key->sta, - key, NULL); + key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, + key, NULL); __ieee80211_key_destroy(key); } diff --git a/net/mac80211/key.h b/net/mac80211/key.h index cb9a4a65cc68..0db1c0f5f697 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h @@ -16,6 +16,9 @@ #include #include +#define NUM_DEFAULT_KEYS 4 +#define NUM_DEFAULT_MGMT_KEYS 2 + #define WEP_IV_LEN 4 #define WEP_ICV_LEN 4 #define ALG_TKIP_KEY_LEN 32 diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index b3e161ffa4b3..b67221def584 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -846,7 +846,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) int keyidx; int hdrlen; ieee80211_rx_result result = RX_DROP_UNUSABLE; - struct ieee80211_key *stakey = NULL; + struct ieee80211_key *sta_ptk = NULL; int mmie_keyidx = -1; __le16 fc; @@ -888,15 +888,15 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) rx->key = NULL; if (rx->sta) - stakey = rcu_dereference(rx->sta->key); + sta_ptk = rcu_dereference(rx->sta->ptk); fc = hdr->frame_control; if (!ieee80211_has_protected(fc)) mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb); - if (!is_multicast_ether_addr(hdr->addr1) && stakey) { - rx->key = stakey; + if (!is_multicast_ether_addr(hdr->addr1) && sta_ptk) { + rx->key = sta_ptk; if ((status->flag & RX_FLAG_DECRYPTED) && (status->flag & RX_FLAG_IV_STRIPPED)) return RX_CONTINUE; @@ -912,7 +912,10 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) if (mmie_keyidx < NUM_DEFAULT_KEYS || mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) return RX_DROP_MONITOR; /* unexpected BIP keyidx */ - rx->key = rcu_dereference(rx->sdata->keys[mmie_keyidx]); + if (rx->sta) + rx->key = rcu_dereference(rx->sta->gtk[mmie_keyidx]); + if (!rx->key) + rx->key = rcu_dereference(rx->sdata->keys[mmie_keyidx]); } else if (!ieee80211_has_protected(fc)) { /* * The frame was not protected, so skip decryption. However, we @@ -955,17 +958,25 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) skb_copy_bits(rx->skb, hdrlen + 3, &keyid, 1); keyidx = keyid >> 6; - rx->key = rcu_dereference(rx->sdata->keys[keyidx]); + /* check per-station GTK first, if multicast packet */ + if (is_multicast_ether_addr(hdr->addr1) && rx->sta) + rx->key = rcu_dereference(rx->sta->gtk[keyidx]); - /* - * RSNA-protected unicast frames should always be sent with - * pairwise or station-to-station keys, but for WEP we allow - * using a key index as well. - */ - if (rx->key && rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP40 && - rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP104 && - !is_multicast_ether_addr(hdr->addr1)) - rx->key = NULL; + /* if not found, try default key */ + if (!rx->key) { + rx->key = rcu_dereference(rx->sdata->keys[keyidx]); + + /* + * RSNA-protected unicast frames should always be + * sent with pairwise or station-to-station keys, + * but for WEP we allow using a key index as well. + */ + if (rx->key && + rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP40 && + rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP104 && + !is_multicast_ether_addr(hdr->addr1)) + rx->key = NULL; + } } if (rx->key) { diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index aeaf2d6fccc8..6d8f897d8763 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -616,7 +616,7 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) struct ieee80211_sub_if_data *sdata; struct sk_buff *skb; unsigned long flags; - int ret; + int ret, i; might_sleep(); @@ -644,10 +644,10 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) if (ret) return ret; - if (sta->key) { - ieee80211_key_free(local, sta->key); - WARN_ON(sta->key); - } + for (i = 0; i < NUM_DEFAULT_KEYS; i++) + ieee80211_key_free(local, sta->gtk[i]); + if (sta->ptk) + ieee80211_key_free(local, sta->ptk); sta->dead = true; diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index cf21a2e8134f..9265acadef32 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -199,7 +199,8 @@ enum plink_state { * @hnext: hash table linked list pointer * @local: pointer to the global information * @sdata: virtual interface this station belongs to - * @key: peer key negotiated with this station, if any + * @ptk: peer key negotiated with this station, if any + * @gtk: group keys negotiated with this station, if any * @rate_ctrl: rate control algorithm reference * @rate_ctrl_priv: rate control private per-STA pointer * @last_tx_rate: rate used for last transmit, to report to userspace as @@ -254,7 +255,8 @@ struct sta_info { struct sta_info *hnext; struct ieee80211_local *local; struct ieee80211_sub_if_data *sdata; - struct ieee80211_key *key; + struct ieee80211_key *gtk[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; + struct ieee80211_key *ptk; struct rate_control_ref *rate_ctrl; void *rate_ctrl_priv; spinlock_t lock; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 258fbdbedbdf..96c594309506 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -532,7 +532,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) if (unlikely(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT)) tx->key = NULL; - else if (tx->sta && (key = rcu_dereference(tx->sta->key))) + else if (tx->sta && (key = rcu_dereference(tx->sta->ptk))) tx->key = key; else if (ieee80211_is_mgmt(hdr->frame_control) && is_multicast_ether_addr(hdr->addr1) && diff --git a/net/wireless/core.h b/net/wireless/core.h index 37580e090a3d..2d1d4c70113c 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -375,7 +375,7 @@ bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev); /* internal helpers */ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, struct key_params *params, int key_idx, - const u8 *mac_addr); + bool pairwise, const u8 *mac_addr); void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, size_t ie_len, u16 reason, bool from_ap); void cfg80211_sme_scan_done(struct net_device *dev); diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 8cb6e08373b9..f33fbb79437c 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -160,7 +160,7 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext) */ if (rdev->ops->del_key) for (i = 0; i < 6; i++) - rdev->ops->del_key(wdev->wiphy, dev, i, NULL); + rdev->ops->del_key(wdev->wiphy, dev, i, false, NULL); if (wdev->current_bss) { cfg80211_unhold_bss(wdev->current_bss); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 0c9497170f1f..8826888cc14e 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -93,6 +93,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 }, [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG }, [NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 }, + [NL80211_ATTR_KEY_TYPE] = { .type = NLA_U32 }, [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 }, [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 }, @@ -168,7 +169,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { [NL80211_ATTR_FRAME_TYPE] = { .type = NLA_U16 }, }; -/* policy for the attributes */ +/* policy for the key attributes */ static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = { [NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN }, [NL80211_KEY_IDX] = { .type = NLA_U8 }, @@ -176,6 +177,7 @@ static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = { [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 }, [NL80211_KEY_DEFAULT] = { .type = NLA_FLAG }, [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG }, + [NL80211_KEY_TYPE] = { .type = NLA_U32 }, }; /* ifidx get helper */ @@ -306,6 +308,7 @@ static int nl80211_msg_put_channel(struct sk_buff *msg, struct key_parse { struct key_params p; int idx; + int type; bool def, defmgmt; }; @@ -336,6 +339,12 @@ static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k) if (tb[NL80211_KEY_CIPHER]) k->p.cipher = nla_get_u32(tb[NL80211_KEY_CIPHER]); + if (tb[NL80211_KEY_TYPE]) { + k->type = nla_get_u32(tb[NL80211_KEY_TYPE]); + if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES) + return -EINVAL; + } + return 0; } @@ -360,6 +369,12 @@ static int nl80211_parse_key_old(struct genl_info *info, struct key_parse *k) k->def = !!info->attrs[NL80211_ATTR_KEY_DEFAULT]; k->defmgmt = !!info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT]; + if (info->attrs[NL80211_ATTR_KEY_TYPE]) { + k->type = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]); + if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES) + return -EINVAL; + } + return 0; } @@ -369,6 +384,7 @@ static int nl80211_parse_key(struct genl_info *info, struct key_parse *k) memset(k, 0, sizeof(*k)); k->idx = -1; + k->type = -1; if (info->attrs[NL80211_ATTR_KEY]) err = nl80211_parse_key_new(info->attrs[NL80211_ATTR_KEY], k); @@ -433,7 +449,7 @@ nl80211_parse_connkeys(struct cfg80211_registered_device *rdev, } else if (parse.defmgmt) goto error; err = cfg80211_validate_key_settings(rdev, &parse.p, - parse.idx, NULL); + parse.idx, false, NULL); if (err) goto error; result->params[parse.idx].cipher = parse.p.cipher; @@ -516,6 +532,9 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN, dev->wiphy.max_scan_ie_len); + if (dev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) + NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_IBSS_RSN); + NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES, sizeof(u32) * dev->wiphy.n_cipher_suites, dev->wiphy.cipher_suites); @@ -1446,7 +1465,8 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) int err; struct net_device *dev = info->user_ptr[1]; u8 key_idx = 0; - u8 *mac_addr = NULL; + const u8 *mac_addr = NULL; + bool pairwise; struct get_key_cookie cookie = { .error = 0, }; @@ -1462,6 +1482,17 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_MAC]) mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); + pairwise = !!mac_addr; + if (info->attrs[NL80211_ATTR_KEY_TYPE]) { + u32 kt = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]); + if (kt >= NUM_NL80211_KEYTYPES) + return -EINVAL; + if (kt != NL80211_KEYTYPE_GROUP && + kt != NL80211_KEYTYPE_PAIRWISE) + return -EINVAL; + pairwise = kt == NL80211_KEYTYPE_PAIRWISE; + } + if (!rdev->ops->get_key) return -EOPNOTSUPP; @@ -1482,8 +1513,12 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) if (mac_addr) NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); - err = rdev->ops->get_key(&rdev->wiphy, dev, key_idx, mac_addr, - &cookie, get_key_callback); + if (pairwise && mac_addr && + !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) + return -ENOENT; + + err = rdev->ops->get_key(&rdev->wiphy, dev, key_idx, pairwise, + mac_addr, &cookie, get_key_callback); if (err) goto free_msg; @@ -1553,7 +1588,7 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) int err; struct net_device *dev = info->user_ptr[1]; struct key_parse key; - u8 *mac_addr = NULL; + const u8 *mac_addr = NULL; err = nl80211_parse_key(info, &key); if (err) @@ -1565,16 +1600,31 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_MAC]) mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); + if (key.type == -1) { + if (mac_addr) + key.type = NL80211_KEYTYPE_PAIRWISE; + else + key.type = NL80211_KEYTYPE_GROUP; + } + + /* for now */ + if (key.type != NL80211_KEYTYPE_PAIRWISE && + key.type != NL80211_KEYTYPE_GROUP) + return -EINVAL; + if (!rdev->ops->add_key) return -EOPNOTSUPP; - if (cfg80211_validate_key_settings(rdev, &key.p, key.idx, mac_addr)) + if (cfg80211_validate_key_settings(rdev, &key.p, key.idx, + key.type == NL80211_KEYTYPE_PAIRWISE, + mac_addr)) return -EINVAL; wdev_lock(dev->ieee80211_ptr); err = nl80211_key_allowed(dev->ieee80211_ptr); if (!err) err = rdev->ops->add_key(&rdev->wiphy, dev, key.idx, + key.type == NL80211_KEYTYPE_PAIRWISE, mac_addr, &key.p); wdev_unlock(dev->ieee80211_ptr); @@ -1596,13 +1646,32 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_MAC]) mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); + if (key.type == -1) { + if (mac_addr) + key.type = NL80211_KEYTYPE_PAIRWISE; + else + key.type = NL80211_KEYTYPE_GROUP; + } + + /* for now */ + if (key.type != NL80211_KEYTYPE_PAIRWISE && + key.type != NL80211_KEYTYPE_GROUP) + return -EINVAL; + if (!rdev->ops->del_key) return -EOPNOTSUPP; wdev_lock(dev->ieee80211_ptr); err = nl80211_key_allowed(dev->ieee80211_ptr); + + if (key.type == NL80211_KEYTYPE_PAIRWISE && mac_addr && + !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) + err = -ENOENT; + if (!err) - err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, mac_addr); + err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, + key.type == NL80211_KEYTYPE_PAIRWISE, + mac_addr); #ifdef CONFIG_CFG80211_WEXT if (!err) { @@ -3212,6 +3281,8 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) return err; if (key.idx >= 0) { + if (key.type != -1 && key.type != NL80211_KEYTYPE_GROUP) + return -EINVAL; if (!key.p.key || !key.p.key_len) return -EINVAL; if ((key.p.cipher != WLAN_CIPHER_SUITE_WEP40 || diff --git a/net/wireless/sme.c b/net/wireless/sme.c index f161b9844542..e17b0bee6bdc 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -698,7 +698,7 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, */ if (rdev->ops->del_key) for (i = 0; i < 6; i++) - rdev->ops->del_key(wdev->wiphy, dev, i, NULL); + rdev->ops->del_key(wdev->wiphy, dev, i, false, NULL); #ifdef CONFIG_CFG80211_WEXT memset(&wrqu, 0, sizeof(wrqu)); diff --git a/net/wireless/util.c b/net/wireless/util.c index fb5448f7d55a..76120aeda57d 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -144,19 +144,25 @@ void ieee80211_set_bitrate_flags(struct wiphy *wiphy) int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, struct key_params *params, int key_idx, - const u8 *mac_addr) + bool pairwise, const u8 *mac_addr) { int i; if (key_idx > 5) return -EINVAL; + if (!pairwise && mac_addr && !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) + return -EINVAL; + + if (pairwise && !mac_addr) + return -EINVAL; + /* * Disallow pairwise keys with non-zero index unless it's WEP * (because current deployments use pairwise WEP keys with * non-zero indizes but 802.11i clearly specifies to use zero) */ - if (mac_addr && key_idx && + if (pairwise && key_idx && params->cipher != WLAN_CIPHER_SUITE_WEP40 && params->cipher != WLAN_CIPHER_SUITE_WEP104) return -EINVAL; @@ -677,7 +683,7 @@ void cfg80211_upload_connect_keys(struct wireless_dev *wdev) for (i = 0; i < 6; i++) { if (!wdev->connect_keys->params[i].cipher) continue; - if (rdev->ops->add_key(wdev->wiphy, dev, i, NULL, + if (rdev->ops->add_key(wdev->wiphy, dev, i, false, NULL, &wdev->connect_keys->params[i])) { printk(KERN_ERR "%s: failed to set key %d\n", dev->name, i); diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 7e5c3a45f811..6002265289c6 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -432,14 +432,17 @@ int cfg80211_wext_giwretry(struct net_device *dev, EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry); static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, - struct net_device *dev, const u8 *addr, - bool remove, bool tx_key, int idx, - struct key_params *params) + struct net_device *dev, bool pairwise, + const u8 *addr, bool remove, bool tx_key, + int idx, struct key_params *params) { struct wireless_dev *wdev = dev->ieee80211_ptr; int err, i; bool rejoin = false; + if (pairwise && !addr) + return -EINVAL; + if (!wdev->wext.keys) { wdev->wext.keys = kzalloc(sizeof(*wdev->wext.keys), GFP_KERNEL); @@ -478,7 +481,13 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, __cfg80211_leave_ibss(rdev, wdev->netdev, true); rejoin = true; } - err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr); + + if (!pairwise && addr && + !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) + err = -ENOENT; + else + err = rdev->ops->del_key(&rdev->wiphy, dev, idx, + pairwise, addr); } wdev->wext.connect.privacy = false; /* @@ -507,12 +516,13 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, if (addr) tx_key = false; - if (cfg80211_validate_key_settings(rdev, params, idx, addr)) + if (cfg80211_validate_key_settings(rdev, params, idx, pairwise, addr)) return -EINVAL; err = 0; if (wdev->current_bss) - err = rdev->ops->add_key(&rdev->wiphy, dev, idx, addr, params); + err = rdev->ops->add_key(&rdev->wiphy, dev, idx, + pairwise, addr, params); if (err) return err; @@ -563,17 +573,17 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, } static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev, - struct net_device *dev, const u8 *addr, - bool remove, bool tx_key, int idx, - struct key_params *params) + struct net_device *dev, bool pairwise, + const u8 *addr, bool remove, bool tx_key, + int idx, struct key_params *params) { int err; /* devlist mutex needed for possible IBSS re-join */ mutex_lock(&rdev->devlist_mtx); wdev_lock(dev->ieee80211_ptr); - err = __cfg80211_set_encryption(rdev, dev, addr, remove, - tx_key, idx, params); + err = __cfg80211_set_encryption(rdev, dev, pairwise, addr, + remove, tx_key, idx, params); wdev_unlock(dev->ieee80211_ptr); mutex_unlock(&rdev->devlist_mtx); @@ -635,7 +645,7 @@ int cfg80211_wext_siwencode(struct net_device *dev, else if (!remove) return -EINVAL; - return cfg80211_set_encryption(rdev, dev, NULL, remove, + return cfg80211_set_encryption(rdev, dev, false, NULL, remove, wdev->wext.default_key == -1, idx, ¶ms); } @@ -725,7 +735,9 @@ int cfg80211_wext_siwencodeext(struct net_device *dev, } return cfg80211_set_encryption( - rdev, dev, addr, remove, + rdev, dev, + !(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY), + addr, remove, ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, idx, ¶ms); } -- cgit v1.2.3 From d537f5fdfcc9c57c1e3b9fb316a4bed2bf7597e7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 5 Oct 2010 21:34:11 +0200 Subject: nl80211: fix error in generic netif_running check Yikes! The error return keeps a netdev reference and the rdev mutex locked, fix that! Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/nl80211.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 8826888cc14e..9942f0b061ff 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -4418,6 +4418,8 @@ static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, } if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP && !netif_running(dev)) { + cfg80211_unlock_rdev(rdev); + dev_put(dev); if (rtnl) rtnl_unlock(); return -ENETDOWN; -- cgit v1.2.3 From 5e7ee098ce2795e0c2628686dd97fc64bcc11594 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 6 Oct 2010 07:50:06 +0200 Subject: b43: N-PHY: simplify channel switching MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 5f0ce35bbe27..74c32b06efa1 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -73,7 +73,8 @@ 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); -static int nphy_channel_switch(struct b43_wldev *dev, unsigned int channel); +static int b43_nphy_op_switch_channel(struct b43_wldev *dev, + unsigned int new_channel); static inline bool b43_empty_chanspec(struct b43_chanspec *chanspec) { @@ -223,7 +224,7 @@ static void b43_radio_init2055_post(struct b43_wldev *dev) if (i) b43err(dev->wl, "radio post init timeout\n"); b43_radio_mask(dev, B2055_CAL_LPOCTL, 0xFF7F); - nphy_channel_switch(dev, dev->phy.channel); + b43_nphy_op_switch_channel(dev, dev->phy.channel); b43_radio_write(dev, B2055_C1_RX_BB_LPF, 0x9); b43_radio_write(dev, B2055_C2_RX_BB_LPF, 0x9); b43_radio_write(dev, B2055_C1_RX_BB_MIDACHP, 0x83); @@ -3438,18 +3439,6 @@ static int b43_nphy_set_chanspec(struct b43_wldev *dev, return 0; } -/* Tune the hardware to a new channel */ -static int nphy_channel_switch(struct b43_wldev *dev, unsigned int channel) -{ - struct b43_phy_n *nphy = dev->phy.n; - - struct b43_chanspec chanspec; - chanspec = nphy->radio_chanspec; - chanspec.channel = channel; - - return b43_nphy_set_chanspec(dev, chanspec); -} - static int b43_nphy_op_allocate(struct b43_wldev *dev) { struct b43_phy_n *nphy; @@ -3570,7 +3559,7 @@ static void b43_nphy_op_software_rfkill(struct b43_wldev *dev, } else { if (dev->phy.rev >= 3) { b43_radio_init2056(dev); - b43_nphy_set_chanspec(dev, nphy->radio_chanspec); + b43_nphy_op_switch_channel(dev, dev->phy.channel); } else { b43_radio_init2055(dev); } @@ -3586,6 +3575,9 @@ static void b43_nphy_op_switch_analog(struct b43_wldev *dev, bool on) static int b43_nphy_op_switch_channel(struct b43_wldev *dev, unsigned int new_channel) { + struct b43_phy_n *nphy = dev->phy.n; + struct b43_chanspec chanspec; + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { if ((new_channel < 1) || (new_channel > 14)) return -EINVAL; @@ -3594,7 +3586,10 @@ static int b43_nphy_op_switch_channel(struct b43_wldev *dev, return -EINVAL; } - return nphy_channel_switch(dev, new_channel); + chanspec = nphy->radio_chanspec; + chanspec.channel = new_channel; + + return b43_nphy_set_chanspec(dev, chanspec); } static unsigned int b43_nphy_op_get_default_chan(struct b43_wldev *dev) -- cgit v1.2.3 From 106cb09a145a5c6d8e206af41284c300b13c408c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 6 Oct 2010 07:50:07 +0200 Subject: b43: define B43_SHM_SH_CHAN_40MHZ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/b43.h | 3 ++- drivers/net/wireless/b43/phy_common.c | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 8674a99356af..72821c456b02 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -186,7 +186,8 @@ enum { #define B43_SHM_SH_PHYTXNOI 0x006E /* PHY noise directly after TX (lower 8bit only) */ #define B43_SHM_SH_RFRXSP1 0x0072 /* RF RX SP Register 1 */ #define B43_SHM_SH_CHAN 0x00A0 /* Current channel (low 8bit only) */ -#define B43_SHM_SH_CHAN_5GHZ 0x0100 /* Bit set, if 5Ghz channel */ +#define B43_SHM_SH_CHAN_5GHZ 0x0100 /* Bit set, if 5 Ghz channel */ +#define B43_SHM_SH_CHAN_40MHZ 0x0200 /* Bit set, if 40 Mhz channel width */ #define B43_SHM_SH_BCMCFIFOID 0x0108 /* Last posted cookie to the bcast/mcast FIFO */ /* TSSI information */ #define B43_SHM_SH_TSSI_CCK 0x0058 /* TSSI for last 4 CCK frames (32bit) */ diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index 8f7d7eff2d80..7b2ea6781457 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -294,8 +294,10 @@ int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel) */ channelcookie = new_channel; if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) - channelcookie |= 0x100; - //FIXME set 40Mhz flag if required + channelcookie |= B43_SHM_SH_CHAN_5GHZ; + /* FIXME: set 40Mhz flag if required */ + if (0) + channelcookie |= B43_SHM_SH_CHAN_40MHZ; savedcookie = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN); b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN, channelcookie); -- cgit v1.2.3 From 78159788e1d0909ffa6beb714dcca7f3aa4574a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 6 Oct 2010 07:50:08 +0200 Subject: b43: N-PHY: don't duplicate setting channel in shared memory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's already set in PHY common code. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 74c32b06efa1..52ce4383a056 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -73,8 +73,6 @@ 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); -static int b43_nphy_op_switch_channel(struct b43_wldev *dev, - unsigned int new_channel); static inline bool b43_empty_chanspec(struct b43_chanspec *chanspec) { @@ -224,7 +222,7 @@ static void b43_radio_init2055_post(struct b43_wldev *dev) if (i) b43err(dev->wl, "radio post init timeout\n"); b43_radio_mask(dev, B2055_CAL_LPOCTL, 0xFF7F); - b43_nphy_op_switch_channel(dev, dev->phy.channel); + b43_switch_channel(dev, dev->phy.channel); b43_radio_write(dev, B2055_C1_RX_BB_LPF, 0x9); b43_radio_write(dev, B2055_C2_RX_BB_LPF, 0x9); b43_radio_write(dev, B2055_C1_RX_BB_MIDACHP, 0x83); @@ -3352,12 +3350,6 @@ static void b43_nphy_chanspec_setup(struct b43_wldev *dev, b43_chantab_phy_upload(dev, e); - tmp = chanspec.channel; - if (chanspec.b_freq == 1) - tmp |= 0x0100; - if (chanspec.b_width == 3) - tmp |= 0x0200; - b43_shm_write16(dev, B43_SHM_SHARED, 0xA0, tmp); if (nphy->radio_chanspec.channel == 14) { b43_nphy_classifier(dev, 2, 0); @@ -3559,7 +3551,7 @@ static void b43_nphy_op_software_rfkill(struct b43_wldev *dev, } else { if (dev->phy.rev >= 3) { b43_radio_init2056(dev); - b43_nphy_op_switch_channel(dev, dev->phy.channel); + b43_switch_channel(dev, dev->phy.channel); } else { b43_radio_init2055(dev); } -- cgit v1.2.3 From 259b62e35bf44a97983f275de569929a7d2bd5dd Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 6 Oct 2010 11:22:08 +0200 Subject: mac80211: reduce number of __ieee80211_scan_completed calls Use goto instruction to call __ieee80211_scan_completed only ones in ieee80211_scan_work. This is prepare for the next patch. Signed-off-by: Stanislaw Gruszka Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/scan.c | 51 +++++++++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 5171a9581631..830c02bc398a 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -651,27 +651,25 @@ void ieee80211_scan_work(struct work_struct *work) container_of(work, struct ieee80211_local, scan_work.work); struct ieee80211_sub_if_data *sdata = local->scan_sdata; unsigned long next_delay = 0; + bool aborted; - if (test_and_clear_bit(SCAN_COMPLETED, &local->scanning)) { - bool aborted; + mutex_lock(&local->mtx); + if (test_and_clear_bit(SCAN_COMPLETED, &local->scanning)) { aborted = test_and_clear_bit(SCAN_ABORTED, &local->scanning); - __ieee80211_scan_completed(&local->hw, aborted); - return; + goto out_complete; } - mutex_lock(&local->mtx); - if (!sdata || !local->scan_req) { - mutex_unlock(&local->mtx); - return; - } + if (!sdata || !local->scan_req) + goto out; if (local->hw_scan_req) { int rc = drv_hw_scan(local, sdata, local->hw_scan_req); - mutex_unlock(&local->mtx); - if (rc) - __ieee80211_scan_completed(&local->hw, true); - return; + if (rc) { + aborted = true; + goto out_complete; + } else + goto out; } if (local->scan_req && !local->scanning) { @@ -682,23 +680,23 @@ void ieee80211_scan_work(struct work_struct *work) local->scan_sdata = NULL; rc = __ieee80211_start_scan(sdata, req); - mutex_unlock(&local->mtx); - - if (rc) - __ieee80211_scan_completed(&local->hw, true); - return; + if (rc) { + aborted = true; + goto out_complete; + } else + goto out; } - mutex_unlock(&local->mtx); - /* * Avoid re-scheduling when the sdata is going away. */ if (!ieee80211_sdata_running(sdata)) { - __ieee80211_scan_completed(&local->hw, true); - return; + aborted = true; + goto out_complete; } + mutex_unlock(&local->mtx); + /* * as long as no delay is required advance immediately * without scheduling a new work @@ -725,6 +723,15 @@ void ieee80211_scan_work(struct work_struct *work) } while (next_delay == 0); ieee80211_queue_delayed_work(&local->hw, &local->scan_work, next_delay); + return; + +out_complete: + mutex_unlock(&local->mtx); + __ieee80211_scan_completed(&local->hw, aborted); + return; + +out: + mutex_unlock(&local->mtx); } int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, -- cgit v1.2.3 From e229f844d7223b7063bea1e649203ac521a58fe1 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 6 Oct 2010 11:22:09 +0200 Subject: mac80211: keep lock when calling __ieee80211_scan_completed() We are taking local->mtx inside __ieee80211_scan_completed(), but just before call to that function we drop the lock. Dropping/taking lock is not good, because can lead to hard to understand race conditions. Patch split scan_completed() code into two functions, first must be called with local->mtx taken and second without it. Signed-off-by: Stanislaw Gruszka Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/scan.c | 75 ++++++++++++++++++++++++++++------------------------- 1 file changed, 39 insertions(+), 36 deletions(-) diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 830c02bc398a..6964a4598176 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -249,12 +249,12 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) return true; } -static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) +static bool __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted, + bool was_hw_scan) { struct ieee80211_local *local = hw_to_local(hw); - bool was_hw_scan; - mutex_lock(&local->mtx); + lockdep_assert_held(&local->mtx); /* * It's ok to abort a not-yet-running scan (that @@ -265,17 +265,13 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) if (WARN_ON(!local->scanning && !aborted)) aborted = true; - if (WARN_ON(!local->scan_req)) { - mutex_unlock(&local->mtx); - return; - } + if (WARN_ON(!local->scan_req)) + return false; - was_hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning); if (was_hw_scan && !aborted && ieee80211_prep_hw_scan(local)) { ieee80211_queue_delayed_work(&local->hw, &local->scan_work, 0); - mutex_unlock(&local->mtx); - return; + return false; } kfree(local->hw_scan_req); @@ -289,23 +285,25 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) local->scanning = 0; local->scan_channel = NULL; - /* we only have to protect scan_req and hw/sw scan */ - mutex_unlock(&local->mtx); - - ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); - if (was_hw_scan) - goto done; - - ieee80211_configure_filter(local); + return true; +} - drv_sw_scan_complete(local); +static void __ieee80211_scan_completed_finish(struct ieee80211_hw *hw, + bool was_hw_scan) +{ + struct ieee80211_local *local = hw_to_local(hw); - ieee80211_offchannel_return(local, true); + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); + if (!was_hw_scan) { + ieee80211_configure_filter(local); + drv_sw_scan_complete(local); + ieee80211_offchannel_return(local, true); + } - done: mutex_lock(&local->mtx); ieee80211_recalc_idle(local); mutex_unlock(&local->mtx); + ieee80211_mlme_notify_scan_completed(local); ieee80211_ibss_notify_scan_completed(local); ieee80211_mesh_notify_scan_completed(local); @@ -366,6 +364,8 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, struct ieee80211_local *local = sdata->local; int rc; + lockdep_assert_held(&local->mtx); + if (local->scan_req) return -EBUSY; @@ -447,8 +447,8 @@ ieee80211_scan_get_channel_time(struct ieee80211_channel *chan) return IEEE80211_PROBE_DELAY + IEEE80211_CHANNEL_TIME; } -static int ieee80211_scan_state_decision(struct ieee80211_local *local, - unsigned long *next_delay) +static void ieee80211_scan_state_decision(struct ieee80211_local *local, + unsigned long *next_delay) { bool associated = false; bool tx_empty = true; @@ -458,12 +458,6 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata; struct ieee80211_channel *next_chan; - /* if no more bands/channels left, complete scan and advance to the idle state */ - if (local->scan_channel_idx >= local->scan_req->n_channels) { - __ieee80211_scan_completed(&local->hw, false); - return 1; - } - /* * check if at least one STA interface is associated, * check if at least one STA interface has pending tx frames @@ -535,7 +529,6 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local, } *next_delay = 0; - return 0; } static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *local, @@ -651,7 +644,7 @@ void ieee80211_scan_work(struct work_struct *work) container_of(work, struct ieee80211_local, scan_work.work); struct ieee80211_sub_if_data *sdata = local->scan_sdata; unsigned long next_delay = 0; - bool aborted; + bool aborted, hw_scan, finish; mutex_lock(&local->mtx); @@ -704,8 +697,12 @@ void ieee80211_scan_work(struct work_struct *work) do { switch (local->next_scan_state) { case SCAN_DECISION: - if (ieee80211_scan_state_decision(local, &next_delay)) - return; + /* if no more bands/channels left, complete scan */ + if (local->scan_channel_idx >= local->scan_req->n_channels) { + aborted = false; + goto out_complete; + } + ieee80211_scan_state_decision(local, &next_delay); break; case SCAN_SET_CHANNEL: ieee80211_scan_state_set_channel(local, &next_delay); @@ -726,8 +723,11 @@ void ieee80211_scan_work(struct work_struct *work) return; out_complete: + hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning); + finish = __ieee80211_scan_completed(&local->hw, aborted, hw_scan); mutex_unlock(&local->mtx); - __ieee80211_scan_completed(&local->hw, aborted); + if (finish) + __ieee80211_scan_completed_finish(&local->hw, hw_scan); return; out: @@ -796,6 +796,7 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata, void ieee80211_scan_cancel(struct ieee80211_local *local) { bool abortscan; + bool finish = false; cancel_delayed_work_sync(&local->scan_work); @@ -806,8 +807,10 @@ void ieee80211_scan_cancel(struct ieee80211_local *local) mutex_lock(&local->mtx); abortscan = test_bit(SCAN_SW_SCANNING, &local->scanning) || (!local->scanning && local->scan_req); + if (abortscan) + finish = __ieee80211_scan_completed(&local->hw, true, false); mutex_unlock(&local->mtx); - if (abortscan) - __ieee80211_scan_completed(&local->hw, true); + if (finish) + __ieee80211_scan_completed_finish(&local->hw, false); } -- cgit v1.2.3 From 4136c4224ccf1907d309e1cdfaefef9da97dbc5e Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 6 Oct 2010 11:22:10 +0200 Subject: mac80211: assure we also cancel deferred scan request This is partial revert and fix for commit 85f72bc839705294b32b6c16b491c0422f0a71b3 "mac80211: only cancel software-based scans on suspend" When cfg80211 request the scan and mac80211 perform some management work, we defer the scan request. We do not canceling such requests when calling ieee80211_scan_cancel(), because of SCAN_SW_SCANNING bit check just before the call. So fix that problem. Another problem, which commit 85f72bc839705294b32b6c16b491c0422f0a71b3 tries to solve, is we can not cancel HW scan. Hence patch make ieee80211_scan_cancel() ignore HW scan (see code comments). Keeping local->mtx lock assures that the deferred scan will not become "working" HW scan. Signed-off-by: Stanislaw Gruszka Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/main.c | 3 +-- net/mac80211/pm.c | 3 +-- net/mac80211/scan.c | 35 +++++++++++++++++++++++++---------- 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/net/mac80211/main.c b/net/mac80211/main.c index e3717092115f..915ecf87e4ac 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -307,8 +307,7 @@ static void ieee80211_restart_work(struct work_struct *work) mutex_unlock(&local->mtx); rtnl_lock(); - if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning))) - ieee80211_scan_cancel(local); + ieee80211_scan_cancel(local); ieee80211_reconfig(local); rtnl_unlock(); } diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index e3e2bce3bb41..e37355193ed1 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c @@ -12,8 +12,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) struct ieee80211_sub_if_data *sdata; struct sta_info *sta; - if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning))) - ieee80211_scan_cancel(local); + ieee80211_scan_cancel(local); ieee80211_stop_queues_by_reason(hw, IEEE80211_QUEUE_STOP_REASON_SUSPEND); diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 6964a4598176..4dbef714d946 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -793,24 +793,39 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata, return ret; } +/* + * Only call this function when a scan can't be queued -- under RTNL. + */ void ieee80211_scan_cancel(struct ieee80211_local *local) { - bool abortscan; - bool finish = false; - - cancel_delayed_work_sync(&local->scan_work); + bool abortscan, finish; /* - * Only call this function when a scan can't be - * queued -- mostly at suspend under RTNL. + * We are only canceling software scan, or deferred scan that was not + * yet really started (see __ieee80211_start_scan ). + * + * Regarding hardware scan: + * - we can not call __ieee80211_scan_completed() as when + * SCAN_HW_SCANNING bit is set this function change + * local->hw_scan_req to operate on 5G band, what race with + * driver which can use local->hw_scan_req + * + * - we can not cancel scan_work since driver can schedule it + * by ieee80211_scan_completed(..., true) to finish scan + * + * Hence low lever driver is responsible for canceling HW scan. */ + mutex_lock(&local->mtx); - abortscan = test_bit(SCAN_SW_SCANNING, &local->scanning) || - (!local->scanning && local->scan_req); + abortscan = local->scan_req && !test_bit(SCAN_HW_SCANNING, &local->scanning); if (abortscan) finish = __ieee80211_scan_completed(&local->hw, true, false); mutex_unlock(&local->mtx); - if (finish) - __ieee80211_scan_completed_finish(&local->hw, false); + if (abortscan) { + /* The scan is canceled, but stop work from being pending */ + cancel_delayed_work_sync(&local->scan_work); + if (finish) + __ieee80211_scan_completed_finish(&local->hw, false); + } } -- cgit v1.2.3 From 6eb11a9a311a0f7e5b9b66c18f7498a26c9ec206 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 6 Oct 2010 11:22:11 +0200 Subject: mac80211: do not requeue scan work when not needed When performing hw scan and not abort it, __ieee80211_scan_completed() is currently called from scan work, so does not need to reschedule work to call drv_hw_scan(). Signed-off-by: Stanislaw Gruszka Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/scan.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 4dbef714d946..9aab921f7ca8 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -269,9 +269,9 @@ static bool __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted, return false; if (was_hw_scan && !aborted && ieee80211_prep_hw_scan(local)) { - ieee80211_queue_delayed_work(&local->hw, - &local->scan_work, 0); - return false; + int rc = drv_hw_scan(local, local->scan_sdata, local->hw_scan_req); + if (rc == 0) + return false; } kfree(local->hw_scan_req); @@ -656,15 +656,6 @@ void ieee80211_scan_work(struct work_struct *work) if (!sdata || !local->scan_req) goto out; - if (local->hw_scan_req) { - int rc = drv_hw_scan(local, sdata, local->hw_scan_req); - if (rc) { - aborted = true; - goto out_complete; - } else - goto out; - } - if (local->scan_req && !local->scanning) { struct cfg80211_scan_request *req = local->scan_req; int rc; -- cgit v1.2.3 From 3aed49ef17c7bc8397420529ac976fe058818e3d Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 6 Oct 2010 11:22:12 +0200 Subject: mac80211: compete scan to cfg80211 if deferred scan fail to start We nulify local->scan_req on failure in __ieee80211_start_scan, so __ieee80211_scan_completed will not call cfg80211_scan_done. Fix that. Signed-off-by: Stanislaw Gruszka Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/scan.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 9aab921f7ca8..80e017df5f31 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -665,6 +665,8 @@ void ieee80211_scan_work(struct work_struct *work) rc = __ieee80211_start_scan(sdata, req); if (rc) { + /* need to complete scan in cfg80211 */ + local->scan_req = req; aborted = true; goto out_complete; } else -- cgit v1.2.3 From 09be251e9005ebd67e5eabcaad904edb7ecacc55 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 6 Oct 2010 11:22:13 +0200 Subject: Revert "iwlwifi: do not perferm force reset while doing scan" This reverts commit 7acc7c683a747689aaaaad4fce1683fc3f85e552. It was applied to avoid possible warning in ieee80211_restart_hw, however reason of the warning were races in mac80211, currently hopefully fixed. Not reseting device when performing scan is bad for two reasons. When forcing reset from iwl_check_stuck_queue(), in case of fail, reset will be repeated until scan finish. But since firmware is in bad shape, scan only finish after scan_check work (about 7s). So we will delay the reset, what is not good behaviour. When forcing reset from iwl_recover_from_statistics(), we will not repeat the reset, so we will not perform reset at all when needed. Signed-off-by: Stanislaw Gruszka Acked-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index b7adcf87280d..3532e1dadf10 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2737,11 +2737,6 @@ int iwl_force_reset(struct iwl_priv *priv, int mode, bool external) if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return -EINVAL; - if (test_bit(STATUS_SCANNING, &priv->status)) { - IWL_DEBUG_INFO(priv, "scan in progress.\n"); - return -EINVAL; - } - if (mode >= IWL_MAX_FORCE_RESET) { IWL_DEBUG_INFO(priv, "invalid reset request.\n"); return -EINVAL; -- cgit v1.2.3 From b206b4ef062d83c0875a085672ed50e8c8b01521 Mon Sep 17 00:00:00 2001 From: Bruno Randolf Date: Wed, 6 Oct 2010 18:34:12 +0900 Subject: nl80211/mac80211: Add retry and failed transmission count to station info This information is already available in mac80211, we just need to export it via cfg80211 and nl80211. Signed-off-by: Bruno Randolf Acked-by: Johannes Berg Signed-off-by: John W. Linville --- include/linux/nl80211.h | 4 ++++ include/net/cfg80211.h | 8 ++++++++ net/mac80211/cfg.c | 4 ++++ net/wireless/nl80211.c | 6 ++++++ 4 files changed, 22 insertions(+) diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index e451f176e662..c08709fe36fc 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -1137,6 +1137,8 @@ enum nl80211_rate_info { * @NL80211_STA_INFO_RX_PACKETS: total received packet (u32, from this station) * @NL80211_STA_INFO_TX_PACKETS: total transmitted packets (u32, to this * station) + * @NL80211_STA_INFO_TX_RETRIES: total retries (u32, to this station) + * @NL80211_STA_INFO_TX_FAILED: total failed packets (u32, to this station) */ enum nl80211_sta_info { __NL80211_STA_INFO_INVALID, @@ -1150,6 +1152,8 @@ enum nl80211_sta_info { NL80211_STA_INFO_TX_BITRATE, NL80211_STA_INFO_RX_PACKETS, NL80211_STA_INFO_TX_PACKETS, + NL80211_STA_INFO_TX_RETRIES, + NL80211_STA_INFO_TX_FAILED, /* keep last */ __NL80211_STA_INFO_AFTER_LAST, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 0f77515266b8..e76daaa7dc25 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -401,6 +401,8 @@ struct station_parameters { * (tx_bitrate, tx_bitrate_flags and tx_bitrate_mcs) * @STATION_INFO_RX_PACKETS: @rx_packets filled * @STATION_INFO_TX_PACKETS: @tx_packets filled + * @STATION_INFO_TX_RETRIES: @tx_retries filled + * @STATION_INFO_TX_FAILED: @tx_failed filled */ enum station_info_flags { STATION_INFO_INACTIVE_TIME = 1<<0, @@ -413,6 +415,8 @@ enum station_info_flags { STATION_INFO_TX_BITRATE = 1<<7, STATION_INFO_RX_PACKETS = 1<<8, STATION_INFO_TX_PACKETS = 1<<9, + STATION_INFO_TX_RETRIES = 1<<10, + STATION_INFO_TX_FAILED = 1<<11, }; /** @@ -462,6 +466,8 @@ struct rate_info { * @txrate: current unicast bitrate to this station * @rx_packets: packets received from this station * @tx_packets: packets transmitted to this station + * @tx_retries: cumulative retry counts + * @tx_failed: number of failed transmissions (retries exceeded, no ACK) * @generation: generation number for nl80211 dumps. * This number should increase every time the list of stations * changes, i.e. when a station is added or removed, so that @@ -479,6 +485,8 @@ struct station_info { struct rate_info txrate; u32 rx_packets; u32 tx_packets; + u32 tx_retries; + u32 tx_failed; int generation; }; diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 8b0e874a3d65..2e5a3fb38efe 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -327,6 +327,8 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) STATION_INFO_TX_BYTES | STATION_INFO_RX_PACKETS | STATION_INFO_TX_PACKETS | + STATION_INFO_TX_RETRIES | + STATION_INFO_TX_FAILED | STATION_INFO_TX_BITRATE; sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); @@ -334,6 +336,8 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) sinfo->tx_bytes = sta->tx_bytes; sinfo->rx_packets = sta->rx_packets; sinfo->tx_packets = sta->tx_packets; + sinfo->tx_retries = sta->tx_retry_count; + sinfo->tx_failed = sta->tx_retry_failed; if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) || (sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) { diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 9942f0b061ff..524f55402838 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -1890,6 +1890,12 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, if (sinfo->filled & STATION_INFO_TX_PACKETS) NLA_PUT_U32(msg, NL80211_STA_INFO_TX_PACKETS, sinfo->tx_packets); + if (sinfo->filled & STATION_INFO_TX_RETRIES) + NLA_PUT_U32(msg, NL80211_STA_INFO_TX_RETRIES, + sinfo->tx_retries); + if (sinfo->filled & STATION_INFO_TX_FAILED) + NLA_PUT_U32(msg, NL80211_STA_INFO_TX_FAILED, + sinfo->tx_failed); nla_nest_end(msg, sinfoattr); return genlmsg_end(msg, hdr); -- cgit v1.2.3 From 3207390a8b58bfc1335750f91cf6783c48ca19ca Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 6 Oct 2010 21:18:04 +0200 Subject: cfg80211: fix BSS double-unlinking When multiple interfaces are actively trying to associate with the same BSS, they may both find that the BSS isn't there and then try to unlink it. This can cause errors since the unlinking code can't currently deal with items that have already been unlinked. Normally this doesn't happen as most people don't try to use multiple station interfaces that associate at the same time too. Fix this by using the list entry as a flag to see if the item is still on a list. Cc: stable@kernel.org Reported-by: Ben Greear Tested-by: Hun-Kyi Wynn Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/scan.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 5ca8c7180141..503ebb86ba18 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -650,14 +650,14 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub) bss = container_of(pub, struct cfg80211_internal_bss, pub); spin_lock_bh(&dev->bss_lock); + if (!list_empty(&bss->list)) { + list_del_init(&bss->list); + dev->bss_generation++; + rb_erase(&bss->rbn, &dev->bss_tree); - list_del(&bss->list); - dev->bss_generation++; - rb_erase(&bss->rbn, &dev->bss_tree); - + kref_put(&bss->ref, bss_release); + } spin_unlock_bh(&dev->bss_lock); - - kref_put(&bss->ref, bss_release); } EXPORT_SYMBOL(cfg80211_unlink_bss); -- cgit v1.2.3 From 494486f8fd0eec956c5df823581df5dcf5409a6f Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Wed, 6 Oct 2010 16:40:40 -0400 Subject: mac80211: avoid uninitialized var warning in ieee80211_scan_cancel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit net/mac80211/scan.c: In function ‘ieee80211_scan_cancel’: net/mac80211/scan.c:794: warning: ‘finish’ may be used uninitialized in this function Signed-off-by: John W. Linville --- net/mac80211/scan.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 80e017df5f31..523db930dabb 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -791,7 +791,8 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata, */ void ieee80211_scan_cancel(struct ieee80211_local *local) { - bool abortscan, finish; + bool abortscan; + bool finish = false; /* * We are only canceling software scan, or deferred scan that was not @@ -818,7 +819,7 @@ void ieee80211_scan_cancel(struct ieee80211_local *local) if (abortscan) { /* The scan is canceled, but stop work from being pending */ cancel_delayed_work_sync(&local->scan_work); - if (finish) - __ieee80211_scan_completed_finish(&local->hw, false); } + if (finish) + __ieee80211_scan_completed_finish(&local->hw, false); } -- cgit v1.2.3 From d9d9a5194bb96d60fc846c94c602c874802e107d Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Wed, 6 Oct 2010 16:39:17 -0700 Subject: iwlagn: fix module firmware name for 130 series device 130 series device should use firmware name with 130 in it. Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-6000.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 43ec8988feb0..b448b03ae6d7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -78,8 +78,8 @@ #define IWL6000G2B_MODULE_FIRMWARE(api) _IWL6000G2B_MODULE_FIRMWARE(api) #define IWL130_FW_PRE "iwlwifi-130-" -#define _IWL100_MODULE_FIRMWARE(api) IWL130_FW_PRE #api ".ucode" -#define IWL100_MODULE_FIRMWARE(api) _IWL130_MODULE_FIRMWARE(api) +#define _IWL130_MODULE_FIRMWARE(api) IWL130_FW_PRE #api ".ucode" +#define IWL130_MODULE_FIRMWARE(api) _IWL130_MODULE_FIRMWARE(api) static void iwl6000_set_ct_threshold(struct iwl_priv *priv) { -- cgit v1.2.3 From cf9768d6a3f901b00fc9d8ecdf8e506d7cbcae99 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Wed, 6 Oct 2010 16:39:18 -0700 Subject: iwlagn: add define for MODULE_FIRMWARE Adding MODULE_FIRMWARE define for 130 series of devices Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-6000.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index b448b03ae6d7..6261aec5ebdc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -858,3 +858,4 @@ MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL6050_MODULE_FIRMWARE(IWL6050_UCODE_API_MAX)); MODULE_FIRMWARE(IWL6000G2A_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX)); MODULE_FIRMWARE(IWL6000G2B_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL130_MODULE_FIRMWARE(IWL130_UCODE_API_MAX)); -- cgit v1.2.3 From a6d27d2ac89359f84c1a559b5530967ff671d269 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Thu, 7 Oct 2010 11:31:56 -0400 Subject: Revert "rtl8180: use NAPI for bottom-half processing" This reverts commit 030725d2c7c1fafec7ede618647bf30ed79601f0. This commit relies on commit 5ed3bc7288487bd4f891f420a07319e0b538b4fe ("mac80211: use netif_receive_skb in ieee80211_tx_status callpath") Unfortunately not all drivers are calling ieee80211_tx_status from a compatible context, so that commit needs to be reverted in 2.6.36. Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8180_dev.c | 128 +++++++++++++---------------- 1 file changed, 59 insertions(+), 69 deletions(-) diff --git a/drivers/net/wireless/rtl818x/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c index 05c6badbe201..707c688da618 100644 --- a/drivers/net/wireless/rtl818x/rtl8180_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c @@ -99,66 +99,19 @@ void rtl8180_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data) } } -static void rtl8180_handle_tx(struct ieee80211_hw *dev) +static void rtl8180_handle_rx(struct ieee80211_hw *dev) { struct rtl8180_priv *priv = dev->priv; - struct rtl8180_tx_ring *ring; - int prio; - - spin_lock(&priv->lock); - - for (prio = 3; prio >= 0; prio--) { - ring = &priv->tx_ring[prio]; - - while (skb_queue_len(&ring->queue)) { - struct rtl8180_tx_desc *entry = &ring->desc[ring->idx]; - struct sk_buff *skb; - struct ieee80211_tx_info *info; - u32 flags = le32_to_cpu(entry->flags); - - if (flags & RTL818X_TX_DESC_FLAG_OWN) - break; - - ring->idx = (ring->idx + 1) % ring->entries; - skb = __skb_dequeue(&ring->queue); - pci_unmap_single(priv->pdev, le32_to_cpu(entry->tx_buf), - skb->len, PCI_DMA_TODEVICE); - - info = IEEE80211_SKB_CB(skb); - ieee80211_tx_info_clear_status(info); - - if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && - (flags & RTL818X_TX_DESC_FLAG_TX_OK)) - info->flags |= IEEE80211_TX_STAT_ACK; - - info->status.rates[0].count = (flags & 0xFF) + 1; - info->status.rates[1].idx = -1; - - ieee80211_tx_status(dev, skb); - if (ring->entries - skb_queue_len(&ring->queue) == 2) - ieee80211_wake_queue(dev, prio); - } - } - - spin_unlock(&priv->lock); -} - -static int rtl8180_poll(struct ieee80211_hw *dev, int budget) -{ - struct rtl8180_priv *priv = dev->priv; - unsigned int count = 0; + unsigned int count = 32; u8 signal, agc, sq; - /* handle pending Tx queue cleanup */ - rtl8180_handle_tx(dev); - - while (count++ < budget) { + while (count--) { struct rtl8180_rx_desc *entry = &priv->rx_ring[priv->rx_idx]; struct sk_buff *skb = priv->rx_buf[priv->rx_idx]; u32 flags = le32_to_cpu(entry->flags); if (flags & RTL818X_RX_DESC_FLAG_OWN) - break; + return; if (unlikely(flags & (RTL818X_RX_DESC_FLAG_DMA_FAIL | RTL818X_RX_DESC_FLAG_FOF | @@ -198,7 +151,7 @@ static int rtl8180_poll(struct ieee80211_hw *dev, int budget) rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); - ieee80211_rx(dev, skb); + ieee80211_rx_irqsafe(dev, skb); skb = new_skb; priv->rx_buf[priv->rx_idx] = skb; @@ -215,16 +168,41 @@ static int rtl8180_poll(struct ieee80211_hw *dev, int budget) entry->flags |= cpu_to_le32(RTL818X_RX_DESC_FLAG_EOR); priv->rx_idx = (priv->rx_idx + 1) % 32; } +} + +static void rtl8180_handle_tx(struct ieee80211_hw *dev, unsigned int prio) +{ + struct rtl8180_priv *priv = dev->priv; + struct rtl8180_tx_ring *ring = &priv->tx_ring[prio]; - if (count < budget) { - /* disable polling */ - ieee80211_napi_complete(dev); + while (skb_queue_len(&ring->queue)) { + struct rtl8180_tx_desc *entry = &ring->desc[ring->idx]; + struct sk_buff *skb; + struct ieee80211_tx_info *info; + u32 flags = le32_to_cpu(entry->flags); - /* enable interrupts */ - rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0xFFFF); - } + if (flags & RTL818X_TX_DESC_FLAG_OWN) + return; + + ring->idx = (ring->idx + 1) % ring->entries; + skb = __skb_dequeue(&ring->queue); + pci_unmap_single(priv->pdev, le32_to_cpu(entry->tx_buf), + skb->len, PCI_DMA_TODEVICE); + + info = IEEE80211_SKB_CB(skb); + ieee80211_tx_info_clear_status(info); + + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && + (flags & RTL818X_TX_DESC_FLAG_TX_OK)) + info->flags |= IEEE80211_TX_STAT_ACK; + + info->status.rates[0].count = (flags & 0xFF) + 1; + info->status.rates[1].idx = -1; - return count; + ieee80211_tx_status_irqsafe(dev, skb); + if (ring->entries - skb_queue_len(&ring->queue) == 2) + ieee80211_wake_queue(dev, prio); + } } static irqreturn_t rtl8180_interrupt(int irq, void *dev_id) @@ -233,17 +211,31 @@ static irqreturn_t rtl8180_interrupt(int irq, void *dev_id) struct rtl8180_priv *priv = dev->priv; u16 reg; + spin_lock(&priv->lock); reg = rtl818x_ioread16(priv, &priv->map->INT_STATUS); - if (unlikely(reg == 0xFFFF)) + if (unlikely(reg == 0xFFFF)) { + spin_unlock(&priv->lock); return IRQ_HANDLED; + } rtl818x_iowrite16(priv, &priv->map->INT_STATUS, reg); - /* disable interrupts */ - rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0); + if (reg & (RTL818X_INT_TXB_OK | RTL818X_INT_TXB_ERR)) + rtl8180_handle_tx(dev, 3); + + if (reg & (RTL818X_INT_TXH_OK | RTL818X_INT_TXH_ERR)) + rtl8180_handle_tx(dev, 2); + + if (reg & (RTL818X_INT_TXN_OK | RTL818X_INT_TXN_ERR)) + rtl8180_handle_tx(dev, 1); - /* enable polling */ - ieee80211_napi_schedule(dev); + if (reg & (RTL818X_INT_TXL_OK | RTL818X_INT_TXL_ERR)) + rtl8180_handle_tx(dev, 0); + + if (reg & (RTL818X_INT_RX_OK | RTL818X_INT_RX_ERR)) + rtl8180_handle_rx(dev); + + spin_unlock(&priv->lock); return IRQ_HANDLED; } @@ -255,6 +247,7 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb) struct rtl8180_priv *priv = dev->priv; struct rtl8180_tx_ring *ring; struct rtl8180_tx_desc *entry; + unsigned long flags; unsigned int idx, prio; dma_addr_t mapping; u32 tx_flags; @@ -301,7 +294,7 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb) plcp_len |= 1 << 15; } - spin_lock(&priv->lock); + spin_lock_irqsave(&priv->lock, flags); if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) @@ -325,7 +318,7 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb) if (ring->entries - skb_queue_len(&ring->queue) < 2) ieee80211_stop_queue(dev, prio); - spin_unlock(&priv->lock); + spin_unlock_irqrestore(&priv->lock, flags); rtl818x_iowrite8(priv, &priv->map->TX_DMA_POLLING, (1 << (prio + 4))); @@ -871,7 +864,6 @@ static const struct ieee80211_ops rtl8180_ops = { .prepare_multicast = rtl8180_prepare_multicast, .configure_filter = rtl8180_configure_filter, .get_tsf = rtl8180_get_tsf, - .napi_poll = rtl8180_poll, }; static void rtl8180_eeprom_register_read(struct eeprom_93cx6 *eeprom) @@ -1003,8 +995,6 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev, dev->queues = 1; dev->max_signal = 65; - dev->napi_weight = 64; - reg = rtl818x_ioread32(priv, &priv->map->TX_CONF); reg &= RTL818X_TX_CONF_HWVER_MASK; switch (reg) { -- cgit v1.2.3 From 4efe7f51be508a13965f163006dcb32b38a914a3 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Thu, 7 Oct 2010 11:35:40 -0400 Subject: Revert "mac80211: use netif_receive_skb in ieee80211_tx_status callpath" This reverts commit 5ed3bc7288487bd4f891f420a07319e0b538b4fe. It turns-out that not all drivers are calling ieee80211_tx_status from a compatible context. Revert this for now and try again later... Signed-off-by: John W. Linville --- net/mac80211/status.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 10caec5ea8fa..34da67995d94 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -377,7 +377,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) skb2 = skb_clone(skb, GFP_ATOMIC); if (skb2) { skb2->dev = prev_dev; - netif_receive_skb(skb2); + netif_rx(skb2); } } @@ -386,7 +386,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) } if (prev_dev) { skb->dev = prev_dev; - netif_receive_skb(skb); + netif_rx(skb); skb = NULL; } rcu_read_unlock(); -- cgit v1.2.3 From 4b34d432b0fcff422304de4eb49d6da861fe335c Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Thu, 7 Oct 2010 10:16:42 +0300 Subject: wl1271: Support FEM autodetection In the NVS/INI-parameters for the driver/firmware there is the FEM (front end module) selection option, which may configure the hardware FEM via autodetection or manual selection. So far, there has been support for manual selection only. Add support for FEM autodetection. Signed-off-by: Juuso Oikarinen Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_cmd.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index 596e333919ae..5d3e8485ea4e 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -108,6 +108,8 @@ out: int wl1271_cmd_general_parms(struct wl1271 *wl) { struct wl1271_general_parms_cmd *gen_parms; + struct wl1271_ini_general_params *gp = &wl->nvs->general_params; + bool answer = false; int ret; if (!wl->nvs) @@ -119,13 +121,24 @@ int wl1271_cmd_general_parms(struct wl1271 *wl) gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM; - memcpy(&gen_parms->general_params, &wl->nvs->general_params, - sizeof(struct wl1271_ini_general_params)); + memcpy(&gen_parms->general_params, gp, sizeof(*gp)); - ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), 0); - if (ret < 0) + if (gp->tx_bip_fem_auto_detect) + answer = true; + + ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer); + if (ret < 0) { wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed"); + goto out; + } + + gp->tx_bip_fem_manufacturer = + gen_parms->general_params.tx_bip_fem_manufacturer; + wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n", + answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer); + +out: kfree(gen_parms); return ret; } -- cgit v1.2.3 From 7b99a7c2dab7efe7c265b66fedbf3444958ebfe3 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 7 Oct 2010 12:55:24 +0200 Subject: mac80211: fix sw scan locking The recent scan overhaul broke locking because now we can jump to code that attempts to unlock, while we don't have the mutex held. Fix this by holding the mutex around all the relevant code. Reported-by: Ben Greear Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/scan.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 523db930dabb..fb274db77e3c 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -681,8 +681,6 @@ void ieee80211_scan_work(struct work_struct *work) goto out_complete; } - mutex_unlock(&local->mtx); - /* * as long as no delay is required advance immediately * without scheduling a new work @@ -713,6 +711,7 @@ void ieee80211_scan_work(struct work_struct *work) } while (next_delay == 0); ieee80211_queue_delayed_work(&local->hw, &local->scan_work, next_delay); + mutex_unlock(&local->mtx); return; out_complete: -- cgit v1.2.3 From 43b19952de54b0fccfcdc5968891ebe550367fe8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 7 Oct 2010 13:10:30 +0200 Subject: nl80211: use new genl helpers for WDS Bill Jordan's patch to allow setting the WDS peer crossed with my patch removing all the boilerplate code in nl80211, and consequently he didn't make use of it yet. Fix that. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/nl80211.c | 45 ++++++++++++--------------------------------- 1 file changed, 12 insertions(+), 33 deletions(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 524f55402838..4fed1663aba3 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -876,48 +876,25 @@ static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info) static int nl80211_set_wds_peer(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - struct wireless_dev *wdev; - struct net_device *dev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + struct wireless_dev *wdev = dev->ieee80211_ptr; u8 *bssid; - int err; if (!info->attrs[NL80211_ATTR_MAC]) return -EINVAL; - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rtnl; - - wdev = dev->ieee80211_ptr; - - if (netif_running(dev)) { - err = -EBUSY; - goto out; - } + if (netif_running(dev)) + return -EBUSY; - if (!rdev->ops->set_wds_peer) { - err = -EOPNOTSUPP; - goto out; - } + if (!rdev->ops->set_wds_peer) + return -EOPNOTSUPP; - if (wdev->iftype != NL80211_IFTYPE_WDS) { - err = -EOPNOTSUPP; - goto out; - } + if (wdev->iftype != NL80211_IFTYPE_WDS) + return -EOPNOTSUPP; bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); - err = rdev->ops->set_wds_peer(wdev->wiphy, dev, bssid); - -out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); -unlock_rtnl: - rtnl_unlock(); - - return err; + return rdev->ops->set_wds_peer(wdev->wiphy, dev, bssid); } @@ -4860,6 +4837,8 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_set_wds_peer, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, }; -- cgit v1.2.3 From 388ac775be95e510c2095ed6cd59422a5183a9fb Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 7 Oct 2010 13:11:09 +0200 Subject: cfg80211: constify WDS address There's no need for the WDS peer address to not be const, so make it const. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/net/cfg80211.h | 2 +- net/mac80211/cfg.c | 2 +- net/wireless/nl80211.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index e76daaa7dc25..0778d04b3bbe 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1229,7 +1229,7 @@ struct cfg80211_ops { int (*get_tx_power)(struct wiphy *wiphy, int *dbm); int (*set_wds_peer)(struct wiphy *wiphy, struct net_device *dev, - u8 *addr); + const u8 *addr); void (*rfkill_poll)(struct wiphy *wiphy); diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 2e5a3fb38efe..ecf9b7166ed1 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1363,7 +1363,7 @@ static int ieee80211_get_tx_power(struct wiphy *wiphy, int *dbm) } static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev, - u8 *addr) + const u8 *addr) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 4fed1663aba3..882dc921103b 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -879,7 +879,7 @@ static int nl80211_set_wds_peer(struct sk_buff *skb, struct genl_info *info) struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct net_device *dev = info->user_ptr[1]; struct wireless_dev *wdev = dev->ieee80211_ptr; - u8 *bssid; + const u8 *bssid; if (!info->attrs[NL80211_ATTR_MAC]) return -EINVAL; -- cgit v1.2.3 From 15a6321d1c0f8db561932cd99e1b9897981da71f Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Thu, 7 Oct 2010 20:58:39 +0530 Subject: ath9k_hw: Fix hw reset failure with HTC driver The following commit removed DISABLE_REGWRITE_BUFFER ops. The unnecessary REGWRITE_BUFFER_FLUSH was not removed properly which is causing failure on hw reset. Author: Felix Fietkau Date: Tue Oct 5 12:03:42 2010 +0200 ath9k_hw: clean up register write buffering Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/mac.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index e5784595bd0f..8c13479b17cd 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -491,8 +491,6 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) REG_WRITE(ah, AR_DMISC(q), AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x2); - REGWRITE_BUFFER_FLUSH(ah); - if (qi->tqi_cbrPeriod) { REG_WRITE(ah, AR_QCBRCFG(q), SM(qi->tqi_cbrPeriod, AR_Q_CBRCFG_INTERVAL) | @@ -508,8 +506,6 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) AR_Q_RDYTIMECFG_EN); } - REGWRITE_BUFFER_FLUSH(ah); - REG_WRITE(ah, AR_DCHNTIME(q), SM(qi->tqi_burstTime, AR_D_CHNTIME_DUR) | (qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0)); -- cgit v1.2.3