Skip to content

Commit

Permalink
mwifiex: add schedule scan support
Browse files Browse the repository at this point in the history
This patch add sched scan support for mwifiex, include cfg80211
sched_scan_start/sched_scan_stop handler, corresponding bgscan
command path and event handler.

Signed-off-by: Xinming Hu <huxm@marvell.com>
Signed-off-by: chunfan chen <jeffc@marvell.com>
Signed-off-by: Cathy Luo <cluo@marvell.com>
Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
  • Loading branch information
Xinming Hu authored and Kalle Valo committed Jan 29, 2016
1 parent dc896b1 commit 0c9b7f2
Show file tree
Hide file tree
Showing 10 changed files with 493 additions and 0 deletions.
134 changes: 134 additions & 0 deletions drivers/net/wireless/marvell/mwifiex/cfg80211.c
Original file line number Diff line number Diff line change
Expand Up @@ -1962,6 +1962,9 @@ mwifiex_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
{
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);

if (!mwifiex_stop_bg_scan(priv))
cfg80211_sched_scan_stopped_rtnl(priv->wdev.wiphy);

if (mwifiex_deauthenticate(priv, NULL))
return -EFAULT;

Expand Down Expand Up @@ -2217,6 +2220,9 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
"info: Trying to associate to %s and bssid %pM\n",
(char *)sme->ssid, sme->bssid);

if (!mwifiex_stop_bg_scan(priv))
cfg80211_sched_scan_stopped_rtnl(priv->wdev.wiphy);

ret = mwifiex_cfg80211_assoc(priv, sme->ssid_len, sme->ssid, sme->bssid,
priv->bss_mode, sme->channel, sme, 0);
if (!ret) {
Expand Down Expand Up @@ -2420,6 +2426,9 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,
return -EBUSY;
}

if (!mwifiex_stop_bg_scan(priv))
cfg80211_sched_scan_stopped_rtnl(priv->wdev.wiphy);

user_scan_cfg = kzalloc(sizeof(*user_scan_cfg), GFP_KERNEL);
if (!user_scan_cfg)
return -ENOMEM;
Expand Down Expand Up @@ -2487,6 +2496,121 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,
return 0;
}

/* CFG802.11 operation handler for sched_scan_start.
*
* This function issues a bgscan config request to the firmware based upon
* the user specified sched_scan configuration. On successful completion,
* firmware will generate BGSCAN_REPORT event, driver should issue bgscan
* query command to get sched_scan results from firmware.
*/
static int
mwifiex_cfg80211_sched_scan_start(struct wiphy *wiphy,
struct net_device *dev,
struct cfg80211_sched_scan_request *request)
{
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
int i, offset;
struct ieee80211_channel *chan;
struct mwifiex_bg_scan_cfg *bgscan_cfg;
struct ieee_types_header *ie;

if (!request || (!request->n_ssids && !request->n_match_sets)) {
wiphy_err(wiphy, "%s : Invalid Sched_scan parameters",
__func__);
return -EINVAL;
}

wiphy_info(wiphy, "sched_scan start : n_ssids=%d n_match_sets=%d ",
request->n_ssids, request->n_match_sets);
wiphy_info(wiphy, "n_channels=%d interval=%d ie_len=%d\n",
request->n_channels, request->scan_plans->interval,
(int)request->ie_len);

bgscan_cfg = kzalloc(sizeof(*bgscan_cfg), GFP_KERNEL);
if (!bgscan_cfg)
return -ENOMEM;

if (priv->scan_request || priv->scan_aborting)
bgscan_cfg->start_later = true;

bgscan_cfg->num_ssids = request->n_match_sets;
bgscan_cfg->ssid_list = request->match_sets;

if (request->ie && request->ie_len) {
offset = 0;
for (i = 0; i < MWIFIEX_MAX_VSIE_NUM; i++) {
if (priv->vs_ie[i].mask != MWIFIEX_VSIE_MASK_CLEAR)
continue;
priv->vs_ie[i].mask = MWIFIEX_VSIE_MASK_BGSCAN;
ie = (struct ieee_types_header *)(request->ie + offset);
memcpy(&priv->vs_ie[i].ie, ie, sizeof(*ie) + ie->len);
offset += sizeof(*ie) + ie->len;

if (offset >= request->ie_len)
break;
}
}

for (i = 0; i < min_t(u32, request->n_channels,
MWIFIEX_BG_SCAN_CHAN_MAX); i++) {
chan = request->channels[i];
bgscan_cfg->chan_list[i].chan_number = chan->hw_value;
bgscan_cfg->chan_list[i].radio_type = chan->band;

if ((chan->flags & IEEE80211_CHAN_NO_IR) || !request->n_ssids)
bgscan_cfg->chan_list[i].scan_type =
MWIFIEX_SCAN_TYPE_PASSIVE;
else
bgscan_cfg->chan_list[i].scan_type =
MWIFIEX_SCAN_TYPE_ACTIVE;

bgscan_cfg->chan_list[i].scan_time = 0;
}

bgscan_cfg->chan_per_scan = min_t(u32, request->n_channels,
MWIFIEX_BG_SCAN_CHAN_MAX);

/* Use at least 15 second for per scan cycle */
bgscan_cfg->scan_interval = (request->scan_plans->interval >
MWIFIEX_BGSCAN_INTERVAL) ?
request->scan_plans->interval :
MWIFIEX_BGSCAN_INTERVAL;

bgscan_cfg->repeat_count = MWIFIEX_BGSCAN_REPEAT_COUNT;
bgscan_cfg->report_condition = MWIFIEX_BGSCAN_SSID_MATCH |
MWIFIEX_BGSCAN_WAIT_ALL_CHAN_DONE;
bgscan_cfg->bss_type = MWIFIEX_BSS_MODE_INFRA;
bgscan_cfg->action = MWIFIEX_BGSCAN_ACT_SET;
bgscan_cfg->enable = true;

if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11_BG_SCAN_CONFIG,
HostCmd_ACT_GEN_SET, 0, bgscan_cfg, true)) {
kfree(bgscan_cfg);
return -EFAULT;
}

