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_FILTER_GROUP_BITMAP_SET(cmd->filter_group_bitmap, 165 rcc->filter_group_bitmap); 166 WMI_CFR_UL_MU_USER_UPPER_SET(cmd->ul_mu_user_mask_upper, 167 rcc->ul_mu_user_mask_upper); 168 cmd->ul_mu_user_mask_lower = rcc->ul_mu_user_mask_lower; 169 WMI_CFR_FREEZE_DELAY_CNT_EN_SET(cmd->freeze_tlv_delay_cnt, 170 rcc->freeze_tlv_delay_cnt_en); 171 WMI_CFR_FREEZE_DELAY_CNT_THR_SET(cmd->freeze_tlv_delay_cnt, 172 rcc->freeze_tlv_delay_cnt_thr); 173 WMI_CFR_DIRECTED_FTM_ACK_EN_SET(cmd->filter_type, 174 rcc->m_directed_ftm); 175 WMI_CFR_ALL_FTM_ACK_EN_SET(cmd->filter_type, 176 rcc->m_all_ftm_ack); 177 WMI_CFR_NDPA_NDP_DIRECTED_EN_SET(cmd->filter_type, 178 rcc->m_ndpa_ndp_directed); 179 WMI_CFR_NDPA_NDP_ALL_EN_SET(cmd->filter_type, 180 rcc->m_ndpa_ndp_all); 181 WMI_CFR_TA_RA_TYPE_FILTER_EN_SET(cmd->filter_type, 182 rcc->m_ta_ra_filter); 183 WMI_CFR_ALL_PACKET_EN_SET(cmd->filter_type, 184 rcc->m_all_packet); 185 186 /* TLV indicating array of structures to follow */ 187 buf_ptr += sizeof(wmi_cfr_capture_filter_cmd_fixed_param); 188 189 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 190 rcc->num_grp_tlvs * sizeof(wmi_cfr_filter_group_config)); 191 192 if (rcc->num_grp_tlvs) { 193 buf_ptr += WMI_TLV_HDR_SIZE; 194 param = (wmi_cfr_filter_group_config *)buf_ptr; 195 196 for (grp_id = 0; grp_id < MAX_TA_RA_ENTRIES; grp_id++) { 197 if (qdf_test_bit(grp_id, 198 (unsigned long *) 199 &rcc->modified_in_curr_session)) { 200 populate_wmi_cfr_param(grp_id, rcc, param); 201 param++; 202 } 203 } 204 } 205 status = wmi_unified_cmd_send(wmi_handle, buf, len, 206 WMI_CFR_CAPTURE_FILTER_CMDID); 207 if (status) 208 wmi_buf_free(buf); 209 210 return status; 211 } 212 #endif 213 214 static QDF_STATUS send_peer_cfr_capture_cmd_tlv(wmi_unified_t wmi_handle, 215 struct peer_cfr_params *param) 216 { 217 wmi_peer_cfr_capture_cmd_fixed_param *cmd; 218 wmi_buf_t buf; 219 int len = sizeof(*cmd); 220 int ret; 221 222 buf = wmi_buf_alloc(wmi_handle, len); 223 if (!buf) { 224 qdf_print("%s:wmi_buf_alloc failed\n", __func__); 225 return QDF_STATUS_E_NOMEM; 226 } 227 228 cmd = (wmi_peer_cfr_capture_cmd_fixed_param *)wmi_buf_data(buf); 229 WMITLV_SET_HDR(&cmd->tlv_header, 230 WMITLV_TAG_STRUC_wmi_peer_cfr_capture_cmd_fixed_param, 231 WMITLV_GET_STRUCT_TLVLEN 232 (wmi_peer_cfr_capture_cmd_fixed_param)); 233 234 WMI_CHAR_ARRAY_TO_MAC_ADDR(param->macaddr, &cmd->mac_addr); 235 cmd->request = param->request; 236 cmd->vdev_id = param->vdev_id; 237 cmd->periodicity = param->periodicity; 238 cmd->bandwidth = param->bandwidth; 239 cmd->capture_method = param->capture_method; 240 241 ret = wmi_unified_cmd_send(wmi_handle, buf, len, 242 WMI_PEER_CFR_CAPTURE_CMDID); 243 if (QDF_IS_STATUS_ERROR(ret)) { 244 WMI_LOGE("Failed to send WMI_PEER_CFR_CAPTURE_CMDID"); 245 wmi_buf_free(buf); 246 } 247 248 return ret; 249 } 250 251 #ifdef WLAN_ENH_CFR_ENABLE 252 static inline void wmi_enh_cfr_attach_tlv(wmi_unified_t wmi_handle) 253 { 254 struct wmi_ops *ops = wmi_handle->ops; 255 256 ops->send_cfr_rcc_cmd = send_cfr_rcc_cmd_tlv; 257 } 258 #else 259 static inline void wmi_enh_cfr_attach_tlv(wmi_unified_t wmi_handle) 260 { 261 } 262 #endif 263 264 void wmi_cfr_attach_tlv(wmi_unified_t wmi_handle) 265 { 266 struct wmi_ops *ops = wmi_handle->ops; 267 268 ops->send_peer_cfr_capture_cmd = send_peer_cfr_capture_cmd_tlv; 269 ops->extract_cfr_peer_tx_event_param = 270 extract_cfr_peer_tx_event_param_tlv; 271 wmi_enh_cfr_attach_tlv(wmi_handle); 272 } 273 #endif /* WLAN_CFR_ENABLE */ 274