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 "wifi.h" 34#include "osdep_intf.h" 35#include "usb_ops.h" 36 37static void dump_xframe(struct _adapter *padapter, 38 struct xmit_frame *pxmitframe); 39static void update_txdesc(struct xmit_frame *pxmitframe, uint *pmem, int sz); 40 41sint _r8712_init_hw_txqueue(struct hw_txqueue *phw_txqueue, u8 ac_tag) 42{ 43 phw_txqueue->ac_tag = ac_tag; 44 switch (ac_tag) { 45 case BE_QUEUE_INX: 46 phw_txqueue->ff_hwaddr = RTL8712_DMA_BEQ; 47 break; 48 case BK_QUEUE_INX: 49 phw_txqueue->ff_hwaddr = RTL8712_DMA_BKQ; 50 break; 51 case VI_QUEUE_INX: 52 phw_txqueue->ff_hwaddr = RTL8712_DMA_VIQ; 53 break; 54 case VO_QUEUE_INX: 55 phw_txqueue->ff_hwaddr = RTL8712_DMA_VOQ; 56 break; 57 case BMC_QUEUE_INX: 58 phw_txqueue->ff_hwaddr = RTL8712_DMA_BEQ; 59 break; 60 } 61 return _SUCCESS; 62} 63 64int r8712_txframes_sta_ac_pending(struct _adapter *padapter, 65 struct pkt_attrib *pattrib) 66{ 67 struct sta_info *psta; 68 struct tx_servq *ptxservq; 69 int priority = pattrib->priority; 70 71 psta = pattrib->psta; 72 switch (priority) { 73 case 1: 74 case 2: 75 ptxservq = &(psta->sta_xmitpriv.bk_q); 76 break; 77 case 4: 78 case 5: 79 ptxservq = &(psta->sta_xmitpriv.vi_q); 80 break; 81 case 6: 82 case 7: 83 ptxservq = &(psta->sta_xmitpriv.vo_q); 84 break; 85 case 0: 86 case 3: 87 default: 88 ptxservq = &(psta->sta_xmitpriv.be_q); 89 break; 90 } 91 return ptxservq->qcnt; 92} 93 94static u32 get_ff_hwaddr(struct xmit_frame *pxmitframe) 95{ 96 u32 addr = 0; 97 struct pkt_attrib *pattrib = &pxmitframe->attrib; 98 struct _adapter *padapter = pxmitframe->padapter; 99 struct dvobj_priv *pdvobj = (struct dvobj_priv *)&padapter->dvobjpriv; 100 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) { 107 case 0: 108 case 3: 109 addr = RTL8712_DMA_BEQ; 110 break; 111 case 1: 112 case 2: 113 addr = RTL8712_DMA_BKQ; 114 break; 115 case 4: 116 case 5: 117 addr = RTL8712_DMA_VIQ; 118 break; 119 case 6: 120 case 7: 121 addr = RTL8712_DMA_VOQ; 122 break; 123 case 0x10: 124 case 0x11: 125 case 0x12: 126 case 0x13: 127 addr = RTL8712_DMA_H2CCMD; 128 break; 129 default: 130 addr = RTL8712_DMA_BEQ; 131 break; 132 } 133 } else if (pdvobj->nr_endpoint == 4) { 134 switch (pattrib->qsel) { 135 case 0: 136 case 3: 137 case 1: 138 case 2: 139 addr = RTL8712_DMA_BEQ;/*RTL8712_EP_LO;*/ 140 break; 141 case 4: 142 case 5: 143 case 6: 144 case 7: 145 addr = RTL8712_DMA_VOQ;/*RTL8712_EP_HI;*/ 146 break; 147 case 0x10: 148 case 0x11: 149 case 0x12: 150 case 0x13: 151 addr = RTL8712_DMA_H2CCMD; 152 break; 153 default: 154 addr = RTL8712_DMA_BEQ;/*RTL8712_EP_LO;*/ 155 break; 156 } 157 } 158 return addr; 159} 160 161static 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) 165{ 166 struct list_head *xmitframe_plist, *xmitframe_phead; 167 struct xmit_frame *pxmitframe = NULL; 168 169 xmitframe_phead = &pframe_queue->queue; 170 xmitframe_plist = xmitframe_phead->next; 171 if ((end_of_queue_search(xmitframe_phead, xmitframe_plist)) == false) { 172 pxmitframe = LIST_CONTAINOR(xmitframe_plist, 173 struct xmit_frame, list); 174 list_del_init(&pxmitframe->list); 175 ptxservq->qcnt--; 176 phwxmit->txcmdcnt++; 177 } 178 return pxmitframe; 179} 180 181static struct xmit_frame *dequeue_xframe_ex(struct xmit_priv *pxmitpriv, 182 struct hw_xmit *phwxmit_i, sint entry) 183{ 184 unsigned long irqL0; 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; 190 int i, inx[4]; 191 int j, tmp, acirp_cnt[4]; 192 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]) { 201 tmp = acirp_cnt[i]; 202 acirp_cnt[i] = acirp_cnt[j]; 203 acirp_cnt[j] = tmp; 204 tmp = inx[i]; 205 inx[i] = inx[j]; 206 inx[j] = tmp; 207 } 208 } 209 } 210 spin_lock_irqsave(&pxmitpriv->lock, irqL0); 211 for (i = 0; i < entry; i++) { 212 phwxmit = phwxmit_i + inx[i]; 213 sta_phead = &phwxmit->sta_queue->queue; 214 sta_plist = sta_phead->next; 215 while ((end_of_queue_search(sta_phead, sta_plist)) == false) { 216 ptxservq = LIST_CONTAINOR(sta_plist, struct tx_servq, 217 tx_pending); 218 pframe_queue = &ptxservq->sta_pending; 219 pxmitframe = dequeue_one_xmitframe(pxmitpriv, phwxmit, 220 ptxservq, pframe_queue); 221 if (pxmitframe) { 222 phwxmit->accnt--; 223 goto exit_dequeue_xframe_ex; 224 } 225 sta_plist = sta_plist->next; 226 /*Remove sta node when there are no pending packets.*/ 227 if (list_empty(&pframe_queue->queue)) { 228 /* must be done after sta_plist->next 229 * and before break 230 */ 231 list_del_init(&ptxservq->tx_pending); 232 } 233 } 234 } 235exit_dequeue_xframe_ex: 236 spin_unlock_irqrestore(&pxmitpriv->lock, irqL0); 237 return pxmitframe; 238} 239 240void r8712_do_queue_select(struct _adapter *padapter, 241 struct pkt_attrib *pattrib) 242{ 243 unsigned int qsel = 0; 244 struct dvobj_priv *pdvobj = (struct dvobj_priv *)&padapter->dvobjpriv; 245 246 if (pdvobj->nr_endpoint == 6) 247 qsel = (unsigned int) pattrib->priority; 248 else if (pdvobj->nr_endpoint == 4) { 249 qsel = (unsigned int) pattrib->priority; 250 if (qsel == 0 || qsel == 3) 251 qsel = 3; 252 else if (qsel == 1 || qsel == 2) 253 qsel = 1; 254 else if (qsel == 4 || qsel == 5) 255 qsel = 5; 256 else if (qsel == 6 || qsel == 7) 257 qsel = 7; 258 else 259 qsel = 3; 260 } 261 pattrib->qsel = qsel; 262} 263 264#ifdef CONFIG_R8712_TX_AGGR 265u8 r8712_construct_txaggr_cmd_desc(struct xmit_buf *pxmitbuf) 266{ 267 struct tx_desc *ptx_desc = (struct tx_desc *)pxmitbuf->pbuf; 268 269 /* Fill up TxCmd Descriptor according as USB FW Tx Aaggregation info.*/ 270 /* dw0 */ 271 ptx_desc->txdw0 = cpu_to_le32(CMD_HDR_SZ&0xffff); 272 ptx_desc->txdw0 |= 273 cpu_to_le32(((TXDESC_SIZE+OFFSET_SZ)<<OFFSET_SHT)&0x00ff0000); 274 ptx_desc->txdw0 |= cpu_to_le32(OWN | FSG | LSG); 275 276 /* dw1 */ 277 ptx_desc->txdw1 |= cpu_to_le32((0x13<<QSEL_SHT)&0x00001f00); 278 279 return _SUCCESS; 280} 281 282u8 r8712_construct_txaggr_cmd_hdr(struct xmit_buf *pxmitbuf) 283{ 284 struct xmit_frame *pxmitframe = (struct xmit_frame *) 285 pxmitbuf->priv_data; 286 struct _adapter *padapter = pxmitframe->padapter; 287 struct cmd_priv *pcmdpriv = &(padapter->cmdpriv); 288 struct cmd_hdr *pcmd_hdr = (struct cmd_hdr *) 289 (pxmitbuf->pbuf + TXDESC_SIZE); 290 291 /* Fill up Cmd Header for USB FW Tx Aggregation.*/ 292 /* dw0 */ 293 pcmd_hdr->cmd_dw0 = cpu_to_le32((GEN_CMD_CODE(_AMSDU_TO_AMPDU) << 16) | 294 (pcmdpriv->cmd_seq << 24)); 295 pcmdpriv->cmd_seq++; 296 297 return _SUCCESS; 298} 299 300u8 r8712_append_mpdu_unit(struct xmit_buf *pxmitbuf, 301 struct xmit_frame *pxmitframe) 302{ 303 struct _adapter *padapter = pxmitframe->padapter; 304 struct tx_desc *ptx_desc = (struct tx_desc *)pxmitbuf->pbuf; 305 int last_txcmdsz = 0; 306 int padding_sz = 0; 307 308 /* 802.3->802.11 convertor */ 309 r8712_xmitframe_coalesce(padapter, pxmitframe->pkt, pxmitframe); 310 /* free skb struct */ 311 r8712_xmit_complete(padapter, pxmitframe); 312 if (pxmitframe->attrib.ether_type != 0x0806) { 313 if ((pxmitframe->attrib.ether_type != 0x888e) && 314 (pxmitframe->attrib.dhcp_pkt != 1)) { 315 r8712_issue_addbareq_cmd(padapter, 316 pxmitframe->attrib.priority); 317 } 318 } 319 pxmitframe->last[0] = 1; 320 update_txdesc(pxmitframe, (uint *)(pxmitframe->buf_addr), 321 pxmitframe->attrib.last_txcmdsz); 322 /*padding zero */ 323 last_txcmdsz = pxmitframe->attrib.last_txcmdsz; 324 padding_sz = (8 - (last_txcmdsz % 8)); 325 if ((last_txcmdsz % 8) != 0) { 326 int i; 327 328 for (i = 0; i < padding_sz; i++) 329 *(pxmitframe->buf_addr+TXDESC_SIZE+last_txcmdsz+i) = 0; 330 } 331 /* Add the new mpdu's length */ 332 ptx_desc->txdw0 = cpu_to_le32((ptx_desc->txdw0&0xffff0000) | 333 ((ptx_desc->txdw0&0x0000ffff)+ 334 ((TXDESC_SIZE+last_txcmdsz+padding_sz)&0x0000ffff))); 335 336 return _SUCCESS; 337} 338 339 340u8 r8712_xmitframe_aggr_1st(struct xmit_buf *pxmitbuf, 341 struct xmit_frame *pxmitframe) 342{ 343 /* linux complete context doesnt need to protect */ 344 pxmitframe->pxmitbuf = pxmitbuf; 345 pxmitbuf->priv_data = pxmitframe; 346 pxmitframe->pxmit_urb[0] = pxmitbuf->pxmit_urb[0]; 347 /* buffer addr assoc */ 348 pxmitframe->buf_addr = pxmitbuf->pbuf+TXDESC_SIZE+CMD_HDR_SZ; 349 /*RTL8712_DMA_H2CCMD */ 350 r8712_construct_txaggr_cmd_desc(pxmitbuf); 351 r8712_construct_txaggr_cmd_hdr(pxmitbuf); 352 if (r8712_append_mpdu_unit(pxmitbuf, pxmitframe) == _SUCCESS) 353 pxmitbuf->aggr_nr = 1; 354 355 return _SUCCESS; 356} 357 358u16 r8712_xmitframe_aggr_next(struct xmit_buf *pxmitbuf, 359 struct xmit_frame *pxmitframe) 360{ 361 pxmitframe->pxmitbuf = pxmitbuf; 362 pxmitbuf->priv_data = pxmitframe; 363 pxmitframe->pxmit_urb[0] = pxmitbuf->pxmit_urb[0]; 364 /* buffer addr assoc */ 365 pxmitframe->buf_addr = pxmitbuf->pbuf + TXDESC_SIZE + 366 (((struct tx_desc *)pxmitbuf->pbuf)->txdw0 & 0x0000ffff); 367 if (r8712_append_mpdu_unit(pxmitbuf, pxmitframe) == _SUCCESS) { 368 r8712_free_xmitframe_ex(&pxmitframe->padapter->xmitpriv, 369 pxmitframe); 370 pxmitbuf->aggr_nr++; 371 } 372 373 return TXDESC_SIZE + 374 (((struct tx_desc *)pxmitbuf->pbuf)->txdw0 & 0x0000ffff); 375} 376 377u8 r8712_dump_aggr_xframe(struct xmit_buf *pxmitbuf, 378 struct xmit_frame *pxmitframe) 379{ 380 struct _adapter *padapter = pxmitframe->padapter; 381 struct dvobj_priv *pdvobj = (struct dvobj_priv *) &padapter->dvobjpriv; 382 struct tx_desc *ptxdesc = (struct tx_desc *)pxmitbuf->pbuf; 383 struct cmd_hdr *pcmd_hdr = (struct cmd_hdr *) 384 (pxmitbuf->pbuf + TXDESC_SIZE); 385 u16 total_length = (u16) (ptxdesc->txdw0 & 0xffff); 386 387 /* use 1st xmitframe as media */ 388 xmitframe_xmitbuf_attach(pxmitframe, pxmitbuf); 389 pcmd_hdr->cmd_dw0 = cpu_to_le32(((total_length-CMD_HDR_SZ)&0x0000ffff)| 390 (pcmd_hdr->cmd_dw0&0xffff0000)); 391 392 /* urb length in cmd_dw1 */ 393 pcmd_hdr->cmd_dw1 = cpu_to_le32((pxmitbuf->aggr_nr & 0xff)| 394 ((total_length+TXDESC_SIZE) << 16)); 395 pxmitframe->last[0] = 1; 396 pxmitframe->bpending[0] = false; 397 pxmitframe->mem_addr = pxmitbuf->pbuf; 398 399 if ((pdvobj->ishighspeed && ((total_length+TXDESC_SIZE)%0x200) == 0) || 400 ((!pdvobj->ishighspeed && 401 ((total_length+TXDESC_SIZE)%0x40) == 0))) { 402 ptxdesc->txdw0 |= cpu_to_le32 403 (((TXDESC_SIZE+OFFSET_SZ+8)<<OFFSET_SHT)&0x00ff0000); 404 /*32 bytes for TX Desc + 8 bytes pending*/ 405 } else { 406 ptxdesc->txdw0 |= cpu_to_le32 407 (((TXDESC_SIZE+OFFSET_SZ)<<OFFSET_SHT)&0x00ff0000); 408 /*default = 32 bytes for TX Desc*/ 409 } 410 r8712_write_port(pxmitframe->padapter, RTL8712_DMA_H2CCMD, 411 total_length+TXDESC_SIZE, (u8 *)pxmitframe); 412 413 return _SUCCESS; 414} 415 416#endif 417 418static void update_txdesc(struct xmit_frame *pxmitframe, uint *pmem, int sz) 419{ 420 uint qsel; 421 struct _adapter *padapter = pxmitframe->padapter; 422 struct mlme_priv *pmlmepriv = &padapter->mlmepriv; 423 struct qos_priv *pqospriv = &pmlmepriv->qospriv; 424 struct security_priv *psecuritypriv = &padapter->securitypriv; 425 struct pkt_attrib *pattrib = &pxmitframe->attrib; 426 struct tx_desc *ptxdesc = (struct tx_desc *)pmem; 427 struct dvobj_priv *pdvobj = (struct dvobj_priv *)&padapter->dvobjpriv; 428#ifdef CONFIG_R8712_TX_AGGR 429 struct cmd_priv *pcmdpriv = (struct cmd_priv *)&padapter->cmdpriv; 430#endif 431 u8 blnSetTxDescOffset; 432 sint bmcst = IS_MCAST(pattrib->ra); 433 struct ht_priv *phtpriv = &pmlmepriv->htpriv; 434 struct tx_desc txdesc_mp; 435 436 memcpy(&txdesc_mp, ptxdesc, sizeof(struct tx_desc)); 437 memset(ptxdesc, 0, sizeof(struct tx_desc)); 438 /* offset 0 */ 439 ptxdesc->txdw0 |= cpu_to_le32(sz&0x0000ffff); 440 if (pdvobj->ishighspeed) { 441 if (((sz + TXDESC_SIZE) % 512) == 0) 442 blnSetTxDescOffset = 1; 443 else 444 blnSetTxDescOffset = 0; 445 } else { 446 if (((sz + TXDESC_SIZE) % 64) == 0) 447 blnSetTxDescOffset = 1; 448 else 449 blnSetTxDescOffset = 0; 450 } 451 if (blnSetTxDescOffset) { 452 /* 32 bytes for TX Desc + 8 bytes pending */ 453 ptxdesc->txdw0 |= cpu_to_le32(((TXDESC_SIZE+OFFSET_SZ + 8) << 454 OFFSET_SHT) & 0x00ff0000); 455 } else { 456 /* default = 32 bytes for TX Desc */ 457 ptxdesc->txdw0 |= cpu_to_le32(((TXDESC_SIZE+OFFSET_SZ) << 458 OFFSET_SHT) & 0x00ff0000); 459 } 460 ptxdesc->txdw0 |= cpu_to_le32(OWN | FSG | LSG); 461 if (pxmitframe->frame_tag == DATA_FRAMETAG) { 462 /* offset 4 */ 463 ptxdesc->txdw1 |= cpu_to_le32((pattrib->mac_id)&0x1f); 464 465#ifdef CONFIG_R8712_TX_AGGR 466 /* dirty workaround, need to check if it is aggr cmd. */ 467 if ((u8 *)pmem != (u8 *)pxmitframe->pxmitbuf->pbuf) { 468 ptxdesc->txdw0 |= cpu_to_le32 469 ((0x3 << TYPE_SHT)&TYPE_MSK); 470 qsel = (uint)(pattrib->qsel & 0x0000001f); 471 if (qsel == 2) 472 qsel = 0; 473 ptxdesc->txdw1 |= cpu_to_le32 474 ((qsel << QSEL_SHT) & 0x00001f00); 475 ptxdesc->txdw2 = cpu_to_le32 476 ((qsel << RTS_RC_SHT)&0x001f0000); 477 ptxdesc->txdw6 |= cpu_to_le32 478 ((0x5 << RSVD6_SHT)&RSVD6_MSK); 479 } else { 480 ptxdesc->txdw0 |= cpu_to_le32 481 ((0x3 << TYPE_SHT)&TYPE_MSK); 482 ptxdesc->txdw1 |= cpu_to_le32 483 ((0x13 << QSEL_SHT) & 0x00001f00); 484 qsel = (uint)(pattrib->qsel & 0x0000001f); 485 if (qsel == 2) 486 qsel = 0; 487 ptxdesc->txdw2 = cpu_to_le32 488 ((qsel << RTS_RC_SHT)&0x0001f000); 489 ptxdesc->txdw7 |= cpu_to_le32 490 (pcmdpriv->cmd_seq << 24); 491 pcmdpriv->cmd_seq++; 492 } 493 pattrib->qsel = 0x13; 494#else 495 qsel = (uint)(pattrib->qsel & 0x0000001f); 496 ptxdesc->txdw1 |= cpu_to_le32((qsel << QSEL_SHT) & 0x00001f00); 497#endif 498 if (!pqospriv->qos_option) 499 ptxdesc->txdw1 |= cpu_to_le32(BIT(16));/*Non-QoS*/ 500 if ((pattrib->encrypt > 0) && !pattrib->bswenc) { 501 switch (pattrib->encrypt) { /*SEC_TYPE*/ 502 case _WEP40_: 503 case _WEP104_: 504 ptxdesc->txdw1 |= cpu_to_le32((0x01 << 22) & 505 0x00c00000); 506 /*KEY_ID when WEP is used;*/ 507 ptxdesc->txdw1 |= cpu_to_le32((psecuritypriv-> 508 PrivacyKeyIndex << 17) & 509 0x00060000); 510 break; 511 case _TKIP_: 512 case _TKIP_WTMIC_: 513 ptxdesc->txdw1 |= cpu_to_le32((0x02 << 22) & 514 0x00c00000); 515 break; 516 case _AES_: 517 ptxdesc->txdw1 |= cpu_to_le32((0x03 << 22) & 518 0x00c00000); 519 break; 520 case _NO_PRIVACY_: 521 default: 522 break; 523 } 524 } 525 /*offset 8*/ 526 if (bmcst) 527 ptxdesc->txdw2 |= cpu_to_le32(BMC); 528 529 /*offset 12*/ 530 /* f/w will increase the seqnum by itself, driver pass the 531 * correct priority to fw 532 * fw will check the correct priority for increasing the 533 * seqnum per tid. about usb using 4-endpoint, qsel points out 534 * the correct mapping between AC&Endpoint, 535 * the purpose is that correct mapping lets the MAC release 536 * the AC Queue list correctly. */ 537 ptxdesc->txdw3 = cpu_to_le32((pattrib->priority << SEQ_SHT) & 538 0x0fff0000); 539 if ((pattrib->ether_type != 0x888e) && 540 (pattrib->ether_type != 0x0806) && 541 (pattrib->dhcp_pkt != 1)) { 542 /*Not EAP & ARP type data packet*/ 543 if (phtpriv->ht_option == 1) { /*B/G/N Mode*/ 544 if (phtpriv->ampdu_enable != true) 545 ptxdesc->txdw2 |= cpu_to_le32(BK); 546 } 547 } else { 548 /* EAP data packet and ARP packet. 549 * Use the 1M data rate to send the EAP/ARP packet. 550 * This will maybe make the handshake smooth. 551 */ 552 /*driver uses data rate*/ 553 ptxdesc->txdw4 = cpu_to_le32(0x80000000); 554 ptxdesc->txdw5 = cpu_to_le32(0x001f8000);/*1M*/ 555 } 556 if (pattrib->pctrl == 1) { /* mp tx packets */ 557 struct tx_desc *ptxdesc_mp; 558 559 ptxdesc_mp = &txdesc_mp; 560 /* offset 8 */ 561 ptxdesc->txdw2 = cpu_to_le32(ptxdesc_mp->txdw2); 562 if (bmcst) 563 ptxdesc->txdw2 |= cpu_to_le32(BMC); 564 ptxdesc->txdw2 |= cpu_to_le32(BK); 565 /* offset 16 */ 566 ptxdesc->txdw4 = cpu_to_le32(ptxdesc_mp->txdw4); 567 /* offset 20 */ 568 ptxdesc->txdw5 = cpu_to_le32(ptxdesc_mp->txdw5); 569 pattrib->pctrl = 0;/* reset to zero; */ 570 } 571 } else if (pxmitframe->frame_tag == MGNT_FRAMETAG) { 572 /* offset 4 */ 573 ptxdesc->txdw1 |= (0x05) & 0x1f;/*CAM_ID(MAC_ID), default=5;*/ 574 qsel = (uint)(pattrib->qsel & 0x0000001f); 575 ptxdesc->txdw1 |= cpu_to_le32((qsel << QSEL_SHT) & 0x00001f00); 576 ptxdesc->txdw1 |= cpu_to_le32(BIT(16));/* Non-QoS */ 577 /* offset 8 */ 578 if (bmcst) 579 ptxdesc->txdw2 |= cpu_to_le32(BMC); 580 /* offset 12 */ 581 /* f/w will increase the seqnum by itself, driver pass the 582 * correct priority to fw 583 * fw will check the correct priority for increasing the seqnum 584 * per tid. about usb using 4-endpoint, qsel points out the 585 * correct mapping between AC&Endpoint, 586 * the purpose is that correct mapping let the MAC releases 587 * the AC Queue list correctly. */ 588 ptxdesc->txdw3 = cpu_to_le32((pattrib->priority << SEQ_SHT) & 589 0x0fff0000); 590 /* offset 16 */ 591 ptxdesc->txdw4 = cpu_to_le32(0x80002040);/*gtest*/ 592 /* offset 20 */ 593 ptxdesc->txdw5 = cpu_to_le32(0x001f8000);/* gtest 1M */ 594 } else if (pxmitframe->frame_tag == TXAGG_FRAMETAG) { 595 /* offset 4 */ 596 qsel = 0x13; 597 ptxdesc->txdw1 |= cpu_to_le32((qsel << QSEL_SHT) & 0x00001f00); 598 } else { 599 /* offset 4 */ 600 qsel = (uint)(pattrib->priority&0x0000001f); 601 ptxdesc->txdw1 |= cpu_to_le32((qsel << QSEL_SHT) & 0x00001f00); 602 /*offset 8*/ 603 /*offset 12*/ 604 ptxdesc->txdw3 = cpu_to_le32((pattrib->seqnum << SEQ_SHT) & 605 0x0fff0000); 606 /*offset 16*/ 607 ptxdesc->txdw4 = cpu_to_le32(0x80002040);/*gtest*/ 608 /*offset 20*/ 609 ptxdesc->txdw5 = cpu_to_le32(0x001f9600);/*gtest*/ 610 } 611} 612 613int r8712_xmitframe_complete(struct _adapter *padapter, 614 struct xmit_priv *pxmitpriv, 615 struct xmit_buf *pxmitbuf) 616{ 617 struct hw_xmit *phwxmits; 618 sint hwentry; 619 struct xmit_frame *pxmitframe = NULL; 620#ifdef CONFIG_R8712_TX_AGGR 621 struct xmit_frame *p2ndxmitframe = NULL; 622#else 623 int res = _SUCCESS, xcnt = 0; 624#endif 625 626 phwxmits = pxmitpriv->hwxmits; 627 hwentry = pxmitpriv->hwxmit_entry; 628 if (pxmitbuf == NULL) { 629 pxmitbuf = r8712_alloc_xmitbuf(pxmitpriv); 630 if (!pxmitbuf) 631 return false; 632#ifdef CONFIG_R8712_TX_AGGR 633 pxmitbuf->aggr_nr = 0; 634#endif 635 } 636 /* 1st frame dequeued */ 637 pxmitframe = dequeue_xframe_ex(pxmitpriv, phwxmits, hwentry); 638 /* need to remember the 1st frame */ 639 if (pxmitframe != NULL) { 640 641#ifdef CONFIG_R8712_TX_AGGR 642 /* 1. dequeue 2nd frame 643 * 2. aggr if 2nd xframe is dequeued, else dump directly 644 */ 645 if (AGGR_NR_HIGH_BOUND > 1) 646 p2ndxmitframe = dequeue_xframe_ex(pxmitpriv, phwxmits, 647 hwentry); 648 if (pxmitframe->frame_tag != DATA_FRAMETAG) { 649 r8712_free_xmitbuf(pxmitpriv, pxmitbuf); 650 return false; 651 } 652 if (p2ndxmitframe != NULL) 653 if (p2ndxmitframe->frame_tag != DATA_FRAMETAG) { 654 r8712_free_xmitbuf(pxmitpriv, pxmitbuf); 655 return false; 656 } 657 r8712_xmitframe_aggr_1st(pxmitbuf, pxmitframe); 658 if (p2ndxmitframe != NULL) { 659 u16 total_length; 660 661 total_length = r8712_xmitframe_aggr_next( 662 pxmitbuf, p2ndxmitframe); 663 do { 664 p2ndxmitframe = dequeue_xframe_ex( 665 pxmitpriv, phwxmits, hwentry); 666 if (p2ndxmitframe != NULL) 667 total_length = 668 r8712_xmitframe_aggr_next( 669 pxmitbuf, 670 p2ndxmitframe); 671 else 672 break; 673 } while (total_length <= 0x1800 && 674 pxmitbuf->aggr_nr <= AGGR_NR_HIGH_BOUND); 675 } 676 if (pxmitbuf->aggr_nr > 0) 677 r8712_dump_aggr_xframe(pxmitbuf, pxmitframe); 678 679#else 680 681 xmitframe_xmitbuf_attach(pxmitframe, pxmitbuf); 682 if (pxmitframe->frame_tag == DATA_FRAMETAG) { 683 if (pxmitframe->attrib.priority <= 15) 684 res = r8712_xmitframe_coalesce(padapter, 685 pxmitframe->pkt, pxmitframe); 686 /* always return ndis_packet after 687 * r8712_xmitframe_coalesce */ 688 r8712_xmit_complete(padapter, pxmitframe); 689 } 690 if (res == _SUCCESS) 691 dump_xframe(padapter, pxmitframe); 692 else 693 r8712_free_xmitframe_ex(pxmitpriv, pxmitframe); 694 xcnt++; 695#endif 696 697 } else { /* pxmitframe == NULL && p2ndxmitframe == NULL */ 698 r8712_free_xmitbuf(pxmitpriv, pxmitbuf); 699 return false; 700 } 701 return true; 702} 703 704static void dump_xframe(struct _adapter *padapter, 705 struct xmit_frame *pxmitframe) 706{ 707 int t, sz, w_sz; 708 u8 *mem_addr; 709 u32 ff_hwaddr; 710 struct pkt_attrib *pattrib = &pxmitframe->attrib; 711 struct xmit_priv *pxmitpriv = &padapter->xmitpriv; 712 struct security_priv *psecuritypriv = &padapter->securitypriv; 713 714 if (pxmitframe->attrib.ether_type != 0x0806) { 715 if (pxmitframe->attrib.ether_type != 0x888e) 716 r8712_issue_addbareq_cmd(padapter, pattrib->priority); 717 } 718 mem_addr = pxmitframe->buf_addr; 719 for (t = 0; t < pattrib->nr_frags; t++) { 720 if (t != (pattrib->nr_frags - 1)) { 721 sz = pxmitpriv->frag_len; 722 sz = sz - 4 - (psecuritypriv->sw_encrypt ? 0 : 723 pattrib->icv_len); 724 pxmitframe->last[t] = 0; 725 } else { 726 sz = pattrib->last_txcmdsz; 727 pxmitframe->last[t] = 1; 728 } 729 update_txdesc(pxmitframe, (uint *)mem_addr, sz); 730 w_sz = sz + TXDESC_SIZE; 731 pxmitframe->mem_addr = mem_addr; 732 pxmitframe->bpending[t] = false; 733 ff_hwaddr = get_ff_hwaddr(pxmitframe); 734#ifdef CONFIG_R8712_TX_AGGR 735 r8712_write_port(padapter, RTL8712_DMA_H2CCMD, w_sz, 736 (unsigned char *)pxmitframe); 737#else 738 r8712_write_port(padapter, ff_hwaddr, w_sz, 739 (unsigned char *)pxmitframe); 740#endif 741 mem_addr += w_sz; 742 mem_addr = (u8 *)RND4(((addr_t)(mem_addr))); 743 } 744} 745 746int r8712_xmit_direct(struct _adapter *padapter, struct xmit_frame *pxmitframe) 747{ 748 int res = _SUCCESS; 749 750 res = r8712_xmitframe_coalesce(padapter, pxmitframe->pkt, pxmitframe); 751 pxmitframe->pkt = NULL; 752 if (res == _SUCCESS) 753 dump_xframe(padapter, pxmitframe); 754 return res; 755} 756 757int r8712_xmit_enqueue(struct _adapter *padapter, struct xmit_frame *pxmitframe) 758{ 759 if (r8712_xmit_classifier(padapter, pxmitframe) == _FAIL) { 760 pxmitframe->pkt = NULL; 761 return _FAIL; 762 } 763 return _SUCCESS; 764} 765