staging: r8712u: Merging Realtek's latest (v2.6.6). Various fixes.
[deliverable/linux.git] / drivers / staging / rtl8712 / rtl8712_xmit.c
CommitLineData
2865d42c
LF
1/******************************************************************************
2 * rtl8712_xmit.c
3 *
4 * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
5 * Linux device driver for RTL8192SU
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of version 2 of the GNU General Public License as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
19 *
20 * Modifications for inclusion into the Linux staging tree are
21 * Copyright(c) 2010 Larry Finger. All rights reserved.
22 *
23 * Contact information:
24 * WLAN FAE <wlanfae@realtek.com>
25 * Larry Finger <Larry.Finger@lwfinger.net>
26 *
27 ******************************************************************************/
28
29#define _RTL8712_XMIT_C_
30
31#include "osdep_service.h"
32#include "drv_types.h"
33#include "rtl871x_byteorder.h"
34#include "wifi.h"
35#include "osdep_intf.h"
36#include "usb_ops.h"
37
38static void dump_xframe(struct _adapter *padapter,
39 struct xmit_frame *pxmitframe);
ee5b1aad 40static void update_txdesc(struct xmit_frame *pxmitframe, uint *pmem, int sz);
2865d42c
LF
41
42sint _r8712_init_hw_txqueue(struct hw_txqueue *phw_txqueue, u8 ac_tag)
43{
44 phw_txqueue->ac_tag = ac_tag;
45 switch (ac_tag) {
46 case BE_QUEUE_INX:
47 phw_txqueue->ff_hwaddr = RTL8712_DMA_BEQ;
48 break;
49 case BK_QUEUE_INX:
50 phw_txqueue->ff_hwaddr = RTL8712_DMA_BKQ;
51 break;
52 case VI_QUEUE_INX:
53 phw_txqueue->ff_hwaddr = RTL8712_DMA_VIQ;
54 break;
55 case VO_QUEUE_INX:
56 phw_txqueue->ff_hwaddr = RTL8712_DMA_VOQ;
57 break;
58 case BMC_QUEUE_INX:
59 phw_txqueue->ff_hwaddr = RTL8712_DMA_BEQ;
60 break;
61 }
62 return _SUCCESS;
63}
64
65int r8712_txframes_sta_ac_pending(struct _adapter *padapter,
66 struct pkt_attrib *pattrib)
67{
68 struct sta_info *psta;
69 struct tx_servq *ptxservq;
70 int priority = pattrib->priority;
71
72 psta = pattrib->psta;
73 switch (priority) {
74 case 1:
75 case 2:
76 ptxservq = &(psta->sta_xmitpriv.bk_q);
77 break;
78 case 4:
79 case 5:
80 ptxservq = &(psta->sta_xmitpriv.vi_q);
81 break;
82 case 6:
83 case 7:
84 ptxservq = &(psta->sta_xmitpriv.vo_q);
85 break;
86 case 0:
87 case 3:
88 default:
89 ptxservq = &(psta->sta_xmitpriv.be_q);
90 break;
91 }
92 return ptxservq->qcnt;
93}
94
95static u32 get_ff_hwaddr(struct xmit_frame *pxmitframe)
96{
97 u32 addr = 0;
98 struct pkt_attrib *pattrib = &pxmitframe->attrib;
99 struct _adapter *padapter = pxmitframe->padapter;
100 struct dvobj_priv *pdvobj = (struct dvobj_priv *)&padapter->dvobjpriv;
101
102 if (pxmitframe->frame_tag == TXAGG_FRAMETAG)
103 addr = RTL8712_DMA_H2CCMD;
104 else if (pxmitframe->frame_tag == MGNT_FRAMETAG)
105 addr = RTL8712_DMA_MGTQ;
106 else if (pdvobj->nr_endpoint == 6) {
107 switch (pattrib->priority) {
108 case 0:
109 case 3:
110 addr = RTL8712_DMA_BEQ;
111 break;
112 case 1:
113 case 2:
114 addr = RTL8712_DMA_BKQ;
115 break;
116 case 4:
117 case 5:
118 addr = RTL8712_DMA_VIQ;
119 break;
120 case 6:
121 case 7:
122 addr = RTL8712_DMA_VOQ;
123 break;
124 case 0x10:
125 case 0x11:
126 case 0x12:
127 case 0x13:
128 addr = RTL8712_DMA_H2CCMD;
129 break;
130 default:
131 addr = RTL8712_DMA_BEQ;
132 break;
133 }
134 } else if (pdvobj->nr_endpoint == 4) {
135 switch (pattrib->qsel) {
136 case 0:
137 case 3:
138 case 1:
139 case 2:
140 addr = RTL8712_DMA_BEQ;/*RTL8712_EP_LO;*/
141 break;
142 case 4:
143 case 5:
144 case 6:
145 case 7:
146 addr = RTL8712_DMA_VOQ;/*RTL8712_EP_HI;*/
147 break;
148 case 0x10:
149 case 0x11:
150 case 0x12:
151 case 0x13:
859171ca 152 addr = RTL8712_DMA_H2CCMD;
2865d42c
LF
153 break;
154 default:
155 addr = RTL8712_DMA_BEQ;/*RTL8712_EP_LO;*/
156 break;
157 }
158 }
159 return addr;
160}
161
162static struct xmit_frame *dequeue_one_xmitframe(struct xmit_priv *pxmitpriv,
163 struct hw_xmit *phwxmit,
164 struct tx_servq *ptxservq,
165 struct __queue *pframe_queue)
166{
167 struct list_head *xmitframe_plist, *xmitframe_phead;
168 struct xmit_frame *pxmitframe = NULL;
169
170 xmitframe_phead = get_list_head(pframe_queue);
171 xmitframe_plist = get_next(xmitframe_phead);
172 if ((end_of_queue_search(xmitframe_phead, xmitframe_plist)) == false) {
173 pxmitframe = LIST_CONTAINOR(xmitframe_plist,
174 struct xmit_frame, list);
175 list_delete(&pxmitframe->list);
176 ptxservq->qcnt--;
177 phwxmit->txcmdcnt++;
178 }
179 return pxmitframe;
180}
181
182static struct xmit_frame *dequeue_xframe_ex(struct xmit_priv *pxmitpriv,
183 struct hw_xmit *phwxmit_i, sint entry)
184{
185 unsigned long irqL0;
186 struct list_head *sta_plist, *sta_phead;
187 struct hw_xmit *phwxmit;
188 struct tx_servq *ptxservq = NULL;
189 struct __queue *pframe_queue = NULL;
190 struct xmit_frame *pxmitframe = NULL;
191 int i, inx[4];
192 int j, tmp, acirp_cnt[4];
193
194 /*entry indx: 0->vo, 1->vi, 2->be, 3->bk.*/
195 inx[0] = 0; acirp_cnt[0] = pxmitpriv->voq_cnt;
196 inx[1] = 1; acirp_cnt[1] = pxmitpriv->viq_cnt;
197 inx[2] = 2; acirp_cnt[2] = pxmitpriv->beq_cnt;
198 inx[3] = 3; acirp_cnt[3] = pxmitpriv->bkq_cnt;
199 for (i = 0; i < 4; i++) {
200 for (j = i + 1; j < 4; j++) {
201 if (acirp_cnt[j] < acirp_cnt[i]) {
202 tmp = acirp_cnt[i];
203 acirp_cnt[i] = acirp_cnt[j];
204 acirp_cnt[j] = tmp;
205 tmp = inx[i];
206 inx[i] = inx[j];
207 inx[j] = tmp;
208 }
209 }
210 }
211 spin_lock_irqsave(&pxmitpriv->lock, irqL0);
212 for (i = 0; i < entry; i++) {
213 phwxmit = phwxmit_i + inx[i];
214 sta_phead = get_list_head(phwxmit->sta_queue);
215 sta_plist = get_next(sta_phead);
216 while ((end_of_queue_search(sta_phead, sta_plist)) == false) {
217 ptxservq = LIST_CONTAINOR(sta_plist, struct tx_servq,
218 tx_pending);
219 pframe_queue = &ptxservq->sta_pending;
220 pxmitframe = dequeue_one_xmitframe(pxmitpriv, phwxmit,
221 ptxservq, pframe_queue);
222 if (pxmitframe) {
223 phwxmit->accnt--;
224 goto exit_dequeue_xframe_ex;
225 }
226 sta_plist = get_next(sta_plist);
227 /*Remove sta node when there are no pending packets.*/
228 if (_queue_empty(pframe_queue)) {
229 /*must be done after get_next and before break*/
230 list_delete(&ptxservq->tx_pending);
231 }
232 }
233 }
234exit_dequeue_xframe_ex:
235 spin_unlock_irqrestore(&pxmitpriv->lock, irqL0);
236 return pxmitframe;
237}
238
239void r8712_do_queue_select(struct _adapter *padapter,
240 struct pkt_attrib *pattrib)
241{
ee5b1aad 242 unsigned int qsel = 0;
2865d42c
LF
243 struct dvobj_priv *pdvobj = (struct dvobj_priv *)&padapter->dvobjpriv;
244
245 if (pdvobj->nr_endpoint == 6)
ee5b1aad
AB
246 qsel = (unsigned int) pattrib->priority;
247 else if (pdvobj->nr_endpoint == 4) {
248 qsel = (unsigned int) pattrib->priority;
249 if (qsel == 0 || qsel == 3)
250 qsel = 3;
251 else if (qsel == 1 || qsel == 2)
252 qsel = 1;
253 else if (qsel == 4 || qsel == 5)
254 qsel = 5;
255 else if (qsel == 6 || qsel == 7)
256 qsel = 7;
257 else
258 qsel = 3;
259 }
2865d42c
LF
260 pattrib->qsel = qsel;
261}
262
263static void update_txdesc(struct xmit_frame *pxmitframe, uint *pmem, int sz)
264{
265 uint qsel;
266 struct _adapter *padapter = pxmitframe->padapter;
267 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
268 struct qos_priv *pqospriv = &pmlmepriv->qospriv;
269 struct security_priv *psecuritypriv = &padapter->securitypriv;
270 struct pkt_attrib *pattrib = &pxmitframe->attrib;
271 struct tx_desc *ptxdesc = (struct tx_desc *)pmem;
272 struct dvobj_priv *pdvobj = (struct dvobj_priv *)&padapter->dvobjpriv;
273 u8 blnSetTxDescOffset;
274 sint bmcst = IS_MCAST(pattrib->ra);
275 struct ht_priv *phtpriv = &pmlmepriv->htpriv;
276 struct tx_desc txdesc_mp;
277
278 memcpy(&txdesc_mp, ptxdesc, sizeof(struct tx_desc));
279 memset(ptxdesc, 0, sizeof(struct tx_desc));
280 /* offset 0 */
281 ptxdesc->txdw0 |= cpu_to_le32(sz&0x0000ffff);
282 if (pdvobj->ishighspeed) {
283 if (((sz + TXDESC_SIZE) % 512) == 0)
284 blnSetTxDescOffset = 1;
285 else
286 blnSetTxDescOffset = 0;
287 } else {
288 if (((sz + TXDESC_SIZE) % 64) == 0)
289 blnSetTxDescOffset = 1;
290 else
291 blnSetTxDescOffset = 0;
292 }
293 if (blnSetTxDescOffset) {
294 /* 32 bytes for TX Desc + 8 bytes pending */
295 ptxdesc->txdw0 |= cpu_to_le32(((TXDESC_SIZE+OFFSET_SZ + 8) <<
296 OFFSET_SHT) & 0x00ff0000);
297 } else {
298 /* default = 32 bytes for TX Desc */
299 ptxdesc->txdw0 |= cpu_to_le32(((TXDESC_SIZE+OFFSET_SZ) <<
300 OFFSET_SHT) & 0x00ff0000);
301 }
302 ptxdesc->txdw0 |= cpu_to_le32(OWN | FSG | LSG);
303 if (pxmitframe->frame_tag == DATA_FRAMETAG) {
304 /* offset 4 */
305 ptxdesc->txdw1 |= cpu_to_le32((pattrib->mac_id)&0x1f);
306 qsel = (uint)(pattrib->qsel & 0x0000001f);
307 ptxdesc->txdw1 |= cpu_to_le32((qsel << QSEL_SHT) & 0x00001f00);
308 if (!pqospriv->qos_option)
309 ptxdesc->txdw1 |= cpu_to_le32(BIT(16));/*Non-QoS*/
310 if ((pattrib->encrypt > 0) && !pattrib->bswenc) {
311 switch (pattrib->encrypt) { /*SEC_TYPE*/
312 case _WEP40_:
313 case _WEP104_:
314 ptxdesc->txdw1 |= cpu_to_le32((0x01 << 22) &
315 0x00c00000);
316 /*KEY_ID when WEP is used;*/
317 ptxdesc->txdw1 |= cpu_to_le32((psecuritypriv->
318 PrivacyKeyIndex << 17) &
319 0x00060000);
320 break;
321 case _TKIP_:
322 case _TKIP_WTMIC_:
323 ptxdesc->txdw1 |= cpu_to_le32((0x02 << 22) &
324 0x00c00000);
325 break;
326 case _AES_:
327 ptxdesc->txdw1 |= cpu_to_le32((0x03 << 22) &
328 0x00c00000);
329 break;
330 case _NO_PRIVACY_:
331 default:
332 break;
333 }
334 }
335 /*offset 8*/
336 if (bmcst)
337 ptxdesc->txdw2 |= cpu_to_le32(BMC);
338
339 /*offset 12*/
340 /* f/w will increase the seqnum by itself, driver pass the
341 * correct priority to fw
342 * fw will check the correct priority for increasing the
343 * seqnum per tid. about usb using 4-endpoint, qsel points out
344 * the correct mapping between AC&Endpoint,
345 * the purpose is that correct mapping lets the MAC release
346 * the AC Queue list correctly. */
347 ptxdesc->txdw3 = cpu_to_le32((pattrib->priority << SEQ_SHT) &
348 0x0fff0000);
349 if ((pattrib->ether_type != 0x888e) &&
350 (pattrib->ether_type != 0x0806) &&
351 (pattrib->dhcp_pkt != 1)) {
352 /*Not EAP & ARP type data packet*/
353 if (phtpriv->ht_option == 1) { /*B/G/N Mode*/
354 if (phtpriv->ampdu_enable != true)
355 ptxdesc->txdw2 |= cpu_to_le32(BK);
356 }
357 } else {
358 /* EAP data packet and ARP packet.
359 * Use the 1M data rate to send the EAP/ARP packet.
360 * This will maybe make the handshake smooth.
361 */
362 /*driver uses data rate*/
363 ptxdesc->txdw4 = cpu_to_le32(0x80000000);
364 ptxdesc->txdw5 = cpu_to_le32(0x001f8000);/*1M*/
365 }
366 if (pattrib->pctrl == 1) { /* mp tx packets */
367 struct tx_desc *ptxdesc_mp;
368 ptxdesc_mp = &txdesc_mp;
369 /* offset 8 */
370 ptxdesc->txdw2 = cpu_to_le32(ptxdesc_mp->txdw2);
371 if (bmcst)
372 ptxdesc->txdw2 |= cpu_to_le32(BMC);
373 ptxdesc->txdw2 |= cpu_to_le32(BK);
374 /* offset 16 */
375 ptxdesc->txdw4 = cpu_to_le32(ptxdesc_mp->txdw4);
376 /* offset 20 */
377 ptxdesc->txdw5 = cpu_to_le32(ptxdesc_mp->txdw5);
378 pattrib->pctrl = 0;/* reset to zero; */
379 }
380 } else if (pxmitframe->frame_tag == MGNT_FRAMETAG) {
381 /* offset 4 */
382 ptxdesc->txdw1 |= (0x05) & 0x1f;/*CAM_ID(MAC_ID), default=5;*/
383 qsel = (uint)(pattrib->qsel & 0x0000001f);
384 ptxdesc->txdw1 |= cpu_to_le32((qsel << QSEL_SHT) & 0x00001f00);
385 ptxdesc->txdw1 |= cpu_to_le32(BIT(16));/* Non-QoS */
386 /* offset 8 */
387 if (bmcst)
388 ptxdesc->txdw2 |= cpu_to_le32(BMC);
389 /* offset 12 */
390 /* f/w will increase the seqnum by itself, driver pass the
391 * correct priority to fw
392 * fw will check the correct priority for increasing the seqnum
393 * per tid. about usb using 4-endpoint, qsel points out the
394 * correct mapping between AC&Endpoint,
395 * the purpose is that correct mapping let the MAC releases
396 * the AC Queue list correctly. */
397 ptxdesc->txdw3 = cpu_to_le32((pattrib->priority << SEQ_SHT) &
398 0x0fff0000);
399 /* offset 16 */
400 ptxdesc->txdw4 = cpu_to_le32(0x80002040);/*gtest*/
401 /* offset 20 */
402 ptxdesc->txdw5 = cpu_to_le32(0x001f8000);/* gtest 1M */
403 } else if (pxmitframe->frame_tag == TXAGG_FRAMETAG) {
404 /* offset 4 */
405 qsel = 0x13;
406 ptxdesc->txdw1 |= cpu_to_le32((qsel << QSEL_SHT) & 0x00001f00);
407 } else {
408 /* offset 4 */
409 qsel = (uint)(pattrib->priority&0x0000001f);
410 ptxdesc->txdw1 |= cpu_to_le32((qsel << QSEL_SHT) & 0x00001f00);
411 /*offset 8*/
412 /*offset 12*/
413 ptxdesc->txdw3 = cpu_to_le32((pattrib->seqnum << SEQ_SHT) &
414 0x0fff0000);
415 /*offset 16*/
416 ptxdesc->txdw4 = cpu_to_le32(0x80002040);/*gtest*/
417 /*offset 20*/
418 ptxdesc->txdw5 = cpu_to_le32(0x001f9600);/*gtest*/
419 }
420}
421
422int r8712_xmitframe_complete(struct _adapter *padapter,
423 struct xmit_priv *pxmitpriv,
424 struct xmit_buf *pxmitbuf)
425{
426 struct hw_xmit *phwxmits;
427 sint hwentry;
428 struct xmit_frame *pxmitframe = NULL;
429 int res = _SUCCESS, xcnt = 0;
430
431 phwxmits = pxmitpriv->hwxmits;
432 hwentry = pxmitpriv->hwxmit_entry;
433 if (pxmitbuf == NULL) {
434 pxmitbuf = r8712_alloc_xmitbuf(pxmitpriv);
435 if (!pxmitbuf)
436 return false;
437 }
07a6b037
AB
438 /* 1st frame dequeued */
439 pxmitframe = dequeue_xframe_ex(pxmitpriv, phwxmits, hwentry);
440 /* need to remember the 1st frame */
441 if (pxmitframe != NULL) {
442
443
444 xmitframe_xmitbuf_attach(pxmitframe, pxmitbuf);
445 if (pxmitframe->frame_tag == DATA_FRAMETAG) {
446 if (pxmitframe->attrib.priority <= 15)
447 res = r8712_xmitframe_coalesce(padapter,
448 pxmitframe->pkt, pxmitframe);
449 /* always return ndis_packet after
450 * r8712_xmitframe_coalesce */
451 r8712_xmit_complete(padapter, pxmitframe);
2865d42c 452 }
07a6b037
AB
453 if (res == _SUCCESS)
454 dump_xframe(padapter, pxmitframe);
455 else
456 r8712_free_xmitframe_ex(pxmitpriv, pxmitframe);
457 xcnt++;
458
459 } else { /* pxmitframe == NULL && p2ndxmitframe == NULL */
460 r8712_free_xmitbuf(pxmitpriv, pxmitbuf);
461 return false;
462 }
2865d42c
LF
463 return true;
464}
465
466static void dump_xframe(struct _adapter *padapter,
467 struct xmit_frame *pxmitframe)
468{
469 int t, sz, w_sz;
470 u8 *mem_addr;
471 u32 ff_hwaddr;
472 struct pkt_attrib *pattrib = &pxmitframe->attrib;
473 struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
474 struct security_priv *psecuritypriv = &padapter->securitypriv;
475
476 if (pxmitframe->attrib.ether_type != 0x0806) {
477 if (pxmitframe->attrib.ether_type != 0x888e)
478 r8712_issue_addbareq_cmd(padapter, pattrib->priority);
479 }
480 mem_addr = pxmitframe->buf_addr;
481 for (t = 0; t < pattrib->nr_frags; t++) {
482 if (t != (pattrib->nr_frags - 1)) {
483 sz = pxmitpriv->frag_len;
484 sz = sz - 4 - (psecuritypriv->sw_encrypt ? 0 :
485 pattrib->icv_len);
486 pxmitframe->last[t] = 0;
487 } else {
488 sz = pattrib->last_txcmdsz;
489 pxmitframe->last[t] = 1;
490 }
491 update_txdesc(pxmitframe, (uint *)mem_addr, sz);
492 w_sz = sz + TXDESC_SIZE;
493 pxmitframe->mem_addr = mem_addr;
494 pxmitframe->bpending[t] = false;
495 ff_hwaddr = get_ff_hwaddr(pxmitframe);
496 r8712_write_port(padapter, ff_hwaddr, w_sz,
497 (unsigned char *)pxmitframe);
498 mem_addr += w_sz;
499 mem_addr = (u8 *)RND4(((addr_t)(mem_addr)));
500 }
501}
502
503int r8712_xmit_direct(struct _adapter *padapter, struct xmit_frame *pxmitframe)
504{
505 int res = _SUCCESS;
506
507 res = r8712_xmitframe_coalesce(padapter, pxmitframe->pkt, pxmitframe);
508 pxmitframe->pkt = NULL;
509 if (res == _SUCCESS)
510 dump_xframe(padapter, pxmitframe);
511 return res;
512}
513
514int r8712_xmit_enqueue(struct _adapter *padapter, struct xmit_frame *pxmitframe)
515{
516 if (r8712_xmit_classifier(padapter, pxmitframe) == _FAIL) {
517 pxmitframe->pkt = NULL;
518 return _FAIL;
519 }
520 return _SUCCESS;
521}
This page took 0.155343 seconds and 5 git commands to generate.