linux/drivers/staging/rtl8723au/hal/rtl8723au_xmit.c
<<
>>
Prefs
   1/******************************************************************************
   2 *
   3 * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
   4 *
   5 * This program is free software; you can redistribute it and/or modify it
   6 * under the terms of version 2 of the GNU General Public License as
   7 * published by the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope that it will be useful, but WITHOUT
  10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  12 * more details.
  13 *
  14 ******************************************************************************/
  15#define _RTL8192C_XMIT_C_
  16#include <osdep_service.h>
  17#include <drv_types.h>
  18#include <wifi.h>
  19#include <osdep_intf.h>
  20#include <usb_ops.h>
  21/* include <rtl8192c_hal.h> */
  22#include <rtl8723a_hal.h>
  23
  24static int urb_zero_packet_chk(struct rtw_adapter *padapter, int sz)
  25{
  26        int blnSetTxDescOffset;
  27        struct dvobj_priv       *pdvobj = adapter_to_dvobj(padapter);
  28
  29        if (pdvobj->ishighspeed) {
  30                if (((sz + TXDESC_SIZE) % 512) == 0)
  31                        blnSetTxDescOffset = 1;
  32                else
  33                        blnSetTxDescOffset = 0;
  34        } else {
  35                if (((sz + TXDESC_SIZE) % 64) == 0)
  36                        blnSetTxDescOffset = 1;
  37                else
  38                        blnSetTxDescOffset = 0;
  39        }
  40        return blnSetTxDescOffset;
  41}
  42
  43static void rtl8192cu_cal_txdesc_chksum(struct tx_desc  *ptxdesc)
  44{
  45                __le16  *usPtr = (__le16 *)ptxdesc;
  46                u32 count = 16;         /*  (32 bytes / 2 bytes per XOR) => 16 times */
  47                u32 index;
  48                u16 checksum = 0;
  49
  50                /* Clear first */
  51                ptxdesc->txdw7 &= cpu_to_le32(0xffff0000);
  52
  53                for (index = 0 ; index < count ; index++)
  54                        checksum = checksum ^ le16_to_cpu(*(usPtr + index));
  55
  56                ptxdesc->txdw7 |= cpu_to_le32(0x0000ffff&checksum);
  57}
  58
  59static void fill_txdesc_sectype(struct pkt_attrib *pattrib, struct tx_desc *ptxdesc)
  60{
  61        if ((pattrib->encrypt > 0) && !pattrib->bswenc) {
  62                switch (pattrib->encrypt) {
  63                /* SEC_TYPE */
  64                case WLAN_CIPHER_SUITE_WEP40:
  65                case WLAN_CIPHER_SUITE_WEP104:
  66                        ptxdesc->txdw1 |= cpu_to_le32((0x01<<22)&0x00c00000);
  67                        break;
  68                case WLAN_CIPHER_SUITE_TKIP:
  69                        /* ptxdesc->txdw1 |= cpu_to_le32((0x02<<22)&0x00c00000); */
  70                        ptxdesc->txdw1 |= cpu_to_le32((0x01<<22)&0x00c00000);
  71                        break;
  72                case WLAN_CIPHER_SUITE_CCMP:
  73                        ptxdesc->txdw1 |= cpu_to_le32((0x03<<22)&0x00c00000);
  74                        break;
  75                case 0:
  76                default:
  77                        break;
  78                }
  79        }
  80}
  81
  82static void fill_txdesc_vcs(struct pkt_attrib *pattrib, __le32 *pdw)
  83{
  84        /* DBG_8723A("cvs_mode =%d\n", pattrib->vcs_mode); */
  85
  86        switch (pattrib->vcs_mode) {
  87        case RTS_CTS:
  88                *pdw |= cpu_to_le32(BIT(12));
  89                break;
  90        case CTS_TO_SELF:
  91                *pdw |= cpu_to_le32(BIT(11));
  92                break;
  93        case NONE_VCS:
  94        default:
  95                break;
  96        }
  97
  98        if (pattrib->vcs_mode) {
  99                *pdw |= cpu_to_le32(BIT(13));
 100
 101                /*  Set RTS BW */
 102                if (pattrib->ht_en) {
 103                        *pdw |= (pattrib->bwmode&HT_CHANNEL_WIDTH_40) ? cpu_to_le32(BIT(27)) : 0;
 104
 105                        if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER)
 106                                *pdw |= cpu_to_le32((0x01<<28)&0x30000000);
 107                        else if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_UPPER)
 108                                *pdw |= cpu_to_le32((0x02<<28)&0x30000000);
 109                        else if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE)
 110                                *pdw |= 0;
 111                        else
 112                                *pdw |= cpu_to_le32((0x03<<28)&0x30000000);
 113                }
 114        }
 115}
 116
 117static void fill_txdesc_phy(struct pkt_attrib *pattrib, __le32 *pdw)
 118{
 119        if (pattrib->ht_en) {
 120                *pdw |= (pattrib->bwmode&HT_CHANNEL_WIDTH_40) ? cpu_to_le32(BIT(25)) : 0;
 121
 122                if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER)
 123                        *pdw |= cpu_to_le32((0x01<<20)&0x003f0000);
 124                else if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_UPPER)
 125                        *pdw |= cpu_to_le32((0x02<<20)&0x003f0000);
 126                else if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE)
 127                        *pdw |= 0;
 128                else
 129                        *pdw |= cpu_to_le32((0x03<<20)&0x003f0000);
 130        }
 131}
 132
 133static s32 update_txdesc(struct xmit_frame *pxmitframe, u8 *pmem, s32 sz)
 134{
 135        int     pull = 0;
 136        uint    qsel;
 137        struct rtw_adapter      *padapter = pxmitframe->padapter;
 138        struct pkt_attrib       *pattrib = &pxmitframe->attrib;
 139        struct hal_data_8723a   *pHalData = GET_HAL_DATA(padapter);
 140        struct dm_priv  *pdmpriv = &pHalData->dmpriv;
 141        struct tx_desc  *ptxdesc = (struct tx_desc *)pmem;
 142        struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
 143        struct mlme_ext_info    *pmlmeinfo = &pmlmeext->mlmext_info;
 144        int     bmcst = is_multicast_ether_addr(pattrib->ra);
 145
 146        if (urb_zero_packet_chk(padapter, sz) == 0) {
 147                ptxdesc = (struct tx_desc *)(pmem+PACKET_OFFSET_SZ);
 148                pull = 1;
 149                pxmitframe->pkt_offset--;
 150        }
 151
 152        memset(ptxdesc, 0, sizeof(struct tx_desc));
 153
 154        if (pxmitframe->frame_tag == DATA_FRAMETAG) {
 155                /* offset 4 */
 156                ptxdesc->txdw1 |= cpu_to_le32(pattrib->mac_id&0x1f);
 157
 158                qsel = (uint)(pattrib->qsel & 0x0000001f);
 159                ptxdesc->txdw1 |= cpu_to_le32((qsel << QSEL_SHT) & 0x00001f00);
 160
 161                ptxdesc->txdw1 |= cpu_to_le32((pattrib->raid<<16) & 0x000f0000);
 162
 163                fill_txdesc_sectype(pattrib, ptxdesc);
 164
 165                if (pattrib->ampdu_en)
 166                        ptxdesc->txdw1 |= cpu_to_le32(BIT(5));/* AGG EN */
 167                else
 168                        ptxdesc->txdw1 |= cpu_to_le32(BIT(6));/* AGG BK */
 169
 170                /* offset 8 */
 171
 172                /* offset 12 */
 173                ptxdesc->txdw3 |= cpu_to_le32((pattrib->seqnum<<16)&0xffff0000);
 174
 175                /* offset 16 , offset 20 */
 176                if (pattrib->qos_en)
 177                        ptxdesc->txdw4 |= cpu_to_le32(BIT(6));/* QoS */
 178
 179                if ((pattrib->ether_type != 0x888e) &&
 180                    (pattrib->ether_type != 0x0806) &&
 181                    (pattrib->dhcp_pkt != 1)) {
 182                        /* Non EAP & ARP & DHCP type data packet */
 183
 184                        fill_txdesc_vcs(pattrib, &ptxdesc->txdw4);
 185                        fill_txdesc_phy(pattrib, &ptxdesc->txdw4);
 186
 187                        ptxdesc->txdw4 |= cpu_to_le32(0x00000008);/* RTS Rate = 24M */
 188                        ptxdesc->txdw5 |= cpu_to_le32(0x0001ff00);/*  */
 189
 190                        /* use REG_INIDATA_RATE_SEL value */
 191                        ptxdesc->txdw5 |= cpu_to_le32(pdmpriv->INIDATA_RATE[pattrib->mac_id]);
 192                } else {
 193                        /*  EAP data packet and ARP packet. */
 194                        /*  Use the 1M data rate to send the EAP/ARP packet. */
 195                        /*  This will maybe make the handshake smooth. */
 196
 197                        ptxdesc->txdw1 |= cpu_to_le32(BIT(6));/* AGG BK */
 198
 199                        ptxdesc->txdw4 |= cpu_to_le32(BIT(8));/* driver uses rate */
 200
 201                        if (pmlmeinfo->preamble_mode == PREAMBLE_SHORT)
 202                                ptxdesc->txdw4 |= cpu_to_le32(BIT(24));/*  DATA_SHORT */
 203
 204                        ptxdesc->txdw5 |= cpu_to_le32(MRateToHwRate23a(pmlmeext->tx_rate));
 205                }
 206        } else if (pxmitframe->frame_tag == MGNT_FRAMETAG) {
 207                /* offset 4 */
 208                ptxdesc->txdw1 |= cpu_to_le32(pattrib->mac_id&0x1f);
 209
 210                qsel = (uint)(pattrib->qsel&0x0000001f);
 211                ptxdesc->txdw1 |= cpu_to_le32((qsel<<QSEL_SHT)&0x00001f00);
 212
 213                ptxdesc->txdw1 |= cpu_to_le32((pattrib->raid<<16) & 0x000f0000);
 214
 215                /* offset 8 */
 216                /* CCX-TXRPT ack for xmit mgmt frames. */
 217                if (pxmitframe->ack_report)
 218                        ptxdesc->txdw2 |= cpu_to_le32(BIT(19));
 219
 220                /* offset 12 */
 221                ptxdesc->txdw3 |= cpu_to_le32((pattrib->seqnum<<16)&0xffff0000);
 222
 223                /* offset 16 */
 224                ptxdesc->txdw4 |= cpu_to_le32(BIT(8));/* driver uses rate */
 225
 226                /* offset 20 */
 227                ptxdesc->txdw5 |= cpu_to_le32(BIT(17));/* retry limit enable */
 228                ptxdesc->txdw5 |= cpu_to_le32(0x00180000);/* retry limit = 6 */
 229
 230                ptxdesc->txdw5 |= cpu_to_le32(MRateToHwRate23a(pmlmeext->tx_rate));
 231        } else if (pxmitframe->frame_tag == TXAGG_FRAMETAG) {
 232                DBG_8723A("pxmitframe->frame_tag == TXAGG_FRAMETAG\n");
 233        } else {
 234                DBG_8723A("pxmitframe->frame_tag = %d\n",
 235                          pxmitframe->frame_tag);
 236
 237                /* offset 4 */
 238                ptxdesc->txdw1 |= cpu_to_le32((4)&0x1f);/* CAM_ID(MAC_ID) */
 239
 240                ptxdesc->txdw1 |= cpu_to_le32((6<<16) & 0x000f0000);/* raid */
 241
 242                /* offset 8 */
 243
 244                /* offset 12 */
 245                ptxdesc->txdw3 |= cpu_to_le32((pattrib->seqnum<<16)&0xffff0000);
 246
 247                /* offset 16 */
 248                ptxdesc->txdw4 |= cpu_to_le32(BIT(8));/* driver uses rate */
 249
 250                /* offset 20 */
 251                ptxdesc->txdw5 |= cpu_to_le32(MRateToHwRate23a(pmlmeext->tx_rate));
 252        }
 253
 254        /*  (1) The sequence number of each non-Qos frame / broadcast / multicast / */
 255        /*  mgnt frame should be controlled by Hw because Fw will also send null data */
 256        /*  which we cannot control when Fw LPS enable. */
 257        /*  --> default enable non-Qos data sequense number. 2010.06.23. by tynli. */
 258        /*  (2) Enable HW SEQ control for beacon packet, because we use Hw beacon. */
 259        /*  (3) Use HW Qos SEQ to control the seq num of Ext port non-Qos packets. */
 260        if (!pattrib->qos_en) {
 261                /*  Hw set sequence number */
 262                ptxdesc->txdw4 |= cpu_to_le32(BIT(7));
 263                /* set bit3 to 1. */
 264                ptxdesc->txdw3 |= cpu_to_le32((8 << 28));
 265        }
 266
 267        /* offset 0 */
 268        ptxdesc->txdw0 |= cpu_to_le32(sz&0x0000ffff);
 269        ptxdesc->txdw0 |= cpu_to_le32(OWN | FSG | LSG);
 270        ptxdesc->txdw0 |= cpu_to_le32(((TXDESC_SIZE+OFFSET_SZ)<<OFFSET_SHT)&0x00ff0000);/* 32 bytes for TX Desc */
 271
 272        if (bmcst)
 273                ptxdesc->txdw0 |= cpu_to_le32(BIT(24));
 274
 275        RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_,
 276                 "offset0-txdesc = 0x%x\n", ptxdesc->txdw0);
 277
 278        /* offset 4 */
 279        /*  pkt_offset, unit:8 bytes padding */
 280        if (pxmitframe->pkt_offset > 0)
 281                ptxdesc->txdw1 |= cpu_to_le32((pxmitframe->pkt_offset << 26) & 0x7c000000);
 282
 283        rtl8192cu_cal_txdesc_chksum(ptxdesc);
 284        return pull;
 285}
 286
 287static int rtw_dump_xframe(struct rtw_adapter *padapter,
 288                           struct xmit_frame *pxmitframe)
 289{
 290        int ret = _SUCCESS;
 291        int inner_ret = _SUCCESS;
 292        int t, sz, w_sz, pull = 0;
 293        u8 *mem_addr;
 294        u32 ff_hwaddr;
 295        struct xmit_buf *pxmitbuf = pxmitframe->pxmitbuf;
 296        struct pkt_attrib *pattrib = &pxmitframe->attrib;
 297        struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
 298
 299        if (pxmitframe->frame_tag == DATA_FRAMETAG &&
 300            pxmitframe->attrib.ether_type != ETH_P_ARP &&
 301            pxmitframe->attrib.ether_type != ETH_P_PAE &&
 302            pxmitframe->attrib.dhcp_pkt != 1)
 303                rtw_issue_addbareq_cmd23a(padapter, pxmitframe);
 304
 305        mem_addr = pxmitframe->buf_addr;
 306
 307        RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, "rtw_dump_xframe()\n");
 308
 309        for (t = 0; t < pattrib->nr_frags; t++) {
 310                if (inner_ret != _SUCCESS && ret == _SUCCESS)
 311                        ret = _FAIL;
 312
 313                if (t != (pattrib->nr_frags - 1)) {
 314                        RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
 315                                 "pattrib->nr_frags =%d\n", pattrib->nr_frags);
 316
 317                        sz = pxmitpriv->frag_len;
 318                        sz = sz - 4 - pattrib->icv_len;
 319                } else {
 320                        /* no frag */
 321                        sz = pattrib->last_txcmdsz;
 322                }
 323
 324                pull = update_txdesc(pxmitframe, mem_addr, sz);
 325
 326                if (pull) {
 327                        mem_addr += PACKET_OFFSET_SZ; /* pull txdesc head */
 328
 329                        pxmitframe->buf_addr = mem_addr;
 330
 331                        w_sz = sz + TXDESC_SIZE;
 332                } else {
 333                        w_sz = sz + TXDESC_SIZE + PACKET_OFFSET_SZ;
 334                }
 335
 336                ff_hwaddr = rtw_get_ff_hwaddr23a(pxmitframe);
 337                inner_ret = rtl8723au_write_port(padapter, ff_hwaddr,
 338                                                 w_sz, pxmitbuf);
 339                rtw_count_tx_stats23a(padapter, pxmitframe, sz);
 340
 341                RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_,
 342                         "rtw_write_port, w_sz =%d\n", w_sz);
 343
 344                mem_addr += w_sz;
 345
 346                mem_addr = PTR_ALIGN(mem_addr, 4);
 347        }
 348
 349        rtw_free_xmitframe23a(pxmitpriv, pxmitframe);
 350
 351        if  (ret != _SUCCESS)
 352                rtw23a_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_UNKNOWN);
 353
 354        return ret;
 355}
 356
 357bool rtl8723au_xmitframe_complete(struct rtw_adapter *padapter,
 358                                  struct xmit_priv *pxmitpriv,
 359                                  struct xmit_buf *pxmitbuf)
 360{
 361        struct hw_xmit *phwxmits;
 362        struct xmit_frame *pxmitframe;
 363        int hwentry;
 364        int res = _SUCCESS, xcnt = 0;
 365
 366        phwxmits = pxmitpriv->hwxmits;
 367        hwentry = pxmitpriv->hwxmit_entry;
 368
 369        RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, "xmitframe_complete()\n");
 370
 371        if (pxmitbuf == NULL) {
 372                pxmitbuf = rtw_alloc_xmitbuf23a(pxmitpriv);
 373                if (!pxmitbuf)
 374                        return false;
 375        }
 376        pxmitframe =  rtw_dequeue_xframe23a(pxmitpriv, phwxmits, hwentry);
 377
 378        if (pxmitframe) {
 379                pxmitframe->pxmitbuf = pxmitbuf;
 380
 381                pxmitframe->buf_addr = pxmitbuf->pbuf;
 382
 383                pxmitbuf->priv_data = pxmitframe;
 384
 385                if (pxmitframe->frame_tag == DATA_FRAMETAG) {
 386                        if (pxmitframe->attrib.priority <= 15)/* TID0~15 */
 387                                res = rtw_xmitframe_coalesce23a(padapter, pxmitframe->pkt, pxmitframe);
 388
 389                        rtw_os_xmit_complete23a(padapter, pxmitframe);/* always return ndis_packet after rtw_xmitframe_coalesce23a */
 390                }
 391
 392                RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_,
 393                         "xmitframe_complete(): rtw_dump_xframe\n");
 394
 395                if (res == _SUCCESS) {
 396                        rtw_dump_xframe(padapter, pxmitframe);
 397                } else {
 398                        rtw_free_xmitbuf23a(pxmitpriv, pxmitbuf);
 399                        rtw_free_xmitframe23a(pxmitpriv, pxmitframe);
 400                }
 401                xcnt++;
 402        } else {
 403                rtw_free_xmitbuf23a(pxmitpriv, pxmitbuf);
 404                return false;
 405        }
 406        return true;
 407}
 408
 409static int xmitframe_direct(struct rtw_adapter *padapter,
 410                            struct xmit_frame *pxmitframe)
 411{
 412        int res;
 413
 414        res = rtw_xmitframe_coalesce23a(padapter, pxmitframe->pkt, pxmitframe);
 415        if (res == _SUCCESS)
 416                rtw_dump_xframe(padapter, pxmitframe);
 417        return res;
 418}
 419
 420/*
 421 * Return
 422 *      true    dump packet directly
 423 *      false   enqueue packet
 424 */
 425bool rtl8723au_hal_xmit(struct rtw_adapter *padapter,
 426                        struct xmit_frame *pxmitframe)
 427{
 428        int res;
 429        struct xmit_buf *pxmitbuf = NULL;
 430        struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
 431        struct pkt_attrib *pattrib = &pxmitframe->attrib;
 432        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
 433
 434        pattrib->qsel = pattrib->priority;
 435        spin_lock_bh(&pxmitpriv->lock);
 436
 437#ifdef CONFIG_8723AU_AP_MODE
 438        if (xmitframe_enqueue_for_sleeping_sta23a(padapter, pxmitframe)) {
 439                struct sta_info *psta;
 440                struct sta_priv *pstapriv = &padapter->stapriv;
 441
 442                spin_unlock_bh(&pxmitpriv->lock);
 443
 444                if (pattrib->psta)
 445                        psta = pattrib->psta;
 446                else
 447                        psta = rtw_get_stainfo23a(pstapriv, pattrib->ra);
 448
 449                if (psta) {
 450                        if (psta->sleepq_len > (NR_XMITFRAME>>3))
 451                                wakeup_sta_to_xmit23a(padapter, psta);
 452                }
 453
 454                return false;
 455        }
 456#endif
 457
 458        if (rtw_txframes_sta_ac_pending23a(padapter, pattrib) > 0)
 459                goto enqueue;
 460
 461        if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING) == true)
 462                goto enqueue;
 463
 464        pxmitbuf = rtw_alloc_xmitbuf23a(pxmitpriv);
 465        if (pxmitbuf == NULL)
 466                goto enqueue;
 467
 468        spin_unlock_bh(&pxmitpriv->lock);
 469
 470        pxmitframe->pxmitbuf = pxmitbuf;
 471        pxmitframe->buf_addr = pxmitbuf->pbuf;
 472        pxmitbuf->priv_data = pxmitframe;
 473
 474        if (xmitframe_direct(padapter, pxmitframe) != _SUCCESS) {
 475                rtw_free_xmitbuf23a(pxmitpriv, pxmitbuf);
 476                rtw_free_xmitframe23a(pxmitpriv, pxmitframe);
 477        }
 478        return true;
 479
 480enqueue:
 481        res = rtw_xmitframe_enqueue23a(padapter, pxmitframe);
 482        spin_unlock_bh(&pxmitpriv->lock);
 483
 484        if (res != _SUCCESS) {
 485                RT_TRACE(_module_xmit_osdep_c_, _drv_err_,
 486                         "pre_xmitframe: enqueue xmitframe fail\n");
 487                rtw_free_xmitframe23a(pxmitpriv, pxmitframe);
 488
 489                /*  Trick, make the statistics correct */
 490                pxmitpriv->tx_pkts--;
 491                pxmitpriv->tx_drop++;
 492                return true;
 493        }
 494        return false;
 495}
 496
 497int rtl8723au_mgnt_xmit(struct rtw_adapter *padapter,
 498                        struct xmit_frame *pmgntframe)
 499{
 500        return rtw_dump_xframe(padapter, pmgntframe);
 501}
 502
 503int rtl8723au_hal_xmitframe_enqueue(struct rtw_adapter *padapter,
 504                                    struct xmit_frame *pxmitframe)
 505{
 506        struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
 507        int err;
 508
 509        err = rtw_xmitframe_enqueue23a(padapter, pxmitframe);
 510        if (err != _SUCCESS) {
 511                rtw_free_xmitframe23a(pxmitpriv, pxmitframe);
 512
 513                /*  Trick, make the statistics correct */
 514                pxmitpriv->tx_pkts--;
 515                pxmitpriv->tx_drop++;
 516        } else {
 517                tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
 518        }
 519        return err;
 520}
 521