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