priv->sched_scanning = true;

kfree(bgscan_cfg);
return 0;
}

/* CFG802.11 operation handler for sched_scan_stop.
*
* This function issues a bgscan config command to disable
* previous bgscan configuration in the firmware
*/
static int mwifiex_cfg80211_sched_scan_stop(struct wiphy *wiphy,
struct net_device *dev)
{
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);

wiphy_info(wiphy, "sched scan stop!");
mwifiex_stop_bg_scan(priv);

return 0;
}

static void mwifiex_setup_vht_caps(struct ieee80211_sta_vht_cap *vht_info,
struct mwifiex_private *priv)
{
Expand Down Expand Up @@ -2848,6 +2972,9 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
mwifiex_dev_debugfs_remove(priv);
#endif

if (priv->sched_scanning)
priv->sched_scanning = false;

mwifiex_stop_net_dev_queue(priv->netdev, adapter);

skb_queue_walk_safe(&priv->bypass_txq, skb, tmp)
Expand Down Expand Up @@ -3701,6 +3828,8 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
.set_cqm_rssi_config = mwifiex_cfg80211_set_cqm_rssi_config,
.set_antenna = mwifiex_cfg80211_set_antenna,
.del_station = mwifiex_cfg80211_del_station,
.sched_scan_start = mwifiex_cfg80211_sched_scan_start,
.sched_scan_stop = mwifiex_cfg80211_sched_scan_stop,
#ifdef CONFIG_PM
.suspend = mwifiex_cfg80211_suspend,
.resume = mwifiex_cfg80211_resume,
Expand Down Expand Up @@ -3829,6 +3958,7 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME |
WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD |
WIPHY_FLAG_AP_UAPSD |
WIPHY_FLAG_SUPPORTS_SCHED_SCAN |
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
WIPHY_FLAG_HAS_CHANNEL_SWITCH |
WIPHY_FLAG_PS_ON_BY_DEFAULT;
Expand All @@ -3847,6 +3977,10 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;

wiphy->max_sched_scan_ssids = MWIFIEX_MAX_SSID_LIST_LENGTH;
wiphy->max_sched_scan_ie_len = MWIFIEX_MAX_VSIE_LEN;
wiphy->max_match_sets = MWIFIEX_MAX_SSID_LIST_LENGTH;

wiphy->available_antennas_tx = BIT(adapter->number_of_antenna) - 1;
wiphy->available_antennas_rx = BIT(adapter->number_of_antenna) - 1;

Expand Down
59 changes: 59 additions & 0 deletions drivers/net/wireless/marvell/mwifiex/fw.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define TLV_TYPE_WILDCARDSSID (PROPRIETARY_TLV_BASE_ID + 18)
#define TLV_TYPE_TSFTIMESTAMP (PROPRIETARY_TLV_BASE_ID + 19)
#define TLV_TYPE_RSSI_HIGH (PROPRIETARY_TLV_BASE_ID + 22)
#define TLV_TYPE_BGSCAN_START_LATER (PROPRIETARY_TLV_BASE_ID + 30)
#define TLV_TYPE_AUTH_TYPE (PROPRIETARY_TLV_BASE_ID + 31)
#define TLV_TYPE_STA_MAC_ADDR (PROPRIETARY_TLV_BASE_ID + 32)
#define TLV_TYPE_BSSID (PROPRIETARY_TLV_BASE_ID + 35)
Expand Down Expand Up @@ -177,6 +178,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define TLV_TYPE_TX_PAUSE (PROPRIETARY_TLV_BASE_ID + 148)
#define TLV_TYPE_COALESCE_RULE (PROPRIETARY_TLV_BASE_ID + 154)
#define TLV_TYPE_KEY_PARAM_V2 (PROPRIETARY_TLV_BASE_ID + 156)
#define TLV_TYPE_REPEAT_COUNT (PROPRIETARY_TLV_BASE_ID + 176)
#define TLV_TYPE_MULTI_CHAN_INFO (PROPRIETARY_TLV_BASE_ID + 183)
#define TLV_TYPE_MC_GROUP_INFO (PROPRIETARY_TLV_BASE_ID + 184)
#define TLV_TYPE_TDLS_IDLE_TIMEOUT (PROPRIETARY_TLV_BASE_ID + 194)
Expand Down Expand Up @@ -331,6 +333,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define HostCmd_CMD_802_11_MAC_ADDRESS 0x004D
#define HostCmd_CMD_802_11D_DOMAIN_INFO 0x005b
#define HostCmd_CMD_802_11_KEY_MATERIAL 0x005e
#define HostCmd_CMD_802_11_BG_SCAN_CONFIG 0x006b
#define HostCmd_CMD_802_11_BG_SCAN_QUERY 0x006c
#define HostCmd_CMD_WMM_GET_STATUS 0x0071
#define HostCmd_CMD_802_11_SUBSCRIBE_EVENT 0x0075
Expand Down Expand Up @@ -523,6 +526,7 @@ enum P2P_MODES {
#define EVENT_CHANNEL_REPORT_RDY 0x00000054
#define EVENT_TX_DATA_PAUSE 0x00000055
#define EVENT_EXT_SCAN_REPORT 0x00000058
#define EVENT_BG_SCAN_STOPPED 0x00000065
#define EVENT_REMAIN_ON_CHAN_EXPIRED 0x0000005f
#define EVENT_MULTI_CHAN_INFO 0x0000006a
#define EVENT_TX_STATUS_REPORT 0x00000074
Expand Down Expand Up @@ -733,6 +737,16 @@ struct mwifiex_ie_types_num_probes {
__le16 num_probes;
} __packed;

struct mwifiex_ie_types_repeat_count {
struct mwifiex_ie_types_header header;
__le16 repeat_count;
} __packed;

struct mwifiex_ie_types_bgscan_start_later {
struct mwifiex_ie_types_header header;
__le16 start_later;
} __packed;

struct mwifiex_ie_types_scan_chan_gap {
struct mwifiex_ie_types_header header;
/* time gap in TUs to be used between two consecutive channels scan */
Expand Down Expand Up @@ -1425,6 +1439,36 @@ struct mwifiex_user_scan_cfg {
u16 scan_chan_gap;
} __packed;

#define MWIFIEX_BG_SCAN_CHAN_MAX 38
#define MWIFIEX_BSS_MODE_INFRA 1
#define MWIFIEX_BGSCAN_ACT_GET 0x0000
#define MWIFIEX_BGSCAN_ACT_SET 0x0001
#define MWIFIEX_BGSCAN_ACT_SET_ALL 0xff01
/** ssid match */
#define MWIFIEX_BGSCAN_SSID_MATCH 0x0001
/** ssid match and RSSI exceeded */
#define MWIFIEX_BGSCAN_SSID_RSSI_MATCH 0x0004
/**wait for all channel scan to complete to report scan result*/
#define MWIFIEX_BGSCAN_WAIT_ALL_CHAN_DONE 0x80000000

struct mwifiex_bg_scan_cfg {
u16 action;
u8 enable;
u8 bss_type;
u8 chan_per_scan;
u32 scan_interval;
u32 report_condition;
u8 num_probes;
u8 rssi_threshold;
u8 snr_threshold;
u16 repeat_count;
u16 start_later;
struct cfg80211_match_set *ssid_list;
u8 num_ssids;
struct mwifiex_user_scan_chan chan_list[MWIFIEX_BG_SCAN_CHAN_MAX];
u16 scan_chan_gap;
} __packed;

struct ie_body {
u8 grp_key_oui[4];
u8 ptk_cnt[2];
Expand Down Expand Up @@ -1470,6 +1514,20 @@ struct mwifiex_ie_types_bss_scan_info {
__le64 tsf;
} __packed;

struct host_cmd_ds_802_11_bg_scan_config {
__le16 action;
u8 enable;
u8 bss_type;
u8 chan_per_scan;
u8 reserved;
__le16 reserved1;
__le32 scan_interval;
__le32 reserved2;
__le32 report_condition;
__le16 reserved3;
u8 tlv[0];
} __packed;

struct host_cmd_ds_802_11_bg_scan_query {
u8 flush;
} __packed;
Expand Down Expand Up @@ -2124,6 +2182,7 @@ struct host_cmd_ds_command {
struct host_cmd_ds_802_11_scan scan;
struct host_cmd_ds_802_11_scan_ext ext_scan;
struct host_cmd_ds_802_11_scan_rsp scan_resp;
struct host_cmd_ds_802_11_bg_scan_config bg_scan_config;
struct host_cmd_ds_802_11_bg_scan_query bg_scan_query;
struct host_cmd_ds_802_11_bg_scan_query_rsp bg_scan_query_resp;
struct host_cmd_ds_802_11_associate associate;
Expand Down
1 change: 1 addition & 0 deletions drivers/net/wireless/marvell/mwifiex/ioctl.h
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,7 @@ struct mwifiex_ds_mef_cfg {
#define MWIFIEX_VSIE_MASK_SCAN 0x01
#define MWIFIEX_VSIE_MASK_ASSOC 0x02
#define MWIFIEX_VSIE_MASK_ADHOC 0x04
#define MWIFIEX_VSIE_MASK_BGSCAN 0x08

enum {
MWIFIEX_FUNC_INIT = 1,
Expand Down
7 changes: 7 additions & 0 deletions drivers/net/wireless/marvell/mwifiex/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -746,6 +746,13 @@ int mwifiex_queue_tx_pkt(struct mwifiex_private *priv, struct sk_buff *skb)

mwifiex_queue_main_work(priv->adapter);

if (priv->sched_scanning) {
mwifiex_dbg(priv->adapter, INFO,
"aborting bgscan on ndo_stop\n");
mwifiex_stop_bg_scan(priv);
cfg80211_sched_scan_stopped(priv->wdev.wiphy);
}

return 0;
}

Expand Down
10 changes: 10 additions & 0 deletions drivers/net/wireless/marvell/mwifiex/main.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,11 @@ do { \
buf, len, false); \
} while (0)

/** Min BGSCAN interval 15 second */
#define MWIFIEX_BGSCAN_INTERVAL 15000
/** default repeat count */
#define MWIFIEX_BGSCAN_REPEAT_COUNT 6

struct mwifiex_dbg {
u32 num_cmd_host_to_card_failure;
u32 num_cmd_sleep_cfm_host_to_card_failure;
Expand Down Expand Up @@ -641,6 +646,7 @@ struct mwifiex_private {
u32 mgmt_frame_mask;
struct mwifiex_roc_cfg roc_cfg;
bool scan_aborting;
u8 sched_scanning;
u8 csa_chan;
unsigned long csa_expire_time;
u8 del_list_idx;
Expand Down Expand Up @@ -1198,6 +1204,10 @@ int mwifiex_ret_802_11_scan_ext(struct mwifiex_private *priv,
struct host_cmd_ds_command *resp);
int mwifiex_handle_event_ext_scan_report(struct mwifiex_private *priv,
void *buf);
int mwifiex_cmd_802_11_bg_scan_config(struct mwifiex_private *priv,
struct host_cmd_ds_command *cmd,
void *data_buf);
int mwifiex_stop_bg_scan(struct mwifiex_private *priv);

/*
* This function checks if the queuing is RA based or not.
Expand Down
Loading

0 comments on commit 0c9b7f2

Please sign in to comment.