Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /******************************************************************************
0003  *
0004  *  (c) Copyright 2008, RealTEK Technologies Inc. All Rights Reserved.
0005  *
0006  *  Module: r819xusb_cmdpkt.c
0007  *      (RTL8190 TX/RX command packet handler Source C File)
0008  *
0009  *  Note:   The module is responsible for handling TX and RX command packet.
0010  *      1. TX : Send set and query configuration command packet.
0011  *      2. RX : Receive tx feedback, beacon state, query configuration
0012  *          command packet.
0013  *
0014  *  Function:
0015  *
0016  *  Export:
0017  *
0018  *  Abbrev:
0019  *
0020  *  History:
0021  *
0022  *  Date        Who     Remark
0023  *  05/06/2008  amy     Create initial version porting from
0024  *                  windows driver.
0025  *
0026  ******************************************************************************/
0027 #include "r8192U.h"
0028 #include "r819xU_cmdpkt.h"
0029 
0030 rt_status SendTxCommandPacket(struct net_device *dev, void *pData, u32 DataLen)
0031 {
0032     struct r8192_priv   *priv = ieee80211_priv(dev);
0033     struct sk_buff      *skb;
0034     struct cb_desc      *tcb_desc;
0035 
0036     /* Get TCB and local buffer from common pool.
0037      * (It is shared by CmdQ, MgntQ, and USB coalesce DataQ)
0038      */
0039     skb  = dev_alloc_skb(USB_HWDESC_HEADER_LEN + DataLen + 4);
0040     if (!skb)
0041         return RT_STATUS_FAILURE;
0042     memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev));
0043     tcb_desc = (struct cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
0044     tcb_desc->queue_index = TXCMD_QUEUE;
0045     tcb_desc->bCmdOrInit = DESC_PACKET_TYPE_NORMAL;
0046     tcb_desc->bLastIniPkt = 0;
0047     skb_reserve(skb, USB_HWDESC_HEADER_LEN);
0048     skb_put_data(skb, pData, DataLen);
0049     tcb_desc->txbuf_size = (u16)DataLen;
0050 
0051     if (!priv->ieee80211->check_nic_enough_desc(dev, tcb_desc->queue_index) ||
0052         (!skb_queue_empty(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index])) ||
0053         (priv->ieee80211->queue_stop)) {
0054         RT_TRACE(COMP_FIRMWARE, "=== NULL packet ======> tx full!\n");
0055         skb_queue_tail(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index], skb);
0056     } else {
0057         priv->ieee80211->softmac_hard_start_xmit(skb, dev);
0058     }
0059 
0060     return RT_STATUS_SUCCESS;
0061 }
0062 
0063 static void cmpk_count_txstatistic(struct net_device *dev, struct cmd_pkt_tx_feedback *pstx_fb)
0064 {
0065     struct r8192_priv *priv = ieee80211_priv(dev);
0066 #ifdef ENABLE_PS
0067     RT_RF_POWER_STATE   rtState;
0068 
0069     pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE,
0070                       (pu1Byte)(&rtState));
0071 
0072     /* When RF is off, we should not count the packet for hw/sw synchronize
0073      * reason, ie. there may be a duration while sw switch is changed and
0074      * hw switch is being changed.
0075      */
0076     if (rtState == eRfOff)
0077         return;
0078 #endif
0079 
0080 #ifdef TODO
0081     if (pAdapter->bInHctTest)
0082         return;
0083 #endif
0084     /* We can not know the packet length and transmit type:
0085      * broadcast or uni or multicast. So the relative statistics
0086      * must be collected in tx feedback info.
0087      */
0088     if (pstx_fb->tok) {
0089         priv->stats.txfeedbackok++;
0090         priv->stats.txoktotal++;
0091         priv->stats.txokbytestotal += pstx_fb->pkt_length;
0092         priv->stats.txokinperiod++;
0093 
0094         /* We can not make sure broadcast/multicast or unicast mode. */
0095         if (pstx_fb->pkt_type == PACKET_MULTICAST) {
0096             priv->stats.txmulticast++;
0097             priv->stats.txbytesmulticast += pstx_fb->pkt_length;
0098         } else if (pstx_fb->pkt_type == PACKET_BROADCAST) {
0099             priv->stats.txbroadcast++;
0100             priv->stats.txbytesbroadcast += pstx_fb->pkt_length;
0101         } else {
0102             priv->stats.txunicast++;
0103             priv->stats.txbytesunicast += pstx_fb->pkt_length;
0104         }
0105     } else {
0106         priv->stats.txfeedbackfail++;
0107         priv->stats.txerrtotal++;
0108         priv->stats.txerrbytestotal += pstx_fb->pkt_length;
0109 
0110         /* We can not make sure broadcast/multicast or unicast mode. */
0111         if (pstx_fb->pkt_type == PACKET_MULTICAST)
0112             priv->stats.txerrmulticast++;
0113         else if (pstx_fb->pkt_type == PACKET_BROADCAST)
0114             priv->stats.txerrbroadcast++;
0115         else
0116             priv->stats.txerrunicast++;
0117     }
0118 
0119     priv->stats.txretrycount += pstx_fb->retry_cnt;
0120     priv->stats.txfeedbackretry += pstx_fb->retry_cnt;
0121 }
0122 
0123 /*-----------------------------------------------------------------------------
0124  * Function:    cmpk_handle_tx_feedback()
0125  *
0126  * Overview:    The function is responsible for extract the message inside TX
0127  *      feedbck message from firmware. It will contain dedicated info in
0128  *      ws-06-0063-rtl8190-command-packet-specification.
0129  *      Please refer to chapter "TX Feedback Element".
0130  *              We have to read 20 bytes in the command packet.
0131  *
0132  * Input:       struct net_device   *dev
0133  *              u8          *pmsg   - Msg Ptr of the command packet.
0134  *
0135  * Output:      NONE
0136  *
0137  * Return:      NONE
0138  *
0139  * Revised History:
0140  *  When        Who Remark
0141  *  05/08/2008      amy Create Version 0 porting from windows code.
0142  *
0143  *---------------------------------------------------------------------------
0144  */
0145 static void cmpk_handle_tx_feedback(struct net_device *dev, u8 *pmsg)
0146 {
0147     struct r8192_priv *priv = ieee80211_priv(dev);
0148     struct cmd_pkt_tx_feedback rx_tx_fb;
0149 
0150     priv->stats.txfeedback++;
0151 
0152     /* 1. Extract TX feedback info from RFD to temp structure buffer. */
0153     /* It seems that FW use big endian(MIPS) and DRV use little endian in
0154      * windows OS. So we have to read the content byte by byte or transfer
0155      * endian type before copy the message copy.
0156      */
0157     /* Use pointer to transfer structure memory. */
0158     memcpy((u8 *)&rx_tx_fb, pmsg, sizeof(struct cmd_pkt_tx_feedback));
0159     /* 2. Use tx feedback info to count TX statistics. */
0160     cmpk_count_txstatistic(dev, &rx_tx_fb);
0161     /* Comment previous method for TX statistic function. */
0162     /* Collect info TX feedback packet to fill TCB. */
0163     /* We can not know the packet length and transmit type: broadcast or uni
0164      * or multicast.
0165      */
0166 }
0167 
0168 static void cmdpkt_beacontimerinterrupt_819xusb(struct net_device *dev)
0169 {
0170     struct r8192_priv *priv = ieee80211_priv(dev);
0171     u16 tx_rate;
0172 
0173     /* 87B have to S/W beacon for DTM encryption_cmn. */
0174     if (priv->ieee80211->current_network.mode == IEEE_A ||
0175         priv->ieee80211->current_network.mode == IEEE_N_5G ||
0176         (priv->ieee80211->current_network.mode == IEEE_N_24G &&
0177          (!priv->ieee80211->pHTInfo->bCurSuppCCK))) {
0178         tx_rate = 60;
0179         DMESG("send beacon frame  tx rate is 6Mbpm\n");
0180     } else {
0181         tx_rate = 10;
0182         DMESG("send beacon frame  tx rate is 1Mbpm\n");
0183     }
0184 
0185     rtl819xusb_beacon_tx(dev, tx_rate); /* HW Beacon */
0186 }
0187 
0188 /*-----------------------------------------------------------------------------
0189  * Function:    cmpk_handle_interrupt_status()
0190  *
0191  * Overview:    The function is responsible for extract the message from
0192  *      firmware. It will contain dedicated info in
0193  *      ws-07-0063-v06-rtl819x-command-packet-specification-070315.doc.
0194  *      Please refer to chapter "Interrupt Status Element".
0195  *
0196  * Input:       struct net_device *dev
0197  *              u8 *pmsg        - Message Pointer of the command packet.
0198  *
0199  * Output:      NONE
0200  *
0201  * Return:      NONE
0202  *
0203  * Revised History:
0204  *  When        Who Remark
0205  *  05/12/2008      amy Add this for rtl8192 porting from windows code.
0206  *
0207  *---------------------------------------------------------------------------
0208  */
0209 static void cmpk_handle_interrupt_status(struct net_device *dev, u8 *pmsg)
0210 {
0211     struct cmd_pkt_interrupt_status  rx_intr_status;    /* */
0212     struct r8192_priv *priv = ieee80211_priv(dev);
0213 
0214     DMESG("---> cmpk_Handle_Interrupt_Status()\n");
0215 
0216     /* 1. Extract TX feedback info from RFD to temp structure buffer. */
0217     /* It seems that FW use big endian(MIPS) and DRV use little endian in
0218      * windows OS. So we have to read the content byte by byte or transfer
0219      * endian type before copy the message copy.
0220      */
0221     rx_intr_status.length = pmsg[1];
0222     if (rx_intr_status.length != (sizeof(struct cmd_pkt_interrupt_status) - 2)) {
0223         DMESG("cmpk_Handle_Interrupt_Status: wrong length!\n");
0224         return;
0225     }
0226 
0227     /* Statistics of beacon for ad-hoc mode. */
0228     if (priv->ieee80211->iw_mode == IW_MODE_ADHOC) {
0229         /* 2 maybe need endian transform? */
0230         rx_intr_status.interrupt_status = *((u32 *)(pmsg + 4));
0231 
0232         DMESG("interrupt status = 0x%x\n",
0233               rx_intr_status.interrupt_status);
0234 
0235         if (rx_intr_status.interrupt_status & ISR_TX_BCN_OK) {
0236             priv->ieee80211->bibsscoordinator = true;
0237             priv->stats.txbeaconokint++;
0238         } else if (rx_intr_status.interrupt_status & ISR_TX_BCN_ERR) {
0239             priv->ieee80211->bibsscoordinator = false;
0240             priv->stats.txbeaconerr++;
0241         }
0242 
0243         if (rx_intr_status.interrupt_status & ISR_BCN_TIMER_INTR)
0244             cmdpkt_beacontimerinterrupt_819xusb(dev);
0245     }
0246 
0247     /* Other information in interrupt status we need? */
0248 
0249     DMESG("<---- cmpk_handle_interrupt_status()\n");
0250 }
0251 
0252 /*-----------------------------------------------------------------------------
0253  * Function:    cmpk_count_tx_status()
0254  *
0255  * Overview:    Count aggregated tx status from firmwar of one type rx command
0256  *      packet element id = RX_TX_STATUS.
0257  *
0258  * Input:   NONE
0259  *
0260  * Output:  NONE
0261  *
0262  * Return:  NONE
0263  *
0264  * Revised History:
0265  *  When        Who Remark
0266  *  05/12/2008  amy Create Version 0 porting from windows code.
0267  *
0268  *---------------------------------------------------------------------------
0269  */
0270 static void cmpk_count_tx_status(struct net_device *dev,
0271                  cmpk_tx_status_t *pstx_status)
0272 {
0273     struct r8192_priv *priv = ieee80211_priv(dev);
0274 
0275 #ifdef ENABLE_PS
0276 
0277     RT_RF_POWER_STATE   rtstate;
0278 
0279     pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE,
0280                       (pu1Byte)(&rtState));
0281 
0282     /* When RF is off, we should not count the packet for hw/sw synchronize
0283      * reason, ie. there may be a duration while sw switch is changed and
0284      * hw switch is being changed.
0285      */
0286     if (rtState == eRfOff)
0287         return;
0288 #endif
0289 
0290     priv->stats.txfeedbackok    += pstx_status->txok;
0291     priv->stats.txoktotal       += pstx_status->txok;
0292 
0293     priv->stats.txfeedbackfail  += pstx_status->txfail;
0294     priv->stats.txerrtotal      += pstx_status->txfail;
0295 
0296     priv->stats.txretrycount    += pstx_status->txretry;
0297     priv->stats.txfeedbackretry += pstx_status->txretry;
0298 
0299     priv->stats.txmulticast     += pstx_status->txmcok;
0300     priv->stats.txbroadcast     += pstx_status->txbcok;
0301     priv->stats.txunicast       += pstx_status->txucok;
0302 
0303     priv->stats.txerrmulticast  += pstx_status->txmcfail;
0304     priv->stats.txerrbroadcast  += pstx_status->txbcfail;
0305     priv->stats.txerrunicast    += pstx_status->txucfail;
0306 
0307     priv->stats.txbytesmulticast    += pstx_status->txmclength;
0308     priv->stats.txbytesbroadcast    += pstx_status->txbclength;
0309     priv->stats.txbytesunicast  += pstx_status->txuclength;
0310 
0311     priv->stats.last_packet_rate    = pstx_status->rate;
0312 }
0313 
0314 /*-----------------------------------------------------------------------------
0315  * Function:    cmpk_handle_tx_status()
0316  *
0317  * Overview:    Firmware add a new tx feedback status to reduce rx command
0318  *      packet buffer operation load.
0319  *
0320  * Input:       NONE
0321  *
0322  * Output:      NONE
0323  *
0324  * Return:      NONE
0325  *
0326  * Revised History:
0327  *  When        Who Remark
0328  *  05/12/2008  amy Create Version 0 porting from windows code.
0329  *
0330  *---------------------------------------------------------------------------
0331  */
0332 static void cmpk_handle_tx_status(struct net_device *dev, u8 *pmsg)
0333 {
0334     cmpk_tx_status_t    rx_tx_sts;
0335 
0336     memcpy((void *)&rx_tx_sts, (void *)pmsg, sizeof(cmpk_tx_status_t));
0337     /* 2. Use tx feedback info to count TX statistics. */
0338     cmpk_count_tx_status(dev, &rx_tx_sts);
0339 }
0340 
0341 /*-----------------------------------------------------------------------------
0342  * Function:    cmpk_handle_tx_rate_history()
0343  *
0344  * Overview:    Firmware add a new tx rate history
0345  *
0346  * Input:       NONE
0347  *
0348  * Output:      NONE
0349  *
0350  * Return:      NONE
0351  *
0352  * Revised History:
0353  *  When        Who Remark
0354  *  05/12/2008  amy Create Version 0 porting from windows code.
0355  *
0356  *---------------------------------------------------------------------------
0357  */
0358 static void cmpk_handle_tx_rate_history(struct net_device *dev, u8 *pmsg)
0359 {
0360     cmpk_tx_rahis_t *ptxrate;
0361     u8      i, j;
0362     u16     length = sizeof(cmpk_tx_rahis_t);
0363     u32     *ptemp;
0364     struct r8192_priv *priv = ieee80211_priv(dev);
0365 
0366 #ifdef ENABLE_PS
0367     pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE,
0368                       (pu1Byte)(&rtState));
0369 
0370     /* When RF is off, we should not count the packet for hw/sw synchronize
0371      * reason, ie. there may be a duration while sw switch is changed and
0372      * hw switch is being changed.
0373      */
0374     if (rtState == eRfOff)
0375         return;
0376 #endif
0377 
0378     ptemp = (u32 *)pmsg;
0379 
0380     /* Do endian transfer to word alignment(16 bits) for windows system.
0381      * You must do different endian transfer for linux and MAC OS
0382      */
0383     for (i = 0; i < (length/4); i++) {
0384         u16  temp1, temp2;
0385 
0386         temp1 = ptemp[i] & 0x0000FFFF;
0387         temp2 = ptemp[i] >> 16;
0388         ptemp[i] = (temp1 << 16) | temp2;
0389     }
0390 
0391     ptxrate = (cmpk_tx_rahis_t *)pmsg;
0392 
0393     if (!ptxrate)
0394         return;
0395 
0396     for (i = 0; i < 16; i++) {
0397         /* Collect CCK rate packet num */
0398         if (i < 4)
0399             priv->stats.txrate.cck[i] += ptxrate->cck[i];
0400 
0401         /* Collect OFDM rate packet num */
0402         if (i < 8)
0403             priv->stats.txrate.ofdm[i] += ptxrate->ofdm[i];
0404 
0405         for (j = 0; j < 4; j++)
0406             priv->stats.txrate.ht_mcs[j][i] += ptxrate->ht_mcs[j][i];
0407     }
0408 }
0409 
0410 /*-----------------------------------------------------------------------------
0411  * Function:    cmpk_message_handle_rx()
0412  *
0413  * Overview:    In the function, we will capture different RX command packet
0414  *      info. Every RX command packet element has different message
0415  *      length and meaning in content. We only support three type of RX
0416  *      command packet now. Please refer to document
0417  *      ws-06-0063-rtl8190-command-packet-specification.
0418  *
0419  * Input:       NONE
0420  *
0421  * Output:      NONE
0422  *
0423  * Return:      NONE
0424  *
0425  * Revised History:
0426  *  When        Who Remark
0427  *  05/06/2008      amy Create Version 0 porting from windows code.
0428  *
0429  *---------------------------------------------------------------------------
0430  */
0431 u32 cmpk_message_handle_rx(struct net_device *dev,
0432                struct ieee80211_rx_stats *pstats)
0433 {
0434     int         total_length;
0435     u8          cmd_length, exe_cnt = 0;
0436     u8          element_id;
0437     u8          *pcmd_buff;
0438 
0439     /* 0. Check inpt arguments. It is a command queue message or
0440      * pointer is null.
0441      */
0442     if (!pstats)
0443         return 0;   /* This is not a command packet. */
0444 
0445     /* 1. Read received command packet message length from RFD. */
0446     total_length = pstats->Length;
0447 
0448     /* 2. Read virtual address from RFD. */
0449     pcmd_buff = pstats->virtual_address;
0450 
0451     /* 3. Read command packet element id and length. */
0452     element_id = pcmd_buff[0];
0453 
0454     /* 4. Check every received command packet content according to different
0455      *    element type. Because FW may aggregate RX command packet to
0456      *    minimize transmit time between DRV and FW.
0457      */
0458     /* Add a counter to prevent the lock in the loop from being held too
0459      * long
0460      */
0461     while (total_length > 0 && exe_cnt++ < 100) {
0462         /* We support aggregation of different cmd in the same packet */
0463         element_id = pcmd_buff[0];
0464 
0465         switch (element_id) {
0466         case RX_TX_FEEDBACK:
0467             cmpk_handle_tx_feedback(dev, pcmd_buff);
0468             cmd_length = CMPK_RX_TX_FB_SIZE;
0469             break;
0470 
0471         case RX_INTERRUPT_STATUS:
0472             cmpk_handle_interrupt_status(dev, pcmd_buff);
0473             cmd_length = sizeof(struct cmd_pkt_interrupt_status);
0474             break;
0475 
0476         case BOTH_QUERY_CONFIG:
0477             cmd_length = CMPK_BOTH_QUERY_CONFIG_SIZE;
0478             break;
0479 
0480         case RX_TX_STATUS:
0481             cmpk_handle_tx_status(dev, pcmd_buff);
0482             cmd_length = CMPK_RX_TX_STS_SIZE;
0483             break;
0484 
0485         case RX_TX_PER_PKT_FEEDBACK:
0486             /* You must at lease add a switch case element here,
0487              * Otherwise, we will jump to default case.
0488              */
0489             cmd_length = CMPK_RX_TX_FB_SIZE;
0490             break;
0491 
0492         case RX_TX_RATE_HISTORY:
0493             cmpk_handle_tx_rate_history(dev, pcmd_buff);
0494             cmd_length = CMPK_TX_RAHIS_SIZE;
0495             break;
0496 
0497         default:
0498 
0499             RT_TRACE(COMP_ERR, "---->%s():unknown CMD Element\n",
0500                  __func__);
0501             return 1;   /* This is a command packet. */
0502         }
0503 
0504         total_length -= cmd_length;
0505         pcmd_buff    += cmd_length;
0506     }
0507     return  1;  /* This is a command packet. */
0508 }