1 /* 2 * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for 6 * any purpose with or without fee is hereby granted, provided that the 7 * above copyright notice and this permission notice appear in all 8 * copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /** 21 * @file htt_rx.c 22 * @brief Implement receive aspects of HTT. 23 * @details 24 * This file contains three categories of HTT rx code: 25 * 1. An abstraction of the rx descriptor, to hide the 26 * differences between the HL vs. LL rx descriptor. 27 * 2. Functions for providing access to the (series of) 28 * rx descriptor(s) and rx frame(s) associated with 29 * an rx indication message. 30 * 3. Functions for setting up and using the MAC DMA 31 * rx ring (applies to LL only). 32 */ 33 34 #include <qdf_mem.h> /* qdf_mem_malloc,free, etc. */ 35 #include <qdf_types.h> /* qdf_print, bool */ 36 #include <qdf_nbuf.h> /* qdf_nbuf_t, etc. */ 37 #include <qdf_timer.h> /* qdf_timer_free */ 38 39 #include <htt.h> /* HTT_HL_RX_DESC_SIZE */ 40 #include <ol_cfg.h> 41 #include <ol_rx.h> 42 #include <ol_htt_rx_api.h> 43 #include <htt_internal.h> /* HTT_ASSERT, htt_pdev_t, HTT_RX_BUF_SIZE */ 44 #include "regtable.h" 45 46 #include <cds_ieee80211_common.h> /* ieee80211_frame, ieee80211_qoscntl */ 47 #include <cds_utils.h> 48 #include <wlan_policy_mgr_api.h> 49 #include "ol_txrx_types.h" 50 #ifdef DEBUG_DMA_DONE 51 #include <asm/barrier.h> 52 #include <wma_api.h> 53 #endif 54 #include <pktlog_ac_fmt.h> 55 56 /** 57 * htt_rx_mpdu_wifi_hdr_retrieve() - retrieve 802.11 header 58 * @pdev - pdev handle 59 * @mpdu_desc - mpdu descriptor 60 * 61 * Return : pointer to 802.11 header 62 */ 63 char *htt_rx_mpdu_wifi_hdr_retrieve(htt_pdev_handle pdev, void *mpdu_desc) 64 { 65 struct htt_host_rx_desc_base *rx_desc = 66 (struct htt_host_rx_desc_base *)mpdu_desc; 67 68 if (!rx_desc) 69 return NULL; 70 else 71 return rx_desc->rx_hdr_status; 72 } 73 74 /** 75 * htt_rx_mpdu_desc_tsf32() - Return the TSF timestamp indicating when 76 * a MPDU was received. 77 * @pdev - the HTT instance the rx data was received on 78 * @mpdu_desc - the abstract descriptor for the MPDU in question 79 * 80 * return : 32 LSBs of TSF time at which the MPDU's PPDU was received 81 */ 82 uint32_t htt_rx_mpdu_desc_tsf32(htt_pdev_handle pdev, void *mpdu_desc) 83 { 84 return 0; 85 } 86 87 static inline 88 uint8_t htt_rx_msdu_fw_desc_get(htt_pdev_handle pdev, void *msdu_desc) 89 { 90 /* 91 * HL and LL use the same format for FW rx desc, but have the FW rx desc 92 * in different locations. 93 * In LL, the FW rx descriptor has been copied into the same 94 * htt_host_rx_desc_base struct that holds the HW rx desc. 95 * In HL, the FW rx descriptor, along with the MSDU payload, 96 * is in the same buffer as the rx indication message. 97 * 98 * Use the FW rx desc offset configured during startup to account for 99 * this difference between HL vs. LL. 100 * 101 * An optimization would be to define the LL and HL msdu_desc pointer 102 * in such a way that they both use the same offset to the FW rx desc. 103 * Then the following functions could be converted to macros, without 104 * needing to expose the htt_pdev_t definition outside HTT. 105 */ 106 return *(((uint8_t *)msdu_desc) + pdev->rx_fw_desc_offset); 107 } 108 109 int htt_rx_msdu_discard(htt_pdev_handle pdev, void *msdu_desc) 110 { 111 return htt_rx_msdu_fw_desc_get(pdev, msdu_desc) & FW_RX_DESC_DISCARD_M; 112 } 113 114 int htt_rx_msdu_forward(htt_pdev_handle pdev, void *msdu_desc) 115 { 116 return htt_rx_msdu_fw_desc_get(pdev, msdu_desc) & FW_RX_DESC_FORWARD_M; 117 } 118 119 int htt_rx_msdu_inspect(htt_pdev_handle pdev, void *msdu_desc) 120 { 121 return htt_rx_msdu_fw_desc_get(pdev, msdu_desc) & FW_RX_DESC_INSPECT_M; 122 } 123 124 void 125 htt_rx_msdu_actions(htt_pdev_handle pdev, 126 void *msdu_desc, int *discard, int *forward, int *inspect) 127 { 128 uint8_t rx_msdu_fw_desc = htt_rx_msdu_fw_desc_get(pdev, msdu_desc); 129 #ifdef HTT_DEBUG_DATA 130 HTT_PRINT("act:0x%x ", rx_msdu_fw_desc); 131 #endif 132 *discard = rx_msdu_fw_desc & FW_RX_DESC_DISCARD_M; 133 *forward = rx_msdu_fw_desc & FW_RX_DESC_FORWARD_M; 134 *inspect = rx_msdu_fw_desc & FW_RX_DESC_INSPECT_M; 135 } 136 137 uint32_t htt_rx_amsdu_rx_in_order_get_pktlog(qdf_nbuf_t rx_ind_msg) 138 { 139 uint32_t *msg_word; 140 141 msg_word = (uint32_t *)qdf_nbuf_data(rx_ind_msg); 142 return HTT_RX_IN_ORD_PADDR_IND_PKTLOG_GET(*msg_word); 143 } 144 145 int16_t htt_rx_mpdu_desc_rssi_dbm(htt_pdev_handle pdev, void *mpdu_desc) 146 { 147 /* 148 * Currently the RSSI is provided only as a field in the 149 * HTT_T2H_RX_IND message, rather than in each rx descriptor. 150 */ 151 return HTT_RSSI_INVALID; 152 } 153 154 /* 155 * htt_rx_amsdu_pop - 156 * global function pointer that is programmed during attach to point 157 * to either htt_rx_amsdu_pop_ll or htt_rx_amsdu_rx_in_order_pop_ll. 158 */ 159 int (*htt_rx_amsdu_pop)(htt_pdev_handle pdev, 160 qdf_nbuf_t rx_ind_msg, 161 qdf_nbuf_t *head_msdu, qdf_nbuf_t *tail_msdu, 162 uint32_t *msdu_count); 163 164 /* 165 * htt_rx_frag_pop - 166 * global function pointer that is programmed during attach to point 167 * to either htt_rx_amsdu_pop_ll 168 */ 169 int (*htt_rx_frag_pop)(htt_pdev_handle pdev, 170 qdf_nbuf_t rx_ind_msg, 171 qdf_nbuf_t *head_msdu, qdf_nbuf_t *tail_msdu, 172 uint32_t *msdu_count); 173 174 int (*htt_rx_offload_msdu_cnt)(htt_pdev_handle pdev); 175 176 int 177 (*htt_rx_offload_msdu_pop)(htt_pdev_handle pdev, 178 qdf_nbuf_t offload_deliver_msg, 179 int *vdev_id, 180 int *peer_id, 181 int *tid, 182 uint8_t *fw_desc, 183 qdf_nbuf_t *head_buf, qdf_nbuf_t *tail_buf); 184 185 void * (*htt_rx_mpdu_desc_list_next)(htt_pdev_handle pdev, 186 qdf_nbuf_t rx_ind_msg); 187 188 bool (*htt_rx_mpdu_desc_retry)(htt_pdev_handle pdev, void *mpdu_desc); 189 190 uint16_t (*htt_rx_mpdu_desc_seq_num)(htt_pdev_handle pdev, void *mpdu_desc, 191 bool update_seq_num); 192 193 void (*htt_rx_mpdu_desc_pn)(htt_pdev_handle pdev, 194 void *mpdu_desc, 195 union htt_rx_pn_t *pn, int pn_len_bits); 196 197 uint8_t (*htt_rx_mpdu_desc_tid)(htt_pdev_handle pdev, void *mpdu_desc); 198 199 bool (*htt_rx_msdu_desc_completes_mpdu)(htt_pdev_handle pdev, void *msdu_desc); 200 201 bool (*htt_rx_msdu_first_msdu_flag)(htt_pdev_handle pdev, void *msdu_desc); 202 203 int (*htt_rx_msdu_has_wlan_mcast_flag)(htt_pdev_handle pdev, void *msdu_desc); 204 205 bool (*htt_rx_msdu_is_wlan_mcast)(htt_pdev_handle pdev, void *msdu_desc); 206 207 int (*htt_rx_msdu_is_frag)(htt_pdev_handle pdev, void *msdu_desc); 208 209 void * (*htt_rx_msdu_desc_retrieve)(htt_pdev_handle pdev, qdf_nbuf_t msdu); 210 211 bool (*htt_rx_mpdu_is_encrypted)(htt_pdev_handle pdev, void *mpdu_desc); 212 213 bool (*htt_rx_msdu_desc_key_id)(htt_pdev_handle pdev, 214 void *mpdu_desc, uint8_t *key_id); 215 216 bool (*htt_rx_msdu_chan_info_present)( 217 htt_pdev_handle pdev, 218 void *mpdu_desc); 219 220 bool (*htt_rx_msdu_center_freq)( 221 htt_pdev_handle pdev, 222 struct ol_txrx_peer_t *peer, 223 void *mpdu_desc, 224 uint16_t *primary_chan_center_freq_mhz, 225 uint16_t *contig_chan1_center_freq_mhz, 226 uint16_t *contig_chan2_center_freq_mhz, 227 uint8_t *phy_mode); 228 229 void htt_rx_desc_frame_free(htt_pdev_handle htt_pdev, qdf_nbuf_t msdu) 230 { 231 qdf_nbuf_free(msdu); 232 } 233 234 void htt_rx_msdu_desc_free(htt_pdev_handle htt_pdev, qdf_nbuf_t msdu) 235 { 236 /* 237 * The rx descriptor is in the same buffer as the rx MSDU payload, 238 * and does not need to be freed separately. 239 */ 240 } 241 242 void htt_rx_msdu_buff_replenish(htt_pdev_handle pdev) 243 { 244 if (qdf_atomic_dec_and_test(&pdev->rx_ring.refill_ref_cnt)) 245 htt_rx_fill_ring_count(pdev); 246 247 qdf_atomic_inc(&pdev->rx_ring.refill_ref_cnt); 248 } 249 250 #ifdef IPA_OFFLOAD 251 #ifdef QCA_WIFI_3_0 252 /** 253 * htt_rx_ipa_uc_alloc_wdi2_rsc() - Allocate WDI2.0 resources 254 * @pdev: htt context 255 * @rx_ind_ring_elements: rx ring elements 256 * 257 * Return: 0 success 258 */ 259 static int htt_rx_ipa_uc_alloc_wdi2_rsc(struct htt_pdev_t *pdev, 260 unsigned int rx_ind_ring_elements) 261 { 262 /* 263 * Allocate RX2 indication ring 264 * RX2 IND ring element 265 * 4bytes: pointer 266 * 2bytes: VDEV ID 267 * 2bytes: length 268 * 269 * RX indication ring size, by bytes 270 */ 271 pdev->ipa_uc_rx_rsc.rx2_ind_ring = 272 qdf_mem_shared_mem_alloc(pdev->osdev, 273 rx_ind_ring_elements * 274 sizeof(target_paddr_t)); 275 if (!pdev->ipa_uc_rx_rsc.rx2_ind_ring) { 276 QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_ERROR, 277 "%s: Unable to allocate memory for IPA rx2 ind ring", 278 __func__); 279 return 1; 280 } 281 282 pdev->ipa_uc_rx_rsc.rx2_ipa_prc_done_idx = 283 qdf_mem_shared_mem_alloc(pdev->osdev, 4); 284 if (!pdev->ipa_uc_rx_rsc.rx2_ipa_prc_done_idx) { 285 QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_ERROR, 286 "%s: Unable to allocate memory for IPA rx proc done index", 287 __func__); 288 qdf_mem_shared_mem_free(pdev->osdev, 289 pdev->ipa_uc_rx_rsc.rx2_ind_ring); 290 return 1; 291 } 292 293 return 0; 294 } 295 296 /** 297 * htt_rx_ipa_uc_free_wdi2_rsc() - Free WDI2.0 resources 298 * @pdev: htt context 299 * 300 * Return: None 301 */ 302 static void htt_rx_ipa_uc_free_wdi2_rsc(struct htt_pdev_t *pdev) 303 { 304 qdf_mem_shared_mem_free(pdev->osdev, pdev->ipa_uc_rx_rsc.rx2_ind_ring); 305 qdf_mem_shared_mem_free(pdev->osdev, 306 pdev->ipa_uc_rx_rsc.rx2_ipa_prc_done_idx); 307 } 308 #else 309 static int htt_rx_ipa_uc_alloc_wdi2_rsc(struct htt_pdev_t *pdev, 310 unsigned int rx_ind_ring_elements) 311 { 312 return 0; 313 } 314 315 static void htt_rx_ipa_uc_free_wdi2_rsc(struct htt_pdev_t *pdev) 316 { 317 } 318 #endif 319 320 /** 321 * htt_rx_ipa_uc_attach() - attach htt ipa uc rx resource 322 * @pdev: htt context 323 * @rx_ind_ring_size: rx ring size 324 * 325 * Return: 0 success 326 */ 327 int htt_rx_ipa_uc_attach(struct htt_pdev_t *pdev, 328 unsigned int rx_ind_ring_elements) 329 { 330 int ret = 0; 331 332 /* 333 * Allocate RX indication ring 334 * RX IND ring element 335 * 4bytes: pointer 336 * 2bytes: VDEV ID 337 * 2bytes: length 338 */ 339 pdev->ipa_uc_rx_rsc.rx_ind_ring = 340 qdf_mem_shared_mem_alloc(pdev->osdev, 341 rx_ind_ring_elements * 342 sizeof(struct ipa_uc_rx_ring_elem_t)); 343 if (!pdev->ipa_uc_rx_rsc.rx_ind_ring) { 344 QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_ERROR, 345 "%s: Unable to allocate memory for IPA rx ind ring", 346 __func__); 347 return 1; 348 } 349 350 pdev->ipa_uc_rx_rsc.rx_ipa_prc_done_idx = 351 qdf_mem_shared_mem_alloc(pdev->osdev, 4); 352 if (!pdev->ipa_uc_rx_rsc.rx_ipa_prc_done_idx) { 353 QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_ERROR, 354 "%s: Unable to allocate memory for IPA rx proc done index", 355 __func__); 356 qdf_mem_shared_mem_free(pdev->osdev, 357 pdev->ipa_uc_rx_rsc.rx_ind_ring); 358 return 1; 359 } 360 361 ret = htt_rx_ipa_uc_alloc_wdi2_rsc(pdev, rx_ind_ring_elements); 362 if (ret) { 363 qdf_mem_shared_mem_free(pdev->osdev, pdev->ipa_uc_rx_rsc.rx_ind_ring); 364 qdf_mem_shared_mem_free(pdev->osdev, 365 pdev->ipa_uc_rx_rsc.rx_ipa_prc_done_idx); 366 } 367 return ret; 368 } 369 370 int htt_rx_ipa_uc_detach(struct htt_pdev_t *pdev) 371 { 372 qdf_mem_shared_mem_free(pdev->osdev, pdev->ipa_uc_rx_rsc.rx_ind_ring); 373 qdf_mem_shared_mem_free(pdev->osdev, 374 pdev->ipa_uc_rx_rsc.rx_ipa_prc_done_idx); 375 376 htt_rx_ipa_uc_free_wdi2_rsc(pdev); 377 return 0; 378 } 379 #endif /* IPA_OFFLOAD */ 380 381 #ifdef CONNECTIVITY_PKTLOG 382 /** 383 * htt_register_rx_pkt_dump_callback() - registers callback to 384 * get rx pkt status and call callback to do rx packet dump 385 * 386 * @pdev: htt pdev handle 387 * @callback: callback to get rx pkt status and 388 * call callback to do rx packet dump 389 * 390 * This function is used to register the callback to get 391 * rx pkt status and call callback to do rx packet dump 392 * 393 * Return: None 394 * 395 */ 396 void htt_register_rx_pkt_dump_callback(struct htt_pdev_t *pdev, 397 tp_rx_pkt_dump_cb callback) 398 { 399 if (!pdev) { 400 qdf_print("pdev is NULL"); 401 return; 402 } 403 pdev->rx_pkt_dump_cb = callback; 404 } 405 406 /** 407 * htt_deregister_rx_pkt_dump_callback() - deregisters callback to 408 * get rx pkt status and call callback to do rx packet dump 409 * 410 * @pdev: htt pdev handle 411 * 412 * This function is used to deregister the callback to get 413 * rx pkt status and call callback to do rx packet dump 414 * 415 * Return: None 416 * 417 */ 418 void htt_deregister_rx_pkt_dump_callback(struct htt_pdev_t *pdev) 419 { 420 if (!pdev) { 421 qdf_print("pdev is NULL"); 422 return; 423 } 424 pdev->rx_pkt_dump_cb = NULL; 425 } 426 #endif 427 428 #ifdef WLAN_FEATURE_TSF_PLUS 429 void htt_rx_enable_ppdu_end(int *enable_ppdu_end) 430 { 431 *enable_ppdu_end = 1; 432 } 433 #endif 434