OSDN Git Service

Add rtl8821ce driver version 5.5.2
[android-x86/external-kernel-drivers.git] / rtl8821ce / hal / rtl8821c / pci / rtl8821ce_halmac.c
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
20 static u8 pci_write_port_not_xmitframe(void *d,  u32 size, u8 *pBuf, u8 qsel)
21 {
22         struct dvobj_priv *pobj = (struct dvobj_priv *)d;
23         struct pci_dev *pdev = pobj->ppcidev;
24         PADAPTER padapter = dvobj_get_primary_adapter(pobj);
25         u32 page_size = 0;
26         u8 *txbd;
27 #ifdef  CONFIG_64BIT
28         u64 txbd_dma;
29 #else
30         dma_addr_t txbd_dma;
31 #endif
32         u8 ret = _SUCCESS;
33         dma_addr_t mapping;
34
35         u16 seg_num = 2 << TX_BUFFER_SEG_NUM;
36
37         u16 page_size_length = 0;
38 #ifdef CONFIG_64BIT_DMA
39         u16 tmp = rtw_read16(padapter, REG_RX_RXBD_NUM_8821C);
40         /* using 64bit */
41         rtw_write16(padapter, REG_RX_RXBD_NUM_8821C, tmp | 0x8000);
42 #endif
43
44         rtw_hal_get_def_var(padapter, HAL_DEF_TX_PAGE_SIZE, &page_size);
45
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);
49
50
51         /* Calculate page size.
52          * Total buffer length including TX_WIFI_INFO and PacketLen
53          */
54         page_size_length =
55                 (size + TX_WIFI_INFO_SIZE) / page_size;
56
57         if (((size + TX_WIFI_INFO_SIZE) % page_size) > 0)
58                 page_size_length++;
59
60         txbd = pci_alloc_consistent(pdev,
61                 sizeof(struct tx_buf_desc), &txbd_dma);
62
63         if (!txbd) {
64                 pci_unmap_single(pdev, mapping,
65                         size + TX_WIFI_INFO_SIZE, PCI_DMA_FROMDEVICE);
66
67                 return _FALSE;
68         }
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,
74                         txbd_dma >> 32);
75         #endif
76
77                 rtw_write32(padapter, REG_H2CQ_TXBD_NUM_8821C,
78                         2 | ((RTL8821CE_SEG_NUM << 12) & 0x3000));
79         } else {
80                 /* Set BCN BD Reg */
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,
85                         txbd_dma >> 32);
86         #endif
87         }
88
89         /*
90          * Reset all tx buffer desciprtor content
91          * -- Reset first element
92          */
93         _rtw_memset(txbd, 0, sizeof(struct tx_buf_desc));
94
95         /*
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
99          * TX_WIFI_INFO_SIZE.
100          */
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);
107 #endif
108
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
115         SET_TXBUFFER_DESC_ADD_LOW_WITH_OFFSET(txbd, 1,
116                                       mapping + TX_WIFI_INFO_SIZE); /* pkt */
117
118 #ifdef CONFIG_64BIT_DMA
119         SET_TXBUFFER_DESC_ADD_HIGH_WITH_OFFSET(txbd, 1,
120                                       (mapping + TX_WIFI_INFO_SIZE) >> 32); /* pkt */
121 #endif
122
123
124         /* Need Comment */
125         wmb();
126
127         if (qsel == HALMAC_TXDESC_QSEL_H2C_CMD)
128                 rtw_write16(padapter, REG_H2CQ_TXBD_IDX, 1);
129         else {
130                 /* fill_txbd_own*/
131                 SET_TX_BD_OWN(txbd, 1);
132                 /* kick start */
133                 rtw_write8(padapter, REG_RX_RXBD_NUM + 1,
134                         rtw_read8(padapter, REG_RX_RXBD_NUM + 1) | BIT(4));
135         }
136
137         udelay(100);
138
139         pci_free_consistent(pdev, sizeof(struct tx_buf_desc), txbd, txbd_dma);
140
141         pci_unmap_single(pdev, mapping,
142                         size + TX_WIFI_INFO_SIZE,        PCI_DMA_FROMDEVICE);
143
144         return ret;
145
146 }
147
148 static u8 pci_write_data_not_xmitframe(void *d, u8 *pBuf, u32 size, u8 qsel)
149 {
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);
154         u32 desclen = 0;
155         u8 *buf = NULL;
156         u8 ret = _FALSE;
157
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);
161                 return _FALSE;
162         }
163
164         rtw_halmac_get_tx_desc_size(pobj, &desclen);
165
166         buf = rtw_zmalloc(desclen + size);
167
168         if (!buf) {
169                 RTW_INFO("%s: rtw_zmalloc for rsvd Fail\n", __func__);
170                 return _FALSE;
171         }
172
173         _rtw_memcpy(buf + desclen, pBuf, size);
174
175         SET_TX_DESC_TXPKTSIZE_8821C(buf, size);
176
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.
180          */
181         if (qsel == HALMAC_TXDESC_QSEL_H2C_CMD)
182                 SET_TX_DESC_OFFSET_8821C(buf, 0);
183         else
184                 SET_TX_DESC_OFFSET_8821C(buf, desclen);
185
186         SET_TX_DESC_QSEL_8821C(buf, qsel);
187
188         api->halmac_fill_txdesc_checksum(halmac, buf);
189
190         ret = pci_write_port_not_xmitframe(d, size, buf, qsel);
191
192
193         if (ret == _SUCCESS)
194                 ret = _TRUE;
195         else
196                 ret = _FALSE;
197
198         rtw_mfree(buf, desclen + size);
199
200         return _TRUE;
201 }
202
203 static u8 pci_write_data_rsvd_page_xmitframe(void *d, u8 *pBuf, u32 size)
204 {
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;
210         u32 desclen = 0;
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;
214         u8 DLBcnCount = 0;
215         u32 poll = 0;
216         u8 *txbd;
217         bool bcn_valid = _FALSE;
218         u8 *txdesc = NULL;
219         dma_addr_t mapping;
220
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);
224                 return _FALSE;
225         }
226
227         pcmdframe = rtw_alloc_cmdxmitframe(pxmitpriv);
228
229         if (pcmdframe == NULL) {
230                 RTW_INFO("%s: alloc ReservedPagePacket fail!\n", __func__);
231                 return _FALSE;
232         }
233
234         pxmitbuf = pcmdframe->pxmitbuf;
235         rtw_halmac_get_tx_desc_size(pobj, &desclen);
236         txdesc = pcmdframe->buf_addr;
237
238         _rtw_memcpy((txdesc + desclen), pBuf, size); /* shift desclen */
239
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;
246
247         /* Clear beacon valid check bit. */
248         rtw_hal_set_hwreg(padapter, HW_VAR_BCN_VALID, NULL);
249
250         dump_mgntframe(padapter, pcmdframe);
251
252         DLBcnCount = 0;
253         poll = 0;
254         do {
255                 DLBcnCount++;
256                 do {
257                         rtw_yield_os();
258                         /* does rsvd page download OK. */
259                         rtw_hal_get_hwreg(padapter,
260                                 HW_VAR_BCN_VALID,(u8 *)(&bcn_valid));
261                         poll++;
262                 } while (!bcn_valid && (poll % 10) != 0 && !RTW_CANNOT_RUN(padapter));
263         } while (!bcn_valid && DLBcnCount <= 100 && !RTW_CANNOT_RUN(padapter));
264
265         txbd = (u8 *)(&ring->buf_desc[0]);
266
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;
270         #endif
271
272         /*To patch*/
273
274         pci_unmap_single(pdev, mapping, pxmitbuf->len, PCI_DMA_TODEVICE);
275
276         return _TRUE;
277 }
278
279 static u8 pci_write_data_h2c_normal(void *d, u8 *pBuf, u32 size)
280 {
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;
288         u32 desclen;
289         u8 *buf;
290
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);
294                 return _FALSE;
295         }
296
297         pcmdframe = alloc_mgtxmitframe(pxmitpriv);
298
299         if (pcmdframe == NULL) {
300                 RTW_INFO("%s: alloc ReservedPagePacket fail!\n", __func__);
301                 return _FALSE;
302         }
303
304         api = HALMAC_GET_API(halmac);
305
306         rtw_halmac_get_tx_desc_size(pobj, &desclen);
307         buf = pcmdframe->buf_addr;
308         _rtw_memcpy(buf + desclen, pBuf, size); /* shift desclen */
309
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);
315
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;
322
323         /* fill tx desc in dump_mgntframe */
324         dump_mgntframe(padapter, pcmdframe);
325
326         return _TRUE;
327 }
328
329 static u8 pci_write_data_rsvd_page(void *d, u8 *pBuf, u32 size)
330 {
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);
334         u8 ret;
335
336         if (pHalData->not_xmitframe_fw_dl)
337                 ret = pci_write_data_not_xmitframe(d, pBuf, size, HALMAC_TXDESC_QSEL_BEACON);
338         else
339                 ret = pci_write_data_rsvd_page_xmitframe(d, pBuf, size);
340
341         if (ret == _TRUE)
342                 return 1;
343         return 0;
344 }
345
346 static u8 pci_write_data_h2c(void *d, u8 *pBuf, u32 size)
347 {
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);
351         u8 ret;
352
353         if (pHalData->not_xmitframe_fw_dl)
354                 ret = pci_write_data_not_xmitframe(d, pBuf, size, HALMAC_TXDESC_QSEL_H2C_CMD);
355         else
356                 ret = pci_write_data_h2c_normal(d, pBuf, size);
357
358         if (ret == _TRUE)
359                 return 1;
360         return 0;
361 }
362
363 int rtl8821ce_halmac_init_adapter(PADAPTER padapter)
364 {
365         struct dvobj_priv *d;
366         struct halmac_platform_api *api;
367         int err;
368
369 #ifdef CONFIG_64BIT_DMA
370         if (adapter_to_dvobj(padapter)->bdma64)
371                 PlatformEnableDMA64(padapter);
372 #endif
373
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;
378
379         err = rtw_halmac_init_adapter(d, api);
380
381         return err;
382 }