1 /******************************************************************************
3 * Copyright(c) 2016 - 2018 Realtek Corporation.
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.
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
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"
20 static u8 pci_write_port_not_xmitframe(void *d, u32 size, u8 *pBuf, u8 qsel)
22 struct dvobj_priv *pobj = (struct dvobj_priv *)d;
23 struct pci_dev *pdev = pobj->ppcidev;
24 PADAPTER padapter = dvobj_get_primary_adapter(pobj);
35 u16 seg_num = 2 << TX_BUFFER_SEG_NUM;
37 u16 page_size_length = 0;
38 #ifdef CONFIG_64BIT_DMA
39 u16 tmp = rtw_read16(padapter, REG_RX_RXBD_NUM_8821C);
41 rtw_write16(padapter, REG_RX_RXBD_NUM_8821C, tmp | 0x8000);
44 rtw_hal_get_def_var(padapter, HAL_DEF_TX_PAGE_SIZE, &page_size);
46 /* map TX DESC buf_addr (including TX DESC + tx data) */
47 mapping = pci_map_single(pdev, pBuf,
48 size+TX_WIFI_INFO_SIZE, PCI_DMA_TODEVICE);
51 /* Calculate page size.
52 * Total buffer length including TX_WIFI_INFO and PacketLen
55 (size + TX_WIFI_INFO_SIZE) / page_size;
57 if (((size + TX_WIFI_INFO_SIZE) % page_size) > 0)
60 txbd = pci_alloc_consistent(pdev,
61 sizeof(struct tx_buf_desc), &txbd_dma);
64 pci_unmap_single(pdev, mapping,
65 size + TX_WIFI_INFO_SIZE, PCI_DMA_FROMDEVICE);
69 if (qsel == HALMAC_TXDESC_QSEL_H2C_CMD) {
70 rtw_write32(padapter, REG_H2CQ_TXBD_DESA_8821C,
71 txbd_dma & DMA_BIT_MASK(32));
72 #ifdef CONFIG_64BIT_DMA
73 rtw_write32(padapter, REG_H2CQ_TXBD_DESA_8821C + 4,
77 rtw_write32(padapter, REG_H2CQ_TXBD_NUM_8821C,
78 2 | ((RTL8821CE_SEG_NUM << 12) & 0x3000));
81 rtw_write32(padapter, REG_BCNQ_TXBD_DESA_8821C,
82 txbd_dma & DMA_BIT_MASK(32));
83 #ifdef CONFIG_64BIT_DMA
84 rtw_write32(padapter, REG_BCNQ_TXBD_DESA_8821C + 4,
90 * Reset all tx buffer desciprtor content
91 * -- Reset first element
93 _rtw_memset(txbd, 0, sizeof(struct tx_buf_desc));
96 * Fill buffer length of the first buffer,
97 * For 8821ce, it is required that TX_WIFI_INFO is put in first segment,
98 * and the size of the first segment cannot be larger than
101 SET_TX_BD_TX_BUFF_SIZE0(txbd, TX_WIFI_INFO_SIZE);
102 SET_TX_BD_PSB(txbd, page_size_length);
103 /* starting addr of TXDESC */
104 SET_TX_BD_PHYSICAL_ADDR0_LOW(txbd, mapping);
105 #ifdef CONFIG_64BIT_DMA
106 SET_TX_BD_PHYSICAL_ADDR0_HIGH(txbd, mapping>>32);
110 * It is assumed that in linux implementation, packet is coalesced
111 * in only one buffer. Extension mode is not supported here
113 SET_TXBUFFER_DESC_LEN_WITH_OFFSET(txbd, 1, size);
115 SET_TXBUFFER_DESC_ADD_LOW_WITH_OFFSET(txbd, 1,
116 mapping + TX_WIFI_INFO_SIZE); /* pkt */
118 #ifdef CONFIG_64BIT_DMA
119 SET_TXBUFFER_DESC_ADD_HIGH_WITH_OFFSET(txbd, 1,
120 (mapping + TX_WIFI_INFO_SIZE) >> 32); /* pkt */
127 if (qsel == HALMAC_TXDESC_QSEL_H2C_CMD)
128 rtw_write16(padapter, REG_H2CQ_TXBD_IDX, 1);
131 SET_TX_BD_OWN(txbd, 1);
133 rtw_write8(padapter, REG_RX_RXBD_NUM + 1,
134 rtw_read8(padapter, REG_RX_RXBD_NUM + 1) | BIT(4));
139 pci_free_consistent(pdev, sizeof(struct tx_buf_desc), txbd, txbd_dma);
141 pci_unmap_single(pdev, mapping,
142 size + TX_WIFI_INFO_SIZE, PCI_DMA_FROMDEVICE);
148 static u8 pci_write_data_not_xmitframe(void *d, u8 *pBuf, u32 size, u8 qsel)
150 struct dvobj_priv *pobj = (struct dvobj_priv *)d;
151 PADAPTER padapter = dvobj_get_primary_adapter(pobj);
152 struct halmac_adapter *halmac = dvobj_to_halmac((struct dvobj_priv *)d);
153 struct halmac_api *api = HALMAC_GET_API(halmac);
158 if ((size + TXDESC_OFFSET) > MAX_CMDBUF_SZ) {
159 RTW_INFO("%s: total buffer size(%d) > MAX_CMDBUF_SZ(%d)\n"
160 , __func__, size + TXDESC_OFFSET, MAX_CMDBUF_SZ);
164 rtw_halmac_get_tx_desc_size(pobj, &desclen);
166 buf = rtw_zmalloc(desclen + size);
169 RTW_INFO("%s: rtw_zmalloc for rsvd Fail\n", __func__);
173 _rtw_memcpy(buf + desclen, pBuf, size);
175 SET_TX_DESC_TXPKTSIZE_8821C(buf, size);
177 /* TX_DESC is not included in the data,
178 * driver needs to fill in the TX_DESC with qsel=h2c
179 * Offset in TX_DESC should be set to 0.
181 if (qsel == HALMAC_TXDESC_QSEL_H2C_CMD)
182 SET_TX_DESC_OFFSET_8821C(buf, 0);
184 SET_TX_DESC_OFFSET_8821C(buf, desclen);
186 SET_TX_DESC_QSEL_8821C(buf, qsel);
188 api->halmac_fill_txdesc_checksum(halmac, buf);
190 ret = pci_write_port_not_xmitframe(d, size, buf, qsel);
198 rtw_mfree(buf, desclen + size);
203 static u8 pci_write_data_rsvd_page_xmitframe(void *d, u8 *pBuf, u32 size)
205 struct dvobj_priv *pobj = (struct dvobj_priv *)d;
206 PADAPTER padapter = dvobj_get_primary_adapter(pobj);
207 struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
208 struct xmit_frame *pcmdframe = NULL;
209 struct pkt_attrib *pattrib = NULL;
211 struct rtw_tx_ring *ring = &pxmitpriv->tx_ring[BCN_QUEUE_INX];
212 struct pci_dev *pdev = pobj->ppcidev;
213 struct xmit_buf *pxmitbuf = NULL;
217 bool bcn_valid = _FALSE;
221 if (size + TXDESC_OFFSET > MAX_CMDBUF_SZ) {
222 RTW_INFO("%s: total buffer size(%d) > MAX_CMDBUF_SZ(%d)\n"
223 , __func__, size + TXDESC_OFFSET, MAX_CMDBUF_SZ);
227 pcmdframe = rtw_alloc_cmdxmitframe(pxmitpriv);
229 if (pcmdframe == NULL) {
230 RTW_INFO("%s: alloc ReservedPagePacket fail!\n", __func__);
234 pxmitbuf = pcmdframe->pxmitbuf;
235 rtw_halmac_get_tx_desc_size(pobj, &desclen);
236 txdesc = pcmdframe->buf_addr;
238 _rtw_memcpy((txdesc + desclen), pBuf, size); /* shift desclen */
240 /* update attribute */
241 pattrib = &pcmdframe->attrib;
242 update_mgntframe_attrib(padapter, pattrib);
243 pattrib->qsel = QSLT_BEACON;
244 pattrib->pktlen = size;
245 pattrib->last_txcmdsz = size;
247 /* Clear beacon valid check bit. */
248 rtw_hal_set_hwreg(padapter, HW_VAR_BCN_VALID, NULL);
250 dump_mgntframe(padapter, pcmdframe);
258 /* does rsvd page download OK. */
259 rtw_hal_get_hwreg(padapter,
260 HW_VAR_BCN_VALID,(u8 *)(&bcn_valid));
262 } while (!bcn_valid && (poll % 10) != 0 && !RTW_CANNOT_RUN(padapter));
263 } while (!bcn_valid && DLBcnCount <= 100 && !RTW_CANNOT_RUN(padapter));
265 txbd = (u8 *)(&ring->buf_desc[0]);
267 mapping = GET_TX_BD_PHYSICAL_ADDR0_LOW(txbd);
268 #ifdef CONFIG_64BIT_DMA
269 mapping |= (dma_addr_t)GET_TX_BD_PHYSICAL_ADDR0_HIGH(txbd) << 32;
274 pci_unmap_single(pdev, mapping, pxmitbuf->len, PCI_DMA_TODEVICE);
279 static u8 pci_write_data_h2c_normal(void *d, u8 *pBuf, u32 size)
281 struct dvobj_priv *pobj = (struct dvobj_priv *)d;
282 PADAPTER padapter = dvobj_get_primary_adapter(pobj);
283 struct halmac_adapter *halmac = dvobj_to_halmac((struct dvobj_priv *)d);
284 struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
285 struct xmit_frame *pcmdframe = NULL;
286 struct pkt_attrib *pattrib = NULL;
287 struct halmac_api *api;
291 if (size + TXDESC_OFFSET > MAX_XMIT_EXTBUF_SZ) {
292 RTW_INFO("%s: total buffer size(%d) > MAX_XMIT_EXTBUF_SZ(%d)\n"
293 , __func__, size + TXDESC_OFFSET, MAX_XMIT_EXTBUF_SZ);
297 pcmdframe = alloc_mgtxmitframe(pxmitpriv);
299 if (pcmdframe == NULL) {
300 RTW_INFO("%s: alloc ReservedPagePacket fail!\n", __func__);
304 api = HALMAC_GET_API(halmac);
306 rtw_halmac_get_tx_desc_size(pobj, &desclen);
307 buf = pcmdframe->buf_addr;
308 _rtw_memcpy(buf + desclen, pBuf, size); /* shift desclen */
310 SET_TX_DESC_TXPKTSIZE_8821C(buf, size);
311 SET_TX_DESC_OFFSET_8821C(buf, 0);
312 SET_TX_DESC_QSEL_8821C(buf, HALMAC_TXDESC_QSEL_H2C_CMD);
313 SET_TX_DESC_TXDESC_CHECKSUM_8821C(buf, 0);
314 api->halmac_fill_txdesc_checksum(halmac, buf);
316 /* update attribute */
317 pattrib = &pcmdframe->attrib;
318 update_mgntframe_attrib(padapter, pattrib);
319 pattrib->qsel = QSLT_CMD;
320 pattrib->pktlen = size;
321 pattrib->last_txcmdsz = size;
323 /* fill tx desc in dump_mgntframe */
324 dump_mgntframe(padapter, pcmdframe);
329 static u8 pci_write_data_rsvd_page(void *d, u8 *pBuf, u32 size)
331 struct dvobj_priv *pobj = (struct dvobj_priv *)d;
332 PADAPTER padapter = dvobj_get_primary_adapter(pobj);
333 HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
336 if (pHalData->not_xmitframe_fw_dl)
337 ret = pci_write_data_not_xmitframe(d, pBuf, size, HALMAC_TXDESC_QSEL_BEACON);
339 ret = pci_write_data_rsvd_page_xmitframe(d, pBuf, size);
346 static u8 pci_write_data_h2c(void *d, u8 *pBuf, u32 size)
348 struct dvobj_priv *pobj = (struct dvobj_priv *)d;
349 PADAPTER padapter = dvobj_get_primary_adapter(pobj);
350 HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
353 if (pHalData->not_xmitframe_fw_dl)
354 ret = pci_write_data_not_xmitframe(d, pBuf, size, HALMAC_TXDESC_QSEL_H2C_CMD);
356 ret = pci_write_data_h2c_normal(d, pBuf, size);
363 int rtl8821ce_halmac_init_adapter(PADAPTER padapter)
365 struct dvobj_priv *d;
366 struct halmac_platform_api *api;
369 #ifdef CONFIG_64BIT_DMA
370 if (adapter_to_dvobj(padapter)->bdma64)
371 PlatformEnableDMA64(padapter);
374 d = adapter_to_dvobj(padapter);
375 api = &rtw_halmac_platform_api;
376 api->SEND_RSVD_PAGE = pci_write_data_rsvd_page;
377 api->SEND_H2C_PKT = pci_write_data_h2c;
379 err = rtw_halmac_init_adapter(d, api);