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

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
Loading
Loading
Loading
Loading
+66 −0
Original line number Diff line number Diff line
@@ -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);
	}
}
+59 −0
Original line number Diff line number Diff line
@@ -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
+6 −0
Original line number Diff line number Diff line
@@ -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_ */
+13 −0
Original line number Diff line number Diff line
@@ -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;

+1 −0
Original line number Diff line number Diff line
@@ -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);
		}
Loading