diff --git a/wmi/inc/wmi_unified_api.h b/wmi/inc/wmi_unified_api.h index 768b48ef6b18..d230ca1c1afa 100644 --- a/wmi/inc/wmi_unified_api.h +++ b/wmi/inc/wmi_unified_api.h @@ -2330,6 +2330,33 @@ QDF_STATUS wmi_unified_fils_discovery_send_cmd(void *wmi_hdl, struct fd_params *param); #endif /* WLAN_SUPPORT_FILS */ +/** + * wmi_unified_send_roam_scan_stats_cmd() - Wrapper to request roam scan stats + * @wmi_hdl: wmi handle + * @params: request params + * + * This function is used to send the roam scan stats request command to + * firmware. + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS +wmi_unified_send_roam_scan_stats_cmd(void *wmi_hdl, + struct wmi_roam_scan_stats_req *params); + +/** + * wmi_extract_roam_scan_stats_res_evt() - API to extract roam scan stats res + * @wmi: wmi handle + * @evt_buf: pointer to the event buffer + * @vdev_id: output pointer to hold vdev id + * @res_param: output pointer to hold extracted memory + * + * Return: QDF_STATUS + */ +QDF_STATUS +wmi_extract_roam_scan_stats_res_evt(wmi_unified_t wmi, void *evt_buf, + uint32_t *vdev_id, + struct wmi_roam_scan_stats_res **res_param); /** * wmi_unified_offload_11k_cmd() - send 11k offload command * @wmi_hdl: wmi handle diff --git a/wmi/inc/wmi_unified_param.h b/wmi/inc/wmi_unified_param.h index 8443b0230614..c26eca3ae33b 100644 --- a/wmi/inc/wmi_unified_param.h +++ b/wmi/inc/wmi_unified_param.h @@ -5614,6 +5614,7 @@ typedef enum { #endif wmi_twt_enable_complete_event_id, wmi_apf_get_vdev_work_memory_resp_event_id, + wmi_roam_scan_stats_event_id, #ifdef OL_ATH_SMART_LOGGING wmi_debug_fatal_condition_eventid, @@ -8752,4 +8753,82 @@ struct wmi_apf_read_memory_resp_event_params { #define WMI_HOST_VDEV_FLAGS_TRANSMIT_AP 0x00000002 #define WMI_HOST_VDEV_FLAGS_NON_TRANSMIT_AP 0x00000004 +/* Begin of roam scan stats definitions */ + +#define WMI_ROAM_SCAN_STATS_MAX 5 +#define WMI_ROAM_SCAN_STATS_CANDIDATES_MAX 4 +#define WMI_ROAM_SCAN_STATS_CHANNELS_MAX 50 + +/** + * struct wmi_roam_scan_stats_req - Structure to hold roam scan stats request + * @vdev_id: interface id + */ +struct wmi_roam_scan_stats_req { + uint32_t vdev_id; +}; + +/** + * struct wmi_roam_scan_cand - Roam scan candidates + * @score: score of AP + * @rssi: rssi of the AP + * @freq: center frequency + * @bssid: bssid of AP + */ +struct wmi_roam_scan_cand { + uint32_t score; + uint32_t rssi; + uint32_t freq; + uint8_t bssid[QDF_MAC_ADDR_SIZE]; +}; + +/** + * struct wmi_roam_scan_stats_params - Roam scan details + * @time_stamp: time at which this roam scan happened + * @client_id: id of client which triggered this scan + * @num_scan_chans: number of channels that were scanned as part of this scan + * @scan_freqs: frequencies of the channels that were scanned + * @is_roam_successful: whether a successful roaming happened after this scan + * @old_bssid: bssid to which STA is connected just before this scan + * @new_bssid: bssid to which STA is roamed to in case of successful roaming + * @num_roam_candidates: no.of roam candidates that are being reported + * @roam_candidate: roam scan candidate details + * @trigger_id: reason for triggering this roam or roam scan + * @trigger_value: threshold value related to trigger_id + */ +struct wmi_roam_scan_stats_params { + uint64_t time_stamp; + uint32_t client_id; + uint32_t num_scan_chans; + uint32_t scan_freqs[WMI_ROAM_SCAN_STATS_CHANNELS_MAX]; + uint32_t is_roam_successful; + + /* Bssid to which STA is connected when the roam scan is triggered */ + uint8_t old_bssid[QDF_MAC_ADDR_SIZE]; + + /* + * Bssid to which STA is connected after roaming. Will be valid only + * if is_roam_successful is true. + */ + uint8_t new_bssid[QDF_MAC_ADDR_SIZE]; + + /* Number of roam candidates that are being reported in the stats */ + uint32_t num_roam_candidates; + struct wmi_roam_scan_cand cand[WMI_ROAM_SCAN_STATS_CANDIDATES_MAX]; + uint32_t trigger_id; + uint32_t trigger_value; +}; + +/** + * struct wmi_roam_scan_stats_res - Roam scan stats response from firmware + * @num_roam_scan: number of roam scans triggered + * @roam_scan: place holder to indicate the array of + * wmi_roam_scan_stats_params followed by this structure + */ +struct wmi_roam_scan_stats_res { + uint32_t num_roam_scans; + struct wmi_roam_scan_stats_params roam_scan[0]; +}; + +/* End of roam scan stats definitions */ + #endif /* _WMI_UNIFIED_PARAM_H_ */ diff --git a/wmi/inc/wmi_unified_priv.h b/wmi/inc/wmi_unified_priv.h index cd843a9947e1..ff8be3ac4397 100644 --- a/wmi/inc/wmi_unified_priv.h +++ b/wmi/inc/wmi_unified_priv.h @@ -1620,6 +1620,17 @@ QDF_STATUS (*extract_swfda_vdev_id)(wmi_unified_t wmi_handle, void *evt_buf, QDF_STATUS (*send_fils_discovery_send_cmd)(wmi_unified_t wmi_handle, struct fd_params *param); #endif /* WLAN_SUPPORT_FILS */ + +QDF_STATUS +(*send_roam_scan_stats_cmd)(wmi_unified_t wmi_handle, + struct wmi_roam_scan_stats_req *params); + +QDF_STATUS +(*extract_roam_scan_stats_res_evt)(wmi_unified_t wmi_handle, + void *evt_buf, + uint32_t *vdev_id, + struct wmi_roam_scan_stats_res **res_param); + QDF_STATUS (*send_offload_11k_cmd)(wmi_unified_t wmi_handle, struct wmi_11k_offload_params *params); diff --git a/wmi/src/wmi_unified_api.c b/wmi/src/wmi_unified_api.c index 28e5ac0eb619..26b89f337ea9 100644 --- a/wmi/src/wmi_unified_api.c +++ b/wmi/src/wmi_unified_api.c @@ -7492,3 +7492,29 @@ QDF_STATUS wmi_extract_smartlog_ev(void *wmi_hdl, return QDF_STATUS_E_FAILURE; } #endif /* OL_ATH_SMART_LOGGING */ + +QDF_STATUS +wmi_unified_send_roam_scan_stats_cmd(void *wmi_hdl, + struct wmi_roam_scan_stats_req *params) +{ + wmi_unified_t wmi_handle = (wmi_unified_t)wmi_hdl; + + if (wmi_handle->ops->send_roam_scan_stats_cmd) + return wmi_handle->ops->send_roam_scan_stats_cmd(wmi_handle, + params); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS +wmi_extract_roam_scan_stats_res_evt(wmi_unified_t wmi, void *evt_buf, + uint32_t *vdev_id, + struct wmi_roam_scan_stats_res **res_param) +{ + if (wmi->ops->extract_roam_scan_stats_res_evt) + return wmi->ops->extract_roam_scan_stats_res_evt(wmi, + evt_buf, + vdev_id, res_param); + + return QDF_STATUS_E_FAILURE; +} diff --git a/wmi/src/wmi_unified_tlv.c b/wmi/src/wmi_unified_tlv.c index ae4e1db8f41f..2bedad45872c 100644 --- a/wmi/src/wmi_unified_tlv.c +++ b/wmi/src/wmi_unified_tlv.c @@ -21424,6 +21424,237 @@ static QDF_STATUS extract_obss_detection_info_tlv(uint8_t *evt_buf, return QDF_STATUS_SUCCESS; } +/** + * send_roam_scan_stats_cmd_tlv() - Send roam scan stats req command to fw + * @wmi_handle: wmi handle + * @params: pointer to request structure + * + * Return: QDF_STATUS + */ +static QDF_STATUS +send_roam_scan_stats_cmd_tlv(wmi_unified_t wmi_handle, + struct wmi_roam_scan_stats_req *params) +{ + wmi_buf_t buf; + wmi_request_roam_scan_stats_cmd_fixed_param *cmd; + WMITLV_TAG_ID tag; + uint32_t size; + uint32_t len = sizeof(*cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE(FL("Failed to allocate wmi buffer")); + return QDF_STATUS_E_FAILURE; + } + + cmd = (wmi_request_roam_scan_stats_cmd_fixed_param *)wmi_buf_data(buf); + + tag = WMITLV_TAG_STRUC_wmi_request_roam_scan_stats_cmd_fixed_param; + size = WMITLV_GET_STRUCT_TLVLEN( + wmi_request_roam_scan_stats_cmd_fixed_param); + WMITLV_SET_HDR(&cmd->tlv_header, tag, size); + + cmd->vdev_id = params->vdev_id; + + WMI_LOGD(FL("Roam Scan Stats Req vdev_id: %u"), cmd->vdev_id); + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_REQUEST_ROAM_SCAN_STATS_CMDID)) { + WMI_LOGE("%s: Failed to send WMI_REQUEST_ROAM_SCAN_STATS_CMDID", + __func__); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_roam_scan_stats_res_evt_tlv() - Extract roam scan stats event + * @wmi_handle: wmi handle + * @evt_buf: pointer to event buffer + * @vdev_id: output pointer to hold vdev id + * @res_param: output pointer to hold the allocated response + * + * Return: QDF_STATUS + */ +static QDF_STATUS +extract_roam_scan_stats_res_evt_tlv(wmi_unified_t wmi_handle, void *evt_buf, + uint32_t *vdev_id, + struct wmi_roam_scan_stats_res **res_param) +{ + WMI_ROAM_SCAN_STATS_EVENTID_param_tlvs *param_buf; + wmi_roam_scan_stats_event_fixed_param *fixed_param; + uint32_t *client_id = NULL; + wmi_roaming_timestamp *timestamp = NULL; + uint32_t *num_channels = NULL; + uint32_t *chan_info = NULL; + wmi_mac_addr *old_bssid = NULL; + uint32_t *is_roaming_success = NULL; + wmi_mac_addr *new_bssid = NULL; + uint32_t *num_roam_candidates = NULL; + wmi_roam_scan_trigger_reason *roam_reason = NULL; + wmi_mac_addr *bssid = NULL; + uint32_t *score = NULL; + uint32_t *channel = NULL; + uint32_t *rssi = NULL; + int chan_idx = 0, cand_idx = 0; + uint32_t total_len; + struct wmi_roam_scan_stats_res *res; + uint32_t i, j; + uint32_t num_scans; + + *res_param = NULL; + *vdev_id = 0xFF; /* Initialize to invalid vdev id */ + param_buf = (WMI_ROAM_SCAN_STATS_EVENTID_param_tlvs *)evt_buf; + if (!param_buf) { + WMI_LOGE(FL("Invalid roam scan stats event")); + return QDF_STATUS_E_INVAL; + } + + fixed_param = param_buf->fixed_param; + total_len = sizeof(*res) + fixed_param->num_roam_scans * + sizeof(struct wmi_roam_scan_stats_params); + + *vdev_id = fixed_param->vdev_id; + num_scans = fixed_param->num_roam_scans; + + res = qdf_mem_malloc(total_len); + if (!res) { + WMI_LOGE("Failed to allocate roam scan stats response memory"); + return QDF_STATUS_E_NOMEM; + } + + if (!num_scans) { + *res_param = res; + return QDF_STATUS_SUCCESS; + } + + if (param_buf->client_id && + param_buf->num_client_id == num_scans) + client_id = param_buf->client_id; + + if (param_buf->timestamp && + param_buf->num_timestamp == num_scans) + timestamp = param_buf->timestamp; + + if (param_buf->old_bssid && + param_buf->num_old_bssid == num_scans) + old_bssid = param_buf->old_bssid; + + if (param_buf->new_bssid && + param_buf->num_new_bssid == num_scans) + new_bssid = param_buf->new_bssid; + + if (param_buf->is_roaming_success && + param_buf->num_is_roaming_success == num_scans) + is_roaming_success = param_buf->is_roaming_success; + + if (param_buf->roam_reason && + param_buf->num_roam_reason == num_scans) + roam_reason = param_buf->roam_reason; + + if (param_buf->num_channels && + param_buf->num_num_channels == num_scans) { + uint32_t count, chan_info_sum = 0; + + num_channels = param_buf->num_channels; + for (count = 0; count < param_buf->num_num_channels; count++) + chan_info_sum += param_buf->num_channels[count]; + + if (param_buf->chan_info && + param_buf->num_chan_info == chan_info_sum) + chan_info = param_buf->chan_info; + } + + if (param_buf->num_roam_candidates && + param_buf->num_num_roam_candidates == num_scans) { + uint32_t count, roam_cand_sum = 0; + + num_roam_candidates = param_buf->num_roam_candidates; + for (count = 0; count < param_buf->num_num_roam_candidates; + count++) + roam_cand_sum += param_buf->num_roam_candidates[count]; + + if (param_buf->bssid && + param_buf->num_bssid == roam_cand_sum) + bssid = param_buf->bssid; + + if (param_buf->score && + param_buf->num_score == roam_cand_sum) + score = param_buf->score; + + if (param_buf->channel && + param_buf->num_channel == roam_cand_sum) + channel = param_buf->channel; + + if (param_buf->rssi && + param_buf->num_rssi == roam_cand_sum) + rssi = param_buf->rssi; + } + + res->num_roam_scans = num_scans; + for (i = 0; i < num_scans; i++) { + struct wmi_roam_scan_stats_params *roam = &res->roam_scan[i]; + + if (timestamp) + roam->time_stamp = timestamp[i].lower32bit | + (timestamp[i].upper32bit << 31); + + if (client_id) + roam->client_id = client_id[i]; + + if (num_channels) { + roam->num_scan_chans = num_channels[i]; + if (chan_info) { + for (j = 0; j < num_channels[i]; j++) + roam->scan_freqs[j] = + chan_info[chan_idx++]; + } + } + + if (is_roaming_success) + roam->is_roam_successful = is_roaming_success[i]; + + if (roam_reason) { + roam->trigger_id = roam_reason[i].trigger_id; + roam->trigger_value = roam_reason[i].trigger_value; + } + + if (num_roam_candidates) { + roam->num_roam_candidates = num_roam_candidates[i]; + + for (j = 0; j < num_roam_candidates[i]; j++) { + if (score) + roam->cand[j].score = score[cand_idx]; + if (rssi) + roam->cand[j].rssi = rssi[cand_idx]; + if (channel) + roam->cand[j].freq = + channel[cand_idx]; + + if (bssid) + WMI_MAC_ADDR_TO_CHAR_ARRAY( + &bssid[cand_idx], + roam->cand[j].bssid); + + cand_idx++; + } + } + + if (old_bssid) + WMI_MAC_ADDR_TO_CHAR_ARRAY(&old_bssid[i], + roam->old_bssid); + + if (new_bssid) + WMI_MAC_ADDR_TO_CHAR_ARRAY(&new_bssid[i], + roam->new_bssid); + } + + *res_param = res; + + return QDF_STATUS_SUCCESS; +} + /** * send_offload_11k_cmd_tlv() - send wmi cmd with 11k offload params * @wmi_handle: wmi handler @@ -22415,6 +22646,8 @@ struct wmi_ops tlv_ops = { #endif .extract_esp_estimation_ev_param = extract_esp_estimation_ev_param_tlv, + .send_roam_scan_stats_cmd = send_roam_scan_stats_cmd_tlv, + .extract_roam_scan_stats_res_evt = extract_roam_scan_stats_res_evt_tlv, }; /** @@ -22710,6 +22943,7 @@ static void populate_tlv_events_id(uint32_t *event_ids) WMI_BPF_GET_VDEV_WORK_MEMORY_RESP_EVENTID; event_ids[wmi_wlan_sar2_result_event_id] = WMI_SAR2_RESULT_EVENTID; event_ids[wmi_esp_estimate_event_id] = WMI_ESP_ESTIMATE_EVENTID; + event_ids[wmi_roam_scan_stats_event_id] = WMI_ROAM_SCAN_STATS_EVENTID; } /**