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