Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6f83bfd8 authored by Srikanth Marepalli's avatar Srikanth Marepalli Committed by Madan Koyyalamudi
Browse files

qcacld-3.0: Fill the vendor attributes with the Roam stats

This change gathers the roam event stats from the FW.
New vendor event is used to fill in the vendor attributes
whenever the roam stats are received from Firmware.

Change-Id: I9a2ddef62d26b0b68897891788733df452ac1ceb
CRs-Fixed: 3036518
parent 9ad14721
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -2486,6 +2486,7 @@ struct wlan_mlme_sae_single_pmk {
 * @btm_rsp:            BTM response information
 * @roam_init_info:     Roam initial info
 * @roam_msg_info:      roam related message information
 * @roam_event_param:   Roam event notif params
 */
struct mlme_roam_debug_info {
	struct wmi_roam_trigger_info trigger;
@@ -2495,6 +2496,7 @@ struct mlme_roam_debug_info {
	struct roam_btm_response_data btm_rsp;
	struct roam_initial_data roam_init_info;
	struct roam_msg_info roam_msg_info;
	struct roam_event_rt_info roam_event_param;
};

/**
+26 −0
Original line number Diff line number Diff line
@@ -891,6 +891,32 @@ struct wlan_rso_sae_offload_params {
};
#endif

/**
 * struct roam_event_rt_info - Roam event related information
 * @vdev_id: Vdev id
 * @roam_scan_state: roam scan state notif value
 * @roam_invoke_fail_reason: roam invoke fail reason
 */
struct roam_event_rt_info {
	uint8_t vdev_id;
	uint32_t roam_scan_state;
	uint32_t roam_invoke_fail_reason;
};

/**
 * enum roam_rt_stats_type: different types of params to get roam event stats
 * for the vdev
 * @ROAM_RT_STATS_TYPE_SCAN_STATE: Roam Scan Start/End
 * @ROAM_RT_STATS_TYPE_INVOKE_FAIL_REASON: One of WMI_ROAM_FAIL_REASON_ID for
 * roam failure in case of forced roam
 * @ROAM_RT_STATS_TYPE_ROAM_SCAN_INFO: Roam Trigger/Fail/Scan/AP Stats
 */
enum roam_rt_stats_type {
	ROAM_RT_STATS_TYPE_SCAN_STATE,
	ROAM_RT_STATS_TYPE_INVOKE_FAIL_REASON,
	ROAM_RT_STATS_TYPE_ROAM_SCAN_INFO,
};

#define ROAM_SCAN_DWELL_TIME_ACTIVE_DEFAULT   (100)
#define ROAM_SCAN_DWELL_TIME_PASSIVE_DEFAULT  (110)
#define ROAM_SCAN_MIN_REST_TIME_DEFAULT       (50)
+4 −0
Original line number Diff line number Diff line
@@ -15462,6 +15462,9 @@ int hdd_register_cb(struct hdd_context *hdd_ctx)
	sme_stats_ext2_register_callback(mac_handle,
					wlan_hdd_cfg80211_stats_ext2_callback);

	sme_roam_events_register_callback(mac_handle,
					wlan_hdd_cfg80211_roam_events_callback);

	sme_set_rssi_threshold_breached_cb(mac_handle,
					   hdd_rssi_threshold_breached);

@@ -15571,6 +15574,7 @@ void hdd_deregister_cb(struct hdd_context *hdd_ctx)
		hdd_err("Failed to de-register data stall detect event callback");

	sme_deregister_oem_data_rsp_callback(mac_handle);
	sme_roam_events_deregister_callback(mac_handle);

	hdd_exit();
}
+337 −0
Original line number Diff line number Diff line
@@ -3800,6 +3800,343 @@ wlan_hdd_cfg80211_stats_ext2_callback(hdd_handle_t hdd_handle,
}
#endif /* End of WLAN_FEATURE_STATS_EXT */

#ifdef WLAN_FEATURE_ROAM_OFFLOAD
/**
 * enum roam_event_rt_info_reset - Reset the notif param value of struct
 * roam_event_rt_info to 0
 * @ROAM_EVENT_RT_INFO_RESET: Reset the value to 0
 */
enum roam_event_rt_info_reset {
	ROAM_EVENT_RT_INFO_RESET = 0,
};

/**
 * struct roam_ap - Roamed/Failed AP info
 * @num_cand: number of candidate APs
 * @bssid:    BSSID of roamed/failed AP
 * rssi:      RSSI of roamed/failed AP
 * freq:      Frequency of roamed/failed AP
 */
struct roam_ap {
	uint32_t num_cand;
	struct qdf_mac_addr bssid;
	int8_t rssi;
	uint16_t freq;
};

/**
 * hdd_get_roam_rt_stats_event_len() - calculate length of skb required for
 * sending roam events stats.
 * @roam_stats: pointer to mlme_roam_debug_info structure
 *
 * Return: length of skb
 */
static uint32_t
hdd_get_roam_rt_stats_event_len(struct mlme_roam_debug_info *roam_stats)
{
	uint32_t len = 0;
	uint8_t i = 0, num_cand = 0;

	/* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_TRIGGER_REASON  */
	if (roam_stats->trigger.present)
		len += nla_total_size(sizeof(uint32_t));

	/* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_INVOKE_FAIL_REASON */
	if (roam_stats->roam_event_param.roam_invoke_fail_reason)
		len += nla_total_size(sizeof(uint32_t));

	/* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_ROAM_SCAN_STATE */
	if (roam_stats->roam_event_param.roam_scan_state)
		len += nla_total_size(sizeof(uint8_t));

	if (roam_stats->scan.present) {
		if (roam_stats->scan.num_chan && !roam_stats->scan.type)
			for (i = 0; i < roam_stats->scan.num_chan;)
				i++;

		/* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_ROAM_SCAN_FREQ_LIST */
		len += (nla_total_size(sizeof(uint32_t)) * i);

		if (roam_stats->result.present &&
		    roam_stats->result.fail_reason) {
			num_cand++;
		} else if (roam_stats->trigger.present) {
			for (i = 0; i < roam_stats->scan.num_ap; i++) {
				if (roam_stats->scan.ap[i].type == 2)
					num_cand++;
			}
		}
		/* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO */
		len += NLA_HDRLEN;
		/* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_BSSID */
		len += (nla_total_size(QDF_MAC_ADDR_SIZE) * num_cand);
		/* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_RSSI */
		len += (nla_total_size(sizeof(int32_t)) * num_cand);
		/* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_FREQ */
		len += (nla_total_size(sizeof(uint32_t)) * num_cand);
		/* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_FAIL_REASON */
		len += (nla_total_size(sizeof(uint32_t)) * num_cand);
	}

	/* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_TYPE */
	if (len)
		len += nla_total_size(sizeof(uint32_t));

	return len;
}

#define SUBCMD_ROAM_EVENTS_INDEX \
	QCA_NL80211_VENDOR_SUBCMD_ROAM_EVENTS_INDEX
#define ROAM_SCAN_FREQ_LIST \
	QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_ROAM_SCAN_FREQ_LIST
#define ROAM_INVOKE_FAIL_REASON \
	QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_INVOKE_FAIL_REASON
#define ROAM_SCAN_STATE         QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_ROAM_SCAN_STATE
#define ROAM_EVENTS_CANDIDATE   QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO
#define CANDIDATE_BSSID \
	QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_BSSID
#define CANDIDATE_RSSI \
	QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_RSSI
#define CANDIDATE_FREQ \
	QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_FREQ
#define ROAM_FAIL_REASON \
	QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_FAIL_REASON

/**
 * roam_rt_stats_fill_scan_freq() - Fill the scan frequency list from the
 * roam stats event.
 * @vendor_event: pointer to sk_buff structure
 * @roam_stats:   pointer to mlme_roam_debug_info structure
 *
 * Return: none
 */
static void
roam_rt_stats_fill_scan_freq(struct sk_buff *vendor_event,
			     struct mlme_roam_debug_info *roam_stats)
{
	struct nlattr *nl_attr;
	uint8_t i;

	nl_attr = nla_nest_start(vendor_event, ROAM_SCAN_FREQ_LIST);
	if (!nl_attr) {
		hdd_err("nla nest start fail");
		kfree_skb(vendor_event);
		return;
	}
	if (roam_stats->scan.num_chan && !roam_stats->scan.type) {
		for (i = 0; i < roam_stats->scan.num_chan; i++) {
			if (nla_put_u32(vendor_event, i,
					roam_stats->scan.chan_freq[i])) {
				hdd_err("failed to put freq at index %d", i);
				kfree_skb(vendor_event);
				return;
			}
		}
	}
	nla_nest_end(vendor_event, nl_attr);
}

/**
 * roam_rt_stats_fill_cand_info() - Fill the roamed/failed AP info from the
 * roam stats event.
 * @vendor_event: pointer to sk_buff structure
 * @roam_stats:   pointer to mlme_roam_debug_info structure
 *
 * Return: none
 */
static void
roam_rt_stats_fill_cand_info(struct sk_buff *vendor_event,
			     struct mlme_roam_debug_info *roam_stats)
{
	struct nlattr *nl_attr, *nl_array;
	struct roam_ap cand_ap = {0};
	uint8_t i, num_cand = 0;

	if (roam_stats->result.present && roam_stats->result.fail_reason) {
		num_cand++;
		for (i = 0; i < roam_stats->scan.num_ap; i++) {
			if (roam_stats->scan.ap[i].type == 0 &&
			    qdf_is_macaddr_equal(&roam_stats->result.fail_bssid,
						 &roam_stats->
						 scan.ap[i].bssid)) {
				qdf_copy_macaddr(&cand_ap.bssid,
						 &roam_stats->scan.ap[i].bssid);
				cand_ap.rssi = roam_stats->scan.ap[i].rssi;
				cand_ap.freq = roam_stats->scan.ap[i].freq;
			}
		}
	} else if (roam_stats->trigger.present) {
		for (i = 0; i < roam_stats->scan.num_ap; i++) {
			if (roam_stats->scan.ap[i].type == 2) {
				num_cand++;
				qdf_copy_macaddr(&cand_ap.bssid,
						 &roam_stats->scan.ap[i].bssid);
				cand_ap.rssi = roam_stats->scan.ap[i].rssi;
				cand_ap.freq = roam_stats->scan.ap[i].freq;
			}
		}
	}

	nl_array = nla_nest_start(vendor_event, ROAM_EVENTS_CANDIDATE);
	if (!nl_array) {
		hdd_err("nl array nest start fail");
		kfree_skb(vendor_event);
		return;
	}
	for (i = 0; i < num_cand; i++) {
		nl_attr = nla_nest_start(vendor_event, i);
		if (!nl_attr) {
			hdd_err("nl attr nest start fail");
			kfree_skb(vendor_event);
			return;
		}
		if (nla_put(vendor_event, CANDIDATE_BSSID,
			    sizeof(cand_ap.bssid), cand_ap.bssid.bytes)) {
			hdd_err("%s put fail",
				"ROAM_EVENTS_CANDIDATE_INFO_BSSID");
			kfree_skb(vendor_event);
			return;
		}
		if (nla_put_s32(vendor_event, CANDIDATE_RSSI, cand_ap.rssi)) {
			hdd_err("%s put fail",
				"ROAM_EVENTS_CANDIDATE_INFO_RSSI");
			kfree_skb(vendor_event);
			return;
		}
		if (nla_put_u32(vendor_event, CANDIDATE_FREQ, cand_ap.freq)) {
			hdd_err("%s put fail",
				"ROAM_EVENTS_CANDIDATE_INFO_FREQ");
			kfree_skb(vendor_event);
			return;
		}
		if (roam_stats->result.present &&
		    roam_stats->result.fail_reason) {
			if (nla_put_u32(vendor_event, ROAM_FAIL_REASON,
					roam_stats->result.fail_reason)) {
				hdd_err("%s put fail",
					"ROAM_EVENTS_CANDIDATE_FAIL_REASON");
				kfree_skb(vendor_event);
				return;
			}
		}
		nla_nest_end(vendor_event, nl_attr);
	}
	nla_nest_end(vendor_event, nl_array);
}

void
wlan_hdd_cfg80211_roam_events_callback(hdd_handle_t hdd_handle,
				       struct mlme_roam_debug_info *roam_stats)
{
	struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle);
	int status;
	uint32_t data_size, roam_event_type = 0;
	struct sk_buff *vendor_event;
	struct hdd_adapter *adapter;

	status = wlan_hdd_validate_context(hdd_ctx);
	if (status) {
		hdd_err("Invalid hdd_ctx");
		return;
	}

	if (!roam_stats) {
		hdd_err("msg received here is null");
		return;
	}

	adapter = hdd_get_adapter_by_vdev(hdd_ctx,
					  roam_stats->roam_event_param.vdev_id);
	if (!adapter) {
		hdd_err("vdev_id %d does not exist with host",
			roam_stats->roam_event_param.vdev_id);
		return;
	}

	data_size = hdd_get_roam_rt_stats_event_len(roam_stats);
	if (!data_size) {
		hdd_err("No data requested");
		return;
	}

	data_size += NLMSG_HDRLEN;
	vendor_event = cfg80211_vendor_event_alloc(hdd_ctx->wiphy,
						   &adapter->wdev,
						   data_size,
						   SUBCMD_ROAM_EVENTS_INDEX,
						   GFP_KERNEL);

	if (!vendor_event) {
		hdd_err("vendor_event_alloc failed for ROAM_EVENTS_STATS");
		return;
	}

	if (roam_stats->scan.present && roam_stats->trigger.present) {
		roam_rt_stats_fill_scan_freq(vendor_event, roam_stats);
		roam_rt_stats_fill_cand_info(vendor_event, roam_stats);
	}

	if (roam_stats->roam_event_param.roam_scan_state) {
		roam_event_type |= QCA_WLAN_VENDOR_ROAM_EVENT_ROAM_SCAN_STATE;
		if (nla_put_u8(vendor_event, ROAM_SCAN_STATE,
			       roam_stats->roam_event_param.roam_scan_state)) {
			hdd_err("%s put fail",
				"VENDOR_ATTR_ROAM_EVENTS_ROAM_SCAN_STATE");
			kfree_skb(vendor_event);
			return;
		}
		roam_stats->roam_event_param.roam_scan_state =
						ROAM_EVENT_RT_INFO_RESET;
	}
	if (roam_stats->trigger.present) {
		roam_event_type |= QCA_WLAN_VENDOR_ROAM_EVENT_TRIGGER_REASON;
		if (nla_put_u32(vendor_event,
				QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_TRIGGER_REASON,
				roam_stats->trigger.trigger_reason)) {
			hdd_err("%s put fail",
				"VENDOR_ATTR_ROAM_EVENTS_TRIGGER_REASON");
			kfree_skb(vendor_event);
			return;
		}
	}
	if (roam_stats->roam_event_param.roam_invoke_fail_reason) {
		roam_event_type |=
			QCA_WLAN_VENDOR_ROAM_EVENT_INVOKE_FAIL_REASON;
		if (nla_put_u32(vendor_event, ROAM_INVOKE_FAIL_REASON,
				roam_stats->
				roam_event_param.roam_invoke_fail_reason)) {
			hdd_err("%s put fail",
				"VENDOR_ATTR_ROAM_EVENTS_INVOKE_FAIL_REASON");
			kfree_skb(vendor_event);
			return;
		}
		roam_stats->roam_event_param.roam_invoke_fail_reason =
						ROAM_EVENT_RT_INFO_RESET;
	}
	if (roam_stats->result.present && roam_stats->result.fail_reason)
		roam_event_type |= QCA_WLAN_VENDOR_ROAM_EVENT_FAIL_REASON;

	if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_TYPE,
			roam_event_type)) {
		hdd_err("%s put fail", "QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_TYPE");
			kfree_skb(vendor_event);
		return;
	}

	cfg80211_vendor_event(vendor_event, GFP_KERNEL);
}

