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