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