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