PageRenderTime 62ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/drivers/net/wireless/sd8797/mlan/mlan_wmm.c

https://bitbucket.org/cyanogenmod/android_kernel_asus_tf300t
C | 2521 lines | 1609 code | 319 blank | 593 comment | 217 complexity | 023668abc83217137f2911e85c46548b MD5 | raw file
Possible License(s): LGPL-2.0, AGPL-1.0, GPL-2.0
  1. /** @file mlan_wmm.c
  2. *
  3. * @brief This file contains functions for WMM.
  4. *
  5. * Copyright (C) 2008-2011, Marvell International Ltd.
  6. *
  7. * This software file (the "File") is distributed by Marvell International
  8. * Ltd. under the terms of the GNU General Public License Version 2, June 1991
  9. * (the "License"). You may use, redistribute and/or modify this File in
  10. * accordance with the terms and conditions of the License, a copy of which
  11. * is available by writing to the Free Software Foundation, Inc.,
  12. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
  13. * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
  14. *
  15. * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
  16. * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
  17. * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
  18. * this warranty disclaimer.
  19. */
  20. /********************************************************
  21. Change log:
  22. 10/24/2008: initial version
  23. ********************************************************/
  24. #include "mlan.h"
  25. #ifdef STA_SUPPORT
  26. #include "mlan_join.h"
  27. #endif
  28. #include "mlan_util.h"
  29. #include "mlan_fw.h"
  30. #include "mlan_main.h"
  31. #include "mlan_wmm.h"
  32. #include "mlan_11n.h"
  33. #include "mlan_sdio.h"
  34. /********************************************************
  35. Local Variables
  36. ********************************************************/
  37. /** Maximum value FW can accept for driver delay in packet transmission */
  38. #define DRV_PKT_DELAY_TO_FW_MAX 512
  39. /*
  40. * Upper and Lower threshold for packet queuing in the driver
  41. * - When the number of packets queued reaches the upper limit,
  42. * the driver will stop the net queue in the app/kernel space.
  43. * - When the number of packets drops beneath the lower limit after
  44. * having reached the upper limit, the driver will restart the net
  45. * queue.
  46. */
  47. /** Lower threshold for packet queuing in the driver.
  48. * When the number of packets drops beneath the lower limit after having
  49. * reached the upper limit, the driver will restart the net queue.
  50. */
  51. #define WMM_QUEUED_PACKET_LOWER_LIMIT 180
  52. /** Upper threshold for packet queuing in the driver.
  53. * When the number of packets queued reaches the upper limit, the driver
  54. * will stop the net queue in the app/kernel space.
  55. */
  56. #define WMM_QUEUED_PACKET_UPPER_LIMIT 200
  57. /** Offset for TOS field in the IP header */
  58. #define IPTOS_OFFSET 5
  59. /** WMM information IE */
  60. static const t_u8 wmm_info_ie[] = { WMM_IE, 0x07,
  61. 0x00, 0x50, 0xf2, 0x02,
  62. 0x00, 0x01, 0x00
  63. };
  64. /**
  65. * AC Priorities go from AC_BK to AC_VO. The ACI enumeration for AC_BK (1)
  66. * is higher than the enumeration for AC_BE (0); hence the needed
  67. * mapping conversion for wmm AC to priority Queue Index
  68. */
  69. static const t_u8 wmm_aci_to_qidx_map[] = { WMM_AC_BE,
  70. WMM_AC_BK,
  71. WMM_AC_VI,
  72. WMM_AC_VO
  73. };
  74. /**
  75. * This table will be used to store the tid values based on ACs.
  76. * It is initialized to default values per TID.
  77. */
  78. t_u8 tos_to_tid[] = {
  79. /* TID DSCP_P2 DSCP_P1 DSCP_P0 WMM_AC */
  80. 0x01, /* 0 1 0 AC_BK */
  81. 0x02, /* 0 0 0 AC_BK */
  82. 0x00, /* 0 0 1 AC_BE */
  83. 0x03, /* 0 1 1 AC_BE */
  84. 0x04, /* 1 0 0 AC_VI */
  85. 0x05, /* 1 0 1 AC_VI */
  86. 0x06, /* 1 1 0 AC_VO */
  87. 0x07 /* 1 1 1 AC_VO */
  88. };
  89. /**
  90. * This table inverses the tos_to_tid operation to get a priority
  91. * which is in sequential order, and can be compared.
  92. * Use this to compare the priority of two different TIDs.
  93. */
  94. t_u8 tos_to_tid_inv[] = { 0x02, /* from tos_to_tid[2] = 0 */
  95. 0x00, /* from tos_to_tid[0] = 1 */
  96. 0x01, /* from tos_to_tid[1] = 2 */
  97. 0x03,
  98. 0x04,
  99. 0x05,
  100. 0x06,
  101. 0x07
  102. };
  103. /**
  104. * This table will provide the tid value for given ac. This table does not
  105. * change and will be used to copy back the default values to tos_to_tid in
  106. * case of disconnect.
  107. */
  108. const t_u8 ac_to_tid[4][2] = { {1, 2}, {0, 3}, {4, 5}, {6, 7} };
  109. /* Map of TOS UP values to WMM AC */
  110. static const mlan_wmm_ac_e tos_to_ac[] = { WMM_AC_BE,
  111. WMM_AC_BK,
  112. WMM_AC_BK,
  113. WMM_AC_BE,
  114. WMM_AC_VI,
  115. WMM_AC_VI,
  116. WMM_AC_VO,
  117. WMM_AC_VO
  118. };
  119. raListTbl *wlan_wmm_get_ralist_node(pmlan_private priv, t_u8 tid,
  120. t_u8 * ra_addr);
  121. /********************************************************
  122. Local Functions
  123. ********************************************************/
  124. #ifdef DEBUG_LEVEL2
  125. /**
  126. * @brief Debug print function to display the priority parameters for a WMM AC
  127. *
  128. * @param pac_param Pointer to the AC parameters to display
  129. *
  130. * @return N/A
  131. */
  132. static void
  133. wlan_wmm_ac_debug_print(const IEEEtypes_WmmAcParameters_t * pac_param)
  134. {
  135. const char *ac_str[] = { "BK", "BE", "VI", "VO" };
  136. ENTER();
  137. PRINTM(MINFO, "WMM AC_%s: ACI=%d, ACM=%d, Aifsn=%d, "
  138. "EcwMin=%d, EcwMax=%d, TxopLimit=%d\n",
  139. ac_str[wmm_aci_to_qidx_map[pac_param->aci_aifsn.aci]],
  140. pac_param->aci_aifsn.aci, pac_param->aci_aifsn.acm,
  141. pac_param->aci_aifsn.aifsn, pac_param->ecw.ecw_min,
  142. pac_param->ecw.ecw_max, wlan_le16_to_cpu(pac_param->tx_op_limit));
  143. LEAVE();
  144. }
  145. /** Print the WMM AC for debug purpose */
  146. #define PRINTM_AC(pac_param) wlan_wmm_ac_debug_print(pac_param)
  147. #else
  148. /** Print the WMM AC for debug purpose */
  149. #define PRINTM_AC(pac_param)
  150. #endif
  151. /**
  152. * @brief Allocate route address
  153. *
  154. * @param pmadapter Pointer to the mlan_adapter structure
  155. * @param ra Pointer to the route address
  156. *
  157. * @return ra_list
  158. */
  159. static raListTbl *
  160. wlan_wmm_allocate_ralist_node(pmlan_adapter pmadapter, t_u8 * ra)
  161. {
  162. raListTbl *ra_list = MNULL;
  163. ENTER();
  164. if (pmadapter->callbacks.
  165. moal_malloc(pmadapter->pmoal_handle, sizeof(raListTbl), MLAN_MEM_DEF,
  166. (t_u8 **) & ra_list)) {
  167. PRINTM(MERROR, "Fail to allocate ra_list\n");
  168. goto done;
  169. }
  170. util_init_list((pmlan_linked_list) ra_list);
  171. util_init_list_head((t_void *) pmadapter->pmoal_handle,
  172. &ra_list->buf_head, MFALSE,
  173. pmadapter->callbacks.moal_init_lock);
  174. memcpy(pmadapter, ra_list->ra, ra, MLAN_MAC_ADDR_LENGTH);
  175. ra_list->total_pkts = 0;
  176. ra_list->tx_pause = 0;
  177. PRINTM(MINFO, "RAList: Allocating buffers for TID %p\n", ra_list);
  178. done:
  179. LEAVE();
  180. return ra_list;
  181. }
  182. /**
  183. * @brief Map ACs to TID
  184. *
  185. * @param priv Pointer to the mlan_private driver data struct
  186. * @param queue_priority Queue_priority structure
  187. *
  188. * @return N/A
  189. */
  190. static void
  191. wlan_wmm_queue_priorities_tid(pmlan_private priv, t_u8 queue_priority[])
  192. {
  193. int i;
  194. ENTER();
  195. for (i = 0; i < 4; ++i) {
  196. tos_to_tid[7 - (i * 2)] = ac_to_tid[queue_priority[i]][1];
  197. tos_to_tid[6 - (i * 2)] = ac_to_tid[queue_priority[i]][0];
  198. }
  199. for (i = 0; i < MAX_NUM_TID; i++) {
  200. tos_to_tid_inv[tos_to_tid[i]] = (t_u8) i;
  201. }
  202. /* in case priorities have changed, force highest priority so next packet
  203. will check from top to re-establish the highest */
  204. util_scalar_write(priv->adapter->pmoal_handle,
  205. &priv->wmm.highest_queued_prio,
  206. HIGH_PRIO_TID,
  207. priv->adapter->callbacks.moal_spin_lock,
  208. priv->adapter->callbacks.moal_spin_unlock);
  209. LEAVE();
  210. }
  211. /**
  212. * @brief Evaluate whether or not an AC is to be downgraded
  213. *
  214. * @param priv Pointer to the mlan_private driver data struct
  215. * @param eval_ac AC to evaluate for downgrading
  216. *
  217. * @return WMM AC The eval_ac traffic is to be sent on.
  218. */
  219. static mlan_wmm_ac_e
  220. wlan_wmm_eval_downgrade_ac(pmlan_private priv, mlan_wmm_ac_e eval_ac)
  221. {
  222. int down_ac;
  223. mlan_wmm_ac_e ret_ac;
  224. WmmAcStatus_t *pac_status;
  225. ENTER();
  226. pac_status = &priv->wmm.ac_status[eval_ac];
  227. if (pac_status->disabled == MFALSE) {
  228. LEAVE();
  229. /* Okay to use this AC, its enabled */
  230. return eval_ac;
  231. }
  232. /* Setup a default return value of the lowest priority */
  233. ret_ac = WMM_AC_BK;
  234. /*
  235. * Find the highest AC that is enabled and does not require admission
  236. * control. The spec disallows downgrading to an AC, which is enabled
  237. * due to a completed admission control. Unadmitted traffic is not
  238. * to be sent on an AC with admitted traffic.
  239. */
  240. for (down_ac = WMM_AC_BK; down_ac < eval_ac; down_ac++) {
  241. pac_status = &priv->wmm.ac_status[down_ac];
  242. if ((pac_status->disabled == MFALSE)
  243. && (pac_status->flow_required == MFALSE))
  244. /* AC is enabled and does not require admission control */
  245. ret_ac = (mlan_wmm_ac_e) down_ac;
  246. }
  247. LEAVE();
  248. return ret_ac;
  249. }
  250. /**
  251. * @brief Convert the IP TOS field to an WMM AC Queue assignment
  252. *
  253. * @param pmadapter A pointer to mlan_adapter structure
  254. * @param tos IP TOS field
  255. *
  256. * @return WMM AC Queue mapping of the IP TOS field
  257. */
  258. static mlan_wmm_ac_e INLINE
  259. wlan_wmm_convert_tos_to_ac(pmlan_adapter pmadapter, t_u32 tos)
  260. {
  261. ENTER();
  262. if (tos >= NELEMENTS(tos_to_ac)) {
  263. LEAVE();
  264. return WMM_AC_BE;
  265. }
  266. LEAVE();
  267. return tos_to_ac[tos];
  268. }
  269. /**
  270. * @brief Evaluate a given TID and downgrade it to a lower TID if the
  271. * WMM Parameter IE received from the AP indicates that the AP
  272. * is disabled (due to call admission control (ACM bit). Mapping
  273. * of TID to AC is taken care internally
  274. *
  275. * @param priv Pointer to the mlan_private data struct
  276. * @param tid tid to evaluate for downgrading
  277. *
  278. * @return Same tid as input if downgrading not required or
  279. * the tid the traffic for the given tid should be downgraded to
  280. */
  281. static t_u8 INLINE
  282. wlan_wmm_downgrade_tid(pmlan_private priv, t_u32 tid)
  283. {
  284. mlan_wmm_ac_e ac_down;
  285. pmlan_adapter pmadapter = priv->adapter;
  286. ENTER();
  287. ac_down =
  288. priv->wmm.ac_down_graded_vals[wlan_wmm_convert_tos_to_ac(pmadapter,
  289. tid)];
  290. LEAVE();
  291. /*
  292. * Send the index to tid array, picking from the array will be
  293. * taken care by dequeuing function
  294. */
  295. if (tid == 1 || tid == 2)
  296. return ac_to_tid[ac_down][(tid + 1) % 2];
  297. else if (tid >= MAX_NUM_TID)
  298. return ac_to_tid[ac_down][0];
  299. else
  300. return ac_to_tid[ac_down][tid % 2];
  301. }
  302. /**
  303. * @brief Delete packets in RA node
  304. *
  305. * @param priv Pointer to the mlan_private driver data struct
  306. * @param ra_list Pointer to raListTbl
  307. *
  308. * @return N/A
  309. */
  310. static INLINE void
  311. wlan_wmm_del_pkts_in_ralist_node(pmlan_private priv, raListTbl * ra_list)
  312. {
  313. pmlan_buffer pmbuf;
  314. pmlan_adapter pmadapter = priv->adapter;
  315. ENTER();
  316. while ((pmbuf =
  317. (pmlan_buffer) util_peek_list(pmadapter->pmoal_handle,
  318. &ra_list->buf_head, MNULL, MNULL))) {
  319. util_unlink_list(pmadapter->pmoal_handle, &ra_list->buf_head,
  320. (pmlan_linked_list) pmbuf, MNULL, MNULL);
  321. wlan_write_data_complete(pmadapter, pmbuf, MLAN_STATUS_FAILURE);
  322. }
  323. util_free_list_head((t_void *) pmadapter->pmoal_handle, &ra_list->buf_head,
  324. pmadapter->callbacks.moal_free_lock);
  325. LEAVE();
  326. }
  327. /**
  328. * @brief Delete packets in RA list
  329. *
  330. * @param priv Pointer to the mlan_private driver data struct
  331. * @param ra_list_head ra list header
  332. *
  333. * @return N/A
  334. */
  335. static INLINE void
  336. wlan_wmm_del_pkts_in_ralist(pmlan_private priv, mlan_list_head * ra_list_head)
  337. {
  338. raListTbl *ra_list;
  339. ENTER();
  340. ra_list =
  341. (raListTbl *) util_peek_list(priv->adapter->pmoal_handle, ra_list_head,
  342. MNULL, MNULL);
  343. while (ra_list && ra_list != (raListTbl *) ra_list_head) {
  344. wlan_wmm_del_pkts_in_ralist_node(priv, ra_list);
  345. ra_list = ra_list->pnext;
  346. }
  347. LEAVE();
  348. }
  349. /**
  350. * @brief Clean up the wmm queue
  351. *
  352. * @param priv Pointer to the mlan_private driver data struct
  353. *
  354. * @return N/A
  355. */
  356. static void
  357. wlan_wmm_cleanup_queues(pmlan_private priv)
  358. {
  359. int i;
  360. ENTER();
  361. for (i = 0; i < MAX_NUM_TID; i++) {
  362. wlan_wmm_del_pkts_in_ralist(priv, &priv->wmm.tid_tbl_ptr[i].ra_list);
  363. priv->wmm.pkts_queued[i] = 0;
  364. }
  365. util_scalar_write(priv->adapter->pmoal_handle, &priv->wmm.tx_pkts_queued, 0,
  366. MNULL, MNULL);
  367. util_scalar_write(priv->adapter->pmoal_handle,
  368. &priv->wmm.highest_queued_prio, HIGH_PRIO_TID, MNULL,
  369. MNULL);
  370. LEAVE();
  371. }
  372. /**
  373. * @brief Delete all route address from RA list
  374. *
  375. * @param priv Pointer to the mlan_private driver data struct
  376. *
  377. * @return N/A
  378. */
  379. static void
  380. wlan_wmm_delete_all_ralist(pmlan_private priv)
  381. {
  382. raListTbl *ra_list;
  383. int i;
  384. pmlan_adapter pmadapter = priv->adapter;
  385. ENTER();
  386. for (i = 0; i < MAX_NUM_TID; ++i) {
  387. PRINTM(MINFO, "RAList: Freeing buffers for TID %d\n", i);
  388. while ((ra_list = (raListTbl *) util_peek_list(pmadapter->pmoal_handle,
  389. &priv->wmm.
  390. tid_tbl_ptr[i].ra_list,
  391. MNULL, MNULL))) {
  392. util_unlink_list(pmadapter->pmoal_handle,
  393. &priv->wmm.tid_tbl_ptr[i].ra_list,
  394. (pmlan_linked_list) ra_list, MNULL, MNULL);
  395. pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle,
  396. (t_u8 *) ra_list);
  397. }
  398. util_init_list((pmlan_linked_list)
  399. & priv->wmm.tid_tbl_ptr[i].ra_list);
  400. priv->wmm.tid_tbl_ptr[i].ra_list_curr = MNULL;
  401. }
  402. LEAVE();
  403. }
  404. /**
  405. * @brief Get queue RA pointer
  406. *
  407. * @param priv Pointer to the mlan_private driver data struct
  408. * @param tid TID
  409. * @param ra_addr Pointer to the route address
  410. *
  411. * @return ra_list
  412. */
  413. static raListTbl *
  414. wlan_wmm_get_queue_raptr(pmlan_private priv, t_u8 tid, t_u8 * ra_addr)
  415. {
  416. raListTbl *ra_list;
  417. #if defined(UAP_SUPPORT)
  418. t_u8 bcast_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
  419. #endif
  420. ENTER();
  421. ra_list = wlan_wmm_get_ralist_node(priv, tid, ra_addr);
  422. if (ra_list) {
  423. LEAVE();
  424. return ra_list;
  425. }
  426. #if defined(UAP_SUPPORT)
  427. if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) &&
  428. (0 != memcmp(priv->adapter, ra_addr, bcast_addr, sizeof(bcast_addr)))) {
  429. if (MNULL == wlan_get_station_entry(priv, ra_addr)) {
  430. PRINTM(MDATA, "Drop packets to unknown station\n");
  431. LEAVE();
  432. return MNULL;
  433. }
  434. }
  435. #endif
  436. wlan_ralist_add(priv, ra_addr);
  437. ra_list = wlan_wmm_get_ralist_node(priv, tid, ra_addr);
  438. LEAVE();
  439. return ra_list;
  440. }
  441. #ifdef STA_SUPPORT
  442. /**
  443. * @brief Sends wmmac host event
  444. *
  445. * @param priv Pointer to the mlan_private driver data struct
  446. * @param typeStr Type of host event
  447. * @param srcAddr Pointer to the source Address
  448. * @param tid TID
  449. * @param up User priority
  450. * @param status Status code or Reason code
  451. *
  452. * @return N/A
  453. */
  454. static void
  455. wlan_send_wmmac_host_event(pmlan_private priv,
  456. char *typeStr,
  457. t_u8 * srcAddr, t_u8 tid, t_u8 up, t_u8 status)
  458. {
  459. t_u8 event_buf[100];
  460. mlan_event *pevent;
  461. t_u8 *pOutBuf;
  462. ENTER();
  463. /* Format one of the following two output strings: ** -
  464. TSPEC:ADDTS_RSP:[<status code>]:TID=X:UP=Y ** - TSPEC:DELTS_RX:[<reason
  465. code>]:TID=X:UP=Y */
  466. pevent = (mlan_event *) event_buf;
  467. pOutBuf = pevent->event_buf;
  468. memcpy(priv->adapter, pOutBuf, (t_u8 *) "TSPEC:", 6);
  469. pOutBuf += 6;
  470. memcpy(priv->adapter, pOutBuf, (t_u8 *) typeStr, wlan_strlen(typeStr));
  471. pOutBuf += wlan_strlen(typeStr);
  472. *pOutBuf++ = ':';
  473. *pOutBuf++ = '[';
  474. if (status >= 100) {
  475. *pOutBuf++ = (status / 100) + '0';
  476. status = (status % 100);
  477. }
  478. if (status >= 10) {
  479. *pOutBuf++ = (status / 10) + '0';
  480. status = (status % 10);
  481. }
  482. *pOutBuf++ = status + '0';
  483. memcpy(priv->adapter, pOutBuf, (t_u8 *) "]:TID", 5);
  484. pOutBuf += 5;
  485. *pOutBuf++ = tid + '0';
  486. memcpy(priv->adapter, pOutBuf, (t_u8 *) ":UP", 3);
  487. pOutBuf += 3;
  488. *pOutBuf++ = up + '0';
  489. *pOutBuf = '\0';
  490. pevent->bss_index = priv->bss_index;
  491. pevent->event_id = MLAN_EVENT_ID_DRV_REPORT_STRING;
  492. pevent->event_len = wlan_strlen((const t_s8 *) (pevent->event_buf));
  493. wlan_recv_event(priv, MLAN_EVENT_ID_DRV_REPORT_STRING, pevent);
  494. LEAVE();
  495. }
  496. #endif /* STA_SUPPORT */
  497. /**
  498. * @brief This function gets the highest priority list pointer
  499. *
  500. * @param pmadapter A pointer to mlan_adapter
  501. * @param priv A pointer to mlan_private
  502. * @param tid A pointer to return tid
  503. *
  504. * @return raListTbl
  505. */
  506. static raListTbl *
  507. wlan_wmm_get_highest_priolist_ptr(pmlan_adapter pmadapter,
  508. pmlan_private * priv, int *tid)
  509. {
  510. pmlan_private priv_tmp;
  511. raListTbl *ptr, *head;
  512. mlan_bssprio_node *bssprio_node, *bssprio_head;
  513. tid_tbl_t *tid_ptr;
  514. int i, j;
  515. int next_prio = 0;
  516. int next_tid = 0;
  517. ENTER();
  518. PRINTM(MDAT_D, "POP\n");
  519. for (j = pmadapter->priv_num - 1; j >= 0; --j) {
  520. if (!(util_peek_list(pmadapter->pmoal_handle,
  521. &pmadapter->bssprio_tbl[j].bssprio_head,
  522. pmadapter->callbacks.moal_spin_lock,
  523. pmadapter->callbacks.moal_spin_unlock)))
  524. continue;
  525. if (pmadapter->bssprio_tbl[j].bssprio_cur == (mlan_bssprio_node *)
  526. & pmadapter->bssprio_tbl[j].bssprio_head) {
  527. pmadapter->bssprio_tbl[j].bssprio_cur =
  528. pmadapter->bssprio_tbl[j].bssprio_cur->pnext;
  529. }
  530. bssprio_head = bssprio_node = pmadapter->bssprio_tbl[j].bssprio_cur;
  531. do {
  532. priv_tmp = bssprio_node->priv;
  533. if ((priv_tmp->port_ctrl_mode == MTRUE)
  534. && (priv_tmp->port_open == MFALSE)) {
  535. PRINTM(MINFO, "get_highest_prio_ptr(): "
  536. "PORT_CLOSED Ignore pkts from BSS%d\n",
  537. priv_tmp->bss_index);
  538. /* Ignore data pkts from a BSS if port is closed */
  539. goto next_intf;
  540. }
  541. pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
  542. priv_tmp->wmm.ra_list_spinlock);
  543. for (i = util_scalar_read(pmadapter->pmoal_handle,
  544. &priv_tmp->wmm.highest_queued_prio,
  545. MNULL, MNULL); i >= LOW_PRIO_TID; --i) {
  546. tid_ptr = &(priv_tmp)->wmm.tid_tbl_ptr[tos_to_tid[i]];
  547. if (!util_peek_list
  548. (pmadapter->pmoal_handle, &tid_ptr->ra_list, MNULL, MNULL))
  549. continue;
  550. /*
  551. * Always choose the next ra we transmitted
  552. * last time, this way we pick the ra's in
  553. * round robin fashion.
  554. */
  555. head = ptr = tid_ptr->ra_list_curr->pnext;
  556. if (ptr == (raListTbl *) & tid_ptr->ra_list)
  557. head = ptr = ptr->pnext;
  558. do {
  559. if (!ptr->tx_pause &&
  560. util_peek_list(pmadapter->pmoal_handle, &ptr->buf_head,
  561. MNULL, MNULL)) {
  562. /* Because WMM only support BK/BE/VI/VO, we have 8 tid
  563. We should balance the traffic of the same AC */
  564. if (i % 2)
  565. next_prio = i - 1;
  566. else
  567. next_prio = i + 1;
  568. next_tid = tos_to_tid[next_prio];
  569. if (priv_tmp->wmm.pkts_queued[next_tid])
  570. util_scalar_write(pmadapter->pmoal_handle,
  571. &priv_tmp->wmm.
  572. highest_queued_prio, next_prio,
  573. MNULL, MNULL);
  574. else
  575. /* if highest_queued_prio > i, set it to i */
  576. util_scalar_conditional_write(pmadapter->
  577. pmoal_handle,
  578. &priv_tmp->wmm.
  579. highest_queued_prio,
  580. MLAN_SCALAR_COND_GREATER_THAN,
  581. i, i, MNULL, MNULL);
  582. *priv = priv_tmp;
  583. *tid = tos_to_tid[i];
  584. /* hold priv->ra_list_spinlock to maintain ptr */
  585. PRINTM(MDAT_D, "get highest prio ptr %p, tid %d\n",
  586. ptr, *tid);
  587. LEAVE();
  588. return ptr;
  589. }
  590. if ((ptr = ptr->pnext) == (raListTbl *) & tid_ptr->ra_list)
  591. ptr = ptr->pnext;
  592. } while (ptr != head);
  593. }
  594. /* No packet at any TID for this priv. Mark as such to skip
  595. checking TIDs for this priv (until pkt is added). */
  596. util_scalar_write(pmadapter->pmoal_handle,
  597. &priv_tmp->wmm.highest_queued_prio,
  598. NO_PKT_PRIO_TID, MNULL, MNULL);
  599. pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
  600. priv_tmp->wmm.
  601. ra_list_spinlock);
  602. next_intf:
  603. if ((bssprio_node = bssprio_node->pnext) == (mlan_bssprio_node *)
  604. & pmadapter->bssprio_tbl[j].bssprio_head)
  605. bssprio_node = bssprio_node->pnext;
  606. } while (bssprio_node != bssprio_head);
  607. }
  608. LEAVE();
  609. return MNULL;
  610. }
  611. /**
  612. * @brief This function gets the number of packets in the Tx queue
  613. *
  614. * @param priv A pointer to mlan_private
  615. * @param ptr A pointer to RA list table
  616. * @param maxBufSize Maximum buffer size
  617. *
  618. * @return Packet count
  619. */
  620. static int
  621. wlan_num_pkts_in_txq(mlan_private * priv, raListTbl * ptr, int maxBufSize)
  622. {
  623. int count = 0, total_size = 0;
  624. pmlan_buffer pmbuf;
  625. ENTER();
  626. for (pmbuf = (pmlan_buffer) ptr->buf_head.pnext;
  627. pmbuf != (pmlan_buffer) (&ptr->buf_head); pmbuf = pmbuf->pnext) {
  628. total_size += pmbuf->data_len;
  629. if (total_size < maxBufSize)
  630. ++count;
  631. else
  632. break;
  633. }
  634. LEAVE();
  635. return count;
  636. }
  637. /**
  638. * @brief This function sends a single packet
  639. *
  640. * @param priv A pointer to mlan_private
  641. * @param ptr A pointer to RA list table
  642. * @param ptrindex ptr's TID index
  643. *
  644. * @return N/A
  645. */
  646. static void INLINE
  647. wlan_send_single_packet(pmlan_private priv, raListTbl * ptr, int ptrindex)
  648. {
  649. pmlan_buffer pmbuf;
  650. pmlan_buffer pmbuf_next;
  651. mlan_tx_param tx_param;
  652. pmlan_adapter pmadapter = priv->adapter;
  653. mlan_status status = MLAN_STATUS_SUCCESS;
  654. ENTER();
  655. if ((pmbuf = (pmlan_buffer) util_dequeue_list(pmadapter->pmoal_handle,
  656. &ptr->buf_head,
  657. MNULL, MNULL))) {
  658. PRINTM(MINFO, "Dequeuing the packet %p %p\n", ptr, pmbuf);
  659. priv->wmm.pkts_queued[ptrindex]--;
  660. util_scalar_decrement(pmadapter->pmoal_handle,
  661. &priv->wmm.tx_pkts_queued, MNULL, MNULL);
  662. ptr->total_pkts--;
  663. pmbuf_next = (pmlan_buffer) util_peek_list(pmadapter->pmoal_handle,
  664. &ptr->buf_head,
  665. MNULL, MNULL);
  666. pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
  667. priv->wmm.ra_list_spinlock);
  668. tx_param.next_pkt_len = ((pmbuf_next)
  669. ? pmbuf_next->data_len + sizeof(TxPD) : 0);
  670. status = wlan_process_tx(priv, pmbuf, &tx_param);
  671. if (status == MLAN_STATUS_RESOURCE) {
  672. /** Queue the packet back at the head */
  673. PRINTM(MDAT_D, "Queuing pkt back to raList %p %p\n", ptr, pmbuf);
  674. pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
  675. priv->wmm.ra_list_spinlock);
  676. if (!wlan_is_ralist_valid(priv, ptr, ptrindex)) {
  677. pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
  678. priv->wmm.
  679. ra_list_spinlock);
  680. wlan_write_data_complete(pmadapter, pmbuf, MLAN_STATUS_FAILURE);
  681. LEAVE();
  682. return;
  683. }
  684. priv->wmm.pkts_queued[ptrindex]++;
  685. util_scalar_increment(pmadapter->pmoal_handle,
  686. &priv->wmm.tx_pkts_queued, MNULL, MNULL);
  687. util_enqueue_list_head(pmadapter->pmoal_handle, &ptr->buf_head,
  688. (pmlan_linked_list) pmbuf, MNULL, MNULL);
  689. ptr->total_pkts++;
  690. pmbuf->flags |= MLAN_BUF_FLAG_REQUEUED_PKT;
  691. pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
  692. priv->wmm.ra_list_spinlock);
  693. } else {
  694. pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
  695. priv->wmm.ra_list_spinlock);
  696. if (wlan_is_ralist_valid(priv, ptr, ptrindex)) {
  697. priv->wmm.packets_out[ptrindex]++;
  698. priv->wmm.tid_tbl_ptr[ptrindex].ra_list_curr = ptr;
  699. }
  700. pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur =
  701. pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur->pnext;
  702. pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
  703. priv->wmm.ra_list_spinlock);
  704. }
  705. } else {
  706. pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
  707. priv->wmm.ra_list_spinlock);
  708. PRINTM(MINFO, "Nothing to send\n");
  709. }
  710. LEAVE();
  711. }
  712. /**
  713. * @brief This function checks if this mlan_buffer is already processed.
  714. *
  715. * @param priv A pointer to mlan_private
  716. * @param ptr A pointer to RA list table
  717. *
  718. * @return MTRUE or MFALSE
  719. */
  720. static int INLINE
  721. wlan_is_ptr_processed(mlan_private * priv, raListTbl * ptr)
  722. {
  723. pmlan_buffer pmbuf;
  724. if ((pmbuf = (pmlan_buffer) util_peek_list(priv->adapter->pmoal_handle,
  725. &ptr->buf_head, MNULL, MNULL))
  726. && (pmbuf->flags & MLAN_BUF_FLAG_REQUEUED_PKT))
  727. return MTRUE;
  728. return MFALSE;
  729. }
  730. /**
  731. * @brief This function sends a single packet that has been processed
  732. *
  733. * @param priv A pointer to mlan_private
  734. * @param ptr A pointer to RA list table
  735. * @param ptrindex ptr's TID index
  736. *
  737. * @return N/A
  738. */
  739. static void INLINE
  740. wlan_send_processed_packet(pmlan_private priv, raListTbl * ptr, int ptrindex)
  741. {
  742. pmlan_buffer pmbuf_next;
  743. mlan_tx_param tx_param;
  744. pmlan_buffer pmbuf;
  745. pmlan_adapter pmadapter = priv->adapter;
  746. mlan_status ret = MLAN_STATUS_FAILURE;
  747. if ((pmbuf = (pmlan_buffer) util_dequeue_list(pmadapter->pmoal_handle,
  748. &ptr->buf_head,
  749. MNULL, MNULL))) {
  750. pmbuf_next =
  751. (pmlan_buffer) util_peek_list(pmadapter->pmoal_handle,
  752. &ptr->buf_head, MNULL, MNULL);
  753. pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
  754. priv->wmm.ra_list_spinlock);
  755. tx_param.next_pkt_len =
  756. ((pmbuf_next) ? pmbuf_next->data_len + sizeof(TxPD) : 0);
  757. ret =
  758. wlan_sdio_host_to_card(pmadapter, MLAN_TYPE_DATA, pmbuf, &tx_param);
  759. switch (ret) {
  760. case MLAN_STATUS_RESOURCE:
  761. PRINTM(MINFO, "MLAN_STATUS_RESOURCE is returned\n");
  762. pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
  763. priv->wmm.ra_list_spinlock);
  764. if (!wlan_is_ralist_valid(priv, ptr, ptrindex)) {
  765. pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
  766. priv->wmm.
  767. ra_list_spinlock);
  768. wlan_write_data_complete(pmadapter, pmbuf, MLAN_STATUS_FAILURE);
  769. LEAVE();
  770. return;
  771. }
  772. util_enqueue_list_head(pmadapter->pmoal_handle,
  773. &ptr->buf_head,
  774. (pmlan_linked_list) pmbuf, MNULL, MNULL);
  775. pmbuf->flags |= MLAN_BUF_FLAG_REQUEUED_PKT;
  776. pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
  777. priv->wmm.ra_list_spinlock);
  778. break;
  779. case MLAN_STATUS_FAILURE:
  780. pmadapter->data_sent = MFALSE;
  781. PRINTM(MERROR, "Error: Failed to write data\n");
  782. pmadapter->dbg.num_tx_host_to_card_failure++;
  783. pmbuf->status_code = MLAN_ERROR_DATA_TX_FAIL;
  784. wlan_write_data_complete(pmadapter, pmbuf, ret);
  785. break;
  786. case MLAN_STATUS_PENDING:
  787. pmadapter->data_sent = MFALSE;
  788. default:
  789. break;
  790. }
  791. if (ret != MLAN_STATUS_RESOURCE) {
  792. pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
  793. priv->wmm.ra_list_spinlock);
  794. if (wlan_is_ralist_valid(priv, ptr, ptrindex)) {
  795. priv->wmm.packets_out[ptrindex]++;
  796. priv->wmm.tid_tbl_ptr[ptrindex].ra_list_curr = ptr;
  797. ptr->total_pkts--;
  798. }
  799. pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur =
  800. pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur->pnext;
  801. priv->wmm.pkts_queued[ptrindex]--;
  802. util_scalar_decrement(pmadapter->pmoal_handle,
  803. &priv->wmm.tx_pkts_queued, MNULL, MNULL);
  804. pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
  805. priv->wmm.ra_list_spinlock);
  806. }
  807. } else {
  808. pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
  809. priv->wmm.ra_list_spinlock);
  810. }
  811. }
  812. /**
  813. * @brief This function dequeues a packet
  814. *
  815. * @param pmadapter A pointer to mlan_adapter
  816. *
  817. * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
  818. */
  819. static int
  820. wlan_dequeue_tx_packet(pmlan_adapter pmadapter)
  821. {
  822. raListTbl *ptr;
  823. pmlan_private priv = MNULL;
  824. int ptrindex = 0;
  825. t_u8 ra[MLAN_MAC_ADDR_LENGTH];
  826. int tid_del = 0;
  827. int tid = 0;
  828. ENTER();
  829. if (!(ptr = wlan_wmm_get_highest_priolist_ptr(pmadapter, &priv, &ptrindex))) {
  830. LEAVE();
  831. return MLAN_STATUS_FAILURE;
  832. }
  833. /* Note:- Spinlock is locked in wlan_wmm_get_highest_priolist_ptr when it
  834. returns a pointer (for the priv it returns), and is unlocked in
  835. wlan_send_processed_packet, wlan_send_single_packet or
  836. wlan_11n_aggregate_pkt. The spinlock would be required for some parts
  837. of both of function. But, the the bulk of these function will execute
  838. w/o spinlock. Unlocking the spinlock inside these function will help
  839. us avoid taking the spinlock again, check to see if the ptr is still
  840. valid and then proceed. This is done purely to increase execution time.
  841. */
  842. /* Note:- Also, anybody adding code which does not get into
  843. wlan_send_processed_packet, wlan_send_single_packet, or
  844. wlan_11n_aggregate_pkt should make sure ra_list_spinlock is freed.
  845. Otherwise there would be a lock up. */
  846. tid = wlan_get_tid(priv->adapter, ptr);
  847. if (tid >= MAX_NUM_TID)
  848. tid = wlan_wmm_downgrade_tid(priv, tid);
  849. if (wlan_is_ptr_processed(priv, ptr)) {
  850. wlan_send_processed_packet(priv, ptr, ptrindex);
  851. LEAVE();
  852. return MLAN_STATUS_SUCCESS;
  853. }
  854. if (!ptr->is_11n_enabled || wlan_is_bastream_setup(priv, ptr, tid)
  855. #ifdef STA_SUPPORT
  856. || ((priv->sec_info.ewpa_enabled == MFALSE) &&
  857. ((priv->sec_info.wpa_enabled
  858. || priv->sec_info.wpa2_enabled) &&
  859. priv->wpa_is_gtk_set == MFALSE))
  860. || priv->wps.session_enable
  861. #endif /* STA_SUPPORT */
  862. ) {
  863. if (ptr->is_11n_enabled && wlan_is_bastream_setup(priv, ptr, tid)
  864. && wlan_is_amsdu_in_ampdu_allowed(priv, ptr, tid)
  865. && wlan_is_amsdu_allowed(priv, ptr, tid)
  866. && (wlan_num_pkts_in_txq(priv, ptr, pmadapter->tx_buf_size) >=
  867. MIN_NUM_AMSDU)) {
  868. wlan_11n_aggregate_pkt(priv, ptr, INTF_HEADER_LEN, ptrindex);
  869. } else
  870. wlan_send_single_packet(priv, ptr, ptrindex);
  871. } else {
  872. if (wlan_is_ampdu_allowed(priv, ptr, tid) &&
  873. (ptr->packet_count > ptr->ba_packet_threshold)) {
  874. if (wlan_is_bastream_avail(priv)) {
  875. PRINTM(MINFO, "BA setup threshold %d reached. tid=%d\n",
  876. ptr->packet_count, tid);
  877. wlan_11n_create_txbastream_tbl(priv,
  878. ptr->ra, tid,
  879. BA_STREAM_SETUP_INPROGRESS);
  880. wlan_send_addba(priv, tid, ptr->ra);
  881. } else if (wlan_find_stream_to_delete(priv, ptr, tid, &tid_del, ra)) {
  882. PRINTM(MDAT_D, "tid_del=%d tid=%d\n", tid_del, tid);
  883. wlan_11n_create_txbastream_tbl(priv,
  884. ptr->ra, tid,
  885. BA_STREAM_SETUP_INPROGRESS);
  886. wlan_send_delba(priv, tid_del, ra, 1);
  887. }
  888. }
  889. if (wlan_is_amsdu_allowed(priv, ptr, tid) &&
  890. (wlan_num_pkts_in_txq(priv, ptr,
  891. pmadapter->tx_buf_size) >= MIN_NUM_AMSDU)) {
  892. wlan_11n_aggregate_pkt(priv, ptr, INTF_HEADER_LEN, ptrindex);
  893. } else {
  894. wlan_send_single_packet(priv, ptr, ptrindex);
  895. }
  896. }
  897. LEAVE();
  898. return MLAN_STATUS_SUCCESS;
  899. }
  900. /**
  901. * @brief update tx_pause flag in ra_list
  902. *
  903. * @param priv A pointer to mlan_private
  904. * @param mac peer mac address
  905. * @param tx_pause tx_pause flag (0/1)
  906. *
  907. * @return N/A
  908. */
  909. t_void
  910. wlan_updata_ralist_tx_pause(pmlan_private priv, t_u8 * mac, t_u8 tx_pause)
  911. {
  912. raListTbl *ra_list;
  913. int i;
  914. pmlan_adapter pmadapter = priv->adapter;
  915. t_u32 pkt_cnt = 0;
  916. t_u32 tx_pkts_queued = 0;
  917. ENTER();
  918. pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
  919. priv->wmm.ra_list_spinlock);
  920. for (i = 0; i < MAX_NUM_TID; ++i) {
  921. ra_list = wlan_wmm_get_ralist_node(priv, i, mac);
  922. if (ra_list) {
  923. pkt_cnt += ra_list->total_pkts;
  924. ra_list->tx_pause = tx_pause;
  925. }
  926. }
  927. if (pkt_cnt) {
  928. tx_pkts_queued = util_scalar_read(pmadapter->pmoal_handle,
  929. &priv->wmm.tx_pkts_queued, MNULL,
  930. MNULL);
  931. if (tx_pause)
  932. tx_pkts_queued -= pkt_cnt;
  933. else
  934. tx_pkts_queued += pkt_cnt;
  935. util_scalar_write(priv->adapter->pmoal_handle,
  936. &priv->wmm.tx_pkts_queued, tx_pkts_queued, MNULL,
  937. MNULL);
  938. util_scalar_write(priv->adapter->pmoal_handle,
  939. &priv->wmm.highest_queued_prio, HIGH_PRIO_TID, MNULL,
  940. MNULL);
  941. }
  942. pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
  943. priv->wmm.ra_list_spinlock);
  944. LEAVE();
  945. }
  946. #ifdef STA_SUPPORT
  947. #endif /* STA_SUPPORT */
  948. /********************************************************
  949. Global Functions
  950. ********************************************************/
  951. /**
  952. * @brief Get the threshold value for BA setup using system time.
  953. *
  954. * @param pmadapter Pointer to the mlan_adapter structure
  955. *
  956. * @return threshold value.
  957. */
  958. t_u8
  959. wlan_get_random_ba_threshold(pmlan_adapter pmadapter)
  960. {
  961. t_u32 sec, usec;
  962. t_u8 ba_threshold = 0;
  963. ENTER();
  964. /* setup ba_packet_threshold here random number between
  965. [BA_SETUP_PACKET_OFFSET,
  966. BA_SETUP_PACKET_OFFSET+BA_SETUP_MAX_PACKET_THRESHOLD-1] */
  967. #define BA_SETUP_MAX_PACKET_THRESHOLD 16
  968. #define BA_SETUP_PACKET_OFFSET 16
  969. pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle, &sec,
  970. &usec);
  971. sec = (sec & 0xFFFF) + (sec >> 16);
  972. usec = (usec & 0xFFFF) + (usec >> 16);
  973. ba_threshold =
  974. (((sec << 16) + usec) % BA_SETUP_MAX_PACKET_THRESHOLD) +
  975. BA_SETUP_PACKET_OFFSET;
  976. PRINTM(MINFO, "setup BA after %d packets\n", ba_threshold);
  977. LEAVE();
  978. return ba_threshold;
  979. }
  980. /**
  981. * @brief This function cleans Tx/Rx queues
  982. *
  983. * @param priv A pointer to mlan_private
  984. *
  985. * @return N/A
  986. */
  987. t_void
  988. wlan_clean_txrx(pmlan_private priv)
  989. {
  990. mlan_adapter *pmadapter = priv->adapter;
  991. t_u8 i = 0;
  992. ENTER();
  993. if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
  994. wlan_cleanup_bypass_txq(pmadapter);
  995. }
  996. wlan_11n_cleanup_reorder_tbl(priv);
  997. pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
  998. priv->wmm.ra_list_spinlock);
  999. wlan_wmm_cleanup_queues(priv);
  1000. wlan_11n_deleteall_txbastream_tbl(priv);
  1001. #ifdef SDIO_MULTI_PORT_TX_AGGR
  1002. MP_TX_AGGR_BUF_RESET(priv->adapter);
  1003. #endif
  1004. #ifdef SDIO_MULTI_PORT_RX_AGGR
  1005. MP_RX_AGGR_BUF_RESET(priv->adapter);
  1006. #endif
  1007. wlan_wmm_delete_all_ralist(priv);
  1008. memcpy(pmadapter, tos_to_tid, ac_to_tid, sizeof(tos_to_tid));
  1009. for (i = 0; i < MAX_NUM_TID; i++) {
  1010. tos_to_tid_inv[tos_to_tid[i]] = (t_u8) i;
  1011. }
  1012. #if defined(UAP_SUPPORT)
  1013. priv->num_drop_pkts = 0;
  1014. #endif
  1015. pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
  1016. priv->wmm.ra_list_spinlock);
  1017. LEAVE();
  1018. }
  1019. /**
  1020. * @brief Set the WMM queue priorities to their default values
  1021. *
  1022. * @param priv Pointer to the mlan_private driver data struct
  1023. *
  1024. * @return N/A
  1025. */
  1026. void
  1027. wlan_wmm_default_queue_priorities(pmlan_private priv)
  1028. {
  1029. ENTER();
  1030. /* Default queue priorities: VO->VI->BE->BK */
  1031. priv->wmm.queue_priority[0] = WMM_AC_VO;
  1032. priv->wmm.queue_priority[1] = WMM_AC_VI;
  1033. priv->wmm.queue_priority[2] = WMM_AC_BE;
  1034. priv->wmm.queue_priority[3] = WMM_AC_BK;
  1035. LEAVE();
  1036. }
  1037. /**
  1038. * @brief Initialize WMM priority queues
  1039. *
  1040. * @param priv Pointer to the mlan_private driver data struct
  1041. * @param pwmm_ie Pointer to the IEEEtypes_WmmParameter_t data struct
  1042. *
  1043. * @return N/A
  1044. */
  1045. void
  1046. wlan_wmm_setup_queue_priorities(pmlan_private priv,
  1047. IEEEtypes_WmmParameter_t * pwmm_ie)
  1048. {
  1049. t_u16 cw_min, avg_back_off, tmp[4];
  1050. t_u32 i, j, num_ac;
  1051. t_u8 ac_idx;
  1052. ENTER();
  1053. if (!pwmm_ie || priv->wmm_enabled == MFALSE) {
  1054. /* WMM is not enabled, just set the defaults and return */
  1055. wlan_wmm_default_queue_priorities(priv);
  1056. LEAVE();
  1057. return;
  1058. }
  1059. HEXDUMP("WMM: setup_queue_priorities: param IE",
  1060. (t_u8 *) pwmm_ie, sizeof(IEEEtypes_WmmParameter_t));
  1061. PRINTM(MINFO, "WMM Parameter IE: version=%d, "
  1062. "qos_info Parameter Set Count=%d, Reserved=%#x\n",
  1063. pwmm_ie->vend_hdr.version, pwmm_ie->qos_info.para_set_count,
  1064. pwmm_ie->reserved);
  1065. for (num_ac = 0; num_ac < NELEMENTS(pwmm_ie->ac_params); num_ac++) {
  1066. cw_min = (1 << pwmm_ie->ac_params[num_ac].ecw.ecw_min) - 1;
  1067. avg_back_off
  1068. = (cw_min >> 1) + pwmm_ie->ac_params[num_ac].aci_aifsn.aifsn;
  1069. ac_idx = wmm_aci_to_qidx_map[pwmm_ie->ac_params[num_ac].aci_aifsn.aci];
  1070. priv->wmm.queue_priority[ac_idx] = ac_idx;
  1071. tmp[ac_idx] = avg_back_off;
  1072. PRINTM(MCMND, "WMM: CWmax=%d CWmin=%d Avg Back-off=%d\n",
  1073. (1 << pwmm_ie->ac_params[num_ac].ecw.ecw_max) - 1,
  1074. cw_min, avg_back_off);
  1075. PRINTM_AC(&pwmm_ie->ac_params[num_ac]);
  1076. }
  1077. HEXDUMP("WMM: avg_back_off", (t_u8 *) tmp, sizeof(tmp));
  1078. HEXDUMP("WMM: queue_priority", priv->wmm.queue_priority,
  1079. sizeof(priv->wmm.queue_priority));
  1080. /* Bubble sort */
  1081. for (i = 0; i < num_ac; i++) {
  1082. for (j = 1; j < num_ac - i; j++) {
  1083. if (tmp[j - 1] > tmp[j]) {
  1084. SWAP_U16(tmp[j - 1], tmp[j]);
  1085. SWAP_U8(priv->wmm.queue_priority[j - 1],
  1086. priv->wmm.queue_priority[j]);
  1087. } else if (tmp[j - 1] == tmp[j]) {
  1088. if (priv->wmm.queue_priority[j - 1]
  1089. < priv->wmm.queue_priority[j]) {
  1090. SWAP_U8(priv->wmm.queue_priority[j - 1],
  1091. priv->wmm.queue_priority[j]);
  1092. }
  1093. }
  1094. }
  1095. }
  1096. wlan_wmm_queue_priorities_tid(priv, priv->wmm.queue_priority);
  1097. HEXDUMP("WMM: avg_back_off, sort", (t_u8 *) tmp, sizeof(tmp));
  1098. DBG_HEXDUMP(MCMD_D, "WMM: queue_priority, sort", priv->wmm.queue_priority,
  1099. sizeof(priv->wmm.queue_priority));
  1100. LEAVE();
  1101. }
  1102. /**
  1103. * @brief Downgrade WMM priority queue
  1104. *
  1105. * @param priv Pointer to the mlan_private driver data struct
  1106. *
  1107. * @return N/A
  1108. */
  1109. void
  1110. wlan_wmm_setup_ac_downgrade(pmlan_private priv)
  1111. {
  1112. int ac_val;
  1113. ENTER();
  1114. PRINTM(MINFO, "WMM: AC Priorities: BK(0), BE(1), VI(2), VO(3)\n");
  1115. if (priv->wmm_enabled == MFALSE) {
  1116. /* WMM is not enabled, default priorities */
  1117. for (ac_val = WMM_AC_BK; ac_val <= WMM_AC_VO; ac_val++) {
  1118. priv->wmm.ac_down_graded_vals[ac_val] = (mlan_wmm_ac_e) ac_val;
  1119. }
  1120. } else {
  1121. for (ac_val = WMM_AC_BK; ac_val <= WMM_AC_VO; ac_val++) {
  1122. priv->wmm.ac_down_graded_vals[ac_val]
  1123. = wlan_wmm_eval_downgrade_ac(priv, (mlan_wmm_ac_e) ac_val);
  1124. PRINTM(MINFO, "WMM: AC PRIO %d maps to %d\n",
  1125. ac_val, priv->wmm.ac_down_graded_vals[ac_val]);
  1126. }
  1127. }
  1128. LEAVE();
  1129. }
  1130. /**
  1131. * @brief Allocate and add a RA list for all TIDs with the given RA
  1132. *
  1133. * @param priv Pointer to the mlan_private driver data struct
  1134. * @param ra Address of the receiver STA (AP in case of infra)
  1135. *
  1136. * @return N/A
  1137. */
  1138. void
  1139. wlan_ralist_add(mlan_private * priv, t_u8 * ra)
  1140. {
  1141. int i;
  1142. raListTbl *ra_list;
  1143. pmlan_adapter pmadapter = priv->adapter;
  1144. ENTER();
  1145. for (i = 0; i < MAX_NUM_TID; ++i) {
  1146. ra_list = wlan_wmm_allocate_ralist_node(pmadapter, ra);
  1147. PRINTM(MINFO, "Creating RA List %p for tid %d\n", ra_list, i);
  1148. if (!ra_list)
  1149. break;
  1150. ra_list->max_amsdu = 0;
  1151. if (queuing_ra_based(priv)) {
  1152. ra_list->is_11n_enabled = wlan_is_11n_enabled(priv, ra);
  1153. if (ra_list->is_11n_enabled)
  1154. ra_list->max_amsdu = get_station_max_amsdu_size(priv, ra);
  1155. ra_list->tx_pause = wlan_is_tx_pause(priv, ra);
  1156. } else {
  1157. ra_list->is_11n_enabled = IS_11N_ENABLED(priv);
  1158. if (ra_list->is_11n_enabled)
  1159. ra_list->max_amsdu = priv->max_amsdu;
  1160. }
  1161. PRINTM(MDATA, "ralist %p: is_11n_enabled=%d max_amsdu=%d\n",
  1162. ra_list, ra_list->is_11n_enabled, ra_list->max_amsdu);
  1163. if (ra_list->is_11n_enabled) {
  1164. ra_list->packet_count = 0;
  1165. ra_list->ba_packet_threshold =
  1166. wlan_get_random_ba_threshold(pmadapter);
  1167. }
  1168. util_enqueue_list_tail(pmadapter->pmoal_handle,
  1169. &priv->wmm.tid_tbl_ptr[i].ra_list,
  1170. (pmlan_linked_list) ra_list, MNULL, MNULL);
  1171. if (!priv->wmm.tid_tbl_ptr[i].ra_list_curr)
  1172. priv->wmm.tid_tbl_ptr[i].ra_list_curr = ra_list;
  1173. }
  1174. LEAVE();
  1175. }
  1176. /**
  1177. * @brief Initialize the WMM state information and the WMM data path queues.
  1178. *
  1179. * @param pmadapter Pointer to the mlan_adapter data structure
  1180. *
  1181. * @return N/A
  1182. */
  1183. t_void
  1184. wlan_wmm_init(pmlan_adapter pmadapter)
  1185. {
  1186. int i, j;
  1187. pmlan_private priv;
  1188. ENTER();
  1189. for (j = 0; j < pmadapter->priv_num; ++j) {
  1190. if ((priv = pmadapter->priv[j])) {
  1191. for (i = 0; i < MAX_NUM_TID; ++i) {
  1192. priv->aggr_prio_tbl[i].amsdu = BA_STREAM_NOT_ALLOWED;
  1193. #ifdef WIFI_DIRECT_SUPPORT
  1194. if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT)
  1195. priv->aggr_prio_tbl[i].ampdu_ap =
  1196. priv->aggr_prio_tbl[i].ampdu_user =
  1197. BA_STREAM_NOT_ALLOWED;
  1198. else
  1199. #endif
  1200. priv->aggr_prio_tbl[i].ampdu_ap =
  1201. priv->aggr_prio_tbl[i].ampdu_user = tos_to_tid_inv[i];
  1202. priv->wmm.pkts_queued[i] = 0;
  1203. priv->wmm.tid_tbl_ptr[i].ra_list_curr = MNULL;
  1204. }
  1205. priv->aggr_prio_tbl[6].ampdu_ap
  1206. = priv->aggr_prio_tbl[6].ampdu_user = BA_STREAM_NOT_ALLOWED;
  1207. priv->aggr_prio_tbl[7].ampdu_ap
  1208. = priv->aggr_prio_tbl[7].ampdu_user = BA_STREAM_NOT_ALLOWED;
  1209. priv->add_ba_param.timeout = MLAN_DEFAULT_BLOCK_ACK_TIMEOUT;
  1210. #ifdef STA_SUPPORT
  1211. if (priv->bss_type == MLAN_BSS_TYPE_STA) {
  1212. priv->add_ba_param.tx_win_size = MLAN_STA_AMPDU_DEF_TXWINSIZE;
  1213. priv->add_ba_param.rx_win_size = MLAN_STA_AMPDU_DEF_RXWINSIZE;
  1214. }
  1215. #endif
  1216. #ifdef UAP_SUPPORT
  1217. if (priv->bss_type == MLAN_BSS_TYPE_UAP
  1218. #ifdef WIFI_DIRECT_SUPPORT
  1219. || priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT
  1220. #endif
  1221. ) {
  1222. priv->add_ba_param.tx_win_size = MLAN_UAP_AMPDU_DEF_TXWINSIZE;
  1223. priv->add_ba_param.rx_win_size = MLAN_UAP_AMPDU_DEF_RXWINSIZE;
  1224. }
  1225. #endif
  1226. priv->add_ba_param.tx_amsdu = MTRUE;
  1227. priv->add_ba_param.rx_amsdu = MTRUE;
  1228. memset(priv->adapter, priv->rx_seq, 0xff, sizeof(priv->rx_seq));
  1229. wlan_wmm_default_queue_priorities(priv);
  1230. }
  1231. }
  1232. LEAVE();
  1233. }
  1234. /**
  1235. * @brief Setup the queue priorities and downgrade any queues as required
  1236. * by the WMM info. Setups default values if WMM is not active
  1237. * for this association.
  1238. *
  1239. * @param priv Pointer to the mlan_private driver data struct
  1240. *
  1241. * @return N/A
  1242. */
  1243. void
  1244. wlan_wmm_setup_queues(pmlan_private priv)
  1245. {
  1246. ENTER();
  1247. wlan_wmm_setup_queue_priorities(priv, MNULL);
  1248. wlan_wmm_setup_ac_downgrade(priv);
  1249. LEAVE();
  1250. }
  1251. #ifdef STA_SUPPORT
  1252. /**
  1253. * @brief Send a command to firmware to retrieve the current WMM status
  1254. *
  1255. * @param priv Pointer to the mlan_private driver data struct
  1256. *
  1257. * @return MLAN_STATUS_SUCCESS; MLAN_STATUS_FAILURE
  1258. */
  1259. mlan_status
  1260. wlan_cmd_wmm_status_change(pmlan_private priv)
  1261. {
  1262. mlan_status ret = MLAN_STATUS_SUCCESS;
  1263. ENTER();
  1264. ret = wlan_prepare_cmd(priv, HostCmd_CMD_WMM_GET_STATUS, 0, 0, 0, MNULL);
  1265. LEAVE();
  1266. return ret;
  1267. }
  1268. #endif
  1269. /**
  1270. * @brief Check if wmm TX queue is empty
  1271. *
  1272. * @param pmadapter Pointer to the mlan_adapter driver data struct
  1273. *
  1274. * @return MFALSE if not empty; MTRUE if empty
  1275. */
  1276. int
  1277. wlan_wmm_lists_empty(pmlan_adapter pmadapter)
  1278. {
  1279. int j;
  1280. pmlan_private priv;
  1281. ENTER();
  1282. for (j = 0; j < pmadapter->priv_num; ++j) {
  1283. if ((priv = pmadapter->priv[j])) {
  1284. if ((priv->port_ctrl_mode == MTRUE) && (priv->port_open == MFALSE)) {
  1285. PRINTM(MINFO,
  1286. "wmm_lists_empty: PORT_CLOSED Ignore pkts from BSS%d\n",
  1287. j);
  1288. continue;
  1289. }
  1290. if (util_scalar_read(pmadapter->pmoal_handle,
  1291. &priv->wmm.tx_pkts_queued,
  1292. pmadapter->callbacks.moal_spin_lock,
  1293. pmadapter->callbacks.moal_spin_unlock)) {
  1294. LEAVE();
  1295. return MFALSE;
  1296. }
  1297. }
  1298. }
  1299. LEAVE();
  1300. return MTRUE;
  1301. }
  1302. /**
  1303. * @brief Get ralist node
  1304. *
  1305. * @param priv Pointer to the mlan_private driver data struct
  1306. * @param tid TID
  1307. * @param ra_addr Pointer to the route address
  1308. *
  1309. * @return ra_list or MNULL
  1310. */
  1311. raListTbl *
  1312. wlan_wmm_get_ralist_node(pmlan_private priv, t_u8 tid, t_u8 * ra_addr)
  1313. {
  1314. raListTbl *ra_list;
  1315. ENTER();
  1316. ra_list =
  1317. (raListTbl *) util_peek_list(priv->adapter->pmoal_handle,
  1318. &priv->wmm.tid_tbl_ptr[tid].ra_list, MNULL,
  1319. MNULL);
  1320. while (ra_list && (ra_list != (raListTbl *)
  1321. & priv->wmm.tid_tbl_ptr[tid].ra_list)) {
  1322. if (!memcmp(priv->adapter, ra_list->ra, ra_addr, MLAN_MAC_ADDR_LENGTH)) {
  1323. LEAVE();
  1324. return ra_list;
  1325. }
  1326. ra_list = ra_list->pnext;
  1327. }
  1328. LEAVE();
  1329. return MNULL;
  1330. }
  1331. /**
  1332. * @brief Check if RA list is valid or not
  1333. *
  1334. * @param priv Pointer to the mlan_private driver data struct
  1335. * @param ra_list Pointer to raListTbl
  1336. * @param ptrindex TID pointer index
  1337. *
  1338. * @return MTRUE- valid. MFALSE- invalid.
  1339. */
  1340. int
  1341. wlan_is_ralist_valid(mlan_private * priv, raListTbl * ra_list, int ptrindex)
  1342. {
  1343. raListTbl *rlist;
  1344. ENTER();
  1345. rlist =
  1346. (raListTbl *) util_peek_list(priv->adapter->pmoal_handle,
  1347. &priv->wmm.tid_tbl_ptr[ptrindex].ra_list,
  1348. MNULL, MNULL);
  1349. while (rlist && (rlist != (raListTbl *)
  1350. & priv->wmm.tid_tbl_ptr[ptrindex].ra_list)) {
  1351. if (rlist == ra_list) {
  1352. LEAVE();
  1353. return MTRUE;
  1354. }
  1355. rlist = rlist->pnext;
  1356. }
  1357. LEAVE();
  1358. return MFALSE;
  1359. }
  1360. /**
  1361. * @brief Update an existing raList with a new RA and 11n capability
  1362. *
  1363. * @param priv Pointer to the mlan_private driver data struct
  1364. * @param old_ra Old receiver address
  1365. * @param new_ra New receiver address
  1366. *
  1367. * @return integer count of updated nodes
  1368. */
  1369. int
  1370. wlan_ralist_update(mlan_private * priv, t_u8 * old_ra, t_u8 * new_ra)
  1371. {
  1372. t_u8 tid;
  1373. int update_count;
  1374. raListTbl *ra_list;
  1375. ENTER();
  1376. update_count = 0;
  1377. for (tid = 0; tid < MAX_NUM_TID; ++tid) {
  1378. ra_list = wlan_wmm_get_ralist_node(priv, tid, old_ra);
  1379. if (ra_list) {
  1380. update_count++;
  1381. if (queuing_ra_based(priv))
  1382. ra_list->is_11n_enabled = wlan_is_11n_enabled(priv, new_ra);
  1383. else
  1384. ra_list->is_11n_enabled = IS_11N_ENABLED(priv);
  1385. ra_list->packet_count = 0;
  1386. ra_list->ba_packet_threshold =
  1387. wlan_get_random_ba_threshold(priv->adapter);
  1388. PRINTM(MINFO,
  1389. "ralist_update: %p, %d, %02x:%02x:%02x:%02x:%02x:%02x-->"
  1390. "%02x:%02x:%02x:%02x:%02x:%02x\n", ra_list,
  1391. ra_list->is_11n_enabled, ra_list->ra[0], ra_list->ra[1],
  1392. ra_list->ra[2], ra_list->ra[3], ra_list->ra[4],
  1393. ra_list->ra[5], new_ra[0], new_ra[1], new_ra[2], new_ra[3],
  1394. new_ra[4], new_ra[5]);
  1395. memcpy(priv->adapter, ra_list->ra, new_ra, MLAN_MAC_ADDR_LENGTH);
  1396. }
  1397. }
  1398. LEAVE();
  1399. return update_count;
  1400. }
  1401. /**
  1402. * @brief Add packet to WMM queue
  1403. *
  1404. * @param pmadapter Pointer to the mlan_adapter driver data struct
  1405. * @param pmbuf Pointer to the mlan_buffer data struct
  1406. *
  1407. * @return N/A
  1408. */
  1409. t_void
  1410. wlan_wmm_add_buf_txqueue(pmlan_adapter pmadapter, pmlan_buffer pmbuf)
  1411. {
  1412. pmlan_private priv = pmadapter->priv[pmbuf->bss_index];
  1413. t_u32 tid;
  1414. raListTbl *ra_list;
  1415. t_u8 ra[MLAN_MAC_ADDR_LENGTH], tid_down;
  1416. ENTER();
  1417. pmbuf->buf_type = MLAN_BUF_TYPE_DATA;
  1418. if (!priv->media_connected) {
  1419. PRINTM(MWARN, "Drop packet in disconnect state\n");
  1420. wlan_write_data_complete(pmadapter, pmbuf, MLAN_STATUS_FAILURE);
  1421. LEAVE();
  1422. return;
  1423. }
  1424. tid = pmbuf->priority;
  1425. pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
  1426. priv->wmm.ra_list_spinlock);
  1427. tid_down = wlan_wmm_downgrade_tid(priv, tid);
  1428. /* In case of infra as we have already created the list during association
  1429. we just don't have to call get_queue_raptr, we will have only 1 raptr
  1430. for a tid in case of infra */
  1431. if (!queuing_ra_based(priv)) {
  1432. ra_list = (raListTbl *) util_peek_list(pmadapter->pmoal_handle,
  1433. &priv->wmm.tid_tbl_ptr[tid_down].
  1434. ra_list, MNULL, MNULL);
  1435. } else {
  1436. memcpy(pmadapter, ra, pmbuf->pbuf + pmbuf->data_offset,
  1437. MLAN_MAC_ADDR_LENGTH);
  1438. /** put multicast/broadcast packet in the same ralist */
  1439. if (ra[0] & 0x01)
  1440. memset(pmadapter, ra, 0xff, sizeof(ra));
  1441. ra_list = wlan_wmm_get_queue_raptr(priv, tid_down, ra);
  1442. }
  1443. if (!ra_list) {
  1444. PRINTM(MWARN, "Drop packet, ra_list=%p, "
  1445. "media_connected=%d\n", ra_list, priv->media_connected);
  1446. pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
  1447. priv->wmm.ra_list_spinlock);
  1448. wlan_write_data_complete(pmadapter, pmbuf, MLAN_STATUS_FAILURE);
  1449. LEAVE();
  1450. return;
  1451. }
  1452. PRINTM(MDATA, "Adding pkt to ra_list %p %p priority=%d, tid_down=%d\n",
  1453. ra_list, pmbuf, pmbuf->priority, tid_down);
  1454. util_enqueue_list_tail(pmadapter->pmoal_handle, &ra_list->buf_head,
  1455. (pmlan_linked_list) pmbuf, MNULL, MNULL);
  1456. ra_list->total_pkts++;
  1457. ra_list->packet_count++;
  1458. priv->wmm.pkts_queued[tid_down]++;
  1459. if (!ra_list->tx_pause) {
  1460. util_scalar_increment(pmadapter->pmoal_handle,
  1461. &priv->wmm.tx_pkts_queued, MNULL, MNULL);
  1462. /* if highest_queued_prio < prio(tid_down), set it to prio(tid_down) */
  1463. util_scalar_conditional_write(pmadapter->pmoal_handle,
  1464. &priv->wmm.highest_queued_prio,
  1465. MLAN_SCALAR_COND_LESS_THAN,
  1466. tos_to_tid_inv[tid_down],
  1467. tos_to_tid_inv[tid_down], MNULL, MNULL);
  1468. }
  1469. /* Record the current time the packet was queued; used to determine the
  1470. amount of time the packet was queued in the driver before it was sent to
  1471. the firmware. The delay is then sent along with the packet to the
  1472. firmware for aggregate delay calculation for stats and MSDU lifetime
  1473. expiry. */
  1474. pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
  1475. priv->wmm.ra_list_spinlock);
  1476. pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle,
  1477. &pmbuf->in_ts_sec,
  1478. &pmbuf->in_ts_usec);
  1479. LEAVE();
  1480. }
  1481. #ifdef STA_SUPPORT
  1482. /**
  1483. * @brief Process the GET_WMM_STATUS command response from firmware
  1484. *
  1485. * The GET_WMM_STATUS response may contain multiple TLVs for:
  1486. * - AC Queue status TLVs
  1487. * - Current WMM Parameter IE TLV
  1488. * - Admission Control action frame TLVs
  1489. *
  1490. * This function parses the TLVs and then calls further functions
  1491. * to process any changes in the queue prioritize or state.
  1492. *
  1493. * @param priv Pointer to the mlan_private driver data struct
  1494. * @param ptlv Pointer to the tlv block returned in the response.
  1495. * @param resp_len Length of TLV block
  1496. *
  1497. * @return MLAN_STATUS_SUCCESS
  1498. */
  1499. mlan_status
  1500. wlan_ret_wmm_get_status(pmlan_private priv, t_u8 * ptlv, int resp_len)
  1501. {
  1502. t_u8 *pcurrent = ptlv;
  1503. t_u32 tlv_len;
  1504. t_u8 sendWmmEvent;
  1505. MrvlIEtypes_Data_t *pTlvHdr;
  1506. MrvlIEtypes_WmmQueueStatus_t *pTlvWmmQStatus;
  1507. IEEEtypes_WmmParameter_t *pWmmParamIe = MNULL;
  1508. WmmAcStatus_t *pac_status;
  1509. MrvlIETypes_ActionFrame_t *pTlvAction;
  1510. IEEEtypes_Action_WMM_AddTsRsp_t *pAddTsRsp;
  1511. IEEEtypes_Action_WMM_DelTs_t *pDelTs;
  1512. ENTER();
  1513. sendWmmEvent = MFALSE;
  1514. PRINTM(MINFO, "WMM: WMM_GET_STATUS cmdresp received: %d\n", resp_len);
  1515. HEXDUMP("CMD_RESP: WMM_GET_STATUS", pcurrent, resp_len);
  1516. while (resp_len >= sizeof(pTlvHdr->header)) {
  1517. pTlvHdr = (MrvlIEtypes_Data_t *) pcurrent;
  1518. tlv_len = wlan_le16_to_cpu(pTlvHdr->header.len);
  1519. switch (wlan_le16_to_cpu(pTlvHdr->header.type)) {
  1520. case TLV_TYPE_WMMQSTATUS:
  1521. pTlvWmmQStatus = (MrvlIEtypes_WmmQueueStatus_t *) pTlvHdr;
  1522. PRINTM(MEVENT, "WMM_STATUS: QSTATUS TLV: %d\n",
  1523. pTlvWmmQStatus->queue_index);
  1524. PRINTM(MINFO,
  1525. "CMD_RESP: WMM_GET_STATUS: QSTATUS TLV: %d, %d, %d\n",
  1526. pTlvWmmQStatus->queue_index,
  1527. pTlvWmmQStatus->flow_required, pTlvWmmQStatus->disabled);
  1528. pac_status = &priv->wmm.ac_status[pTlvWmmQStatus->queue_index];
  1529. pac_status->disabled = pTlvWmmQStatus->disabled;
  1530. pac_status->flow_required = pTlvWmmQStatus->flow_required;
  1531. pac_status->flow_created = pTlvWmmQStatus->flow_created;
  1532. break;
  1533. case WMM_IE:
  1534. /*
  1535. * Point the regular IEEE IE 2 bytes into the Marvell IE
  1536. * and setup the IEEE IE type and length byte fields
  1537. */
  1538. PRINTM(MEVENT, "WMM STATUS: WMM IE\n");
  1539. HEXDUMP("WMM: WMM TLV:", (t_u8 *) pTlvHdr, tlv_len + 4);
  1540. pWmmParamIe = (IEEEtypes_WmmParameter_t *) (pcurrent + 2);
  1541. pWmmParamIe->vend_hdr.len = (t_u8) tlv_len;
  1542. pWmmParamIe->vend_hdr.element_id = WMM_IE;
  1543. PRINTM(MINFO, "CMD_RESP: WMM_GET_STATUS: WMM Parameter Set: %d\n",
  1544. pWmmParamIe->qos_info.para_set_count);
  1545. memcpy(priv->adapter,
  1546. (t_u8 *) & priv->curr_bss_params.bss_descriptor.wmm_ie,
  1547. pWmmParamIe, MIN(sizeof(IEEEtypes_WmmParameter_t),
  1548. (pWmmParamIe->vend_hdr.len + 2)));
  1549. sendWmmEvent = MTRUE;
  1550. break;
  1551. case TLV_TYPE_IEEE_ACTION_FRAME:
  1552. PRINTM(MEVENT, "WMM_STATUS: IEEE Action Frame\n");
  1553. pTlvAction = (MrvlIETypes_ActionFrame_t *) pcurrent;
  1554. if (pTlvAction->actionFrame.wmmAc.tspecAct.category
  1555. == IEEE_MGMT_ACTION_CATEGORY_WMM_TSPEC) {
  1556. switch (pTlvAction->actionFrame.wmmAc.tspecAct.action) {
  1557. case TSPEC_ACTION_CODE_ADDTS_RSP:
  1558. pAddTsRsp = &pTlvAction->actionFrame.wmmAc.addTsRsp;
  1559. wlan_send_wmmac_host_event(priv, "ADDTS_RSP",
  1560. pTlvAction->srcAddr,
  1561. pAddTsRsp->tspecIE.TspecBody.
  1562. TSInfo.TID,
  1563. pAddTsRsp->tspecIE.TspecBody.
  1564. TSInfo.UserPri,
  1565. pAddTsRsp->statusCode);
  1566. break;
  1567. case TSPEC_ACTION_CODE_DELTS:
  1568. pDelTs = &pTlvAction->actionFrame.wmmAc.delTs;
  1569. wlan_send_wmmac_host_event(priv, "DELTS_RX",
  1570. pTlvAction->srcAddr,
  1571. pDelTs->tspecIE.TspecBody.TSInfo.
  1572. TID,
  1573. pDelTs->tspecIE.TspecBody.TSInfo.
  1574. UserPri, pDelTs->reasonCode);
  1575. break;
  1576. case TSPEC_ACTION_CODE_ADDTS_REQ:
  1577. default:
  1578. break;
  1579. }
  1580. }
  1581. break;
  1582. default:
  1583. break;
  1584. }
  1585. pcurrent += (tlv_len + sizeof(pTlvHdr->header));
  1586. resp_len -= (tlv_len + sizeof(pTlvHdr->header));
  1587. }
  1588. wlan_wmm_setup_queue_priorities(priv, pWmmParamIe);
  1589. wlan_wmm_setup_ac_downgrade(priv);
  1590. if (sendWmmEvent) {
  1591. wlan_recv_event(priv, MLAN_EVENT_ID_FW_WMM_CONFIG_CHANGE, MNULL);
  1592. }
  1593. LEAVE();
  1594. return MLAN_STATUS_SUCCESS;
  1595. }
  1596. /**
  1597. * @brief Call back from the command module to allow insertion of a WMM TLV
  1598. *
  1599. * If the BSS we are associating to supports WMM, add the required WMM
  1600. * Information IE to the association request command buffer in the form
  1601. * of a Marvell extended IEEE IE.
  1602. *
  1603. * @param priv Pointer to the mlan_private driver data struct
  1604. * @param ppAssocBuf Output parameter: Pointer to the TLV output buffer,
  1605. * modified on return to point after the appended WMM TLV
  1606. * @param pWmmIE Pointer to the WMM IE for the BSS we are joining
  1607. * @param pHTCap Pointer to the HT IE for the BSS we are joining
  1608. *
  1609. * @return Length of data appended to the association tlv buffer
  1610. */
  1611. t_u32
  1612. wlan_wmm_process_association_req(pmlan_private priv,
  1613. t_u8 ** ppAssocBuf,
  1614. IEEEtypes_WmmParameter_t * pWmmIE,
  1615. IEEEtypes_HTCap_t * pHTCap)
  1616. {
  1617. MrvlIEtypes_WmmParamSet_t *pwmm_tlv;
  1618. t_u32 ret_len = 0;
  1619. ENTER();
  1620. /* Null checks */
  1621. if (!ppAssocBuf) {
  1622. LEAVE();
  1623. return 0;
  1624. }
  1625. if (!(*ppAssocBuf)) {
  1626. LEAVE();
  1627. return 0;
  1628. }
  1629. if (!pWmmIE) {
  1630. LEAVE();
  1631. return 0;
  1632. }
  1633. PRINTM(MINFO, "WMM: process assoc req: bss->wmmIe=0x%x\n",
  1634. pWmmIE->vend_hdr.element_id);
  1635. if ((priv->wmm_required
  1636. || (pHTCap && (pHTCap->ieee_hdr.element_id == HT_CAPABILITY)
  1637. && (priv->config_bands & BAND_GN || priv->config_bands & BAND_AN))
  1638. )
  1639. && pWmmIE->vend_hdr.element_id == WMM_IE) {
  1640. pwmm_tlv = (MrvlIEtypes_WmmParamSet_t *) * ppAssocBuf;
  1641. pwmm_tlv->header.type = (t_u16) wmm_info_ie[0];
  1642. pwmm_tlv->header.type = wlan_cpu_to_le16(pwmm_tlv->header.type);
  1643. pwmm_tlv->header.len = (t_u16) wmm_info_ie[1];
  1644. memcpy(priv->adapter, pwmm_tlv->wmm_ie, &wmm_info_ie[2],
  1645. pwmm_tlv->header.len);
  1646. if (pWmmIE->qos_info.qos_uapsd)
  1647. memcpy(priv->adapter,
  1648. (t_u8 *) (pwmm_tlv->wmm_ie + pwmm_tlv->header.len -
  1649. sizeof(priv->wmm_qosinfo)), &priv->wmm_qosinfo,
  1650. sizeof(priv->wmm_qosinfo));
  1651. ret_len = sizeof(pwmm_tlv->header) + pwmm_tlv->header.len;
  1652. pwmm_tlv->header.len = wlan_cpu_to_le16(pwmm_tlv->header.len);
  1653. HEXDUMP("ASSOC_CMD: WMM IE", (t_u8 *) pwmm_tlv, ret_len);
  1654. *ppAssocBuf += ret_len;
  1655. }
  1656. LEAVE();
  1657. return ret_len;
  1658. }
  1659. #endif /* STA_SUPPORT */
  1660. /**
  1661. * @brief Compute the time delay in the driver queues for a given packet.
  1662. *
  1663. * When the packet is received at the OS/Driver interface, the current
  1664. * time is set in the packet structure. The difference between the present
  1665. * time and that received time is computed in this function and limited
  1666. * based on pre-compiled limits in the driver.
  1667. *
  1668. * @param priv Ptr to the mlan_private driver data struct
  1669. * @param pmbuf Ptr to the mlan_buffer which has been previously timestamped
  1670. *
  1671. * @return Time delay of the packet in 2ms units after having limit applied
  1672. */
  1673. t_u8
  1674. wlan_wmm_compute_driver_packet_delay(pmlan_private priv,
  1675. const pmlan_buffer pmbuf)
  1676. {
  1677. t_u8 ret_val = 0;
  1678. t_u32 out_ts_sec, out_ts_usec, queue_delay;
  1679. ENTER();
  1680. priv->adapter->callbacks.moal_get_system_time(priv->adapter->pmoal_handle,
  1681. &out_ts_sec, &out_ts_usec);
  1682. queue_delay = (out_ts_sec - pmbuf->in_ts_sec) * 1000;
  1683. queue_delay += (out_ts_usec - pmbuf->in_ts_usec) / 1000;
  1684. /*
  1685. * Queue delay is passed as a uint8 in units of 2ms (ms shifted
  1686. * by 1). Min value (other than 0) is therefore 2ms, max is 510ms.
  1687. *
  1688. * Pass max value if queue_delay is beyond the uint8 range
  1689. */
  1690. ret_val = (t_u8) (MIN(queue_delay, priv->wmm.drv_pkt_delay_max) >> 1);
  1691. PRINTM(MINFO, "WMM: Pkt Delay: %d ms, %d ms sent to FW\n",
  1692. queue_delay, ret_val);
  1693. LEAVE();
  1694. return ret_val;
  1695. }
  1696. /**
  1697. * @brief Transmit the highest priority packet awaiting in the WMM Queues
  1698. *
  1699. * @param pmadapter Pointer to the mlan_adapter driver data struct
  1700. *
  1701. * @return N/A
  1702. */
  1703. void
  1704. wlan_wmm_process_tx(pmlan_adapter pmadapter)
  1705. {
  1706. ENTER();
  1707. do {
  1708. if (wlan_dequeue_tx_packet(pmadapter))
  1709. break;
  1710. /* Check if busy */
  1711. } while (!pmadapter->data_sent && !pmadapter->tx_lock_flag
  1712. && !wlan_wmm_lists_empty(pmadapter));
  1713. LEAVE();
  1714. return;
  1715. }
  1716. /**
  1717. * @brief select wmm queue
  1718. *
  1719. * @param pmpriv A pointer to mlan_private structure
  1720. * @param tid TID 0-7
  1721. *
  1722. * @return wmm_queue priority (0-3)
  1723. */
  1724. t_u8
  1725. wlan_wmm_select_queue(mlan_private * pmpriv, t_u8 tid)
  1726. {
  1727. pmlan_adapter pmadapter = pmpriv->adapter;
  1728. t_u8 i;
  1729. mlan_wmm_ac_e ac_down =
  1730. pmpriv->wmm.
  1731. ac_down_graded_vals[wlan_wmm_convert_tos_to_ac(pmadapter, tid)];
  1732. ENTER();
  1733. for (i = 0; i < 4; i++) {
  1734. if (pmpriv->wmm.queue_priority[i] == ac_down) {
  1735. LEAVE();
  1736. return i;
  1737. }
  1738. }
  1739. LEAVE();
  1740. return 0;
  1741. }
  1742. #if defined(UAP_SUPPORT)
  1743. /**
  1744. * @brief Delete tx packets in RA list
  1745. *
  1746. * @param priv Pointer to the mlan_private driver data struct
  1747. * @param ra_list_head ra list header
  1748. * @param tid tid
  1749. *
  1750. * @return N/A
  1751. */
  1752. static INLINE t_u8
  1753. wlan_del_tx_pkts_in_ralist(pmlan_private priv,
  1754. mlan_list_head * ra_list_head, int tid)
  1755. {
  1756. raListTbl *ra_list = MNULL;
  1757. pmlan_adapter pmadapter = priv->adapter;
  1758. pmlan_buffer pmbuf = MNULL;
  1759. t_u8 ret = MFALSE;
  1760. ENTER();
  1761. ra_list =
  1762. (raListTbl *) util_peek_list(priv->adapter->pmoal_handle, ra_list_head,
  1763. MNULL, MNULL);
  1764. while (ra_list && ra_list != (raListTbl *) ra_list_head) {
  1765. if (ra_list->total_pkts && (ra_list->tx_pause ||
  1766. (ra_list->total_pkts > RX_LOW_THRESHOLD))) {
  1767. if ((pmbuf =
  1768. (pmlan_buffer) util_dequeue_list(pmadapter->pmoal_handle,
  1769. &ra_list->buf_head, MNULL,
  1770. MNULL))) {
  1771. PRINTM(MDATA,
  1772. "Drop pkts: tid=%d tx_pause=%d pkts=%d brd_pkts=%d %02x:%02x:%02x:%02x:%02x:%02x\n",
  1773. tid, ra_list->tx_pause, ra_list->total_pkts,
  1774. pmadapter->pending_bridge_pkts, ra_list->ra[0],
  1775. ra_list->ra[1], ra_list->ra[2], ra_list->ra[3],
  1776. ra_list->ra[4], ra_list->ra[5]);
  1777. wlan_write_data_complete(pmadapter, pmbuf, MLAN_STATUS_FAILURE);
  1778. priv->wmm.pkts_queued[tid]--;
  1779. priv->num_drop_pkts++;
  1780. ra_list->total_pkts--;
  1781. if (!ra_list->tx_pause)
  1782. util_scalar_decrement(pmadapter->pmoal_handle,
  1783. &priv->wmm.tx_pkts_queued, MNULL,
  1784. MNULL);
  1785. ret = MTRUE;
  1786. break;
  1787. }
  1788. }
  1789. ra_list = ra_list->pnext;
  1790. }
  1791. LEAVE();
  1792. return ret;
  1793. }
  1794. /**
  1795. * @brief Drop tx pkts
  1796. *
  1797. * @param priv Pointer to the mlan_private driver data struct
  1798. *
  1799. * @return N/A
  1800. */
  1801. t_void
  1802. wlan_drop_tx_pkts(pmlan_private priv)
  1803. {
  1804. int j;
  1805. static int i = 0;
  1806. pmlan_adapter pmadapter = priv->adapter;
  1807. pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
  1808. priv->wmm.ra_list_spinlock);
  1809. for (j = 0; j < MAX_NUM_TID; j++, i++) {
  1810. if (i == MAX_NUM_TID)
  1811. i = 0;
  1812. if (wlan_del_tx_pkts_in_ralist
  1813. (priv, &priv->wmm.tid_tbl_ptr[i].ra_list, i)) {
  1814. i++;
  1815. break;
  1816. }
  1817. }
  1818. pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
  1819. priv->wmm.ra_list_spinlock);
  1820. return;
  1821. }
  1822. /**
  1823. * @brief Remove peer ralist
  1824. *
  1825. * @param priv A pointer to mlan_private
  1826. * @param mac peer mac address
  1827. *
  1828. * @return N/A
  1829. */
  1830. t_void
  1831. wlan_wmm_delete_peer_ralist(pmlan_private priv, t_u8 * mac)
  1832. {
  1833. raListTbl *ra_list;
  1834. int i;
  1835. pmlan_adapter pmadapter = priv->adapter;
  1836. t_u32 pkt_cnt = 0;
  1837. t_u32 tx_pkts_queued = 0;
  1838. ENTER();
  1839. pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
  1840. priv->wmm.ra_list_spinlock);
  1841. for (i = 0; i < MAX_NUM_TID; ++i) {
  1842. ra_list = wlan_wmm_get_ralist_node(priv, i, mac);
  1843. if (ra_list) {
  1844. PRINTM(MINFO, "delete sta ralist %p\n", ra_list);
  1845. if (!ra_list->tx_pause)
  1846. pkt_cnt += ra_list->total_pkts;
  1847. wlan_wmm_del_pkts_in_ralist_node(priv, ra_list);
  1848. util_unlink_list(pmadapter->pmoal_handle,
  1849. &priv->wmm.tid_tbl_ptr[i].ra_list,
  1850. (pmlan_linked_list) ra_list, MNULL, MNULL);
  1851. pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle,
  1852. (t_u8 *) ra_list);
  1853. if (priv->wmm.tid_tbl_ptr[i].ra_list_curr == ra_list)
  1854. priv->wmm.tid_tbl_ptr[i].ra_list_curr =
  1855. (raListTbl *) & priv->wmm.tid_tbl_ptr[i].ra_list;
  1856. }
  1857. }
  1858. if (pkt_cnt) {
  1859. tx_pkts_queued = util_scalar_read(pmadapter->pmoal_handle,
  1860. &priv->wmm.tx_pkts_queued, MNULL,
  1861. MNULL);
  1862. tx_pkts_queued -= pkt_cnt;
  1863. util_scalar_write(priv->adapter->pmoal_handle,
  1864. &priv->wmm.tx_pkts_queued, tx_pkts_queued, MNULL,
  1865. MNULL);
  1866. util_scalar_write(priv->adapter->pmoal_handle,
  1867. &priv->wmm.highest_queued_prio, HIGH_PRIO_TID, MNULL,
  1868. MNULL);
  1869. }
  1870. pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
  1871. priv->wmm.ra_list_spinlock);
  1872. LEAVE();
  1873. }
  1874. #endif
  1875. #ifdef STA_SUPPORT
  1876. /**
  1877. * @brief This function prepares the command of ADDTS
  1878. *
  1879. * @param pmpriv A pointer to mlan_private structure
  1880. * @param cmd A pointer to HostCmd_DS_COMMAND structure
  1881. * @param pdata_buf A pointer to data buffer
  1882. * @return MLAN_STATUS_SUCCESS
  1883. */
  1884. mlan_status
  1885. wlan_cmd_wmm_addts_req(IN pmlan_private pmpriv,
  1886. OUT HostCmd_DS_COMMAND * cmd, IN t_void * pdata_buf)
  1887. {
  1888. mlan_ds_wmm_addts *paddts = (mlan_ds_wmm_addts *) pdata_buf;
  1889. HostCmd_DS_WMM_ADDTS_REQ *pcmd_addts = &cmd->params.add_ts;
  1890. ENTER();
  1891. cmd->command = wlan_cpu_to_le16(HostCmd_CMD_WMM_ADDTS_REQ);
  1892. cmd->size = wlan_cpu_to_le16(sizeof(pcmd_addts->dialog_token)
  1893. + sizeof(pcmd_addts->timeout_ms)
  1894. + sizeof(pcmd_addts->command_result)
  1895. + sizeof(pcmd_addts->ieee_status_code)
  1896. + paddts->ie_data_len + S_DS_GEN);
  1897. cmd->result = 0;
  1898. pcmd_addts->timeout_ms = wlan_cpu_to_le32(paddts->timeout);
  1899. pcmd_addts->dialog_token = paddts->dialog_tok;
  1900. memcpy(pmpriv->adapter,
  1901. pcmd_addts->tspec_data,
  1902. paddts->ie_data, MIN(WMM_TSPEC_SIZE, paddts->ie_data_len));
  1903. LEAVE();
  1904. return MLAN_STATUS_SUCCESS;
  1905. }
  1906. /**
  1907. * @brief This function handles the command response of ADDTS
  1908. *
  1909. * @param pmpriv A pointer to mlan_private structure
  1910. * @param resp A pointer to HostCmd_DS_COMMAND
  1911. * @param pioctl_buf A pointer to mlan_ioctl_req structure
  1912. *
  1913. * @return MLAN_STATUS_SUCCESS
  1914. */
  1915. mlan_status
  1916. wlan_ret_wmm_addts_req(IN pmlan_private pmpriv,
  1917. const IN HostCmd_DS_COMMAND * resp,
  1918. OUT mlan_ioctl_req * pioctl_buf)
  1919. {
  1920. mlan_ds_wmm_cfg *pwmm = MNULL;
  1921. mlan_ds_wmm_addts *paddts = MNULL;
  1922. const HostCmd_DS_WMM_ADDTS_REQ *presp_addts = &resp->params.add_ts;
  1923. ENTER();
  1924. if (pioctl_buf) {
  1925. pwmm = (mlan_ds_wmm_cfg *) pioctl_buf->pbuf;
  1926. paddts = (mlan_ds_wmm_addts *) & pwmm->param.addts;
  1927. paddts->result = presp_addts->command_result;
  1928. paddts->dialog_tok = presp_addts->dialog_token;
  1929. paddts->status_code = (t_u32) presp_addts->ieee_status_code;
  1930. if (presp_addts->command_result == MLAN_CMD_RESULT_SUCCESS) {
  1931. /* The tspecData field is potentially variable in size due to extra
  1932. IEs that may have been in the ADDTS response action frame.
  1933. Calculate the data length from the firmware command response. */
  1934. paddts->ie_data_len
  1935. = (t_u8) (resp->size - sizeof(presp_addts->command_result)
  1936. - sizeof(presp_addts->timeout_ms)
  1937. - sizeof(presp_addts->dialog_token)
  1938. - sizeof(presp_addts->ieee_status_code)
  1939. - S_DS_GEN);
  1940. /* Copy the TSPEC data include any extra IEs after the TSPEC */
  1941. memcpy(pmpriv->adapter,
  1942. paddts->ie_data,
  1943. presp_addts->tspec_data, paddts->ie_data_len);
  1944. } else {
  1945. paddts->ie_data_len = 0;
  1946. }
  1947. PRINTM(MINFO, "TSPEC: ADDTS ret = %d,%d sz=%d\n",
  1948. paddts->result, paddts->status_code, paddts->ie_data_len);
  1949. HEXDUMP("TSPEC: ADDTS data", paddts->ie_data, paddts->ie_data_len);
  1950. }
  1951. LEAVE();
  1952. return MLAN_STATUS_SUCCESS;
  1953. }
  1954. /**
  1955. * @brief This function prepares the command of DELTS
  1956. *
  1957. * @param pmpriv A pointer to mlan_private structure
  1958. * @param cmd A pointer to HostCmd_DS_COMMAND structure
  1959. * @param pdata_buf A pointer to data buffer
  1960. * @return MLAN_STATUS_SUCCESS
  1961. */
  1962. mlan_status
  1963. wlan_cmd_wmm_delts_req(IN pmlan_private pmpriv,
  1964. OUT HostCmd_DS_COMMAND * cmd, IN t_void * pdata_buf)
  1965. {
  1966. mlan_ds_wmm_delts *pdelts = (mlan_ds_wmm_delts *) pdata_buf;
  1967. HostCmd_DS_WMM_DELTS_REQ *pcmd_delts = &cmd->params.del_ts;
  1968. ENTER();
  1969. cmd->command = wlan_cpu_to_le16(HostCmd_CMD_WMM_DELTS_REQ);
  1970. cmd->size = wlan_cpu_to_le16(sizeof(pcmd_delts->dialog_token)
  1971. + sizeof(pcmd_delts->command_result)
  1972. + sizeof(pcmd_delts->ieee_reason_code)
  1973. + pdelts->ie_data_len + S_DS_GEN);
  1974. cmd->result = 0;
  1975. pcmd_delts->ieee_reason_code = (t_u8) pdelts->status_code;
  1976. memcpy(pmpriv->adapter,
  1977. pcmd_delts->tspec_data,
  1978. pdelts->ie_data, MIN(WMM_TSPEC_SIZE, pdelts->ie_data_len));
  1979. LEAVE();
  1980. return MLAN_STATUS_SUCCESS;
  1981. }
  1982. /**
  1983. * @brief This function handles the command response of DELTS
  1984. *
  1985. * @param pmpriv A pointer to mlan_private structure
  1986. * @param resp A pointer to HostCmd_DS_COMMAND
  1987. * @param pioctl_buf A pointer to mlan_ioctl_req structure
  1988. *
  1989. * @return MLAN_STATUS_SUCCESS
  1990. */
  1991. mlan_status
  1992. wlan_ret_wmm_delts_req(IN pmlan_private pmpriv,
  1993. const IN HostCmd_DS_COMMAND * resp,
  1994. OUT mlan_ioctl_req * pioctl_buf)
  1995. {
  1996. mlan_ds_wmm_cfg *pwmm;
  1997. IEEEtypes_WMM_TSPEC_t *pTspecIE;
  1998. const HostCmd_DS_WMM_DELTS_REQ *presp_delts = &resp->params.del_ts;
  1999. ENTER();
  2000. if (pioctl_buf) {
  2001. pwmm = (mlan_ds_wmm_cfg *) pioctl_buf->pbuf;
  2002. pwmm->param.delts.result = presp_delts->command_result;
  2003. PRINTM(MINFO, "TSPEC: DELTS result = %d\n",
  2004. presp_delts->command_result);
  2005. if (presp_delts->command_result == 0) {
  2006. pTspecIE = (IEEEtypes_WMM_TSPEC_t *) presp_delts->tspec_data;
  2007. wlan_send_wmmac_host_event(pmpriv,
  2008. "DELTS_TX",
  2009. MNULL,
  2010. pTspecIE->TspecBody.TSInfo.TID,
  2011. pTspecIE->TspecBody.TSInfo.UserPri,
  2012. presp_delts->ieee_reason_code);
  2013. }
  2014. }
  2015. LEAVE();
  2016. return MLAN_STATUS_SUCCESS;
  2017. }
  2018. /**
  2019. * @brief This function prepares the command of WMM_QUEUE_CONFIG
  2020. *
  2021. * @param pmpriv A pointer to mlan_private structure
  2022. * @param cmd A pointer to HostCmd_DS_COMMAND structure
  2023. * @param pdata_buf A pointer to data buffer
  2024. * @return MLAN_STATUS_SUCCESS
  2025. */
  2026. mlan_status
  2027. wlan_cmd_wmm_queue_config(IN pmlan_private pmpriv,
  2028. OUT HostCmd_DS_COMMAND * cmd, IN t_void * pdata_buf)
  2029. {
  2030. mlan_ds_wmm_queue_config *pqcfg = (mlan_ds_wmm_queue_config *) pdata_buf;
  2031. HostCmd_DS_WMM_QUEUE_CONFIG *pcmd_qcfg = &cmd->params.queue_config;
  2032. ENTER();
  2033. cmd->command = wlan_cpu_to_le16(HostCmd_CMD_WMM_QUEUE_CONFIG);
  2034. cmd->size = wlan_cpu_to_le16(sizeof(pcmd_qcfg->action)
  2035. + sizeof(pcmd_qcfg->access_category)
  2036. + sizeof(pcmd_qcfg->msdu_lifetime_expiry)
  2037. + S_DS_GEN);
  2038. cmd->result = 0;
  2039. pcmd_qcfg->action = pqcfg->action;
  2040. pcmd_qcfg->access_category = pqcfg->access_category;
  2041. pcmd_qcfg->msdu_lifetime_expiry =
  2042. wlan_cpu_to_le16(pqcfg->msdu_lifetime_expiry);
  2043. LEAVE();
  2044. return MLAN_STATUS_SUCCESS;
  2045. }
  2046. /**
  2047. * @brief This function handles the command response of WMM_QUEUE_CONFIG
  2048. *
  2049. * @param pmpriv A pointer to mlan_private structure
  2050. * @param resp A pointer to HostCmd_DS_COMMAND
  2051. * @param pioctl_buf A pointer to mlan_ioctl_req structure
  2052. *
  2053. * @return MLAN_STATUS_SUCCESS
  2054. */
  2055. mlan_status
  2056. wlan_ret_wmm_queue_config(IN pmlan_private pmpriv,
  2057. const IN HostCmd_DS_COMMAND * resp,
  2058. OUT mlan_ioctl_req * pioctl_buf)
  2059. {
  2060. mlan_ds_wmm_cfg *pwmm = MNULL;
  2061. const HostCmd_DS_WMM_QUEUE_CONFIG *presp_qcfg = &resp->params.queue_config;
  2062. ENTER();
  2063. if (pioctl_buf) {
  2064. pwmm = (mlan_ds_wmm_cfg *) pioctl_buf->pbuf;
  2065. pwmm->param.q_cfg.action = presp_qcfg->action;
  2066. pwmm->param.q_cfg.access_category = presp_qcfg->access_category;
  2067. pwmm->param.q_cfg.msdu_lifetime_expiry =
  2068. wlan_le16_to_cpu(presp_qcfg->msdu_lifetime_expiry);
  2069. }
  2070. LEAVE();
  2071. return MLAN_STATUS_SUCCESS;
  2072. }
  2073. /**
  2074. * @brief This function prepares the command of WMM_QUEUE_STATS
  2075. *
  2076. * @param pmpriv A pointer to mlan_private structure
  2077. * @param cmd A pointer to HostCmd_DS_COMMAND structure
  2078. * @param pdata_buf A pointer to data buffer
  2079. * @return MLAN_STATUS_SUCCESS
  2080. */
  2081. mlan_status
  2082. wlan_cmd_wmm_queue_stats(IN pmlan_private pmpriv,
  2083. OUT HostCmd_DS_COMMAND * cmd, IN t_void * pdata_buf)
  2084. {
  2085. mlan_ds_wmm_queue_stats *pqstats = (mlan_ds_wmm_queue_stats *) pdata_buf;
  2086. HostCmd_DS_WMM_QUEUE_STATS *pcmd_qstats = &cmd->params.queue_stats;
  2087. t_u8 id;
  2088. ENTER();
  2089. cmd->command = wlan_cpu_to_le16(HostCmd_CMD_WMM_QUEUE_STATS);
  2090. cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_WMM_QUEUE_STATS)
  2091. + S_DS_GEN);
  2092. cmd->result = 0;
  2093. pcmd_qstats->action = pqstats->action;
  2094. pcmd_qstats->select_is_userpri = 1;
  2095. pcmd_qstats->select_bin = pqstats->user_priority;
  2096. pcmd_qstats->pkt_count = wlan_cpu_to_le16(pqstats->pkt_count);
  2097. pcmd_qstats->pkt_loss = wlan_cpu_to_le16(pqstats->pkt_loss);
  2098. pcmd_qstats->avg_queue_delay = wlan_cpu_to_le32(pqstats->avg_queue_delay);
  2099. pcmd_qstats->avg_tx_delay = wlan_cpu_to_le32(pqstats->avg_tx_delay);
  2100. pcmd_qstats->used_time = wlan_cpu_to_le16(pqstats->used_time);
  2101. pcmd_qstats->policed_time = wlan_cpu_to_le16(pqstats->policed_time);
  2102. for (id = 0; id < MLAN_WMM_STATS_PKTS_HIST_BINS; id++) {
  2103. pcmd_qstats->delay_histogram[id] =
  2104. wlan_cpu_to_le16(pqstats->delay_histogram[id]);
  2105. }
  2106. LEAVE();
  2107. return MLAN_STATUS_SUCCESS;
  2108. }
  2109. /**
  2110. * @brief This function handles the command response of WMM_QUEUE_STATS
  2111. *
  2112. * @param pmpriv A pointer to mlan_private structure
  2113. * @param resp A pointer to HostCmd_DS_COMMAND
  2114. * @param pioctl_buf A pointer to mlan_ioctl_req structure
  2115. *
  2116. * @return MLAN_STATUS_SUCCESS
  2117. */
  2118. mlan_status
  2119. wlan_ret_wmm_queue_stats(IN pmlan_private pmpriv,
  2120. const IN HostCmd_DS_COMMAND * resp,
  2121. OUT mlan_ioctl_req * pioctl_buf)
  2122. {
  2123. mlan_ds_wmm_cfg *pwmm = MNULL;
  2124. mlan_ds_wmm_queue_stats *pqstats = MNULL;
  2125. const HostCmd_DS_WMM_QUEUE_STATS *presp_qstats = &resp->params.queue_stats;
  2126. t_u8 id;
  2127. ENTER();
  2128. if (pioctl_buf) {
  2129. pwmm = (mlan_ds_wmm_cfg *) pioctl_buf->pbuf;
  2130. pqstats = (mlan_ds_wmm_queue_stats *) & pwmm->param.q_stats;
  2131. pqstats->action = presp_qstats->action;
  2132. pqstats->user_priority = presp_qstats->select_bin;
  2133. pqstats->pkt_count = wlan_le16_to_cpu(presp_qstats->pkt_count);
  2134. pqstats->pkt_loss = wlan_le16_to_cpu(presp_qstats->pkt_loss);
  2135. pqstats->avg_queue_delay
  2136. = wlan_le32_to_cpu(presp_qstats->avg_queue_delay);
  2137. pqstats->avg_tx_delay = wlan_le32_to_cpu(presp_qstats->avg_tx_delay);
  2138. pqstats->used_time = wlan_le16_to_cpu(presp_qstats->used_time);
  2139. pqstats->policed_time = wlan_le16_to_cpu(presp_qstats->policed_time);
  2140. for (id = 0; id < MLAN_WMM_STATS_PKTS_HIST_BINS; id++) {
  2141. pqstats->delay_histogram[id]
  2142. = wlan_le16_to_cpu(presp_qstats->delay_histogram[id]);
  2143. }
  2144. }
  2145. LEAVE();
  2146. return MLAN_STATUS_SUCCESS;
  2147. }
  2148. /**
  2149. * @brief This function prepares the command of WMM_TS_STATUS
  2150. *
  2151. * @param pmpriv A pointer to mlan_private structure
  2152. * @param cmd A pointer to HostCmd_DS_COMMAND structure
  2153. * @param pdata_buf A pointer to data buffer
  2154. * @return MLAN_STATUS_SUCCESS
  2155. */
  2156. mlan_status
  2157. wlan_cmd_wmm_ts_status(IN pmlan_private pmpriv,
  2158. OUT HostCmd_DS_COMMAND * cmd, IN t_void * pdata_buf)
  2159. {
  2160. mlan_ds_wmm_ts_status *pts_status = (mlan_ds_wmm_ts_status *) pdata_buf;
  2161. HostCmd_DS_WMM_TS_STATUS *pcmd_ts_status = &cmd->params.ts_status;
  2162. ENTER();
  2163. cmd->command = wlan_cpu_to_le16(HostCmd_CMD_WMM_TS_STATUS);
  2164. cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_WMM_TS_STATUS)
  2165. + S_DS_GEN);
  2166. cmd->result = 0;
  2167. memcpy(pmpriv->adapter, (t_void *) pcmd_ts_status, (t_void *) pts_status,
  2168. sizeof(HostCmd_DS_WMM_TS_STATUS));
  2169. LEAVE();
  2170. return MLAN_STATUS_SUCCESS;
  2171. }
  2172. /**
  2173. * @brief This function handles the command response of WMM_TS_STATUS
  2174. *
  2175. * @param pmpriv A pointer to mlan_private structure
  2176. * @param resp A pointer to HostCmd_DS_COMMAND
  2177. * @param pioctl_buf A pointer to mlan_ioctl_req structure
  2178. *
  2179. * @return MLAN_STATUS_SUCCESS
  2180. */
  2181. mlan_status
  2182. wlan_ret_wmm_ts_status(IN pmlan_private pmpriv,
  2183. IN HostCmd_DS_COMMAND * resp,
  2184. OUT mlan_ioctl_req * pioctl_buf)
  2185. {
  2186. mlan_ds_wmm_cfg *pwmm = MNULL;
  2187. HostCmd_DS_WMM_TS_STATUS *presp_ts_status = &resp->params.ts_status;
  2188. ENTER();
  2189. if (pioctl_buf) {
  2190. pwmm = (mlan_ds_wmm_cfg *) pioctl_buf->pbuf;
  2191. presp_ts_status->medium_time
  2192. = wlan_le16_to_cpu(presp_ts_status->medium_time);
  2193. memcpy(pmpriv->adapter,
  2194. (t_void *) & pwmm->param.ts_status,
  2195. (t_void *) presp_ts_status, sizeof(mlan_ds_wmm_ts_status));
  2196. }
  2197. LEAVE();
  2198. return MLAN_STATUS_SUCCESS;
  2199. }
  2200. #endif /* STA_SUPPORT */