#undef SUBCMD_ROAM_EVENTS_INDEX
#undef ROAM_SCAN_FREQ_LIST
#undef ROAM_INVOKE_FAIL_REASON
#undef ROAM_SCAN_STATE
#undef ROAM_EVENTS_CANDIDATE
#undef CANDIDATE_BSSID
#undef CANDIDATE_RSSI
#undef CANDIDATE_FREQ
#undef ROAM_FAIL_REASON
#endif /* End of WLAN_FEATURE_ROAM_OFFLOAD */

#ifdef LINKSPEED_DEBUG_ENABLED
#define linkspeed_dbg(format, args...) pr_info(format, ## args)
#else
+19 −0
Original line number Diff line number Diff line
@@ -393,6 +393,25 @@ void
wlan_hdd_cfg80211_stats_ext2_callback(hdd_handle_t hdd_handle,
				      struct sir_sme_rx_aggr_hole_ind *pmsg);

#ifdef WLAN_FEATURE_ROAM_OFFLOAD
/**
 * wlan_hdd_cfg80211_roam_events_callback() - roam_events_callback
 * @hdd_handle: opaque handle to the hdd context
 * @roam_stats: roam events stats
 *
 * Return: void
 */
void
wlan_hdd_cfg80211_roam_events_callback(hdd_handle_t hdd_handle,
				       struct mlme_roam_debug_info *roam_stats);
#else
static inline void
wlan_hdd_cfg80211_roam_events_callback(hdd_handle_t hdd_handle,
				       struct mlme_roam_debug_info *roam_stats)
{
}
#endif /* End of WLAN_FEATURE_ROAM_OFFLOAD */

/**
 * wlan_hdd_get_rcpi() - Wrapper to get current RCPI
 * @adapter: adapter upon which the measurement is requested
Loading