linux/drivers/staging/rtl8192u/r819xU_cmdpkt.c
<<
>>
Prefs
   1/******************************************************************************
   2 *
   3 *  (c) Copyright 2008, RealTEK Technologies Inc. All Rights Reserved.
   4 *
   5 *  Module:     r819xusb_cmdpkt.c
   6 *              (RTL8190 TX/RX command packet handler Source C File)
   7 *
   8 *  Note:       The module is responsible for handling TX and RX command packet.
   9 *              1. TX : Send set and query configuration command packet.
  10 *              2. RX : Receive tx feedback, beacon state, query configuration
  11 *                      command packet.
  12 *
  13 *  Function:
  14 *
  15 *  Export:
  16 *
  17 *  Abbrev:
  18 *
  19 *  History:
  20 *
  21 *      Date            Who             Remark
  22 *      05/06/2008      amy             Create initial version porting from
  23 *                                      windows driver.
  24 *
  25 ******************************************************************************/
  26#include "r8192U.h"
  27#include "r819xU_cmdpkt.h"
  28
  29rt_status SendTxCommandPacket(struct net_device *dev, void *pData, u32 DataLen)
  30{
  31        rt_status       rtStatus = RT_STATUS_SUCCESS;
  32        struct r8192_priv   *priv = ieee80211_priv(dev);
  33        struct sk_buff      *skb;
  34        cb_desc             *tcb_desc;
  35        unsigned char       *ptr_buf;
  36
  37        /* Get TCB and local buffer from common pool.
  38           (It is shared by CmdQ, MgntQ, and USB coalesce DataQ) */
  39        skb  = dev_alloc_skb(USB_HWDESC_HEADER_LEN + DataLen + 4);
  40        if (!skb)
  41                return RT_STATUS_FAILURE;
  42        memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev));
  43        tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
  44        tcb_desc->queue_index = TXCMD_QUEUE;
  45        tcb_desc->bCmdOrInit = DESC_PACKET_TYPE_NORMAL;
  46        tcb_desc->bLastIniPkt = 0;
  47        skb_reserve(skb, USB_HWDESC_HEADER_LEN);
  48        ptr_buf = skb_put(skb, DataLen);
  49        memcpy(ptr_buf, pData, DataLen);
  50        tcb_desc->txbuf_size = (u16)DataLen;
  51
  52        if (!priv->ieee80211->check_nic_enough_desc(dev, tcb_desc->queue_index) ||
  53            (!skb_queue_empty(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index])) ||
  54            (priv->ieee80211->queue_stop)) {
  55                RT_TRACE(COMP_FIRMWARE, "=== NULL packet ======> tx full!\n");
  56                skb_queue_tail(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index], skb);
  57        } else {
  58                priv->ieee80211->softmac_hard_start_xmit(skb, dev);
  59        }
  60
  61        return rtStatus;
  62}
  63
  64/*-----------------------------------------------------------------------------
  65 * Function:    cmpk_counttxstatistic()
  66 *
  67 * Overview:
  68 *
  69 * Input:       PADAPTER        pAdapter
  70 *              CMPK_TXFB_T     *psTx_FB
  71 *
  72 * Output:      NONE
  73 *
  74 * Return:      NONE
  75 *
  76 * Revised History:
  77 *  When                Who     Remark
  78 *  05/12/2008          amy     Create Version 0 porting from windows code.
  79 *
  80 *---------------------------------------------------------------------------*/
  81static void cmpk_count_txstatistic(struct net_device *dev, cmpk_txfb_t *pstx_fb)
  82{
  83        struct r8192_priv *priv = ieee80211_priv(dev);
  84#ifdef ENABLE_PS
  85        RT_RF_POWER_STATE       rtState;
  86
  87        pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE,
  88                                          (pu1Byte)(&rtState));
  89
  90        /* When RF is off, we should not count the packet for hw/sw synchronize
  91           reason, ie. there may be a duration while sw switch is changed and
  92           hw switch is being changed. */
  93        if (rtState == eRfOff)
  94                return;
  95#endif
  96
  97#ifdef TODO
  98        if (pAdapter->bInHctTest)
  99                return;
 100#endif
 101        /* We can not know the packet length and transmit type:
 102           broadcast or uni or multicast. So the relative statistics
 103           must be collected in tx feedback info. */
 104        if (pstx_fb->tok) {
 105                priv->stats.txfeedbackok++;
 106                priv->stats.txoktotal++;
 107                priv->stats.txokbytestotal += pstx_fb->pkt_length;
 108                priv->stats.txokinperiod++;
 109
 110                /* We can not make sure broadcast/multicast or unicast mode. */
 111                if (pstx_fb->pkt_type == PACKET_MULTICAST) {
 112                        priv->stats.txmulticast++;
 113                        priv->stats.txbytesmulticast += pstx_fb->pkt_length;
 114                } else if (pstx_fb->pkt_type == PACKET_BROADCAST) {
 115                        priv->stats.txbroadcast++;
 116                        priv->stats.txbytesbroadcast += pstx_fb->pkt_length;
 117                } else {
 118                        priv->stats.txunicast++;
 119                        priv->stats.txbytesunicast += pstx_fb->pkt_length;
 120                }
 121        } else {
 122                priv->stats.txfeedbackfail++;
 123                priv->stats.txerrtotal++;
 124                priv->stats.txerrbytestotal += pstx_fb->pkt_length;
 125
 126                /* We can not make sure broadcast/multicast or unicast mode. */
 127                if (pstx_fb->pkt_type == PACKET_MULTICAST)
 128                        priv->stats.txerrmulticast++;
 129                else if (pstx_fb->pkt_type == PACKET_BROADCAST)
 130                        priv->stats.txerrbroadcast++;
 131                else
 132                        priv->stats.txerrunicast++;
 133        }
 134
 135        priv->stats.txretrycount += pstx_fb->retry_cnt;
 136        priv->stats.txfeedbackretry += pstx_fb->retry_cnt;
 137
 138}
 139
 140
 141
 142/*-----------------------------------------------------------------------------
 143 * Function:    cmpk_handle_tx_feedback()
 144 *
 145 * Overview:    The function is responsible for extract the message inside TX
 146 *              feedbck message from firmware. It will contain dedicated info in
 147 *              ws-06-0063-rtl8190-command-packet-specification.
 148 *              Please refer to chapter "TX Feedback Element".
 149 *              We have to read 20 bytes in the command packet.
 150 *
 151 * Input:       struct net_device       *dev
 152 *              u8                      *pmsg   - Msg Ptr of the command packet.
 153 *
 154 * Output:      NONE
 155 *
 156 * Return:      NONE
 157 *
 158 * Revised History:
 159 *  When                Who     Remark
 160 *  05/08/2008          amy     Create Version 0 porting from windows code.
 161 *
 162 *---------------------------------------------------------------------------*/
 163static void cmpk_handle_tx_feedback(struct net_device *dev, u8 *pmsg)
 164{
 165        struct r8192_priv *priv = ieee80211_priv(dev);
 166        cmpk_txfb_t             rx_tx_fb;
 167
 168        priv->stats.txfeedback++;
 169
 170        /* 1. Extract TX feedback info from RFD to temp structure buffer. */
 171        /* It seems that FW use big endian(MIPS) and DRV use little endian in
 172           windows OS. So we have to read the content byte by byte or transfer
 173           endian type before copy the message copy. */
 174        /* Use pointer to transfer structure memory. */
 175        memcpy((u8 *)&rx_tx_fb, pmsg, sizeof(cmpk_txfb_t));
 176        /* 2. Use tx feedback info to count TX statistics. */
 177        cmpk_count_txstatistic(dev, &rx_tx_fb);
 178        /* Comment previous method for TX statistic function. */
 179        /* Collect info TX feedback packet to fill TCB. */
 180        /* We can not know the packet length and transmit type: broadcast or uni
 181           or multicast. */
 182
 183}
 184
 185void cmdpkt_beacontimerinterrupt_819xusb(struct net_device *dev)
 186{
 187        struct r8192_priv *priv = ieee80211_priv(dev);
 188        u16 tx_rate;
 189                /* 87B have to S/W beacon for DTM encryption_cmn. */
 190                if (priv->ieee80211->current_network.mode == IEEE_A ||
 191                        priv->ieee80211->current_network.mode == IEEE_N_5G ||
 192                        (priv->ieee80211->current_network.mode == IEEE_N_24G &&
 193                         (!priv->ieee80211->pHTInfo->bCurSuppCCK))) {
 194                        tx_rate = 60;
 195                        DMESG("send beacon frame  tx rate is 6Mbpm\n");
 196                } else {
 197                        tx_rate = 10;
 198                        DMESG("send beacon frame  tx rate is 1Mbpm\n");
 199                }
 200
 201                rtl819xusb_beacon_tx(dev, tx_rate); /* HW Beacon */
 202
 203
 204}
 205
 206
 207
 208
 209/*-----------------------------------------------------------------------------
 210 * Function:    cmpk_handle_interrupt_status()
 211 *
 212 * Overview:    The function is responsible for extract the message from
 213 *              firmware. It will contain dedicated info in
 214 *              ws-07-0063-v06-rtl819x-command-packet-specification-070315.doc.
 215 *              Please refer to chapter "Interrupt Status Element".
 216 *
 217 * Input:       struct net_device *dev
 218 *              u8 *pmsg                - Message Pointer of the command packet.
 219 *
 220 * Output:      NONE
 221 *
 222 * Return:      NONE
 223 *
 224 * Revised History:
 225 *  When                Who     Remark
 226 *  05/12/2008          amy     Add this for rtl8192 porting from windows code.
 227 *
 228 *---------------------------------------------------------------------------*/
 229static void cmpk_handle_interrupt_status(struct net_device *dev, u8 *pmsg)
 230{
 231        cmpk_intr_sta_t         rx_intr_status; /* */
 232        struct r8192_priv *priv = ieee80211_priv(dev);
 233
 234        DMESG("---> cmpk_Handle_Interrupt_Status()\n");
 235
 236        /* 1. Extract TX feedback info from RFD to temp structure buffer. */
 237        /* It seems that FW use big endian(MIPS) and DRV use little endian in
 238           windows OS. So we have to read the content byte by byte or transfer
 239           endian type before copy the message copy. */
 240        rx_intr_status.length = pmsg[1];
 241        if (rx_intr_status.length != (sizeof(cmpk_intr_sta_t) - 2)) {
 242                DMESG("cmpk_Handle_Interrupt_Status: wrong length!\n");
 243                return;
 244        }
 245
 246
 247        /* Statistics of beacon for ad-hoc mode. */
 248        if (priv->ieee80211->iw_mode == IW_MODE_ADHOC) {
 249                /* 2 maybe need endian transform? */
 250                rx_intr_status.interrupt_status = *((u32 *)(pmsg + 4));
 251
 252                DMESG("interrupt status = 0x%x\n",
 253                      rx_intr_status.interrupt_status);
 254
 255                if (rx_intr_status.interrupt_status & ISR_TxBcnOk) {
 256                        priv->ieee80211->bibsscoordinator = true;
 257                        priv->stats.txbeaconokint++;
 258                } else if (rx_intr_status.interrupt_status & ISR_TxBcnErr) {
 259                        priv->ieee80211->bibsscoordinator = false;
 260                        priv->stats.txbeaconerr++;
 261                }
 262
 263                if (rx_intr_status.interrupt_status & ISR_BcnTimerIntr)
 264                        cmdpkt_beacontimerinterrupt_819xusb(dev);
 265
 266        }
 267
 268        /* Other informations in interrupt status we need? */
 269
 270
 271        DMESG("<---- cmpk_handle_interrupt_status()\n");
 272
 273}
 274
 275
 276/*-----------------------------------------------------------------------------
 277 * Function:    cmpk_handle_query_config_rx()
 278 *
 279 * Overview:    The function is responsible for extract the message from
 280 *              firmware. It will contain dedicated info in
 281 *              ws-06-0063-rtl8190-command-packet-specification. Please
 282 *              refer to chapter "Beacon State Element".
 283 *
 284 * Input:       u8    *pmsg     -       Message Pointer of the command packet.
 285 *
 286 * Output:      NONE
 287 *
 288 * Return:      NONE
 289 *
 290 * Revised History:
 291 *  When                Who     Remark
 292 *  05/12/2008          amy     Create Version 0 porting from windows code.
 293 *
 294 *---------------------------------------------------------------------------*/
 295static void cmpk_handle_query_config_rx(struct net_device *dev, u8 *pmsg)
 296{
 297        cmpk_query_cfg_t        rx_query_cfg;
 298
 299
 300        /* 1. Extract TX feedback info from RFD to temp structure buffer. */
 301        /* It seems that FW use big endian(MIPS) and DRV use little endian in
 302           windows OS. So we have to read the content byte by byte or transfer
 303           endian type before copy the message copy. */
 304        rx_query_cfg.cfg_action         = (pmsg[4] & 0x80000000) >> 31;
 305        rx_query_cfg.cfg_type           = (pmsg[4] & 0x60) >> 5;
 306        rx_query_cfg.cfg_size           = (pmsg[4] & 0x18) >> 3;
 307        rx_query_cfg.cfg_page           = (pmsg[6] & 0x0F) >> 0;
 308        rx_query_cfg.cfg_offset         = pmsg[7];
 309        rx_query_cfg.value              = (pmsg[8]  << 24) | (pmsg[9]  << 16) |
 310                                          (pmsg[10] <<  8) | (pmsg[11] <<  0);
 311        rx_query_cfg.mask               = (pmsg[12] << 24) | (pmsg[13] << 16) |
 312                                          (pmsg[14] <<  8) | (pmsg[15] <<  0);
 313
 314}
 315
 316
 317/*-----------------------------------------------------------------------------
 318 * Function:    cmpk_count_tx_status()
 319 *
 320 * Overview:    Count aggregated tx status from firmwar of one type rx command
 321 *              packet element id = RX_TX_STATUS.
 322 *
 323 * Input:       NONE
 324 *
 325 * Output:      NONE
 326 *
 327 * Return:      NONE
 328 *
 329 * Revised History:
 330 *      When            Who     Remark
 331 *      05/12/2008      amy     Create Version 0 porting from windows code.
 332 *
 333 *---------------------------------------------------------------------------*/
 334static void cmpk_count_tx_status(struct net_device *dev,
 335                                 cmpk_tx_status_t *pstx_status)
 336{
 337        struct r8192_priv *priv = ieee80211_priv(dev);
 338
 339#ifdef ENABLE_PS
 340
 341        RT_RF_POWER_STATE       rtstate;
 342
 343        pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE,
 344                                          (pu1Byte)(&rtState));
 345
 346        /* When RF is off, we should not count the packet for hw/sw synchronize
 347           reason, ie. there may be a duration while sw switch is changed and
 348           hw switch is being changed. */
 349        if (rtState == eRfOff)
 350                return;
 351#endif
 352
 353        priv->stats.txfeedbackok        += pstx_status->txok;
 354        priv->stats.txoktotal           += pstx_status->txok;
 355
 356        priv->stats.txfeedbackfail      += pstx_status->txfail;
 357        priv->stats.txerrtotal          += pstx_status->txfail;
 358
 359        priv->stats.txretrycount        += pstx_status->txretry;
 360        priv->stats.txfeedbackretry     += pstx_status->txretry;
 361
 362
 363        priv->stats.txmulticast         += pstx_status->txmcok;
 364        priv->stats.txbroadcast         += pstx_status->txbcok;
 365        priv->stats.txunicast           += pstx_status->txucok;
 366
 367        priv->stats.txerrmulticast      += pstx_status->txmcfail;
 368        priv->stats.txerrbroadcast      += pstx_status->txbcfail;
 369        priv->stats.txerrunicast        += pstx_status->txucfail;
 370
 371        priv->stats.txbytesmulticast    += pstx_status->txmclength;
 372        priv->stats.txbytesbroadcast    += pstx_status->txbclength;
 373        priv->stats.txbytesunicast      += pstx_status->txuclength;
 374
 375        priv->stats.last_packet_rate    = pstx_status->rate;
 376}
 377
 378
 379
 380/*-----------------------------------------------------------------------------
 381 * Function:    cmpk_handle_tx_status()
 382 *
 383 * Overview:    Firmware add a new tx feedback status to reduce rx command
 384 *              packet buffer operation load.
 385 *
 386 * Input:               NONE
 387 *
 388 * Output:              NONE
 389 *
 390 * Return:              NONE
 391 *
 392 * Revised History:
 393 *      When            Who     Remark
 394 *      05/12/2008      amy     Create Version 0 porting from windows code.
 395 *
 396 *---------------------------------------------------------------------------*/
 397static void cmpk_handle_tx_status(struct net_device *dev, u8 *pmsg)
 398{
 399        cmpk_tx_status_t        rx_tx_sts;
 400
 401        memcpy((void *)&rx_tx_sts, (void *)pmsg, sizeof(cmpk_tx_status_t));
 402        /* 2. Use tx feedback info to count TX statistics. */
 403        cmpk_count_tx_status(dev, &rx_tx_sts);
 404
 405}
 406
 407
 408/*-----------------------------------------------------------------------------
 409 * Function:    cmpk_handle_tx_rate_history()
 410 *
 411 * Overview:    Firmware add a new tx rate history
 412 *
 413 * Input:               NONE
 414 *
 415 * Output:              NONE
 416 *
 417 * Return:              NONE
 418 *
 419 * Revised History:
 420 *      When            Who     Remark
 421 *      05/12/2008      amy     Create Version 0 porting from windows code.
 422 *
 423 *---------------------------------------------------------------------------*/
 424static void cmpk_handle_tx_rate_history(struct net_device *dev, u8 *pmsg)
 425{
 426        cmpk_tx_rahis_t *ptxrate;
 427        u8              i, j;
 428        u16             length = sizeof(cmpk_tx_rahis_t);
 429        u32             *ptemp;
 430        struct r8192_priv *priv = ieee80211_priv(dev);
 431
 432
 433#ifdef ENABLE_PS
 434        pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE,
 435                                          (pu1Byte)(&rtState));
 436
 437        /* When RF is off, we should not count the packet for hw/sw synchronize
 438           reason, ie. there may be a duration while sw switch is changed and
 439           hw switch is being changed. */
 440        if (rtState == eRfOff)
 441                return;
 442#endif
 443
 444        ptemp = (u32 *)pmsg;
 445
 446        /* Do endian transfer to word alignment(16 bits) for windows system.
 447           You must do different endian transfer for linux and MAC OS */
 448        for (i = 0; i < (length/4); i++) {
 449                u16      temp1, temp2;
 450
 451                temp1 = ptemp[i] & 0x0000FFFF;
 452                temp2 = ptemp[i] >> 16;
 453                ptemp[i] = (temp1 << 16) | temp2;
 454        }
 455
 456        ptxrate = (cmpk_tx_rahis_t *)pmsg;
 457
 458        if (ptxrate == NULL)
 459                return;
 460
 461        for (i = 0; i < 16; i++) {
 462                /* Collect CCK rate packet num */
 463                if (i < 4)
 464                        priv->stats.txrate.cck[i] += ptxrate->cck[i];
 465
 466                /* Collect OFDM rate packet num */
 467                if (i < 8)
 468                        priv->stats.txrate.ofdm[i] += ptxrate->ofdm[i];
 469
 470                for (j = 0; j < 4; j++)
 471                        priv->stats.txrate.ht_mcs[j][i] += ptxrate->ht_mcs[j][i];
 472        }
 473
 474}
 475
 476
 477/*-----------------------------------------------------------------------------
 478 * Function:    cmpk_message_handle_rx()
 479 *
 480 * Overview:    In the function, we will capture different RX command packet
 481 *              info. Every RX command packet element has different message
 482 *              length and meaning in content. We only support three type of RX
 483 *              command packet now. Please refer to document
 484 *              ws-06-0063-rtl8190-command-packet-specification.
 485 *
 486 * Input:       NONE
 487 *
 488 * Output:      NONE
 489 *
 490 * Return:      NONE
 491 *
 492 * Revised History:
 493 *  When                Who     Remark
 494 *  05/06/2008          amy     Create Version 0 porting from windows code.
 495 *
 496 *---------------------------------------------------------------------------*/
 497u32 cmpk_message_handle_rx(struct net_device *dev,
 498                           struct ieee80211_rx_stats *pstats)
 499{
 500        int                     total_length;
 501        u8                      cmd_length, exe_cnt = 0;
 502        u8                      element_id;
 503        u8                      *pcmd_buff;
 504
 505        /* 0. Check inpt arguments. If is is a command queue message or
 506           pointer is null. */
 507        if (pstats == NULL)
 508                return 0;       /* This is not a command packet. */
 509
 510        /* 1. Read received command packet message length from RFD. */
 511        total_length = pstats->Length;
 512
 513        /* 2. Read virtual address from RFD. */
 514        pcmd_buff = pstats->virtual_address;
 515
 516        /* 3. Read command packet element id and length. */
 517        element_id = pcmd_buff[0];
 518
 519        /* 4. Check every received command packet content according to different
 520              element type. Because FW may aggregate RX command packet to
 521              minimize transmit time between DRV and FW.*/
 522        /* Add a counter to prevent the lock in the loop from being held too
 523           long */
 524        while (total_length > 0 && exe_cnt++ < 100) {
 525                /* We support aggregation of different cmd in the same packet */
 526                element_id = pcmd_buff[0];
 527
 528                switch (element_id) {
 529                case RX_TX_FEEDBACK:
 530                        cmpk_handle_tx_feedback(dev, pcmd_buff);
 531                        cmd_length = CMPK_RX_TX_FB_SIZE;
 532                        break;
 533
 534                case RX_INTERRUPT_STATUS:
 535                        cmpk_handle_interrupt_status(dev, pcmd_buff);
 536                        cmd_length = sizeof(cmpk_intr_sta_t);
 537                        break;
 538
 539                case BOTH_QUERY_CONFIG:
 540                        cmpk_handle_query_config_rx(dev, pcmd_buff);
 541                        cmd_length = CMPK_BOTH_QUERY_CONFIG_SIZE;
 542                        break;
 543
 544                case RX_TX_STATUS:
 545                        cmpk_handle_tx_status(dev, pcmd_buff);
 546                        cmd_length = CMPK_RX_TX_STS_SIZE;
 547                        break;
 548
 549                case RX_TX_PER_PKT_FEEDBACK:
 550                        /* You must at lease add a switch case element here,
 551                           Otherwise, we will jump to default case. */
 552                        cmd_length = CMPK_RX_TX_FB_SIZE;
 553                        break;
 554
 555                case RX_TX_RATE_HISTORY:
 556                        cmpk_handle_tx_rate_history(dev, pcmd_buff);
 557                        cmd_length = CMPK_TX_RAHIS_SIZE;
 558                        break;
 559
 560                default:
 561
 562                        RT_TRACE(COMP_ERR, "---->%s():unknown CMD Element\n",
 563                                 __func__);
 564                        return 1;       /* This is a command packet. */
 565                }
 566
 567                total_length -= cmd_length;
 568                pcmd_buff    += cmd_length;
 569        }
 570        return  1;      /* This is a command packet. */
 571
 572}
 573