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
 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}
 746