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 } 92 } 93 94 return QDF_STATUS_SUCCESS; 95 } 96 97 #ifdef WLAN_ENH_CFR_ENABLE 98 static void populate_wmi_cfr_param(uint8_t grp_id, struct cfr_rcc_param *rcc, 99 wmi_cfr_filter_group_config *param) 100 { 101 struct ta_ra_cfr_cfg *tgt_cfg = NULL; 102 103 WMITLV_SET_HDR(¶m->tlv_header, 104 WMITLV_TAG_STRUC_wmi_cfr_filter_group_config, 105 WMITLV_GET_STRUCT_TLVLEN 106 (wmi_cfr_filter_group_config)); 107 tgt_cfg = &rcc->curr[grp_id]; 108 109 param->filter_group_id = grp_id; 110 WMI_CFR_GROUP_TA_ADDR_VALID_SET(param->filter_set_valid_mask, 111 tgt_cfg->valid_ta); 112 WMI_CFR_GROUP_TA_ADDR_MASK_VALID_SET(param->filter_set_valid_mask, 113 tgt_cfg->valid_ta_mask); 114 WMI_CFR_GROUP_RA_ADDR_VALID_SET(param->filter_set_valid_mask, 115 tgt_cfg->valid_ra); 116 WMI_CFR_GROUP_RA_ADDR_MASK_VALID_SET(param->filter_set_valid_mask, 117 tgt_cfg->valid_ra_mask); 118 WMI_CFR_GROUP_BW_VALID_SET(param->filter_set_valid_mask, 119 tgt_cfg->valid_bw_mask); 120 WMI_CFR_GROUP_NSS_VALID_SET(param->filter_set_valid_mask, 121 tgt_cfg->valid_nss_mask); 122 WMI_CFR_GROUP_MGMT_SUBTYPE_VALID_SET(param->filter_set_valid_mask, 123 tgt_cfg->valid_mgmt_subtype); 124 WMI_CFR_GROUP_CTRL_SUBTYPE_VALID_SET(param->filter_set_valid_mask, 125 tgt_cfg->valid_ctrl_subtype); 126 WMI_CFR_GROUP_DATA_SUBTYPE_VALID_SET(param->filter_set_valid_mask, 127 tgt_cfg->valid_data_subtype); 128 WMI_CHAR_ARRAY_TO_MAC_ADDR(tgt_cfg->tx_addr, 129 ¶m->ta_addr); 130 WMI_CHAR_ARRAY_TO_MAC_ADDR(tgt_cfg->tx_addr_mask, 131 ¶m->ta_addr_mask); 132 WMI_CHAR_ARRAY_TO_MAC_ADDR(tgt_cfg->rx_addr, 133 ¶m->ra_addr); 134 WMI_CHAR_ARRAY_TO_MAC_ADDR(tgt_cfg->rx_addr_mask, 135 ¶m->ra_addr_mask); 136 WMI_CFR_GROUP_BW_SET(param->bw_nss_filter, 137 tgt_cfg->bw); 138 WMI_CFR_GROUP_NSS_SET(param->bw_nss_filter, 139 tgt_cfg->nss); 140 param->mgmt_subtype_filter = tgt_cfg->mgmt_subtype_filter; 141 param->ctrl_subtype_filter = tgt_cfg->ctrl_subtype_filter; 142 param->data_subtype_filter = tgt_cfg->data_subtype_filter; 143 } 144 145 static QDF_STATUS send_cfr_rcc_cmd_tlv(wmi_unified_t wmi_handle, 146 struct cfr_rcc_param *rcc) 147 { 148 wmi_cfr_capture_filter_cmd_fixed_param *cmd; 149 wmi_cfr_filter_group_config *param; 150 uint8_t *buf_ptr, grp_id; 151 wmi_buf_t buf; 152 uint32_t len; 153 QDF_STATUS status = QDF_STATUS_SUCCESS; 154 struct wmi_ops *ops = wmi_handle->ops; 155 156 len = sizeof(*cmd) + WMI_TLV_HDR_SIZE; 157 len += rcc->num_grp_tlvs * sizeof(wmi_cfr_filter_group_config); 158 buf = wmi_buf_alloc(wmi_handle, len); 159 160 if (!buf) { 161 wmi_err("wmi_buf_alloc failed"); 162 return QDF_STATUS_E_NOMEM; 163 } 164 165 buf_ptr = wmi_buf_data(buf); 166 cmd = (wmi_cfr_capture_filter_cmd_fixed_param *)buf_ptr; 167 168 WMITLV_SET_HDR(&cmd->tlv_header, 169 WMITLV_TAG_STRUC_wmi_cfr_capture_filter_cmd_fixed_param, 170 WMITLV_GET_STRUCT_TLVLEN 171 (wmi_cfr_capture_filter_cmd_fixed_param)); 172 cmd->pdev_id = ops->convert_host_pdev_id_to_target(wmi_handle, 173 rcc->pdev_id); 174 WMI_CFR_CAPTURE_INTERVAL_SET(cmd->capture_interval, 175 rcc->capture_interval); 176 WMI_CFR_CAPTURE_DURATION_SET(cmd->capture_duration, 177 rcc->capture_duration); 178 WMI_CFR_CAPTURE_COUNT_SET(cmd->capture_count, rcc->capture_count); 179 WMI_CFR_CAPTURE_INTERVAL_MODE_SEL_SET(cmd->capture_count, 180 rcc->capture_intval_mode_sel); 181 WMI_CFR_FILTER_GROUP_BITMAP_SET(cmd->filter_group_bitmap, 182 rcc->filter_group_bitmap); 183 WMI_CFR_UL_MU_USER_UPPER_SET(cmd->ul_mu_user_mask_upper, 184 rcc->ul_mu_user_mask_upper); 185 cmd->ul_mu_user_mask_lower = rcc->ul_mu_user_mask_lower; 186 WMI_CFR_FREEZE_DELAY_CNT_EN_SET(cmd->freeze_tlv_delay_cnt, 187 rcc->freeze_tlv_delay_cnt_en); 188 WMI_CFR_FREEZE_DELAY_CNT_THR_SET(cmd->freeze_tlv_delay_cnt, 189 rcc->freeze_tlv_delay_cnt_thr); 190 WMI_CFR_DIRECTED_FTM_ACK_EN_SET(cmd->filter_type, 191 rcc->m_directed_ftm); 192 WMI_CFR_ALL_FTM_ACK_EN_SET(cmd->filter_type, 193 rcc->m_all_ftm_ack); 194 WMI_CFR_NDPA_NDP_DIRECTED_EN_SET(cmd->filter_type, 195 rcc->m_ndpa_ndp_directed); 196 WMI_CFR_NDPA_NDP_ALL_EN_SET(cmd->filter_type, 197 rcc->m_ndpa_ndp_all); 198 WMI_CFR_TA_RA_TYPE_FILTER_EN_SET(cmd->filter_type, 199 rcc->m_ta_ra_filter); 200 WMI_CFR_FILTER_IN_AS_FP_TA_RA_TYPE_SET(cmd->filter_type, 201 rcc->en_ta_ra_filter_in_as_fp); 202 WMI_CFR_ALL_PACKET_EN_SET(cmd->filter_type, 203 rcc->m_all_packet); 204 205 /* TLV indicating array of structures to follow */ 206 buf_ptr += sizeof(wmi_cfr_capture_filter_cmd_fixed_param); 207 208 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 209 rcc->num_grp_tlvs * sizeof(wmi_cfr_filter_group_config)); 210 211 if (rcc->num_grp_tlvs) { 212 buf_ptr += WMI_TLV_HDR_SIZE; 213 param = (wmi_cfr_filter_group_config *)buf_ptr; 214 215 for (grp_id = 0; grp_id < MAX_TA_RA_ENTRIES; grp_id++) { 216 if (qdf_test_bit(grp_id, 217 &rcc->modified_in_curr_session)) { 218 populate_wmi_cfr_param(grp_id, rcc, param); 219 param++; 220 } 221 } 222 } 223 status = wmi_unified_cmd_send(wmi_handle, buf, len, 224 WMI_CFR_CAPTURE_FILTER_CMDID); 225 if (status) 226 wmi_buf_free(buf); 227 228 return status; 229 } 230 231 static QDF_STATUS 232 extract_cfr_phase_param_tlv(wmi_unified_t wmi_handle, 233 void *evt_buf, 234 struct wmi_cfr_phase_delta_param *param) 235 { 236 WMI_PDEV_AOA_PHASEDELTA_EVENTID_param_tlvs *param_buf; 237 wmi_pdev_aoa_phasedelta_evt_fixed_param *phase_event; 238 239 param_buf = (WMI_PDEV_AOA_PHASEDELTA_EVENTID_param_tlvs *)evt_buf; 240 if (!param_buf) { 241 wmi_err("Invalid cfr aoa phase delta buffer"); 242 return QDF_STATUS_E_INVAL; 243 } 244 245 phase_event = param_buf->fixed_param; 246 if (!phase_event) { 247 wmi_err("CFR phase AoA delta buffer is NULL"); 248 return QDF_STATUS_E_NULL_VALUE; 249 } 250 251 param->freq = phase_event->freq; 252 param->pdev_id = wmi_handle->ops->convert_pdev_id_target_to_host 253 (wmi_handle, phase_event->pdev_id); 254 255 param->max_chains = phase_event->chainInfo & 0xFFFF; 256 257 param->chain_phase_mask = (phase_event->chainInfo >> 16) & 0xFFFF; 258 259 if ((sizeof(param->ibf_cal_val)) < 260 (sizeof(phase_event->perChainIbfCalVal))) { 261 wmi_err("ibf_cal_val can not hold all values from event data"); 262 return QDF_STATUS_E_RANGE; 263 } 264 265 if ((sizeof(param->phase_delta)) < 266 (sizeof(phase_event->phasedelta))) { 267 wmi_err("phase_delta can not hold all values from event data"); 268 return QDF_STATUS_E_RANGE; 269 } 270 271 qdf_mem_copy(param->ibf_cal_val, 272 phase_event->perChainIbfCalVal, 273 sizeof(param->ibf_cal_val)); 274 275 qdf_mem_copy(param->phase_delta, 276 phase_event->phasedelta, 277 sizeof(param->phase_delta)); 278 279 return QDF_STATUS_SUCCESS; 280 } 281 #endif 282 283 static QDF_STATUS send_peer_cfr_capture_cmd_tlv(wmi_unified_t wmi_handle, 284 struct peer_cfr_params *param) 285 { 286 wmi_peer_cfr_capture_cmd_fixed_param *cmd; 287 wmi_buf_t buf; 288 int len = sizeof(*cmd); 289 int ret; 290 291 buf = wmi_buf_alloc(wmi_handle, len); 292 if (!buf) { 293 qdf_print("%s:wmi_buf_alloc failed\n", __func__); 294 return QDF_STATUS_E_NOMEM; 295 } 296 297 cmd = (wmi_peer_cfr_capture_cmd_fixed_param *)wmi_buf_data(buf); 298 WMITLV_SET_HDR(&cmd->tlv_header, 299 WMITLV_TAG_STRUC_wmi_peer_cfr_capture_cmd_fixed_param, 300 WMITLV_GET_STRUCT_TLVLEN 301 (wmi_peer_cfr_capture_cmd_fixed_param)); 302 303 WMI_CHAR_ARRAY_TO_MAC_ADDR(param->macaddr, &cmd->mac_addr); 304 cmd->request = param->request; 305 cmd->vdev_id = param->vdev_id; 306 cmd->periodicity = param->periodicity; 307 cmd->bandwidth = param->bandwidth; 308 cmd->capture_method = param->capture_method; 309 310 ret = wmi_unified_cmd_send(wmi_handle, buf, len, 311 WMI_PEER_CFR_CAPTURE_CMDID); 312 if (QDF_IS_STATUS_ERROR(ret)) { 313 wmi_err("Failed to send WMI_PEER_CFR_CAPTURE_CMDID"); 314 wmi_buf_free(buf); 315 } 316 317 return ret; 318 } 319 320 #ifdef WLAN_ENH_CFR_ENABLE 321 static inline void wmi_enh_cfr_attach_tlv(wmi_unified_t wmi_handle) 322 { 323 struct wmi_ops *ops = wmi_handle->ops; 324 325 ops->send_cfr_rcc_cmd = send_cfr_rcc_cmd_tlv; 326 } 327 #else 328 static inline void wmi_enh_cfr_attach_tlv(wmi_unified_t wmi_handle) 329 { 330 } 331 #endif 332 333 void wmi_cfr_attach_tlv(wmi_unified_t wmi_handle) 334 { 335 struct wmi_ops *ops = wmi_handle->ops; 336 337 ops->send_peer_cfr_capture_cmd = send_peer_cfr_capture_cmd_tlv; 338 ops->extract_cfr_peer_tx_event_param = 339 extract_cfr_peer_tx_event_param_tlv; 340 ops->extract_cfr_phase_param = extract_cfr_phase_param_tlv; 341 wmi_enh_cfr_attach_tlv(wmi_handle); 342 } 343 #endif /* WLAN_CFR_ENABLE */ 344