rtl8821c_cmd.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  1. /******************************************************************************
  2. *
  3. * Copyright(c) 2016 - 2017 Realtek Corporation.
  4. *
  5. * This program is free software; you can redistribute it and/or modify it
  6. * under the terms of version 2 of the GNU General Public License as
  7. * published by the Free Software Foundation.
  8. *
  9. * This program is distributed in the hope that it will be useful, but WITHOUT
  10. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  12. * more details.
  13. *
  14. *****************************************************************************/
  15. #define _RTL8821C_CMD_C_
  16. #include <hal_data.h> /* HAL_DATA_TYPE */
  17. #include "../hal_halmac.h" /* HRTW_HALMAC_H2C_MAX_SIZE, CMD_ID_RSVD_PAGE and etc. */
  18. #include "rtl8821c.h"
  19. /*
  20. * Below functions are for C2H
  21. */
  22. /*****************************************
  23. * H2C Msg format :
  24. *| 31 - 8 |7-5 | 4 - 0 |
  25. *| h2c_msg |Class |CMD_ID |
  26. *| 31-0 |
  27. *| Ext msg |
  28. *
  29. ******************************************/
  30. s32 rtl8821c_fillh2ccmd(PADAPTER adapter, u8 id, u32 buf_len, u8 *pbuf)
  31. {
  32. u8 h2c[RTW_HALMAC_H2C_MAX_SIZE] = {0};
  33. #ifdef DBG_H2C_CONTENT
  34. u8 msg[(RTW_HALMAC_H2C_MAX_SIZE - 1) * 5 + 1] = {0};
  35. u8 *msg_p;
  36. u32 msg_size, i, n;
  37. #endif /* CONFIG_RTW_DEBUG */
  38. int err;
  39. s32 ret = _FAIL;
  40. if (!pbuf)
  41. goto exit;
  42. if (buf_len > (RTW_HALMAC_H2C_MAX_SIZE - 1))
  43. goto exit;
  44. if (rtw_is_surprise_removed(adapter))
  45. goto exit;
  46. #ifdef DBG_H2C_CONTENT
  47. msg_p = msg;
  48. msg_size = (RTW_HALMAC_H2C_MAX_SIZE - 1) * 5 + 1;
  49. for (i = 0; i < buf_len; i++) {
  50. n = rtw_sprintf(msg_p, msg_size, " 0x%02x", pbuf[i]);
  51. msg_p += n;
  52. msg_size -= n;
  53. if (msg_size == 0)
  54. break;
  55. }
  56. RTW_INFO(FUNC_ADPT_FMT ": id=0x%02x buf=%s\n",
  57. FUNC_ADPT_ARG(adapter), id, msg);
  58. #endif /* CONFIG_RTW_DEBUG */
  59. h2c[0] = id;
  60. _rtw_memcpy(h2c + 1, pbuf, buf_len);
  61. err = rtw_halmac_send_h2c(adapter_to_dvobj(adapter), h2c);
  62. if (!err)
  63. ret = _SUCCESS;
  64. exit:
  65. return ret;
  66. }
  67. static u8 get_ra_vht_en(u32 wirelessMode, u32 bitmap)
  68. {
  69. u8 ret = 0;
  70. if (wirelessMode == WIRELESS_11_24AC) {
  71. if (bitmap & 0xfff00000) /* 2SS */
  72. ret = 3;
  73. else /* 1SS */
  74. ret = 2;
  75. } else if (wirelessMode == WIRELESS_11_5AC)
  76. ret = 1;
  77. return ret;
  78. }
  79. #define SET_PWR_MODE_SET_BCN_RECEIVING_TIME(h2c_pkt, value) \
  80. SET_BITS_TO_LE_4BYTE(h2c_pkt + 0X04, 24, 5, value)
  81. #define SET_PWR_MODE_SET_ADOPT_BCN_RECEIVING_TIME(h2c_pkt, value) \
  82. SET_BITS_TO_LE_4BYTE(h2c_pkt + 0X04, 31, 1, value)
  83. void rtl8821c_set_FwPwrMode_cmd(PADAPTER adapter, u8 psmode)
  84. {
  85. u8 mode = 0, smart_ps = 0;
  86. struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(adapter);
  87. #ifdef CONFIG_BCN_RECV_TIME
  88. u8 bcn_recv_time;
  89. struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
  90. #endif
  91. #ifdef CONFIG_WMMPS_STA
  92. struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
  93. struct qos_priv *pqospriv = &pmlmepriv->qospriv;
  94. #endif /* CONFIG_WMMPS_STA */
  95. u8 h2c[RTW_HALMAC_H2C_MAX_SIZE] = {0};
  96. u8 PowerState = 0, awake_intvl = 1, rlbm = 0;
  97. u8 allQueueUAPSD = 0;
  98. char *fw_psmode_str = "";
  99. #ifdef CONFIG_P2P
  100. struct wifidirect_info *wdinfo = &adapter->wdinfo;
  101. #endif /* CONFIG_P2P */
  102. u8 hw_port = rtw_hal_get_port(adapter);
  103. if (pwrpriv->dtim > 0)
  104. RTW_INFO(FUNC_ADPT_FMT ": dtim=%d, HW port id=%d\n", FUNC_ADPT_ARG(adapter),
  105. pwrpriv->dtim, psmode == PS_MODE_ACTIVE ? pwrpriv->current_lps_hw_port_id : hw_port);
  106. else
  107. RTW_INFO(FUNC_ADPT_FMT ": HW port id=%d\n", FUNC_ADPT_ARG(adapter),
  108. psmode == PS_MODE_ACTIVE ? pwrpriv->current_lps_hw_port_id : hw_port);
  109. smart_ps = pwrpriv->smart_ps;
  110. switch (psmode) {
  111. case PS_MODE_MIN:
  112. case PS_MODE_MAX:
  113. {
  114. #ifdef CONFIG_WMMPS_STA
  115. if (rtw_is_wmmps_mode(adapter)) {
  116. mode = 2;
  117. smart_ps = pwrpriv->wmm_smart_ps;
  118. /* (WMMPS) allQueueUAPSD: 0: PSPoll, 1: QosNullData (if wmm_smart_ps=1) or do nothing (if wmm_smart_ps=2) */
  119. if ((pqospriv->uapsd_tid & BIT_MASK_TID_TC) == ALL_TID_TC_SUPPORTED_UAPSD)
  120. allQueueUAPSD = 1;
  121. } else
  122. #endif /* CONFIG_WMMPS_STA */
  123. {
  124. mode = 1;
  125. #ifdef CONFIG_WMMPS_STA
  126. /* For WMMPS test case, the station must retain sleep mode to capture buffered data on LPS mechanism */
  127. if ((pqospriv->uapsd_tid & BIT_MASK_TID_TC) != 0)
  128. smart_ps = 0;
  129. else
  130. #endif /* CONFIG_WMMPS_STA */
  131. {
  132. smart_ps = pwrpriv->smart_ps;
  133. }
  134. }
  135. if (psmode == PS_MODE_MIN)
  136. rlbm = 0;
  137. else
  138. rlbm = 1;
  139. }
  140. break;
  141. case PS_MODE_DTIM:
  142. {
  143. mode = 1;
  144. rlbm = 2;
  145. /* For WOWLAN LPS, DTIM = (awake_intvl - 1) */
  146. if (pwrpriv->dtim > 0 && pwrpriv->dtim < 16) /* DTIM = (awake_intvl - 1) */
  147. awake_intvl = pwrpriv->dtim + 1;
  148. else /* DTIM = 3 */
  149. awake_intvl = 4;
  150. }
  151. break;
  152. case PS_MODE_ACTIVE:
  153. default:
  154. mode = 0;
  155. break;
  156. }
  157. #ifdef CONFIG_P2P
  158. if (!rtw_p2p_chk_state(wdinfo, P2P_STATE_NONE)) {
  159. awake_intvl = 2;
  160. rlbm = 1;
  161. }
  162. #endif /* CONFIG_P2P */
  163. if (adapter->registrypriv.wifi_spec == 1) {
  164. awake_intvl = 2;
  165. rlbm = 1;
  166. }
  167. if (psmode > 0) {
  168. #ifdef CONFIG_BT_COEXIST
  169. if (rtw_btcoex_IsBtControlLps(adapter) == _TRUE)
  170. PowerState = rtw_btcoex_RpwmVal(adapter);
  171. else
  172. #endif /* CONFIG_BT_COEXIST */
  173. PowerState = 0x00; /* AllON(0x0C), RFON(0x04), RFOFF(0x00) */
  174. } else
  175. PowerState = 0x0C; /* AllON(0x0C), RFON(0x04), RFOFF(0x00) */
  176. if (mode == 0)
  177. fw_psmode_str = "ACTIVE";
  178. else if (mode == 1)
  179. fw_psmode_str = "LPS";
  180. else if (mode == 2)
  181. fw_psmode_str = "WMMPS";
  182. else
  183. fw_psmode_str = "UNSPECIFIED";
  184. RTW_INFO(FUNC_ADPT_FMT": fw ps mode = %s, drv ps mode = %d, rlbm = %d , smart_ps = %d, allQueueUAPSD = %d\n",
  185. FUNC_ADPT_ARG(adapter), fw_psmode_str, psmode, rlbm, smart_ps, allQueueUAPSD);
  186. SET_PWR_MODE_SET_CMD_ID(h2c, CMD_ID_SET_PWR_MODE);
  187. SET_PWR_MODE_SET_CLASS(h2c, CLASS_SET_PWR_MODE);
  188. SET_PWR_MODE_SET_MODE(h2c, mode);
  189. SET_PWR_MODE_SET_SMART_PS(h2c, smart_ps);
  190. SET_PWR_MODE_SET_RLBM(h2c, rlbm);
  191. SET_PWR_MODE_SET_AWAKE_INTERVAL(h2c, awake_intvl);
  192. SET_PWR_MODE_SET_B_ALL_QUEUE_UAPSD(h2c, allQueueUAPSD);
  193. SET_PWR_MODE_SET_PWR_STATE(h2c, PowerState);
  194. if (psmode == PS_MODE_ACTIVE) {
  195. /* Leave LPS, set the same HW port ID */
  196. SET_PWR_MODE_SET_PORT_ID(h2c, pwrpriv->current_lps_hw_port_id);
  197. } else {
  198. /* Enter LPS, record HW port ID */
  199. SET_PWR_MODE_SET_PORT_ID(h2c, hw_port);
  200. pwrpriv->current_lps_hw_port_id = hw_port;
  201. }
  202. #ifdef CONFIG_BCN_RECV_TIME
  203. if (pmlmeext->bcn_rx_time) {
  204. bcn_recv_time = pmlmeext->bcn_rx_time / 128;
  205. if (pmlmeext->bcn_rx_time % 128)
  206. bcn_recv_time += 1;
  207. if (bcn_recv_time >= 31)
  208. bcn_recv_time = 31;
  209. SET_PWR_MODE_SET_ADOPT_BCN_RECEIVING_TIME(h2c, 1);
  210. SET_PWR_MODE_SET_BCN_RECEIVING_TIME(h2c, bcn_recv_time);
  211. }
  212. #endif
  213. RTW_INFO("%s=> psmode:%02x, smart_ps:%02x, PowerState:%02x\n", __func__, psmode, smart_ps, PowerState);
  214. #ifdef CONFIG_BT_COEXIST
  215. rtw_btcoex_RecordPwrMode(adapter, h2c + 1, RTW_HALMAC_H2C_MAX_SIZE - 1);
  216. #endif /* CONFIG_BT_COEXIST */
  217. RTW_DBG_DUMP("H2C-PwrMode Parm:", h2c, RTW_HALMAC_H2C_MAX_SIZE);
  218. rtw_halmac_send_h2c(adapter_to_dvobj(adapter), h2c);
  219. }
  220. void rtl8821c_set_FwPwrModeInIPS_cmd(PADAPTER adapter, u8 cmd_param)
  221. {
  222. u8 h2c[RTW_HALMAC_H2C_MAX_SIZE] = {0};
  223. INACTIVE_PS_SET_CMD_ID(h2c, CMD_ID_INACTIVE_PS);
  224. INACTIVE_PS_SET_CLASS(h2c, CLASS_INACTIVE_PS);
  225. if (cmd_param & BIT0)
  226. INACTIVE_PS_SET_ENABLE(h2c, 1);
  227. if (cmd_param & BIT1)
  228. INACTIVE_PS_SET_IGNORE_PS_CONDITION(h2c, 1);
  229. RTW_DBG_DUMP("FW_IPS Parm:", h2c, RTW_HALMAC_H2C_MAX_SIZE);
  230. rtw_halmac_send_h2c(adapter_to_dvobj(adapter), h2c);
  231. }
  232. #ifdef CONFIG_BT_COEXIST
  233. void rtl8821c_download_BTCoex_AP_mode_rsvd_page(PADAPTER adapter)
  234. {
  235. rtl8821c_dl_rsvd_page(adapter, RT_MEDIA_CONNECT);
  236. }
  237. #endif /* CONFIG_BT_COEXIST */
  238. /*
  239. * Below functions are for C2H
  240. */
  241. static void c2h_ccx_rpt(PADAPTER adapter, u8 *pdata)
  242. {
  243. #ifdef CONFIG_XMIT_ACK
  244. u8 tx_state;
  245. tx_state = CCX_RPT_GET_TX_STATE(pdata);
  246. /* 0 means success, 1 means retry drop */
  247. if (tx_state == 0)
  248. rtw_ack_tx_done(&adapter->xmitpriv, RTW_SCTX_DONE_SUCCESS);
  249. else
  250. rtw_ack_tx_done(&adapter->xmitpriv, RTW_SCTX_DONE_CCX_PKT_FAIL);
  251. #endif /* CONFIG_XMIT_ACK */
  252. }
  253. #ifdef CONFIG_FW_HANDLE_TXBCN
  254. #define C2H_SUB_CMD_ID_FW_TBTT_RPT 0X23
  255. #define TBTT_RPT_GET_SN(c2h_pkt) LE_BITS_TO_4BYTE(c2h_pkt + 0X01, 0, 8)
  256. #define TBTT_RPT_GET_PORT_ID(c2h_pkt) LE_BITS_TO_4BYTE(c2h_pkt + 0X04, 0, 8)
  257. #define TBTT_ROOT 0x00
  258. #define TBTT_VAP1 0x10
  259. #define TBTT_VAP2 0x20
  260. #define TBTT_VAP3 0x30
  261. static void c2h_tbtt_rpt(PADAPTER adapter, u8 *pdata)
  262. {
  263. u8 ap_id, c2h_sn;
  264. ap_id = TBTT_RPT_GET_PORT_ID(pdata);
  265. c2h_sn = TBTT_RPT_GET_SN(pdata);
  266. #ifdef DBG_FW_TBTT_RPT
  267. if (ap_id == TBTT_ROOT)
  268. RTW_INFO("== TBTT ROOT SN:%d==\n", c2h_sn);
  269. else if (ap_id == TBTT_VAP1)
  270. RTW_INFO("== TBTT_VAP1 SN:%d==\n", c2h_sn);
  271. else if (ap_id == TBTT_VAP2)
  272. RTW_INFO("== TBTT_VAP2 SN:%d==\n", c2h_sn);
  273. else if (ap_id == TBTT_VAP3)
  274. RTW_INFO("== TBTT_VAP3 SN:%d==\n", c2h_sn);
  275. else
  276. RTW_ERR("TBTT RPT INFO ERROR\n");
  277. #endif
  278. }
  279. #endif
  280. /**
  281. * pbuf = RXDESC + c2h packet
  282. * length = RXDESC_SIZE + c2h packet size
  283. * c2h format => ID(1B) | SN(1B) | Payload
  284. * C2H - 0xFF format
  285. * u8 CMD_ID
  286. * u8 CMD_SEQ
  287. * u8 SUB_CMD_ID
  288. * u8 CMD_LEN
  289. * u8 *pContent
  290. */
  291. void c2h_handler_rtl8821c(PADAPTER adapter, u8 *pbuf, u16 length)
  292. {
  293. u8 c2h_id, c2h_sn;
  294. int c2h_len;
  295. u8 *pc2h_hdr;
  296. u8 *pc2h_data;
  297. u8 c2h_sub_cmd_id = 0;
  298. u32 desc_size = 0;
  299. #ifdef CONFIG_WOWLAN
  300. struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(adapter);
  301. #endif /* CONFIG_WOWLAN*/
  302. rtw_halmac_get_rx_desc_size(adapter_to_dvobj(adapter), &desc_size);
  303. #ifdef CONFIG_WOWLAN
  304. if (pwrpriv->wowlan_mode == _TRUE) {
  305. RTW_INFO("%s: return because wowolan_mode==TRUE! CMDID=%d\n",
  306. __FUNCTION__, C2H_GET_CMD_ID(pbuf + desc_size));
  307. return;
  308. }
  309. #endif /* CONFIG_WOWLAN*/
  310. if (pbuf == NULL)
  311. return;
  312. if (length < desc_size) {
  313. RTW_INFO("%s: [ERROR] c2h length(%d) is smaller than RXDESC_SIZE(%d)!!\n",
  314. __func__, length, desc_size);
  315. return;
  316. }
  317. pc2h_hdr = pbuf + desc_size;
  318. pc2h_data = pbuf + desc_size + 2; /* cmd ID not 0xFF original C2H have 2 bytes C2H header */
  319. c2h_id = C2H_GET_CMD_ID(pc2h_hdr);
  320. c2h_sn = C2H_GET_SEQ(pc2h_hdr);
  321. c2h_len = length - desc_size - 2;
  322. if ((c2h_len < 0) || (c2h_len > C2H_DBG_CONTENT_MAX_LENGTH)) {
  323. RTW_ERR("%s: [ERROR] C2H_ID(%02x) C2H_SN(%d) warn c2h_len :%d (length:%d)\n", __func__, c2h_id, c2h_sn, c2h_len, length);
  324. rtw_warn_on(1);
  325. }
  326. #ifdef DBG_C2H_CONTENT
  327. RTW_INFO("%s "ADPT_FMT" C2H, ID=%d seq=%d len=%d\n", __func__, ADPT_ARG(adapter), c2h_id, c2h_sn, length);
  328. #endif
  329. switch (c2h_id) {
  330. case CMD_ID_C2H_SND_TXBF:
  331. /*C2HTxBeamformingHandler_8821C(adapter, pc2h_data, c2h_len);*/
  332. break;
  333. /* FW offload C2H is 0xFF cmd according to halmac function - halmac_parse_c2h_packet */
  334. case 0xFF:
  335. /* Get C2H sub cmd ID */
  336. c2h_sub_cmd_id = (u8)C2H_HDR_GET_C2H_SUB_CMD_ID(pc2h_hdr);
  337. if (c2h_sub_cmd_id == C2H_SUB_CMD_ID_CCX_RPT)
  338. c2h_ccx_rpt(adapter, pbuf + desc_size);
  339. #ifdef CONFIG_FW_HANDLE_TXBCN
  340. else if (c2h_sub_cmd_id == C2H_SUB_CMD_ID_FW_TBTT_RPT)
  341. c2h_tbtt_rpt(adapter, pbuf + desc_size);
  342. #endif
  343. else
  344. /* indicate rx desc + c2h pkt to halmac */
  345. if (rtw_halmac_c2h_handle(adapter_to_dvobj(adapter), pbuf, length) == -1)
  346. RTW_ERR("%s "ADPT_FMT" C2H, ID=%d, SubID=%d seq=%d len=%d ,HALMAC not to handle\n",
  347. __func__, ADPT_ARG(adapter), c2h_id, c2h_sub_cmd_id, c2h_sn, length);
  348. break;
  349. /* others for c2h common code */
  350. default:
  351. /* shift 2 byte to remove cmd id & seq */
  352. c2h_handler(adapter, c2h_id, c2h_sn, c2h_len, pc2h_data);
  353. break;
  354. }
  355. }
  356. static inline u8 is_c2h_id_handle_directly(u8 c2h_id, u8 c2h_sub_cmd_id)
  357. {
  358. switch (c2h_id) {
  359. case CMD_ID_C2H_CCX_RPT:
  360. case C2H_IQK_FINISH:
  361. case C2H_EXTEND:
  362. #if defined(CONFIG_TDLS) && defined(CONFIG_TDLS_CH_SW)
  363. case C2H_BCN_EARLY_RPT:
  364. case C2H_FW_CHNL_SWITCH_COMPLETE:
  365. #endif
  366. #ifdef CONFIG_BT_COEXIST
  367. case C2H_BT_MP_INFO:
  368. #endif
  369. #ifdef CONFIG_MCC_MODE
  370. case C2H_MCC:
  371. #endif
  372. return _TRUE;
  373. default:
  374. return _FALSE;
  375. }
  376. }
  377. /*
  378. * pbuf = RXDESC + c2h packet
  379. * length = RXDESC_SIZE + c2h packet size
  380. */
  381. void c2h_pre_handler_rtl8821c(_adapter *adapter, u8 *pbuf, s32 length)
  382. {
  383. u8 c2h_id;
  384. u8 c2h_sub_cmd_id = 0;
  385. u32 desc_size = 0;
  386. if ((length <= 0) || (!pbuf))
  387. return;
  388. rtw_halmac_get_rx_desc_size(adapter_to_dvobj(adapter), &desc_size);
  389. c2h_id = C2H_GET_CMD_ID(pbuf + desc_size);
  390. /* Get C2H sub cmd ID */
  391. if (c2h_id == 0xFF)
  392. c2h_sub_cmd_id = (u8)C2H_HDR_GET_C2H_SUB_CMD_ID(pbuf + desc_size);
  393. if (is_c2h_id_handle_directly(c2h_id, c2h_sub_cmd_id))
  394. c2h_handler_rtl8821c(adapter, pbuf, length);
  395. else
  396. rtw_c2h_packet_wk_cmd(adapter, pbuf, length);
  397. }