1 /* 2 * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 #include <osdep.h> 18 #include "wmi.h" 19 #include "wmi_unified_priv.h" 20 #include "wmi_unified_cfr_param.h" 21 #include "wmi_unified_cfr_api.h" 22 23 #ifdef WLAN_CFR_ENABLE 24 static QDF_STATUS 25 extract_cfr_peer_tx_event_param_tlv(wmi_unified_t wmi_handle, void *evt_buf, 26 wmi_cfr_peer_tx_event_param *peer_tx_event) 27 { 28 int idx; 29 WMI_PEER_CFR_CAPTURE_EVENTID_param_tlvs *param_buf; 30 wmi_peer_cfr_capture_event_fixed_param *peer_tx_event_ev; 31 wmi_peer_cfr_capture_event_phase_fixed_param *chain_phase_ev; 32 33 param_buf = (WMI_PEER_CFR_CAPTURE_EVENTID_param_tlvs *)evt_buf; 34 if (!param_buf) { 35 wmi_err("Invalid cfr capture buffer"); 36 return QDF_STATUS_E_INVAL; 37 } 38 39 peer_tx_event_ev = param_buf->fixed_param; 40 if (!peer_tx_event_ev) { 41 wmi_err("peer cfr capture buffer is null"); 42 return QDF_STATUS_E_NULL_VALUE; 43 } 44 45 peer_tx_event->capture_method = peer_tx_event_ev->capture_method; 46 peer_tx_event->vdev_id = peer_tx_event_ev->vdev_id; 47 WMI_MAC_ADDR_TO_CHAR_ARRAY(&peer_tx_event_ev->mac_addr, 48 &peer_tx_event->peer_mac_addr.bytes[0]); 49 peer_tx_event->primary_20mhz_chan = 50 peer_tx_event_ev->chan_mhz; 51 peer_tx_event->bandwidth = peer_tx_event_ev->bandwidth; 52 peer_tx_event->phy_mode = peer_tx_event_ev->phy_mode; 53 peer_tx_event->band_center_freq1 = peer_tx_event_ev->band_center_freq1; 54 peer_tx_event->band_center_freq2 = peer_tx_event_ev->band_center_freq2; 55 peer_tx_event->spatial_streams = peer_tx_event_ev->sts_count; 56 peer_tx_event->correlation_info_1 = 57 peer_tx_event_ev->correlation_info_1; 58 peer_tx_event->correlation_info_2 = 59 peer_tx_event_ev->correlation_info_2; 60 peer_tx_event->status = peer_tx_event_ev->status; 61 peer_tx_event->timestamp_us = peer_tx_event_ev->timestamp_us; 62 peer_tx_event->counter = peer_tx_event_ev->counter; 63 qdf_mem_copy(peer_tx_event->chain_rssi, peer_tx_event_ev->chain_rssi, 64 sizeof(peer_tx_event->chain_rssi)); 65 if (peer_tx_event_ev->cfo_measurement_valid) 66 peer_tx_event->cfo_measurement = 67 peer_tx_event_ev->cfo_measurement; 68 else 69 peer_tx_event->cfo_measurement = 0; 70 71 peer_tx_event->rx_start_ts = peer_tx_event_ev->rx_start_ts; 72 peer_tx_event->rx_ts_reset = peer_tx_event_ev->rx_ts_reset; 73 peer_tx_event->mcs_rate = 74 WMI_CFR_MCS_GET(peer_tx_event_ev->mcs_gi_info); 75 peer_tx_event->gi_type = 76 WMI_CFR_GI_TYPE_GET(peer_tx_event_ev->mcs_gi_info); 77 78 chain_phase_ev = param_buf->phase_param; 79 if (chain_phase_ev) { 80 for (idx = 0; idx < WMI_HOST_MAX_CHAINS; idx++) { 81 /* Due to FW's alignment rules, phase information being 82 * passed is 32-bit, out of which only 16 bits is valid. 83 * Remaining bits are all zeroed. So direct mem copy 84 * will not work as it will copy extra zeroes into host 85 * structures. 86 */ 87 peer_tx_event->chain_phase[idx] = 88 (0xffff & chain_phase_ev->chain_phase[idx]); 89 peer_tx_event->agc_gain[idx] = 90 WMI_UNIFIED_AGC_GAIN_GET(chain_phase_ev, idx); 91 peer_tx_event->agc_gain_tbl_index[idx] = 92 WMI_UNIFIED_AGC_GAIN_TBL_IDX_GET(chain_phase_ev, 93 idx); 94 } 95 } 96 97 return QDF_STATUS_SUCCESS; 98 } 99 100 #ifdef WLAN_ENH_CFR_ENABLE 101 static void populate_wmi_cfr_param(uint8_t grp_id, struct cfr_rcc_param *rcc, 102 wmi_cfr_filter_group_config *param) 103 { 104 struct ta_ra_cfr_cfg *tgt_cfg = NULL; 105 106 WMITLV_SET_HDR(¶m->tlv_header, 107 WMITLV_TAG_STRUC_wmi_cfr_filter_group_config, 108 WMITLV_GET_STRUCT_TLVLEN 109 (wmi_cfr_filter_group_config)); 110 tgt_cfg = &rcc->curr[grp_id]; 111 112 param->filter_group_id = grp_id; 113 WMI_CFR_GROUP_TA_ADDR_VALID_SET(param->filter_set_valid_mask, 114 tgt_cfg->valid_ta); 115 WMI_CFR_GROUP_TA_ADDR_MASK_VALID_SET(param->filter_set_valid_mask, 116 tgt_cfg->valid_ta_mask); 117 WMI_CFR_GROUP_RA_ADDR_VALID_SET(param->filter_set_valid_mask, 118 tgt_cfg->valid_ra); 119 WMI_CFR_GROUP_RA_ADDR_MASK_VALID_SET(param->filter_set_valid_mask, 120 tgt_cfg->valid_ra_mask); 121 WMI_CFR_GROUP_BW_VALID_SET(param->filter_set_valid_mask, 122 tgt_cfg->valid_bw_mask); 123 WMI_CFR_GROUP_NSS_VALID_SET(param->filter_set_valid_mask, 124 tgt_cfg->valid_nss_mask); 125 WMI_CFR_GROUP_MGMT_SUBTYPE_VALID_SET(param->filter_set_valid_mask, 126 tgt_cfg->valid_mgmt_subtype); 127 WMI_CFR_GROUP_CTRL_SUBTYPE_VALID_SET(param->filter_set_valid_mask, 128 tgt_cfg->valid_ctrl_subtype); 129 WMI_CFR_GROUP_DATA_SUBTYPE_VALID_SET(param->filter_set_valid_mask, 130 tgt_cfg->valid_data_subtype); 131 WMI_CHAR_ARRAY_TO_MAC_ADDR(tgt_cfg->tx_addr, 132 ¶m->ta_addr); 133 WMI_CHAR_ARRAY_TO_MAC_ADDR(tgt_cfg->tx_addr_mask, 134 ¶m->ta_addr_mask); 135 WMI_CHAR_ARRAY_TO_MAC_ADDR(tgt_cfg->rx_addr, 136 ¶m->ra_addr); 137 WMI_CHAR_ARRAY_TO_MAC_ADDR(tgt_cfg->rx_addr_mask, 138 ¶m->ra_addr_mask); 139 WMI_CFR_GROUP_BW_SET(param->bw_nss_filter, 140 tgt_cfg->bw); 141 WMI_CFR_GROUP_NSS_SET(param->bw_nss_filter, 142 tgt_cfg->nss); 143 param->mgmt_subtype_filter = tgt_cfg->mgmt_subtype_filter; 144 param->ctrl_subtype_filter = tgt_cfg->ctrl_subtype_filter; 145 param->data_subtype_filter = tgt_cfg->data_subtype_filter; 146 } 147 148 static QDF_STATUS send_cfr_rcc_cmd_tlv(wmi_unified_t wmi_handle, 149 struct cfr_rcc_param *rcc) 150 { 151 wmi_cfr_capture_filter_cmd_fixed_param *cmd; 152 wmi_cfr_filter_group_config *param; 153 uint8_t *buf_ptr, grp_id; 154 wmi_buf_t buf; 155 uint32_t len; 156 QDF_STATUS status = QDF_STATUS_SUCCESS; 157 struct wmi_ops *ops = wmi_handle->ops; 158 159 len = sizeof(*cmd) + WMI_TLV_HDR_SIZE; 160 len += rcc->num_grp_tlvs * sizeof(wmi_cfr_filter_group_config); 161 buf = wmi_buf_alloc(wmi_handle, len); 162 163 if (!buf) { 164 wmi_err("wmi_buf_alloc failed"); 165 return QDF_STATUS_E_NOMEM; 166 } 167 168 buf_ptr = wmi_buf_data(buf); 169 cmd = (wmi_cfr_capture_filter_cmd_fixed_param *)buf_ptr; 170 171 WMITLV_SET_HDR(&cmd->tlv_header, 172 WMITLV_TAG_STRUC_wmi_cfr_capture_filter_cmd_fixed_param, 173 WMITLV_GET_STRUCT_TLVLEN 174 (wmi_cfr_capture_filter_cmd_fixed_param)); 175 cmd->pdev_id = ops->convert_host_pdev_id_to_target(wmi_handle, 176 rcc->pdev_id); 177 WMI_CFR_CAPTURE_INTERVAL_SET(cmd->capture_interval, 178 rcc->capture_interval); 179 WMI_CFR_CAPTURE_DURATION_SET(cmd->capture_duration, 180 rcc->capture_duration); 181 WMI_CFR_CAPTURE_COUNT_SET(cmd->capture_count, rcc->capture_count); 182 WMI_CFR_CAPTURE_INTERVAL_MODE_SEL_SET(cmd->capture_count, 183 rcc->capture_intval_mode_sel); 184 WMI_CFR_FILTER_GROUP_BITMAP_SET(cmd->filter_group_bitmap, 185 rcc->filter_group_bitmap); 186 WMI_CFR_UL_MU_USER_UPPER_SET(cmd->ul_mu_user_mask_upper, 187 rcc->ul_mu_user_mask_upper); 188 cmd->ul_mu_user_mask_lower = rcc->ul_mu_user_mask_lower; 189 WMI_CFR_FREEZE_DELAY_CNT_EN_SET(cmd->freeze_tlv_delay_cnt, 190 rcc->freeze_tlv_delay_cnt_en); 191 WMI_CFR_FREEZE_DELAY_CNT_THR_SET(cmd->freeze_tlv_delay_cnt, 192 rcc->freeze_tlv_delay_cnt_thr); 193 WMI_CFR_DIRECTED_FTM_ACK_EN_SET(cmd->filter_type, 194 rcc->m_directed_ftm); 195 WMI_CFR_ALL_FTM_ACK_EN_SET(cmd->filter_type, 196 rcc->m_all_ftm_ack); 197 WMI_CFR_NDPA_NDP_DIRECTED_EN_SET(cmd->filter_type, 198 rcc->m_ndpa_ndp_directed); 199 WMI_CFR_NDPA_NDP_ALL_EN_SET(cmd->filter_type, 200 rcc->m_ndpa_ndp_all); 201 WMI_CFR_TA_RA_TYPE_FILTER_EN_SET(cmd->filter_type, 202 rcc->m_ta_ra_filter); 203 WMI_CFR_FILTER_IN_AS_FP_TA_RA_TYPE_SET(cmd->filter_type, 204 rcc->en_ta_ra_filter_in_as_fp); 205 WMI_CFR_ALL_PACKET_EN_SET(cmd->filter_type, 206 rcc->m_all_packet); 207 208 /* TLV indicating array of structures to follow */ 209 buf_ptr += sizeof(wmi_cfr_capture_filter_cmd_fixed_param); 210 211 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 212 rcc->num_grp_tlvs * sizeof(wmi_cfr_filter_group_config)); 213 214 if (rcc->num_grp_tlvs) { 215 buf_ptr += WMI_TLV_HDR_SIZE; 216 param = (wmi_cfr_filter_group_config *)buf_ptr; 217 218 for (grp_id = 0; grp_id < MAX_TA_RA_ENTRIES; grp_id++) { 219 if (qdf_test_bit(grp_id, 220 &rcc->modified_in_curr_session)) { 221 populate_wmi_cfr_param(grp_id, rcc, param); 222 param++; 223 } 224 } 225 } 226 status = wmi_unified_cmd_send(wmi_handle, buf, len, 227 WMI_CFR_CAPTURE_FILTER_CMDID); 228 if (status) 229 wmi_buf_free(buf); 230 231 return status; 232 } 233 234 static QDF_STATUS 235 extract_cfr_phase_param_tlv(wmi_unified_t wmi_handle, 236 void *evt_buf, 237 struct wmi_cfr_phase_delta_param *param) 238 { 239 WMI_PDEV_AOA_PHASEDELTA_EVENTID_param_tlvs *param_buf; 240 wmi_pdev_aoa_phasedelta_evt_fixed_param *phase_event; 241 242 param_buf = (WMI_PDEV_AOA_PHASEDELTA_EVENTID_param_tlvs *)evt_buf; 243 if (!param_buf) { 244 wmi_err("Invalid cfr aoa phase delta buffer"); 245 return QDF_STATUS_E_INVAL; 246 } 247 248 phase_event = param_buf->fixed_param; 249 if (!phase_event) { 250 wmi_err("CFR phase AoA delta buffer is NULL"); 251 return QDF_STATUS_E_NULL_VALUE; 252 } 253 254 param->freq = phase_event->freq; 255 param->pdev_id = wmi_handle->ops->convert_pdev_id_target_to_host 256 (wmi_handle, phase_event->pdev_id); 257 258 param->max_chains = phase_event->chainInfo & 0xFFFF; 259 260 param->chain_phase_mask = (phase_event->chainInfo >> 16) & 0xFFFF; 261 262 if ((sizeof(param->ibf_cal_val)) < 263 (sizeof(phase_event->perChainIbfCalVal))) { 264 wmi_err("ibf_cal_val can not hold all values from event data"); 265 return QDF_STATUS_E_RANGE; 266 } 267 268 if ((sizeof(param->phase_delta)) < 269 (sizeof(phase_event->phasedelta))) { 270 wmi_err("phase_delta can not hold all values from event data"); 271 return QDF_STATUS_E_RANGE; 272 } 273 274 qdf_mem_copy(param->ibf_cal_val, 275 phase_event->perChainIbfCalVal, 276 sizeof(param->ibf_cal_val)); 277 278 qdf_mem_copy(param->phase_delta, 279 phase_event->phasedelta, 280 sizeof(param->phase_delta)); 281 282 return QDF_STATUS_SUCCESS; 283 } 284 #endif 285 286 static QDF_STATUS send_peer_cfr_capture_cmd_tlv(wmi_unified_t wmi_handle, 287 struct peer_cfr_params *param) 288 { 289 wmi_peer_cfr_capture_cmd_fixed_param *cmd; 290 wmi_buf_t buf; 291 int len = sizeof(*cmd); 292 int ret; 293 294 buf = wmi_buf_alloc(wmi_handle, len); 295 if (!buf) { 296 qdf_print("%s:wmi_buf_alloc failed\n", __func__); 297 return QDF_STATUS_E_NOMEM; 298 } 299 300 cmd = (wmi_peer_cfr_capture_cmd_fixed_param *)wmi_buf_data(buf); 301 WMITLV_SET_HDR(&cmd->tlv_header, 302 WMITLV_TAG_STRUC_wmi_peer_cfr_capture_cmd_fixed_param, 303 WMITLV_GET_STRUCT_TLVLEN 304 (wmi_peer_cfr_capture_cmd_fixed_param)); 305 306 WMI_CHAR_ARRAY_TO_MAC_ADDR(param->macaddr, &cmd->mac_addr); 307 cmd->request = param->request; 308 cmd->vdev_id = param->vdev_id; 309 cmd->periodicity = param->periodicity; 310 cmd->bandwidth = param->bandwidth; 311 cmd->capture_method = param->capture_method; 312 313 ret = wmi_unified_cmd_send(wmi_handle, buf, len, 314 WMI_PEER_CFR_CAPTURE_CMDID); 315 if (QDF_IS_STATUS_ERROR(ret)) { 316 wmi_err("Failed to send WMI_PEER_CFR_CAPTURE_CMDID"); 317 wmi_buf_free(buf); 318 } 319 320 return ret; 321 } 322 323 #ifdef WLAN_ENH_CFR_ENABLE 324 static inline void wmi_enh_cfr_attach_tlv(wmi_unified_t wmi_handle) 325 { 326 struct wmi_ops *ops = wmi_handle->ops; 327 328 ops->send_cfr_rcc_cmd = send_cfr_rcc_cmd_tlv; 329 } 330 #else 331 static inline void wmi_enh_cfr_attach_tlv(wmi_unified_t wmi_handle) 332 { 333 } 334 #endif 335 336 void wmi_cfr_attach_tlv(wmi_unified_t wmi_handle) 337 { 338 struct wmi_ops *ops = wmi_handle->ops; 339 340 ops->send_peer_cfr_capture_cmd = send_peer_cfr_capture_cmd_tlv; 341 ops->extract_cfr_peer_tx_event_param = 342 extract_cfr_peer_tx_event_param_tlv; 343 ops->extract_cfr_phase_param = extract_cfr_phase_param_tlv; 344 wmi_enh_cfr_attach_tlv(wmi_handle); 345 } 346 #endif /* WLAN_CFR_ENABLE */ 347