linux/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c
<<
>>
Prefs
   1/******************************************************************************
   2 *
   3 * Copyright(c) 2009-2014  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 * The full GNU General Public License is included in this distribution in the
  15 * file called LICENSE.
  16 *
  17 * Contact Information:
  18 * wlanfae <wlanfae@realtek.com>
  19 * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
  20 * Hsinchu 300, Taiwan.
  21 *
  22 * Larry Finger <Larry.Finger@lwfinger.net>
  23 *
  24 *****************************************************************************/
  25
  26#include "../wifi.h"
  27#include "../pci.h"
  28#include "../base.h"
  29#include "../core.h"
  30#include "reg.h"
  31#include "def.h"
  32#include "fw.h"
  33#include "dm.h"
  34
  35static void _rtl92ee_enable_fw_download(struct ieee80211_hw *hw, bool enable)
  36{
  37        struct rtl_priv *rtlpriv = rtl_priv(hw);
  38        u8 tmp;
  39
  40        if (enable) {
  41                rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x05);
  42
  43                tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
  44                rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
  45        } else {
  46                tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
  47                rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
  48        }
  49}
  50
  51static void _rtl92ee_fw_block_write(struct ieee80211_hw *hw,
  52                                    const u8 *buffer, u32 size)
  53{
  54        struct rtl_priv *rtlpriv = rtl_priv(hw);
  55        u32 blocksize = sizeof(u32);
  56        u8 *bufferptr = (u8 *)buffer;
  57        u32 *pu4byteptr = (u32 *)buffer;
  58        u32 i, offset, blockcount, remainsize;
  59
  60        blockcount = size / blocksize;
  61        remainsize = size % blocksize;
  62
  63        for (i = 0; i < blockcount; i++) {
  64                offset = i * blocksize;
  65                rtl_write_dword(rtlpriv, (FW_8192C_START_ADDRESS + offset),
  66                                *(pu4byteptr + i));
  67        }
  68
  69        if (remainsize) {
  70                offset = blockcount * blocksize;
  71                bufferptr += offset;
  72                for (i = 0; i < remainsize; i++) {
  73                        rtl_write_byte(rtlpriv,
  74                                       (FW_8192C_START_ADDRESS + offset + i),
  75                                       *(bufferptr + i));
  76                }
  77        }
  78}
  79
  80static void _rtl92ee_fw_page_write(struct ieee80211_hw *hw, u32 page,
  81                                   const u8 *buffer, u32 size)
  82{
  83        struct rtl_priv *rtlpriv = rtl_priv(hw);
  84        u8 value8;
  85        u8 u8page = (u8)(page & 0x07);
  86
  87        value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page;
  88        rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8);
  89
  90        _rtl92ee_fw_block_write(hw, buffer, size);
  91}
  92
  93static void _rtl92ee_fill_dummy(u8 *pfwbuf, u32 *pfwlen)
  94{
  95        u32 fwlen = *pfwlen;
  96        u8 remain = (u8)(fwlen % 4);
  97
  98        remain = (remain == 0) ? 0 : (4 - remain);
  99
 100        while (remain > 0) {
 101                pfwbuf[fwlen] = 0;
 102                fwlen++;
 103                remain--;
 104        }
 105
 106        *pfwlen = fwlen;
 107}
 108
 109static void _rtl92ee_write_fw(struct ieee80211_hw *hw,
 110                              enum version_8192e version,
 111                              u8 *buffer, u32 size)
 112{
 113        struct rtl_priv *rtlpriv = rtl_priv(hw);
 114        u8 *bufferptr = (u8 *)buffer;
 115        u32 pagenums, remainsize;
 116        u32 page, offset;
 117
 118        RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD , "FW size is %d bytes,\n", size);
 119
 120        _rtl92ee_fill_dummy(bufferptr, &size);
 121
 122        pagenums = size / FW_8192C_PAGE_SIZE;
 123        remainsize = size % FW_8192C_PAGE_SIZE;
 124
 125        if (pagenums > 8) {
 126                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 127                         "Page numbers should not greater then 8\n");
 128        }
 129
 130        for (page = 0; page < pagenums; page++) {
 131                offset = page * FW_8192C_PAGE_SIZE;
 132                _rtl92ee_fw_page_write(hw, page, (bufferptr + offset),
 133                                       FW_8192C_PAGE_SIZE);
 134                udelay(2);
 135        }
 136
 137        if (remainsize) {
 138                offset = pagenums * FW_8192C_PAGE_SIZE;
 139                page = pagenums;
 140                _rtl92ee_fw_page_write(hw, page, (bufferptr + offset),
 141                                       remainsize);
 142        }
 143}
 144
 145static int _rtl92ee_fw_free_to_go(struct ieee80211_hw *hw)
 146{
 147        struct rtl_priv *rtlpriv = rtl_priv(hw);
 148        int err = -EIO;
 149        u32 counter = 0;
 150        u32 value32;
 151
 152        do {
 153                value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
 154        } while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) &&
 155                 (!(value32 & FWDL_CHKSUM_RPT)));
 156
 157        if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) {
 158                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 159                         "chksum report faill ! REG_MCUFWDL:0x%08x .\n",
 160                          value32);
 161                goto exit;
 162        }
 163
 164        RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
 165                 "Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32);
 166
 167        value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
 168        value32 |= MCUFWDL_RDY;
 169        value32 &= ~WINTINI_RDY;
 170        rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
 171
 172        rtl92ee_firmware_selfreset(hw);
 173        counter = 0;
 174
 175        do {
 176                value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
 177                if (value32 & WINTINI_RDY) {
 178                        RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD ,
 179                                 "Polling FW ready success!! REG_MCUFWDL:0x%08x. count = %d\n",
 180                                 value32, counter);
 181                        err = 0;
 182                        goto exit;
 183                }
 184
 185                udelay(FW_8192C_POLLING_DELAY*10);
 186
 187        } while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT);
 188
 189        RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 190                 "Polling FW ready fail!! REG_MCUFWDL:0x%08x. count = %d\n",
 191                 value32, counter);
 192
 193exit:
 194        return err;
 195}
 196
 197int rtl92ee_download_fw(struct ieee80211_hw *hw, bool buse_wake_on_wlan_fw)
 198{
 199        struct rtl_priv *rtlpriv = rtl_priv(hw);
 200        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 201        struct rtlwifi_firmware_header *pfwheader;
 202        u8 *pfwdata;
 203        u32 fwsize;
 204        int err;
 205        enum version_8192e version = rtlhal->version;
 206
 207        if (!rtlhal->pfirmware)
 208                return 1;
 209
 210        pfwheader = (struct rtlwifi_firmware_header *)rtlhal->pfirmware;
 211        rtlhal->fw_version = le16_to_cpu(pfwheader->version);
 212        rtlhal->fw_subversion = pfwheader->subversion;
 213        pfwdata = (u8 *)rtlhal->pfirmware;
 214        fwsize = rtlhal->fwsize;
 215        RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
 216                 "normal Firmware SIZE %d\n" , fwsize);
 217
 218        if (IS_FW_HEADER_EXIST(pfwheader)) {
 219                RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
 220                         "Firmware Version(%d), Signature(%#x),Size(%d)\n",
 221                          pfwheader->version, pfwheader->signature,
 222                          (int)sizeof(struct rtlwifi_firmware_header));
 223
 224                pfwdata = pfwdata + sizeof(struct rtlwifi_firmware_header);
 225                fwsize = fwsize - sizeof(struct rtlwifi_firmware_header);
 226        } else {
 227                RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
 228                         "Firmware no Header, Signature(%#x)\n",
 229                          pfwheader->signature);
 230        }
 231
 232        if (rtlhal->mac_func_enable) {
 233                if (rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) {
 234                        rtl_write_byte(rtlpriv, REG_MCUFWDL, 0);
 235                        rtl92ee_firmware_selfreset(hw);
 236                }
 237        }
 238        _rtl92ee_enable_fw_download(hw, true);
 239        _rtl92ee_write_fw(hw, version, pfwdata, fwsize);
 240        _rtl92ee_enable_fw_download(hw, false);
 241
 242        err = _rtl92ee_fw_free_to_go(hw);
 243        if (err) {
 244                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 245                         "Firmware is not ready to run!\n");
 246        } else {
 247                RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD ,
 248                         "Firmware is ready to run!\n");
 249        }
 250
 251        return 0;
 252}
 253
 254static bool _rtl92ee_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
 255{
 256        struct rtl_priv *rtlpriv = rtl_priv(hw);
 257        u8 val_hmetfr;
 258        bool result = false;
 259
 260        val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
 261        if (((val_hmetfr >> boxnum) & BIT(0)) == 0)
 262                result = true;
 263        return result;
 264}
 265
 266static void _rtl92ee_fill_h2c_command(struct ieee80211_hw *hw, u8 element_id,
 267                                      u32 cmd_len, u8 *cmdbuffer)
 268{
 269        struct rtl_priv *rtlpriv = rtl_priv(hw);
 270        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 271        struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 272        u8 boxnum;
 273        u16 box_reg = 0, box_extreg = 0;
 274        u8 u1b_tmp;
 275        bool isfw_read = false;
 276        u8 buf_index = 0;
 277        bool bwrite_sucess = false;
 278        u8 wait_h2c_limmit = 100;
 279        u8 boxcontent[4], boxextcontent[4];
 280        u32 h2c_waitcounter = 0;
 281        unsigned long flag;
 282        u8 idx;
 283
 284        if (ppsc->dot11_psmode != EACTIVE ||
 285            ppsc->inactive_pwrstate == ERFOFF) {
 286                RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD ,
 287                         "FillH2CCommand8192E(): Return because RF is off!!!\n");
 288                return;
 289        }
 290
 291        RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD , "come in\n");
 292
 293        /* 1. Prevent race condition in setting H2C cmd.
 294         * (copy from MgntActSet_RF_State().)
 295         */
 296        while (true) {
 297                spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
 298                if (rtlhal->h2c_setinprogress) {
 299                        RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD ,
 300                                 "H2C set in progress! Wait to set..element_id(%d).\n",
 301                                  element_id);
 302
 303                        while (rtlhal->h2c_setinprogress) {
 304                                spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
 305                                                       flag);
 306                                h2c_waitcounter++;
 307                                RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD ,
 308                                         "Wait 100 us (%d times)...\n",
 309                                          h2c_waitcounter);
 310                                udelay(100);
 311
 312                                if (h2c_waitcounter > 1000)
 313                                        return;
 314                                spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
 315                                                  flag);
 316                        }
 317                        spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
 318                } else {
 319                        rtlhal->h2c_setinprogress = true;
 320                        spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
 321                        break;
 322                }
 323        }
 324
 325        while (!bwrite_sucess) {
 326                /* 2. Find the last BOX number which has been writen. */
 327                boxnum = rtlhal->last_hmeboxnum;
 328                switch (boxnum) {
 329                case 0:
 330                        box_reg = REG_HMEBOX_0;
 331                        box_extreg = REG_HMEBOX_EXT_0;
 332                        break;
 333                case 1:
 334                        box_reg = REG_HMEBOX_1;
 335                        box_extreg = REG_HMEBOX_EXT_1;
 336                        break;
 337                case 2:
 338                        box_reg = REG_HMEBOX_2;
 339                        box_extreg = REG_HMEBOX_EXT_2;
 340                        break;
 341                case 3:
 342                        box_reg = REG_HMEBOX_3;
 343                        box_extreg = REG_HMEBOX_EXT_3;
 344                        break;
 345                default:
 346                        RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
 347                                 "switch case not process\n");
 348                        break;
 349                }
 350
 351                /* 3. Check if the box content is empty. */
 352                isfw_read = false;
 353                u1b_tmp = rtl_read_byte(rtlpriv, REG_CR);
 354
 355                if (u1b_tmp != 0xea) {
 356                        isfw_read = true;
 357                } else {
 358                        if (rtl_read_byte(rtlpriv, REG_TXDMA_STATUS) == 0xea ||
 359                            rtl_read_byte(rtlpriv, REG_TXPKT_EMPTY) == 0xea)
 360                                rtl_write_byte(rtlpriv, REG_SYS_CFG1 + 3, 0xff);
 361                }
 362
 363                if (isfw_read) {
 364                        wait_h2c_limmit = 100;
 365                        isfw_read = _rtl92ee_check_fw_read_last_h2c(hw, boxnum);
 366                        while (!isfw_read) {
 367                                wait_h2c_limmit--;
 368                                if (wait_h2c_limmit == 0) {
 369                                        RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD ,
 370                                                 "Waiting too long for FW read clear HMEBox(%d)!!!\n",
 371                                                 boxnum);
 372                                        break;
 373                                }
 374                                udelay(10);
 375                                isfw_read =
 376                                  _rtl92ee_check_fw_read_last_h2c(hw, boxnum);
 377                                u1b_tmp = rtl_read_byte(rtlpriv, 0x130);
 378                                RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD ,
 379                                         "Waiting for FW read clear HMEBox(%d)!!! 0x130 = %2x\n",
 380                                         boxnum, u1b_tmp);
 381                        }
 382                }
 383
 384                /* If Fw has not read the last
 385                 * H2C cmd, break and give up this H2C.
 386                 */
 387                if (!isfw_read) {
 388                        RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD ,
 389                                 "Write H2C reg BOX[%d] fail,Fw don't read.\n",
 390                                 boxnum);
 391                        break;
 392                }
 393                /* 4. Fill the H2C cmd into box */
 394                memset(boxcontent, 0, sizeof(boxcontent));
 395                memset(boxextcontent, 0, sizeof(boxextcontent));
 396                boxcontent[0] = element_id;
 397                RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD ,
 398                         "Write element_id box_reg(%4x) = %2x\n",
 399                          box_reg, element_id);
 400
 401                switch (cmd_len) {
 402                case 1:
 403                case 2:
 404                case 3:
 405                        /*boxcontent[0] &= ~(BIT(7));*/
 406                        memcpy((u8 *)(boxcontent) + 1,
 407                               cmdbuffer + buf_index, cmd_len);
 408
 409                        for (idx = 0; idx < 4; idx++) {
 410                                rtl_write_byte(rtlpriv, box_reg + idx,
 411                                               boxcontent[idx]);
 412                        }
 413                        break;
 414                case 4:
 415                case 5:
 416                case 6:
 417                case 7:
 418                        /*boxcontent[0] |= (BIT(7));*/
 419                        memcpy((u8 *)(boxextcontent),
 420                               cmdbuffer + buf_index+3, cmd_len-3);
 421                        memcpy((u8 *)(boxcontent) + 1,
 422                               cmdbuffer + buf_index, 3);
 423
 424                        for (idx = 0; idx < 4; idx++) {
 425                                rtl_write_byte(rtlpriv, box_extreg + idx,
 426                                               boxextcontent[idx]);
 427                        }
 428
 429                        for (idx = 0; idx < 4; idx++) {
 430                                rtl_write_byte(rtlpriv, box_reg + idx,
 431                                               boxcontent[idx]);
 432                        }
 433                        break;
 434                default:
 435                        RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
 436                                 "switch case not process\n");
 437                        break;
 438                }
 439
 440                bwrite_sucess = true;
 441
 442                rtlhal->last_hmeboxnum = boxnum + 1;
 443                if (rtlhal->last_hmeboxnum == 4)
 444                        rtlhal->last_hmeboxnum = 0;
 445
 446                RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD ,
 447                         "pHalData->last_hmeboxnum  = %d\n",
 448                          rtlhal->last_hmeboxnum);
 449        }
 450
 451        spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
 452        rtlhal->h2c_setinprogress = false;
 453        spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
 454
 455        RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD , "go out\n");
 456}
 457
 458void rtl92ee_fill_h2c_cmd(struct ieee80211_hw *hw,
 459                          u8 element_id, u32 cmd_len, u8 *cmdbuffer)
 460{
 461        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 462        u32 tmp_cmdbuf[2];
 463
 464        if (!rtlhal->fw_ready) {
 465                RT_ASSERT(false,
 466                          "return H2C cmd because of Fw download fail!!!\n");
 467                return;
 468        }
 469
 470        memset(tmp_cmdbuf, 0, 8);
 471        memcpy(tmp_cmdbuf, cmdbuffer, cmd_len);
 472        _rtl92ee_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
 473}
 474
 475void rtl92ee_firmware_selfreset(struct ieee80211_hw *hw)
 476{
 477        u8 u1b_tmp;
 478        struct rtl_priv *rtlpriv = rtl_priv(hw);
 479
 480        u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1);
 481        rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, (u1b_tmp & (~BIT(0))));
 482
 483        u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
 484        rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, (u1b_tmp & (~BIT(2))));
 485
 486        udelay(50);
 487
 488        u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1);
 489        rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, (u1b_tmp | BIT(0)));
 490
 491        u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
 492        rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, (u1b_tmp | BIT(2)));
 493
 494        RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD ,
 495                 "  _8051Reset92E(): 8051 reset success .\n");
 496}
 497
 498void rtl92ee_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
 499{
 500        struct rtl_priv *rtlpriv = rtl_priv(hw);
 501        u8 u1_h2c_set_pwrmode[H2C_92E_PWEMODE_LENGTH] = { 0 };
 502        struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 503        u8 rlbm , power_state = 0;
 504
 505        RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD , "FW LPS mode = %d\n", mode);
 506
 507        SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, ((mode) ? 1 : 0));
 508        rlbm = 0;/*YJ,temp,120316. FW now not support RLBM=2.*/
 509        SET_H2CCMD_PWRMODE_PARM_RLBM(u1_h2c_set_pwrmode, rlbm);
 510        SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode,
 511                                         (rtlpriv->mac80211.p2p) ?
 512                                         ppsc->smart_ps : 1);
 513        SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(u1_h2c_set_pwrmode,
 514                                               ppsc->reg_max_lps_awakeintvl);
 515        SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(u1_h2c_set_pwrmode, 0);
 516        if (mode == FW_PS_ACTIVE_MODE)
 517                power_state |= FW_PWR_STATE_ACTIVE;
 518        else
 519                power_state |= FW_PWR_STATE_RF_OFF;
 520        SET_H2CCMD_PWRMODE_PARM_PWR_STATE(u1_h2c_set_pwrmode, power_state);
 521
 522        RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
 523                      "rtl92c_set_fw_pwrmode(): u1_h2c_set_pwrmode\n",
 524                      u1_h2c_set_pwrmode, H2C_92E_PWEMODE_LENGTH);
 525        rtl92ee_fill_h2c_cmd(hw, H2C_92E_SETPWRMODE, H2C_92E_PWEMODE_LENGTH,
 526                             u1_h2c_set_pwrmode);
 527}
 528
 529void rtl92ee_set_fw_media_status_rpt_cmd(struct ieee80211_hw *hw, u8 mstatus)
 530{
 531        u8 parm[3] = { 0 , 0 , 0 };
 532        /* parm[0]: bit0=0-->Disconnect, bit0=1-->Connect
 533         *          bit1=0-->update Media Status to MACID
 534         *          bit1=1-->update Media Status from MACID to MACID_End
 535         * parm[1]: MACID, if this is INFRA_STA, MacID = 0
 536         * parm[2]: MACID_End
 537         */
 538
 539        SET_H2CCMD_MSRRPT_PARM_OPMODE(parm, mstatus);
 540        SET_H2CCMD_MSRRPT_PARM_MACID_IND(parm, 0);
 541
 542        rtl92ee_fill_h2c_cmd(hw, H2C_92E_MSRRPT, 3, parm);
 543}
 544
 545#define BEACON_PG               0 /* ->1 */
 546#define PSPOLL_PG               2
 547#define NULL_PG                 3
 548#define PROBERSP_PG             4 /* ->5 */
 549
 550#define TOTAL_RESERVED_PKT_LEN  768
 551
 552static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
 553        /* page 0 beacon */
 554        0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
 555        0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78,
 556        0xEC, 0x1A, 0x59, 0x0B, 0xAD, 0xD4, 0x20, 0x00,
 557        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 558        0x64, 0x00, 0x10, 0x04, 0x00, 0x05, 0x54, 0x65,
 559        0x73, 0x74, 0x32, 0x01, 0x08, 0x82, 0x84, 0x0B,
 560        0x16, 0x24, 0x30, 0x48, 0x6C, 0x03, 0x01, 0x06,
 561        0x06, 0x02, 0x00, 0x00, 0x2A, 0x01, 0x02, 0x32,
 562        0x04, 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C,
 563        0x09, 0x03, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
 564        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 565        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 566        0x00, 0x3D, 0x00, 0xDD, 0x07, 0x00, 0xE0, 0x4C,
 567        0x02, 0x02, 0x00, 0x00, 0xDD, 0x18, 0x00, 0x50,
 568        0xF2, 0x01, 0x01, 0x00, 0x00, 0x50, 0xF2, 0x04,
 569        0x01, 0x00, 0x00, 0x50, 0xF2, 0x04, 0x01, 0x00,
 570
 571        /* page 1 beacon */
 572        0x00, 0x50, 0xF2, 0x02, 0x00, 0x00, 0x00, 0x00,
 573        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 574        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 575        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 576        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 577        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 578        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 579        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 580        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 581        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 582        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 583        0x10, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00,
 584        0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00,
 585        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 586        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 587        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 588
 589        /* page 2  ps-poll */
 590        0xA4, 0x10, 0x01, 0xC0, 0xEC, 0x1A, 0x59, 0x0B,
 591        0xAD, 0xD4, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78,
 592        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 593        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 594        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 595        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 596        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 597        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 598        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 599        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 600        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 601        0x18, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00,
 602        0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
 603        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 604        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 605        0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 606
 607        /* page 3  null */
 608        0x48, 0x01, 0x00, 0x00, 0xEC, 0x1A, 0x59, 0x0B,
 609        0xAD, 0xD4, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78,
 610        0xEC, 0x1A, 0x59, 0x0B, 0xAD, 0xD4, 0x00, 0x00,
 611        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 612        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 613        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 614        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 615        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 616        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 617        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 618        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 619        0x72, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00,
 620        0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
 621        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 622        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 623        0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 624
 625        /* page 4  probe_resp */
 626        0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
 627        0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
 628        0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
 629        0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
 630        0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
 631        0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
 632        0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
 633        0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
 634        0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
 635        0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
 636        0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 637        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 638        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 639        0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
 640        0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 641        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 642
 643        /* page 5  probe_resp */
 644        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 645        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 646        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 647        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 648        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 649        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 650        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 651        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 652        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 653        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 654        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 655        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 656        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 657        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 658        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 659        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 660};
 661
 662void rtl92ee_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished)
 663{
 664        struct rtl_priv *rtlpriv = rtl_priv(hw);
 665        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 666        struct sk_buff *skb = NULL;
 667
 668        u32 totalpacketlen;
 669        u8 u1rsvdpageloc[5] = { 0 };
 670        bool b_dlok = false;
 671
 672        u8 *beacon;
 673        u8 *p_pspoll;
 674        u8 *nullfunc;
 675        u8 *p_probersp;
 676        /*---------------------------------------------------------
 677         *                      (1) beacon
 678         *---------------------------------------------------------
 679         */
 680        beacon = &reserved_page_packet[BEACON_PG * 128];
 681        SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
 682        SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
 683
 684        /*-------------------------------------------------------
 685         *                      (2) ps-poll
 686         *--------------------------------------------------------
 687         */
 688        p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
 689        SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
 690        SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
 691        SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
 692
 693        SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1rsvdpageloc, PSPOLL_PG);
 694
 695        /*--------------------------------------------------------
 696         *                      (3) null data
 697         *---------------------------------------------------------
 698         */
 699        nullfunc = &reserved_page_packet[NULL_PG * 128];
 700        SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
 701        SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
 702        SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
 703
 704        SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1rsvdpageloc, NULL_PG);
 705
 706        /*---------------------------------------------------------
 707         *                      (4) probe response
 708         *----------------------------------------------------------
 709         */
 710        p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
 711        SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
 712        SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
 713        SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
 714
 715        SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1rsvdpageloc, PROBERSP_PG);
 716
 717        totalpacketlen = TOTAL_RESERVED_PKT_LEN;
 718
 719        RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD ,
 720                      "rtl92ee_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
 721                      &reserved_page_packet[0], totalpacketlen);
 722        RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD ,
 723                      "rtl92ee_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
 724                      u1rsvdpageloc, 3);
 725
 726        skb = dev_alloc_skb(totalpacketlen);
 727        memcpy((u8 *)skb_put(skb, totalpacketlen),
 728               &reserved_page_packet, totalpacketlen);
 729
 730        b_dlok = true;
 731
 732        if (b_dlok) {
 733                RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD ,
 734                         "Set RSVD page location to Fw.\n");
 735                RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD ,
 736                              "H2C_RSVDPAGE:\n", u1rsvdpageloc, 3);
 737                rtl92ee_fill_h2c_cmd(hw, H2C_92E_RSVDPAGE,
 738                                     sizeof(u1rsvdpageloc), u1rsvdpageloc);
 739        } else {
 740                RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
 741                         "Set RSVD page location to Fw FAIL!!!!!!.\n");
 742        }
 743}
 744
 745/*Shoud check FW support p2p or not.*/
 746static void rtl92ee_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw, u8 ctwindow)
 747{
 748        u8 u1_ctwindow_period[1] = {ctwindow};
 749
 750        rtl92ee_fill_h2c_cmd(hw, H2C_92E_P2P_PS_CTW_CMD, 1, u1_ctwindow_period);
 751}
 752
 753void rtl92ee_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
 754{
 755        struct rtl_priv *rtlpriv = rtl_priv(hw);
 756        struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
 757        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 758        struct rtl_p2p_ps_info *p2pinfo = &rtlps->p2p_ps_info;
 759        struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload;
 760        u8 i;
 761        u16 ctwindow;
 762        u32 start_time, tsf_low;
 763
 764        switch (p2p_ps_state) {
 765        case P2P_PS_DISABLE:
 766                RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD , "P2P_PS_DISABLE\n");
 767                memset(p2p_ps_offload, 0, sizeof(*p2p_ps_offload));
 768                break;
 769        case P2P_PS_ENABLE:
 770                RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD , "P2P_PS_ENABLE\n");
 771                /* update CTWindow value. */
 772                if (p2pinfo->ctwindow > 0) {
 773                        p2p_ps_offload->ctwindow_en = 1;
 774                        ctwindow = p2pinfo->ctwindow;
 775                        rtl92ee_set_p2p_ctw_period_cmd(hw, ctwindow);
 776                }
 777                /* hw only support 2 set of NoA */
 778                for (i = 0 ; i < p2pinfo->noa_num ; i++) {
 779                        /* To control the register setting for which NOA*/
 780                        rtl_write_byte(rtlpriv, 0x5cf, (i << 4));
 781                        if (i == 0)
 782                                p2p_ps_offload->noa0_en = 1;
 783                        else
 784                                p2p_ps_offload->noa1_en = 1;
 785                        /* config P2P NoA Descriptor Register */
 786                        rtl_write_dword(rtlpriv, 0x5E0,
 787                                        p2pinfo->noa_duration[i]);
 788                        rtl_write_dword(rtlpriv, 0x5E4,
 789                                        p2pinfo->noa_interval[i]);
 790
 791                        /*Get Current TSF value */
 792                        tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
 793
 794                        start_time = p2pinfo->noa_start_time[i];
 795                        if (p2pinfo->noa_count_type[i] != 1) {
 796                                while (start_time <= (tsf_low + (50 * 1024))) {
 797                                        start_time += p2pinfo->noa_interval[i];
 798                                        if (p2pinfo->noa_count_type[i] != 255)
 799                                                p2pinfo->noa_count_type[i]--;
 800                                }
 801                        }
 802                        rtl_write_dword(rtlpriv, 0x5E8, start_time);
 803                        rtl_write_dword(rtlpriv, 0x5EC,
 804                                        p2pinfo->noa_count_type[i]);
 805                }
 806                if ((p2pinfo->opp_ps == 1) || (p2pinfo->noa_num > 0)) {
 807                        /* rst p2p circuit */
 808                        rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, BIT(4));
 809                        p2p_ps_offload->offload_en = 1;
 810
 811                        if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) {
 812                                p2p_ps_offload->role = 1;
 813                                p2p_ps_offload->allstasleep = 0;
 814                        } else {
 815                                p2p_ps_offload->role = 0;
 816                        }
 817                        p2p_ps_offload->discovery = 0;
 818                }
 819                break;
 820        case P2P_PS_SCAN:
 821                RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD , "P2P_PS_SCAN\n");
 822                p2p_ps_offload->discovery = 1;
 823                break;
 824        case P2P_PS_SCAN_DONE:
 825                RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD , "P2P_PS_SCAN_DONE\n");
 826                p2p_ps_offload->discovery = 0;
 827                p2pinfo->p2p_ps_state = P2P_PS_ENABLE;
 828                break;
 829        default:
 830                break;
 831        }
 832        rtl92ee_fill_h2c_cmd(hw, H2C_92E_P2P_PS_OFFLOAD, 1,
 833                             (u8 *)p2p_ps_offload);
 834}
 835
 836static void _rtl92ee_c2h_ra_report_handler(struct ieee80211_hw *hw,
 837                                           u8 *cmd_buf, u8 cmd_len)
 838{
 839        u8 rate = cmd_buf[0] & 0x3F;
 840        bool collision_state = cmd_buf[3] & BIT(0);
 841
 842        rtl92ee_dm_dynamic_arfb_select(hw, rate, collision_state);
 843}
 844
 845static void _rtl92ee_c2h_content_parsing(struct ieee80211_hw *hw, u8 c2h_cmd_id,
 846                                         u8 c2h_cmd_len, u8 *tmp_buf)
 847{
 848        struct rtl_priv *rtlpriv = rtl_priv(hw);
 849
 850        switch (c2h_cmd_id) {
 851        case C2H_8192E_DBG:
 852                RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
 853                         "[C2H], C2H_8723BE_DBG!!\n");
 854                break;
 855        case C2H_8192E_TXBF:
 856                RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
 857                         "[C2H], C2H_8192E_TXBF!!\n");
 858                break;
 859        case C2H_8192E_TX_REPORT:
 860                RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE ,
 861                         "[C2H], C2H_8723BE_TX_REPORT!\n");
 862                break;
 863        case C2H_8192E_BT_INFO:
 864                RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
 865                         "[C2H], C2H_8723BE_BT_INFO!!\n");
 866                rtlpriv->btcoexist.btc_ops->btc_btinfo_notify(rtlpriv, tmp_buf,
 867                                                              c2h_cmd_len);
 868                break;
 869        case C2H_8192E_BT_MP:
 870                RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
 871                         "[C2H], C2H_8723BE_BT_MP!!\n");
 872                break;
 873        case C2H_8192E_RA_RPT:
 874                _rtl92ee_c2h_ra_report_handler(hw, tmp_buf, c2h_cmd_len);
 875                break;
 876        default:
 877                RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
 878                         "[C2H], Unknown packet!! CmdId(%#X)!\n", c2h_cmd_id);
 879                break;
 880        }
 881}
 882
 883void rtl92ee_c2h_packet_handler(struct ieee80211_hw *hw, u8 *buffer, u8 len)
 884{
 885        struct rtl_priv *rtlpriv = rtl_priv(hw);
 886        u8 c2h_cmd_id = 0, c2h_cmd_seq = 0, c2h_cmd_len = 0;
 887        u8 *tmp_buf = NULL;
 888
 889        c2h_cmd_id = buffer[0];
 890        c2h_cmd_seq = buffer[1];
 891        c2h_cmd_len = len - 2;
 892        tmp_buf = buffer + 2;
 893
 894        RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
 895                 "[C2H packet], c2hCmdId=0x%x, c2hCmdSeq=0x%x, c2hCmdLen=%d\n",
 896                 c2h_cmd_id, c2h_cmd_seq, c2h_cmd_len);
 897
 898        RT_PRINT_DATA(rtlpriv, COMP_FW, DBG_TRACE,
 899                      "[C2H packet], Content Hex:\n", tmp_buf, c2h_cmd_len);
 900
 901        _rtl92ee_c2h_content_parsing(hw, c2h_cmd_id, c2h_cmd_len, tmp_buf);
 902}
 903