1 /******************************************************************************
4 * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
5 * Linux device driver for RTL8192SU
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.
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
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
20 * Modifications for inclusion into the Linux staging tree are
21 * Copyright(c) 2010 Larry Finger. All rights reserved.
23 * Contact information:
24 * WLAN FAE <wlanfae@realtek.com>
25 * Larry Finger <Larry.Finger@lwfinger.net>
27 ******************************************************************************/
29 #define _RTL8712_XMIT_C_
31 #include "osdep_service.h"
32 #include "drv_types.h"
33 #include "rtl871x_byteorder.h"
35 #include "osdep_intf.h"
38 static void dump_xframe(struct _adapter
*padapter
,
39 struct xmit_frame
*pxmitframe
);
41 sint
_r8712_init_hw_txqueue(struct hw_txqueue
*phw_txqueue
, u8 ac_tag
)
43 phw_txqueue
->ac_tag
= ac_tag
;
46 phw_txqueue
->ff_hwaddr
= RTL8712_DMA_BEQ
;
49 phw_txqueue
->ff_hwaddr
= RTL8712_DMA_BKQ
;
52 phw_txqueue
->ff_hwaddr
= RTL8712_DMA_VIQ
;
55 phw_txqueue
->ff_hwaddr
= RTL8712_DMA_VOQ
;
58 phw_txqueue
->ff_hwaddr
= RTL8712_DMA_BEQ
;
64 int r8712_txframes_sta_ac_pending(struct _adapter
*padapter
,
65 struct pkt_attrib
*pattrib
)
67 struct sta_info
*psta
;
68 struct tx_servq
*ptxservq
;
69 int priority
= pattrib
->priority
;
75 ptxservq
= &(psta
->sta_xmitpriv
.bk_q
);
79 ptxservq
= &(psta
->sta_xmitpriv
.vi_q
);
83 ptxservq
= &(psta
->sta_xmitpriv
.vo_q
);
88 ptxservq
= &(psta
->sta_xmitpriv
.be_q
);
91 return ptxservq
->qcnt
;
94 static u32
get_ff_hwaddr(struct xmit_frame
*pxmitframe
)
97 struct pkt_attrib
*pattrib
= &pxmitframe
->attrib
;
98 struct _adapter
*padapter
= pxmitframe
->padapter
;
99 struct dvobj_priv
*pdvobj
= (struct dvobj_priv
*)&padapter
->dvobjpriv
;
101 if (pxmitframe
->frame_tag
== TXAGG_FRAMETAG
)
102 addr
= RTL8712_DMA_H2CCMD
;
103 else if (pxmitframe
->frame_tag
== MGNT_FRAMETAG
)
104 addr
= RTL8712_DMA_MGTQ
;
105 else if (pdvobj
->nr_endpoint
== 6) {
106 switch (pattrib
->priority
) {
109 addr
= RTL8712_DMA_BEQ
;
113 addr
= RTL8712_DMA_BKQ
;
117 addr
= RTL8712_DMA_VIQ
;
121 addr
= RTL8712_DMA_VOQ
;
127 addr
= RTL8712_DMA_H2CCMD
;
130 addr
= RTL8712_DMA_BEQ
;
133 } else if (pdvobj
->nr_endpoint
== 4) {
134 switch (pattrib
->qsel
) {
139 addr
= RTL8712_DMA_BEQ
;/*RTL8712_EP_LO;*/
145 addr
= RTL8712_DMA_VOQ
;/*RTL8712_EP_HI;*/
151 addr
= RTL8712_DMA_H2CCMD
;
154 addr
= RTL8712_DMA_BEQ
;/*RTL8712_EP_LO;*/
161 static struct xmit_frame
*dequeue_one_xmitframe(struct xmit_priv
*pxmitpriv
,
162 struct hw_xmit
*phwxmit
,
163 struct tx_servq
*ptxservq
,
164 struct __queue
*pframe_queue
)
166 struct list_head
*xmitframe_plist
, *xmitframe_phead
;
167 struct xmit_frame
*pxmitframe
= NULL
;
169 xmitframe_phead
= get_list_head(pframe_queue
);
170 xmitframe_plist
= get_next(xmitframe_phead
);
171 if ((end_of_queue_search(xmitframe_phead
, xmitframe_plist
)) == false) {
172 pxmitframe
= LIST_CONTAINOR(xmitframe_plist
,
173 struct xmit_frame
, list
);
174 list_delete(&pxmitframe
->list
);
181 static struct xmit_frame
*dequeue_xframe_ex(struct xmit_priv
*pxmitpriv
,
182 struct hw_xmit
*phwxmit_i
, sint entry
)
185 struct list_head
*sta_plist
, *sta_phead
;
186 struct hw_xmit
*phwxmit
;
187 struct tx_servq
*ptxservq
= NULL
;
188 struct __queue
*pframe_queue
= NULL
;
189 struct xmit_frame
*pxmitframe
= NULL
;
191 int j
, tmp
, acirp_cnt
[4];
193 /*entry indx: 0->vo, 1->vi, 2->be, 3->bk.*/
194 inx
[0] = 0; acirp_cnt
[0] = pxmitpriv
->voq_cnt
;
195 inx
[1] = 1; acirp_cnt
[1] = pxmitpriv
->viq_cnt
;
196 inx
[2] = 2; acirp_cnt
[2] = pxmitpriv
->beq_cnt
;
197 inx
[3] = 3; acirp_cnt
[3] = pxmitpriv
->bkq_cnt
;
198 for (i
= 0; i
< 4; i
++) {
199 for (j
= i
+ 1; j
< 4; j
++) {
200 if (acirp_cnt
[j
] < acirp_cnt
[i
]) {
202 acirp_cnt
[i
] = acirp_cnt
[j
];
210 spin_lock_irqsave(&pxmitpriv
->lock
, irqL0
);
211 for (i
= 0; i
< entry
; i
++) {
212 phwxmit
= phwxmit_i
+ inx
[i
];
213 sta_phead
= get_list_head(phwxmit
->sta_queue
);
214 sta_plist
= get_next(sta_phead
);
215 while ((end_of_queue_search(sta_phead
, sta_plist
)) == false) {
216 ptxservq
= LIST_CONTAINOR(sta_plist
, struct tx_servq
,
218 pframe_queue
= &ptxservq
->sta_pending
;
219 pxmitframe
= dequeue_one_xmitframe(pxmitpriv
, phwxmit
,
220 ptxservq
, pframe_queue
);
223 goto exit_dequeue_xframe_ex
;
225 sta_plist
= get_next(sta_plist
);
226 /*Remove sta node when there are no pending packets.*/
227 if (_queue_empty(pframe_queue
)) {
228 /*must be done after get_next and before break*/
229 list_delete(&ptxservq
->tx_pending
);
233 exit_dequeue_xframe_ex
:
234 spin_unlock_irqrestore(&pxmitpriv
->lock
, irqL0
);
238 void r8712_do_queue_select(struct _adapter
*padapter
,
239 struct pkt_attrib
*pattrib
)
242 struct dvobj_priv
*pdvobj
= (struct dvobj_priv
*)&padapter
->dvobjpriv
;
244 if (pdvobj
->nr_endpoint
== 6)
245 qsel
= pattrib
->priority
;
246 else if (pdvobj
->nr_endpoint
== 4)
247 qsel
= pattrib
->priority
;
248 pattrib
->qsel
= qsel
;
251 static void update_txdesc(struct xmit_frame
*pxmitframe
, uint
*pmem
, int sz
)
254 struct _adapter
*padapter
= pxmitframe
->padapter
;
255 struct mlme_priv
*pmlmepriv
= &padapter
->mlmepriv
;
256 struct qos_priv
*pqospriv
= &pmlmepriv
->qospriv
;
257 struct security_priv
*psecuritypriv
= &padapter
->securitypriv
;
258 struct pkt_attrib
*pattrib
= &pxmitframe
->attrib
;
259 struct tx_desc
*ptxdesc
= (struct tx_desc
*)pmem
;
260 struct dvobj_priv
*pdvobj
= (struct dvobj_priv
*)&padapter
->dvobjpriv
;
261 u8 blnSetTxDescOffset
;
262 sint bmcst
= IS_MCAST(pattrib
->ra
);
263 struct ht_priv
*phtpriv
= &pmlmepriv
->htpriv
;
264 struct tx_desc txdesc_mp
;
266 memcpy(&txdesc_mp
, ptxdesc
, sizeof(struct tx_desc
));
267 memset(ptxdesc
, 0, sizeof(struct tx_desc
));
269 ptxdesc
->txdw0
|= cpu_to_le32(sz
&0x0000ffff);
270 if (pdvobj
->ishighspeed
) {
271 if (((sz
+ TXDESC_SIZE
) % 512) == 0)
272 blnSetTxDescOffset
= 1;
274 blnSetTxDescOffset
= 0;
276 if (((sz
+ TXDESC_SIZE
) % 64) == 0)
277 blnSetTxDescOffset
= 1;
279 blnSetTxDescOffset
= 0;
281 if (blnSetTxDescOffset
) {
282 /* 32 bytes for TX Desc + 8 bytes pending */
283 ptxdesc
->txdw0
|= cpu_to_le32(((TXDESC_SIZE
+OFFSET_SZ
+ 8) <<
284 OFFSET_SHT
) & 0x00ff0000);
286 /* default = 32 bytes for TX Desc */
287 ptxdesc
->txdw0
|= cpu_to_le32(((TXDESC_SIZE
+OFFSET_SZ
) <<
288 OFFSET_SHT
) & 0x00ff0000);
290 ptxdesc
->txdw0
|= cpu_to_le32(OWN
| FSG
| LSG
);
291 if (pxmitframe
->frame_tag
== DATA_FRAMETAG
) {
293 ptxdesc
->txdw1
|= cpu_to_le32((pattrib
->mac_id
)&0x1f);
294 qsel
= (uint
)(pattrib
->qsel
& 0x0000001f);
295 ptxdesc
->txdw1
|= cpu_to_le32((qsel
<< QSEL_SHT
) & 0x00001f00);
296 if (!pqospriv
->qos_option
)
297 ptxdesc
->txdw1
|= cpu_to_le32(BIT(16));/*Non-QoS*/
298 if ((pattrib
->encrypt
> 0) && !pattrib
->bswenc
) {
299 switch (pattrib
->encrypt
) { /*SEC_TYPE*/
302 ptxdesc
->txdw1
|= cpu_to_le32((0x01 << 22) &
304 /*KEY_ID when WEP is used;*/
305 ptxdesc
->txdw1
|= cpu_to_le32((psecuritypriv
->
306 PrivacyKeyIndex
<< 17) &
311 ptxdesc
->txdw1
|= cpu_to_le32((0x02 << 22) &
315 ptxdesc
->txdw1
|= cpu_to_le32((0x03 << 22) &
325 ptxdesc
->txdw2
|= cpu_to_le32(BMC
);
328 /* f/w will increase the seqnum by itself, driver pass the
329 * correct priority to fw
330 * fw will check the correct priority for increasing the
331 * seqnum per tid. about usb using 4-endpoint, qsel points out
332 * the correct mapping between AC&Endpoint,
333 * the purpose is that correct mapping lets the MAC release
334 * the AC Queue list correctly. */
335 ptxdesc
->txdw3
= cpu_to_le32((pattrib
->priority
<< SEQ_SHT
) &
337 if ((pattrib
->ether_type
!= 0x888e) &&
338 (pattrib
->ether_type
!= 0x0806) &&
339 (pattrib
->dhcp_pkt
!= 1)) {
340 /*Not EAP & ARP type data packet*/
341 if (phtpriv
->ht_option
== 1) { /*B/G/N Mode*/
342 if (phtpriv
->ampdu_enable
!= true)
343 ptxdesc
->txdw2
|= cpu_to_le32(BK
);
346 /* EAP data packet and ARP packet.
347 * Use the 1M data rate to send the EAP/ARP packet.
348 * This will maybe make the handshake smooth.
350 /*driver uses data rate*/
351 ptxdesc
->txdw4
= cpu_to_le32(0x80000000);
352 ptxdesc
->txdw5
= cpu_to_le32(0x001f8000);/*1M*/
354 if (pattrib
->pctrl
== 1) { /* mp tx packets */
355 struct tx_desc
*ptxdesc_mp
;
356 ptxdesc_mp
= &txdesc_mp
;
358 ptxdesc
->txdw2
= cpu_to_le32(ptxdesc_mp
->txdw2
);
360 ptxdesc
->txdw2
|= cpu_to_le32(BMC
);
361 ptxdesc
->txdw2
|= cpu_to_le32(BK
);
363 ptxdesc
->txdw4
= cpu_to_le32(ptxdesc_mp
->txdw4
);
365 ptxdesc
->txdw5
= cpu_to_le32(ptxdesc_mp
->txdw5
);
366 pattrib
->pctrl
= 0;/* reset to zero; */
368 } else if (pxmitframe
->frame_tag
== MGNT_FRAMETAG
) {
370 ptxdesc
->txdw1
|= (0x05) & 0x1f;/*CAM_ID(MAC_ID), default=5;*/
371 qsel
= (uint
)(pattrib
->qsel
& 0x0000001f);
372 ptxdesc
->txdw1
|= cpu_to_le32((qsel
<< QSEL_SHT
) & 0x00001f00);
373 ptxdesc
->txdw1
|= cpu_to_le32(BIT(16));/* Non-QoS */
376 ptxdesc
->txdw2
|= cpu_to_le32(BMC
);
378 /* f/w will increase the seqnum by itself, driver pass the
379 * correct priority to fw
380 * fw will check the correct priority for increasing the seqnum
381 * per tid. about usb using 4-endpoint, qsel points out the
382 * correct mapping between AC&Endpoint,
383 * the purpose is that correct mapping let the MAC releases
384 * the AC Queue list correctly. */
385 ptxdesc
->txdw3
= cpu_to_le32((pattrib
->priority
<< SEQ_SHT
) &
388 ptxdesc
->txdw4
= cpu_to_le32(0x80002040);/*gtest*/
390 ptxdesc
->txdw5
= cpu_to_le32(0x001f8000);/* gtest 1M */
391 } else if (pxmitframe
->frame_tag
== TXAGG_FRAMETAG
) {
394 ptxdesc
->txdw1
|= cpu_to_le32((qsel
<< QSEL_SHT
) & 0x00001f00);
397 qsel
= (uint
)(pattrib
->priority
&0x0000001f);
398 ptxdesc
->txdw1
|= cpu_to_le32((qsel
<< QSEL_SHT
) & 0x00001f00);
401 ptxdesc
->txdw3
= cpu_to_le32((pattrib
->seqnum
<< SEQ_SHT
) &
404 ptxdesc
->txdw4
= cpu_to_le32(0x80002040);/*gtest*/
406 ptxdesc
->txdw5
= cpu_to_le32(0x001f9600);/*gtest*/
410 int r8712_xmitframe_complete(struct _adapter
*padapter
,
411 struct xmit_priv
*pxmitpriv
,
412 struct xmit_buf
*pxmitbuf
)
414 struct hw_xmit
*phwxmits
;
416 struct xmit_frame
*pxmitframe
= NULL
;
417 int res
= _SUCCESS
, xcnt
= 0;
419 phwxmits
= pxmitpriv
->hwxmits
;
420 hwentry
= pxmitpriv
->hwxmit_entry
;
421 if (pxmitbuf
== NULL
) {
422 pxmitbuf
= r8712_alloc_xmitbuf(pxmitpriv
);
427 pxmitframe
= dequeue_xframe_ex(pxmitpriv
, phwxmits
, hwentry
);
429 pxmitframe
->pxmitbuf
= pxmitbuf
;
430 pxmitframe
->pxmit_urb
[0] = pxmitbuf
->pxmit_urb
[0];
431 pxmitframe
->buf_addr
= pxmitbuf
->pbuf
;
432 if (pxmitframe
->frame_tag
== DATA_FRAMETAG
) {
433 if (pxmitframe
->attrib
.priority
<= 15)
434 res
= r8712_xmitframe_coalesce(padapter
,
435 pxmitframe
->pkt
, pxmitframe
);
436 /* always return ndis_packet after
437 * r8712_xmitframe_coalesce */
438 r8712_xmit_complete(padapter
, pxmitframe
);
441 dump_xframe(padapter
, pxmitframe
);
443 r8712_free_xmitframe_ex(pxmitpriv
, pxmitframe
);
446 r8712_free_xmitbuf(pxmitpriv
, pxmitbuf
);
454 static void dump_xframe(struct _adapter
*padapter
,
455 struct xmit_frame
*pxmitframe
)
460 struct pkt_attrib
*pattrib
= &pxmitframe
->attrib
;
461 struct xmit_priv
*pxmitpriv
= &padapter
->xmitpriv
;
462 struct security_priv
*psecuritypriv
= &padapter
->securitypriv
;
464 if (pxmitframe
->attrib
.ether_type
!= 0x0806) {
465 if (pxmitframe
->attrib
.ether_type
!= 0x888e)
466 r8712_issue_addbareq_cmd(padapter
, pattrib
->priority
);
468 mem_addr
= pxmitframe
->buf_addr
;
469 for (t
= 0; t
< pattrib
->nr_frags
; t
++) {
470 if (t
!= (pattrib
->nr_frags
- 1)) {
471 sz
= pxmitpriv
->frag_len
;
472 sz
= sz
- 4 - (psecuritypriv
->sw_encrypt
? 0 :
474 pxmitframe
->last
[t
] = 0;
476 sz
= pattrib
->last_txcmdsz
;
477 pxmitframe
->last
[t
] = 1;
479 update_txdesc(pxmitframe
, (uint
*)mem_addr
, sz
);
480 w_sz
= sz
+ TXDESC_SIZE
;
481 pxmitframe
->mem_addr
= mem_addr
;
482 pxmitframe
->bpending
[t
] = false;
483 ff_hwaddr
= get_ff_hwaddr(pxmitframe
);
484 r8712_write_port(padapter
, ff_hwaddr
, w_sz
,
485 (unsigned char *)pxmitframe
);
487 mem_addr
= (u8
*)RND4(((addr_t
)(mem_addr
)));
491 int r8712_xmit_direct(struct _adapter
*padapter
, struct xmit_frame
*pxmitframe
)
495 res
= r8712_xmitframe_coalesce(padapter
, pxmitframe
->pkt
, pxmitframe
);
496 pxmitframe
->pkt
= NULL
;
498 dump_xframe(padapter
, pxmitframe
);
502 int r8712_xmit_enqueue(struct _adapter
*padapter
, struct xmit_frame
*pxmitframe
)
504 if (r8712_xmit_classifier(padapter
, pxmitframe
) == _FAIL
) {
505 pxmitframe
->pkt
= NULL
;