rtl8821ce_halmac.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. /******************************************************************************
  2. *
  3. * Copyright(c) 2016 - 2018 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 _RTL8821CE_HALMAC_C_
  16. #include <drv_types.h> /* struct dvobj_priv and etc. */
  17. #include "../../hal_halmac.h"
  18. #include "rtl8821ce.h"
  19. static u8 pci_write_port_not_xmitframe(void *d, u32 size, u8 *pBuf, u8 qsel)
  20. {
  21. struct dvobj_priv *pobj = (struct dvobj_priv *)d;
  22. struct pci_dev *pdev = pobj->ppcidev;
  23. PADAPTER padapter = dvobj_get_primary_adapter(pobj);
  24. u32 page_size = 0;
  25. u8 *txbd;
  26. #ifdef CONFIG_64BIT
  27. u64 txbd_dma;
  28. #else
  29. dma_addr_t txbd_dma;
  30. #endif
  31. u8 ret = _SUCCESS;
  32. dma_addr_t mapping;
  33. u16 seg_num = 2 << TX_BUFFER_SEG_NUM;
  34. u16 page_size_length = 0;
  35. #ifdef CONFIG_64BIT_DMA
  36. u16 tmp = rtw_read16(padapter, REG_RX_RXBD_NUM_8821C);
  37. /* using 64bit */
  38. rtw_write16(padapter, REG_RX_RXBD_NUM_8821C, tmp | 0x8000);
  39. #endif
  40. rtw_hal_get_def_var(padapter, HAL_DEF_TX_PAGE_SIZE, &page_size);
  41. /* map TX DESC buf_addr (including TX DESC + tx data) */
  42. #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0))
  43. mapping = pci_map_single(pdev, pBuf,
  44. size+TX_WIFI_INFO_SIZE, PCI_DMA_TODEVICE);
  45. #else
  46. mapping = dma_map_single(&pdev->dev, pBuf,
  47. size+TX_WIFI_INFO_SIZE, DMA_TO_DEVICE);
  48. #endif
  49. /* Calculate page size.
  50. * Total buffer length including TX_WIFI_INFO and PacketLen
  51. */
  52. page_size_length =
  53. (size + TX_WIFI_INFO_SIZE) / page_size;
  54. if (((size + TX_WIFI_INFO_SIZE) % page_size) > 0)
  55. page_size_length++;
  56. #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0))
  57. txbd = pci_alloc_consistent(pdev,
  58. sizeof(struct tx_buf_desc), &txbd_dma);
  59. #else
  60. txbd = dma_alloc_coherent(&pdev->dev,
  61. sizeof(struct tx_buf_desc), &txbd_dma, GFP_KERNEL);
  62. #endif
  63. if (!txbd) {
  64. #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0))
  65. pci_unmap_single(pdev, mapping,
  66. size + TX_WIFI_INFO_SIZE, PCI_DMA_FROMDEVICE);
  67. #else
  68. dma_unmap_single(&pdev->dev, mapping,
  69. size + TX_WIFI_INFO_SIZE, DMA_FROM_DEVICE);
  70. #endif
  71. return _FALSE;
  72. }
  73. if (qsel == HALMAC_TXDESC_QSEL_H2C_CMD) {
  74. rtw_write32(padapter, REG_H2CQ_TXBD_DESA_8821C,
  75. txbd_dma & DMA_BIT_MASK(32));
  76. #ifdef CONFIG_64BIT_DMA
  77. rtw_write32(padapter, REG_H2CQ_TXBD_DESA_8821C + 4,
  78. txbd_dma >> 32);
  79. #endif
  80. rtw_write32(padapter, REG_H2CQ_TXBD_NUM_8821C,
  81. 2 | ((RTL8821CE_SEG_NUM << 12) & 0x3000));
  82. } else {
  83. /* Set BCN BD Reg */
  84. rtw_write32(padapter, REG_BCNQ_TXBD_DESA_8821C,
  85. txbd_dma & DMA_BIT_MASK(32));
  86. #ifdef CONFIG_64BIT_DMA
  87. rtw_write32(padapter, REG_BCNQ_TXBD_DESA_8821C + 4,
  88. txbd_dma >> 32);
  89. #endif
  90. }
  91. /*
  92. * Reset all tx buffer desciprtor content
  93. * -- Reset first element
  94. */
  95. _rtw_memset(txbd, 0, sizeof(struct tx_buf_desc));
  96. /*
  97. * Fill buffer length of the first buffer,
  98. * For 8821ce, it is required that TX_WIFI_INFO is put in first segment,
  99. * and the size of the first segment cannot be larger than
  100. * TX_WIFI_INFO_SIZE.
  101. */
  102. SET_TX_BD_TX_BUFF_SIZE0(txbd, TX_WIFI_INFO_SIZE);
  103. SET_TX_BD_PSB(txbd, page_size_length);
  104. /* starting addr of TXDESC */
  105. SET_TX_BD_PHYSICAL_ADDR0_LOW(txbd, mapping);
  106. #ifdef CONFIG_64BIT_DMA
  107. SET_TX_BD_PHYSICAL_ADDR0_HIGH(txbd, mapping>>32);
  108. #endif
  109. /*
  110. * It is assumed that in linux implementation, packet is coalesced
  111. * in only one buffer. Extension mode is not supported here
  112. */
  113. SET_TXBUFFER_DESC_LEN_WITH_OFFSET(txbd, 1, size);
  114. SET_TXBUFFER_DESC_ADD_LOW_WITH_OFFSET(txbd, 1,
  115. mapping + TX_WIFI_INFO_SIZE); /* pkt */
  116. #ifdef CONFIG_64BIT_DMA
  117. SET_TXBUFFER_DESC_ADD_HIGH_WITH_OFFSET(txbd, 1,
  118. (mapping + TX_WIFI_INFO_SIZE) >> 32); /* pkt */
  119. #endif
  120. /* Need Comment */
  121. wmb();
  122. if (qsel == HALMAC_TXDESC_QSEL_H2C_CMD)
  123. rtw_write16(padapter, REG_H2CQ_TXBD_IDX, 1);
  124. else {
  125. /* fill_txbd_own*/
  126. SET_TX_BD_OWN(txbd, 1);
  127. /* kick start */
  128. rtw_write8(padapter, REG_RX_RXBD_NUM + 1,
  129. rtw_read8(padapter, REG_RX_RXBD_NUM + 1) | BIT(4));
  130. }
  131. udelay(100);
  132. #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0))
  133. pci_free_consistent(pdev, sizeof(struct tx_buf_desc), txbd, txbd_dma);
  134. #else
  135. dma_free_coherent(&pdev->dev, sizeof(struct tx_buf_desc), txbd, txbd_dma);
  136. #endif
  137. #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0))
  138. pci_unmap_single(pdev, mapping,
  139. size + TX_WIFI_INFO_SIZE, PCI_DMA_FROMDEVICE);
  140. #else
  141. dma_unmap_single(&pdev->dev, mapping,
  142. size + TX_WIFI_INFO_SIZE, DMA_FROM_DEVICE);
  143. #endif
  144. return ret;
  145. }
  146. static u8 pci_write_data_not_xmitframe(void *d, u8 *pBuf, u32 size, u8 qsel)
  147. {
  148. struct dvobj_priv *pobj = (struct dvobj_priv *)d;
  149. PADAPTER padapter = dvobj_get_primary_adapter(pobj);
  150. struct halmac_adapter *halmac = dvobj_to_halmac((struct dvobj_priv *)d);
  151. struct halmac_api *api = HALMAC_GET_API(halmac);
  152. u32 desclen = 0;
  153. u8 *buf = NULL;
  154. u8 ret = _FALSE;
  155. if ((size + TXDESC_OFFSET) > MAX_CMDBUF_SZ) {
  156. RTW_INFO("%s: total buffer size(%d) > MAX_CMDBUF_SZ(%d)\n"
  157. , __func__, size + TXDESC_OFFSET, MAX_CMDBUF_SZ);
  158. return _FALSE;
  159. }
  160. rtw_halmac_get_tx_desc_size(pobj, &desclen);
  161. buf = rtw_zmalloc(desclen + size);
  162. if (!buf) {
  163. RTW_INFO("%s: rtw_zmalloc for rsvd Fail\n", __func__);
  164. return _FALSE;
  165. }
  166. _rtw_memcpy(buf + desclen, pBuf, size);
  167. SET_TX_DESC_TXPKTSIZE_8821C(buf, size);
  168. /* TX_DESC is not included in the data,
  169. * driver needs to fill in the TX_DESC with qsel=h2c
  170. * Offset in TX_DESC should be set to 0.
  171. */
  172. if (qsel == HALMAC_TXDESC_QSEL_H2C_CMD)
  173. SET_TX_DESC_OFFSET_8821C(buf, 0);
  174. else
  175. SET_TX_DESC_OFFSET_8821C(buf, desclen);
  176. SET_TX_DESC_QSEL_8821C(buf, qsel);
  177. api->halmac_fill_txdesc_checksum(halmac, buf);
  178. ret = pci_write_port_not_xmitframe(d, size, buf, qsel);
  179. if (ret == _SUCCESS)
  180. ret = _TRUE;
  181. else
  182. ret = _FALSE;
  183. rtw_mfree(buf, desclen + size);
  184. return _TRUE;
  185. }
  186. static u8 pci_write_data_rsvd_page_xmitframe(void *d, u8 *pBuf, u32 size)
  187. {
  188. struct dvobj_priv *pobj = (struct dvobj_priv *)d;
  189. PADAPTER padapter = dvobj_get_primary_adapter(pobj);
  190. struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
  191. struct xmit_frame *pcmdframe = NULL;
  192. struct pkt_attrib *pattrib = NULL;
  193. u32 desclen = 0;
  194. struct rtw_tx_ring *ring = &pxmitpriv->tx_ring[BCN_QUEUE_INX];
  195. struct pci_dev *pdev = pobj->ppcidev;
  196. struct xmit_buf *pxmitbuf = NULL;
  197. u8 DLBcnCount = 0;
  198. u32 poll = 0;
  199. u8 *txbd;
  200. bool bcn_valid = _FALSE;
  201. u8 *txdesc = NULL;
  202. dma_addr_t mapping;
  203. if (size + TXDESC_OFFSET > MAX_CMDBUF_SZ) {
  204. RTW_INFO("%s: total buffer size(%d) > MAX_CMDBUF_SZ(%d)\n"
  205. , __func__, size + TXDESC_OFFSET, MAX_CMDBUF_SZ);
  206. return _FALSE;
  207. }
  208. pcmdframe = rtw_alloc_cmdxmitframe(pxmitpriv);
  209. if (pcmdframe == NULL) {
  210. RTW_INFO("%s: alloc ReservedPagePacket fail!\n", __func__);
  211. return _FALSE;
  212. }
  213. pxmitbuf = pcmdframe->pxmitbuf;
  214. rtw_halmac_get_tx_desc_size(pobj, &desclen);
  215. txdesc = pcmdframe->buf_addr;
  216. _rtw_memcpy((txdesc + desclen), pBuf, size); /* shift desclen */
  217. /* update attribute */
  218. pattrib = &pcmdframe->attrib;
  219. update_mgntframe_attrib(padapter, pattrib);
  220. pattrib->qsel = QSLT_BEACON;
  221. pattrib->pktlen = size;
  222. pattrib->last_txcmdsz = size;
  223. /* Clear beacon valid check bit. */
  224. rtw_hal_set_hwreg(padapter, HW_VAR_BCN_VALID, NULL);
  225. dump_mgntframe(padapter, pcmdframe);
  226. DLBcnCount = 0;
  227. poll = 0;
  228. do {
  229. DLBcnCount++;
  230. do {
  231. rtw_yield_os();
  232. /* does rsvd page download OK. */
  233. rtw_hal_get_hwreg(padapter,
  234. HW_VAR_BCN_VALID,(u8 *)(&bcn_valid));
  235. poll++;
  236. } while (!bcn_valid && (poll % 10) != 0 && !RTW_CANNOT_RUN(padapter));
  237. } while (!bcn_valid && DLBcnCount <= 100 && !RTW_CANNOT_RUN(padapter));
  238. txbd = (u8 *)(&ring->buf_desc[0]);
  239. mapping = GET_TX_BD_PHYSICAL_ADDR0_LOW(txbd);
  240. #ifdef CONFIG_64BIT_DMA
  241. mapping |= (dma_addr_t)GET_TX_BD_PHYSICAL_ADDR0_HIGH(txbd) << 32;
  242. #endif
  243. /*To patch*/
  244. #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0))
  245. pci_unmap_single(pdev, mapping, pxmitbuf->len, PCI_DMA_TODEVICE);
  246. #else
  247. dma_unmap_single(&pdev->dev, mapping, pxmitbuf->len, DMA_TO_DEVICE);
  248. #endif
  249. return _TRUE;
  250. }
  251. static u8 pci_write_data_h2c_normal(void *d, u8 *pBuf, u32 size)
  252. {
  253. struct dvobj_priv *pobj = (struct dvobj_priv *)d;
  254. PADAPTER padapter = dvobj_get_primary_adapter(pobj);
  255. struct halmac_adapter *halmac = dvobj_to_halmac((struct dvobj_priv *)d);
  256. struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
  257. struct xmit_frame *pcmdframe = NULL;
  258. struct pkt_attrib *pattrib = NULL;
  259. struct halmac_api *api;
  260. u32 desclen;
  261. u8 *buf;
  262. if (size + TXDESC_OFFSET > MAX_XMIT_EXTBUF_SZ) {
  263. RTW_INFO("%s: total buffer size(%d) > MAX_XMIT_EXTBUF_SZ(%d)\n"
  264. , __func__, size + TXDESC_OFFSET, MAX_XMIT_EXTBUF_SZ);
  265. return _FALSE;
  266. }
  267. pcmdframe = alloc_mgtxmitframe(pxmitpriv);
  268. if (pcmdframe == NULL) {
  269. RTW_INFO("%s: alloc ReservedPagePacket fail!\n", __func__);
  270. return _FALSE;
  271. }
  272. api = HALMAC_GET_API(halmac);
  273. rtw_halmac_get_tx_desc_size(pobj, &desclen);
  274. buf = pcmdframe->buf_addr;
  275. _rtw_memcpy(buf + desclen, pBuf, size); /* shift desclen */
  276. SET_TX_DESC_TXPKTSIZE_8821C(buf, size);
  277. SET_TX_DESC_OFFSET_8821C(buf, 0);
  278. SET_TX_DESC_QSEL_8821C(buf, HALMAC_TXDESC_QSEL_H2C_CMD);
  279. SET_TX_DESC_TXDESC_CHECKSUM_8821C(buf, 0);
  280. api->halmac_fill_txdesc_checksum(halmac, buf);
  281. /* update attribute */
  282. pattrib = &pcmdframe->attrib;
  283. update_mgntframe_attrib(padapter, pattrib);
  284. pattrib->qsel = QSLT_CMD;
  285. pattrib->pktlen = size;
  286. pattrib->last_txcmdsz = size;
  287. /* fill tx desc in dump_mgntframe */
  288. dump_mgntframe(padapter, pcmdframe);
  289. return _TRUE;
  290. }
  291. static u8 pci_write_data_rsvd_page(void *d, u8 *pBuf, u32 size)
  292. {
  293. struct dvobj_priv *pobj = (struct dvobj_priv *)d;
  294. PADAPTER padapter = dvobj_get_primary_adapter(pobj);
  295. HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
  296. u8 ret;
  297. if (pHalData->not_xmitframe_fw_dl)
  298. ret = pci_write_data_not_xmitframe(d, pBuf, size, HALMAC_TXDESC_QSEL_BEACON);
  299. else
  300. ret = pci_write_data_rsvd_page_xmitframe(d, pBuf, size);
  301. if (ret == _TRUE)
  302. return 1;
  303. return 0;
  304. }
  305. static u8 pci_write_data_h2c(void *d, u8 *pBuf, u32 size)
  306. {
  307. struct dvobj_priv *pobj = (struct dvobj_priv *)d;
  308. PADAPTER padapter = dvobj_get_primary_adapter(pobj);
  309. HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
  310. u8 ret;
  311. if (pHalData->not_xmitframe_fw_dl)
  312. ret = pci_write_data_not_xmitframe(d, pBuf, size, HALMAC_TXDESC_QSEL_H2C_CMD);
  313. else
  314. ret = pci_write_data_h2c_normal(d, pBuf, size);
  315. if (ret == _TRUE)
  316. return 1;
  317. return 0;
  318. }
  319. int rtl8821ce_halmac_init_adapter(PADAPTER padapter)
  320. {
  321. struct dvobj_priv *d;
  322. struct halmac_platform_api *api;
  323. int err;
  324. #ifdef CONFIG_64BIT_DMA
  325. if (adapter_to_dvobj(padapter)->bdma64)
  326. PlatformEnableDMA64(padapter);
  327. #endif
  328. d = adapter_to_dvobj(padapter);
  329. api = &rtw_halmac_platform_api;
  330. api->SEND_RSVD_PAGE = pci_write_data_rsvd_page;
  331. api->SEND_H2C_PKT = pci_write_data_h2c;
  332. err = rtw_halmac_init_adapter(d, api);
  333. return err;
  334. }