Commit 85afb186 authored by Avinash Patil's avatar Avinash Patil Committed by Kalle Valo

mwifiex: add cfg80211 start_radar_detection handler

This patch adds support for cfg80211 start_radar_detection handler.
Upon reception of start_radar_detection, driver prepares radar detect
command to FW.

Delayed work is queued for CAC time which sends radar detection finished
event to cfg80211.
Signed-off-by: default avatarAvinash Patil <patila@marvell.com>
Signed-off-by: default avatarQingshui Gao <gaoqs@marvell.com>
Signed-off-by: default avatarCathy Luo <cluo@marvell.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent 2ade5667
......@@ -99,3 +99,69 @@ void mwifiex_11h_process_join(struct mwifiex_private *priv, u8 **buffer,
bss_desc->cap_info_bitmap &= ~WLAN_CAPABILITY_SPECTRUM_MGMT;
}
}
/* This is DFS CAC work queue function.
* This delayed work emits CAC finished event for cfg80211 if
* CAC was started earlier.
*/
void mwifiex_dfs_cac_work_queue(struct work_struct *work)
{
struct cfg80211_chan_def chandef;
struct delayed_work *delayed_work =
container_of(work, struct delayed_work, work);
struct mwifiex_private *priv =
container_of(delayed_work, struct mwifiex_private,
dfs_cac_work);
if (WARN_ON(!priv))
return;
chandef = priv->dfs_chandef;
if (priv->wdev.cac_started) {
dev_dbg(priv->adapter->dev,
"CAC timer finished; No radar detected\n");
cfg80211_cac_event(priv->netdev, &chandef,
NL80211_RADAR_CAC_FINISHED,
GFP_KERNEL);
}
}
/* This function prepares channel report request command to FW for
* starting radar detection.
*/
int mwifiex_cmd_issue_chan_report_request(struct mwifiex_private *priv,
struct host_cmd_ds_command *cmd,
void *data_buf)
{
struct host_cmd_ds_chan_rpt_req *cr_req = &cmd->params.chan_rpt_req;
struct mwifiex_radar_params *radar_params = (void *)data_buf;
cmd->command = cpu_to_le16(HostCmd_CMD_CHAN_REPORT_REQUEST);
cmd->size = cpu_to_le16(S_DS_GEN);
le16_add_cpu(&cmd->size, sizeof(struct host_cmd_ds_chan_rpt_req));
cr_req->chan_desc.start_freq = cpu_to_le16(MWIFIEX_A_BAND_START_FREQ);
cr_req->chan_desc.chan_num = radar_params->chandef->chan->hw_value;
cr_req->chan_desc.chan_width = radar_params->chandef->width;
cr_req->msec_dwell_time = cpu_to_le32(radar_params->cac_time_ms);
dev_dbg(priv->adapter->dev,
"11h: issuing DFS Radar check for channel=%d\n",
radar_params->chandef->chan->hw_value);
return 0;
}
/* This function is to abort ongoing CAC upon stopping AP operations
* or during unload.
*/
void mwifiex_abort_cac(struct mwifiex_private *priv)
{
if (priv->wdev.cac_started) {
dev_dbg(priv->adapter->dev,
"Aborting delayed work for CAC.\n");
cancel_delayed_work_sync(&priv->dfs_cac_work);
cfg80211_cac_event(priv->netdev, &priv->dfs_chandef,
NL80211_RADAR_CAC_ABORTED, GFP_KERNEL);
}
}
......@@ -1651,6 +1651,8 @@ static int mwifiex_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
{
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
mwifiex_abort_cac(priv);
if (mwifiex_del_mgmt_ies(priv))
wiphy_err(wiphy, "Failed to delete mgmt IEs!\n");
......@@ -2383,6 +2385,7 @@ mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info,
ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
}
#define MWIFIEX_MAX_WQ_LEN 30
/*
* create a new virtual interface with the given name
*/
......@@ -2396,6 +2399,7 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
struct mwifiex_private *priv;
struct net_device *dev;
void *mdev_priv;
char dfs_cac_str[MWIFIEX_MAX_WQ_LEN];
if (!adapter)
return ERR_PTR(-EFAULT);
......@@ -2560,6 +2564,24 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
return ERR_PTR(-EFAULT);
}
strcpy(dfs_cac_str, "MWIFIEX_DFS_CAC");
strcat(dfs_cac_str, name);
priv->dfs_cac_workqueue = alloc_workqueue(dfs_cac_str,
WQ_HIGHPRI |
WQ_MEM_RECLAIM |
WQ_UNBOUND, 1);
if (!priv->dfs_cac_workqueue) {
wiphy_err(wiphy, "cannot register virtual network device\n");
free_netdev(dev);
priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
priv->netdev = NULL;
memset(&priv->wdev, 0, sizeof(priv->wdev));
priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
return ERR_PTR(-ENOMEM);
}
INIT_DELAYED_WORK(&priv->dfs_cac_work, mwifiex_dfs_cac_work_queue);
sema_init(&priv->async_sem, 1);
dev_dbg(adapter->dev, "info: %s: Marvell 802.11 Adapter\n", dev->name);
......@@ -2609,6 +2631,12 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
if (wdev->netdev->reg_state == NETREG_REGISTERED)
unregister_netdevice(wdev->netdev);
if (priv->dfs_cac_workqueue) {
flush_workqueue(priv->dfs_cac_workqueue);
destroy_workqueue(priv->dfs_cac_workqueue);
priv->dfs_cac_workqueue = NULL;
}
/* Clear the priv in adapter */
priv->netdev->ieee80211_ptr = NULL;
priv->netdev = NULL;
......@@ -3087,6 +3115,36 @@ mwifiex_cfg80211_add_station(struct wiphy *wiphy, struct net_device *dev,
return mwifiex_tdls_oper(priv, mac, MWIFIEX_TDLS_CREATE_LINK);
}
static int
mwifiex_cfg80211_start_radar_detection(struct wiphy *wiphy,
struct net_device *dev,
struct cfg80211_chan_def *chandef,
u32 cac_time_ms)
{
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
struct mwifiex_radar_params radar_params;
if (priv->adapter->scan_processing) {
dev_err(priv->adapter->dev,
"radar detection: scan already in process...\n");
return -EBUSY;
}
memset(&radar_params, 0, sizeof(struct mwifiex_radar_params));
radar_params.chandef = chandef;
radar_params.cac_time_ms = cac_time_ms;
memcpy(&priv->dfs_chandef, chandef, sizeof(priv->dfs_chandef));
if (mwifiex_send_cmd(priv, HostCmd_CMD_CHAN_REPORT_REQUEST,
HostCmd_ACT_GEN_SET, 0, &radar_params, true))
return -1;
queue_delayed_work(priv->dfs_cac_workqueue, &priv->dfs_cac_work,
msecs_to_jiffies(cac_time_ms));
return 0;
}
static int
mwifiex_cfg80211_change_station(struct wiphy *wiphy, struct net_device *dev,
const u8 *mac,
......@@ -3151,6 +3209,7 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
.tdls_oper = mwifiex_cfg80211_tdls_oper,
.add_station = mwifiex_cfg80211_add_station,
.change_station = mwifiex_cfg80211_change_station,
.start_radar_detection = mwifiex_cfg80211_start_radar_detection,
};
#ifdef CONFIG_PM
......
......@@ -108,6 +108,8 @@
#define MWIFIEX_MAX_UAP_NUM 1
#define MWIFIEX_MAX_P2P_NUM 1
#define MWIFIEX_A_BAND_START_FREQ 5000
enum mwifiex_bss_type {
MWIFIEX_BSS_TYPE_STA = 0,
MWIFIEX_BSS_TYPE_UAP = 1,
......@@ -242,4 +244,8 @@ struct mwifiex_iface_comb {
u8 p2p_intf;
};
struct mwifiex_radar_params {
struct cfg80211_chan_def *chandef;
u32 cac_time_ms;
} __packed;
#endif /* !_MWIFIEX_DECL_H_ */
......@@ -336,6 +336,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define HostCmd_CMD_11N_ADDBA_RSP 0x00cf
#define HostCmd_CMD_11N_DELBA 0x00d0
#define HostCmd_CMD_RECONFIGURE_TX_BUFF 0x00d9
#define HostCmd_CMD_CHAN_REPORT_REQUEST 0x00dd
#define HostCmd_CMD_AMSDU_AGGR_CTRL 0x00df
#define HostCmd_CMD_TXPWR_CFG 0x00d1
#define HostCmd_CMD_TX_RATE_CFG 0x00d6
......@@ -1216,6 +1217,17 @@ struct host_cmd_ds_tdls_oper {
u8 peer_mac[ETH_ALEN];
} __packed;
struct mwifiex_chan_desc {
__le16 start_freq;
u8 chan_width;
u8 chan_num;
} __packed;
struct host_cmd_ds_chan_rpt_req {
struct mwifiex_chan_desc chan_desc;
__le32 msec_dwell_time;
} __packed;
struct mwifiex_fixed_bcn_param {
__le64 timestamp;
__le16 beacon_period;
......@@ -1904,6 +1916,7 @@ struct host_cmd_ds_command {
struct host_cmd_11ac_vht_cfg vht_cfg;
struct host_cmd_ds_coalesce_cfg coalesce_cfg;
struct host_cmd_ds_tdls_oper tdls_oper;
struct host_cmd_ds_chan_rpt_req chan_rpt_req;
} params;
} __packed;
......
......@@ -681,6 +681,7 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter)
priv = adapter->priv[i];
mwifiex_clean_auto_tdls(priv);
mwifiex_abort_cac(priv);
mwifiex_clean_txrx(priv);
mwifiex_delete_bss_prio_tbl(priv);
}
......
......@@ -588,6 +588,9 @@ struct mwifiex_private {
spinlock_t ack_status_lock;
/** rx histogram data */
struct mwifiex_histogram_data *hist_data;
struct cfg80211_chan_def dfs_chandef;
struct workqueue_struct *dfs_cac_workqueue;
struct delayed_work dfs_cac_work;
};
enum mwifiex_ba_status {
......@@ -754,6 +757,8 @@ struct mwifiex_adapter {
struct work_struct main_work;
struct workqueue_struct *rx_workqueue;
struct work_struct rx_work;
struct workqueue_struct *dfs_workqueue;
struct work_struct dfs_work;
bool rx_work_enabled;
bool rx_processing;
bool delay_main_work;
......@@ -1376,6 +1381,9 @@ void mwifiex_check_auto_tdls(unsigned long context);
void mwifiex_add_auto_tdls_peer(struct mwifiex_private *priv, const u8 *mac);
void mwifiex_setup_auto_tdls_timer(struct mwifiex_private *priv);
void mwifiex_clean_auto_tdls(struct mwifiex_private *priv);
int mwifiex_cmd_issue_chan_report_request(struct mwifiex_private *priv,
struct host_cmd_ds_command *cmd,
void *data_buf);
void mwifiex_parse_tx_status_event(struct mwifiex_private *priv,
void *event_body);
......@@ -1383,6 +1391,8 @@ void mwifiex_parse_tx_status_event(struct mwifiex_private *priv,
struct sk_buff *
mwifiex_clone_skb_for_tx_status(struct mwifiex_private *priv,
struct sk_buff *skb, u8 flag, u64 *cookie);
void mwifiex_dfs_cac_work_queue(struct work_struct *work);
void mwifiex_abort_cac(struct mwifiex_private *priv);
void mwifiex_hist_data_set(struct mwifiex_private *priv, u8 rx_rate, s8 snr,
s8 nflr);
......
......@@ -1897,6 +1897,10 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
case HostCmd_CMD_TDLS_OPER:
ret = mwifiex_cmd_tdls_oper(priv, cmd_ptr, data_buf);
break;
case HostCmd_CMD_CHAN_REPORT_REQUEST:
ret = mwifiex_cmd_issue_chan_report_request(priv, cmd_ptr,
data_buf);
break;
default:
dev_err(priv->adapter->dev,
"PREP_CMD: unknown cmd- %#x\n", cmd_no);
......
......@@ -1119,6 +1119,8 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
case HostCmd_CMD_TDLS_OPER:
ret = mwifiex_ret_tdls_oper(priv, resp);
break;
case HostCmd_CMD_CHAN_REPORT_REQUEST:
break;
default:
dev_err(adapter->dev, "CMD_RESP: unknown cmd response %#x\n",
resp->command);
......
......@@ -761,6 +761,11 @@ int mwifiex_uap_prepare_cmd(struct mwifiex_private *priv, u16 cmd_no,
if (mwifiex_cmd_uap_sta_deauth(priv, cmd, data_buf))
return -1;
break;
case HostCmd_CMD_CHAN_REPORT_REQUEST:
if (mwifiex_cmd_issue_chan_report_request(priv, cmd_buf,
data_buf))
return -1;
break;
default:
dev_err(priv->adapter->dev,
"PREP_CMD: unknown cmd %#x\n", cmd_no);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment