From 82429d32ca3bae9d67faa32ffbc989be2e63094f Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Wed, 28 Apr 2010 09:50:01 +0300 Subject: [PATCH] wl1271: Rewrite hardware keep-alive handling The driver had a join command without keep-alive restart procedures in the channel changing code. After associated scans, the mac80211 does re-set the current channel, causing the join to occur. This would stop the hardware keep alive. To make the joins safer in this respect, this patch adds a join function that does the hardware-keep-alive magic along the join. This is now invoked in the above mentioned scenario, and also other scenarios. 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 | 91 ++++++++++++----------- 1 file changed, 46 insertions(+), 45 deletions(-) diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index c160e5ad1e5..a794d5ed8c6 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -1117,14 +1117,13 @@ static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters) } } -static int wl1271_join_channel(struct wl1271 *wl, int channel) +static int wl1271_dummy_join(struct wl1271 *wl) { int ret = 0; /* we need to use a dummy BSSID for now */ static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde, 0xad, 0xbe, 0xef }; - wl->channel = channel; memcpy(wl->bssid, dummy_bssid, ETH_ALEN); /* pass through frames from all BSS */ @@ -1140,7 +1139,47 @@ out: return ret; } -static int wl1271_unjoin_channel(struct wl1271 *wl) +static int wl1271_join(struct wl1271 *wl) +{ + int ret; + + ret = wl1271_cmd_join(wl, wl->set_bss_type); + if (ret < 0) + goto out; + + set_bit(WL1271_FLAG_JOINED, &wl->flags); + + if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) + goto out; + + /* + * The join command disable the keep-alive mode, shut down its process, + * and also clear the template config, so we need to reset it all after + * the join. The acx_aid starts the keep-alive process, and the order + * of the commands below is relevant. + */ + ret = wl1271_acx_keep_alive_mode(wl, true); + if (ret < 0) + goto out; + + ret = wl1271_acx_aid(wl, wl->aid); + if (ret < 0) + goto out; + + ret = wl1271_cmd_build_klv_null_data(wl); + if (ret < 0) + goto out; + + ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA, + ACX_KEEP_ALIVE_TPL_VALID); + if (ret < 0) + goto out; + +out: + return ret; +} + +static int wl1271_unjoin(struct wl1271 *wl) { int ret; @@ -1230,7 +1269,7 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) "failed %d", ret); if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) { - ret = wl1271_cmd_join(wl, wl->set_bss_type); + ret = wl1271_join(wl); if (ret < 0) wl1271_warning("cmd join to update channel " "failed %d", ret); @@ -1240,9 +1279,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_channel(wl); + wl1271_unjoin(wl); else if (!(conf->flags & IEEE80211_CONF_IDLE)) - wl1271_join_channel(wl, channel); + wl1271_dummy_join(wl); if (conf->flags & IEEE80211_CONF_IDLE) { wl->rate_set = wl1271_min_rate_get(wl); @@ -1612,7 +1651,6 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, enum wl1271_cmd_ps_mode mode; struct wl1271 *wl = hw->priv; bool do_join = false; - bool do_keepalive = false; int ret; wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed"); @@ -1755,19 +1793,6 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, ret = wl1271_cmd_build_probe_req(wl, NULL, 0, NULL, 0, wl->band); - /* Enable the keep-alive feature */ - ret = wl1271_acx_keep_alive_mode(wl, true); - if (ret < 0) - goto out_sleep; - - /* - * This is awkward. The keep-alive configs must be done - * *after* the join command, because otherwise it will - * not work, but it must only be done *once* because - * otherwise the firmware will start complaining. - */ - do_keepalive = true; - /* enable the connection monitoring feature */ ret = wl1271_acx_conn_monit_params(wl, true); if (ret < 0) @@ -1835,35 +1860,11 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, } if (do_join) { - ret = wl1271_cmd_join(wl, wl->set_bss_type); + ret = wl1271_join(wl); if (ret < 0) { wl1271_warning("cmd join failed %d", ret); goto out_sleep; } - set_bit(WL1271_FLAG_JOINED, &wl->flags); - } - - /* - * The JOIN operation shuts down the firmware keep-alive as a side - * effect, and the ACX_AID will start the keep-alive as a side effect. - * Hence, for non-IBSS, the ACX_AID must always happen *after* the - * JOIN operation, and the template config after the ACX_AID. - */ - if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) { - ret = wl1271_acx_aid(wl, wl->aid); - if (ret < 0) - goto out_sleep; - } - - if (do_keepalive) { - ret = wl1271_cmd_build_klv_null_data(wl); - if (ret < 0) - goto out_sleep; - ret = wl1271_acx_keep_alive_config( - wl, CMD_TEMPL_KLV_IDX_NULL_DATA, - ACX_KEEP_ALIVE_TPL_VALID); - if (ret < 0) - goto out_sleep; } out_sleep: -- 2.20.1