From eb70eb723b489dd4e233e22e47d993f59858cdd8 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Fri, 14 May 2010 10:46:22 +0300 Subject: wl1271: Update handling of the NVS file / INI parameters This patch updates the handling of the NVS file INI-section, trying to make it slightly more generic, and exposing the parameters being set. This is done in preparation for 5GHz parameters. 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_cmd.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless/wl12xx/wl1271_cmd.c') diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index 19393e236e2..241b4778186 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -212,8 +212,8 @@ int wl1271_cmd_general_parms(struct wl1271 *wl) gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM; - memcpy(gen_parms->params, wl->nvs->general_params, - WL1271_NVS_GENERAL_PARAMS_SIZE); + memcpy(&gen_parms->general_params, &wl->nvs->general_params, + sizeof(struct wl1271_ini_general_params)); ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), 0); if (ret < 0) @@ -238,11 +238,11 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl) radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM; - memcpy(radio_parms->stat_radio_params, wl->nvs->stat_radio_params, - WL1271_NVS_STAT_RADIO_PARAMS_SIZE); - memcpy(radio_parms->dyn_radio_params, - wl->nvs->dyn_radio_params[rparam->fem], - WL1271_NVS_DYN_RADIO_PARAMS_SIZE); + memcpy(&radio_parms->static_params_2, &wl->nvs->stat_radio_params_2, + sizeof(struct wl1271_ini_band_params_2)); + memcpy(&radio_parms->dyn_params_2, + &wl->nvs->dyn_radio_params_2[rparam->fem].params, + sizeof(struct wl1271_ini_fem_params_2)); /* FIXME: current NVS is missing 5GHz parameters */ -- cgit v1.2.3 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_cmd.c | 9 ++++++++- drivers/net/wireless/wl12xx/wl1271_ini.h | 11 ++++++++--- drivers/net/wireless/wl12xx/wl1271_main.c | 13 ++++++++++--- drivers/net/wireless/wl12xx/wl1271_testmode.c | 11 +++++++++-- 4 files changed, 35 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless/wl12xx/wl1271_cmd.c') diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index 241b4778186..d7bcce887c4 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -238,13 +238,20 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl) radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM; + /* 2.4GHz parameters */ memcpy(&radio_parms->static_params_2, &wl->nvs->stat_radio_params_2, sizeof(struct wl1271_ini_band_params_2)); memcpy(&radio_parms->dyn_params_2, &wl->nvs->dyn_radio_params_2[rparam->fem].params, sizeof(struct wl1271_ini_fem_params_2)); - /* FIXME: current NVS is missing 5GHz parameters */ + /* 5GHz parameters */ + memcpy(&radio_parms->static_params_5, + &wl->nvs->stat_radio_params_5, + sizeof(struct wl1271_ini_band_params_5)); + memcpy(&radio_parms->dyn_params_5, + &wl->nvs->dyn_radio_params_5[rparam->fem].params, + sizeof(struct wl1271_ini_fem_params_5)); wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ", radio_parms, sizeof(*radio_parms)); diff --git a/drivers/net/wireless/wl12xx/wl1271_ini.h b/drivers/net/wireless/wl12xx/wl1271_ini.h index d1590bc1bf8..0fb156a5af1 100644 --- a/drivers/net/wireless/wl12xx/wl1271_ini.h +++ b/drivers/net/wireless/wl12xx/wl1271_ini.h @@ -95,9 +95,10 @@ struct wl1271_ini_fem_params_5 { /* NVS data structure */ #define WL1271_INI_NVS_SECTION_SIZE 468 -#define WL1271_INI_SPARE_SIZE 124 #define WL1271_INI_FEM_MODULE_COUNT 2 +#define WL1271_INI_LEGACY_NVS_FILE_SIZE 800 + struct wl1271_nvs_file { /* NVS section */ u8 nvs[WL1271_INI_NVS_SECTION_SIZE]; @@ -111,8 +112,12 @@ struct wl1271_nvs_file { struct wl1271_ini_fem_params_2 params; u8 padding; } dyn_radio_params_2[WL1271_INI_FEM_MODULE_COUNT]; - - u8 ini_spare[WL1271_INI_SPARE_SIZE]; + struct wl1271_ini_band_params_5 stat_radio_params_5; + u8 padding3; + struct { + struct wl1271_ini_fem_params_5 params; + u8 padding; + } dyn_radio_params_5[WL1271_INI_FEM_MODULE_COUNT]; } __attribute__ ((packed)); #endif diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index b7d9137851a..5568f559a16 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); diff --git a/drivers/net/wireless/wl12xx/wl1271_testmode.c b/drivers/net/wireless/wl12xx/wl1271_testmode.c index 554deb4d024..6e0952f79e9 100644 --- a/drivers/net/wireless/wl12xx/wl1271_testmode.c +++ b/drivers/net/wireless/wl12xx/wl1271_testmode.c @@ -199,7 +199,14 @@ 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]); - if (len != 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 (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; @@ -209,7 +216,7 @@ static int wl1271_tm_cmd_nvs_push(struct wl1271 *wl, struct nlattr *tb[]) kfree(wl->nvs); - 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"); ret = -ENOMEM; -- 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_cmd.c | 6 ------ drivers/net/wireless/wl12xx/wl1271_main.c | 5 +++++ 2 files changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless/wl12xx/wl1271_cmd.c') diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index d7bcce887c4..05b6d8a4aea 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -336,12 +336,6 @@ int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type) join->channel = wl->channel; join->ssid_len = wl->ssid_len; memcpy(join->ssid, wl->ssid, wl->ssid_len); - join->ctrl = WL1271_JOIN_CMD_CTRL_TX_FLUSH; - - /* increment the session counter */ - wl->session_counter++; - if (wl->session_counter >= SESSION_COUNTER_MAX) - wl->session_counter = 0; join->ctrl |= wl->session_counter << WL1271_JOIN_CMD_TX_SESSION_OFFSET; diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 032cb5de908..108a3e2a58f 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 5da54f94992b35fd58ad5b569abe8ca04048f8f1 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Mon, 24 May 2010 11:18:19 +0300 Subject: wl1271: Use proper rates for PSM entry/exit null-funcs for 5GHz A fixed 1 mbps rate was used for the PSM entry/exit null-func frames. Fix this by using the basic rates instead. 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_cmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/wl12xx/wl1271_cmd.c') diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index 05b6d8a4aea..dcad42ccc9d 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -518,7 +518,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(1); /* 1 Mbps */ + ps_params->null_data_rate = cpu_to_le32(wl->basic_rate_set); ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params, sizeof(*ps_params), 0); -- 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.h | 1 + drivers/net/wireless/wl12xx/wl1271_cmd.c | 8 +++++--- drivers/net/wireless/wl12xx/wl1271_cmd.h | 2 +- drivers/net/wireless/wl12xx/wl1271_event.c | 10 +++++----- drivers/net/wireless/wl12xx/wl1271_main.c | 10 ++++------ 5 files changed, 16 insertions(+), 15 deletions(-) (limited to 'drivers/net/wireless/wl12xx/wl1271_cmd.c') diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index 4984f46626d..1b52ce6a84d 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -299,6 +299,7 @@ struct wl1271_rx_mem_pool_addr { }; struct wl1271_scan { + struct cfg80211_scan_request *req; u8 state; u8 ssid[IW_ESSID_MAX_SIZE+1]; size_t ssid_len; diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index dcad42ccc9d..530678e45a1 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -568,7 +568,7 @@ out: } int wl1271_cmd_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, - const u8 *ie, size_t ie_len, u8 active_scan, + struct cfg80211_scan_request *req, u8 active_scan, u8 high_prio, u8 band, u8 probe_requests) { @@ -649,7 +649,7 @@ int wl1271_cmd_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, } ret = wl1271_cmd_build_probe_req(wl, ssid, ssid_len, - ie, ie_len, ieee_band); + req->ie, req->ie_len, ieee_band); if (ret < 0) { wl1271_error("PROBE request template failed"); goto out; @@ -685,7 +685,9 @@ int wl1271_cmd_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, memcpy(wl->scan.ssid, ssid, ssid_len); } else wl->scan.ssid_len = 0; - } + wl->scan.req = req; + } else + wl->scan.req = NULL; } ret = wl1271_cmd_send(wl, CMD_SCAN, params, sizeof(*params), 0); diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.h b/drivers/net/wireless/wl12xx/wl1271_cmd.h index 4ff966f6354..68001dffe71 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.h +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.h @@ -42,7 +42,7 @@ 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_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, - const u8 *ie, size_t ie_len, u8 active_scan, + struct cfg80211_scan_request *req, u8 active_scan, u8 high_prio, u8 band, u8 probe_requests); 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_event.c b/drivers/net/wireless/wl12xx/wl1271_event.c index cf37aa6eb13..ca52cdec7a8 100644 --- a/drivers/net/wireless/wl12xx/wl1271_event.c +++ b/drivers/net/wireless/wl12xx/wl1271_event.c @@ -43,11 +43,11 @@ static int wl1271_event_scan_complete(struct wl1271 *wl, clear_bit(WL1271_FLAG_SCANNING, &wl->flags); /* FIXME: ie missing! */ wl1271_cmd_scan(wl, wl->scan.ssid, wl->scan.ssid_len, - NULL, 0, - wl->scan.active, - wl->scan.high_prio, - WL1271_SCAN_BAND_5_GHZ, - wl->scan.probe_requests); + wl->scan.req, + wl->scan.active, + wl->scan.high_prio, + WL1271_SCAN_BAND_5_GHZ, + wl->scan.probe_requests); } else { mutex_unlock(&wl->mutex); ieee80211_scan_completed(wl->hw, false); diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 7bf655d5515..7a14da506d7 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 ab2807efcfd2dd646a2ca8d71585e26cda3fc0c1 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Thu, 8 Jul 2010 17:49:56 +0300 Subject: wl1271: Remove calibration from join command This patch removes the calibration performed on the first join command. The reasoning is that this is unnecessary as devices get their calibration data via the NVS file, and because the commands break BT coexistence. This is actually safe, because of the implementation the calibration was executed on the first JOIN anyway, after an ifdown/ifup the devices have relied on the NVS for calibration anyway (== most of the time.) 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_cmd.c | 104 ------------------------------- 1 file changed, 104 deletions(-) (limited to 'drivers/net/wireless/wl12xx/wl1271_cmd.c') diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index 530678e45a1..8307f21053f 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -104,100 +104,6 @@ out: return ret; } -static int wl1271_cmd_cal_channel_tune(struct wl1271 *wl) -{ - struct wl1271_cmd_cal_channel_tune *cmd; - int ret = 0; - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) - return -ENOMEM; - - cmd->test.id = TEST_CMD_CHANNEL_TUNE; - - cmd->band = WL1271_CHANNEL_TUNE_BAND_2_4; - /* set up any channel, 7 is in the middle of the range */ - cmd->channel = 7; - - ret = wl1271_cmd_test(wl, cmd, sizeof(*cmd), 0); - if (ret < 0) - wl1271_warning("TEST_CMD_CHANNEL_TUNE failed"); - - kfree(cmd); - return ret; -} - -static int wl1271_cmd_cal_update_ref_point(struct wl1271 *wl) -{ - struct wl1271_cmd_cal_update_ref_point *cmd; - int ret = 0; - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) - return -ENOMEM; - - cmd->test.id = TEST_CMD_UPDATE_PD_REFERENCE_POINT; - - /* FIXME: still waiting for the correct values */ - cmd->ref_power = 0; - cmd->ref_detector = 0; - - cmd->sub_band = WL1271_PD_REFERENCE_POINT_BAND_B_G; - - ret = wl1271_cmd_test(wl, cmd, sizeof(*cmd), 0); - if (ret < 0) - wl1271_warning("TEST_CMD_UPDATE_PD_REFERENCE_POINT failed"); - - kfree(cmd); - return ret; -} - -static int wl1271_cmd_cal_p2g(struct wl1271 *wl) -{ - struct wl1271_cmd_cal_p2g *cmd; - int ret = 0; - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) - return -ENOMEM; - - cmd->test.id = TEST_CMD_P2G_CAL; - - cmd->sub_band_mask = WL1271_CAL_P2G_BAND_B_G; - - ret = wl1271_cmd_test(wl, cmd, sizeof(*cmd), 0); - if (ret < 0) - wl1271_warning("TEST_CMD_P2G_CAL failed"); - - kfree(cmd); - return ret; -} - -static int wl1271_cmd_cal(struct wl1271 *wl) -{ - /* - * FIXME: we must make sure that we're not sleeping when calibration - * is done - */ - int ret; - - wl1271_notice("performing tx calibration"); - - ret = wl1271_cmd_cal_channel_tune(wl); - if (ret < 0) - return ret; - - ret = wl1271_cmd_cal_update_ref_point(wl); - if (ret < 0) - return ret; - - ret = wl1271_cmd_cal_p2g(wl); - if (ret < 0) - return ret; - - return ret; -} - int wl1271_cmd_general_parms(struct wl1271 *wl) { struct wl1271_general_parms_cmd *gen_parms; @@ -295,20 +201,10 @@ static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask) int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type) { - static bool do_cal = true; struct wl1271_cmd_join *join; int ret, i; u8 *bssid; - /* FIXME: remove when we get calibration from the factory */ - if (do_cal) { - ret = wl1271_cmd_cal(wl); - if (ret < 0) - wl1271_warning("couldn't calibrate"); - else - do_cal = false; - } - join = kzalloc(sizeof(*join), GFP_KERNEL); if (!join) { ret = -ENOMEM; -- cgit v1.2.3 From 849923f43ca681cc86a401178db31acb60e79f3b Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Thu, 8 Jul 2010 17:49:59 +0300 Subject: wl1271: Use all basic rates for ps-poll, instead of just the slowest This improves ps-poll handling in WLAN PSM. It also improves performance, including WLAN-BT co-existence reliability. 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_cmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/wl12xx/wl1271_cmd.c') diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index 8307f21053f..834f7f8e9c7 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -703,7 +703,7 @@ int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid) goto out; ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, skb->data, - skb->len, 0, wl->basic_rate); + skb->len, 0, wl->basic_rate_set); out: dev_kfree_skb(skb); -- 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_cmd.c | 6 +++--- drivers/net/wireless/wl12xx/wl1271_conf.h | 9 --------- drivers/net/wireless/wl12xx/wl1271_main.c | 5 ----- 3 files changed, 3 insertions(+), 17 deletions(-) (limited to 'drivers/net/wireless/wl12xx/wl1271_cmd.c') diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index 834f7f8e9c7..23c75988f08 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -132,7 +132,7 @@ int wl1271_cmd_general_parms(struct wl1271 *wl) int wl1271_cmd_radio_parms(struct wl1271 *wl) { struct wl1271_radio_parms_cmd *radio_parms; - struct conf_radio_parms *rparam = &wl->conf.init.radioparam; + struct wl1271_ini_general_params *gp = &wl->nvs->general_params; int ret; if (!wl->nvs) @@ -148,7 +148,7 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl) memcpy(&radio_parms->static_params_2, &wl->nvs->stat_radio_params_2, sizeof(struct wl1271_ini_band_params_2)); memcpy(&radio_parms->dyn_params_2, - &wl->nvs->dyn_radio_params_2[rparam->fem].params, + &wl->nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params, sizeof(struct wl1271_ini_fem_params_2)); /* 5GHz parameters */ @@ -156,7 +156,7 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl) &wl->nvs->stat_radio_params_5, sizeof(struct wl1271_ini_band_params_5)); memcpy(&radio_parms->dyn_params_5, - &wl->nvs->dyn_radio_params_5[rparam->fem].params, + &wl->nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params, sizeof(struct wl1271_ini_fem_params_5)); wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ", diff --git a/drivers/net/wireless/wl12xx/wl1271_conf.h b/drivers/net/wireless/wl12xx/wl1271_conf.h index 84b0de7f4bc..0435ffda8f7 100644 --- a/drivers/net/wireless/wl12xx/wl1271_conf.h +++ b/drivers/net/wireless/wl12xx/wl1271_conf.h @@ -955,14 +955,6 @@ struct conf_radio_parms { u8 fem; }; -struct conf_init_settings { - /* - * Configure radio parameters. - */ - struct conf_radio_parms radioparam; - -}; - struct conf_itrim_settings { /* enable dco itrim */ u8 enable; @@ -1029,7 +1021,6 @@ struct conf_drv_settings { struct conf_rx_settings rx; struct conf_tx_settings tx; struct conf_conn_settings conn; - struct conf_init_settings init; struct conf_itrim_settings itrim; struct conf_pm_config_settings pm_config; struct conf_roam_trigger_settings roam_trigger; diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 8a4b17f74db..3a648963fbe 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 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/Makefile | 2 +- drivers/net/wireless/wl12xx/wl1271_cmd.c | 136 -------------------- drivers/net/wireless/wl12xx/wl1271_cmd.h | 68 ---------- drivers/net/wireless/wl12xx/wl1271_event.c | 36 +----- drivers/net/wireless/wl12xx/wl1271_main.c | 9 +- drivers/net/wireless/wl12xx/wl1271_scan.c | 191 +++++++++++++++++++++++++++++ drivers/net/wireless/wl12xx/wl1271_scan.h | 101 +++++++++++++++ 7 files changed, 303 insertions(+), 240 deletions(-) create mode 100644 drivers/net/wireless/wl12xx/wl1271_scan.c create mode 100644 drivers/net/wireless/wl12xx/wl1271_scan.h (limited to 'drivers/net/wireless/wl12xx/wl1271_cmd.c') diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile index 27ddd2be0a9..078b4398ac1 100644 --- a/drivers/net/wireless/wl12xx/Makefile +++ b/drivers/net/wireless/wl12xx/Makefile @@ -10,7 +10,7 @@ obj-$(CONFIG_WL1251_SDIO) += wl1251_sdio.o wl1271-objs = wl1271_main.o wl1271_cmd.o wl1271_io.o \ wl1271_event.o wl1271_tx.o wl1271_rx.o \ wl1271_ps.o wl1271_acx.o wl1271_boot.o \ - wl1271_init.o wl1271_debugfs.o + wl1271_init.o wl1271_debugfs.o wl1271_scan.o wl1271-$(CONFIG_NL80211_TESTMODE) += wl1271_testmode.o obj-$(CONFIG_WL1271) += wl1271.o diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index 23c75988f08..ce503ddd5a4 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -463,142 +463,6 @@ out: return ret; } -int wl1271_cmd_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, - struct cfg80211_scan_request *req, u8 active_scan, - u8 high_prio, u8 band, u8 probe_requests) -{ - - struct wl1271_cmd_trigger_scan_to *trigger = NULL; - struct wl1271_cmd_scan *params = NULL; - struct ieee80211_channel *channels; - u32 rate; - int i, j, n_ch, ret; - u16 scan_options = 0; - u8 ieee_band; - - if (band == WL1271_SCAN_BAND_2_4_GHZ) { - ieee_band = IEEE80211_BAND_2GHZ; - rate = wl->conf.tx.basic_rate; - } else if (band == WL1271_SCAN_BAND_DUAL && wl1271_11a_enabled()) { - ieee_band = IEEE80211_BAND_2GHZ; - rate = wl->conf.tx.basic_rate; - } else if (band == WL1271_SCAN_BAND_5_GHZ && wl1271_11a_enabled()) { - ieee_band = IEEE80211_BAND_5GHZ; - rate = wl->conf.tx.basic_rate_5; - } else - return -EINVAL; - - if (wl->hw->wiphy->bands[ieee_band]->channels == NULL) - return -EINVAL; - - channels = wl->hw->wiphy->bands[ieee_band]->channels; - n_ch = wl->hw->wiphy->bands[ieee_band]->n_channels; - - if (test_bit(WL1271_FLAG_SCANNING, &wl->flags)) - return -EINVAL; - - params = kzalloc(sizeof(*params), GFP_KERNEL); - if (!params) - return -ENOMEM; - - params->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD); - params->params.rx_filter_options = - cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN); - - if (!active_scan) - scan_options |= WL1271_SCAN_OPT_PASSIVE; - if (high_prio) - scan_options |= WL1271_SCAN_OPT_PRIORITY_HIGH; - params->params.scan_options = cpu_to_le16(scan_options); - - params->params.num_probe_requests = probe_requests; - params->params.tx_rate = cpu_to_le32(rate); - params->params.tid_trigger = 0; - params->params.scan_tag = WL1271_SCAN_DEFAULT_TAG; - - if (band == WL1271_SCAN_BAND_DUAL) - params->params.band = WL1271_SCAN_BAND_2_4_GHZ; - else - params->params.band = band; - - for (i = 0, j = 0; i < n_ch && i < WL1271_SCAN_MAX_CHANNELS; i++) { - if (!(channels[i].flags & IEEE80211_CHAN_DISABLED)) { - params->channels[j].min_duration = - cpu_to_le32(WL1271_SCAN_CHAN_MIN_DURATION); - params->channels[j].max_duration = - cpu_to_le32(WL1271_SCAN_CHAN_MAX_DURATION); - memset(¶ms->channels[j].bssid_lsb, 0xff, 4); - memset(¶ms->channels[j].bssid_msb, 0xff, 2); - params->channels[j].early_termination = 0; - params->channels[j].tx_power_att = - WL1271_SCAN_CURRENT_TX_PWR; - params->channels[j].channel = channels[i].hw_value; - j++; - } - } - - params->params.num_channels = j; - - if (ssid_len && ssid) { - params->params.ssid_len = ssid_len; - memcpy(params->params.ssid, ssid, ssid_len); - } - - ret = wl1271_cmd_build_probe_req(wl, ssid, ssid_len, - req->ie, req->ie_len, ieee_band); - if (ret < 0) { - wl1271_error("PROBE request template failed"); - goto out; - } - - trigger = kzalloc(sizeof(*trigger), GFP_KERNEL); - if (!trigger) { - ret = -ENOMEM; - goto out; - } - - /* disable the timeout */ - trigger->timeout = 0; - - ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger, - sizeof(*trigger), 0); - if (ret < 0) { - wl1271_error("trigger scan to failed for hw scan"); - goto out; - } - - wl1271_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params)); - - set_bit(WL1271_FLAG_SCANNING, &wl->flags); - if (wl1271_11a_enabled()) { - wl->scan.state = band; - if (band == WL1271_SCAN_BAND_DUAL) { - wl->scan.active = active_scan; - wl->scan.high_prio = high_prio; - wl->scan.probe_requests = probe_requests; - if (ssid_len && ssid) { - wl->scan.ssid_len = ssid_len; - memcpy(wl->scan.ssid, ssid, ssid_len); - } else - wl->scan.ssid_len = 0; - wl->scan.req = req; - } else - wl->scan.req = NULL; - } - - ret = wl1271_cmd_send(wl, CMD_SCAN, params, sizeof(*params), 0); - if (ret < 0) { - wl1271_error("SCAN failed"); - clear_bit(WL1271_FLAG_SCANNING, &wl->flags); - goto out; - } - -out: - kfree(params); - kfree(trigger); - 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 68001dffe71..34cd013ae5b 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.h +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.h @@ -41,9 +41,6 @@ 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_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, - struct cfg80211_scan_request *req, u8 active_scan, - u8 high_prio, u8 band, u8 probe_requests); 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); @@ -350,71 +347,6 @@ struct wl1271_cmd_set_keys { __le32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY]; } __attribute__ ((packed)); - -#define WL1271_SCAN_MAX_CHANNELS 24 -#define WL1271_SCAN_DEFAULT_TAG 1 -#define WL1271_SCAN_CURRENT_TX_PWR 0 -#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_BAND_DUAL 2 - -struct basic_scan_params { - __le32 rx_config_options; - __le32 rx_filter_options; - /* Scan option flags (WL1271_SCAN_OPT_*) */ - __le16 scan_options; - /* Number of scan channels in the list (maximum 30) */ - u8 num_channels; - /* This field indicates the number of probe requests to send - per channel for an active scan */ - u8 num_probe_requests; - /* Rate bit field for sending the probes */ - __le32 tx_rate; - u8 tid_trigger; - u8 ssid_len; - /* in order to align */ - u8 padding1[2]; - u8 ssid[IW_ESSID_MAX_SIZE]; - /* Band to scan */ - u8 band; - u8 use_ssid_list; - u8 scan_tag; - u8 padding2; -} __attribute__ ((packed)); - -struct basic_scan_channel_params { - /* Duration in TU to wait for frames on a channel for active scan */ - __le32 min_duration; - __le32 max_duration; - __le32 bssid_lsb; - __le16 bssid_msb; - u8 early_termination; - u8 tx_power_att; - u8 channel; - /* FW internal use only! */ - u8 dfs_candidate; - u8 activity_detected; - u8 pad; -} __attribute__ ((packed)); - -struct wl1271_cmd_scan { - struct wl1271_cmd_header header; - - struct basic_scan_params params; - struct basic_scan_channel_params channels[WL1271_SCAN_MAX_CHANNELS]; -} __attribute__ ((packed)); - -struct wl1271_cmd_trigger_scan_to { - struct wl1271_cmd_header header; - - __le32 timeout; -} __attribute__ ((packed)); - struct wl1271_cmd_test_header { u8 id; u8 padding[3]; diff --git a/drivers/net/wireless/wl12xx/wl1271_event.c b/drivers/net/wireless/wl12xx/wl1271_event.c index 2d60d225744..3bdae892c29 100644 --- a/drivers/net/wireless/wl12xx/wl1271_event.c +++ b/drivers/net/wireless/wl12xx/wl1271_event.c @@ -26,6 +26,7 @@ #include "wl1271_io.h" #include "wl1271_event.h" #include "wl1271_ps.h" +#include "wl1271_scan.h" #include "wl12xx_80211.h" void wl1271_pspoll_work(struct work_struct *work) @@ -85,36 +86,6 @@ static void wl1271_event_pspoll_delivery_fail(struct wl1271 *wl) */ } -static int wl1271_event_scan_complete(struct wl1271 *wl, - struct event_mailbox *mbox) -{ - wl1271_debug(DEBUG_EVENT, "status: 0x%x", - mbox->scheduled_scan_status); - - if (test_bit(WL1271_FLAG_SCANNING, &wl->flags)) { - if (wl->scan.state == WL1271_SCAN_BAND_DUAL) { - /* 2.4 GHz band scanned, scan 5 GHz band, pretend - * to the wl1271_cmd_scan function that we are not - * scanning as it checks that. - */ - clear_bit(WL1271_FLAG_SCANNING, &wl->flags); - /* FIXME: ie missing! */ - wl1271_cmd_scan(wl, wl->scan.ssid, wl->scan.ssid_len, - wl->scan.req, - wl->scan.active, - wl->scan.high_prio, - WL1271_SCAN_BAND_5_GHZ, - wl->scan.probe_requests); - } else { - mutex_unlock(&wl->mutex); - ieee80211_scan_completed(wl->hw, false); - mutex_lock(&wl->mutex); - clear_bit(WL1271_FLAG_SCANNING, &wl->flags); - } - } - return 0; -} - static int wl1271_event_ps_report(struct wl1271 *wl, struct event_mailbox *mbox, bool *beacon_loss) @@ -220,7 +191,10 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) wl1271_debug(DEBUG_EVENT, "vector: 0x%x", vector); if (vector & SCAN_COMPLETE_EVENT_ID) { - ret = wl1271_event_scan_complete(wl, mbox); + wl1271_debug(DEBUG_EVENT, "status: 0x%x", + mbox->scheduled_scan_status); + + ret = wl1271_scan_complete(wl); if (ret < 0) return ret; } diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 70c6b0d2235..cdfcc054efe 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); diff --git a/drivers/net/wireless/wl12xx/wl1271_scan.c b/drivers/net/wireless/wl12xx/wl1271_scan.c new file mode 100644 index 00000000000..eb9b4ece4ec --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_scan.c @@ -0,0 +1,191 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2009-2010 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include + +#include "wl1271.h" +#include "wl1271_cmd.h" +#include "wl1271_scan.h" +#include "wl1271_acx.h" + +int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, + struct cfg80211_scan_request *req, u8 active_scan, + u8 high_prio, u8 band, u8 probe_requests) +{ + + struct wl1271_cmd_trigger_scan_to *trigger = NULL; + struct wl1271_cmd_scan *params = NULL; + struct ieee80211_channel *channels; + u32 rate; + int i, j, n_ch, ret; + u16 scan_options = 0; + u8 ieee_band; + + if (band == WL1271_SCAN_BAND_2_4_GHZ) { + ieee_band = IEEE80211_BAND_2GHZ; + rate = wl->conf.tx.basic_rate; + } else if (band == WL1271_SCAN_BAND_DUAL && wl1271_11a_enabled()) { + ieee_band = IEEE80211_BAND_2GHZ; + rate = wl->conf.tx.basic_rate; + } else if (band == WL1271_SCAN_BAND_5_GHZ && wl1271_11a_enabled()) { + ieee_band = IEEE80211_BAND_5GHZ; + rate = wl->conf.tx.basic_rate_5; + } else + return -EINVAL; + + if (wl->hw->wiphy->bands[ieee_band]->channels == NULL) + return -EINVAL; + + channels = wl->hw->wiphy->bands[ieee_band]->channels; + n_ch = wl->hw->wiphy->bands[ieee_band]->n_channels; + + if (test_bit(WL1271_FLAG_SCANNING, &wl->flags)) + return -EINVAL; + + params = kzalloc(sizeof(*params), GFP_KERNEL); + if (!params) + return -ENOMEM; + + params->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD); + params->params.rx_filter_options = + cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN); + + if (!active_scan) + scan_options |= WL1271_SCAN_OPT_PASSIVE; + if (high_prio) + scan_options |= WL1271_SCAN_OPT_PRIORITY_HIGH; + params->params.scan_options = cpu_to_le16(scan_options); + + params->params.num_probe_requests = probe_requests; + params->params.tx_rate = cpu_to_le32(rate); + params->params.tid_trigger = 0; + params->params.scan_tag = WL1271_SCAN_DEFAULT_TAG; + + if (band == WL1271_SCAN_BAND_DUAL) + params->params.band = WL1271_SCAN_BAND_2_4_GHZ; + else + params->params.band = band; + + for (i = 0, j = 0; i < n_ch && i < WL1271_SCAN_MAX_CHANNELS; i++) { + if (!(channels[i].flags & IEEE80211_CHAN_DISABLED)) { + params->channels[j].min_duration = + cpu_to_le32(WL1271_SCAN_CHAN_MIN_DURATION); + params->channels[j].max_duration = + cpu_to_le32(WL1271_SCAN_CHAN_MAX_DURATION); + memset(¶ms->channels[j].bssid_lsb, 0xff, 4); + memset(¶ms->channels[j].bssid_msb, 0xff, 2); + params->channels[j].early_termination = 0; + params->channels[j].tx_power_att = + WL1271_SCAN_CURRENT_TX_PWR; + params->channels[j].channel = channels[i].hw_value; + j++; + } + } + + params->params.num_channels = j; + + if (ssid_len && ssid) { + params->params.ssid_len = ssid_len; + memcpy(params->params.ssid, ssid, ssid_len); + } + + ret = wl1271_cmd_build_probe_req(wl, ssid, ssid_len, + req->ie, req->ie_len, ieee_band); + if (ret < 0) { + wl1271_error("PROBE request template failed"); + goto out; + } + + trigger = kzalloc(sizeof(*trigger), GFP_KERNEL); + if (!trigger) { + ret = -ENOMEM; + goto out; + } + + /* disable the timeout */ + trigger->timeout = 0; + + ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger, + sizeof(*trigger), 0); + if (ret < 0) { + wl1271_error("trigger scan to failed for hw scan"); + goto out; + } + + wl1271_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params)); + + set_bit(WL1271_FLAG_SCANNING, &wl->flags); + if (wl1271_11a_enabled()) { + wl->scan.state = band; + if (band == WL1271_SCAN_BAND_DUAL) { + wl->scan.active = active_scan; + wl->scan.high_prio = high_prio; + wl->scan.probe_requests = probe_requests; + if (ssid_len && ssid) { + wl->scan.ssid_len = ssid_len; + memcpy(wl->scan.ssid, ssid, ssid_len); + } else + wl->scan.ssid_len = 0; + wl->scan.req = req; + } else + wl->scan.req = NULL; + } + + ret = wl1271_cmd_send(wl, CMD_SCAN, params, sizeof(*params), 0); + if (ret < 0) { + wl1271_error("SCAN failed"); + clear_bit(WL1271_FLAG_SCANNING, &wl->flags); + goto out; + } + +out: + kfree(params); + kfree(trigger); + return ret; +} + +int wl1271_scan_complete(struct wl1271 *wl) +{ + if (test_bit(WL1271_FLAG_SCANNING, &wl->flags)) { + if (wl->scan.state == WL1271_SCAN_BAND_DUAL) { + /* 2.4 GHz band scanned, scan 5 GHz band, pretend to + * the wl1271_scan function that we are not scanning + * as it checks that. + */ + clear_bit(WL1271_FLAG_SCANNING, &wl->flags); + /* FIXME: ie missing! */ + wl1271_scan(wl, wl->scan.ssid, wl->scan.ssid_len, + wl->scan.req, + wl->scan.active, + wl->scan.high_prio, + WL1271_SCAN_BAND_5_GHZ, + wl->scan.probe_requests); + } else { + mutex_unlock(&wl->mutex); + ieee80211_scan_completed(wl->hw, false); + mutex_lock(&wl->mutex); + clear_bit(WL1271_FLAG_SCANNING, &wl->flags); + } + } + return 0; +} diff --git a/drivers/net/wireless/wl12xx/wl1271_scan.h b/drivers/net/wireless/wl12xx/wl1271_scan.h new file mode 100644 index 00000000000..0002e815cb4 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_scan.h @@ -0,0 +1,101 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2009-2010 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL1271_SCAN_H__ +#define __WL1271_SCAN_H__ + +#include "wl1271.h" + +int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, + struct cfg80211_scan_request *req, u8 active_scan, + u8 high_prio, u8 band, u8 probe_requests); +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); +int wl1271_scan_complete(struct wl1271 *wl); + +#define WL1271_SCAN_MAX_CHANNELS 24 +#define WL1271_SCAN_DEFAULT_TAG 1 +#define WL1271_SCAN_CURRENT_TX_PWR 0 +#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_BAND_DUAL 2 + +struct basic_scan_params { + __le32 rx_config_options; + __le32 rx_filter_options; + /* Scan option flags (WL1271_SCAN_OPT_*) */ + __le16 scan_options; + /* Number of scan channels in the list (maximum 30) */ + u8 num_channels; + /* This field indicates the number of probe requests to send + per channel for an active scan */ + u8 num_probe_requests; + /* Rate bit field for sending the probes */ + __le32 tx_rate; + u8 tid_trigger; + u8 ssid_len; + /* in order to align */ + u8 padding1[2]; + u8 ssid[IW_ESSID_MAX_SIZE]; + /* Band to scan */ + u8 band; + u8 use_ssid_list; + u8 scan_tag; + u8 padding2; +} __attribute__ ((packed)); + +struct basic_scan_channel_params { + /* Duration in TU to wait for frames on a channel for active scan */ + __le32 min_duration; + __le32 max_duration; + __le32 bssid_lsb; + __le16 bssid_msb; + u8 early_termination; + u8 tx_power_att; + u8 channel; + /* FW internal use only! */ + u8 dfs_candidate; + u8 activity_detected; + u8 pad; +} __attribute__ ((packed)); + +struct wl1271_cmd_scan { + struct wl1271_cmd_header header; + + struct basic_scan_params params; + struct basic_scan_channel_params channels[WL1271_SCAN_MAX_CHANNELS]; +} __attribute__ ((packed)); + +struct wl1271_cmd_trigger_scan_to { + struct wl1271_cmd_header header; + + __le32 timeout; +} __attribute__ ((packed)); + +#endif /* __WL1271_SCAN_H__ */ -- cgit v1.2.3