0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #define _RTL8712_XMIT_C_
0018
0019 #include "osdep_service.h"
0020 #include "drv_types.h"
0021 #include "wifi.h"
0022 #include "osdep_intf.h"
0023 #include "usb_ops.h"
0024
0025 static void dump_xframe(struct _adapter *padapter,
0026 struct xmit_frame *pxmitframe);
0027 static void update_txdesc(struct xmit_frame *pxmitframe, uint *pmem, int sz);
0028
0029 sint _r8712_init_hw_txqueue(struct hw_txqueue *phw_txqueue, u8 ac_tag)
0030 {
0031 phw_txqueue->ac_tag = ac_tag;
0032 switch (ac_tag) {
0033 case BE_QUEUE_INX:
0034 phw_txqueue->ff_hwaddr = RTL8712_DMA_BEQ;
0035 break;
0036 case BK_QUEUE_INX:
0037 phw_txqueue->ff_hwaddr = RTL8712_DMA_BKQ;
0038 break;
0039 case VI_QUEUE_INX:
0040 phw_txqueue->ff_hwaddr = RTL8712_DMA_VIQ;
0041 break;
0042 case VO_QUEUE_INX:
0043 phw_txqueue->ff_hwaddr = RTL8712_DMA_VOQ;
0044 break;
0045 case BMC_QUEUE_INX:
0046 phw_txqueue->ff_hwaddr = RTL8712_DMA_BEQ;
0047 break;
0048 }
0049 return _SUCCESS;
0050 }
0051
0052 int r8712_txframes_sta_ac_pending(struct _adapter *padapter,
0053 struct pkt_attrib *pattrib)
0054 {
0055 struct sta_info *psta;
0056 struct tx_servq *ptxservq;
0057 int priority = pattrib->priority;
0058
0059 psta = pattrib->psta;
0060 switch (priority) {
0061 case 1:
0062 case 2:
0063 ptxservq = &psta->sta_xmitpriv.bk_q;
0064 break;
0065 case 4:
0066 case 5:
0067 ptxservq = &psta->sta_xmitpriv.vi_q;
0068 break;
0069 case 6:
0070 case 7:
0071 ptxservq = &psta->sta_xmitpriv.vo_q;
0072 break;
0073 case 0:
0074 case 3:
0075 default:
0076 ptxservq = &psta->sta_xmitpriv.be_q;
0077 break;
0078 }
0079 return ptxservq->qcnt;
0080 }
0081
0082 static u32 get_ff_hwaddr(struct xmit_frame *pxmitframe)
0083 {
0084 u32 addr = 0;
0085 struct pkt_attrib *pattrib = &pxmitframe->attrib;
0086 struct _adapter *padapter = pxmitframe->padapter;
0087 struct dvobj_priv *pdvobj = &padapter->dvobjpriv;
0088
0089 if (pxmitframe->frame_tag == TXAGG_FRAMETAG) {
0090 addr = RTL8712_DMA_H2CCMD;
0091 } else if (pxmitframe->frame_tag == MGNT_FRAMETAG) {
0092 addr = RTL8712_DMA_MGTQ;
0093 } else if (pdvobj->nr_endpoint == 6) {
0094 switch (pattrib->priority) {
0095 case 0:
0096 case 3:
0097 addr = RTL8712_DMA_BEQ;
0098 break;
0099 case 1:
0100 case 2:
0101 addr = RTL8712_DMA_BKQ;
0102 break;
0103 case 4:
0104 case 5:
0105 addr = RTL8712_DMA_VIQ;
0106 break;
0107 case 6:
0108 case 7:
0109 addr = RTL8712_DMA_VOQ;
0110 break;
0111 case 0x10:
0112 case 0x11:
0113 case 0x12:
0114 case 0x13:
0115 addr = RTL8712_DMA_H2CCMD;
0116 break;
0117 default:
0118 addr = RTL8712_DMA_BEQ;
0119 break;
0120 }
0121 } else if (pdvobj->nr_endpoint == 4) {
0122 switch (pattrib->qsel) {
0123 case 0:
0124 case 3:
0125 case 1:
0126 case 2:
0127 addr = RTL8712_DMA_BEQ;
0128 break;
0129 case 4:
0130 case 5:
0131 case 6:
0132 case 7:
0133 addr = RTL8712_DMA_VOQ;
0134 break;
0135 case 0x10:
0136 case 0x11:
0137 case 0x12:
0138 case 0x13:
0139 addr = RTL8712_DMA_H2CCMD;
0140 break;
0141 default:
0142 addr = RTL8712_DMA_BEQ;
0143 break;
0144 }
0145 }
0146 return addr;
0147 }
0148
0149 static struct xmit_frame *dequeue_one_xmitframe(struct xmit_priv *pxmitpriv,
0150 struct hw_xmit *phwxmit,
0151 struct tx_servq *ptxservq,
0152 struct __queue *pframe_queue)
0153 {
0154 struct list_head *xmitframe_plist, *xmitframe_phead;
0155 struct xmit_frame *pxmitframe = NULL;
0156
0157 xmitframe_phead = &pframe_queue->queue;
0158 xmitframe_plist = xmitframe_phead->next;
0159 if (!end_of_queue_search(xmitframe_phead, xmitframe_plist)) {
0160 pxmitframe = container_of(xmitframe_plist,
0161 struct xmit_frame, list);
0162 list_del_init(&pxmitframe->list);
0163 ptxservq->qcnt--;
0164 phwxmit->txcmdcnt++;
0165 }
0166 return pxmitframe;
0167 }
0168
0169 static struct xmit_frame *dequeue_xframe_ex(struct xmit_priv *pxmitpriv,
0170 struct hw_xmit *phwxmit_i, sint entry)
0171 {
0172 unsigned long irqL0;
0173 struct list_head *sta_plist, *sta_phead;
0174 struct hw_xmit *phwxmit;
0175 struct tx_servq *ptxservq = NULL;
0176 struct __queue *pframe_queue = NULL;
0177 struct xmit_frame *pxmitframe = NULL;
0178 int i, inx[4];
0179 int j, acirp_cnt[4];
0180
0181
0182 inx[0] = 0; acirp_cnt[0] = pxmitpriv->voq_cnt;
0183 inx[1] = 1; acirp_cnt[1] = pxmitpriv->viq_cnt;
0184 inx[2] = 2; acirp_cnt[2] = pxmitpriv->beq_cnt;
0185 inx[3] = 3; acirp_cnt[3] = pxmitpriv->bkq_cnt;
0186 for (i = 0; i < 4; i++) {
0187 for (j = i + 1; j < 4; j++) {
0188 if (acirp_cnt[j] < acirp_cnt[i]) {
0189 swap(acirp_cnt[i], acirp_cnt[j]);
0190 swap(inx[i], inx[j]);
0191 }
0192 }
0193 }
0194 spin_lock_irqsave(&pxmitpriv->lock, irqL0);
0195 for (i = 0; i < entry; i++) {
0196 phwxmit = phwxmit_i + inx[i];
0197 sta_phead = &phwxmit->sta_queue->queue;
0198 sta_plist = sta_phead->next;
0199 while (!end_of_queue_search(sta_phead, sta_plist)) {
0200 ptxservq = container_of(sta_plist, struct tx_servq,
0201 tx_pending);
0202 pframe_queue = &ptxservq->sta_pending;
0203 pxmitframe = dequeue_one_xmitframe(pxmitpriv, phwxmit,
0204 ptxservq, pframe_queue);
0205 if (pxmitframe) {
0206 phwxmit->accnt--;
0207 goto exit_dequeue_xframe_ex;
0208 }
0209 sta_plist = sta_plist->next;
0210
0211 if (list_empty(&pframe_queue->queue)) {
0212
0213
0214
0215 list_del_init(&ptxservq->tx_pending);
0216 }
0217 }
0218 }
0219 exit_dequeue_xframe_ex:
0220 spin_unlock_irqrestore(&pxmitpriv->lock, irqL0);
0221 return pxmitframe;
0222 }
0223
0224 void r8712_do_queue_select(struct _adapter *padapter,
0225 struct pkt_attrib *pattrib)
0226 {
0227 unsigned int qsel = 0;
0228 struct dvobj_priv *pdvobj = &padapter->dvobjpriv;
0229
0230 if (pdvobj->nr_endpoint == 6) {
0231 qsel = (unsigned int)pattrib->priority;
0232 } else if (pdvobj->nr_endpoint == 4) {
0233 qsel = (unsigned int)pattrib->priority;
0234 if (qsel == 0 || qsel == 3)
0235 qsel = 3;
0236 else if (qsel == 1 || qsel == 2)
0237 qsel = 1;
0238 else if (qsel == 4 || qsel == 5)
0239 qsel = 5;
0240 else if (qsel == 6 || qsel == 7)
0241 qsel = 7;
0242 else
0243 qsel = 3;
0244 }
0245 pattrib->qsel = qsel;
0246 }
0247
0248 #ifdef CONFIG_R8712_TX_AGGR
0249 void r8712_construct_txaggr_cmd_desc(struct xmit_buf *pxmitbuf)
0250 {
0251 struct tx_desc *ptx_desc = (struct tx_desc *)pxmitbuf->pbuf;
0252
0253
0254
0255 ptx_desc->txdw0 = cpu_to_le32(CMD_HDR_SZ & 0xffff);
0256 ptx_desc->txdw0 |=
0257 cpu_to_le32(((TXDESC_SIZE + OFFSET_SZ) << OFFSET_SHT) &
0258 0x00ff0000);
0259 ptx_desc->txdw0 |= cpu_to_le32(OWN | FSG | LSG);
0260
0261
0262 ptx_desc->txdw1 |= cpu_to_le32((0x13 << QSEL_SHT) & 0x00001f00);
0263 }
0264
0265 void r8712_construct_txaggr_cmd_hdr(struct xmit_buf *pxmitbuf)
0266 {
0267 struct xmit_frame *pxmitframe = (struct xmit_frame *)
0268 pxmitbuf->priv_data;
0269 struct _adapter *padapter = pxmitframe->padapter;
0270 struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
0271 struct cmd_hdr *pcmd_hdr = (struct cmd_hdr *)
0272 (pxmitbuf->pbuf + TXDESC_SIZE);
0273
0274
0275
0276 pcmd_hdr->cmd_dw0 = cpu_to_le32((GEN_CMD_CODE(_AMSDU_TO_AMPDU) << 16) |
0277 (pcmdpriv->cmd_seq << 24));
0278 pcmdpriv->cmd_seq++;
0279 }
0280
0281 void r8712_append_mpdu_unit(struct xmit_buf *pxmitbuf,
0282 struct xmit_frame *pxmitframe)
0283 {
0284 struct _adapter *padapter = pxmitframe->padapter;
0285 struct tx_desc *ptx_desc = (struct tx_desc *)pxmitbuf->pbuf;
0286 int last_txcmdsz = 0;
0287 int padding_sz = 0;
0288
0289
0290 r8712_xmitframe_coalesce(padapter, pxmitframe->pkt, pxmitframe);
0291
0292 r8712_xmit_complete(padapter, pxmitframe);
0293 if (pxmitframe->attrib.ether_type != 0x0806) {
0294 if ((pxmitframe->attrib.ether_type != 0x888e) &&
0295 (pxmitframe->attrib.dhcp_pkt != 1)) {
0296 r8712_issue_addbareq_cmd(padapter,
0297 pxmitframe->attrib.priority);
0298 }
0299 }
0300 pxmitframe->last[0] = 1;
0301 update_txdesc(pxmitframe, (uint *)(pxmitframe->buf_addr),
0302 pxmitframe->attrib.last_txcmdsz);
0303
0304 last_txcmdsz = pxmitframe->attrib.last_txcmdsz;
0305 padding_sz = (8 - (last_txcmdsz % 8));
0306 if ((last_txcmdsz % 8) != 0) {
0307 int i;
0308
0309 for (i = 0; i < padding_sz; i++)
0310 *(pxmitframe->buf_addr + TXDESC_SIZE + last_txcmdsz +
0311 i) = 0;
0312 }
0313
0314 ptx_desc->txdw0 = cpu_to_le32((ptx_desc->txdw0 & 0xffff0000) |
0315 ((ptx_desc->txdw0 & 0x0000ffff) +
0316 ((TXDESC_SIZE + last_txcmdsz + padding_sz) &
0317 0x0000ffff)));
0318 }
0319
0320 void r8712_xmitframe_aggr_1st(struct xmit_buf *pxmitbuf,
0321 struct xmit_frame *pxmitframe)
0322 {
0323
0324 pxmitframe->pxmitbuf = pxmitbuf;
0325 pxmitbuf->priv_data = pxmitframe;
0326 pxmitframe->pxmit_urb[0] = pxmitbuf->pxmit_urb[0];
0327
0328 pxmitframe->buf_addr = pxmitbuf->pbuf + TXDESC_SIZE + CMD_HDR_SZ;
0329
0330 r8712_construct_txaggr_cmd_desc(pxmitbuf);
0331 r8712_construct_txaggr_cmd_hdr(pxmitbuf);
0332 r8712_append_mpdu_unit(pxmitbuf, pxmitframe);
0333 pxmitbuf->aggr_nr = 1;
0334 }
0335
0336 u16 r8712_xmitframe_aggr_next(struct xmit_buf *pxmitbuf,
0337 struct xmit_frame *pxmitframe)
0338 {
0339 pxmitframe->pxmitbuf = pxmitbuf;
0340 pxmitbuf->priv_data = pxmitframe;
0341 pxmitframe->pxmit_urb[0] = pxmitbuf->pxmit_urb[0];
0342
0343 pxmitframe->buf_addr = pxmitbuf->pbuf + TXDESC_SIZE +
0344 (((struct tx_desc *)pxmitbuf->pbuf)->txdw0 & 0x0000ffff);
0345 r8712_append_mpdu_unit(pxmitbuf, pxmitframe);
0346 r8712_free_xmitframe_ex(&pxmitframe->padapter->xmitpriv,
0347 pxmitframe);
0348 pxmitbuf->aggr_nr++;
0349
0350 return TXDESC_SIZE +
0351 (((struct tx_desc *)pxmitbuf->pbuf)->txdw0 & 0x0000ffff);
0352 }
0353
0354 void r8712_dump_aggr_xframe(struct xmit_buf *pxmitbuf,
0355 struct xmit_frame *pxmitframe)
0356 {
0357 struct _adapter *padapter = pxmitframe->padapter;
0358 struct dvobj_priv *pdvobj = &padapter->dvobjpriv;
0359 struct tx_desc *ptxdesc = pxmitbuf->pbuf;
0360 struct cmd_hdr *pcmd_hdr = (struct cmd_hdr *)
0361 (pxmitbuf->pbuf + TXDESC_SIZE);
0362 u16 total_length = (u16)(ptxdesc->txdw0 & 0xffff);
0363
0364
0365 xmitframe_xmitbuf_attach(pxmitframe, pxmitbuf);
0366 pcmd_hdr->cmd_dw0 = cpu_to_le32(((total_length - CMD_HDR_SZ) &
0367 0x0000ffff) | (pcmd_hdr->cmd_dw0 &
0368 0xffff0000));
0369
0370
0371 pcmd_hdr->cmd_dw1 = cpu_to_le32((pxmitbuf->aggr_nr & 0xff) |
0372 ((total_length + TXDESC_SIZE) << 16));
0373 pxmitframe->last[0] = 1;
0374 pxmitframe->bpending[0] = false;
0375 pxmitframe->mem_addr = pxmitbuf->pbuf;
0376
0377 if ((pdvobj->ishighspeed && ((total_length + TXDESC_SIZE) % 0x200) ==
0378 0) || ((!pdvobj->ishighspeed && ((total_length + TXDESC_SIZE) %
0379 0x40) == 0))) {
0380 ptxdesc->txdw0 |= cpu_to_le32
0381 (((TXDESC_SIZE + OFFSET_SZ + 8) << OFFSET_SHT) &
0382 0x00ff0000);
0383
0384 } else {
0385 ptxdesc->txdw0 |= cpu_to_le32
0386 (((TXDESC_SIZE + OFFSET_SZ) << OFFSET_SHT) &
0387 0x00ff0000);
0388
0389 }
0390 r8712_write_port(pxmitframe->padapter, RTL8712_DMA_H2CCMD,
0391 total_length + TXDESC_SIZE, (u8 *)pxmitframe);
0392 }
0393
0394 #endif
0395
0396 static void update_txdesc(struct xmit_frame *pxmitframe, uint *pmem, int sz)
0397 {
0398 uint qsel;
0399 struct _adapter *padapter = pxmitframe->padapter;
0400 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
0401 struct qos_priv *pqospriv = &pmlmepriv->qospriv;
0402 struct security_priv *psecuritypriv = &padapter->securitypriv;
0403 struct pkt_attrib *pattrib = &pxmitframe->attrib;
0404 struct tx_desc *ptxdesc = (struct tx_desc *)pmem;
0405 struct dvobj_priv *pdvobj = &padapter->dvobjpriv;
0406 #ifdef CONFIG_R8712_TX_AGGR
0407 struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
0408 #endif
0409 u8 blnSetTxDescOffset;
0410 bool bmcst = is_multicast_ether_addr(pattrib->ra);
0411 struct ht_priv *phtpriv = &pmlmepriv->htpriv;
0412 struct tx_desc txdesc_mp;
0413
0414 memcpy(&txdesc_mp, ptxdesc, sizeof(struct tx_desc));
0415 memset(ptxdesc, 0, sizeof(struct tx_desc));
0416
0417 ptxdesc->txdw0 |= cpu_to_le32(sz & 0x0000ffff);
0418 if (pdvobj->ishighspeed) {
0419 if (((sz + TXDESC_SIZE) % 512) == 0)
0420 blnSetTxDescOffset = 1;
0421 else
0422 blnSetTxDescOffset = 0;
0423 } else {
0424 if (((sz + TXDESC_SIZE) % 64) == 0)
0425 blnSetTxDescOffset = 1;
0426 else
0427 blnSetTxDescOffset = 0;
0428 }
0429 if (blnSetTxDescOffset) {
0430
0431 ptxdesc->txdw0 |= cpu_to_le32(((TXDESC_SIZE + OFFSET_SZ + 8) <<
0432 OFFSET_SHT) & 0x00ff0000);
0433 } else {
0434
0435 ptxdesc->txdw0 |= cpu_to_le32(((TXDESC_SIZE + OFFSET_SZ) <<
0436 OFFSET_SHT) & 0x00ff0000);
0437 }
0438 ptxdesc->txdw0 |= cpu_to_le32(OWN | FSG | LSG);
0439 if (pxmitframe->frame_tag == DATA_FRAMETAG) {
0440
0441 ptxdesc->txdw1 |= cpu_to_le32((pattrib->mac_id) & 0x1f);
0442
0443 #ifdef CONFIG_R8712_TX_AGGR
0444
0445 if ((u8 *)pmem != (u8 *)pxmitframe->pxmitbuf->pbuf) {
0446 ptxdesc->txdw0 |= cpu_to_le32
0447 ((0x3 << TYPE_SHT) & TYPE_MSK);
0448 qsel = (uint)(pattrib->qsel & 0x0000001f);
0449 if (qsel == 2)
0450 qsel = 0;
0451 ptxdesc->txdw1 |= cpu_to_le32
0452 ((qsel << QSEL_SHT) & 0x00001f00);
0453 ptxdesc->txdw2 = cpu_to_le32
0454 ((qsel << RTS_RC_SHT) & 0x001f0000);
0455 ptxdesc->txdw6 |= cpu_to_le32
0456 ((0x5 << RSVD6_SHT) & RSVD6_MSK);
0457 } else {
0458 ptxdesc->txdw0 |= cpu_to_le32
0459 ((0x3 << TYPE_SHT) & TYPE_MSK);
0460 ptxdesc->txdw1 |= cpu_to_le32
0461 ((0x13 << QSEL_SHT) & 0x00001f00);
0462 qsel = (uint)(pattrib->qsel & 0x0000001f);
0463 if (qsel == 2)
0464 qsel = 0;
0465 ptxdesc->txdw2 = cpu_to_le32
0466 ((qsel << RTS_RC_SHT) & 0x0001f000);
0467 ptxdesc->txdw7 |= cpu_to_le32
0468 (pcmdpriv->cmd_seq << 24);
0469 pcmdpriv->cmd_seq++;
0470 }
0471 pattrib->qsel = 0x13;
0472 #else
0473 qsel = (uint)(pattrib->qsel & 0x0000001f);
0474 ptxdesc->txdw1 |= cpu_to_le32((qsel << QSEL_SHT) & 0x00001f00);
0475 #endif
0476 if (!pqospriv->qos_option)
0477 ptxdesc->txdw1 |= cpu_to_le32(BIT(16));
0478 if ((pattrib->encrypt > 0) && !pattrib->bswenc) {
0479 switch (pattrib->encrypt) {
0480 case _WEP40_:
0481 case _WEP104_:
0482 ptxdesc->txdw1 |= cpu_to_le32((0x01 << 22) &
0483 0x00c00000);
0484
0485 ptxdesc->txdw1 |=
0486 cpu_to_le32((psecuritypriv->PrivacyKeyIndex << 17) &
0487 0x00060000);
0488 break;
0489 case _TKIP_:
0490 case _TKIP_WTMIC_:
0491 ptxdesc->txdw1 |= cpu_to_le32((0x02 << 22) &
0492 0x00c00000);
0493 break;
0494 case _AES_:
0495 ptxdesc->txdw1 |= cpu_to_le32((0x03 << 22) &
0496 0x00c00000);
0497 break;
0498 case _NO_PRIVACY_:
0499 default:
0500 break;
0501 }
0502 }
0503
0504 if (bmcst)
0505 ptxdesc->txdw2 |= cpu_to_le32(BMC);
0506
0507
0508
0509
0510
0511
0512
0513
0514
0515
0516 ptxdesc->txdw3 = cpu_to_le32((pattrib->priority << SEQ_SHT) &
0517 0x0fff0000);
0518 if ((pattrib->ether_type != 0x888e) &&
0519 (pattrib->ether_type != 0x0806) &&
0520 (pattrib->dhcp_pkt != 1)) {
0521
0522 if (phtpriv->ht_option == 1) {
0523 if (!phtpriv->ampdu_enable)
0524 ptxdesc->txdw2 |= cpu_to_le32(BK);
0525 }
0526 } else {
0527
0528
0529
0530
0531
0532 ptxdesc->txdw4 = cpu_to_le32(0x80000000);
0533 ptxdesc->txdw5 = cpu_to_le32(0x001f8000);
0534 }
0535 if (pattrib->pctrl == 1) {
0536 struct tx_desc *ptxdesc_mp;
0537
0538 ptxdesc_mp = &txdesc_mp;
0539
0540 ptxdesc->txdw2 = ptxdesc_mp->txdw2;
0541 if (bmcst)
0542 ptxdesc->txdw2 |= cpu_to_le32(BMC);
0543 ptxdesc->txdw2 |= cpu_to_le32(BK);
0544
0545 ptxdesc->txdw4 = ptxdesc_mp->txdw4;
0546
0547 ptxdesc->txdw5 = ptxdesc_mp->txdw5;
0548 pattrib->pctrl = 0;
0549 }
0550 } else if (pxmitframe->frame_tag == MGNT_FRAMETAG) {
0551
0552
0553 ptxdesc->txdw1 |= cpu_to_le32((0x05) & 0x1f);
0554 qsel = (uint)(pattrib->qsel & 0x0000001f);
0555 ptxdesc->txdw1 |= cpu_to_le32((qsel << QSEL_SHT) & 0x00001f00);
0556 ptxdesc->txdw1 |= cpu_to_le32(BIT(16));
0557
0558 if (bmcst)
0559 ptxdesc->txdw2 |= cpu_to_le32(BMC);
0560
0561
0562
0563
0564
0565
0566
0567
0568
0569 ptxdesc->txdw3 = cpu_to_le32((pattrib->priority << SEQ_SHT) &
0570 0x0fff0000);
0571
0572 ptxdesc->txdw4 = cpu_to_le32(0x80002040);
0573
0574 ptxdesc->txdw5 = cpu_to_le32(0x001f8000);
0575 } else if (pxmitframe->frame_tag == TXAGG_FRAMETAG) {
0576
0577 qsel = 0x13;
0578 ptxdesc->txdw1 |= cpu_to_le32((qsel << QSEL_SHT) & 0x00001f00);
0579 } else {
0580
0581 qsel = (uint)(pattrib->priority & 0x0000001f);
0582 ptxdesc->txdw1 |= cpu_to_le32((qsel << QSEL_SHT) & 0x00001f00);
0583
0584
0585 ptxdesc->txdw3 = cpu_to_le32((pattrib->seqnum << SEQ_SHT) &
0586 0x0fff0000);
0587
0588 ptxdesc->txdw4 = cpu_to_le32(0x80002040);
0589
0590 ptxdesc->txdw5 = cpu_to_le32(0x001f9600);
0591 }
0592 }
0593
0594 int r8712_xmitframe_complete(struct _adapter *padapter,
0595 struct xmit_priv *pxmitpriv,
0596 struct xmit_buf *pxmitbuf)
0597 {
0598 struct hw_xmit *phwxmits;
0599 sint hwentry;
0600 struct xmit_frame *pxmitframe = NULL;
0601 #ifdef CONFIG_R8712_TX_AGGR
0602 struct xmit_frame *p2ndxmitframe = NULL;
0603 #else
0604 int res = _SUCCESS, xcnt = 0;
0605 #endif
0606
0607 phwxmits = pxmitpriv->hwxmits;
0608 hwentry = pxmitpriv->hwxmit_entry;
0609 if (!pxmitbuf) {
0610 pxmitbuf = r8712_alloc_xmitbuf(pxmitpriv);
0611 if (!pxmitbuf)
0612 return false;
0613 #ifdef CONFIG_R8712_TX_AGGR
0614 pxmitbuf->aggr_nr = 0;
0615 #endif
0616 }
0617
0618 pxmitframe = dequeue_xframe_ex(pxmitpriv, phwxmits, hwentry);
0619
0620 if (pxmitframe) {
0621
0622 #ifdef CONFIG_R8712_TX_AGGR
0623
0624
0625
0626 if (AGGR_NR_HIGH_BOUND > 1)
0627 p2ndxmitframe = dequeue_xframe_ex(pxmitpriv, phwxmits,
0628 hwentry);
0629 if (pxmitframe->frame_tag != DATA_FRAMETAG) {
0630 r8712_free_xmitbuf(pxmitpriv, pxmitbuf);
0631 return false;
0632 }
0633 if (p2ndxmitframe)
0634 if (p2ndxmitframe->frame_tag != DATA_FRAMETAG) {
0635 r8712_free_xmitbuf(pxmitpriv, pxmitbuf);
0636 return false;
0637 }
0638 r8712_xmitframe_aggr_1st(pxmitbuf, pxmitframe);
0639 if (p2ndxmitframe) {
0640 u16 total_length;
0641
0642 total_length = r8712_xmitframe_aggr_next(
0643 pxmitbuf, p2ndxmitframe);
0644 do {
0645 p2ndxmitframe = dequeue_xframe_ex(
0646 pxmitpriv, phwxmits, hwentry);
0647 if (p2ndxmitframe)
0648 total_length =
0649 r8712_xmitframe_aggr_next(
0650 pxmitbuf,
0651 p2ndxmitframe);
0652 else
0653 break;
0654 } while (total_length <= 0x1800 &&
0655 pxmitbuf->aggr_nr <= AGGR_NR_HIGH_BOUND);
0656 }
0657 if (pxmitbuf->aggr_nr > 0)
0658 r8712_dump_aggr_xframe(pxmitbuf, pxmitframe);
0659
0660 #else
0661
0662 xmitframe_xmitbuf_attach(pxmitframe, pxmitbuf);
0663 if (pxmitframe->frame_tag == DATA_FRAMETAG) {
0664 if (pxmitframe->attrib.priority <= 15)
0665 res = r8712_xmitframe_coalesce(padapter,
0666 pxmitframe->pkt, pxmitframe);
0667
0668
0669
0670 r8712_xmit_complete(padapter, pxmitframe);
0671 }
0672 if (res == _SUCCESS)
0673 dump_xframe(padapter, pxmitframe);
0674 else
0675 r8712_free_xmitframe_ex(pxmitpriv, pxmitframe);
0676 xcnt++;
0677 #endif
0678
0679 } else {
0680 r8712_free_xmitbuf(pxmitpriv, pxmitbuf);
0681 return false;
0682 }
0683 return true;
0684 }
0685
0686 static void dump_xframe(struct _adapter *padapter,
0687 struct xmit_frame *pxmitframe)
0688 {
0689 int t, sz, w_sz;
0690 u8 *mem_addr;
0691 u32 ff_hwaddr;
0692 struct pkt_attrib *pattrib = &pxmitframe->attrib;
0693 struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
0694 struct security_priv *psecuritypriv = &padapter->securitypriv;
0695
0696 if (pxmitframe->attrib.ether_type != 0x0806) {
0697 if (pxmitframe->attrib.ether_type != 0x888e)
0698 r8712_issue_addbareq_cmd(padapter, pattrib->priority);
0699 }
0700 mem_addr = pxmitframe->buf_addr;
0701 for (t = 0; t < pattrib->nr_frags; t++) {
0702 if (t != (pattrib->nr_frags - 1)) {
0703 sz = pxmitpriv->frag_len;
0704 sz = sz - 4 - (psecuritypriv->sw_encrypt ? 0 :
0705 pattrib->icv_len);
0706 pxmitframe->last[t] = 0;
0707 } else {
0708 sz = pattrib->last_txcmdsz;
0709 pxmitframe->last[t] = 1;
0710 }
0711 update_txdesc(pxmitframe, (uint *)mem_addr, sz);
0712 w_sz = sz + TXDESC_SIZE;
0713 pxmitframe->mem_addr = mem_addr;
0714 pxmitframe->bpending[t] = false;
0715 ff_hwaddr = get_ff_hwaddr(pxmitframe);
0716 #ifdef CONFIG_R8712_TX_AGGR
0717 r8712_write_port(padapter, RTL8712_DMA_H2CCMD, w_sz,
0718 (unsigned char *)pxmitframe);
0719 #else
0720 r8712_write_port(padapter, ff_hwaddr, w_sz,
0721 (unsigned char *)pxmitframe);
0722 #endif
0723 mem_addr += w_sz;
0724 mem_addr = (u8 *)RND4(((addr_t)(mem_addr)));
0725 }
0726 }
0727
0728 void r8712_xmit_direct(struct _adapter *padapter, struct xmit_frame *pxmitframe)
0729 {
0730 int res;
0731
0732 res = r8712_xmitframe_coalesce(padapter, pxmitframe->pkt, pxmitframe);
0733 pxmitframe->pkt = NULL;
0734 if (res == _SUCCESS)
0735 dump_xframe(padapter, pxmitframe);
0736 }
0737
0738 int r8712_xmit_enqueue(struct _adapter *padapter, struct xmit_frame *pxmitframe)
0739 {
0740 if (r8712_xmit_classifier(padapter, pxmitframe)) {
0741 pxmitframe->pkt = NULL;
0742 return _FAIL;
0743 }
0744 return _SUCCESS;
0745 }