linux/drivers/net/wireless/realtek/rtlwifi/rtl8192se/fw.c
<<
>>
Prefs
   1/******************************************************************************
   2 *
   3 * Copyright(c) 2009-2012  Realtek Corporation.
   4 *
   5 * This program is free software; you can redistribute it and/or modify it
   6 * under the terms of version 2 of the GNU General Public License as
   7 * published by the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope that it will be useful, but WITHOUT
  10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  12 * more details.
  13 *
  14 * You should have received a copy of the GNU General Public License along with
  15 * this program; if not, write to the Free Software Foundation, Inc.,
  16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
  17 *
  18 * The full GNU General Public License is included in this distribution in the
  19 * file called LICENSE.
  20 *
  21 * Contact Information:
  22 * wlanfae <wlanfae@realtek.com>
  23 * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
  24 * Hsinchu 300, Taiwan.
  25 *
  26 * Larry Finger <Larry.Finger@lwfinger.net>
  27 *
  28 *****************************************************************************/
  29
  30#include "../wifi.h"
  31#include "../pci.h"
  32#include "../base.h"
  33#include "reg.h"
  34#include "def.h"
  35#include "fw.h"
  36
  37static void _rtl92s_fw_set_rqpn(struct ieee80211_hw *hw)
  38{
  39        struct rtl_priv *rtlpriv = rtl_priv(hw);
  40
  41        rtl_write_dword(rtlpriv, RQPN, 0xffffffff);
  42        rtl_write_dword(rtlpriv, RQPN + 4, 0xffffffff);
  43        rtl_write_byte(rtlpriv, RQPN + 8, 0xff);
  44        rtl_write_byte(rtlpriv, RQPN + 0xB, 0x80);
  45}
  46
  47static bool _rtl92s_firmware_enable_cpu(struct ieee80211_hw *hw)
  48{
  49        struct rtl_priv *rtlpriv = rtl_priv(hw);
  50        u32 ichecktime = 200;
  51        u16 tmpu2b;
  52        u8 tmpu1b, cpustatus = 0;
  53
  54        _rtl92s_fw_set_rqpn(hw);
  55
  56        /* Enable CPU. */
  57        tmpu1b = rtl_read_byte(rtlpriv, SYS_CLKR);
  58        /* AFE source */
  59        rtl_write_byte(rtlpriv, SYS_CLKR, (tmpu1b | SYS_CPU_CLKSEL));
  60
  61        tmpu2b = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN);
  62        rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, (tmpu2b | FEN_CPUEN));
  63
  64        /* Polling IMEM Ready after CPU has refilled. */
  65        do {
  66                cpustatus = rtl_read_byte(rtlpriv, TCR);
  67                if (cpustatus & IMEM_RDY) {
  68                        RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
  69                                 "IMEM Ready after CPU has refilled\n");
  70                        break;
  71                }
  72
  73                udelay(100);
  74        } while (ichecktime--);
  75
  76        if (!(cpustatus & IMEM_RDY))
  77                return false;
  78
  79        return true;
  80}
  81
  82static enum fw_status _rtl92s_firmware_get_nextstatus(
  83                enum fw_status fw_currentstatus)
  84{
  85        enum fw_status  next_fwstatus = 0;
  86
  87        switch (fw_currentstatus) {
  88        case FW_STATUS_INIT:
  89                next_fwstatus = FW_STATUS_LOAD_IMEM;
  90                break;
  91        case FW_STATUS_LOAD_IMEM:
  92                next_fwstatus = FW_STATUS_LOAD_EMEM;
  93                break;
  94        case FW_STATUS_LOAD_EMEM:
  95                next_fwstatus = FW_STATUS_LOAD_DMEM;
  96                break;
  97        case FW_STATUS_LOAD_DMEM:
  98                next_fwstatus = FW_STATUS_READY;
  99                break;
 100        default:
 101                break;
 102        }
 103
 104        return next_fwstatus;
 105}
 106
 107static u8 _rtl92s_firmware_header_map_rftype(struct ieee80211_hw *hw)
 108{
 109        struct rtl_priv *rtlpriv = rtl_priv(hw);
 110        struct rtl_phy *rtlphy = &(rtlpriv->phy);
 111
 112        switch (rtlphy->rf_type) {
 113        case RF_1T1R:
 114                return 0x11;
 115        case RF_1T2R:
 116                return 0x12;
 117        case RF_2T2R:
 118                return 0x22;
 119        default:
 120                RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, "Unknown RF type(%x)\n",
 121                         rtlphy->rf_type);
 122                break;
 123        }
 124        return 0x22;
 125}
 126
 127static void _rtl92s_firmwareheader_priveupdate(struct ieee80211_hw *hw,
 128                struct fw_priv *pfw_priv)
 129{
 130        /* Update RF types for RATR settings. */
 131        pfw_priv->rf_config = _rtl92s_firmware_header_map_rftype(hw);
 132}
 133
 134
 135
 136static bool _rtl92s_cmd_send_packet(struct ieee80211_hw *hw,
 137                struct sk_buff *skb, u8 last)
 138{
 139        struct rtl_priv *rtlpriv = rtl_priv(hw);
 140        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 141        struct rtl8192_tx_ring *ring;
 142        struct rtl_tx_desc *pdesc;
 143        unsigned long flags;
 144        u8 idx = 0;
 145
 146        ring = &rtlpci->tx_ring[TXCMD_QUEUE];
 147
 148        spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
 149
 150        idx = (ring->idx + skb_queue_len(&ring->queue)) % ring->entries;
 151        pdesc = &ring->desc[idx];
 152        rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *)pdesc, 1, 1, skb);
 153        __skb_queue_tail(&ring->queue, skb);
 154
 155        spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
 156
 157        return true;
 158}
 159
 160static bool _rtl92s_firmware_downloadcode(struct ieee80211_hw *hw,
 161                u8 *code_virtual_address, u32 buffer_len)
 162{
 163        struct rtl_priv *rtlpriv = rtl_priv(hw);
 164        struct sk_buff *skb;
 165        struct rtl_tcb_desc *tcb_desc;
 166        unsigned char *seg_ptr;
 167        u16 frag_threshold = MAX_FIRMWARE_CODE_SIZE;
 168        u16 frag_length, frag_offset = 0;
 169        u16 extra_descoffset = 0;
 170        u8 last_inipkt = 0;
 171
 172        _rtl92s_fw_set_rqpn(hw);
 173
 174        if (buffer_len >= MAX_FIRMWARE_CODE_SIZE) {
 175                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 176                         "Size over FIRMWARE_CODE_SIZE!\n");
 177
 178                return false;
 179        }
 180
 181        extra_descoffset = 0;
 182
 183        do {
 184                if ((buffer_len - frag_offset) > frag_threshold) {
 185                        frag_length = frag_threshold + extra_descoffset;
 186                } else {
 187                        frag_length = (u16)(buffer_len - frag_offset +
 188                                            extra_descoffset);
 189                        last_inipkt = 1;
 190                }
 191
 192                /* Allocate skb buffer to contain firmware */
 193                /* info and tx descriptor info. */
 194                skb = dev_alloc_skb(frag_length);
 195                if (!skb)
 196                        return false;
 197                skb_reserve(skb, extra_descoffset);
 198                seg_ptr = (u8 *)skb_put(skb, (u32)(frag_length -
 199                                        extra_descoffset));
 200                memcpy(seg_ptr, code_virtual_address + frag_offset,
 201                       (u32)(frag_length - extra_descoffset));
 202
 203                tcb_desc = (struct rtl_tcb_desc *)(skb->cb);
 204                tcb_desc->queue_index = TXCMD_QUEUE;
 205                tcb_desc->cmd_or_init = DESC_PACKET_TYPE_INIT;
 206                tcb_desc->last_inipkt = last_inipkt;
 207
 208                _rtl92s_cmd_send_packet(hw, skb, last_inipkt);
 209
 210                frag_offset += (frag_length - extra_descoffset);
 211
 212        } while (frag_offset < buffer_len);
 213
 214        rtl_write_byte(rtlpriv, TP_POLL, TPPOLL_CQ);
 215
 216        return true ;
 217}
 218
 219static bool _rtl92s_firmware_checkready(struct ieee80211_hw *hw,
 220                u8 loadfw_status)
 221{
 222        struct rtl_priv *rtlpriv = rtl_priv(hw);
 223        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 224        struct rt_firmware *firmware = (struct rt_firmware *)rtlhal->pfirmware;
 225        u32 tmpu4b;
 226        u8 cpustatus = 0;
 227        short pollingcnt = 1000;
 228        bool rtstatus = true;
 229
 230        RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
 231                 "LoadStaus(%d)\n", loadfw_status);
 232
 233        firmware->fwstatus = (enum fw_status)loadfw_status;
 234
 235        switch (loadfw_status) {
 236        case FW_STATUS_LOAD_IMEM:
 237                /* Polling IMEM code done. */
 238                do {
 239                        cpustatus = rtl_read_byte(rtlpriv, TCR);
 240                        if (cpustatus & IMEM_CODE_DONE)
 241                                break;
 242                        udelay(5);
 243                } while (pollingcnt--);
 244
 245                if (!(cpustatus & IMEM_CHK_RPT) || (pollingcnt <= 0)) {
 246                        RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 247                                 "FW_STATUS_LOAD_IMEM FAIL CPU, Status=%x\n",
 248                                 cpustatus);
 249                        goto status_check_fail;
 250                }
 251                break;
 252
 253        case FW_STATUS_LOAD_EMEM:
 254                /* Check Put Code OK and Turn On CPU */
 255                /* Polling EMEM code done. */
 256                do {
 257                        cpustatus = rtl_read_byte(rtlpriv, TCR);
 258                        if (cpustatus & EMEM_CODE_DONE)
 259                                break;
 260                        udelay(5);
 261                } while (pollingcnt--);
 262
 263                if (!(cpustatus & EMEM_CHK_RPT) || (pollingcnt <= 0)) {
 264                        RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 265                                 "FW_STATUS_LOAD_EMEM FAIL CPU, Status=%x\n",
 266                                 cpustatus);
 267                        goto status_check_fail;
 268                }
 269
 270                /* Turn On CPU */
 271                rtstatus = _rtl92s_firmware_enable_cpu(hw);
 272                if (!rtstatus) {
 273                        RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 274                                 "Enable CPU fail!\n");
 275                        goto status_check_fail;
 276                }
 277                break;
 278
 279        case FW_STATUS_LOAD_DMEM:
 280                /* Polling DMEM code done */
 281                do {
 282                        cpustatus = rtl_read_byte(rtlpriv, TCR);
 283                        if (cpustatus & DMEM_CODE_DONE)
 284                                break;
 285                        udelay(5);
 286                } while (pollingcnt--);
 287
 288                if (!(cpustatus & DMEM_CODE_DONE) || (pollingcnt <= 0)) {
 289                        RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 290                                 "Polling DMEM code done fail ! cpustatus(%#x)\n",
 291                                 cpustatus);
 292                        goto status_check_fail;
 293                }
 294
 295                RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
 296                         "DMEM code download success, cpustatus(%#x)\n",
 297                         cpustatus);
 298
 299                /* Prevent Delay too much and being scheduled out */
 300                /* Polling Load Firmware ready */
 301                pollingcnt = 2000;
 302                do {
 303                        cpustatus = rtl_read_byte(rtlpriv, TCR);
 304                        if (cpustatus & FWRDY)
 305                                break;
 306                        udelay(40);
 307                } while (pollingcnt--);
 308
 309                RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
 310                         "Polling Load Firmware ready, cpustatus(%x)\n",
 311                         cpustatus);
 312
 313                if (((cpustatus & LOAD_FW_READY) != LOAD_FW_READY) ||
 314                    (pollingcnt <= 0)) {
 315                        RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 316                                 "Polling Load Firmware ready fail ! cpustatus(%x)\n",
 317                                 cpustatus);
 318                        goto status_check_fail;
 319                }
 320
 321                /* If right here, we can set TCR/RCR to desired value  */
 322                /* and config MAC lookback mode to normal mode */
 323                tmpu4b = rtl_read_dword(rtlpriv, TCR);
 324                rtl_write_dword(rtlpriv, TCR, (tmpu4b & (~TCR_ICV)));
 325
 326                tmpu4b = rtl_read_dword(rtlpriv, RCR);
 327                rtl_write_dword(rtlpriv, RCR, (tmpu4b | RCR_APPFCS |
 328                                RCR_APP_ICV | RCR_APP_MIC));
 329
 330                RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
 331                         "Current RCR settings(%#x)\n", tmpu4b);
 332
 333                /* Set to normal mode. */
 334                rtl_write_byte(rtlpriv, LBKMD_SEL, LBK_NORMAL);
 335                break;
 336
 337        default:
 338                RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG,
 339                         "Unknown status check!\n");
 340                rtstatus = false;
 341                break;
 342        }
 343
 344status_check_fail:
 345        RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
 346                 "loadfw_status(%d), rtstatus(%x)\n",
 347                 loadfw_status, rtstatus);
 348        return rtstatus;
 349}
 350
 351int rtl92s_download_fw(struct ieee80211_hw *hw)
 352{
 353        struct rtl_priv *rtlpriv = rtl_priv(hw);
 354        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 355        struct rt_firmware *firmware = NULL;
 356        struct fw_hdr *pfwheader;
 357        struct fw_priv *pfw_priv = NULL;
 358        u8 *puc_mappedfile = NULL;
 359        u32 ul_filelength = 0;
 360        u8 fwhdr_size = RT_8192S_FIRMWARE_HDR_SIZE;
 361        u8 fwstatus = FW_STATUS_INIT;
 362        bool rtstatus = true;
 363
 364        if (rtlpriv->max_fw_size == 0 || !rtlhal->pfirmware)
 365                return 1;
 366
 367        firmware = (struct rt_firmware *)rtlhal->pfirmware;
 368        firmware->fwstatus = FW_STATUS_INIT;
 369
 370        puc_mappedfile = firmware->sz_fw_tmpbuffer;
 371
 372        /* 1. Retrieve FW header. */
 373        firmware->pfwheader = (struct fw_hdr *) puc_mappedfile;
 374        pfwheader = firmware->pfwheader;
 375        firmware->firmwareversion =  byte(pfwheader->version, 0);
 376        firmware->pfwheader->fwpriv.hci_sel = 1;/* pcie */
 377
 378        RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
 379                 "signature:%x, version:%x, size:%x, imemsize:%x, sram size:%x\n",
 380                 pfwheader->signature,
 381                 pfwheader->version, pfwheader->dmem_size,
 382                 pfwheader->img_imem_size, pfwheader->img_sram_size);
 383
 384        /* 2. Retrieve IMEM image. */
 385        if ((pfwheader->img_imem_size == 0) || (pfwheader->img_imem_size >
 386            sizeof(firmware->fw_imem))) {
 387                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 388                         "memory for data image is less than IMEM required\n");
 389                goto fail;
 390        } else {
 391                puc_mappedfile += fwhdr_size;
 392
 393                memcpy(firmware->fw_imem, puc_mappedfile,
 394                       pfwheader->img_imem_size);
 395                firmware->fw_imem_len = pfwheader->img_imem_size;
 396        }
 397
 398        /* 3. Retriecve EMEM image. */
 399        if (pfwheader->img_sram_size > sizeof(firmware->fw_emem)) {
 400                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 401                         "memory for data image is less than EMEM required\n");
 402                goto fail;
 403        } else {
 404                puc_mappedfile += firmware->fw_imem_len;
 405
 406                memcpy(firmware->fw_emem, puc_mappedfile,
 407                       pfwheader->img_sram_size);
 408                firmware->fw_emem_len = pfwheader->img_sram_size;
 409        }
 410
 411        /* 4. download fw now */
 412        fwstatus = _rtl92s_firmware_get_nextstatus(firmware->fwstatus);
 413        while (fwstatus != FW_STATUS_READY) {
 414                /* Image buffer redirection. */
 415                switch (fwstatus) {
 416                case FW_STATUS_LOAD_IMEM:
 417                        puc_mappedfile = firmware->fw_imem;
 418                        ul_filelength = firmware->fw_imem_len;
 419                        break;
 420                case FW_STATUS_LOAD_EMEM:
 421                        puc_mappedfile = firmware->fw_emem;
 422                        ul_filelength = firmware->fw_emem_len;
 423                        break;
 424                case FW_STATUS_LOAD_DMEM:
 425                        /* Partial update the content of header private. */
 426                        pfwheader = firmware->pfwheader;
 427                        pfw_priv = &pfwheader->fwpriv;
 428                        _rtl92s_firmwareheader_priveupdate(hw, pfw_priv);
 429                        puc_mappedfile = (u8 *)(firmware->pfwheader) +
 430                                        RT_8192S_FIRMWARE_HDR_EXCLUDE_PRI_SIZE;
 431                        ul_filelength = fwhdr_size -
 432                                        RT_8192S_FIRMWARE_HDR_EXCLUDE_PRI_SIZE;
 433                        break;
 434                default:
 435                        RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 436                                 "Unexpected Download step!!\n");
 437                        goto fail;
 438                }
 439
 440                /* <2> Download image file */
 441                rtstatus = _rtl92s_firmware_downloadcode(hw, puc_mappedfile,
 442                                ul_filelength);
 443
 444                if (!rtstatus) {
 445                        RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "fail!\n");
 446                        goto fail;
 447                }
 448
 449                /* <3> Check whether load FW process is ready */
 450                rtstatus = _rtl92s_firmware_checkready(hw, fwstatus);
 451                if (!rtstatus) {
 452                        RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "fail!\n");
 453                        goto fail;
 454                }
 455
 456                fwstatus = _rtl92s_firmware_get_nextstatus(firmware->fwstatus);
 457        }
 458
 459        return rtstatus;
 460fail:
 461        return 0;
 462}
 463
 464static u32 _rtl92s_fill_h2c_cmd(struct sk_buff *skb, u32 h2cbufferlen,
 465                                u32 cmd_num, u32 *pelement_id, u32 *pcmd_len,
 466                                u8 **pcmb_buffer, u8 *cmd_start_seq)
 467{
 468        u32 totallen = 0, len = 0, tx_desclen = 0;
 469        u32 pre_continueoffset = 0;
 470        u8 *ph2c_buffer;
 471        u8 i = 0;
 472
 473        do {
 474                /* 8 - Byte aligment */
 475                len = H2C_TX_CMD_HDR_LEN + N_BYTE_ALIGMENT(pcmd_len[i], 8);
 476
 477                /* Buffer length is not enough */
 478                if (h2cbufferlen < totallen + len + tx_desclen)
 479                        break;
 480
 481                /* Clear content */
 482                ph2c_buffer = (u8 *)skb_put(skb, (u32)len);
 483                memset((ph2c_buffer + totallen + tx_desclen), 0, len);
 484
 485                /* CMD len */
 486                SET_BITS_TO_LE_4BYTE((ph2c_buffer + totallen + tx_desclen),
 487                                      0, 16, pcmd_len[i]);
 488
 489                /* CMD ID */
 490                SET_BITS_TO_LE_4BYTE((ph2c_buffer + totallen + tx_desclen),
 491                                      16, 8, pelement_id[i]);
 492
 493                /* CMD Sequence */
 494                *cmd_start_seq = *cmd_start_seq % 0x80;
 495                SET_BITS_TO_LE_4BYTE((ph2c_buffer + totallen + tx_desclen),
 496                                      24, 7, *cmd_start_seq);
 497                ++*cmd_start_seq;
 498
 499                /* Copy memory */
 500                memcpy((ph2c_buffer + totallen + tx_desclen +
 501                        H2C_TX_CMD_HDR_LEN), pcmb_buffer[i], pcmd_len[i]);
 502
 503                /* CMD continue */
 504                /* set the continue in prevoius cmd. */
 505                if (i < cmd_num - 1)
 506                        SET_BITS_TO_LE_4BYTE((ph2c_buffer + pre_continueoffset),
 507                                              31, 1, 1);
 508
 509                pre_continueoffset = totallen;
 510
 511                totallen += len;
 512        } while (++i < cmd_num);
 513
 514        return totallen;
 515}
 516
 517static u32 _rtl92s_get_h2c_cmdlen(u32 h2cbufferlen, u32 cmd_num, u32 *pcmd_len)
 518{
 519        u32 totallen = 0, len = 0, tx_desclen = 0;
 520        u8 i = 0;
 521
 522        do {
 523                /* 8 - Byte aligment */
 524                len = H2C_TX_CMD_HDR_LEN + N_BYTE_ALIGMENT(pcmd_len[i], 8);
 525
 526                /* Buffer length is not enough */
 527                if (h2cbufferlen < totallen + len + tx_desclen)
 528                        break;
 529
 530                totallen += len;
 531        } while (++i < cmd_num);
 532
 533        return totallen + tx_desclen;
 534}
 535
 536static bool _rtl92s_firmware_set_h2c_cmd(struct ieee80211_hw *hw, u8 h2c_cmd,
 537                                         u8 *pcmd_buffer)
 538{
 539        struct rtl_priv *rtlpriv = rtl_priv(hw);
 540        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 541        struct rtl_tcb_desc *cb_desc;
 542        struct sk_buff *skb;
 543        u32     element_id = 0;
 544        u32     cmd_len = 0;
 545        u32     len;
 546
 547        switch (h2c_cmd) {
 548        case FW_H2C_SETPWRMODE:
 549                element_id = H2C_SETPWRMODE_CMD ;
 550                cmd_len = sizeof(struct h2c_set_pwrmode_parm);
 551                break;
 552        case FW_H2C_JOINBSSRPT:
 553                element_id = H2C_JOINBSSRPT_CMD;
 554                cmd_len = sizeof(struct h2c_joinbss_rpt_parm);
 555                break;
 556        case FW_H2C_WOWLAN_UPDATE_GTK:
 557                element_id = H2C_WOWLAN_UPDATE_GTK_CMD;
 558                cmd_len = sizeof(struct h2c_wpa_two_way_parm);
 559                break;
 560        case FW_H2C_WOWLAN_UPDATE_IV:
 561                element_id = H2C_WOWLAN_UPDATE_IV_CMD;
 562                cmd_len = sizeof(unsigned long long);
 563                break;
 564        case FW_H2C_WOWLAN_OFFLOAD:
 565                element_id = H2C_WOWLAN_FW_OFFLOAD;
 566                cmd_len = sizeof(u8);
 567                break;
 568        default:
 569                break;
 570        }
 571
 572        len = _rtl92s_get_h2c_cmdlen(MAX_TRANSMIT_BUFFER_SIZE, 1, &cmd_len);
 573        skb = dev_alloc_skb(len);
 574        if (!skb)
 575                return false;
 576        cb_desc = (struct rtl_tcb_desc *)(skb->cb);
 577        cb_desc->queue_index = TXCMD_QUEUE;
 578        cb_desc->cmd_or_init = DESC_PACKET_TYPE_NORMAL;
 579        cb_desc->last_inipkt = false;
 580
 581        _rtl92s_fill_h2c_cmd(skb, MAX_TRANSMIT_BUFFER_SIZE, 1, &element_id,
 582                        &cmd_len, &pcmd_buffer, &rtlhal->h2c_txcmd_seq);
 583        _rtl92s_cmd_send_packet(hw, skb, false);
 584        rtlpriv->cfg->ops->tx_polling(hw, TXCMD_QUEUE);
 585
 586        return true;
 587}
 588
 589void rtl92s_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 Mode)
 590{
 591        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 592        struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 593        struct h2c_set_pwrmode_parm     pwrmode;
 594        u16 max_wakeup_period = 0;
 595
 596        pwrmode.mode = Mode;
 597        pwrmode.flag_low_traffic_en = 0;
 598        pwrmode.flag_lpnav_en = 0;
 599        pwrmode.flag_rf_low_snr_en = 0;
 600        pwrmode.flag_dps_en = 0;
 601        pwrmode.bcn_rx_en = 0;
 602        pwrmode.bcn_to = 0;
 603        SET_BITS_TO_LE_2BYTE((u8 *)(&pwrmode) + 8, 0, 16,
 604                        mac->vif->bss_conf.beacon_int);
 605        pwrmode.app_itv = 0;
 606        pwrmode.awake_bcn_itvl = ppsc->reg_max_lps_awakeintvl;
 607        pwrmode.smart_ps = 1;
 608        pwrmode.bcn_pass_period = 10;
 609
 610        /* Set beacon pass count */
 611        if (pwrmode.mode == FW_PS_MIN_MODE)
 612                max_wakeup_period = mac->vif->bss_conf.beacon_int;
 613        else if (pwrmode.mode == FW_PS_MAX_MODE)
 614                max_wakeup_period = mac->vif->bss_conf.beacon_int *
 615                        mac->vif->bss_conf.dtim_period;
 616
 617        if (max_wakeup_period >= 500)
 618                pwrmode.bcn_pass_cnt = 1;
 619        else if ((max_wakeup_period >= 300) && (max_wakeup_period < 500))
 620                pwrmode.bcn_pass_cnt = 2;
 621        else if ((max_wakeup_period >= 200) && (max_wakeup_period < 300))
 622                pwrmode.bcn_pass_cnt = 3;
 623        else if ((max_wakeup_period >= 20) && (max_wakeup_period < 200))
 624                pwrmode.bcn_pass_cnt = 5;
 625        else
 626                pwrmode.bcn_pass_cnt = 1;
 627
 628        _rtl92s_firmware_set_h2c_cmd(hw, FW_H2C_SETPWRMODE, (u8 *)&pwrmode);
 629
 630}
 631
 632void rtl92s_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw,
 633                u8 mstatus, u8 ps_qosinfo)
 634{
 635        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 636        struct h2c_joinbss_rpt_parm joinbss_rpt;
 637
 638        joinbss_rpt.opmode = mstatus;
 639        joinbss_rpt.ps_qos_info = ps_qosinfo;
 640        joinbss_rpt.bssid[0] = mac->bssid[0];
 641        joinbss_rpt.bssid[1] = mac->bssid[1];
 642        joinbss_rpt.bssid[2] = mac->bssid[2];
 643        joinbss_rpt.bssid[3] = mac->bssid[3];
 644        joinbss_rpt.bssid[4] = mac->bssid[4];
 645        joinbss_rpt.bssid[5] = mac->bssid[5];
 646        SET_BITS_TO_LE_2BYTE((u8 *)(&joinbss_rpt) + 8, 0, 16,
 647                        mac->vif->bss_conf.beacon_int);
 648        SET_BITS_TO_LE_2BYTE((u8 *)(&joinbss_rpt) + 10, 0, 16, mac->assoc_id);
 649
 650        _rtl92s_firmware_set_h2c_cmd(hw, FW_H2C_JOINBSSRPT, (u8 *)&joinbss_rpt);
 651}
 652
 653