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