linux/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c
<<
>>
Prefs
   1/******************************************************************************
   2 * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
   3 *
   4 * This program is distributed in the hope that it will be useful, but WITHOUT
   5 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   6 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
   7 * more details.
   8 *
   9 * You should have received a copy of the GNU General Public License along with
  10 * this program; if not, write to the Free Software Foundation, Inc.,
  11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
  12 *
  13 * The full GNU General Public License is included in this distribution in the
  14 * file called LICENSE.
  15 *
  16 * Contact Information:
  17 * wlanfae <wlanfae@realtek.com>
  18******************************************************************************/
  19
  20#include "rtl_core.h"
  21#include "r8192E_hw.h"
  22#include "r8192E_cmdpkt.h"
  23
  24bool cmpk_message_handle_tx(
  25        struct net_device *dev,
  26        u8      *code_virtual_address,
  27        u32     packettype,
  28        u32     buffer_len)
  29{
  30
  31        bool                            rt_status = true;
  32        struct r8192_priv *priv = rtllib_priv(dev);
  33        u16                             frag_threshold;
  34        u16                             frag_length = 0, frag_offset = 0;
  35        struct rt_firmware *pfirmware = priv->pFirmware;
  36        struct sk_buff          *skb;
  37        unsigned char           *seg_ptr;
  38        struct cb_desc *tcb_desc;
  39        u8                              bLastIniPkt;
  40
  41        struct tx_fwinfo_8190pci *pTxFwInfo = NULL;
  42
  43        RT_TRACE(COMP_CMDPKT, "%s(),buffer_len is %d\n", __func__, buffer_len);
  44        firmware_init_param(dev);
  45        frag_threshold = pfirmware->cmdpacket_frag_thresold;
  46
  47        do {
  48                if ((buffer_len - frag_offset) > frag_threshold) {
  49                        frag_length = frag_threshold ;
  50                        bLastIniPkt = 0;
  51
  52                } else {
  53                        frag_length = (u16)(buffer_len - frag_offset);
  54                        bLastIniPkt = 1;
  55                }
  56
  57                skb  = dev_alloc_skb(frag_length +
  58                                     priv->rtllib->tx_headroom + 4);
  59
  60                if (skb == NULL) {
  61                        rt_status = false;
  62                        goto Failed;
  63                }
  64
  65                memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev));
  66                tcb_desc = (struct cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
  67                tcb_desc->queue_index = TXCMD_QUEUE;
  68                tcb_desc->bCmdOrInit = DESC_PACKET_TYPE_NORMAL;
  69                tcb_desc->bLastIniPkt = bLastIniPkt;
  70                tcb_desc->pkt_size = frag_length;
  71
  72                seg_ptr = skb_put(skb, priv->rtllib->tx_headroom);
  73                pTxFwInfo = (struct tx_fwinfo_8190pci *)seg_ptr;
  74                memset(pTxFwInfo, 0, sizeof(struct tx_fwinfo_8190pci));
  75                memset(pTxFwInfo, 0x12, 8);
  76
  77                seg_ptr = skb_put(skb, frag_length);
  78                memcpy(seg_ptr, code_virtual_address, (u32)frag_length);
  79
  80                priv->rtllib->softmac_hard_start_xmit(skb, dev);
  81
  82                code_virtual_address += frag_length;
  83                frag_offset += frag_length;
  84
  85        } while (frag_offset < buffer_len);
  86
  87        write_nic_byte(dev, TPPoll, TPPoll_CQ);
  88Failed:
  89        return rt_status;
  90}
  91
  92static  void
  93cmpk_count_txstatistic(
  94        struct net_device *dev,
  95        struct cmpk_txfb *pstx_fb)
  96{
  97        struct r8192_priv *priv = rtllib_priv(dev);
  98#ifdef ENABLE_PS
  99        enum rt_rf_power_state rtState;
 100
 101        pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE,
 102                                          (pu1Byte)(&rtState));
 103
 104        if (rtState == eRfOff)
 105                return;
 106#endif
 107
 108        if (pstx_fb->tok) {
 109                priv->stats.txfeedbackok++;
 110                priv->stats.txoktotal++;
 111                priv->stats.txokbytestotal += pstx_fb->pkt_length;
 112                priv->stats.txokinperiod++;
 113
 114                if (pstx_fb->pkt_type == PACKET_MULTICAST) {
 115                        priv->stats.txmulticast++;
 116                        priv->stats.txbytesmulticast += pstx_fb->pkt_length;
 117                } else if (pstx_fb->pkt_type == PACKET_BROADCAST) {
 118                        priv->stats.txbroadcast++;
 119                        priv->stats.txbytesbroadcast += pstx_fb->pkt_length;
 120                } else {
 121                        priv->stats.txunicast++;
 122                        priv->stats.txbytesunicast += pstx_fb->pkt_length;
 123                }
 124        } else {
 125                priv->stats.txfeedbackfail++;
 126                priv->stats.txerrtotal++;
 127                priv->stats.txerrbytestotal += pstx_fb->pkt_length;
 128
 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
 141static void cmpk_handle_tx_feedback(struct net_device *dev, u8 *pmsg)
 142{
 143        struct r8192_priv *priv = rtllib_priv(dev);
 144        struct cmpk_txfb rx_tx_fb;
 145
 146        priv->stats.txfeedback++;
 147
 148
 149        memcpy((u8 *)&rx_tx_fb, pmsg, sizeof(struct cmpk_txfb));
 150        cmpk_count_txstatistic(dev, &rx_tx_fb);
 151}
 152
 153static void cmdpkt_beacontimerinterrupt_819xusb(struct net_device *dev)
 154{
 155        struct r8192_priv *priv = rtllib_priv(dev);
 156        u16 tx_rate;
 157
 158        if ((priv->rtllib->current_network.mode == IEEE_A)  ||
 159            (priv->rtllib->current_network.mode == IEEE_N_5G) ||
 160            ((priv->rtllib->current_network.mode == IEEE_N_24G)  &&
 161            (!priv->rtllib->pHTInfo->bCurSuppCCK))) {
 162                tx_rate = 60;
 163                DMESG("send beacon frame  tx rate is 6Mbpm\n");
 164        } else {
 165                tx_rate = 10;
 166                DMESG("send beacon frame  tx rate is 1Mbpm\n");
 167        }
 168}
 169
 170static void cmpk_handle_interrupt_status(struct net_device *dev, u8 *pmsg)
 171{
 172        struct cmpk_intr_sta rx_intr_status;    /* */
 173        struct r8192_priv *priv = rtllib_priv(dev);
 174
 175        DMESG("---> cmpk_Handle_Interrupt_Status()\n");
 176
 177        rx_intr_status.length = pmsg[1];
 178        if (rx_intr_status.length != (sizeof(struct cmpk_intr_sta) - 2)) {
 179                DMESG("cmpk_Handle_Interrupt_Status: wrong length!\n");
 180                return;
 181        }
 182
 183        if (priv->rtllib->iw_mode == IW_MODE_ADHOC) {
 184                rx_intr_status.interrupt_status = *((u32 *)(pmsg + 4));
 185
 186                DMESG("interrupt status = 0x%x\n",
 187                      rx_intr_status.interrupt_status);
 188
 189                if (rx_intr_status.interrupt_status & ISR_TxBcnOk) {
 190                        priv->rtllib->bibsscoordinator = true;
 191                        priv->stats.txbeaconokint++;
 192                } else if (rx_intr_status.interrupt_status & ISR_TxBcnErr) {
 193                        priv->rtllib->bibsscoordinator = false;
 194                        priv->stats.txbeaconerr++;
 195                }
 196
 197                if (rx_intr_status.interrupt_status & ISR_BcnTimerIntr)
 198                        cmdpkt_beacontimerinterrupt_819xusb(dev);
 199        }
 200
 201        DMESG("<---- cmpk_handle_interrupt_status()\n");
 202
 203}
 204
 205static  void cmpk_handle_query_config_rx(struct net_device *dev, u8 *pmsg)
 206{
 207        cmpk_query_cfg_t        rx_query_cfg;
 208
 209
 210        rx_query_cfg.cfg_action = (pmsg[4] & 0x80000000)>>31;
 211        rx_query_cfg.cfg_type = (pmsg[4] & 0x60) >> 5;
 212        rx_query_cfg.cfg_size = (pmsg[4] & 0x18) >> 3;
 213        rx_query_cfg.cfg_page = (pmsg[6] & 0x0F) >> 0;
 214        rx_query_cfg.cfg_offset  = pmsg[7];
 215        rx_query_cfg.value = (pmsg[8] << 24) | (pmsg[9] << 16) |
 216                             (pmsg[10] << 8) | (pmsg[11] << 0);
 217        rx_query_cfg.mask = (pmsg[12] << 24) | (pmsg[13] << 16) |
 218                            (pmsg[14] << 8) | (pmsg[15] << 0);
 219
 220}
 221
 222static void cmpk_count_tx_status(struct net_device *dev,
 223                                 struct cmpk_tx_status *pstx_status)
 224{
 225        struct r8192_priv *priv = rtllib_priv(dev);
 226
 227#ifdef ENABLE_PS
 228
 229        enum rt_rf_power_state rtstate;
 230
 231        pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE,
 232                                          (pu1Byte)(&rtState));
 233
 234        if (rtState == eRfOff)
 235                return;
 236#endif
 237
 238        priv->stats.txfeedbackok        += pstx_status->txok;
 239        priv->stats.txoktotal           += pstx_status->txok;
 240
 241        priv->stats.txfeedbackfail      += pstx_status->txfail;
 242        priv->stats.txerrtotal          += pstx_status->txfail;
 243
 244        priv->stats.txretrycount                += pstx_status->txretry;
 245        priv->stats.txfeedbackretry     += pstx_status->txretry;
 246
 247
 248        priv->stats.txmulticast += pstx_status->txmcok;
 249        priv->stats.txbroadcast += pstx_status->txbcok;
 250        priv->stats.txunicast           += pstx_status->txucok;
 251
 252        priv->stats.txerrmulticast      += pstx_status->txmcfail;
 253        priv->stats.txerrbroadcast      += pstx_status->txbcfail;
 254        priv->stats.txerrunicast        += pstx_status->txucfail;
 255
 256        priv->stats.txbytesmulticast    += pstx_status->txmclength;
 257        priv->stats.txbytesbroadcast    += pstx_status->txbclength;
 258        priv->stats.txbytesunicast              += pstx_status->txuclength;
 259
 260        priv->stats.last_packet_rate            = pstx_status->rate;
 261}
 262
 263static  void cmpk_handle_tx_status(struct net_device *dev, u8 *pmsg)
 264{
 265        struct cmpk_tx_status rx_tx_sts;
 266
 267        memcpy((void *)&rx_tx_sts, (void *)pmsg, sizeof(struct cmpk_tx_status));
 268        cmpk_count_tx_status(dev, &rx_tx_sts);
 269}
 270
 271static  void cmpk_handle_tx_rate_history(struct net_device *dev, u8 *pmsg)
 272{
 273        struct cmpk_tx_rahis *ptxrate;
 274        u8 i, j;
 275        u16                             length = sizeof(struct cmpk_tx_rahis);
 276        u32 *ptemp;
 277        struct r8192_priv *priv = rtllib_priv(dev);
 278
 279#ifdef ENABLE_PS
 280        pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE,
 281                                         (pu1Byte)(&rtState));
 282
 283        if (rtState == eRfOff)
 284                return;
 285#endif
 286
 287        ptemp = (u32 *)pmsg;
 288
 289        for (i = 0; i < (length / 4); i++) {
 290                u16      temp1, temp2;
 291
 292                temp1 = ptemp[i] & 0x0000FFFF;
 293                temp2 = ptemp[i] >> 16;
 294                ptemp[i] = (temp1 << 16) | temp2;
 295        }
 296
 297        ptxrate = (struct cmpk_tx_rahis *)pmsg;
 298
 299        if (ptxrate == NULL)
 300                return;
 301
 302        for (i = 0; i < 16; i++) {
 303                if (i < 4)
 304                        priv->stats.txrate.cck[i] += ptxrate->cck[i];
 305
 306                if (i < 8)
 307                        priv->stats.txrate.ofdm[i] += ptxrate->ofdm[i];
 308
 309                for (j = 0; j < 4; j++)
 310                        priv->stats.txrate.ht_mcs[j][i] +=
 311                                                         ptxrate->ht_mcs[j][i];
 312        }
 313}
 314
 315u32 cmpk_message_handle_rx(struct net_device *dev,
 316                           struct rtllib_rx_stats *pstats)
 317{
 318        int                     total_length;
 319        u8                      cmd_length, exe_cnt = 0;
 320        u8                      element_id;
 321        u8                      *pcmd_buff;
 322
 323        RT_TRACE(COMP_CMDPKT, "---->cmpk_message_handle_rx()\n");
 324
 325        if (pstats == NULL)
 326                return 0;
 327
 328        total_length = pstats->Length;
 329
 330        pcmd_buff = pstats->virtual_address;
 331
 332        element_id = pcmd_buff[0];
 333
 334        while (total_length > 0 || exe_cnt++ > 100) {
 335                element_id = pcmd_buff[0];
 336
 337                switch (element_id) {
 338                case RX_TX_FEEDBACK:
 339                        RT_TRACE(COMP_CMDPKT, "---->cmpk_message_handle_rx():"
 340                                 "RX_TX_FEEDBACK\n");
 341                        cmpk_handle_tx_feedback(dev, pcmd_buff);
 342                        cmd_length = CMPK_RX_TX_FB_SIZE;
 343                        break;
 344                case RX_INTERRUPT_STATUS:
 345                        RT_TRACE(COMP_CMDPKT, "---->cmpk_message_handle_rx():"
 346                                 "RX_INTERRUPT_STATUS\n");
 347                        cmpk_handle_interrupt_status(dev, pcmd_buff);
 348                        cmd_length = sizeof(struct cmpk_intr_sta);
 349                        break;
 350                case BOTH_QUERY_CONFIG:
 351                        RT_TRACE(COMP_CMDPKT, "---->cmpk_message_handle_rx():"
 352                                 "BOTH_QUERY_CONFIG\n");
 353                        cmpk_handle_query_config_rx(dev, pcmd_buff);
 354                        cmd_length = CMPK_BOTH_QUERY_CONFIG_SIZE;
 355                        break;
 356                case RX_TX_STATUS:
 357                        RT_TRACE(COMP_CMDPKT, "---->cmpk_message_handle_rx():"
 358                                 "RX_TX_STATUS\n");
 359                        cmpk_handle_tx_status(dev, pcmd_buff);
 360                        cmd_length = CMPK_RX_TX_STS_SIZE;
 361                        break;
 362                case RX_TX_PER_PKT_FEEDBACK:
 363                        RT_TRACE(COMP_CMDPKT, "---->cmpk_message_handle_rx():"
 364                                 "RX_TX_PER_PKT_FEEDBACK\n");
 365                        cmd_length = CMPK_RX_TX_FB_SIZE;
 366                        break;
 367                case RX_TX_RATE_HISTORY:
 368                        RT_TRACE(COMP_CMDPKT, "---->cmpk_message_handle_rx():"
 369                                 "RX_TX_HISTORY\n");
 370                        cmpk_handle_tx_rate_history(dev, pcmd_buff);
 371                        cmd_length = CMPK_TX_RAHIS_SIZE;
 372                        break;
 373                default:
 374
 375                        RT_TRACE(COMP_CMDPKT, "---->cmpk_message_handle_rx():"
 376                                 "unknow CMD Element\n");
 377                        return 1;
 378                }
 379
 380                total_length -= cmd_length;
 381                pcmd_buff    += cmd_length;
 382        }
 383        return  1;
 384}
 385