htt_t2h.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948
  1. /*
  2. * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved.
  3. *
  4. * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  5. *
  6. *
  7. * Permission to use, copy, modify, and/or distribute this software for
  8. * any purpose with or without fee is hereby granted, provided that the
  9. * above copyright notice and this permission notice appear in all
  10. * copies.
  11. *
  12. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
  13. * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
  14. * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
  15. * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  16. * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
  17. * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  18. * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  19. * PERFORMANCE OF THIS SOFTWARE.
  20. */
  21. /*
  22. * This file was originally distributed by Qualcomm Atheros, Inc.
  23. * under proprietary terms before Copyright ownership was assigned
  24. * to the Linux Foundation.
  25. */
  26. /**
  27. * @file htt_t2h.c
  28. * @brief Provide functions to process target->host HTT messages.
  29. * @details
  30. * This file contains functions related to target->host HTT messages.
  31. * There are two categories of functions:
  32. * 1. A function that receives a HTT message from HTC, and dispatches it
  33. * based on the HTT message type.
  34. * 2. functions that provide the info elements from specific HTT messages.
  35. */
  36. #include <htc_api.h> /* HTC_PACKET */
  37. #include <htt.h> /* HTT_T2H_MSG_TYPE, etc. */
  38. #include <cdf_nbuf.h> /* cdf_nbuf_t */
  39. #include <ol_htt_rx_api.h>
  40. #include <ol_htt_tx_api.h>
  41. #include <ol_txrx_htt_api.h> /* htt_tx_status */
  42. #include <htt_internal.h> /* HTT_TX_SCHED, etc. */
  43. #include <pktlog_ac_fmt.h>
  44. #include <wdi_event.h>
  45. #include <ol_htt_tx_api.h>
  46. #include <ol_txrx_types.h>
  47. /*--- target->host HTT message dispatch function ----------------------------*/
  48. #ifndef DEBUG_CREDIT
  49. #define DEBUG_CREDIT 0
  50. #endif
  51. static uint8_t *htt_t2h_mac_addr_deswizzle(uint8_t *tgt_mac_addr,
  52. uint8_t *buffer)
  53. {
  54. #ifdef BIG_ENDIAN_HOST
  55. /*
  56. * The host endianness is opposite of the target endianness.
  57. * To make uint32_t elements come out correctly, the target->host
  58. * upload has swizzled the bytes in each uint32_t element of the
  59. * message.
  60. * For byte-array message fields like the MAC address, this
  61. * upload swizzling puts the bytes in the wrong order, and needs
  62. * to be undone.
  63. */
  64. buffer[0] = tgt_mac_addr[3];
  65. buffer[1] = tgt_mac_addr[2];
  66. buffer[2] = tgt_mac_addr[1];
  67. buffer[3] = tgt_mac_addr[0];
  68. buffer[4] = tgt_mac_addr[7];
  69. buffer[5] = tgt_mac_addr[6];
  70. return buffer;
  71. #else
  72. /*
  73. * The host endianness matches the target endianness -
  74. * we can use the mac addr directly from the message buffer.
  75. */
  76. return tgt_mac_addr;
  77. #endif
  78. }
  79. static void htt_rx_frag_set_last_msdu(struct htt_pdev_t *pdev, cdf_nbuf_t msg)
  80. {
  81. uint32_t *msg_word;
  82. unsigned num_msdu_bytes;
  83. cdf_nbuf_t msdu;
  84. struct htt_host_rx_desc_base *rx_desc;
  85. int start_idx;
  86. uint8_t *p_fw_msdu_rx_desc = 0;
  87. msg_word = (uint32_t *) cdf_nbuf_data(msg);
  88. num_msdu_bytes = HTT_RX_FRAG_IND_FW_RX_DESC_BYTES_GET(
  89. *(msg_word + HTT_RX_FRAG_IND_HDR_PREFIX_SIZE32));
  90. /*
  91. * 1 word for the message header,
  92. * 1 word to specify the number of MSDU bytes,
  93. * 1 word for every 4 MSDU bytes (round up),
  94. * 1 word for the MPDU range header
  95. */
  96. pdev->rx_mpdu_range_offset_words = 3 + ((num_msdu_bytes + 3) >> 2);
  97. pdev->rx_ind_msdu_byte_idx = 0;
  98. p_fw_msdu_rx_desc = ((uint8_t *) (msg_word) +
  99. HTT_ENDIAN_BYTE_IDX_SWAP
  100. (HTT_RX_FRAG_IND_FW_DESC_BYTE_OFFSET));
  101. /*
  102. * Fix for EV126710, in which BSOD occurs due to last_msdu bit
  103. * not set while the next pointer is deliberately set to NULL
  104. * before calling ol_rx_pn_check_base()
  105. *
  106. * For fragment frames, the HW may not have set the last_msdu bit
  107. * in the rx descriptor, but the SW expects this flag to be set,
  108. * since each fragment is in a separate MPDU. Thus, set the flag here,
  109. * just in case the HW didn't.
  110. */
  111. start_idx = pdev->rx_ring.sw_rd_idx.msdu_payld;
  112. msdu = pdev->rx_ring.buf.netbufs_ring[start_idx];
  113. cdf_nbuf_set_pktlen(msdu, HTT_RX_BUF_SIZE);
  114. cdf_nbuf_unmap(pdev->osdev, msdu, CDF_DMA_FROM_DEVICE);
  115. rx_desc = htt_rx_desc(msdu);
  116. *((uint8_t *) &rx_desc->fw_desc.u.val) = *p_fw_msdu_rx_desc;
  117. rx_desc->msdu_end.last_msdu = 1;
  118. cdf_nbuf_map(pdev->osdev, msdu, CDF_DMA_FROM_DEVICE);
  119. }
  120. /* Target to host Msg/event handler for low priority messages*/
  121. void htt_t2h_lp_msg_handler(void *context, cdf_nbuf_t htt_t2h_msg)
  122. {
  123. struct htt_pdev_t *pdev = (struct htt_pdev_t *)context;
  124. uint32_t *msg_word;
  125. enum htt_t2h_msg_type msg_type;
  126. msg_word = (uint32_t *) cdf_nbuf_data(htt_t2h_msg);
  127. msg_type = HTT_T2H_MSG_TYPE_GET(*msg_word);
  128. switch (msg_type) {
  129. case HTT_T2H_MSG_TYPE_VERSION_CONF:
  130. {
  131. cdf_runtime_pm_put();
  132. pdev->tgt_ver.major = HTT_VER_CONF_MAJOR_GET(*msg_word);
  133. pdev->tgt_ver.minor = HTT_VER_CONF_MINOR_GET(*msg_word);
  134. cdf_print
  135. ("target uses HTT version %d.%d; host uses %d.%d\n",
  136. pdev->tgt_ver.major, pdev->tgt_ver.minor,
  137. HTT_CURRENT_VERSION_MAJOR,
  138. HTT_CURRENT_VERSION_MINOR);
  139. if (pdev->tgt_ver.major != HTT_CURRENT_VERSION_MAJOR)
  140. cdf_print
  141. ("*** Incompatible host/target HTT versions!\n");
  142. /* abort if the target is incompatible with the host */
  143. cdf_assert(pdev->tgt_ver.major ==
  144. HTT_CURRENT_VERSION_MAJOR);
  145. if (pdev->tgt_ver.minor != HTT_CURRENT_VERSION_MINOR) {
  146. cdf_print("*** Warning: host/target HTT versions are ");
  147. cdf_print(" different, though compatible!\n");
  148. }
  149. break;
  150. }
  151. case HTT_T2H_MSG_TYPE_RX_FLUSH:
  152. {
  153. uint16_t peer_id;
  154. uint8_t tid;
  155. int seq_num_start, seq_num_end;
  156. enum htt_rx_flush_action action;
  157. peer_id = HTT_RX_FLUSH_PEER_ID_GET(*msg_word);
  158. tid = HTT_RX_FLUSH_TID_GET(*msg_word);
  159. seq_num_start =
  160. HTT_RX_FLUSH_SEQ_NUM_START_GET(*(msg_word + 1));
  161. seq_num_end =
  162. HTT_RX_FLUSH_SEQ_NUM_END_GET(*(msg_word + 1));
  163. action =
  164. HTT_RX_FLUSH_MPDU_STATUS_GET(*(msg_word + 1)) ==
  165. 1 ? htt_rx_flush_release : htt_rx_flush_discard;
  166. ol_rx_flush_handler(pdev->txrx_pdev, peer_id, tid,
  167. seq_num_start, seq_num_end, action);
  168. break;
  169. }
  170. case HTT_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND:
  171. {
  172. int msdu_cnt;
  173. msdu_cnt =
  174. HTT_RX_OFFLOAD_DELIVER_IND_MSDU_CNT_GET(*msg_word);
  175. ol_rx_offload_deliver_ind_handler(pdev->txrx_pdev,
  176. htt_t2h_msg,
  177. msdu_cnt);
  178. break;
  179. }
  180. case HTT_T2H_MSG_TYPE_RX_FRAG_IND:
  181. {
  182. uint16_t peer_id;
  183. uint8_t tid;
  184. peer_id = HTT_RX_FRAG_IND_PEER_ID_GET(*msg_word);
  185. tid = HTT_RX_FRAG_IND_EXT_TID_GET(*msg_word);
  186. htt_rx_frag_set_last_msdu(pdev, htt_t2h_msg);
  187. ol_rx_frag_indication_handler(pdev->txrx_pdev,
  188. htt_t2h_msg,
  189. peer_id, tid);
  190. break;
  191. }
  192. case HTT_T2H_MSG_TYPE_RX_ADDBA:
  193. {
  194. uint16_t peer_id;
  195. uint8_t tid;
  196. uint8_t win_sz;
  197. uint16_t start_seq_num;
  198. /*
  199. * FOR NOW, the host doesn't need to know the initial
  200. * sequence number for rx aggregation.
  201. * Thus, any value will do - specify 0.
  202. */
  203. start_seq_num = 0;
  204. peer_id = HTT_RX_ADDBA_PEER_ID_GET(*msg_word);
  205. tid = HTT_RX_ADDBA_TID_GET(*msg_word);
  206. win_sz = HTT_RX_ADDBA_WIN_SIZE_GET(*msg_word);
  207. ol_rx_addba_handler(pdev->txrx_pdev, peer_id, tid,
  208. win_sz, start_seq_num,
  209. 0 /* success */);
  210. break;
  211. }
  212. case HTT_T2H_MSG_TYPE_RX_DELBA:
  213. {
  214. uint16_t peer_id;
  215. uint8_t tid;
  216. peer_id = HTT_RX_DELBA_PEER_ID_GET(*msg_word);
  217. tid = HTT_RX_DELBA_TID_GET(*msg_word);
  218. ol_rx_delba_handler(pdev->txrx_pdev, peer_id, tid);
  219. break;
  220. }
  221. case HTT_T2H_MSG_TYPE_PEER_MAP:
  222. {
  223. uint8_t mac_addr_deswizzle_buf[HTT_MAC_ADDR_LEN];
  224. uint8_t *peer_mac_addr;
  225. uint16_t peer_id;
  226. uint8_t vdev_id;
  227. peer_id = HTT_RX_PEER_MAP_PEER_ID_GET(*msg_word);
  228. vdev_id = HTT_RX_PEER_MAP_VDEV_ID_GET(*msg_word);
  229. peer_mac_addr = htt_t2h_mac_addr_deswizzle(
  230. (uint8_t *) (msg_word + 1),
  231. &mac_addr_deswizzle_buf[0]);
  232. ol_rx_peer_map_handler(pdev->txrx_pdev, peer_id,
  233. vdev_id, peer_mac_addr,
  234. 1 /*can tx */);
  235. break;
  236. }
  237. case HTT_T2H_MSG_TYPE_PEER_UNMAP:
  238. {
  239. uint16_t peer_id;
  240. peer_id = HTT_RX_PEER_UNMAP_PEER_ID_GET(*msg_word);
  241. ol_rx_peer_unmap_handler(pdev->txrx_pdev, peer_id);
  242. break;
  243. }
  244. case HTT_T2H_MSG_TYPE_SEC_IND:
  245. {
  246. uint16_t peer_id;
  247. enum htt_sec_type sec_type;
  248. int is_unicast;
  249. peer_id = HTT_SEC_IND_PEER_ID_GET(*msg_word);
  250. sec_type = HTT_SEC_IND_SEC_TYPE_GET(*msg_word);
  251. is_unicast = HTT_SEC_IND_UNICAST_GET(*msg_word);
  252. msg_word++; /* point to the first part of the Michael key */
  253. ol_rx_sec_ind_handler(pdev->txrx_pdev, peer_id,
  254. sec_type, is_unicast, msg_word,
  255. msg_word + 2);
  256. break;
  257. }
  258. case HTT_T2H_MSG_TYPE_MGMT_TX_COMPL_IND:
  259. {
  260. struct htt_mgmt_tx_compl_ind *compl_msg;
  261. compl_msg =
  262. (struct htt_mgmt_tx_compl_ind *)(msg_word + 1);
  263. if (!ol_tx_get_is_mgmt_over_wmi_enabled()) {
  264. ol_tx_single_completion_handler(pdev->txrx_pdev,
  265. compl_msg->status,
  266. compl_msg->desc_id);
  267. cdf_runtime_pm_put();
  268. HTT_TX_SCHED(pdev);
  269. } else {
  270. cdf_print("Ignoring HTT_T2H_MSG_TYPE_MGMT_TX_COMPL_IND indication\n");
  271. }
  272. break;
  273. }
  274. case HTT_T2H_MSG_TYPE_STATS_CONF:
  275. {
  276. uint64_t cookie;
  277. uint8_t *stats_info_list;
  278. cookie = *(msg_word + 1);
  279. cookie |= ((uint64_t) (*(msg_word + 2))) << 32;
  280. stats_info_list = (uint8_t *) (msg_word + 3);
  281. cdf_runtime_pm_put();
  282. ol_txrx_fw_stats_handler(pdev->txrx_pdev, cookie,
  283. stats_info_list);
  284. break;
  285. }
  286. #ifndef REMOVE_PKT_LOG
  287. case HTT_T2H_MSG_TYPE_PKTLOG:
  288. {
  289. uint32_t *pl_hdr;
  290. uint32_t log_type;
  291. pl_hdr = (msg_word + 1);
  292. log_type =
  293. (*(pl_hdr + 1) & ATH_PKTLOG_HDR_LOG_TYPE_MASK) >>
  294. ATH_PKTLOG_HDR_LOG_TYPE_SHIFT;
  295. if ((log_type == PKTLOG_TYPE_TX_CTRL)
  296. || (log_type == PKTLOG_TYPE_TX_STAT)
  297. || (log_type == PKTLOG_TYPE_TX_MSDU_ID)
  298. || (log_type == PKTLOG_TYPE_TX_FRM_HDR)
  299. || (log_type == PKTLOG_TYPE_TX_VIRT_ADDR))
  300. wdi_event_handler(WDI_EVENT_TX_STATUS,
  301. pdev->txrx_pdev, pl_hdr);
  302. else if (log_type == PKTLOG_TYPE_RC_FIND)
  303. wdi_event_handler(WDI_EVENT_RATE_FIND,
  304. pdev->txrx_pdev, pl_hdr);
  305. else if (log_type == PKTLOG_TYPE_RC_UPDATE)
  306. wdi_event_handler(WDI_EVENT_RATE_UPDATE,
  307. pdev->txrx_pdev, pl_hdr);
  308. else if (log_type == PKTLOG_TYPE_RX_STAT)
  309. wdi_event_handler(WDI_EVENT_RX_DESC,
  310. pdev->txrx_pdev, pl_hdr);
  311. break;
  312. }
  313. #endif
  314. case HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND:
  315. {
  316. uint32_t htt_credit_delta_abs;
  317. int32_t htt_credit_delta;
  318. int sign;
  319. htt_credit_delta_abs =
  320. HTT_TX_CREDIT_DELTA_ABS_GET(*msg_word);
  321. sign = HTT_TX_CREDIT_SIGN_BIT_GET(*msg_word) ? -1 : 1;
  322. htt_credit_delta = sign * htt_credit_delta_abs;
  323. ol_tx_credit_completion_handler(pdev->txrx_pdev,
  324. htt_credit_delta);
  325. break;
  326. }
  327. case HTT_T2H_MSG_TYPE_WDI_IPA_OP_RESPONSE:
  328. {
  329. uint8_t op_code;
  330. uint16_t len;
  331. uint8_t *op_msg_buffer;
  332. uint8_t *msg_start_ptr;
  333. cdf_runtime_pm_put();
  334. msg_start_ptr = (uint8_t *) msg_word;
  335. op_code =
  336. HTT_WDI_IPA_OP_RESPONSE_OP_CODE_GET(*msg_word);
  337. msg_word++;
  338. len = HTT_WDI_IPA_OP_RESPONSE_RSP_LEN_GET(*msg_word);
  339. op_msg_buffer =
  340. cdf_mem_malloc(sizeof
  341. (struct htt_wdi_ipa_op_response_t) +
  342. len);
  343. if (!op_msg_buffer) {
  344. cdf_print("OPCODE messsage buffer alloc fail");
  345. break;
  346. }
  347. cdf_mem_copy(op_msg_buffer,
  348. msg_start_ptr,
  349. sizeof(struct htt_wdi_ipa_op_response_t) +
  350. len);
  351. ol_txrx_ipa_uc_op_response(pdev->txrx_pdev,
  352. op_msg_buffer);
  353. break;
  354. }
  355. case HTT_T2H_MSG_TYPE_FLOW_POOL_MAP:
  356. {
  357. uint8_t num_flows;
  358. struct htt_flow_pool_map_payload_t *pool_map_payoad;
  359. num_flows = HTT_FLOW_POOL_MAP_NUM_FLOWS_GET(*msg_word);
  360. msg_word++;
  361. while (num_flows) {
  362. pool_map_payoad = (struct htt_flow_pool_map_payload_t *)
  363. msg_word;
  364. ol_tx_flow_pool_map_handler(pool_map_payoad->flow_id,
  365. pool_map_payoad->flow_type,
  366. pool_map_payoad->flow_pool_id,
  367. pool_map_payoad->flow_pool_size);
  368. msg_word += (HTT_FLOW_POOL_MAP_PAYLOAD_SZ /
  369. HTT_FLOW_POOL_MAP_HEADER_SZ);
  370. num_flows--;
  371. }
  372. break;
  373. }
  374. case HTT_T2H_MSG_TYPE_FLOW_POOL_UNMAP:
  375. {
  376. struct htt_flow_pool_unmap_t *pool_numap_payload;
  377. pool_numap_payload = (struct htt_flow_pool_unmap_t *)msg_word;
  378. ol_tx_flow_pool_unmap_handler(pool_numap_payload->flow_id,
  379. pool_numap_payload->flow_type,
  380. pool_numap_payload->flow_pool_id);
  381. break;
  382. }
  383. default:
  384. break;
  385. };
  386. /* Free the indication buffer */
  387. cdf_nbuf_free(htt_t2h_msg);
  388. }
  389. /* Generic Target to host Msg/event handler for low priority messages
  390. Low priority message are handler in a different handler called from
  391. this function . So that the most likely succes path like Rx and
  392. Tx comp has little code foot print
  393. */
  394. void htt_t2h_msg_handler(void *context, HTC_PACKET *pkt)
  395. {
  396. struct htt_pdev_t *pdev = (struct htt_pdev_t *)context;
  397. cdf_nbuf_t htt_t2h_msg = (cdf_nbuf_t) pkt->pPktContext;
  398. uint32_t *msg_word;
  399. enum htt_t2h_msg_type msg_type;
  400. /* check for successful message reception */
  401. if (pkt->Status != A_OK) {
  402. if (pkt->Status != A_ECANCELED)
  403. pdev->stats.htc_err_cnt++;
  404. cdf_nbuf_free(htt_t2h_msg);
  405. return;
  406. }
  407. #ifdef HTT_RX_RESTORE
  408. if (cdf_unlikely(pdev->rx_ring.rx_reset)) {
  409. cdf_print("rx restore ..\n");
  410. cdf_nbuf_free(htt_t2h_msg);
  411. return;
  412. }
  413. #endif
  414. /* confirm alignment */
  415. HTT_ASSERT3((((unsigned long)cdf_nbuf_data(htt_t2h_msg)) & 0x3) == 0);
  416. msg_word = (uint32_t *) cdf_nbuf_data(htt_t2h_msg);
  417. msg_type = HTT_T2H_MSG_TYPE_GET(*msg_word);
  418. #if defined(HELIUMPLUS_DEBUG)
  419. cdf_print("%s %d: msg_word 0x%x msg_type %d\n",
  420. __func__, __LINE__, *msg_word, msg_type);
  421. #endif
  422. switch (msg_type) {
  423. case HTT_T2H_MSG_TYPE_RX_IND:
  424. {
  425. unsigned num_mpdu_ranges;
  426. unsigned num_msdu_bytes;
  427. uint16_t peer_id;
  428. uint8_t tid;
  429. if (cdf_unlikely(pdev->cfg.is_full_reorder_offload)) {
  430. cdf_print("HTT_T2H_MSG_TYPE_RX_IND not supported ");
  431. cdf_print("with full reorder offload\n");
  432. break;
  433. }
  434. peer_id = HTT_RX_IND_PEER_ID_GET(*msg_word);
  435. tid = HTT_RX_IND_EXT_TID_GET(*msg_word);
  436. if (tid >= OL_TXRX_NUM_EXT_TIDS) {
  437. cdf_print("HTT_T2H_MSG_TYPE_RX_IND, invalid tid %d\n",
  438. tid);
  439. break;
  440. }
  441. num_msdu_bytes =
  442. HTT_RX_IND_FW_RX_DESC_BYTES_GET(
  443. *(msg_word + 2 + HTT_RX_PPDU_DESC_SIZE32));
  444. /*
  445. * 1 word for the message header,
  446. * HTT_RX_PPDU_DESC_SIZE32 words for the FW rx PPDU desc
  447. * 1 word to specify the number of MSDU bytes,
  448. * 1 word for every 4 MSDU bytes (round up),
  449. * 1 word for the MPDU range header
  450. */
  451. pdev->rx_mpdu_range_offset_words =
  452. (HTT_RX_IND_HDR_BYTES + num_msdu_bytes + 3) >> 2;
  453. num_mpdu_ranges =
  454. HTT_RX_IND_NUM_MPDU_RANGES_GET(*(msg_word + 1));
  455. pdev->rx_ind_msdu_byte_idx = 0;
  456. ol_rx_indication_handler(pdev->txrx_pdev,
  457. htt_t2h_msg, peer_id,
  458. tid, num_mpdu_ranges);
  459. break;
  460. }
  461. case HTT_T2H_MSG_TYPE_TX_COMPL_IND:
  462. {
  463. int num_msdus;
  464. enum htt_tx_status status;
  465. /* status - no enum translation needed */
  466. status = HTT_TX_COMPL_IND_STATUS_GET(*msg_word);
  467. num_msdus = HTT_TX_COMPL_IND_NUM_GET(*msg_word);
  468. if (num_msdus & 0x1) {
  469. struct htt_tx_compl_ind_base *compl =
  470. (void *)msg_word;
  471. /*
  472. * Host CPU endianness can be different from FW CPU.
  473. * This can result in even and odd MSDU IDs being
  474. * switched. If this happens, copy the switched final
  475. * odd MSDU ID from location payload[size], to
  476. * location payload[size-1], where the message
  477. * handler function expects to find it
  478. */
  479. if (compl->payload[num_msdus] !=
  480. HTT_TX_COMPL_INV_MSDU_ID) {
  481. compl->payload[num_msdus - 1] =
  482. compl->payload[num_msdus];
  483. }
  484. }
  485. ol_tx_completion_handler(pdev->txrx_pdev, num_msdus,
  486. status, msg_word + 1);
  487. HTT_TX_SCHED(pdev);
  488. break;
  489. }
  490. case HTT_T2H_MSG_TYPE_RX_PN_IND:
  491. {
  492. uint16_t peer_id;
  493. uint8_t tid, pn_ie_cnt, *pn_ie = NULL;
  494. int seq_num_start, seq_num_end;
  495. /*First dword */
  496. peer_id = HTT_RX_PN_IND_PEER_ID_GET(*msg_word);
  497. tid = HTT_RX_PN_IND_EXT_TID_GET(*msg_word);
  498. msg_word++;
  499. /*Second dword */
  500. seq_num_start =
  501. HTT_RX_PN_IND_SEQ_NUM_START_GET(*msg_word);
  502. seq_num_end = HTT_RX_PN_IND_SEQ_NUM_END_GET(*msg_word);
  503. pn_ie_cnt = HTT_RX_PN_IND_PN_IE_CNT_GET(*msg_word);
  504. msg_word++;
  505. /*Third dword */
  506. if (pn_ie_cnt)
  507. pn_ie = (uint8_t *) msg_word;
  508. ol_rx_pn_ind_handler(pdev->txrx_pdev, peer_id, tid,
  509. seq_num_start, seq_num_end,
  510. pn_ie_cnt, pn_ie);
  511. break;
  512. }
  513. case HTT_T2H_MSG_TYPE_TX_INSPECT_IND:
  514. {
  515. int num_msdus;
  516. num_msdus = HTT_TX_COMPL_IND_NUM_GET(*msg_word);
  517. if (num_msdus & 0x1) {
  518. struct htt_tx_compl_ind_base *compl =
  519. (void *)msg_word;
  520. /*
  521. * Host CPU endianness can be different from FW CPU.
  522. * This can result in even and odd MSDU IDs being
  523. * switched. If this happens, copy the switched final
  524. * odd MSDU ID from location payload[size], to
  525. * location payload[size-1], where the message handler
  526. * function expects to find it
  527. */
  528. if (compl->payload[num_msdus] !=
  529. HTT_TX_COMPL_INV_MSDU_ID) {
  530. compl->payload[num_msdus - 1] =
  531. compl->payload[num_msdus];
  532. }
  533. }
  534. ol_tx_inspect_handler(pdev->txrx_pdev, num_msdus,
  535. msg_word + 1);
  536. HTT_TX_SCHED(pdev);
  537. break;
  538. }
  539. case HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND:
  540. {
  541. uint16_t peer_id;
  542. uint8_t tid;
  543. uint8_t offload_ind, frag_ind;
  544. if (cdf_unlikely(!pdev->cfg.is_full_reorder_offload)) {
  545. cdf_print("HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND not ");
  546. cdf_print("supported when full reorder offload is ");
  547. cdf_print("disabled in the configuration.\n");
  548. break;
  549. }
  550. peer_id = HTT_RX_IN_ORD_PADDR_IND_PEER_ID_GET(*msg_word);
  551. tid = HTT_RX_IN_ORD_PADDR_IND_EXT_TID_GET(*msg_word);
  552. offload_ind = HTT_RX_IN_ORD_PADDR_IND_OFFLOAD_GET(*msg_word);
  553. frag_ind = HTT_RX_IN_ORD_PADDR_IND_FRAG_GET(*msg_word);
  554. #if defined(HELIUMPLUS_DEBUG)
  555. cdf_print("%s %d: peerid %d tid %d offloadind %d fragind %d\n",
  556. __func__, __LINE__, peer_id, tid, offload_ind,
  557. frag_ind);
  558. #endif
  559. if (cdf_unlikely(frag_ind)) {
  560. ol_rx_frag_indication_handler(pdev->txrx_pdev,
  561. htt_t2h_msg,
  562. peer_id, tid);
  563. break;
  564. }
  565. ol_rx_in_order_indication_handler(pdev->txrx_pdev,
  566. htt_t2h_msg, peer_id,
  567. tid, offload_ind);
  568. break;
  569. }
  570. default:
  571. htt_t2h_lp_msg_handler(context, htt_t2h_msg);
  572. return;
  573. };
  574. /* Free the indication buffer */
  575. cdf_nbuf_free(htt_t2h_msg);
  576. }
  577. /*--- target->host HTT message Info Element access methods ------------------*/
  578. /*--- tx completion message ---*/
  579. uint16_t htt_tx_compl_desc_id(void *iterator, int num)
  580. {
  581. /*
  582. * The MSDU IDs are packed , 2 per 32-bit word.
  583. * Iterate on them as an array of 16-bit elements.
  584. * This will work fine if the host endianness matches
  585. * the target endianness.
  586. * If the host endianness is opposite of the target's,
  587. * this iterator will produce descriptor IDs in a different
  588. * order than the target inserted them into the message -
  589. * if the target puts in [0, 1, 2, 3, ...] the host will
  590. * put out [1, 0, 3, 2, ...].
  591. * This is fine, except for the last ID if there are an
  592. * odd number of IDs. But the TX_COMPL_IND handling code
  593. * in the htt_t2h_msg_handler already added a duplicate
  594. * of the final ID, if there were an odd number of IDs,
  595. * so this function can safely treat the IDs as an array
  596. * of 16-bit elements.
  597. */
  598. return *(((uint16_t *) iterator) + num);
  599. }
  600. /*--- rx indication message ---*/
  601. int htt_rx_ind_flush(htt_pdev_handle pdev, cdf_nbuf_t rx_ind_msg)
  602. {
  603. uint32_t *msg_word;
  604. msg_word = (uint32_t *) cdf_nbuf_data(rx_ind_msg);
  605. return HTT_RX_IND_FLUSH_VALID_GET(*msg_word);
  606. }
  607. void
  608. htt_rx_ind_flush_seq_num_range(htt_pdev_handle pdev,
  609. cdf_nbuf_t rx_ind_msg,
  610. unsigned *seq_num_start, unsigned *seq_num_end)
  611. {
  612. uint32_t *msg_word;
  613. msg_word = (uint32_t *) cdf_nbuf_data(rx_ind_msg);
  614. msg_word++;
  615. *seq_num_start = HTT_RX_IND_FLUSH_SEQ_NUM_START_GET(*msg_word);
  616. *seq_num_end = HTT_RX_IND_FLUSH_SEQ_NUM_END_GET(*msg_word);
  617. }
  618. int htt_rx_ind_release(htt_pdev_handle pdev, cdf_nbuf_t rx_ind_msg)
  619. {
  620. uint32_t *msg_word;
  621. msg_word = (uint32_t *) cdf_nbuf_data(rx_ind_msg);
  622. return HTT_RX_IND_REL_VALID_GET(*msg_word);
  623. }
  624. void
  625. htt_rx_ind_release_seq_num_range(htt_pdev_handle pdev,
  626. cdf_nbuf_t rx_ind_msg,
  627. unsigned *seq_num_start, unsigned *seq_num_end)
  628. {
  629. uint32_t *msg_word;
  630. msg_word = (uint32_t *) cdf_nbuf_data(rx_ind_msg);
  631. msg_word++;
  632. *seq_num_start = HTT_RX_IND_REL_SEQ_NUM_START_GET(*msg_word);
  633. *seq_num_end = HTT_RX_IND_REL_SEQ_NUM_END_GET(*msg_word);
  634. }
  635. void
  636. htt_rx_ind_mpdu_range_info(struct htt_pdev_t *pdev,
  637. cdf_nbuf_t rx_ind_msg,
  638. int mpdu_range_num,
  639. enum htt_rx_status *status, int *mpdu_count)
  640. {
  641. uint32_t *msg_word;
  642. msg_word = (uint32_t *) cdf_nbuf_data(rx_ind_msg);
  643. msg_word += pdev->rx_mpdu_range_offset_words + mpdu_range_num;
  644. *status = HTT_RX_IND_MPDU_STATUS_GET(*msg_word);
  645. *mpdu_count = HTT_RX_IND_MPDU_COUNT_GET(*msg_word);
  646. }
  647. /**
  648. * htt_rx_ind_rssi_dbm() - Return the RSSI provided in a rx indication message.
  649. *
  650. * @pdev: the HTT instance the rx data was received on
  651. * @rx_ind_msg: the netbuf containing the rx indication message
  652. *
  653. * Return the RSSI from an rx indication message, in dBm units.
  654. *
  655. * Return: RSSI in dBm, or HTT_INVALID_RSSI
  656. */
  657. int16_t htt_rx_ind_rssi_dbm(htt_pdev_handle pdev, cdf_nbuf_t rx_ind_msg)
  658. {
  659. int8_t rssi;
  660. uint32_t *msg_word;
  661. msg_word = (uint32_t *)
  662. (cdf_nbuf_data(rx_ind_msg) +
  663. HTT_RX_IND_FW_RX_PPDU_DESC_BYTE_OFFSET);
  664. /* check if the RX_IND message contains valid rx PPDU start info */
  665. if (!HTT_RX_IND_START_VALID_GET(*msg_word))
  666. return HTT_RSSI_INVALID;
  667. rssi = HTT_RX_IND_RSSI_CMB_GET(*msg_word);
  668. return (HTT_TGT_RSSI_INVALID == rssi) ?
  669. HTT_RSSI_INVALID : rssi;
  670. }
  671. /**
  672. * htt_rx_ind_rssi_dbm_chain() - Return the RSSI for a chain provided in a rx
  673. * indication message.
  674. * @pdev: the HTT instance the rx data was received on
  675. * @rx_ind_msg: the netbuf containing the rx indication message
  676. * @chain: the index of the chain (0-4)
  677. *
  678. * Return the RSSI for a chain from an rx indication message, in dBm units.
  679. *
  680. * Return: RSSI, or HTT_INVALID_RSSI
  681. */
  682. int16_t
  683. htt_rx_ind_rssi_dbm_chain(htt_pdev_handle pdev, cdf_nbuf_t rx_ind_msg,
  684. int8_t chain)
  685. {
  686. int8_t rssi;
  687. uint32_t *msg_word;
  688. if (chain < 0 || chain > 3)
  689. return HTT_RSSI_INVALID;
  690. msg_word = (uint32_t *)
  691. (cdf_nbuf_data(rx_ind_msg) +
  692. HTT_RX_IND_FW_RX_PPDU_DESC_BYTE_OFFSET);
  693. /* check if the RX_IND message contains valid rx PPDU start info */
  694. if (!HTT_RX_IND_START_VALID_GET(*msg_word))
  695. return HTT_RSSI_INVALID;
  696. msg_word += 1 + chain;
  697. rssi = HTT_RX_IND_RSSI_PRI20_GET(*msg_word);
  698. return (HTT_TGT_RSSI_INVALID == rssi) ?
  699. HTT_RSSI_INVALID :
  700. rssi;
  701. }
  702. /**
  703. * htt_rx_ind_legacy_rate() - Return the data rate
  704. * @pdev: the HTT instance the rx data was received on
  705. * @rx_ind_msg: the netbuf containing the rx indication message
  706. * @legacy_rate: (output) the data rate
  707. * The legacy_rate parameter's value depends on the
  708. * legacy_rate_sel value.
  709. * If legacy_rate_sel is 0:
  710. * 0x8: OFDM 48 Mbps
  711. * 0x9: OFDM 24 Mbps
  712. * 0xA: OFDM 12 Mbps
  713. * 0xB: OFDM 6 Mbps
  714. * 0xC: OFDM 54 Mbps
  715. * 0xD: OFDM 36 Mbps
  716. * 0xE: OFDM 18 Mbps
  717. * 0xF: OFDM 9 Mbps
  718. * If legacy_rate_sel is 1:
  719. * 0x8: CCK 11 Mbps long preamble
  720. * 0x9: CCK 5.5 Mbps long preamble
  721. * 0xA: CCK 2 Mbps long preamble
  722. * 0xB: CCK 1 Mbps long preamble
  723. * 0xC: CCK 11 Mbps short preamble
  724. * 0xD: CCK 5.5 Mbps short preamble
  725. * 0xE: CCK 2 Mbps short preamble
  726. * -1 on error.
  727. * @legacy_rate_sel: (output) 0 to indicate OFDM, 1 to indicate CCK.
  728. * -1 on error.
  729. *
  730. * Return the data rate provided in a rx indication message.
  731. */
  732. void
  733. htt_rx_ind_legacy_rate(htt_pdev_handle pdev, cdf_nbuf_t rx_ind_msg,
  734. uint8_t *legacy_rate, uint8_t *legacy_rate_sel)
  735. {
  736. uint32_t *msg_word;
  737. msg_word = (uint32_t *)
  738. (cdf_nbuf_data(rx_ind_msg) +
  739. HTT_RX_IND_FW_RX_PPDU_DESC_BYTE_OFFSET);
  740. /* check if the RX_IND message contains valid rx PPDU start info */
  741. if (!HTT_RX_IND_START_VALID_GET(*msg_word)) {
  742. *legacy_rate = -1;
  743. *legacy_rate_sel = -1;
  744. return;
  745. }
  746. *legacy_rate = HTT_RX_IND_LEGACY_RATE_GET(*msg_word);
  747. *legacy_rate_sel = HTT_RX_IND_LEGACY_RATE_SEL_GET(*msg_word);
  748. }
  749. /**
  750. * htt_rx_ind_timestamp() - Return the timestamp
  751. * @pdev: the HTT instance the rx data was received on
  752. * @rx_ind_msg: the netbuf containing the rx indication message
  753. * @timestamp_microsec: (output) the timestamp to microsecond resolution.
  754. * -1 on error.
  755. * @timestamp_submicrosec: the submicrosecond portion of the
  756. * timestamp. -1 on error.
  757. *
  758. * Return the timestamp provided in a rx indication message.
  759. */
  760. void
  761. htt_rx_ind_timestamp(htt_pdev_handle pdev, cdf_nbuf_t rx_ind_msg,
  762. uint32_t *timestamp_microsec,
  763. uint8_t *timestamp_submicrosec)
  764. {
  765. uint32_t *msg_word;
  766. msg_word = (uint32_t *)
  767. (cdf_nbuf_data(rx_ind_msg) +
  768. HTT_RX_IND_FW_RX_PPDU_DESC_BYTE_OFFSET);
  769. /* check if the RX_IND message contains valid rx PPDU start info */
  770. if (!HTT_RX_IND_END_VALID_GET(*msg_word)) {
  771. *timestamp_microsec = -1;
  772. *timestamp_submicrosec = -1;
  773. return;
  774. }
  775. *timestamp_microsec = *(msg_word + 6);
  776. *timestamp_submicrosec =
  777. HTT_RX_IND_TIMESTAMP_SUBMICROSEC_GET(*msg_word);
  778. }
  779. #define INVALID_TSF -1
  780. /**
  781. * htt_rx_ind_tsf32() - Return the TSF timestamp
  782. * @pdev: the HTT instance the rx data was received on
  783. * @rx_ind_msg: the netbuf containing the rx indication message
  784. *
  785. * Return the TSF timestamp provided in a rx indication message.
  786. *
  787. * Return: TSF timestamp
  788. */
  789. uint32_t
  790. htt_rx_ind_tsf32(htt_pdev_handle pdev, cdf_nbuf_t rx_ind_msg)
  791. {
  792. uint32_t *msg_word;
  793. msg_word = (uint32_t *)
  794. (cdf_nbuf_data(rx_ind_msg) +
  795. HTT_RX_IND_FW_RX_PPDU_DESC_BYTE_OFFSET);
  796. /* check if the RX_IND message contains valid rx PPDU start info */
  797. if (!HTT_RX_IND_END_VALID_GET(*msg_word))
  798. return INVALID_TSF;
  799. return *(msg_word + 5);
  800. }
  801. /**
  802. * htt_rx_ind_ext_tid() - Return the extended traffic ID provided in a rx indication message.
  803. * @pdev: the HTT instance the rx data was received on
  804. * @rx_ind_msg: the netbuf containing the rx indication message
  805. *
  806. * Return the extended traffic ID in a rx indication message.
  807. *
  808. * Return: Extended TID
  809. */
  810. uint8_t
  811. htt_rx_ind_ext_tid(htt_pdev_handle pdev, cdf_nbuf_t rx_ind_msg)
  812. {
  813. uint32_t *msg_word;
  814. msg_word = (uint32_t *)
  815. (cdf_nbuf_data(rx_ind_msg));
  816. return HTT_RX_IND_EXT_TID_GET(*msg_word);
  817. }
  818. /*--- stats confirmation message ---*/
  819. void
  820. htt_t2h_dbg_stats_hdr_parse(uint8_t *stats_info_list,
  821. enum htt_dbg_stats_type *type,
  822. enum htt_dbg_stats_status *status,
  823. int *length, uint8_t **stats_data)
  824. {
  825. uint32_t *msg_word = (uint32_t *) stats_info_list;
  826. *type = HTT_T2H_STATS_CONF_TLV_TYPE_GET(*msg_word);
  827. *status = HTT_T2H_STATS_CONF_TLV_STATUS_GET(*msg_word);
  828. *length = HTT_T2H_STATS_CONF_TLV_HDR_SIZE + /* header length */
  829. HTT_T2H_STATS_CONF_TLV_LENGTH_GET(*msg_word); /* data len */
  830. *stats_data = stats_info_list + HTT_T2H_STATS_CONF_TLV_HDR_SIZE;
  831. }
  832. void
  833. htt_rx_frag_ind_flush_seq_num_range(htt_pdev_handle pdev,
  834. cdf_nbuf_t rx_frag_ind_msg,
  835. int *seq_num_start, int *seq_num_end)
  836. {
  837. uint32_t *msg_word;
  838. msg_word = (uint32_t *) cdf_nbuf_data(rx_frag_ind_msg);
  839. msg_word++;
  840. *seq_num_start = HTT_RX_FRAG_IND_FLUSH_SEQ_NUM_START_GET(*msg_word);
  841. *seq_num_end = HTT_RX_FRAG_IND_FLUSH_SEQ_NUM_END_GET(*msg_word);
  842. }