root/drivers/staging/rtl8192u/r819xU_cmdpkt.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. SendTxCommandPacket
  2. cmpk_count_txstatistic
  3. cmpk_handle_tx_feedback
  4. cmdpkt_beacontimerinterrupt_819xusb
  5. cmpk_handle_interrupt_status
  6. cmpk_handle_query_config_rx
  7. cmpk_count_tx_status
  8. cmpk_handle_tx_status
  9. cmpk_handle_tx_rate_history
  10. cmpk_message_handle_rx

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

/* [<][>][^][v][top][bottom][index][help] */