linux/drivers/net/wireless/rtlwifi/rtl8192de/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#include "sw.h"
  37
  38static bool _rtl92d_is_fw_downloaded(struct rtl_priv *rtlpriv)
  39{
  40        return (rtl_read_dword(rtlpriv, REG_MCUFWDL) & MCUFWDL_RDY) ?
  41                true : false;
  42}
  43
  44static void _rtl92d_enable_fw_download(struct ieee80211_hw *hw, bool enable)
  45{
  46        struct rtl_priv *rtlpriv = rtl_priv(hw);
  47        u8 tmp;
  48
  49        if (enable) {
  50                tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
  51                rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp | 0x04);
  52                tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
  53                rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01);
  54                tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
  55                rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
  56        } else {
  57                tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
  58                rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
  59                /* Reserved for fw extension.
  60                 * 0x81[7] is used for mac0 status ,
  61                 * so don't write this reg here
  62                 * rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00);*/
  63        }
  64}
  65
  66static void _rtl92d_fw_block_write(struct ieee80211_hw *hw,
  67                                   const u8 *buffer, u32 size)
  68{
  69        struct rtl_priv *rtlpriv = rtl_priv(hw);
  70        u32 blocksize = sizeof(u32);
  71        u8 *bufferptr = (u8 *) buffer;
  72        u32 *pu4BytePtr = (u32 *) buffer;
  73        u32 i, offset, blockCount, remainSize;
  74
  75        blockCount = size / blocksize;
  76        remainSize = size % blocksize;
  77        for (i = 0; i < blockCount; i++) {
  78                offset = i * blocksize;
  79                rtl_write_dword(rtlpriv, (FW_8192D_START_ADDRESS + offset),
  80                                *(pu4BytePtr + i));
  81        }
  82        if (remainSize) {
  83                offset = blockCount * blocksize;
  84                bufferptr += offset;
  85                for (i = 0; i < remainSize; i++) {
  86                        rtl_write_byte(rtlpriv, (FW_8192D_START_ADDRESS +
  87                                                 offset + i), *(bufferptr + i));
  88                }
  89        }
  90}
  91
  92static void _rtl92d_fw_page_write(struct ieee80211_hw *hw,
  93                                  u32 page, const u8 *buffer, u32 size)
  94{
  95        struct rtl_priv *rtlpriv = rtl_priv(hw);
  96        u8 value8;
  97        u8 u8page = (u8) (page & 0x07);
  98
  99        value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page;
 100        rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8);
 101        _rtl92d_fw_block_write(hw, buffer, size);
 102}
 103
 104static void _rtl92d_fill_dummy(u8 *pfwbuf, u32 *pfwlen)
 105{
 106        u32 fwlen = *pfwlen;
 107        u8 remain = (u8) (fwlen % 4);
 108
 109        remain = (remain == 0) ? 0 : (4 - remain);
 110        while (remain > 0) {
 111                pfwbuf[fwlen] = 0;
 112                fwlen++;
 113                remain--;
 114        }
 115        *pfwlen = fwlen;
 116}
 117
 118static void _rtl92d_write_fw(struct ieee80211_hw *hw,
 119                             enum version_8192d version, u8 *buffer, u32 size)
 120{
 121        struct rtl_priv *rtlpriv = rtl_priv(hw);
 122        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 123        u8 *bufferPtr = buffer;
 124        u32 pagenums, remainSize;
 125        u32 page, offset;
 126
 127        RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "FW size is %d bytes,\n", size);
 128        if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192DE)
 129                _rtl92d_fill_dummy(bufferPtr, &size);
 130        pagenums = size / FW_8192D_PAGE_SIZE;
 131        remainSize = size % FW_8192D_PAGE_SIZE;
 132        if (pagenums > 8) {
 133                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 134                         "Page numbers should not greater then 8\n");
 135        }
 136        for (page = 0; page < pagenums; page++) {
 137                offset = page * FW_8192D_PAGE_SIZE;
 138                _rtl92d_fw_page_write(hw, page, (bufferPtr + offset),
 139                                      FW_8192D_PAGE_SIZE);
 140        }
 141        if (remainSize) {
 142                offset = pagenums * FW_8192D_PAGE_SIZE;
 143                page = pagenums;
 144                _rtl92d_fw_page_write(hw, page, (bufferPtr + offset),
 145                                      remainSize);
 146        }
 147}
 148
 149static int _rtl92d_fw_free_to_go(struct ieee80211_hw *hw)
 150{
 151        struct rtl_priv *rtlpriv = rtl_priv(hw);
 152        u32 counter = 0;
 153        u32 value32;
 154
 155        do {
 156                value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
 157        } while ((counter++ < FW_8192D_POLLING_TIMEOUT_COUNT) &&
 158                 (!(value32 & FWDL_ChkSum_rpt)));
 159        if (counter >= FW_8192D_POLLING_TIMEOUT_COUNT) {
 160                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 161                         "chksum report faill ! REG_MCUFWDL:0x%08x\n",
 162                         value32);
 163                return -EIO;
 164        }
 165        RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
 166                 "Checksum report OK ! REG_MCUFWDL:0x%08x\n", value32);
 167        value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
 168        value32 |= MCUFWDL_RDY;
 169        rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
 170        return 0;
 171}
 172
 173void rtl92d_firmware_selfreset(struct ieee80211_hw *hw)
 174{
 175        struct rtl_priv *rtlpriv = rtl_priv(hw);
 176        u8 u1b_tmp;
 177        u8 delay = 100;
 178
 179        /* Set (REG_HMETFR + 3) to  0x20 is reset 8051 */
 180        rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20);
 181        u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
 182        while (u1b_tmp & BIT(2)) {
 183                delay--;
 184                if (delay == 0)
 185                        break;
 186                udelay(50);
 187                u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
 188        }
 189        RT_ASSERT((delay > 0), "8051 reset failed!\n");
 190        RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
 191                 "=====> 8051 reset success (%d)\n", delay);
 192}
 193
 194static int _rtl92d_fw_init(struct ieee80211_hw *hw)
 195{
 196        struct rtl_priv *rtlpriv = rtl_priv(hw);
 197        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 198        u32 counter;
 199
 200        RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, "FW already have download\n");
 201        /* polling for FW ready */
 202        counter = 0;
 203        do {
 204                if (rtlhal->interfaceindex == 0) {
 205                        if (rtl_read_byte(rtlpriv, FW_MAC0_READY) &
 206                            MAC0_READY) {
 207                                RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
 208                                         "Polling FW ready success!! REG_MCUFWDL: 0x%x\n",
 209                                         rtl_read_byte(rtlpriv,
 210                                                       FW_MAC0_READY));
 211                                return 0;
 212                        }
 213                        udelay(5);
 214                } else {
 215                        if (rtl_read_byte(rtlpriv, FW_MAC1_READY) &
 216                            MAC1_READY) {
 217                                RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
 218                                         "Polling FW ready success!! REG_MCUFWDL: 0x%x\n",
 219                                         rtl_read_byte(rtlpriv,
 220                                                       FW_MAC1_READY));
 221                                return 0;
 222                        }
 223                        udelay(5);
 224                }
 225        } while (counter++ < POLLING_READY_TIMEOUT_COUNT);
 226
 227        if (rtlhal->interfaceindex == 0) {
 228                RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
 229                         "Polling FW ready fail!! MAC0 FW init not ready: 0x%x\n",
 230                         rtl_read_byte(rtlpriv, FW_MAC0_READY));
 231        } else {
 232                RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
 233                         "Polling FW ready fail!! MAC1 FW init not ready: 0x%x\n",
 234                         rtl_read_byte(rtlpriv, FW_MAC1_READY));
 235        }
 236        RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
 237                 "Polling FW ready fail!! REG_MCUFWDL:0x%08ul\n",
 238                 rtl_read_dword(rtlpriv, REG_MCUFWDL));
 239        return -1;
 240}
 241
 242int rtl92d_download_fw(struct ieee80211_hw *hw)
 243{
 244        struct rtl_priv *rtlpriv = rtl_priv(hw);
 245        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 246        u8 *pfwheader;
 247        u8 *pfwdata;
 248        u32 fwsize;
 249        int err;
 250        enum version_8192d version = rtlhal->version;
 251        u8 value;
 252        u32 count;
 253        bool fw_downloaded = false, fwdl_in_process = false;
 254        unsigned long flags;
 255
 256        if (rtlpriv->max_fw_size == 0 || !rtlhal->pfirmware)
 257                return 1;
 258        fwsize = rtlhal->fwsize;
 259        pfwheader = rtlhal->pfirmware;
 260        pfwdata = rtlhal->pfirmware;
 261        rtlhal->fw_version = (u16) GET_FIRMWARE_HDR_VERSION(pfwheader);
 262        rtlhal->fw_subversion = (u16) GET_FIRMWARE_HDR_SUB_VER(pfwheader);
 263        RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
 264                 "FirmwareVersion(%d), FirmwareSubVersion(%d), Signature(%#x)\n",
 265                 rtlhal->fw_version, rtlhal->fw_subversion,
 266                 GET_FIRMWARE_HDR_SIGNATURE(pfwheader));
 267        if (IS_FW_HEADER_EXIST(pfwheader)) {
 268                RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
 269                         "Shift 32 bytes for FW header!!\n");
 270                pfwdata = pfwdata + 32;
 271                fwsize = fwsize - 32;
 272        }
 273
 274        spin_lock_irqsave(&globalmutex_for_fwdownload, flags);
 275        fw_downloaded = _rtl92d_is_fw_downloaded(rtlpriv);
 276        if ((rtl_read_byte(rtlpriv, 0x1f) & BIT(5)) == BIT(5))
 277                fwdl_in_process = true;
 278        else
 279                fwdl_in_process = false;
 280        if (fw_downloaded) {
 281                spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags);
 282                goto exit;
 283        } else if (fwdl_in_process) {
 284                spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags);
 285                for (count = 0; count < 5000; count++) {
 286                        udelay(500);
 287                        spin_lock_irqsave(&globalmutex_for_fwdownload, flags);
 288                        fw_downloaded = _rtl92d_is_fw_downloaded(rtlpriv);
 289                        if ((rtl_read_byte(rtlpriv, 0x1f) & BIT(5)) == BIT(5))
 290                                fwdl_in_process = true;
 291                        else
 292                                fwdl_in_process = false;
 293                        spin_unlock_irqrestore(&globalmutex_for_fwdownload,
 294                                               flags);
 295                        if (fw_downloaded)
 296                                goto exit;
 297                        else if (!fwdl_in_process)
 298                                break;
 299                        else
 300                                RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
 301                                         "Wait for another mac download fw\n");
 302                }
 303                spin_lock_irqsave(&globalmutex_for_fwdownload, flags);
 304                value = rtl_read_byte(rtlpriv, 0x1f);
 305                value |= BIT(5);
 306                rtl_write_byte(rtlpriv, 0x1f, value);
 307                spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags);
 308        } else {
 309                value = rtl_read_byte(rtlpriv, 0x1f);
 310                value |= BIT(5);
 311                rtl_write_byte(rtlpriv, 0x1f, value);
 312                spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags);
 313        }
 314
 315        /* If 8051 is running in RAM code, driver should
 316         * inform Fw to reset by itself, or it will cause
 317         * download Fw fail.*/
 318        /* 8051 RAM code */
 319        if (rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) {
 320                rtl92d_firmware_selfreset(hw);
 321                rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00);
 322        }
 323        _rtl92d_enable_fw_download(hw, true);
 324        _rtl92d_write_fw(hw, version, pfwdata, fwsize);
 325        _rtl92d_enable_fw_download(hw, false);
 326        spin_lock_irqsave(&globalmutex_for_fwdownload, flags);
 327        err = _rtl92d_fw_free_to_go(hw);
 328        /* download fw over,clear 0x1f[5] */
 329        value = rtl_read_byte(rtlpriv, 0x1f);
 330        value &= (~BIT(5));
 331        rtl_write_byte(rtlpriv, 0x1f, value);
 332        spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags);
 333        if (err) {
 334                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 335                         "fw is not ready to run!\n");
 336                goto exit;
 337        } else {
 338                RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "fw is ready to run!\n");
 339        }
 340exit:
 341        err = _rtl92d_fw_init(hw);
 342        return err;
 343}
 344
 345static bool _rtl92d_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
 346{
 347        struct rtl_priv *rtlpriv = rtl_priv(hw);
 348        u8 val_hmetfr;
 349        bool result = false;
 350
 351        val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
 352        if (((val_hmetfr >> boxnum) & BIT(0)) == 0)
 353                result = true;
 354        return result;
 355}
 356
 357static void _rtl92d_fill_h2c_command(struct ieee80211_hw *hw,
 358                              u8 element_id, u32 cmd_len, u8 *cmdbuffer)
 359{
 360        struct rtl_priv *rtlpriv = rtl_priv(hw);
 361        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 362        struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 363        u8 boxnum;
 364        u16 box_reg = 0, box_extreg = 0;
 365        u8 u1b_tmp;
 366        bool isfw_read = false;
 367        u8 buf_index = 0;
 368        bool bwrite_success = false;
 369        u8 wait_h2c_limmit = 100;
 370        u8 wait_writeh2c_limmit = 100;
 371        u8 boxcontent[4], boxextcontent[2];
 372        u32 h2c_waitcounter = 0;
 373        unsigned long flag;
 374        u8 idx;
 375
 376        if (ppsc->rfpwr_state == ERFOFF || ppsc->inactive_pwrstate == ERFOFF) {
 377                RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
 378                         "Return as RF is off!!!\n");
 379                return;
 380        }
 381        RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n");
 382        while (true) {
 383                spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
 384                if (rtlhal->h2c_setinprogress) {
 385                        RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
 386                                 "H2C set in progress! Wait to set..element_id(%d)\n",
 387                                 element_id);
 388
 389                        while (rtlhal->h2c_setinprogress) {
 390                                spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
 391                                                       flag);
 392                                h2c_waitcounter++;
 393                                RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
 394                                         "Wait 100 us (%d times)...\n",
 395                                         h2c_waitcounter);
 396                                udelay(100);
 397
 398                                if (h2c_waitcounter > 1000)
 399                                        return;
 400
 401                                spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
 402                                                  flag);
 403                        }
 404                        spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
 405                } else {
 406                        rtlhal->h2c_setinprogress = true;
 407                        spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
 408                        break;
 409                }
 410        }
 411        while (!bwrite_success) {
 412                wait_writeh2c_limmit--;
 413                if (wait_writeh2c_limmit == 0) {
 414                        RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 415                                 "Write H2C fail because no trigger for FW INT!\n");
 416                        break;
 417                }
 418                boxnum = rtlhal->last_hmeboxnum;
 419                switch (boxnum) {
 420                case 0:
 421                        box_reg = REG_HMEBOX_0;
 422                        box_extreg = REG_HMEBOX_EXT_0;
 423                        break;
 424                case 1:
 425                        box_reg = REG_HMEBOX_1;
 426                        box_extreg = REG_HMEBOX_EXT_1;
 427                        break;
 428                case 2:
 429                        box_reg = REG_HMEBOX_2;
 430                        box_extreg = REG_HMEBOX_EXT_2;
 431                        break;
 432                case 3:
 433                        box_reg = REG_HMEBOX_3;
 434                        box_extreg = REG_HMEBOX_EXT_3;
 435                        break;
 436                default:
 437                        RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 438                                 "switch case not processed\n");
 439                        break;
 440                }
 441                isfw_read = _rtl92d_check_fw_read_last_h2c(hw, boxnum);
 442                while (!isfw_read) {
 443                        wait_h2c_limmit--;
 444                        if (wait_h2c_limmit == 0) {
 445                                RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
 446                                         "Waiting too long for FW read clear HMEBox(%d)!\n",
 447                                         boxnum);
 448                                break;
 449                        }
 450                        udelay(10);
 451                        isfw_read = _rtl92d_check_fw_read_last_h2c(hw, boxnum);
 452                        u1b_tmp = rtl_read_byte(rtlpriv, 0x1BF);
 453                        RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
 454                                 "Waiting for FW read clear HMEBox(%d)!!! 0x1BF = %2x\n",
 455                                 boxnum, u1b_tmp);
 456                }
 457                if (!isfw_read) {
 458                        RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
 459                                 "Write H2C register BOX[%d] fail!!!!! Fw do not read.\n",
 460                                 boxnum);
 461                        break;
 462                }
 463                memset(boxcontent, 0, sizeof(boxcontent));
 464                memset(boxextcontent, 0, sizeof(boxextcontent));
 465                boxcontent[0] = element_id;
 466                RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
 467                         "Write element_id box_reg(%4x) = %2x\n",
 468                         box_reg, element_id);
 469                switch (cmd_len) {
 470                case 1:
 471                        boxcontent[0] &= ~(BIT(7));
 472                        memcpy(boxcontent + 1, cmdbuffer + buf_index, 1);
 473                        for (idx = 0; idx < 4; idx++)
 474                                rtl_write_byte(rtlpriv, box_reg + idx,
 475                                               boxcontent[idx]);
 476                        break;
 477                case 2:
 478                        boxcontent[0] &= ~(BIT(7));
 479                        memcpy(boxcontent + 1, cmdbuffer + buf_index, 2);
 480                        for (idx = 0; idx < 4; idx++)
 481                                rtl_write_byte(rtlpriv, box_reg + idx,
 482                                               boxcontent[idx]);
 483                        break;
 484                case 3:
 485                        boxcontent[0] &= ~(BIT(7));
 486                        memcpy(boxcontent + 1, cmdbuffer + buf_index, 3);
 487                        for (idx = 0; idx < 4; idx++)
 488                                rtl_write_byte(rtlpriv, box_reg + idx,
 489                                               boxcontent[idx]);
 490                        break;
 491                case 4:
 492                        boxcontent[0] |= (BIT(7));
 493                        memcpy(boxextcontent, cmdbuffer + buf_index, 2);
 494                        memcpy(boxcontent + 1, cmdbuffer + buf_index + 2, 2);
 495                        for (idx = 0; idx < 2; idx++)
 496                                rtl_write_byte(rtlpriv, box_extreg + idx,
 497                                               boxextcontent[idx]);
 498                        for (idx = 0; idx < 4; idx++)
 499                                rtl_write_byte(rtlpriv, box_reg + idx,
 500                                               boxcontent[idx]);
 501                        break;
 502                case 5:
 503                        boxcontent[0] |= (BIT(7));
 504                        memcpy(boxextcontent, cmdbuffer + buf_index, 2);
 505                        memcpy(boxcontent + 1, cmdbuffer + buf_index + 2, 3);
 506                        for (idx = 0; idx < 2; idx++)
 507                                rtl_write_byte(rtlpriv, box_extreg + idx,
 508                                               boxextcontent[idx]);
 509                        for (idx = 0; idx < 4; idx++)
 510                                rtl_write_byte(rtlpriv, box_reg + idx,
 511                                               boxcontent[idx]);
 512                        break;
 513                default:
 514                        RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 515                                 "switch case not processed\n");
 516                        break;
 517                }
 518                bwrite_success = true;
 519                rtlhal->last_hmeboxnum = boxnum + 1;
 520                if (rtlhal->last_hmeboxnum == 4)
 521                        rtlhal->last_hmeboxnum = 0;
 522                RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
 523                         "pHalData->last_hmeboxnum  = %d\n",
 524                         rtlhal->last_hmeboxnum);
 525        }
 526        spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
 527        rtlhal->h2c_setinprogress = false;
 528        spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
 529        RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n");
 530}
 531
 532void rtl92d_fill_h2c_cmd(struct ieee80211_hw *hw,
 533                         u8 element_id, u32 cmd_len, u8 *cmdbuffer)
 534{
 535        u32 tmp_cmdbuf[2];
 536
 537        memset(tmp_cmdbuf, 0, 8);
 538        memcpy(tmp_cmdbuf, cmdbuffer, cmd_len);
 539        _rtl92d_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
 540        return;
 541}
 542
 543void rtl92d_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
 544{
 545        struct rtl_priv *rtlpriv = rtl_priv(hw);
 546        u8 u1_h2c_set_pwrmode[3] = { 0 };
 547        struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 548
 549        RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
 550        SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode);
 551        SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, 1);
 552        SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode,
 553                                              ppsc->reg_max_lps_awakeintvl);
 554        RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
 555                      "rtl92d_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode",
 556                      u1_h2c_set_pwrmode, 3);
 557        rtl92d_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode);
 558}
 559
 560static bool _rtl92d_cmd_send_packet(struct ieee80211_hw *hw,
 561                                    struct sk_buff *skb)
 562{
 563        struct rtl_priv *rtlpriv = rtl_priv(hw);
 564        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 565        struct rtl8192_tx_ring *ring;
 566        struct rtl_tx_desc *pdesc;
 567        u8 idx = 0;
 568        unsigned long flags;
 569        struct sk_buff *pskb;
 570
 571        ring = &rtlpci->tx_ring[BEACON_QUEUE];
 572        pskb = __skb_dequeue(&ring->queue);
 573        kfree_skb(pskb);
 574        spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
 575        pdesc = &ring->desc[idx];
 576        /* discard output from call below */
 577        rtlpriv->cfg->ops->get_desc((u8 *) pdesc, true, HW_DESC_OWN);
 578        rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb);
 579        __skb_queue_tail(&ring->queue, skb);
 580        spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
 581        rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
 582        return true;
 583}
 584
 585#define BEACON_PG               0       /*->1 */
 586#define PSPOLL_PG               2
 587#define NULL_PG                 3
 588#define PROBERSP_PG             4       /*->5 */
 589#define TOTAL_RESERVED_PKT_LEN  768
 590
 591static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
 592        /* page 0 beacon */
 593        0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
 594        0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
 595        0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
 596        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 597        0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
 598        0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
 599        0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
 600        0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
 601        0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
 602        0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
 603        0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 604        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 605        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 606        0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
 607        0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 608        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 609
 610        /* page 1 beacon */
 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        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 620        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 621        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 622        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 623        0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
 624        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 625        0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 626        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 627
 628        /* page 2  ps-poll */
 629        0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
 630        0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
 631        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 632        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 633        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 634        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 635        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 636        0x00, 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        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 640        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 641        0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
 642        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
 643        0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 644        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 645
 646        /* page 3  null */
 647        0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
 648        0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
 649        0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 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        0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
 660        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
 661        0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 662        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 663
 664        /* page 4  probe_resp */
 665        0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
 666        0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
 667        0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
 668        0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
 669        0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
 670        0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
 671        0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
 672        0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
 673        0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
 674        0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
 675        0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 676        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 677        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 678        0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
 679        0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 680        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 681
 682        /* page 5  probe_resp */
 683        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 684        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 685        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 686        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 687        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 688        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 689        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 690        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 691        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 692        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 693        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 694        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 695        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 696        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 697        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 698        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 699};
 700
 701void rtl92d_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished)
 702{
 703        struct rtl_priv *rtlpriv = rtl_priv(hw);
 704        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 705        struct sk_buff *skb = NULL;
 706        u32 totalpacketlen;
 707        bool rtstatus;
 708        u8 u1RsvdPageLoc[3] = { 0 };
 709        bool dlok = false;
 710        u8 *beacon;
 711        u8 *p_pspoll;
 712        u8 *nullfunc;
 713        u8 *p_probersp;
 714        /*---------------------------------------------------------
 715                                                (1) beacon
 716        ---------------------------------------------------------*/
 717        beacon = &reserved_page_packet[BEACON_PG * 128];
 718        SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
 719        SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
 720        /*-------------------------------------------------------
 721                                                (2) ps-poll
 722        --------------------------------------------------------*/
 723        p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
 724        SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
 725        SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
 726        SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
 727        SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG);
 728        /*--------------------------------------------------------
 729                                                (3) null data
 730        ---------------------------------------------------------*/
 731        nullfunc = &reserved_page_packet[NULL_PG * 128];
 732        SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
 733        SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
 734        SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
 735        SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1RsvdPageLoc, NULL_PG);
 736        /*---------------------------------------------------------
 737                                                (4) probe response
 738        ----------------------------------------------------------*/
 739        p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
 740        SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
 741        SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
 742        SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
 743        SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PROBERSP_PG);
 744        totalpacketlen = TOTAL_RESERVED_PKT_LEN;
 745        RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
 746                      "rtl92d_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL",
 747                      &reserved_page_packet[0], totalpacketlen);
 748        RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
 749                      "rtl92d_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL",
 750                      u1RsvdPageLoc, 3);
 751        skb = dev_alloc_skb(totalpacketlen);
 752        if (!skb) {
 753                dlok = false;
 754        } else {
 755                memcpy((u8 *) skb_put(skb, totalpacketlen),
 756                        &reserved_page_packet, totalpacketlen);
 757                rtstatus = _rtl92d_cmd_send_packet(hw, skb);
 758
 759                if (rtstatus)
 760                        dlok = true;
 761        }
 762        if (dlok) {
 763                RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
 764                         "Set RSVD page location to Fw\n");
 765                RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
 766                              "H2C_RSVDPAGE", u1RsvdPageLoc, 3);
 767                rtl92d_fill_h2c_cmd(hw, H2C_RSVDPAGE,
 768                        sizeof(u1RsvdPageLoc), u1RsvdPageLoc);
 769        } else
 770                RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
 771                         "Set RSVD page location to Fw FAIL!!!!!!\n");
 772}
 773
 774void rtl92d_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
 775{
 776        u8 u1_joinbssrpt_parm[1] = {0};
 777
 778        SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
 779        rtl92d_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm);
 780}
 781