From a7da74fc88bff6f82f8255f2def49907f82f4c61 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Fri, 14 May 2010 10:46:23 +0300 Subject: wl1271: Add support for NVS files with 5GHz band parameters This patch adds support for NVS files with 5GHz band parameters. The change is done in a backward compatible manner - if 11a is not enabled in the driver, the driver will allow also old NVS files to be loaded. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_main.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/wl12xx/wl1271_main.c') diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index b7d9137851ac..5568f559a16b 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -566,14 +566,21 @@ static int wl1271_fetch_nvs(struct wl1271 *wl) return ret; } - if (fw->size != sizeof(struct wl1271_nvs_file)) { + /* + * 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 = kmalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL); + wl->nvs = kzalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL); if (!wl->nvs) { wl1271_error("could not allocate memory for the nvs file"); @@ -581,7 +588,7 @@ static int wl1271_fetch_nvs(struct wl1271 *wl) goto out; } - memcpy(wl->nvs, fw->data, sizeof(struct wl1271_nvs_file)); + memcpy(wl->nvs, fw->data, fw->size); out: release_firmware(fw); -- cgit v1.2.3 From a0ea949358579c22019202c6876d61087a79361f Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Thu, 20 May 2010 10:38:11 +0200 Subject: drivers/net/wireless: Storage class should be before const qualifier The C99 specification states in section 6.11.5: The placement of a storage-class specifier other than at the beginning of the declaration specifiers in a declaration is an obsolescent feature. Signed-off-by: Tobias Klauser Acked-by: Reinette Chatre Acked-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/wl12xx/wl1271_main.c') diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 5568f559a16b..032cb5de908c 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -1998,7 +1998,7 @@ static struct ieee80211_channel wl1271_channels[] = { }; /* mapping to indexes for wl1271_rates */ -const static u8 wl1271_rate_to_idx_2ghz[] = { +static const u8 wl1271_rate_to_idx_2ghz[] = { /* MCS rates are used only with 11n */ CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */ CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */ @@ -2110,7 +2110,7 @@ static struct ieee80211_channel wl1271_channels_5ghz[] = { }; /* mapping to indexes for wl1271_rates_5ghz */ -const static u8 wl1271_rate_to_idx_5ghz[] = { +static const u8 wl1271_rate_to_idx_5ghz[] = { /* MCS rates are used only with 11n */ CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */ CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */ @@ -2146,7 +2146,7 @@ static struct ieee80211_supported_band wl1271_band_5ghz = { .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz), }; -const static u8 *wl1271_band_rate_to_idx[] = { +static const u8 *wl1271_band_rate_to_idx[] = { [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz, [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz }; -- cgit v1.2.3 From db81956cc4a6780e9aeb1e85993096e67dcb0cd3 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Mon, 24 May 2010 11:18:15 +0300 Subject: wl1271: Prevent dropping of TX frames in joins The wl1271 uses a session counter in CMD_JOIN and TX frame descriptors. This counter is used to determine which frames to drop when the CMD_JOIN is executed. The driver executes CMD_JOIN multiple times upon association and sometimes disassociation, and we don't want any frames to get lost. Fix this by incrementing the session counter only when leaving idle (not every CMD_JOIN as before.) Also, remove the TX flush flag from the CMD_JOIN options. Signed-off-by: Juuso Oikarinen Reviewed-by: Teemu Paasikivi Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_main.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net/wireless/wl12xx/wl1271_main.c') diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 032cb5de908c..108a3e2a58fd 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -1135,6 +1135,11 @@ static int wl1271_dummy_join(struct wl1271 *wl) memcpy(wl->bssid, dummy_bssid, ETH_ALEN); + /* increment the session counter */ + wl->session_counter++; + if (wl->session_counter >= SESSION_COUNTER_MAX) + wl->session_counter = 0; + /* pass through frames from all BSS */ wl1271_configure_filters(wl, FIF_OTHER_BSS); -- cgit v1.2.3 From 0d58cbff2495fda8b2389719d30da694d3077a87 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Mon, 24 May 2010 11:18:16 +0300 Subject: wl1271: Idle handling into own function As there is more and more stuff triggered by going in and out of idle, create a separate function for handling that. Signed-off-by: Juuso Oikarinen Reviewed-by: Teemu Paasikivi Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_main.c | 60 ++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 21 deletions(-) (limited to 'drivers/net/wireless/wl12xx/wl1271_main.c') diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 108a3e2a58fd..653012662863 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -1135,11 +1135,6 @@ static int wl1271_dummy_join(struct wl1271 *wl) memcpy(wl->bssid, dummy_bssid, ETH_ALEN); - /* increment the session counter */ - wl->session_counter++; - if (wl->session_counter >= SESSION_COUNTER_MAX) - wl->session_counter = 0; - /* pass through frames from all BSS */ wl1271_configure_filters(wl, FIF_OTHER_BSS); @@ -1253,6 +1248,42 @@ static u32 wl1271_min_rate_get(struct wl1271 *wl) return rate; } +static int wl1271_handle_idle(struct wl1271 *wl, bool idle) +{ + int ret; + + if (idle) { + if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) { + ret = wl1271_unjoin(wl); + if (ret < 0) + goto out; + } + wl->rate_set = wl1271_min_rate_get(wl); + wl->sta_rate_set = 0; + ret = wl1271_acx_rate_policies(wl); + if (ret < 0) + goto out; + ret = wl1271_acx_keep_alive_config( + wl, CMD_TEMPL_KLV_IDX_NULL_DATA, + ACX_KEEP_ALIVE_TPL_INVALID); + if (ret < 0) + goto out; + set_bit(WL1271_FLAG_IDLE, &wl->flags); + } else { + /* increment the session counter */ + wl->session_counter++; + if (wl->session_counter >= SESSION_COUNTER_MAX) + wl->session_counter = 0; + ret = wl1271_dummy_join(wl); + if (ret < 0) + goto out; + clear_bit(WL1271_FLAG_IDLE, &wl->flags); + } + +out: + return ret; +} + static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) { struct wl1271 *wl = hw->priv; @@ -1307,22 +1338,9 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) } if (changed & IEEE80211_CONF_CHANGE_IDLE) { - if (conf->flags & IEEE80211_CONF_IDLE && - test_bit(WL1271_FLAG_JOINED, &wl->flags)) - wl1271_unjoin(wl); - else if (!(conf->flags & IEEE80211_CONF_IDLE)) - wl1271_dummy_join(wl); - - if (conf->flags & IEEE80211_CONF_IDLE) { - wl->rate_set = wl1271_min_rate_get(wl); - wl->sta_rate_set = 0; - wl1271_acx_rate_policies(wl); - wl1271_acx_keep_alive_config( - wl, CMD_TEMPL_KLV_IDX_NULL_DATA, - ACX_KEEP_ALIVE_TPL_INVALID); - set_bit(WL1271_FLAG_IDLE, &wl->flags); - } else - clear_bit(WL1271_FLAG_IDLE, &wl->flags); + ret = wl1271_handle_idle(wl, conf->flags & IEEE80211_CONF_IDLE); + if (ret < 0) + wl1271_warning("idle mode change failed %d", ret); } if (conf->flags & IEEE80211_CONF_PS && -- cgit v1.2.3 From 781608c41386b560b501404233fc43d8ef100c71 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Mon, 24 May 2010 11:18:17 +0300 Subject: wl1271: Flush TX buffers to air before going to idle The mac80211 changes to idle almost immediately after transmitting some frames, such as deauth etc. When going to idle, the wl1271 is disconnected, which causes TX frames already on buffers, but not yet transmitted, to be deleted. To make sure deauth frames reach the air, allow the TX buffers to flush before proceeding to idle. Signed-off-by: Juuso Oikarinen Reviewed-by: Teemu Paasikivi Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_main.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/wl12xx/wl1271_main.c') diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 653012662863..7bf655d55152 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -1051,7 +1051,7 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw, mutex_lock(&wl->mutex); /* let's notify MAC80211 about the remaining pending TX frames */ - wl1271_tx_flush(wl); + wl1271_tx_reset(wl); wl1271_power_off(wl); memset(wl->bssid, 0, ETH_ALEN); @@ -1298,6 +1298,15 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) conf->power_level, conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use"); + /* + * mac80211 will go to idle nearly immediately after transmitting some + * frames, such as the deauth. To make sure those frames reach the air, + * wait here until the TX queue is fully flushed. + */ + if ((changed & IEEE80211_CONF_CHANGE_IDLE) && + (conf->flags & IEEE80211_CONF_IDLE)) + wl1271_tx_flush(wl); + mutex_lock(&wl->mutex); if (unlikely(wl->state == WL1271_STATE_OFF)) -- cgit v1.2.3 From 4fb26fa9ae043810eb99c22364d23ffc3b271b8d Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Mon, 24 May 2010 11:18:20 +0300 Subject: wl1271: Fix scan parameter handling for 5GHz The 5GHz bands were scanned without the proper IE's in place, preventing proper 5GHz scanning. This patches fixes the problem by storing a pointer to the scan request (with the IE's) for all iterations of scan. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_main.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless/wl12xx/wl1271_main.c') diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 7bf655d55152..7a14da506d78 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -1634,13 +1634,11 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw, goto out; if (wl1271_11a_enabled()) - ret = wl1271_cmd_scan(hw->priv, ssid, len, - req->ie, req->ie_len, 1, 0, - WL1271_SCAN_BAND_DUAL, 3); + ret = wl1271_cmd_scan(hw->priv, ssid, len, req, + 1, 0, WL1271_SCAN_BAND_DUAL, 3); else - ret = wl1271_cmd_scan(hw->priv, ssid, len, - req->ie, req->ie_len, 1, 0, - WL1271_SCAN_BAND_2_4_GHZ, 3); + ret = wl1271_cmd_scan(hw->priv, ssid, len, req, + 1, 0, WL1271_SCAN_BAND_2_4_GHZ, 3); wl1271_ps_elp_sleep(wl); -- cgit v1.2.3 From bbbb538e337a3eb2166d5a20307b93822bdacc4f Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Thu, 8 Jul 2010 17:49:57 +0300 Subject: wl1271: Add TSF handling Add functionality to pass the current TSF (mac time) to the mac80211. This is needed for ad-hoc merging. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_main.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'drivers/net/wireless/wl12xx/wl1271_main.c') diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 7a14da506d78..5970fde49d40 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -1966,6 +1966,32 @@ out: return ret; } +static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw) +{ + + struct wl1271 *wl = hw->priv; + u64 mactime = ULLONG_MAX; + int ret; + + wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf"); + + mutex_lock(&wl->mutex); + + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + goto out; + + ret = wl1271_acx_tsf_info(wl, &mactime); + if (ret < 0) + goto out_sleep; + +out_sleep: + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); + return mactime; +} /* can't be const, mac80211 writes to this */ static struct ieee80211_rate wl1271_rates[] = { @@ -2195,6 +2221,7 @@ static const struct ieee80211_ops wl1271_ops = { .bss_info_changed = wl1271_op_bss_info_changed, .set_rts_threshold = wl1271_op_set_rts_threshold, .conf_tx = wl1271_op_conf_tx, + .get_tsf = wl1271_op_get_tsf, CFG80211_TESTMODE_CMD(wl1271_tm_cmd) }; -- cgit v1.2.3 From eb887dfd8837bf0a2538418c02b3992fb9ff1f28 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Thu, 8 Jul 2010 17:49:58 +0300 Subject: wl1271: Use the ARP configuration function from mac80211 This patch updates the driver to use the ARP configuration function from the mac80211. Also, clean up IPv6 support from the ACX function as ARP is not used with that protocol version. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_main.c | 142 +++++++++++------------------- 1 file changed, 49 insertions(+), 93 deletions(-) (limited to 'drivers/net/wireless/wl12xx/wl1271_main.c') diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 5970fde49d40..a37244c88fee 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include @@ -818,93 +817,6 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) return NETDEV_TX_OK; } -static int wl1271_dev_notify(struct notifier_block *me, unsigned long what, - void *arg) -{ - struct net_device *dev; - struct wireless_dev *wdev; - struct wiphy *wiphy; - struct ieee80211_hw *hw; - struct wl1271 *wl; - struct wl1271 *wl_temp; - struct in_device *idev; - struct in_ifaddr *ifa = arg; - int ret = 0; - - /* FIXME: this ugly function should probably be implemented in the - * mac80211, and here should only be a simple callback handling actual - * setting of the filters. Now we need to dig up references to - * various structures to gain access to what we need. - * Also, because of this, there is no "initial" setting of the filter - * in "op_start", because we don't want to dig up struct net_device - * there - the filter will be set upon first change of the interface - * IP address. */ - - dev = ifa->ifa_dev->dev; - - 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; - - /* Check that the interface is one supported by this driver. */ - wl_temp = hw->priv; - list_for_each_entry(wl, &wl_list, list) { - if (wl == wl_temp) - break; - } - if (wl != wl_temp) - return NOTIFY_DONE; - - /* Get the interface IP address for the device. "ifa" will become - NULL if: - - there is no IPV4 protocol address configured - - there are multiple (virtual) IPV4 addresses configured - When "ifa" is NULL, filtering will be disabled. - */ - ifa = NULL; - idev = dev->ip_ptr; - if (idev) - ifa = idev->ifa_list; - - if (ifa && ifa->ifa_next) - ifa = NULL; - - mutex_lock(&wl->mutex); - - if (wl->state == WL1271_STATE_OFF) - goto out; - - ret = wl1271_ps_elp_wakeup(wl, false); - if (ret < 0) - goto out; - if (ifa) - ret = wl1271_acx_arp_ip_filter(wl, true, - (u8 *)&ifa->ifa_address, - ACX_IPV4_VERSION); - else - ret = wl1271_acx_arp_ip_filter(wl, false, NULL, - ACX_IPV4_VERSION); - wl1271_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); - - return NOTIFY_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"); @@ -1008,10 +920,8 @@ power_off: out: mutex_unlock(&wl->mutex); - if (!ret) { + if (!ret) list_add(&wl->list, &wl_list); - register_inetaddr_notifier(&wl1271_dev_notifier); - } return ret; } @@ -1022,8 +932,6 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw, struct wl1271 *wl = hw->priv; int i; - unregister_inetaddr_notifier(&wl1271_dev_notifier); - mutex_lock(&wl->mutex); wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface"); @@ -1400,6 +1308,53 @@ struct wl1271_filter_params { u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN]; }; +static int wl1271_op_configure_arp_filter(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct in_ifaddr *ifa_list) +{ + struct wl1271 *wl = hw->priv; + int ret = 0; + + WARN_ON(vif != wl->vif); + + /* disable filtering if there are multiple addresses */ + if (ifa_list && ifa_list->ifa_next) + ifa_list = NULL; + + mutex_lock(&wl->mutex); + + if (wl->state == WL1271_STATE_OFF) + goto out; + + WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS); + + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + goto out; + + if (ifa_list) { + ret = wl1271_cmd_build_arp_reply(wl, &ifa_list->ifa_address); + if (ret < 0) + goto out_sleep; + ret = wl1271_acx_arp_ip_filter(wl, ACX_ARP_FILTER_AND_REPLY, + (u8 *)&ifa_list->ifa_address); + if (ret < 0) + goto out_sleep; + } else { + ret = wl1271_acx_arp_ip_filter(wl, ACX_ARP_DISABLE, NULL); + if (ret < 0) + goto out_sleep; + } + +out_sleep: + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); + + return ret; +} + static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, struct netdev_hw_addr_list *mc_list) { @@ -2213,6 +2168,7 @@ static const struct ieee80211_ops wl1271_ops = { .add_interface = wl1271_op_add_interface, .remove_interface = wl1271_op_remove_interface, .config = wl1271_op_config, + .configure_arp_filter = wl1271_op_configure_arp_filter, .prepare_multicast = wl1271_op_prepare_multicast, .configure_filter = wl1271_op_configure_filter, .tx = wl1271_op_tx, -- cgit v1.2.3 From 90494a90bea010af47547880634e0f1c52824a7d Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Thu, 8 Jul 2010 17:50:00 +0300 Subject: wl1271: Work around AP's with broken ps-poll functionality Some AP's (such as Zyxel Prestige 600) have totally broken ps-poll functionality. When powersave is enabled, these AP's will set the TIM bit for a STA in beacons, but when the STA responds with a ps-poll, the AP does not respond with data. The wl1271 firmware is able to send an indication to the host, when this problem occurs. This patch adds implementation, which temporarily disables power-save in response to this indication, allowing the AP to transmit whatever data it has buffered for the STA / whatever data is inbound at that time. This patch does not make these AP's work reliably in PSM, but improves the chances of inbound data getting through. The side effect of this patch is increased power consumption when using a faulty AP. Signed-off-by: Juuso Oikarinen Reviewed-by: Teemu Paasikivi Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_main.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/wl12xx/wl1271_main.c') diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index a37244c88fee..8a4b17f74dbc 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -233,7 +233,8 @@ static struct conf_drv_settings default_conf = { .beacon_rx_timeout = 10000, .broadcast_timeout = 20000, .rx_broadcast_in_ps = 1, - .ps_poll_threshold = 20, + .ps_poll_threshold = 10, + .ps_poll_recovery_period = 700, .bet_enable = CONF_BET_MODE_ENABLE, .bet_max_consecutive = 10, .psm_entry_retries = 3, @@ -955,6 +956,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); mutex_lock(&wl->mutex); @@ -1260,6 +1262,13 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) wl1271_warning("idle mode change failed %d", ret); } + /* + * if mac80211 changes the PSM mode, make sure the mode is not + * incorrectly changed after the pspoll failure active window. + */ + if (changed & IEEE80211_CONF_CHANGE_PS) + clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags); + if (conf->flags & IEEE80211_CONF_PS && !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) { set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags); @@ -1766,6 +1775,8 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, wl->aid = bss_conf->aid; set_assoc = true; + wl->ps_poll_failures = 0; + /* * use basic rates from AP, and determine lowest rate * to use with control frames. @@ -2390,6 +2401,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void) skb_queue_head_init(&wl->tx_queue); INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work); + INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work); wl->channel = WL1271_DEFAULT_CHANNEL; wl->beacon_int = WL1271_DEFAULT_BEACON_INT; wl->default_key = 0; -- cgit v1.2.3 From e6b190ff3c2f4e4859502c41fa17b5c595e82000 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Thu, 8 Jul 2010 17:50:01 +0300 Subject: wl1271: read fem manufacturer value from nvs We should read the fem manufacturer value from the NVS, so we can modify it easily and use a consistent value throughout the configuration. Previously we had to set the FEM value in the NVS and in the driver's initialization parameters. This patch removes the latter. Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_main.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers/net/wireless/wl12xx/wl1271_main.c') diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 8a4b17f74dbc..3a648963fbed 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -241,11 +241,6 @@ static struct conf_drv_settings default_conf = { .keep_alive_interval = 55000, .max_listen_interval = 20, }, - .init = { - .radioparam = { - .fem = 1, - } - }, .itrim = { .enable = false, .timeout = 50000, -- cgit v1.2.3 From ca52a5ebbb7caff2995214a6ca41a36c5210b0bd Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Thu, 8 Jul 2010 17:50:02 +0300 Subject: wl1271: Update hardware ARP filtering configuration handling The interface for hardware ARP configuration changed in the mac80211. Change driver accordingly. Signed-off-by: Juuso Oikarinen Reviewed-by: Teemu Paasikivi Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_main.c | 61 +++++++------------------------ 1 file changed, 13 insertions(+), 48 deletions(-) (limited to 'drivers/net/wireless/wl12xx/wl1271_main.c') diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 3a648963fbed..15c99dd76774 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -1312,53 +1312,6 @@ struct wl1271_filter_params { u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN]; }; -static int wl1271_op_configure_arp_filter(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct in_ifaddr *ifa_list) -{ - struct wl1271 *wl = hw->priv; - int ret = 0; - - WARN_ON(vif != wl->vif); - - /* disable filtering if there are multiple addresses */ - if (ifa_list && ifa_list->ifa_next) - ifa_list = NULL; - - mutex_lock(&wl->mutex); - - if (wl->state == WL1271_STATE_OFF) - goto out; - - WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS); - - ret = wl1271_ps_elp_wakeup(wl, false); - if (ret < 0) - goto out; - - if (ifa_list) { - ret = wl1271_cmd_build_arp_reply(wl, &ifa_list->ifa_address); - if (ret < 0) - goto out_sleep; - ret = wl1271_acx_arp_ip_filter(wl, ACX_ARP_FILTER_AND_REPLY, - (u8 *)&ifa_list->ifa_address); - if (ret < 0) - goto out_sleep; - } else { - ret = wl1271_acx_arp_ip_filter(wl, ACX_ARP_DISABLE, NULL); - if (ret < 0) - goto out_sleep; - } - -out_sleep: - wl1271_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); - - return ret; -} - static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, struct netdev_hw_addr_list *mc_list) { @@ -1869,6 +1822,19 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, } } + if (changed & BSS_CHANGED_ARP_FILTER) { + __be32 addr = bss_conf->arp_addr_list[0]; + WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS); + + if (bss_conf->arp_addr_cnt == 1 && bss_conf->arp_filter_enabled) + ret = wl1271_acx_arp_ip_filter(wl, true, addr); + else + ret = wl1271_acx_arp_ip_filter(wl, false, addr); + + if (ret < 0) + goto out_sleep; + } + if (do_join) { ret = wl1271_join(wl, set_assoc); if (ret < 0) { @@ -2174,7 +2140,6 @@ static const struct ieee80211_ops wl1271_ops = { .add_interface = wl1271_op_add_interface, .remove_interface = wl1271_op_remove_interface, .config = wl1271_op_config, - .configure_arp_filter = wl1271_op_configure_arp_filter, .prepare_multicast = wl1271_op_prepare_multicast, .configure_filter = wl1271_op_configure_filter, .tx = wl1271_op_tx, -- cgit v1.2.3 From 8d2ef7bd76f222b068a3fd534fe5fdb8c9543ba0 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Thu, 8 Jul 2010 17:50:03 +0300 Subject: wl1271: Disable dynamic PS based on BT co-ext sense events This patch requests mac80211 to disable dynamic PSM based on sense events coming from the firmware. Effectively, whenever there is bluetooth traffic, the mac80211 is forced into full PSM mode. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_main.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/wl12xx/wl1271_main.c') diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 15c99dd76774..366e41518feb 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -54,7 +54,7 @@ static struct conf_drv_settings default_conf = { [CONF_SG_HV3_MAX_OVERRIDE] = 0, [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400, [CONF_SG_BT_LOAD_RATIO] = 50, - [CONF_SG_AUTO_PS_MODE] = 0, + [CONF_SG_AUTO_PS_MODE] = 1, [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170, [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50, [CONF_SG_ANTENNA_CONFIGURATION] = 0, @@ -937,6 +937,9 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw, WARN_ON(wl->state != WL1271_STATE_ON); + /* enable dyn ps just in case (if left on due to fw crash etc) */ + ieee80211_disable_dyn_ps(wl->vif, false); + if (test_and_clear_bit(WL1271_FLAG_SCANNING, &wl->flags)) { mutex_unlock(&wl->mutex); ieee80211_scan_completed(wl->hw, true); @@ -1774,6 +1777,9 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags); wl->aid = 0; + /* re-enable dynamic ps - just in case */ + ieee80211_disable_dyn_ps(wl->vif, false); + /* revert back to minimum rates for the current band */ wl1271_set_band_rate(wl); wl->basic_rate = wl1271_min_rate_get(wl); -- cgit v1.2.3 From 9a547bf9a83ce7211d4290956d9fca8044a409de Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Thu, 8 Jul 2010 17:50:04 +0300 Subject: wl1271: Fix warning when disconnecting and ad-hoc network Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Reviewed-by: Teemu Paasikivi Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/wl12xx/wl1271_main.c') diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 366e41518feb..d50c0a9835a0 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -938,7 +938,8 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw, WARN_ON(wl->state != WL1271_STATE_ON); /* enable dyn ps just in case (if left on due to fw crash etc) */ - ieee80211_disable_dyn_ps(wl->vif, false); + if (wl->bss_type == BSS_TYPE_STA_BSS) + ieee80211_disable_dyn_ps(wl->vif, false); if (test_and_clear_bit(WL1271_FLAG_SCANNING, &wl->flags)) { mutex_unlock(&wl->mutex); -- cgit v1.2.3 From f532be6d48a12cd1b27c4efa38d22e0cbfa512d1 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Thu, 8 Jul 2010 17:50:05 +0300 Subject: wl1271: Update interface to temporarily disable dynamic PS The mac80211 interface to temporarily disable dynamic PS changed, make corresponding changes to the driver. Signed-off-by: Juuso Oikarinen Reviewed-by: Saravanan Dhanabal Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/wl12xx/wl1271_main.c') diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index d50c0a9835a0..70c6b0d22353 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -939,7 +939,7 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw, /* enable dyn ps just in case (if left on due to fw crash etc) */ if (wl->bss_type == BSS_TYPE_STA_BSS) - ieee80211_disable_dyn_ps(wl->vif, false); + ieee80211_enable_dyn_ps(wl->vif); if (test_and_clear_bit(WL1271_FLAG_SCANNING, &wl->flags)) { mutex_unlock(&wl->mutex); @@ -1779,7 +1779,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, wl->aid = 0; /* re-enable dynamic ps - just in case */ - ieee80211_disable_dyn_ps(wl->vif, false); + ieee80211_enable_dyn_ps(wl->vif); /* revert back to minimum rates for the current band */ wl1271_set_band_rate(wl); -- cgit v1.2.3 From 34dd2aaac4a4b908c093980a9894fd878aeb6deb Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Thu, 8 Jul 2010 17:50:06 +0300 Subject: wl1271: moved scan operations to a separate file The scanning code is going to get a bit more complex, with proper support for active/passive scans together with 2.4GHz and 5GHz. In the future, also a new type of scan (periodic scan) will be added. When all this is implemented, the code is going to be much more complex, so we'd better separate it into a separate file. This patch doesn't have any impact on functionality. Signed-off-by: Luciano Coelho Reviewed-by: Saravanan Dhanabal Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_main.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless/wl12xx/wl1271_main.c') diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 70c6b0d22353..cdfcc054efe4 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -44,6 +44,7 @@ #include "wl1271_cmd.h" #include "wl1271_boot.h" #include "wl1271_testmode.h" +#include "wl1271_scan.h" #define WL1271_BOOT_RETRIES 3 @@ -1550,11 +1551,11 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw, goto out; if (wl1271_11a_enabled()) - ret = wl1271_cmd_scan(hw->priv, ssid, len, req, - 1, 0, WL1271_SCAN_BAND_DUAL, 3); + ret = wl1271_scan(hw->priv, ssid, len, req, + 1, 0, WL1271_SCAN_BAND_DUAL, 3); else - ret = wl1271_cmd_scan(hw->priv, ssid, len, req, - 1, 0, WL1271_SCAN_BAND_2_4_GHZ, 3); + ret = wl1271_scan(hw->priv, ssid, len, req, + 1, 0, WL1271_SCAN_BAND_2_4_GHZ, 3); wl1271_ps_elp_sleep(wl); -- cgit v1.2.3 From 08688d6b1a85484cc8e4a920afc60ffa6559999d Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Thu, 8 Jul 2010 17:50:07 +0300 Subject: wl1271: rewritten scanning code This patch is a complete rewrite of the scanning code. It now includes a state machine to scan all four possible sets of channels independently: 2.4GHz active, 2.4GHz passive, 5GHz active and 5GHz passive. The wl1271 firmware doesn't allow these sets to be mixed, so up to several scan commands have to be issued. This patch also allows scanning more than 24 channels per set, by breaking the sets into smaller parts if needed (the firmware can scan a maximum of 24 channels at a time). Previously, the scanning code was erroneously scanning all channels possible actively, not complying with the CRDA values. This is also fixed with this patch. Signed-off-by: Luciano Coelho Reviewed-by: Saravanan Dhanabal Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_main.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless/wl12xx/wl1271_main.c') diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index cdfcc054efe4..d30de58cef90 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -942,10 +942,13 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw, if (wl->bss_type == BSS_TYPE_STA_BSS) ieee80211_enable_dyn_ps(wl->vif); - if (test_and_clear_bit(WL1271_FLAG_SCANNING, &wl->flags)) { + if (wl->scan.state != WL1271_SCAN_STATE_IDLE) { mutex_unlock(&wl->mutex); ieee80211_scan_completed(wl->hw, true); mutex_lock(&wl->mutex); + wl->scan.state = WL1271_SCAN_STATE_IDLE; + kfree(wl->scan.scanned_ch); + wl->scan.scanned_ch = NULL; } wl->state = WL1271_STATE_OFF; @@ -1551,11 +1554,9 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw, goto out; if (wl1271_11a_enabled()) - ret = wl1271_scan(hw->priv, ssid, len, req, - 1, 0, WL1271_SCAN_BAND_DUAL, 3); + ret = wl1271_scan(hw->priv, ssid, len, req); else - ret = wl1271_scan(hw->priv, ssid, len, req, - 1, 0, WL1271_SCAN_BAND_2_4_GHZ, 3); + ret = wl1271_scan(hw->priv, ssid, len, req); wl1271_ps_elp_sleep(wl); -- cgit v1.2.3 From 929ebd30e4f982a1d2817f70154e7441f5714118 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 15 May 2010 23:16:39 +0200 Subject: drivers/net/wireless/wl12xx: Use kmemdup Use kmemdup when some other buffer is immediately copied into the allocated region. A simplified version of the semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ expression from,to,size,flag; statement S; @@ - to = \(kmalloc\|kzalloc\)(size,flag); + to = kmemdup(from,size,flag); if (to==NULL || ...) S - memcpy(to, from, size); // Signed-off-by: Julia Lawall Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_main.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless/wl12xx/wl1271_main.c') diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index d30de58cef90..864318f096ea 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -576,7 +576,7 @@ static int wl1271_fetch_nvs(struct wl1271 *wl) goto out; } - wl->nvs = kzalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL); + wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL); if (!wl->nvs) { wl1271_error("could not allocate memory for the nvs file"); @@ -584,8 +584,6 @@ static int wl1271_fetch_nvs(struct wl1271 *wl) goto out; } - memcpy(wl->nvs, fw->data, fw->size); - out: release_firmware(fw); @@ -2350,15 +2348,13 @@ struct ieee80211_hw *wl1271_alloc_hw(void) goto err_hw_alloc; } - plat_dev = kmalloc(sizeof(wl1271_device), GFP_KERNEL); + plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL); if (!plat_dev) { wl1271_error("could not allocate platform_device"); ret = -ENOMEM; goto err_plat_alloc; } - memcpy(plat_dev, &wl1271_device, sizeof(wl1271_device)); - wl = hw->priv; memset(wl, 0, sizeof(*wl)); -- cgit v1.2.3 From ece550d0e416b4146e1ec3d934f9773dbf8c7242 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Wed, 28 Jul 2010 16:41:06 -0400 Subject: wl1271: add get_survey callback in order to get channel noise Signed-off-by: John W. Linville Acked-by: Juuso Oikarinen --- drivers/net/wireless/wl12xx/wl1271_main.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'drivers/net/wireless/wl12xx/wl1271_main.c') diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 864318f096ea..374abf0f5cc7 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -1927,6 +1927,22 @@ out: return mactime; } +static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx, + struct survey_info *survey) +{ + struct wl1271 *wl = hw->priv; + struct ieee80211_conf *conf = &hw->conf; + + if (idx != 0) + return -ENOENT; + + survey->channel = conf->channel; + survey->filled = SURVEY_INFO_NOISE_DBM; + survey->noise = wl->noise; + + return 0; +} + /* can't be const, mac80211 writes to this */ static struct ieee80211_rate wl1271_rates[] = { { .bitrate = 10, @@ -2156,6 +2172,7 @@ static const struct ieee80211_ops wl1271_ops = { .set_rts_threshold = wl1271_op_set_rts_threshold, .conf_tx = wl1271_op_conf_tx, .get_tsf = wl1271_op_get_tsf, + .get_survey = wl1271_op_get_survey, CFG80211_TESTMODE_CMD(wl1271_tm_cmd) }; -- cgit v1.2.3 From ac01e948b1c27059d47249ef601036633249cb2a Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Wed, 28 Jul 2010 17:09:41 -0400 Subject: wl1271: update hw/fw version info in wiphy struct This makes the information available through ethtool... Signed-off-by: John W. Linville Acked-by: Juuso Oikarinen --- drivers/net/wireless/wl12xx/wl1271_main.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/net/wireless/wl12xx/wl1271_main.c') diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 374abf0f5cc7..9d68f0012f05 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -839,6 +839,7 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct wl1271 *wl = hw->priv; + struct wiphy *wiphy = hw->wiphy; int retries = WL1271_BOOT_RETRIES; int ret = 0; @@ -892,6 +893,12 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, wl->state = WL1271_STATE_ON; wl1271_info("firmware booted (%s)", wl->chip.fw_ver); + + /* update hw/fw version info in wiphy struct */ + wiphy->hw_version = wl->chip.id; + strncpy(wiphy->fw_version, wl->chip.fw_ver, + sizeof(wiphy->fw_version)); + goto out; irq_disable: -- cgit v1.2.3