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