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 74 chain_phase_ev = param_buf->phase_param; 75 if (chain_phase_ev) { 76 for (idx = 0; idx < WMI_HOST_MAX_CHAINS; idx++) { 77 /* Due to FW's alignment rules, phase information being 78 * passed is 32-bit, out of which only 16 bits is valid. 79 * Remaining bits are all zeroed. So direct mem copy 80 * will not work as it will copy extra zeroes into host 81 * structures. 82 */ 83 peer_tx_event->chain_phase[idx] = 84 (0xffff & chain_phase_ev->chain_phase[idx]); 85 peer_tx_event->agc_gain[idx] = 86 WMI_UNIFIED_AGC_GAIN_GET(chain_phase_ev, idx); 87 } 88 } 89 90 return QDF_STATUS_SUCCESS; 91 } 92 93 #ifdef WLAN_ENH_CFR_ENABLE 94 static void populate_wmi_cfr_param(uint8_t grp_id, struct cfr_rcc_param *rcc, 95 wmi_cfr_filter_group_config *param) 96 { 97 struct ta_ra_cfr_cfg *tgt_cfg = NULL; 98 99 WMITLV_SET_HDR(¶m->tlv_header, 100 WMITLV_TAG_STRUC_wmi_cfr_filter_group_config, 101 WMITLV_GET_STRUCT_TLVLEN 102 (wmi_cfr_filter_group_config)); 103 tgt_cfg = &rcc->curr[grp_id]; 104 105 param->filter_group_id = grp_id; 106 WMI_CFR_GROUP_TA_ADDR_VALID_SET(param->filter_set_valid_mask, 107 tgt_cfg->valid_ta); 108 WMI_CFR_GROUP_TA_ADDR_MASK_VALID_SET(param->filter_set_valid_mask, 109 tgt_cfg->valid_ta_mask); 110 WMI_CFR_GROUP_RA_ADDR_VALID_SET(param->filter_set_valid_mask, 111 tgt_cfg->valid_ra); 112 WMI_CFR_GROUP_RA_ADDR_MASK_VALID_SET(param->filter_set_valid_mask, 113 tgt_cfg->valid_ra_mask); 114 WMI_CFR_GROUP_BW_VALID_SET(param->filter_set_valid_mask, 115 tgt_cfg->valid_bw_mask); 116 WMI_CFR_GROUP_NSS_VALID_SET(param->filter_set_valid_mask, 117 tgt_cfg->valid_nss_mask); 118 WMI_CFR_GROUP_MGMT_SUBTYPE_VALID_SET(param->filter_set_valid_mask, 119 tgt_cfg->valid_mgmt_subtype); 120 WMI_CFR_GROUP_CTRL_SUBTYPE_VALID_SET(param->filter_set_valid_mask, 121 tgt_cfg->valid_ctrl_subtype); 122 WMI_CFR_GROUP_DATA_SUBTYPE_VALID_SET(param->filter_set_valid_mask, 123 tgt_cfg->valid_data_subtype); 124 WMI_CHAR_ARRAY_TO_MAC_ADDR(tgt_cfg->tx_addr, 125 ¶m->ta_addr); 126 WMI_CHAR_ARRAY_TO_MAC_ADDR(tgt_cfg->tx_addr_mask, 127 ¶m->ta_addr_mask); 128 WMI_CHAR_ARRAY_TO_MAC_ADDR(tgt_cfg->rx_addr, 129 ¶m->ra_addr); 130 WMI_CHAR_ARRAY_TO_MAC_ADDR(tgt_cfg->rx_addr_mask, 131 ¶m->ra_addr_mask); 132 WMI_CFR_GROUP_BW_SET(param->bw_nss_filter, 133 tgt_cfg->bw); 134 WMI_CFR_GROUP_NSS_SET(param->bw_nss_filter, 135 tgt_cfg->nss); 136 param->mgmt_subtype_filter = tgt_cfg->mgmt_subtype_filter; 137 param->ctrl_subtype_filter = tgt_cfg->ctrl_subtype_filter; 138 param->data_subtype_filter = tgt_cfg->data_subtype_filter; 139 } 140 141 static QDF_STATUS send_cfr_rcc_cmd_tlv(wmi_unified_t wmi_handle, 142 struct cfr_rcc_param *rcc) 143 { 144 wmi_cfr_capture_filter_cmd_fixed_param *cmd; 145 wmi_cfr_filter_group_config *param; 146 uint8_t *buf_ptr, grp_id; 147 wmi_buf_t buf; 148 uint32_t len; 149 QDF_STATUS status = QDF_STATUS_SUCCESS; 150 struct wmi_ops *ops = wmi_handle->ops; 151 152 len = sizeof(*cmd) + WMI_TLV_HDR_SIZE; 153 len += rcc->num_grp_tlvs * sizeof(wmi_cfr_filter_group_config); 154 buf = wmi_buf_alloc(wmi_handle, len); 155 156 if (!buf) { 157 wmi_err("wmi_buf_alloc failed"); 158 return QDF_STATUS_E_NOMEM; 159 } 160 161 buf_ptr = wmi_buf_data(buf); 162 cmd = (wmi_cfr_capture_filter_cmd_fixed_param *)buf_ptr; 163 164 WMITLV_SET_HDR(&cmd->tlv_header, 165 WMITLV_TAG_STRUC_wmi_cfr_capture_filter_cmd_fixed_param, 166 WMITLV_GET_STRUCT_TLVLEN 167 (wmi_cfr_capture_filter_cmd_fixed_param)); 168 cmd->pdev_id = ops->convert_host_pdev_id_to_target(wmi_handle, 169 rcc->pdev_id); 170 WMI_CFR_CAPTURE_INTERVAL_SET(cmd->capture_interval, 171 rcc->capture_interval); 172 WMI_CFR_CAPTURE_DURATION_SET(cmd->capture_duration, 173 rcc->capture_duration); 174 WMI_CFR_CAPTURE_COUNT_SET(cmd->capture_count, rcc->capture_count); 175 WMI_CFR_CAPTURE_INTERVAL_MODE_SEL_SET(cmd->capture_count, 176 rcc->capture_intval_mode_sel); 177 WMI_CFR_FILTER_GROUP_BITMAP_SET(cmd->filter_group_bitmap, 178 rcc->filter_group_bitmap); 179 WMI_CFR_UL_MU_USER_UPPER_SET(cmd->ul_mu_user_mask_upper, 180 rcc->ul_mu_user_mask_upper); 181 cmd->ul_mu_user_mask_lower = rcc->ul_mu_user_mask_lower; 182 WMI_CFR_FREEZE_DELAY_CNT_EN_SET(cmd->freeze_tlv_delay_cnt, 183 rcc->freeze_tlv_delay_cnt_en); 184 WMI_CFR_FREEZE_DELAY_CNT_THR_SET(cmd->freeze_tlv_delay_cnt, 185 rcc->freeze_tlv_delay_cnt_thr); 186 WMI_CFR_DIRECTED_FTM_ACK_EN_SET(cmd->filter_type, 187 rcc->m_directed_ftm); 188 WMI_CFR_ALL_FTM_ACK_EN_SET(cmd->filter_type, 189 rcc->m_all_ftm_ack); 190 WMI_CFR_NDPA_NDP_DIRECTED_EN_SET(cmd->filter_type, 191 rcc->m_ndpa_ndp_directed); 192 WMI_CFR_NDPA_NDP_ALL_EN_SET(cmd->filter_type, 193 rcc->m_ndpa_ndp_all); 194 WMI_CFR_TA_RA_TYPE_FILTER_EN_SET(cmd->filter_type, 195 rcc->m_ta_ra_filter); 196 WMI_CFR_FILTER_IN_AS_FP_TA_RA_TYPE_SET(cmd->filter_type, 197 rcc->en_ta_ra_filter_in_as_fp); 198 WMI_CFR_ALL_PACKET_EN_SET(cmd->filter_type, 199 rcc->m_all_packet); 200 201 /* TLV indicating array of structures to follow */ 202 buf_ptr += sizeof(wmi_cfr_capture_filter_cmd_fixed_param); 203 204 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 205 rcc->num_grp_tlvs * sizeof(wmi_cfr_filter_group_config)); 206 207 if (rcc->num_grp_tlvs) { 208 buf_ptr += WMI_TLV_HDR_SIZE; 209 param = (wmi_cfr_filter_group_config *)buf_ptr; 210 211 for (grp_id = 0; grp_id < MAX_TA_RA_ENTRIES; grp_id++) { 212 if (qdf_test_bit(grp_id, 213 &rcc->modified_in_curr_session)) { 214 populate_wmi_cfr_param(grp_id, rcc, param); 215 param++; 216 } 217 } 218 } 219 status = wmi_unified_cmd_send(wmi_handle, buf, len, 220 WMI_CFR_CAPTURE_FILTER_CMDID); 221 if (status) 222 wmi_buf_free(buf); 223 224 return status; 225 } 226 #endif 227 228 static QDF_STATUS send_peer_cfr_capture_cmd_tlv(wmi_unified_t wmi_handle, 229 struct peer_cfr_params *param) 230 { 231 wmi_peer_cfr_capture_cmd_fixed_param *cmd; 232 wmi_buf_t buf; 233 int len = sizeof(*cmd); 234 int ret; 235 236 buf = wmi_buf_alloc(wmi_handle, len); 237 if (!buf) { 238 qdf_print("%s:wmi_buf_alloc failed\n", __func__); 239 return QDF_STATUS_E_NOMEM; 240 } 241 242 cmd = (wmi_peer_cfr_capture_cmd_fixed_param *)wmi_buf_data(buf); 243 WMITLV_SET_HDR(&cmd->tlv_header, 244 WMITLV_TAG_STRUC_wmi_peer_cfr_capture_cmd_fixed_param, 245 WMITLV_GET_STRUCT_TLVLEN 246 (wmi_peer_cfr_capture_cmd_fixed_param)); 247 248 WMI_CHAR_ARRAY_TO_MAC_ADDR(param->macaddr, &cmd->mac_addr); 249 cmd->request = param->request; 250 cmd->vdev_id = param->vdev_id; 251 cmd->periodicity = param->periodicity; 252 cmd->bandwidth = param->bandwidth; 253 cmd->capture_method = param->capture_method; 254 255 ret = wmi_unified_cmd_send(wmi_handle, buf, len, 256 WMI_PEER_CFR_CAPTURE_CMDID); 257 if (QDF_IS_STATUS_ERROR(ret)) { 258 wmi_err("Failed to send WMI_PEER_CFR_CAPTURE_CMDID"); 259 wmi_buf_free(buf); 260 } 261 262 return ret; 263 } 264 265 #ifdef WLAN_ENH_CFR_ENABLE 266 static inline void wmi_enh_cfr_attach_tlv(wmi_unified_t wmi_handle) 267 { 268 struct wmi_ops *ops = wmi_handle->ops; 269 270 ops->send_cfr_rcc_cmd = send_cfr_rcc_cmd_tlv; 271 } 272 #else 273 static inline void wmi_enh_cfr_attach_tlv(wmi_unified_t wmi_handle) 274 { 275 } 276 #endif 277 278 void wmi_cfr_attach_tlv(wmi_unified_t wmi_handle) 279 { 280 struct wmi_ops *ops = wmi_handle->ops; 281 282 ops->send_peer_cfr_capture_cmd = send_peer_cfr_capture_cmd_tlv; 283 ops->extract_cfr_peer_tx_event_param = 284 extract_cfr_peer_tx_event_param_tlv; 285 wmi_enh_cfr_attach_tlv(wmi_handle); 286 } 287 #endif /* WLAN_CFR_ENABLE */ 288