summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/ti/wl18xx
diff options
context:
space:
mode:
authorEliad Peller <eliad@wizery.com>2012-11-22 16:06:15 (GMT)
committerLuciano Coelho <coelho@ti.com>2012-11-27 08:49:27 (GMT)
commit78e28062fea51c62280cd17fe6143ed583f83ba0 (patch)
treef597ab46488569478a7ed56f3a575076a4ddd090 /drivers/net/wireless/ti/wl18xx
parente9b9d4550733dc322cd0d191e0423a480d9180ef (diff)
downloadlinux-fsl-qoriq-78e28062fea51c62280cd17fe6143ed583f83ba0.tar.xz
wlcore: split 18xx and 12xx scan mechanism
The scan APIs of 12xx and 18xx are totally different. Use some common functions as much as possible (e.g. for setting scan channels), but split scan.c into chip-specific scan.c files, each implementing its own scan mechanism. (in other words - move most of the current wlcore's scan.c into wl12xx, and implement a similar mechanism in 18xx, according to the new api) New wlcore ops are introduced in order to call the chip-specific scan functions. The template indices used for each scan (regular/scheduled) are also different between the chips, so set the correct indices used for each scan type after identifying the chip. Signed-off-by: Eliad Peller <eliad@wizery.com> Signed-off-by: Luciano Coelho <coelho@ti.com>
Diffstat (limited to 'drivers/net/wireless/ti/wl18xx')
-rw-r--r--drivers/net/wireless/ti/wl18xx/Makefile2
-rw-r--r--drivers/net/wireless/ti/wl18xx/main.c13
-rw-r--r--drivers/net/wireless/ti/wl18xx/scan.c320
-rw-r--r--drivers/net/wireless/ti/wl18xx/scan.h120
4 files changed, 453 insertions, 2 deletions
diff --git a/drivers/net/wireless/ti/wl18xx/Makefile b/drivers/net/wireless/ti/wl18xx/Makefile
index 67c0987..f742249 100644
--- a/drivers/net/wireless/ti/wl18xx/Makefile
+++ b/drivers/net/wireless/ti/wl18xx/Makefile
@@ -1,3 +1,3 @@
-wl18xx-objs = main.o acx.o tx.o io.o debugfs.o
+wl18xx-objs = main.o acx.o tx.o io.o debugfs.o scan.o
obj-$(CONFIG_WL18XX) += wl18xx.o
diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c
index 8ba1c93..97c23c8 100644
--- a/drivers/net/wireless/ti/wl18xx/main.c
+++ b/drivers/net/wireless/ti/wl18xx/main.c
@@ -38,6 +38,7 @@
#include "tx.h"
#include "wl18xx.h"
#include "io.h"
+#include "scan.h"
#include "debugfs.h"
#define WL18XX_RX_CHECKSUM_MASK 0x40
@@ -612,7 +613,8 @@ static int wl18xx_identify_chip(struct wl1271 *wl)
WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN |
WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN |
WLCORE_QUIRK_NO_SCHED_SCAN_WHILE_CONN |
- WLCORE_QUIRK_TX_PAD_LAST_FRAME;
+ WLCORE_QUIRK_TX_PAD_LAST_FRAME |
+ WLCORE_QUIRK_DUAL_PROBE_TMPL;
wlcore_set_min_fw_ver(wl, WL18XX_CHIP_VER, WL18XX_IFTYPE_VER,
WL18XX_MAJOR_VER, WL18XX_SUBTYPE_VER,
@@ -630,6 +632,10 @@ static int wl18xx_identify_chip(struct wl1271 *wl)
goto out;
}
+ wl->scan_templ_id_2_4 = CMD_TEMPL_CFG_PROBE_REQ_2_4;
+ wl->scan_templ_id_5 = CMD_TEMPL_CFG_PROBE_REQ_5;
+ wl->sched_scan_templ_id_2_4 = CMD_TEMPL_PROBE_REQ_2_4_PERIODIC;
+ wl->sched_scan_templ_id_5 = CMD_TEMPL_PROBE_REQ_5_PERIODIC;
out:
return ret;
}
@@ -1320,6 +1326,11 @@ static struct wlcore_ops wl18xx_ops = {
.ap_get_mimo_wide_rate_mask = wl18xx_ap_get_mimo_wide_rate_mask,
.get_mac = wl18xx_get_mac,
.debugfs_init = wl18xx_debugfs_add_files,
+ .scan_start = wl18xx_scan_start,
+ .scan_stop = wl18xx_scan_stop,
+ .scan_completed = wl18xx_scan_completed,
+ .sched_scan_start = wl18xx_sched_scan_start,
+ .sched_scan_stop = wl18xx_scan_sched_scan_stop,
.handle_static_data = wl18xx_handle_static_data,
.get_spare_blocks = wl18xx_get_spare_blocks,
.set_key = wl18xx_set_key,
diff --git a/drivers/net/wireless/ti/wl18xx/scan.c b/drivers/net/wireless/ti/wl18xx/scan.c
new file mode 100644
index 0000000..f31d0d4
--- /dev/null
+++ b/drivers/net/wireless/ti/wl18xx/scan.c
@@ -0,0 +1,320 @@
+/*
+ * This file is part of wl18xx
+ *
+ * Copyright (C) 2012 Texas Instruments. All rights reserved.
+ *
+ * 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 <linux/ieee80211.h>
+#include "scan.h"
+#include "../wlcore/debug.h"
+
+static void wl18xx_adjust_channels(struct wl18xx_cmd_scan_params *cmd,
+ struct wlcore_scan_channels *cmd_channels)
+{
+ memcpy(cmd->passive, cmd_channels->passive, sizeof(cmd->passive));
+ memcpy(cmd->active, cmd_channels->active, sizeof(cmd->active));
+ cmd->dfs = cmd_channels->dfs;
+ cmd->passive_active = cmd_channels->passive_active;
+
+ memcpy(cmd->channels_2, cmd_channels->channels_2,
+ sizeof(cmd->channels_2));
+ memcpy(cmd->channels_5, cmd_channels->channels_5,
+ sizeof(cmd->channels_2));
+ /* channels_4 are not supported, so no need to copy them */
+}
+
+static int wl18xx_scan_send(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ struct cfg80211_scan_request *req)
+{
+ struct wl18xx_cmd_scan_params *cmd;
+ struct wlcore_scan_channels *cmd_channels = NULL;
+ int ret;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ cmd->role_id = wlvif->role_id;
+
+ if (WARN_ON(cmd->role_id == WL12XX_INVALID_ROLE_ID)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ cmd->scan_type = SCAN_TYPE_SEARCH;
+ cmd->rssi_threshold = -127;
+ cmd->snr_threshold = 0;
+
+ cmd->bss_type = SCAN_BSS_TYPE_ANY;
+
+ cmd->ssid_from_list = 0;
+ cmd->filter = 0;
+ cmd->add_broadcast = 0;
+
+ cmd->urgency = 0;
+ cmd->protect = 0;
+
+ cmd->n_probe_reqs = wl->conf.scan.num_probe_reqs;
+ cmd->terminate_after = 0;
+
+ /* configure channels */
+ WARN_ON(req->n_ssids > 1);
+
+ cmd_channels = kzalloc(sizeof(*cmd_channels), GFP_KERNEL);
+ if (!cmd_channels) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ wlcore_set_scan_chan_params(wl, cmd_channels, req->channels,
+ req->n_channels, req->n_ssids);
+ wl18xx_adjust_channels(cmd, cmd_channels);
+
+ /*
+ * all the cycles params (except total cycles) should
+ * remain 0 for normal scan
+ */
+ cmd->total_cycles = 1;
+
+ if (req->no_cck)
+ cmd->rate = WL18XX_SCAN_RATE_6;
+
+ cmd->tag = WL1271_SCAN_DEFAULT_TAG;
+
+ if (req->n_ssids) {
+ cmd->ssid_len = req->ssids[0].ssid_len;
+ memcpy(cmd->ssid, req->ssids[0].ssid, cmd->ssid_len);
+ }
+
+ /* TODO: per-band ies? */
+ if (cmd->active[0]) {
+ u8 band = IEEE80211_BAND_2GHZ;
+ ret = wl12xx_cmd_build_probe_req(wl, wlvif,
+ cmd->role_id, band,
+ req->ssids[0].ssid,
+ req->ssids[0].ssid_len,
+ req->ie,
+ req->ie_len,
+ false);
+ if (ret < 0) {
+ wl1271_error("2.4GHz PROBE request template failed");
+ goto out;
+ }
+ }
+
+ if (cmd->active[1]) {
+ u8 band = IEEE80211_BAND_5GHZ;
+ ret = wl12xx_cmd_build_probe_req(wl, wlvif,
+ cmd->role_id, band,
+ req->ssids[0].ssid,
+ req->ssids[0].ssid_len,
+ req->ie,
+ req->ie_len,
+ false);
+ if (ret < 0) {
+ wl1271_error("5GHz PROBE request template failed");
+ goto out;
+ }
+ }
+
+ wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd));
+
+ ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("SCAN failed");
+ goto out;
+ }
+
+out:
+ kfree(cmd_channels);
+ kfree(cmd);
+ return ret;
+}
+
+void wl18xx_scan_completed(struct wl1271 *wl, struct wl12xx_vif *wlvif)
+{
+ 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));
+}
+
+static
+int wl18xx_scan_sched_scan_config(struct wl1271 *wl,
+ struct wl12xx_vif *wlvif,
+ struct cfg80211_sched_scan_request *req,
+ struct ieee80211_sched_scan_ies *ies)
+{
+ struct wl18xx_cmd_scan_params *cmd;
+ struct wlcore_scan_channels *cmd_channels = NULL;
+ struct conf_sched_scan_settings *c = &wl->conf.sched_scan;
+ int ret;
+ int filter_type;
+
+ wl1271_debug(DEBUG_CMD, "cmd sched_scan scan config");
+
+ filter_type = wlcore_scan_sched_scan_ssid_list(wl, wlvif, req);
+ if (filter_type < 0)
+ return filter_type;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ cmd->role_id = wlvif->role_id;
+
+ if (WARN_ON(cmd->role_id == WL12XX_INVALID_ROLE_ID)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ cmd->scan_type = SCAN_TYPE_PERIODIC;
+ cmd->rssi_threshold = c->rssi_threshold;
+ cmd->snr_threshold = c->snr_threshold;
+
+ /* don't filter on BSS type */
+ cmd->bss_type = SCAN_BSS_TYPE_ANY;
+
+ cmd->ssid_from_list = 1;
+ if (filter_type == SCAN_SSID_FILTER_LIST)
+ cmd->filter = 1;
+ cmd->add_broadcast = 0;
+
+ cmd->urgency = 0;
+ cmd->protect = 0;
+
+ cmd->n_probe_reqs = c->num_probe_reqs;
+ /* don't stop scanning automatically when something is found */
+ cmd->terminate_after = 0;
+
+ cmd_channels = kzalloc(sizeof(*cmd_channels), GFP_KERNEL);
+ if (!cmd_channels) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* configure channels */
+ wlcore_set_scan_chan_params(wl, cmd_channels, req->channels,
+ req->n_channels, req->n_ssids);
+ wl18xx_adjust_channels(cmd, cmd_channels);
+
+ cmd->short_cycles_sec = 0;
+ cmd->long_cycles_sec = cpu_to_le16(req->interval);
+ cmd->short_cycles_count = 0;
+
+ cmd->total_cycles = 0;
+
+ cmd->tag = WL1271_SCAN_DEFAULT_TAG;
+
+ if (cmd->active[0]) {
+ u8 band = IEEE80211_BAND_2GHZ;
+ ret = wl12xx_cmd_build_probe_req(wl, wlvif,
+ cmd->role_id, band,
+ req->ssids[0].ssid,
+ req->ssids[0].ssid_len,
+ ies->ie[band],
+ ies->len[band],
+ true);
+ if (ret < 0) {
+ wl1271_error("2.4GHz PROBE request template failed");
+ goto out;
+ }
+ }
+
+ if (cmd->active[1]) {
+ u8 band = IEEE80211_BAND_5GHZ;
+ ret = wl12xx_cmd_build_probe_req(wl, wlvif,
+ cmd->role_id, band,
+ req->ssids[0].ssid,
+ req->ssids[0].ssid_len,
+ ies->ie[band],
+ ies->len[band],
+ true);
+ if (ret < 0) {
+ wl1271_error("5GHz PROBE request template failed");
+ goto out;
+ }
+ }
+
+ wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd));
+
+ ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("SCAN failed");
+ goto out;
+ }
+
+out:
+ kfree(cmd_channels);
+ kfree(cmd);
+ return ret;
+}
+
+int wl18xx_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ struct cfg80211_sched_scan_request *req,
+ struct ieee80211_sched_scan_ies *ies)
+{
+ return wl18xx_scan_sched_scan_config(wl, wlvif, req, ies);
+}
+
+static int __wl18xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ u8 scan_type)
+{
+ struct wl18xx_cmd_scan_stop *stop;
+ int ret;
+
+ wl1271_debug(DEBUG_CMD, "cmd periodic scan stop");
+
+ stop = kzalloc(sizeof(*stop), GFP_KERNEL);
+ if (!stop) {
+ wl1271_error("failed to alloc memory to send sched scan stop");
+ return -ENOMEM;
+ }
+
+ stop->role_id = wlvif->role_id;
+ stop->scan_type = scan_type;
+
+ ret = wl1271_cmd_send(wl, CMD_STOP_SCAN, stop, sizeof(*stop), 0);
+ if (ret < 0) {
+ wl1271_error("failed to send sched scan stop command");
+ goto out_free;
+ }
+
+out_free:
+ kfree(stop);
+ return ret;
+}
+
+void wl18xx_scan_sched_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif)
+{
+ __wl18xx_scan_stop(wl, wlvif, SCAN_TYPE_PERIODIC);
+}
+int wl18xx_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ struct cfg80211_scan_request *req)
+{
+ return wl18xx_scan_send(wl, wlvif, req);
+}
+
+int wl18xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif)
+{
+ return __wl18xx_scan_stop(wl, wlvif, SCAN_TYPE_SEARCH);
+}
diff --git a/drivers/net/wireless/ti/wl18xx/scan.h b/drivers/net/wireless/ti/wl18xx/scan.h
new file mode 100644
index 0000000..404baf1
--- /dev/null
+++ b/drivers/net/wireless/ti/wl18xx/scan.h
@@ -0,0 +1,120 @@
+/*
+ * This file is part of wl18xx
+ *
+ * Copyright (C) 2012 Texas Instruments. All rights reserved.
+ *
+ * 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 __WL18XX_SCAN_H__
+#define __WL18XX_SCAN_H__
+
+#include "../wlcore/wlcore.h"
+#include "../wlcore/cmd.h"
+#include "../wlcore/scan.h"
+
+struct tracking_ch_params {
+ struct conn_scan_ch_params channel;
+
+ __le32 bssid_lsb;
+ __le16 bssid_msb;
+
+ u8 padding[2];
+} __packed;
+
+enum
+{
+ SCAN_TYPE_SEARCH = 0,
+ SCAN_TYPE_PERIODIC = 1,
+ SCAN_TYPE_TRACKING = 2,
+};
+
+/* probe request rate */
+enum
+{
+ WL18XX_SCAN_RATE_1 = 0,
+ WL18XX_SCAN_RATE_5_5 = 1,
+ WL18XX_SCAN_RATE_6 = 2,
+};
+
+struct wl18xx_cmd_scan_params {
+ struct wl1271_cmd_header header;
+
+ u8 role_id;
+ u8 scan_type;
+
+ s8 rssi_threshold; /* for filtering (in dBm) */
+ s8 snr_threshold; /* for filtering (in dB) */
+
+ u8 bss_type; /* for filtering */
+ u8 ssid_from_list; /* use ssid from configured ssid list */
+ u8 filter; /* forward only results with matching ssids */
+
+ /*
+ * add broadcast ssid in addition to the configured ssids.
+ * the driver should add dummy entry for it (?).
+ */
+ u8 add_broadcast;
+
+ u8 urgency;
+ u8 protect; /* ??? */
+ u8 n_probe_reqs; /* Number of probes requests per channel */
+ u8 terminate_after; /* early terminate scan operation */
+
+ u8 passive[SCAN_MAX_BANDS]; /* number of passive scan channels */
+ u8 active[SCAN_MAX_BANDS]; /* number of active scan channels */
+ u8 dfs; /* number of dfs channels in 5ghz */
+ u8 passive_active; /* number of passive before active channels 2.4ghz */
+
+ __le16 short_cycles_sec;
+ __le16 long_cycles_sec;
+ u8 short_cycles_count;
+ u8 total_cycles; /* 0 - infinite */
+ u8 rate;
+ u8 padding[1];
+
+ union {
+ struct {
+ struct conn_scan_ch_params channels_2[MAX_CHANNELS_2GHZ];
+ struct conn_scan_ch_params channels_5[MAX_CHANNELS_5GHZ];
+ struct conn_scan_ch_params channels_4[MAX_CHANNELS_4GHZ];
+ };
+ struct tracking_ch_params channels_tracking[WL1271_SCAN_MAX_CHANNELS];
+ } ;
+
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
+ u8 ssid_len; /* For SCAN_SSID_FILTER_SPECIFIC */
+ u8 tag;
+ u8 padding1[2];
+} __packed;
+
+struct wl18xx_cmd_scan_stop {
+ struct wl1271_cmd_header header;
+
+ u8 role_id;
+ u8 scan_type;
+ u8 padding[2];
+} __packed;
+
+int wl18xx_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ struct cfg80211_scan_request *req);
+int wl18xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif);
+void wl18xx_scan_completed(struct wl1271 *wl, struct wl12xx_vif *wlvif);
+int wl18xx_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ struct cfg80211_sched_scan_request *req,
+ struct ieee80211_sched_scan_ies *ies);
+void wl18xx_scan_sched_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif);
+#endif