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); 40static void update_txdesc(struct xmit_frame *pxmitframe, uint *pmem, int sz); 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: 152 addr = RTL8712_DMA_H2CCMD; 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{ 242 unsigned int qsel = 0; 243 struct dvobj_priv *pdvobj = (struct dvobj_priv *)&padapter->dvobjpriv; 244 245 if (pdvobj->nr_endpoint == 6) 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 } 260 pattrib->qsel = qsel; 261} 262 263#ifdef CONFIG_R8712_TX_AGGR 264u8 r8712_construct_txaggr_cmd_desc(struct xmit_buf *pxmitbuf) 265{ 266 struct tx_desc *ptx_desc = (struct tx_desc *)pxmitbuf->pbuf; 267 268 /* Fill up TxCmd Descriptor according as USB FW Tx Aaggregation info.*/ 269 /* dw0 */ 270 ptx_desc->txdw0 = cpu_to_le32(CMD_HDR_SZ&0xffff); 271 ptx_desc->txdw0 |= 272 cpu_to_le32(((TXDESC_SIZE+OFFSET_SZ)<<OFFSET_SHT)&0x00ff0000); 273 ptx_desc->txdw0 |= cpu_to_le32(OWN | FSG | LSG); 274 275 /* dw1 */ 276 ptx_desc->txdw1 |= cpu_to_le32((0x13<<QSEL_SHT)&0x00001f00); 277 278 return _SUCCESS; 279} 280 281u8 r8712_construct_txaggr_cmd_hdr(struct xmit_buf *pxmitbuf) 282{ 283 struct xmit_frame *pxmitframe = (struct xmit_frame *) 284 pxmitbuf->priv_data; 285 struct _adapter *padapter = pxmitframe->padapter; 286 struct cmd_priv *pcmdpriv = &(padapter->cmdpriv); 287 struct cmd_hdr *pcmd_hdr = (struct cmd_hdr *) 288 (pxmitbuf->pbuf + TXDESC_SIZE); 289 290 /* Fill up Cmd Header for USB FW Tx Aggregation.*/ 291 /* dw0 */ 292 pcmd_hdr->cmd_dw0 = cpu_to_le32((GEN_CMD_CODE(_AMSDU_TO_AMPDU) << 16) | 293 (pcmdpriv->cmd_seq << 24)); 294 pcmdpriv->cmd_seq++; 295 296 return _SUCCESS; 297} 298 299u8 r8712_append_mpdu_unit(struct xmit_buf *pxmitbuf, 300 struct xmit_frame *pxmitframe) 301{ 302 struct _adapter *padapter = pxmitframe->padapter; 303 struct tx_desc *ptx_desc = (struct tx_desc *)pxmitbuf->pbuf; 304 int last_txcmdsz = 0; 305 int padding_sz = 0; 306 307 /* 802.3->802.11 convertor */ 308 r8712_xmitframe_coalesce(padapter, pxmitframe->pkt, pxmitframe); 309 /* free skb struct */ 310 r8712_xmit_complete(padapter, pxmitframe); 311 if (pxmitframe->attrib.ether_type != 0x0806) { 312 if ((pxmitframe->attrib.ether_type != 0x888e) && 313 (pxmitframe->attrib.dhcp_pkt != 1)) { 314 r8712_issue_addbareq_cmd(padapter, 315 pxmitframe->attrib.priority); 316 } 317 } 318 pxmitframe->last[0] = 1; 319 update_txdesc(pxmitframe, (uint *)(pxmitframe->buf_addr), 320 pxmitframe->attrib.last_txcmdsz); 321 /*padding zero */ 322 last_txcmdsz = pxmitframe->attrib.last_txcmdsz; 323 padding_sz = (8 - (last_txcmdsz % 8)); 324 if ((last_txcmdsz % 8) != 0) { 325 int i; 326 for (i = 0; i < padding_sz; i++) 327 *(pxmitframe->buf_addr+TXDESC_SIZE+last_txcmdsz+i) = 0; 328 } 329 /* Add the new mpdu's length */ 330 ptx_desc->txdw0 = cpu_to_le32((ptx_desc->txdw0&0xffff0000) | 331 ((ptx_desc->txdw0&0x0000ffff)+ 332 ((TXDESC_SIZE+last_txcmdsz+padding_sz)&0x0000ffff))); 333 334 return _SUCCESS; 335} 336 337 338u8 r8712_xmitframe_aggr_1st(struct xmit_buf *pxmitbuf, 339 struct xmit_frame *pxmitframe) 340{ 341 /* linux complete context doesnt need to protect */ 342 pxmitframe->pxmitbuf = pxmitbuf; 343 pxmitbuf->priv_data = pxmitframe; 344 pxmitframe->pxmit_urb[0] = pxmitbuf->pxmit_urb[0]; 345 /* buffer addr assoc */ 346 pxmitframe->buf_addr = pxmitbuf->pbuf+TXDESC_SIZE+CMD_HDR_SZ; 347 /*RTL8712_DMA_H2CCMD */ 348 r8712_construct_txaggr_cmd_desc(pxmitbuf); 349 r8712_construct_txaggr_cmd_hdr(pxmitbuf); 350 if (r8712_append_mpdu_unit(pxmitbuf, pxmitframe) == _SUCCESS) 351 pxmitbuf->aggr_nr = 1; 352 353 return _SUCCESS; 354} 355 356u16 r8712_xmitframe_aggr_next(struct xmit_buf *pxmitbuf, 357 struct xmit_frame *pxmitframe) 358{ 359 pxmitframe->pxmitbuf = pxmitbuf; 360 pxmitbuf->priv_data = pxmitframe; 361 pxmitframe->pxmit_urb[0] = pxmitbuf->pxmit_urb[0]; 362 /* buffer addr assoc */ 363 pxmitframe->buf_addr = pxmitbuf->pbuf + TXDESC_SIZE + 364 (((struct tx_desc *)pxmitbuf->pbuf)->txdw0 & 0x0000ffff); 365 if (r8712_append_mpdu_unit(pxmitbuf, pxmitframe) == _SUCCESS) { 366 r8712_free_xmitframe_ex(&pxmitframe->padapter->xmitpriv, 367 pxmitframe); 368 pxmitbuf->aggr_nr++; 369 } 370 371 return TXDESC_SIZE + 372 (((struct tx_desc *)pxmitbuf->pbuf)->txdw0 & 0x0000ffff); 373} 374 375u8 r8712_dump_aggr_xframe(struct xmit_buf *pxmitbuf, 376 struct xmit_frame *pxmitframe) 377{ 378 struct _adapter *padapter = pxmitframe->padapter; 379 struct dvobj_priv *pdvobj = (struct dvobj_priv *) &padapter->dvobjpriv; 380 struct tx_desc * ptxdesc = (struct tx_desc *)pxmitbuf->pbuf; 381 struct cmd_hdr *pcmd_hdr = (struct cmd_hdr *) 382 (pxmitbuf->pbuf + TXDESC_SIZE); 383 u16 total_length = (u16) (ptxdesc->txdw0 & 0xffff); 384 385 /* use 1st xmitframe as media */ 386 xmitframe_xmitbuf_attach(pxmitframe, pxmitbuf); 387 pcmd_hdr->cmd_dw0 = cpu_to_le32(((total_length-CMD_HDR_SZ)&0x0000ffff)| 388 (pcmd_hdr->cmd_dw0&0xffff0000)); 389 390 /* urb length in cmd_dw1 */ 391 pcmd_hdr->cmd_dw1 = cpu_to_le32((pxmitbuf->aggr_nr & 0xff)| 392 ((total_length+TXDESC_SIZE) << 16)); 393 pxmitframe->last[0] = 1; 394 pxmitframe->bpending[0] = false; 395 pxmitframe->mem_addr = pxmitbuf->pbuf; 396 397 if ((pdvobj->ishighspeed && ((total_length+TXDESC_SIZE)%0x200) == 0) || 398 ((!pdvobj->ishighspeed && 399 ((total_length+TXDESC_SIZE)%0x40) == 0))) { 400 ptxdesc->txdw0 |= cpu_to_le32 401 (((TXDESC_SIZE+OFFSET_SZ+8)<<OFFSET_SHT)&0x00ff0000); 402 /*32 bytes for TX Desc + 8 bytes pending*/ 403 } else { 404 ptxdesc->txdw0 |= cpu_to_le32 405 (((TXDESC_SIZE+OFFSET_SZ)<<OFFSET_SHT)&0x00ff0000); 406 /*default = 32 bytes for TX Desc*/ 407 } 408 r8712_write_port(pxmitframe->padapter, RTL8712_DMA_H2CCMD, 409 total_length+TXDESC_SIZE, (u8 *)pxmitframe); 410 411 return _SUCCESS; 412} 413 414#endif 415 416static void update_txdesc(struct xmit_frame *pxmitframe, uint *pmem, int sz) 417{ 418 uint qsel; 419 struct _adapter *padapter = pxmitframe->padapter; 420 struct mlme_priv *pmlmepriv = &padapter->mlmepriv; 421 struct qos_priv *pqospriv = &pmlmepriv->qospriv; 422 struct security_priv *psecuritypriv = &padapter->securitypriv; 423 struct pkt_attrib *pattrib = &pxmitframe->attrib; 424 struct tx_desc *ptxdesc = (struct tx_desc *)pmem; 425 struct dvobj_priv *pdvobj = (struct dvobj_priv *)&padapter->dvobjpriv; 426#ifdef CONFIG_R8712_TX_AGGR 427 struct cmd_priv *pcmdpriv = (struct cmd_priv *)&padapter->cmdpriv; 428#endif 429 u8 blnSetTxDescOffset; 430 sint bmcst = IS_MCAST(pattrib->ra); 431 struct ht_priv *phtpriv = &pmlmepriv->htpriv; 432 struct tx_desc txdesc_mp; 433 434 memcpy(&txdesc_mp, ptxdesc, sizeof(struct tx_desc)); 435 memset(ptxdesc, 0, sizeof(struct tx_desc)); 436 /* offset 0 */ 437 ptxdesc->txdw0 |= cpu_to_le32(sz&0x0000ffff); 438 if (pdvobj->ishighspeed) { 439 if (((sz + TXDESC_SIZE) % 512) == 0) 440 blnSetTxDescOffset = 1; 441 else 442 blnSetTxDescOffset = 0; 443 } else { 444 if (((sz + TXDESC_SIZE) % 64) == 0) 445 blnSetTxDescOffset = 1; 446 else 447 blnSetTxDescOffset = 0; 448 } 449 if (blnSetTxDescOffset) { 450 /* 32 bytes for TX Desc + 8 bytes pending */ 451 ptxdesc->txdw0 |= cpu_to_le32(((TXDESC_SIZE+OFFSET_SZ + 8) << 452 OFFSET_SHT) & 0x00ff0000); 453 } else { 454 /* default = 32 bytes for TX Desc */ 455 ptxdesc->txdw0 |= cpu_to_le32(((TXDESC_SIZE+OFFSET_SZ) << 456 OFFSET_SHT) & 0x00ff0000); 457 } 458 ptxdesc->txdw0 |= cpu_to_le32(OWN | FSG | LSG); 459 if (pxmitframe->frame_tag == DATA_FRAMETAG) { 460 /* offset 4 */ 461 ptxdesc->txdw1 |= cpu_to_le32((pattrib->mac_id)&0x1f); 462 463#ifdef CONFIG_R8712_TX_AGGR 464 /* dirty workaround, need to check if it is aggr cmd. */ 465 if ((u8 *)pmem != (u8 *)pxmitframe->pxmitbuf->pbuf) { 466 ptxdesc->txdw0 |= cpu_to_le32 467 ((0x3 << TYPE_SHT)&TYPE_MSK); 468 qsel = (uint)(pattrib->qsel & 0x0000001f); 469 if (qsel == 2) 470 qsel = 0; 471 ptxdesc->txdw1 |= cpu_to_le32 472 ((qsel << QSEL_SHT) & 0x00001f00); 473 ptxdesc->txdw2 = cpu_to_le32 474 ((qsel << RTS_RC_SHT)&0x001f0000); 475 ptxdesc->txdw6 |= cpu_to_le32 476 ((0x5 << RSVD6_SHT)&RSVD6_MSK); 477 } else { 478 ptxdesc->txdw0 |= cpu_to_le32 479 ((0x3 << TYPE_SHT)&TYPE_MSK); 480 ptxdesc->txdw1 |= cpu_to_le32 481 ((0x13 << QSEL_SHT) & 0x00001f00); 482 qsel = (uint)(pattrib->qsel & 0x0000001f); 483 if (qsel == 2) 484 qsel = 0; 485 ptxdesc->txdw2 = cpu_to_le32 486 ((qsel << RTS_RC_SHT)&0x0001f000); 487 ptxdesc->txdw7 |= cpu_to_le32 488 (pcmdpriv->cmd_seq << 24); 489 pcmdpriv->cmd_seq++; 490 } 491 pattrib->qsel = 0x13; 492#else 493 qsel = (uint)(pattrib->qsel & 0x0000001f); 494 ptxdesc->txdw1 |= cpu_to_le32((qsel << QSEL_SHT) & 0x00001f00); 495#endif 496 if (!pqospriv->qos_option) 497 ptxdesc->txdw1 |= cpu_to_le32(BIT(16));/*Non-QoS*/ 498 if ((pattrib->encrypt > 0) && !pattrib->bswenc) { 499 switch (pattrib->encrypt) { /*SEC_TYPE*/ 500 case _WEP40_: 501 case _WEP104_: 502 ptxdesc->txdw1 |= cpu_to_le32((0x01 << 22) & 503 0x00c00000); 504 /*KEY_ID when WEP is used;*/ 505 ptxdesc->txdw1 |= cpu_to_le32((psecuritypriv-> 506 PrivacyKeyIndex << 17) & 507 0x00060000); 508 break; 509 case _TKIP_: 510 case _TKIP_WTMIC_: 511 ptxdesc->txdw1 |= cpu_to_le32((0x02 << 22) & 512 0x00c00000); 513 break; 514 case _AES_: 515 ptxdesc->txdw1 |= cpu_to_le32((0x03 << 22) & 516 0x00c00000); 517 break; 518 case _NO_PRIVACY_: 519 default: 520 break; 521 } 522 } 523 /*offset 8*/ 524 if (bmcst) 525 ptxdesc->txdw2 |= cpu_to_le32(BMC); 526 527 /*offset 12*/ 528 /* f/w will increase the seqnum by itself, driver pass the 529 * correct priority to fw 530 * fw will check the correct priority for increasing the 531 * seqnum per tid. about usb using 4-endpoint, qsel points out 532 * the correct mapping between AC&Endpoint, 533 * the purpose is that correct mapping lets the MAC release 534 * the AC Queue list correctly. */ 535 ptxdesc->txdw3 = cpu_to_le32((pattrib->priority << SEQ_SHT) & 536 0x0fff0000); 537 if ((pattrib->ether_type != 0x888e) && 538 (pattrib->ether_type != 0x0806) && 539 (pattrib->dhcp_pkt != 1)) { 540 /*Not EAP & ARP type data packet*/ 541 if (phtpriv->ht_option == 1) { /*B/G/N Mode*/ 542 if (phtpriv->ampdu_enable != true) 543 ptxdesc->txdw2 |= cpu_to_le32(BK); 544 } 545 } else { 546 /* EAP data packet and ARP packet. 547 * Use the 1M data rate to send the EAP/ARP packet. 548 * This will maybe make the handshake smooth. 549 */ 550 /*driver uses data rate*/ 551 ptxdesc->txdw4 = cpu_to_le32(0x80000000); 552 ptxdesc->txdw5 = cpu_to_le32(0x001f8000);/*1M*/ 553 } 554 if (pattrib->pctrl == 1) { /* mp tx packets */ 555 struct tx_desc *ptxdesc_mp; 556 ptxdesc_mp = &txdesc_mp; 557 /* offset 8 */ 558 ptxdesc->txdw2 = cpu_to_le32(ptxdesc_mp->txdw2); 559 if (bmcst) 560 ptxdesc->txdw2 |= cpu_to_le32(BMC); 561 ptxdesc->txdw2 |= cpu_to_le32(BK); 562 /* offset 16 */ 563 ptxdesc->txdw4 = cpu_to_le32(ptxdesc_mp->txdw4); 564 /* offset 20 */ 565 ptxdesc->txdw5 = cpu_to_le32(ptxdesc_mp->txdw5); 566 pattrib->pctrl = 0;/* reset to zero; */ 567 } 568 } else if (pxmitframe->frame_tag == MGNT_FRAMETAG) { 569 /* offset 4 */ 570 ptxdesc->txdw1 |= (0x05) & 0x1f;/*CAM_ID(MAC_ID), default=5;*/ 571 qsel = (uint)(pattrib->qsel & 0x0000001f); 572 ptxdesc->txdw1 |= cpu_to_le32((qsel << QSEL_SHT) & 0x00001f00); 573 ptxdesc->txdw1 |= cpu_to_le32(BIT(16));/* Non-QoS */ 574 /* offset 8 */ 575 if (bmcst) 576 ptxdesc->txdw2 |= cpu_to_le32(BMC); 577 /* offset 12 */ 578 /* f/w will increase the seqnum by itself, driver pass the 579 * correct priority to fw 580 * fw will check the correct priority for increasing the seqnum 581 * per tid. about usb using 4-endpoint, qsel points out the 582 * correct mapping between AC&Endpoint, 583 * the purpose is that correct mapping let the MAC releases 584 * the AC Queue list correctly. */ 585 ptxdesc->txdw3 = cpu_to_le32((pattrib->priority << SEQ_SHT) & 586 0x0fff0000); 587 /* offset 16 */ 588 ptxdesc->txdw4 = cpu_to_le32(0x80002040);/*gtest*/ 589 /* offset 20 */ 590 ptxdesc->txdw5 = cpu_to_le32(0x001f8000);/* gtest 1M */ 591 } else if (pxmitframe->frame_tag == TXAGG_FRAMETAG) { 592 /* offset 4 */ 593 qsel = 0x13; 594 ptxdesc->txdw1 |= cpu_to_le32((qsel << QSEL_SHT) & 0x00001f00); 595 } else { 596 /* offset 4 */ 597 qsel = (uint)(pattrib->priority&0x0000001f); 598 ptxdesc->txdw1 |= cpu_to_le32((qsel << QSEL_SHT) & 0x00001f00); 599 /*offset 8*/ 600 /*offset 12*/ 601 ptxdesc->txdw3 = cpu_to_le32((pattrib->seqnum << SEQ_SHT) & 602 0x0fff0000); 603 /*offset 16*/ 604 ptxdesc->txdw4 = cpu_to_le32(0x80002040);/*gtest*/ 605 /*offset 20*/ 606 ptxdesc->txdw5 = cpu_to_le32(0x001f9600);/*gtest*/ 607 } 608} 609 610int r8712_xmitframe_complete(struct _adapter *padapter, 611 struct xmit_priv *pxmitpriv, 612 struct xmit_buf *pxmitbuf) 613{ 614 struct hw_xmit *phwxmits; 615 sint hwentry; 616 struct xmit_frame *pxmitframe = NULL; 617#ifdef CONFIG_R8712_TX_AGGR 618 struct xmit_frame *p2ndxmitframe = NULL; 619#else 620 int res = _SUCCESS, xcnt = 0; 621#endif 622 623 phwxmits = pxmitpriv->hwxmits; 624 hwentry = pxmitpriv->hwxmit_entry; 625 if (pxmitbuf == NULL) { 626 pxmitbuf = r8712_alloc_xmitbuf(pxmitpriv); 627 if (!pxmitbuf) 628 return false; 629#ifdef CONFIG_R8712_TX_AGGR 630 pxmitbuf->aggr_nr = 0; 631#endif 632 } 633 /* 1st frame dequeued */ 634 pxmitframe = dequeue_xframe_ex(pxmitpriv, phwxmits, hwentry); 635 /* need to remember the 1st frame */ 636 if (pxmitframe != NULL) { 637 638#ifdef CONFIG_R8712_TX_AGGR 639 /* 1. dequeue 2nd frame 640 * 2. aggr if 2nd xframe is dequeued, else dump directly 641 */ 642 if (AGGR_NR_HIGH_BOUND > 1) 643 p2ndxmitframe = dequeue_xframe_ex(pxmitpriv, phwxmits, 644 hwentry); 645 if (pxmitframe->frame_tag != DATA_FRAMETAG) { 646 r8712_free_xmitbuf(pxmitpriv, pxmitbuf); 647 return false; 648 } 649 if (p2ndxmitframe != NULL) 650 if (p2ndxmitframe->frame_tag != DATA_FRAMETAG) { 651 r8712_free_xmitbuf(pxmitpriv, pxmitbuf); 652 return false; 653 } 654 r8712_xmitframe_aggr_1st(pxmitbuf, pxmitframe); 655 if (p2ndxmitframe != NULL) { 656 u16 total_length; 657 total_length = r8712_xmitframe_aggr_next( 658 pxmitbuf, p2ndxmitframe); 659 do { 660 p2ndxmitframe = dequeue_xframe_ex( 661 pxmitpriv, phwxmits, hwentry); 662 if (p2ndxmitframe != NULL) 663 total_length = 664 r8712_xmitframe_aggr_next( 665 pxmitbuf, 666 p2ndxmitframe); 667 else 668 break; 669 } while (total_length <= 0x1800 && 670 pxmitbuf->aggr_nr <= AGGR_NR_HIGH_BOUND); 671 } 672 if (pxmitbuf->aggr_nr > 0) 673 r8712_dump_aggr_xframe(pxmitbuf, pxmitframe); 674 675#else 676 677 xmitframe_xmitbuf_attach(pxmitframe, pxmitbuf); 678 if (pxmitframe->frame_tag == DATA_FRAMETAG) { 679 if (pxmitframe->attrib.priority <= 15) 680 res = r8712_xmitframe_coalesce(padapter, 681 pxmitframe->pkt, pxmitframe); 682 /* always return ndis_packet after 683 * r8712_xmitframe_coalesce */ 684 r8712_xmit_complete(padapter, pxmitframe); 685 } 686 if (res == _SUCCESS) 687 dump_xframe(padapter, pxmitframe); 688 else 689 r8712_free_xmitframe_ex(pxmitpriv, pxmitframe); 690 xcnt++; 691#endif 692 693 } else { /* pxmitframe == NULL && p2ndxmitframe == NULL */ 694 r8712_free_xmitbuf(pxmitpriv, pxmitbuf); 695 return false; 696 } 697 return true; 698} 699 700static void dump_xframe(struct _adapter *padapter, 701 struct xmit_frame *pxmitframe) 702{ 703 int t, sz, w_sz; 704 u8 *mem_addr; 705 u32 ff_hwaddr; 706 struct pkt_attrib *pattrib = &pxmitframe->attrib; 707 struct xmit_priv *pxmitpriv = &padapter->xmitpriv; 708 struct security_priv *psecuritypriv = &padapter->securitypriv; 709 710 if (pxmitframe->attrib.ether_type != 0x0806) { 711 if (pxmitframe->attrib.ether_type != 0x888e) 712 r8712_issue_addbareq_cmd(padapter, pattrib->priority); 713 } 714 mem_addr = pxmitframe->buf_addr; 715 for (t = 0; t < pattrib->nr_frags; t++) { 716 if (t != (pattrib->nr_frags - 1)) { 717 sz = pxmitpriv->frag_len; 718 sz = sz - 4 - (psecuritypriv->sw_encrypt ? 0 : 719 pattrib->icv_len); 720 pxmitframe->last[t] = 0; 721 } else { 722 sz = pattrib->last_txcmdsz; 723 pxmitframe->last[t] = 1; 724 } 725 update_txdesc(pxmitframe, (uint *)mem_addr, sz); 726 w_sz = sz + TXDESC_SIZE; 727 pxmitframe->mem_addr = mem_addr; 728 pxmitframe->bpending[t] = false; 729 ff_hwaddr = get_ff_hwaddr(pxmitframe); 730#ifdef CONFIG_R8712_TX_AGGR 731 r8712_write_port(padapter, RTL8712_DMA_H2CCMD, w_sz, 732 (unsigned char *)pxmitframe); 733#else 734 r8712_write_port(padapter, ff_hwaddr, w_sz, 735 (unsigned char *)pxmitframe); 736#endif 737 mem_addr += w_sz; 738 mem_addr = (u8 *)RND4(((addr_t)(mem_addr))); 739 } 740} 741 742int r8712_xmit_direct(struct _adapter *padapter, struct xmit_frame *pxmitframe) 743{ 744 int res = _SUCCESS; 745 746 res = r8712_xmitframe_coalesce(padapter, pxmitframe->pkt, pxmitframe); 747 pxmitframe->pkt = NULL; 748 if (res == _SUCCESS) 749 dump_xframe(padapter, pxmitframe); 750 return res; 751} 752 753int r8712_xmit_enqueue(struct _adapter *padapter, struct xmit_frame *pxmitframe) 754{ 755 if (r8712_xmit_classifier(padapter, pxmitframe) == _FAIL) { 756 pxmitframe->pkt = NULL; 757 return _FAIL; 758 } 759 return _SUCCESS; 760} 761