Browse Source

qcacld-3.0: API for Clear Channel Assessment

Add a vendor command to report statistics to userspace
for clear channel assessment.

Change-Id: I5c8ddc14f6661d2af7e4f3a9e1c9c844fd4cd16d
CRs-Fixed: 2773536
Min Liu 4 years ago
parent
commit
42339f116a
1 changed files with 145 additions and 0 deletions
  1. 145 0
      core/hdd/src/wlan_hdd_medium_assess.c

+ 145 - 0
core/hdd/src/wlan_hdd_medium_assess.c

@@ -25,6 +25,7 @@
 #include <osif_sync.h>
 #include <wlan_hdd_main.h>
 #include <wlan_hdd_object_manager.h>
+#include <wlan_dcs_ucfg_api.h>
 #include <wlan_cp_stats_mc_ucfg_api.h>
 #include <sme_api.h>
 #include <wma_api.h>
@@ -57,6 +58,9 @@
 #define MEDIUM_ASSESS_MAX \
 	QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_MAX
 
+#define DEFAULT_CCA_PERIOD 10	/* seconds */
+#define CCA_GET_RSSI_INTERVAL 1000	/* 1 second */
+
 #define REPORT_DISABLE 0
 #define REPORT_ENABLE 1
 
@@ -71,7 +75,147 @@ hdd_medium_assess_policy[MEDIUM_ASSESS_MAX + 1] = {
 	[CONGESTION_REPORT_INTERVAL] = {.type = NLA_U8},
 };
 
+/*
+ * get_cca_report_len() - Calculate length for CCA report
+ * to allocate skb buffer
+ *
+ * Return: skb buffer length
+ */
+static int get_cca_report_len(void)
+{
+	uint32_t data_len = NLMSG_HDRLEN;
+
+	/* QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_TYPE */
+	data_len += nla_total_size(sizeof(uint8_t));
+
+	/* QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_TOTAL_CYCLE_COUNT */
+	data_len += nla_total_size(sizeof(uint32_t));
+
+	/* QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_IDLE_COUNT */
+	data_len += nla_total_size(sizeof(uint32_t));
+
+	/* QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_IBSS_RX_COUNT */
+	data_len += nla_total_size(sizeof(uint32_t));
+
+	/* QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_OBSS_RX_COUNT */
+	data_len += nla_total_size(sizeof(uint32_t));
+
+	/* QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_MAX_IBSS_RSSI */
+	data_len += nla_total_size(sizeof(uint32_t));
+
+	/* QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_MIN_IBSS_RSSI */
+	data_len += nla_total_size(sizeof(uint32_t));
+
+	return data_len;
+}
+
+/**
+ * hdd_cca_notification_cb() - cca notification callback function
+ * @vdev_id: vdev id
+ * @stats: dcs im stats
+ * @status: status of cca statistics
+ *
+ * Return: None
+ */
+static void hdd_cca_notification_cb(uint8_t vdev_id,
+				    struct wlan_host_dcs_im_user_stats *stats,
+				    int status)
+{
+	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
+	struct hdd_adapter *adapter;
+	struct sk_buff *event;
+
+	if (wlan_hdd_validate_context(hdd_ctx))
+		return;
+
+	adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id);
+	if (!adapter) {
+		hdd_err("Failed to find adapter of vdev %d", vdev_id);
+		return;
+	}
+
+	event = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, NULL,
+				  get_cca_report_len(),
+				  QCA_NL80211_VENDOR_SUBCMD_MEDIUM_ASSESS_INDEX,
+				  GFP_KERNEL);
+	if (!event) {
+		hdd_err("cfg80211_vendor_event_alloc failed");
+		return;
+	}
+
+	if (nla_put_u8(event, MEDIUM_ASSESS_TYPE,
+		       QCA_WLAN_MEDIUM_ASSESS_CCA) ||
+	    nla_put_u32(event, TOTAL_CYCLE_COUNT, stats->cycle_count) ||
+	    nla_put_u32(event, IDLE_COUNT,
+			stats->cycle_count - stats->rxclr_count) ||
+	    nla_put_u32(event, IBSS_RX_COUNT, stats->my_bss_rx_cycle_count) ||
+	    nla_put_u32(event, OBSS_RX_COUNT,
+			stats->rx_frame_count - stats->my_bss_rx_cycle_count) ||
+	    nla_put_u32(event, MAX_IBSS_RSSI, stats->max_rssi) ||
+	    nla_put_u32(event, MIN_IBSS_RSSI, stats->min_rssi)) {
+		hdd_err("nla put failed");
+		kfree_skb(event);
+		return;
+	}
+
+	cfg80211_vendor_event(event, GFP_KERNEL);
+}
+
 /**
+ * hdd_medium_assess_cca() - clear channel assessment
+ * @hdd_ctx: pointer to HDD context
+ * @adapter: pointer to adapter
+ * @tb: list of attributes
+ *
+ * Return: success(0) or reason code for failure
+ */
+static int hdd_medium_assess_cca(struct hdd_context *hdd_ctx,
+				 struct hdd_adapter *adapter,
+				 struct nlattr **tb)
+{
+	struct wlan_objmgr_vdev *vdev;
+	uint32_t cca_period = DEFAULT_CCA_PERIOD;
+	uint8_t pdev_id, dcs_enable;
+	int status = 0;
+
+	vdev = hdd_objmgr_get_vdev(adapter);
+	if (!vdev)
+		return -EINVAL;
+
+	pdev_id = wlan_objmgr_pdev_get_pdev_id(wlan_vdev_get_pdev(vdev));
+
+	dcs_enable = ucfg_get_dcs_enable(hdd_ctx->psoc, pdev_id);
+	if (!(dcs_enable & CAP_DCS_WLANIM)) {
+		hdd_err_rl("DCS_WLANIM is not enabled");
+		status = -EINVAL;
+		goto out;
+	}
+
+	if (qdf_atomic_read(&adapter->session.ap.acs_in_progress)) {
+		hdd_err_rl("ACS is in progress");
+		status = -EBUSY;
+		goto out;
+	}
+
+	if (tb[PERIOD])
+		cca_period = nla_get_u32(tb[PERIOD]);
+	if (cca_period == 0)
+		cca_period = DEFAULT_CCA_PERIOD;
+
+	ucfg_dcs_reset_user_stats(hdd_ctx->psoc, pdev_id);
+	ucfg_dcs_register_user_cb(hdd_ctx->psoc, pdev_id, adapter->vdev_id,
+				  hdd_cca_notification_cb);
+	/* dcs is already enabled and dcs event is reported every second
+	 * set the user request counter to collect user stats
+	 */
+	ucfg_dcs_set_user_request(hdd_ctx->psoc, pdev_id, cca_period);
+
+out:
+	hdd_objmgr_put_vdev(vdev);
+	return status;
+}
+
+/*
  * get_congestion_report_len() - Calculate length for congestion report
  * to allocate skb buffer
  *
@@ -277,6 +421,7 @@ static int __hdd_cfg80211_medium_assess(struct wiphy *wiphy,
 
 	switch (type) {
 	case QCA_WLAN_MEDIUM_ASSESS_CCA:
+		status = hdd_medium_assess_cca(hdd_ctx, adapter, tb);
 		break;
 	case QCA_WLAN_MEDIUM_ASSESS_CONGESTION_REPORT:
 		status = hdd_medium_assess_congestion_report(hdd_ctx, adapter,