rtl8821ce_ops.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834
  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 _HCI_OPS_OS_C_
  16. #include <drv_types.h> /* PADAPTER, basic_types.h and etc. */
  17. #include <hal_data.h> /* HAL_DATA_TYPE, GET_HAL_DATA() and etc. */
  18. #include <hal_intf.h> /* struct hal_ops */
  19. #include "../rtl8821c.h"
  20. #include "rtl8821ce.h"
  21. static void init_bd_ring_var(_adapter *padapter)
  22. {
  23. struct recv_priv *r_priv = &padapter->recvpriv;
  24. struct xmit_priv *t_priv = &padapter->xmitpriv;
  25. u8 i = 0;
  26. for (i = 0; i < HW_QUEUE_ENTRY; i++)
  27. t_priv->txringcount[i] = TX_BD_NUM_8821CE;
  28. /*
  29. * we just alloc 2 desc for beacon queue,
  30. * because we just need first desc in hw beacon.
  31. */
  32. t_priv->txringcount[BCN_QUEUE_INX] = TX_BD_NUM_8821CE_BCN;
  33. t_priv->txringcount[TXCMD_QUEUE_INX] = TX_BD_NUM_8821CE_CMD;
  34. /*
  35. * BE queue need more descriptor for performance consideration
  36. * or, No more tx desc will happen, and may cause mac80211 mem leakage.
  37. */
  38. r_priv->rxbuffersize = MAX_RECVBUF_SZ;
  39. r_priv->rxringcount = PCI_MAX_RX_COUNT;
  40. }
  41. static void rtl8821ce_reset_bd(_adapter *padapter)
  42. {
  43. _irqL irqL;
  44. struct xmit_priv *t_priv = &padapter->xmitpriv;
  45. struct recv_priv *r_priv = &padapter->recvpriv;
  46. struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
  47. struct xmit_buf *pxmitbuf = NULL;
  48. u8 *tx_bd, *rx_bd;
  49. int i, rx_queue_idx;
  50. dma_addr_t mapping;
  51. for (rx_queue_idx = 0; rx_queue_idx < 1; rx_queue_idx++) {
  52. if (r_priv->rx_ring[rx_queue_idx].buf_desc) {
  53. rx_bd = NULL;
  54. for (i = 0; i < r_priv->rxringcount; i++) {
  55. rx_bd = (u8 *)
  56. &r_priv->rx_ring[rx_queue_idx].buf_desc[i];
  57. }
  58. r_priv->rx_ring[rx_queue_idx].idx = 0;
  59. }
  60. }
  61. _enter_critical(&pdvobjpriv->irq_th_lock, &irqL);
  62. for (i = 0; i < PCI_MAX_TX_QUEUE_COUNT; i++) {
  63. if (t_priv->tx_ring[i].buf_desc) {
  64. struct rtw_tx_ring *ring = &t_priv->tx_ring[i];
  65. while (ring->qlen) {
  66. tx_bd = (u8 *)(&ring->buf_desc[ring->idx]);
  67. SET_TX_BD_OWN(tx_bd, 0);
  68. if (i != BCN_QUEUE_INX)
  69. ring->idx =
  70. (ring->idx + 1) % ring->entries;
  71. pxmitbuf = rtl8821ce_dequeue_xmitbuf(ring);
  72. if (pxmitbuf) {
  73. mapping = GET_TX_BD_PHYSICAL_ADDR0_LOW(tx_bd);
  74. #ifdef CONFIG_64BIT_DMA
  75. mapping |= (dma_addr_t)GET_TX_BD_PHYSICAL_ADDR0_HIGH(tx_bd) << 32;
  76. #endif
  77. pci_unmap_single(pdvobjpriv->ppcidev,
  78. mapping,
  79. pxmitbuf->len, PCI_DMA_TODEVICE);
  80. rtw_free_xmitbuf(t_priv, pxmitbuf);
  81. } else {
  82. RTW_INFO("%s(): qlen(%d) is not zero, but have xmitbuf in pending queue\n",
  83. __func__, ring->qlen);
  84. break;
  85. }
  86. }
  87. ring->idx = 0;
  88. }
  89. }
  90. _exit_critical(&pdvobjpriv->irq_th_lock, &irqL);
  91. }
  92. static void intf_chip_configure(PADAPTER padapter)
  93. {
  94. HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
  95. struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
  96. struct pwrctrl_priv *pwrpriv = dvobj_to_pwrctl(pdvobjpriv);
  97. /* close ASPM for AMD defaultly */
  98. pdvobjpriv->const_amdpci_aspm = 0;
  99. /* ASPM PS mode. */
  100. /* 0 - Disable ASPM, 1 - Enable ASPM without Clock Req, */
  101. /* 2 - Enable ASPM with Clock Req, 3- Alwyas Enable ASPM with Clock Req, */
  102. /* 4- Always Enable ASPM without Clock Req. */
  103. /* set default to rtl8188ee:3 RTL8192E:2 */
  104. pdvobjpriv->const_pci_aspm = 0;
  105. /* Setting for PCI-E device */
  106. pdvobjpriv->const_devicepci_aspm_setting = 0x03;
  107. /* Setting for PCI-E bridge */
  108. pdvobjpriv->const_hostpci_aspm_setting = 0x03;
  109. /* In Hw/Sw Radio Off situation. */
  110. /* 0 - Default, 1 - From ASPM setting without low Mac Pwr, */
  111. /* 2 - From ASPM setting with low Mac Pwr, 3 - Bus D3 */
  112. /* set default to RTL8192CE:0 RTL8192SE:2 */
  113. pdvobjpriv->const_hwsw_rfoff_d3 = 0;
  114. /* This setting works for those device with backdoor ASPM setting such as EPHY setting. */
  115. /* 0: Not support ASPM, 1: Support ASPM, 2: According to chipset. */
  116. pdvobjpriv->const_support_pciaspm = 1;
  117. pwrpriv->reg_rfoff = 0;
  118. pwrpriv->rfoff_reason = 0;
  119. pHalData->bL1OffSupport = _FALSE;
  120. }
  121. /*
  122. * Description:
  123. * Collect all hardware information, fill "HAL_DATA_TYPE".
  124. * Sometimes this would be used to read MAC address.
  125. * This function will do
  126. * 1. Read Efuse/EEPROM to initialize
  127. * 2. Read registers to initialize
  128. * 3. Other vaiables initialization
  129. */
  130. static u8 read_adapter_info(PADAPTER padapter)
  131. {
  132. u8 ret = _FAIL;
  133. /*
  134. * 1. Read Efuse/EEPROM to initialize
  135. */
  136. if (rtl8821c_read_efuse(padapter) != _SUCCESS)
  137. goto exit;
  138. /*
  139. * 2. Read registers to initialize
  140. */
  141. /*
  142. * 3. Other Initialization
  143. */
  144. ret = _SUCCESS;
  145. exit:
  146. return ret;
  147. }
  148. static BOOLEAN rtl8821ce_InterruptRecognized(PADAPTER Adapter)
  149. {
  150. HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter);
  151. BOOLEAN bRecognized = _FALSE;
  152. /* 2013.11.18 Glayrainx suggests that turn off IMR and
  153. * restore after cleaning ISR.
  154. */
  155. rtw_write32(Adapter, REG_HIMR0, 0);
  156. rtw_write32(Adapter, REG_HIMR1, 0);
  157. rtw_write32(Adapter, REG_HIMR3, 0);
  158. pHalData->IntArray[0] = rtw_read32(Adapter, REG_HISR0);
  159. pHalData->IntArray[0] &= pHalData->IntrMask[0];
  160. rtw_write32(Adapter, REG_HISR0, pHalData->IntArray[0]);
  161. /* For HISR extension. Added by tynli. 2009.10.07. */
  162. pHalData->IntArray[1] = rtw_read32(Adapter, REG_HISR1);
  163. pHalData->IntArray[1] &= pHalData->IntrMask[1];
  164. rtw_write32(Adapter, REG_HISR1, pHalData->IntArray[1]);
  165. /* for H2C cmd queue */
  166. pHalData->IntArray[3] = rtw_read32(Adapter, REG_HISR3);
  167. pHalData->IntArray[3] &= pHalData->IntrMask[3];
  168. rtw_write32(Adapter, REG_HISR3, pHalData->IntArray[3]);
  169. if (((pHalData->IntArray[0]) & pHalData->IntrMask[0]) != 0 ||
  170. ((pHalData->IntArray[1]) & pHalData->IntrMask[1]) != 0)
  171. bRecognized = _TRUE;
  172. /* restore IMR */
  173. rtw_write32(Adapter, REG_HIMR0, pHalData->IntrMask[0] & 0xFFFFFFFF);
  174. rtw_write32(Adapter, REG_HIMR1, pHalData->IntrMask[1] & 0xFFFFFFFF);
  175. rtw_write32(Adapter, REG_HIMR3, pHalData->IntrMask[3] & 0xFFFFFFFF);
  176. return bRecognized;
  177. }
  178. static VOID DisableInterrupt8821ce(PADAPTER Adapter)
  179. {
  180. struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(Adapter);
  181. rtw_write32(Adapter, REG_HIMR0, 0x0);
  182. rtw_write32(Adapter, REG_HIMR1, 0x0);
  183. rtw_write32(Adapter, REG_HIMR3, 0x0);
  184. pdvobjpriv->irq_enabled = 0;
  185. }
  186. static VOID rtl8821ce_enable_interrupt(PADAPTER Adapter)
  187. {
  188. HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter);
  189. struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(Adapter);
  190. pdvobjpriv->irq_enabled = 1;
  191. rtw_write32(Adapter, REG_HIMR0, pHalData->IntrMask[0] & 0xFFFFFFFF);
  192. rtw_write32(Adapter, REG_HIMR1, pHalData->IntrMask[1] & 0xFFFFFFFF);
  193. rtw_write32(Adapter, REG_HIMR3, pHalData->IntrMask[3] & 0xFFFFFFFF);
  194. }
  195. static VOID rtl8821ce_clear_interrupt(PADAPTER Adapter)
  196. {
  197. u32 u32b;
  198. HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter);
  199. u32b = rtw_read32(Adapter, REG_HISR0_8821C);
  200. rtw_write32(Adapter, REG_HISR0_8821C, u32b);
  201. pHalData->IntArray[0] = 0;
  202. u32b = rtw_read32(Adapter, REG_HISR1_8821C);
  203. rtw_write32(Adapter, REG_HISR1_8821C, u32b);
  204. pHalData->IntArray[1] = 0;
  205. }
  206. static VOID rtl8821ce_disable_interrupt(PADAPTER Adapter)
  207. {
  208. struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(Adapter);
  209. rtw_write32(Adapter, REG_HIMR0, 0x0);
  210. rtw_write32(Adapter, REG_HIMR1, 0x0); /* by tynli */
  211. pdvobjpriv->irq_enabled = 0;
  212. }
  213. VOID UpdateInterruptMask8821CE(PADAPTER Adapter, u32 AddMSR, u32 AddMSR1,
  214. u32 RemoveMSR, u32 RemoveMSR1)
  215. {
  216. PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter);
  217. DisableInterrupt8821ce(Adapter);
  218. if (AddMSR)
  219. pHalData->IntrMask[0] |= AddMSR;
  220. if (AddMSR1)
  221. pHalData->IntrMask[1] |= AddMSR1;
  222. if (RemoveMSR)
  223. pHalData->IntrMask[0] &= (~RemoveMSR);
  224. if (RemoveMSR1)
  225. pHalData->IntrMask[1] &= (~RemoveMSR1);
  226. #if 0 /* TODO */
  227. if (RemoveMSR3)
  228. pHalData->IntrMask[3] &= (~RemoveMSR3);
  229. #endif
  230. rtl8821ce_enable_interrupt(Adapter);
  231. }
  232. static void rtl8821ce_bcn_handler(PADAPTER Adapter, u32 handled[])
  233. {
  234. PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter);
  235. if (pHalData->IntArray[0] & BIT_TXBCN0OK_MSK) {
  236. #ifdef CONFIG_BCN_ICF
  237. /* do nothing */
  238. #else
  239. /* Modify for MI temporary,
  240. * this processor cannot apply to multi-ap
  241. */
  242. PADAPTER bcn_adapter = rtw_mi_get_ap_adapter(Adapter);
  243. if (bcn_adapter->xmitpriv.beaconDMAing) {
  244. bcn_adapter->xmitpriv.beaconDMAing = _FAIL;
  245. rtl8821ce_tx_isr(Adapter, BCN_QUEUE_INX);
  246. }
  247. #endif /* CONFIG_BCN_ICF */
  248. handled[0] |= BIT_TXBCN0OK_MSK;
  249. }
  250. if (pHalData->IntArray[0] & BIT_TXBCN0ERR_MSK) {
  251. #ifdef CONFIG_BCN_ICF
  252. RTW_INFO("IMR_TXBCN0ERR isr!\n");
  253. #else /* !CONFIG_BCN_ICF */
  254. /* Modify for MI temporary,
  255. * this processor cannot apply to multi-ap
  256. */
  257. PADAPTER bcn_adapter = rtw_mi_get_ap_adapter(Adapter);
  258. if (bcn_adapter->xmitpriv.beaconDMAing) {
  259. bcn_adapter->xmitpriv.beaconDMAing = _FAIL;
  260. rtl8821ce_tx_isr(Adapter, BCN_QUEUE_INX);
  261. }
  262. #endif /* CONFIG_BCN_ICF */
  263. handled[0] |= BIT_TXBCN0ERR_MSK;
  264. }
  265. if (pHalData->IntArray[0] & BIT_BCNDERR0_MSK) {
  266. #ifdef CONFIG_BCN_ICF
  267. RTW_INFO("BIT_BCNDERR0_MSK isr!\n");
  268. #else /* !CONFIG_BCN_ICF */
  269. /* Release resource and re-transmit beacon to HW */
  270. struct tasklet_struct *bcn_tasklet;
  271. /* Modify for MI temporary,
  272. * this processor cannot apply to multi-ap
  273. */
  274. PADAPTER bcn_adapter = rtw_mi_get_ap_adapter(Adapter);
  275. rtl8821ce_tx_isr(Adapter, BCN_QUEUE_INX);
  276. bcn_adapter->mlmepriv.update_bcn = _TRUE;
  277. bcn_tasklet = &bcn_adapter->recvpriv.irq_prepare_beacon_tasklet;
  278. tasklet_hi_schedule(bcn_tasklet);
  279. #endif /* CONFIG_BCN_ICF */
  280. handled[0] |= BIT_BCNDERR0_MSK;
  281. }
  282. if (pHalData->IntArray[0] & BIT_BCNDMAINT0_MSK) {
  283. struct tasklet_struct *bcn_tasklet;
  284. /* Modify for MI temporary,
  285. * this processor cannot apply to multi-ap
  286. */
  287. PADAPTER bcn_adapter = rtw_mi_get_ap_adapter(Adapter);
  288. bcn_tasklet = &bcn_adapter->recvpriv.irq_prepare_beacon_tasklet;
  289. tasklet_hi_schedule(bcn_tasklet);
  290. handled[0] |= BIT_BCNDMAINT0_MSK;
  291. }
  292. }
  293. static void rtl8821ce_rx_handler(PADAPTER Adapter, u32 handled[])
  294. {
  295. PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter);
  296. if ((pHalData->IntArray[0] & (BIT_RXOK | BIT_RDU)) ||
  297. (pHalData->IntArray[1] & (BIT_FOVW | BIT_RXERR_INT))) {
  298. pHalData->IntrMask[0] &= (~(BIT_RXOK_MSK | BIT_RDU_MSK));
  299. pHalData->IntrMask[1] &= (~(BIT_FOVW_MSK | BIT_RXERR_MSK));
  300. rtw_write32(Adapter, REG_HIMR0, pHalData->IntrMask[0]);
  301. rtw_write32(Adapter, REG_HIMR1, pHalData->IntrMask[1]);
  302. tasklet_hi_schedule(&Adapter->recvpriv.recv_tasklet);
  303. handled[0] |= pHalData->IntArray[0] & (BIT_RXOK | BIT_RDU);
  304. handled[1] |= pHalData->IntArray[1] & (BIT_FOVW | BIT_RXERR_INT);
  305. }
  306. }
  307. static void rtl8821ce_tx_handler(PADAPTER Adapter, u32 events[], u32 handled[])
  308. {
  309. PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter);
  310. if (events[0] & BIT_MGTDOK_MSK) {
  311. rtl8821ce_tx_isr(Adapter, MGT_QUEUE_INX);
  312. handled[0] |= BIT_MGTDOK_MSK;
  313. }
  314. if (events[0] & BIT_HIGHDOK_MSK) {
  315. rtl8821ce_tx_isr(Adapter, HIGH_QUEUE_INX);
  316. handled[0] |= BIT_HIGHDOK_MSK;
  317. }
  318. if (events[0] & BIT_BKDOK_MSK) {
  319. rtl8821ce_tx_isr(Adapter, BK_QUEUE_INX);
  320. handled[0] |= BIT_BKDOK_MSK;
  321. }
  322. if (events[0] & BIT_BEDOK_MSK) {
  323. rtl8821ce_tx_isr(Adapter, BE_QUEUE_INX);
  324. handled[0] |= BIT_BEDOK_MSK;
  325. }
  326. if (events[0] & BIT_VIDOK_MSK) {
  327. rtl8821ce_tx_isr(Adapter, VI_QUEUE_INX);
  328. handled[0] |= BIT_VIDOK_MSK;
  329. }
  330. if (events[0] & BIT_VODOK_MSK) {
  331. rtl8821ce_tx_isr(Adapter, VO_QUEUE_INX);
  332. handled[0] |= BIT_VODOK_MSK;
  333. }
  334. }
  335. static void rtl8821ce_cmd_handler(PADAPTER Adapter, u32 handled[])
  336. {
  337. PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter);
  338. if (pHalData->IntArray[3] & BIT_SETH2CDOK_MASK) {
  339. rtl8821ce_tx_isr(Adapter, TXCMD_QUEUE_INX);
  340. handled[3] |= BIT_SETH2CDOK_MASK;
  341. }
  342. }
  343. static s32 rtl8821ce_interrupt(PADAPTER Adapter)
  344. {
  345. _irqL irqL;
  346. HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter);
  347. struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(Adapter);
  348. struct xmit_priv *t_priv = &Adapter->xmitpriv;
  349. int ret = _SUCCESS;
  350. u32 handled[4] = {0};
  351. _enter_critical(&pdvobjpriv->irq_th_lock, &irqL);
  352. /* read ISR: 4/8bytes */
  353. if (rtl8821ce_InterruptRecognized(Adapter) == _FALSE) {
  354. ret = _FAIL;
  355. goto done;
  356. }
  357. /* <1> beacon related */
  358. rtl8821ce_bcn_handler(Adapter, handled);
  359. /* <2> Rx related */
  360. rtl8821ce_rx_handler(Adapter, handled);
  361. /* <3> Tx related */
  362. rtl8821ce_tx_handler(Adapter, pHalData->IntArray, handled);
  363. if (pHalData->IntArray[1] & BIT_TXFOVW) {
  364. /*if (printk_ratelimit())*/
  365. RTW_WARN("[TXFOVW]\n");
  366. handled[1] |= BIT_TXFOVW;
  367. }
  368. if (pHalData->IntArray[1] & BIT_PRETXERR_HANDLE_ISR) {
  369. RTW_ERR("[PRE-TX HANG]\n");
  370. handled[1] |= BIT_PRETXERR_HANDLE_ISR;
  371. }
  372. /* <4> Cmd related */
  373. rtl8821ce_cmd_handler(Adapter, handled);
  374. #ifdef CONFIG_LPS_LCLK
  375. if (pHalData->IntArray[0] & BIT_CPWM) {
  376. struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(Adapter);
  377. _set_workitem(&(pwrpriv->cpwm_event));
  378. handled[0] |= BIT_CPWM;
  379. }
  380. #endif
  381. if ((pHalData->IntArray[0] & (~handled[0])) || (pHalData->IntArray[1] & (~handled[1])) || (pHalData->IntArray[3] & (~handled[3]))) {
  382. /*if (printk_ratelimit()) */
  383. {
  384. RTW_WARN("Unhandled ISR = %x, %x, %x\n",
  385. (pHalData->IntArray[0] & (~handled[0])),
  386. (pHalData->IntArray[1] & (~handled[1])),
  387. (pHalData->IntArray[3] & (~handled[3]))
  388. );
  389. }
  390. }
  391. done:
  392. _exit_critical(&pdvobjpriv->irq_th_lock, &irqL);
  393. return ret;
  394. }
  395. u32 rtl8821ce_init_bd(_adapter *padapter)
  396. {
  397. struct xmit_priv *t_priv = &padapter->xmitpriv;
  398. int i, ret = _SUCCESS;
  399. init_bd_ring_var(padapter);
  400. ret = rtl8821ce_init_rxbd_ring(padapter);
  401. if (ret == _FAIL)
  402. return ret;
  403. /* general process for other queue */
  404. for (i = 0; i < PCI_MAX_TX_QUEUE_COUNT; i++) {
  405. ret = rtl8821ce_init_txbd_ring(padapter, i,
  406. t_priv->txringcount[i]);
  407. if (ret == _FAIL)
  408. goto err_free_rings;
  409. }
  410. return ret;
  411. err_free_rings:
  412. rtl8821ce_free_rxbd_ring(padapter);
  413. for (i = 0; i < PCI_MAX_TX_QUEUE_COUNT; i++)
  414. if (t_priv->tx_ring[i].buf_desc)
  415. rtl8821ce_free_txbd_ring(padapter, i);
  416. return ret;
  417. }
  418. u32 rtl8821ce_free_bd(_adapter *padapter)
  419. {
  420. struct xmit_priv *t_priv = &padapter->xmitpriv;
  421. u32 i;
  422. /* free rxbd rings */
  423. rtl8821ce_free_rxbd_ring(padapter);
  424. /* free txbd rings */
  425. for (i = 0; i < HW_QUEUE_ENTRY; i++)
  426. rtl8821ce_free_txbd_ring(padapter, i);
  427. return _SUCCESS;
  428. }
  429. static u16
  430. hal_mdio_read_8821ce(PADAPTER Adapter, u8 Addr)
  431. {
  432. u2Byte ret = 0;
  433. u1Byte tmpU1b = 0, count = 0;
  434. rtw_write8(Adapter, REG_PCIE_MIX_CFG_8821C, Addr | BIT6);
  435. tmpU1b = rtw_read8(Adapter, REG_PCIE_MIX_CFG_8821C) & BIT6;
  436. count = 0;
  437. while (tmpU1b && count < 20) {
  438. rtw_udelay_os(10);
  439. tmpU1b = rtw_read8(Adapter, REG_PCIE_MIX_CFG_8821C) & BIT6;
  440. count++;
  441. }
  442. if (tmpU1b == 0)
  443. ret = rtw_read16(Adapter, REG_MDIO_V1_8821C);
  444. return ret;
  445. }
  446. static VOID
  447. hal_mdio_write_8821ce(PADAPTER Adapter, u8 Addr, u16 Data)
  448. {
  449. u1Byte tmpU1b = 0, count = 0;
  450. rtw_write16(Adapter, REG_MDIO_V1_8821C, Data);
  451. rtw_write8(Adapter, REG_PCIE_MIX_CFG_8821C, Addr | BIT5);
  452. tmpU1b = rtw_read8(Adapter, REG_PCIE_MIX_CFG_8821C) & BIT5;
  453. count = 0;
  454. while (tmpU1b && count < 20) {
  455. rtw_udelay_os(10);
  456. tmpU1b = rtw_read8(Adapter, REG_PCIE_MIX_CFG_8821C) & BIT5;
  457. count++;
  458. }
  459. }
  460. static void hal_dbi_write_8821ce(PADAPTER Adapter, u16 Addr, u8 Data)
  461. {
  462. u1Byte tmpU1b = 0, count = 0;
  463. u2Byte WriteAddr = 0, Remainder = Addr % 4;
  464. /* Write DBI 1Byte Data */
  465. WriteAddr = REG_DBI_WDATA_V1_8821C + Remainder;
  466. rtw_write8(Adapter, WriteAddr, Data);
  467. /* Write DBI 2Byte Address & Write Enable */
  468. WriteAddr = (Addr & 0xfffc) | (BIT0 << (Remainder + 12));
  469. rtw_write16(Adapter, REG_DBI_FLAG_V1_8821C, WriteAddr);
  470. /* Write DBI Write Flag */
  471. rtw_write8(Adapter, REG_DBI_FLAG_V1_8821C + 2, 0x1);
  472. tmpU1b = rtw_read8(Adapter, REG_DBI_FLAG_V1_8821C + 2);
  473. count = 0;
  474. while (tmpU1b && count < 20) {
  475. rtw_udelay_os(10);
  476. tmpU1b = rtw_read8(Adapter, REG_DBI_FLAG_V1_8821C + 2);
  477. count++;
  478. }
  479. }
  480. static u8 hal_dbi_read_8821ce(PADAPTER Adapter, u16 Addr)
  481. {
  482. u16 ReadAddr = Addr & 0xfffc;
  483. u8 ret = 0, tmpU1b = 0, count = 0;
  484. rtw_write16(Adapter, REG_DBI_FLAG_V1_8821C, ReadAddr);
  485. rtw_write8(Adapter, REG_DBI_FLAG_V1_8821C + 2, 0x2);
  486. tmpU1b = rtw_read8(Adapter, REG_DBI_FLAG_V1_8821C + 2);
  487. count = 0;
  488. while (tmpU1b && count < 20) {
  489. rtw_udelay_os(10);
  490. tmpU1b = rtw_read8(Adapter, REG_DBI_FLAG_V1_8821C + 2);
  491. count++;
  492. }
  493. if (tmpU1b == 0) {
  494. ReadAddr = REG_DBI_RDATA_V1_8821C + Addr % 4;
  495. ret = rtw_read8(Adapter, ReadAddr);
  496. }
  497. return ret;
  498. }
  499. /*
  500. * Description:
  501. * Query setting of specified variable.
  502. */
  503. static u8 gethaldefvar(PADAPTER padapter, HAL_DEF_VARIABLE eVariable, PVOID pValue)
  504. {
  505. HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
  506. u8 bResult = _SUCCESS;
  507. switch (eVariable) {
  508. case HAL_DEF_MAX_RECVBUF_SZ:
  509. *((u32 *)pValue) = MAX_RECVBUF_SZ;
  510. break;
  511. case HW_VAR_MAX_RX_AMPDU_FACTOR:
  512. *(HT_CAP_AMPDU_FACTOR *)pValue = MAX_AMPDU_FACTOR_64K;
  513. break;
  514. default:
  515. bResult = rtl8821c_gethaldefvar(padapter, eVariable, pValue);
  516. break;
  517. }
  518. return bResult;
  519. }
  520. /*
  521. * Description:
  522. * Change default setting of specified variable.
  523. */
  524. static u8 sethaldefvar(PADAPTER adapter, HAL_DEF_VARIABLE eVariable, void *pval)
  525. {
  526. PHAL_DATA_TYPE hal = GET_HAL_DATA(adapter);
  527. u8 bResult = _SUCCESS;
  528. switch (eVariable) {
  529. default:
  530. bResult = rtl8821c_sethaldefvar(adapter, eVariable, pval);
  531. break;
  532. }
  533. return bResult;
  534. }
  535. /*
  536. * If variable not handled here,
  537. * some variables will be processed in rtl8821c_sethwreg()
  538. */
  539. static u8 sethwreg(PADAPTER adapter, u8 variable, u8 *val)
  540. {
  541. PHAL_DATA_TYPE hal;
  542. u8 ret = _SUCCESS;
  543. u8 val8;
  544. hal = GET_HAL_DATA(adapter);
  545. switch (variable) {
  546. case HW_VAR_DBI:
  547. {
  548. u16 *pCmd;
  549. pCmd = (u16 *)val;
  550. hal_dbi_write_8821ce(adapter, pCmd[0], (u8)pCmd[1]);
  551. break;
  552. }
  553. case HW_VAR_MDIO:
  554. {
  555. u16 *pCmd;
  556. pCmd = (u16 *)val;
  557. hal_mdio_write_8821ce(adapter, (u8)pCmd[0], pCmd[1]);
  558. break;
  559. }
  560. #ifdef CONFIG_LPS_LCLK
  561. case HW_VAR_SET_RPWM:
  562. {
  563. u8 ps_state = *((u8 *)val);
  564. /* rpwm value only use BIT0(clock bit) ,BIT6(Ack bit), and BIT7(Toggle bit) for 88e. */
  565. /* BIT0 value - 1: 32k, 0:40MHz. */
  566. /* BIT6 value - 1: report cpwm value after success set, 0:do not report. */
  567. /* BIT7 value - Toggle bit change. */
  568. /* modify by Thomas. 2012/4/2. */
  569. ps_state = ps_state & 0xC1;
  570. /* RTW_INFO("##### Change RPWM value to = %x for switch clk #####\n",ps_state); */
  571. rtw_write8(adapter, REG_PCIE_HRPWM1_V1_8821C, ps_state);
  572. break;
  573. }
  574. #endif
  575. default:
  576. ret = rtl8821c_sethwreg(adapter, variable, val);
  577. break;
  578. }
  579. return ret;
  580. }
  581. /*
  582. * If variable not handled here,
  583. * some variables will be processed in GetHwReg8723B()
  584. */
  585. static void gethwreg(PADAPTER adapter, u8 variable, u8 *val)
  586. {
  587. PHAL_DATA_TYPE hal;
  588. hal = GET_HAL_DATA(adapter);
  589. switch (variable) {
  590. case HW_VAR_DBI:
  591. *val = hal_dbi_read_8821ce(adapter, *((u16 *)(val)));
  592. break;
  593. case HW_VAR_MDIO:
  594. *((u16 *)(val)) = hal_mdio_read_8821ce(adapter, *val);
  595. break;
  596. case HW_VAR_L1OFF_NIC_SUPPORT:
  597. {
  598. u8 l1off;
  599. l1off = hal_dbi_read_8821ce(adapter, 0x168);
  600. if (l1off & (BIT2|BIT3))
  601. *val = _TRUE;
  602. else
  603. *val = _FALSE;
  604. }
  605. break;
  606. case HW_VAR_L1OFF_CAPABILITY:
  607. {
  608. u8 l1off;
  609. l1off = hal_dbi_read_8821ce(adapter, 0x164);
  610. if (l1off & (BIT2|BIT3))
  611. *val = _TRUE;
  612. else
  613. *val = _FALSE;
  614. }
  615. break;
  616. #ifdef CONFIG_LPS_LCLK
  617. case HW_VAR_CPWM:
  618. *val = rtw_read8(adapter, REG_PCIE_HCPWM1_V1_8821C);
  619. break;
  620. #endif
  621. default:
  622. rtl8821c_gethwreg(adapter, variable, val);
  623. break;
  624. }
  625. }
  626. void rtl8821ce_set_hal_ops(PADAPTER padapter)
  627. {
  628. struct hal_ops *ops;
  629. int err;
  630. err = rtl8821ce_halmac_init_adapter(padapter);
  631. if (err) {
  632. RTW_INFO("%s: [ERROR]HALMAC initialize FAIL!\n", __func__);
  633. return;
  634. }
  635. rtl8821c_set_hal_ops(padapter);
  636. ops = &padapter->hal_func;
  637. ops->hal_init = rtl8821ce_hal_init;
  638. ops->hal_deinit = rtl8821ce_hal_deinit;
  639. ops->inirp_init = rtl8821ce_init_bd;
  640. ops->inirp_deinit = rtl8821ce_free_bd;
  641. ops->irp_reset = rtl8821ce_reset_bd;
  642. ops->init_xmit_priv = rtl8821ce_init_xmit_priv;
  643. ops->free_xmit_priv = rtl8821ce_free_xmit_priv;
  644. ops->init_recv_priv = rtl8821ce_init_recv_priv;
  645. ops->free_recv_priv = rtl8821ce_free_recv_priv;
  646. #ifdef CONFIG_RTW_SW_LED
  647. ops->InitSwLeds = rtl8821ce_InitSwLeds;
  648. ops->DeInitSwLeds = rtl8821ce_DeInitSwLeds;
  649. #endif
  650. ops->init_default_value = rtl8821ce_init_default_value;
  651. ops->intf_chip_configure = intf_chip_configure;
  652. ops->read_adapter_info = read_adapter_info;
  653. ops->enable_interrupt = rtl8821ce_enable_interrupt;
  654. ops->disable_interrupt = rtl8821ce_disable_interrupt;
  655. ops->interrupt_handler = rtl8821ce_interrupt;
  656. /*
  657. * ops->check_ips_status = check_ips_status;
  658. */
  659. ops->clear_interrupt = rtl8821ce_clear_interrupt;
  660. #if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) ||\
  661. defined(CONFIG_PCI_HCI)
  662. /*
  663. * ops->clear_interrupt = clear_interrupt_all;
  664. */
  665. #endif
  666. ops->set_hw_reg_handler = sethwreg;
  667. ops->GetHwRegHandler = gethwreg;
  668. ops->get_hal_def_var_handler = gethaldefvar;
  669. ops->SetHalDefVarHandler = sethaldefvar;
  670. ops->hal_xmit = rtl8821ce_hal_xmit;
  671. ops->mgnt_xmit = rtl8821ce_mgnt_xmit;
  672. ops->hal_xmitframe_enqueue = rtl8821ce_hal_xmitframe_enqueue;
  673. #ifdef CONFIG_HOSTAPD_MLME
  674. ops->hostap_mgnt_xmit_entry = rtl8821ce_hostap_mgnt_xmit_entry;
  675. #endif
  676. #ifdef CONFIG_XMIT_THREAD_MODE
  677. /* TODO */
  678. ops->xmit_thread_handler = rtl8821ce_xmit_buf_handler;
  679. #endif
  680. ops->hal_set_l1ssbackdoor_handler = rtw_pci_aspm_config_l1off_general;
  681. }