linux/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.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 "../rtl8192ce/reg.h"
  34#include "../rtl8192ce/def.h"
  35#include "fw_common.h"
  36#include <linux/export.h>
  37#include <linux/kmemleak.h>
  38
  39static void _rtl92c_enable_fw_download(struct ieee80211_hw *hw, bool enable)
  40{
  41        struct rtl_priv *rtlpriv = rtl_priv(hw);
  42        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
  43
  44        if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CU) {
  45                u32 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
  46                if (enable)
  47                        value32 |= MCUFWDL_EN;
  48                else
  49                        value32 &= ~MCUFWDL_EN;
  50                rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
  51        } else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CE) {
  52                u8 tmp;
  53                if (enable) {
  54
  55                        tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
  56                        rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1,
  57                                       tmp | 0x04);
  58
  59                        tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
  60                        rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01);
  61
  62                        tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
  63                        rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
  64                } else {
  65
  66                        tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
  67                        rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
  68
  69                        rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00);
  70                }
  71        }
  72}
  73
  74static void rtl_block_fw_writeN(struct ieee80211_hw *hw, const u8 *buffer,
  75                                u32 size)
  76{
  77        struct rtl_priv *rtlpriv = rtl_priv(hw);
  78        u32 blockSize = REALTEK_USB_VENQT_MAX_BUF_SIZE - 20;
  79        u8 *bufferPtr = (u8 *) buffer;
  80        u32 i, offset, blockCount, remainSize;
  81
  82        blockCount = size / blockSize;
  83        remainSize = size % blockSize;
  84
  85        for (i = 0; i < blockCount; i++) {
  86                offset = i * blockSize;
  87                rtlpriv->io.writeN_sync(rtlpriv,
  88                                        (FW_8192C_START_ADDRESS + offset),
  89                                        (void *)(bufferPtr + offset),
  90                                        blockSize);
  91        }
  92
  93        if (remainSize) {
  94                offset = blockCount * blockSize;
  95                rtlpriv->io.writeN_sync(rtlpriv,
  96                                        (FW_8192C_START_ADDRESS + offset),
  97                                        (void *)(bufferPtr + offset),
  98                                        remainSize);
  99        }
 100}
 101
 102static void _rtl92c_fw_block_write(struct ieee80211_hw *hw,
 103                                   const u8 *buffer, u32 size)
 104{
 105        struct rtl_priv *rtlpriv = rtl_priv(hw);
 106        u32 blockSize = sizeof(u32);
 107        u8 *bufferPtr = (u8 *) buffer;
 108        u32 *pu4BytePtr = (u32 *) buffer;
 109        u32 i, offset, blockCount, remainSize;
 110        u32 data;
 111
 112        if (rtlpriv->io.writeN_sync) {
 113                rtl_block_fw_writeN(hw, buffer, size);
 114                return;
 115        }
 116        blockCount = size / blockSize;
 117        remainSize = size % blockSize;
 118        if (remainSize) {
 119                /* the last word is < 4 bytes - pad it with zeros */
 120                for (i = 0; i < 4 - remainSize; i++)
 121                        *(bufferPtr + size + i) = 0;
 122                blockCount++;
 123        }
 124
 125        for (i = 0; i < blockCount; i++) {
 126                offset = i * blockSize;
 127                /* for big-endian platforms, the firmware data need to be byte
 128                 * swapped as it was read as a byte string and will be written
 129                 * as 32-bit dwords and byte swapped when written
 130                 */
 131                data = le32_to_cpu(*(__le32 *)(pu4BytePtr + i));
 132                rtl_write_dword(rtlpriv, (FW_8192C_START_ADDRESS + offset),
 133                                data);
 134        }
 135}
 136
 137static void _rtl92c_fw_page_write(struct ieee80211_hw *hw,
 138                                  u32 page, const u8 *buffer, u32 size)
 139{
 140        struct rtl_priv *rtlpriv = rtl_priv(hw);
 141        u8 value8;
 142        u8 u8page = (u8) (page & 0x07);
 143
 144        value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page;
 145
 146        rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8);
 147        _rtl92c_fw_block_write(hw, buffer, size);
 148}
 149
 150static void _rtl92c_fill_dummy(u8 *pfwbuf, u32 *pfwlen)
 151{
 152        u32 fwlen = *pfwlen;
 153        u8 remain = (u8) (fwlen % 4);
 154
 155        remain = (remain == 0) ? 0 : (4 - remain);
 156
 157        while (remain > 0) {
 158                pfwbuf[fwlen] = 0;
 159                fwlen++;
 160                remain--;
 161        }
 162
 163        *pfwlen = fwlen;
 164}
 165
 166static void _rtl92c_write_fw(struct ieee80211_hw *hw,
 167                             enum version_8192c version, u8 *buffer, u32 size)
 168{
 169        struct rtl_priv *rtlpriv = rtl_priv(hw);
 170        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 171        u8 *bufferPtr = buffer;
 172
 173        RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "FW size is %d bytes\n", size);
 174
 175        if (IS_CHIP_VER_B(version)) {
 176                u32 pageNums, remainSize;
 177                u32 page, offset;
 178
 179                if (IS_HARDWARE_TYPE_8192CE(rtlhal))
 180                        _rtl92c_fill_dummy(bufferPtr, &size);
 181
 182                pageNums = size / FW_8192C_PAGE_SIZE;
 183                remainSize = size % FW_8192C_PAGE_SIZE;
 184
 185                if (pageNums > 4) {
 186                        RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 187                                 "Page numbers should not greater then 4\n");
 188                }
 189
 190                for (page = 0; page < pageNums; page++) {
 191                        offset = page * FW_8192C_PAGE_SIZE;
 192                        _rtl92c_fw_page_write(hw, page, (bufferPtr + offset),
 193                                              FW_8192C_PAGE_SIZE);
 194                }
 195
 196                if (remainSize) {
 197                        offset = pageNums * FW_8192C_PAGE_SIZE;
 198                        page = pageNums;
 199                        _rtl92c_fw_page_write(hw, page, (bufferPtr + offset),
 200                                              remainSize);
 201                }
 202        } else {
 203                _rtl92c_fw_block_write(hw, buffer, size);
 204        }
 205}
 206
 207static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw)
 208{
 209        struct rtl_priv *rtlpriv = rtl_priv(hw);
 210        u32 counter = 0;
 211        u32 value32;
 212
 213        do {
 214                value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
 215        } while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) &&
 216                 (!(value32 & FWDL_ChkSum_rpt)));
 217
 218        if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) {
 219                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 220                         "chksum report faill ! REG_MCUFWDL:0x%08x\n", value32);
 221                return -EIO;
 222        }
 223
 224        RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
 225                 "Checksum report OK ! REG_MCUFWDL:0x%08x\n", value32);
 226
 227        value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
 228        value32 |= MCUFWDL_RDY;
 229        value32 &= ~WINTINI_RDY;
 230        rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
 231
 232        counter = 0;
 233
 234        do {
 235                value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
 236                if (value32 & WINTINI_RDY) {
 237                        RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
 238                                 "Polling FW ready success!! REG_MCUFWDL:0x%08x\n",
 239                                 value32);
 240                        return 0;
 241                }
 242
 243                mdelay(FW_8192C_POLLING_DELAY);
 244
 245        } while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT);
 246
 247        RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 248                 "Polling FW ready fail!! REG_MCUFWDL:0x%08x\n", value32);
 249        return -EIO;
 250}
 251
 252int rtl92c_download_fw(struct ieee80211_hw *hw)
 253{
 254        struct rtl_priv *rtlpriv = rtl_priv(hw);
 255        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 256        struct rtl92c_firmware_header *pfwheader;
 257        u8 *pfwdata;
 258        u32 fwsize;
 259        enum version_8192c version = rtlhal->version;
 260
 261        if (rtlpriv->max_fw_size == 0 || !rtlhal->pfirmware)
 262                return 1;
 263
 264        pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware;
 265        pfwdata = rtlhal->pfirmware;
 266        fwsize = rtlhal->fwsize;
 267
 268        if (IS_FW_HEADER_EXIST(pfwheader)) {
 269                RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
 270                         "Firmware Version(%d), Signature(%#x),Size(%d)\n",
 271                         le16_to_cpu(pfwheader->version),
 272                         le16_to_cpu(pfwheader->signature),
 273                         (uint)sizeof(struct rtl92c_firmware_header));
 274
 275                pfwdata = pfwdata + sizeof(struct rtl92c_firmware_header);
 276                fwsize = fwsize - sizeof(struct rtl92c_firmware_header);
 277        }
 278
 279        _rtl92c_enable_fw_download(hw, true);
 280        _rtl92c_write_fw(hw, version, pfwdata, fwsize);
 281        _rtl92c_enable_fw_download(hw, false);
 282
 283        if (_rtl92c_fw_free_to_go(hw)) {
 284                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 285                         "Firmware is not ready to run!\n");
 286        } else {
 287                RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
 288                         "Firmware is ready to run!\n");
 289        }
 290
 291        return 0;
 292}
 293EXPORT_SYMBOL(rtl92c_download_fw);
 294
 295static bool _rtl92c_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
 296{
 297        struct rtl_priv *rtlpriv = rtl_priv(hw);
 298        u8 val_hmetfr, val_mcutst_1;
 299        bool result = false;
 300
 301        val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
 302        val_mcutst_1 = rtl_read_byte(rtlpriv, (REG_MCUTST_1 + boxnum));
 303
 304        if (((val_hmetfr >> boxnum) & BIT(0)) == 0 && val_mcutst_1 == 0)
 305                result = true;
 306        return result;
 307}
 308
 309static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw,
 310                              u8 element_id, u32 cmd_len, u8 *p_cmdbuffer)
 311{
 312        struct rtl_priv *rtlpriv = rtl_priv(hw);
 313        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 314        u8 boxnum;
 315        u16 box_reg = 0, box_extreg = 0;
 316        u8 u1b_tmp;
 317        bool isfw_read = false;
 318        bool bwrite_success = false;
 319        u8 wait_h2c_limmit = 100;
 320        u8 wait_writeh2c_limmit = 100;
 321        u8 boxcontent[4], boxextcontent[2];
 322        u32 h2c_waitcounter = 0;
 323        unsigned long flag;
 324        u8 idx;
 325
 326        RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n");
 327
 328        while (true) {
 329                spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
 330                if (rtlhal->h2c_setinprogress) {
 331                        RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
 332                                 "H2C set in progress! Wait to set..element_id(%d)\n",
 333                                 element_id);
 334
 335                        while (rtlhal->h2c_setinprogress) {
 336                                spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
 337                                                       flag);
 338                                h2c_waitcounter++;
 339                                RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
 340                                         "Wait 100 us (%d times)...\n",
 341                                         h2c_waitcounter);
 342                                udelay(100);
 343
 344                                if (h2c_waitcounter > 1000)
 345                                        return;
 346                                spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
 347                                                  flag);
 348                        }
 349                        spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
 350                } else {
 351                        rtlhal->h2c_setinprogress = true;
 352                        spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
 353                        break;
 354                }
 355        }
 356
 357        while (!bwrite_success) {
 358                wait_writeh2c_limmit--;
 359                if (wait_writeh2c_limmit == 0) {
 360                        RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 361                                 "Write H2C fail because no trigger for FW INT!\n");
 362                        break;
 363                }
 364
 365                boxnum = rtlhal->last_hmeboxnum;
 366                switch (boxnum) {
 367                case 0:
 368                        box_reg = REG_HMEBOX_0;
 369                        box_extreg = REG_HMEBOX_EXT_0;
 370                        break;
 371                case 1:
 372                        box_reg = REG_HMEBOX_1;
 373                        box_extreg = REG_HMEBOX_EXT_1;
 374                        break;
 375                case 2:
 376                        box_reg = REG_HMEBOX_2;
 377                        box_extreg = REG_HMEBOX_EXT_2;
 378                        break;
 379                case 3:
 380                        box_reg = REG_HMEBOX_3;
 381                        box_extreg = REG_HMEBOX_EXT_3;
 382                        break;
 383                default:
 384                        RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 385                                 "switch case not processed\n");
 386                        break;
 387                }
 388
 389                isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum);
 390                while (!isfw_read) {
 391
 392                        wait_h2c_limmit--;
 393                        if (wait_h2c_limmit == 0) {
 394                                RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
 395                                         "Waiting too long for FW read clear HMEBox(%d)!\n",
 396                                         boxnum);
 397                                break;
 398                        }
 399
 400                        udelay(10);
 401
 402                        isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum);
 403                        u1b_tmp = rtl_read_byte(rtlpriv, 0x1BF);
 404                        RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
 405                                 "Waiting for FW read clear HMEBox(%d)!!! 0x1BF = %2x\n",
 406                                 boxnum, u1b_tmp);
 407                }
 408
 409                if (!isfw_read) {
 410                        RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
 411                                 "Write H2C register BOX[%d] fail!!!!! Fw do not read\n",
 412                                 boxnum);
 413                        break;
 414                }
 415
 416                memset(boxcontent, 0, sizeof(boxcontent));
 417                memset(boxextcontent, 0, sizeof(boxextcontent));
 418                boxcontent[0] = element_id;
 419                RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
 420                         "Write element_id box_reg(%4x) = %2x\n",
 421                         box_reg, element_id);
 422
 423                switch (cmd_len) {
 424                case 1:
 425                        boxcontent[0] &= ~(BIT(7));
 426                        memcpy((u8 *) (boxcontent) + 1,
 427                               p_cmdbuffer, 1);
 428
 429                        for (idx = 0; idx < 4; idx++) {
 430                                rtl_write_byte(rtlpriv, box_reg + idx,
 431                                               boxcontent[idx]);
 432                        }
 433                        break;
 434                case 2:
 435                        boxcontent[0] &= ~(BIT(7));
 436                        memcpy((u8 *) (boxcontent) + 1,
 437                               p_cmdbuffer, 2);
 438
 439                        for (idx = 0; idx < 4; idx++) {
 440                                rtl_write_byte(rtlpriv, box_reg + idx,
 441                                               boxcontent[idx]);
 442                        }
 443                        break;
 444                case 3:
 445                        boxcontent[0] &= ~(BIT(7));
 446                        memcpy((u8 *) (boxcontent) + 1,
 447                               p_cmdbuffer, 3);
 448
 449                        for (idx = 0; idx < 4; idx++) {
 450                                rtl_write_byte(rtlpriv, box_reg + idx,
 451                                               boxcontent[idx]);
 452                        }
 453                        break;
 454                case 4:
 455                        boxcontent[0] |= (BIT(7));
 456                        memcpy((u8 *) (boxextcontent),
 457                               p_cmdbuffer, 2);
 458                        memcpy((u8 *) (boxcontent) + 1,
 459                               p_cmdbuffer + 2, 2);
 460
 461                        for (idx = 0; idx < 2; idx++) {
 462                                rtl_write_byte(rtlpriv, box_extreg + idx,
 463                                               boxextcontent[idx]);
 464                        }
 465
 466                        for (idx = 0; idx < 4; idx++) {
 467                                rtl_write_byte(rtlpriv, box_reg + idx,
 468                                               boxcontent[idx]);
 469                        }
 470                        break;
 471                case 5:
 472                        boxcontent[0] |= (BIT(7));
 473                        memcpy((u8 *) (boxextcontent),
 474                               p_cmdbuffer, 2);
 475                        memcpy((u8 *) (boxcontent) + 1,
 476                               p_cmdbuffer + 2, 3);
 477
 478                        for (idx = 0; idx < 2; idx++) {
 479                                rtl_write_byte(rtlpriv, box_extreg + idx,
 480                                               boxextcontent[idx]);
 481                        }
 482
 483                        for (idx = 0; idx < 4; idx++) {
 484                                rtl_write_byte(rtlpriv, box_reg + idx,
 485                                               boxcontent[idx]);
 486                        }
 487                        break;
 488                default:
 489                        RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 490                                 "switch case not processed\n");
 491                        break;
 492                }
 493
 494                bwrite_success = true;
 495
 496                rtlhal->last_hmeboxnum = boxnum + 1;
 497                if (rtlhal->last_hmeboxnum == 4)
 498                        rtlhal->last_hmeboxnum = 0;
 499
 500                RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
 501                         "pHalData->last_hmeboxnum  = %d\n",
 502                         rtlhal->last_hmeboxnum);
 503        }
 504
 505        spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
 506        rtlhal->h2c_setinprogress = false;
 507        spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
 508
 509        RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n");
 510}
 511
 512void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw,
 513                         u8 element_id, u32 cmd_len, u8 *p_cmdbuffer)
 514{
 515        u32 tmp_cmdbuf[2];
 516
 517        memset(tmp_cmdbuf, 0, 8);
 518        memcpy(tmp_cmdbuf, p_cmdbuffer, cmd_len);
 519        _rtl92c_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
 520
 521        return;
 522}
 523EXPORT_SYMBOL(rtl92c_fill_h2c_cmd);
 524
 525void rtl92c_firmware_selfreset(struct ieee80211_hw *hw)
 526{
 527        u8 u1b_tmp;
 528        u8 delay = 100;
 529        struct rtl_priv *rtlpriv = rtl_priv(hw);
 530
 531        rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20);
 532        u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
 533
 534        while (u1b_tmp & BIT(2)) {
 535                delay--;
 536                if (delay == 0) {
 537                        RT_ASSERT(false, "8051 reset fail\n");
 538                        break;
 539                }
 540                udelay(50);
 541                u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
 542        }
 543}
 544EXPORT_SYMBOL(rtl92c_firmware_selfreset);
 545
 546void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
 547{
 548        struct rtl_priv *rtlpriv = rtl_priv(hw);
 549        u8 u1_h2c_set_pwrmode[3] = {0};
 550        struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 551
 552        RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
 553
 554        SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode);
 555        SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode,
 556                                         (rtlpriv->mac80211.p2p) ?
 557                                         ppsc->smart_ps : 1);
 558        SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode,
 559                                              ppsc->reg_max_lps_awakeintvl);
 560
 561        RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
 562                      "rtl92c_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode",
 563                      u1_h2c_set_pwrmode, 3);
 564        rtl92c_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode);
 565
 566}
 567EXPORT_SYMBOL(rtl92c_set_fw_pwrmode_cmd);
 568
 569static bool _rtl92c_cmd_send_packet(struct ieee80211_hw *hw,
 570                                struct sk_buff *skb)
 571{
 572        struct rtl_priv *rtlpriv = rtl_priv(hw);
 573        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 574        struct rtl8192_tx_ring *ring;
 575        struct rtl_tx_desc *pdesc;
 576        unsigned long flags;
 577        struct sk_buff *pskb = NULL;
 578
 579        ring = &rtlpci->tx_ring[BEACON_QUEUE];
 580
 581        pskb = __skb_dequeue(&ring->queue);
 582        kfree_skb(pskb);
 583
 584        spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
 585
 586        pdesc = &ring->desc[0];
 587
 588        rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb);
 589
 590        __skb_queue_tail(&ring->queue, skb);
 591
 592        spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
 593
 594        rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
 595
 596        return true;
 597}
 598
 599#define BEACON_PG               0 /*->1*/
 600#define PSPOLL_PG               2
 601#define NULL_PG                 3
 602#define PROBERSP_PG             4 /*->5*/
 603
 604#define TOTAL_RESERVED_PKT_LEN  768
 605
 606static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
 607        /* page 0 beacon */
 608        0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
 609        0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
 610        0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
 611        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 612        0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
 613        0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
 614        0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
 615        0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
 616        0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
 617        0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
 618        0x03, 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        0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
 622        0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 623        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 624
 625        /* page 1 beacon */
 626        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 627        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 628        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 629        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 630        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 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        0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
 639        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 640        0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 641        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 642
 643        /* page 2  ps-poll */
 644        0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
 645        0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
 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        0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
 657        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
 658        0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 659        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 660
 661        /* page 3  null */
 662        0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
 663        0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
 664        0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
 665        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 666        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 667        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 668        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 669        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 670        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 671        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 672        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 673        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 674        0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
 675        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
 676        0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 677        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 678
 679        /* page 4  probe_resp */
 680        0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
 681        0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
 682        0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
 683        0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
 684        0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
 685        0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
 686        0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
 687        0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
 688        0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
 689        0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
 690        0x03, 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        0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
 694        0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 695        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 696
 697        /* page 5  probe_resp */
 698        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 699        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 700        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 701        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 702        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 703        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 704        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 705        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 706        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 707        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 708        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 709        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 710        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 711        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 712        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 713        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 714};
 715
 716void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished)
 717{
 718        struct rtl_priv *rtlpriv = rtl_priv(hw);
 719        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 720        struct sk_buff *skb = NULL;
 721
 722        u32 totalpacketlen;
 723        bool rtstatus;
 724        u8 u1RsvdPageLoc[3] = {0};
 725        bool dlok = false;
 726
 727        u8 *beacon;
 728        u8 *pspoll;
 729        u8 *nullfunc;
 730        u8 *probersp;
 731        /*---------------------------------------------------------
 732                                (1) beacon
 733        ---------------------------------------------------------*/
 734        beacon = &reserved_page_packet[BEACON_PG * 128];
 735        SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
 736        SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
 737
 738        /*-------------------------------------------------------
 739                                (2) ps-poll
 740        --------------------------------------------------------*/
 741        pspoll = &reserved_page_packet[PSPOLL_PG * 128];
 742        SET_80211_PS_POLL_AID(pspoll, (mac->assoc_id | 0xc000));
 743        SET_80211_PS_POLL_BSSID(pspoll, mac->bssid);
 744        SET_80211_PS_POLL_TA(pspoll, mac->mac_addr);
 745
 746        SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG);
 747
 748        /*--------------------------------------------------------
 749                                (3) null data
 750        ---------------------------------------------------------*/
 751        nullfunc = &reserved_page_packet[NULL_PG * 128];
 752        SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
 753        SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
 754        SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
 755
 756        SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1RsvdPageLoc, NULL_PG);
 757
 758        /*---------------------------------------------------------
 759                                (4) probe response
 760        ----------------------------------------------------------*/
 761        probersp = &reserved_page_packet[PROBERSP_PG * 128];
 762        SET_80211_HDR_ADDRESS1(probersp, mac->bssid);
 763        SET_80211_HDR_ADDRESS2(probersp, mac->mac_addr);
 764        SET_80211_HDR_ADDRESS3(probersp, mac->bssid);
 765
 766        SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PROBERSP_PG);
 767
 768        totalpacketlen = TOTAL_RESERVED_PKT_LEN;
 769
 770        RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
 771                      "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL",
 772                      &reserved_page_packet[0], totalpacketlen);
 773        RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
 774                      "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL",
 775                      u1RsvdPageLoc, 3);
 776
 777
 778        skb = dev_alloc_skb(totalpacketlen);
 779        if (!skb)
 780                return;
 781        kmemleak_not_leak(skb);
 782
 783        memcpy((u8 *) skb_put(skb, totalpacketlen),
 784               &reserved_page_packet, totalpacketlen);
 785
 786        rtstatus = _rtl92c_cmd_send_packet(hw, skb);
 787
 788        if (rtstatus)
 789                dlok = true;
 790
 791        if (dlok) {
 792                RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
 793                         "Set RSVD page location to Fw\n");
 794                RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
 795                              "H2C_RSVDPAGE", u1RsvdPageLoc, 3);
 796                rtl92c_fill_h2c_cmd(hw, H2C_RSVDPAGE,
 797                                    sizeof(u1RsvdPageLoc), u1RsvdPageLoc);
 798        } else
 799                RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
 800                         "Set RSVD page location to Fw FAIL!!!!!!\n");
 801}
 802EXPORT_SYMBOL(rtl92c_set_fw_rsvdpagepkt);
 803
 804void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
 805{
 806        u8 u1_joinbssrpt_parm[1] = {0};
 807
 808        SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
 809
 810        rtl92c_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm);
 811}
 812EXPORT_SYMBOL(rtl92c_set_fw_joinbss_report_cmd);
 813
 814static void rtl92c_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw, u8 ctwindow)
 815{
 816        u8 u1_ctwindow_period[1] = {ctwindow};
 817
 818        rtl92c_fill_h2c_cmd(hw, H2C_P2P_PS_CTW_CMD, 1, u1_ctwindow_period);
 819}
 820
 821void rtl92c_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
 822{
 823        struct rtl_priv *rtlpriv = rtl_priv(hw);
 824        struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
 825        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 826        struct rtl_p2p_ps_info *p2pinfo = &(rtlps->p2p_ps_info);
 827        struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload;
 828        u8      i;
 829        u16     ctwindow;
 830        u32     start_time, tsf_low;
 831
 832        switch (p2p_ps_state) {
 833        case P2P_PS_DISABLE:
 834                RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_DISABLE\n");
 835                memset(p2p_ps_offload, 0, sizeof(struct p2p_ps_offload_t));
 836                break;
 837        case P2P_PS_ENABLE:
 838                RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_ENABLE\n");
 839                /* update CTWindow value. */
 840                if (p2pinfo->ctwindow > 0) {
 841                        p2p_ps_offload->ctwindow_en = 1;
 842                        ctwindow = p2pinfo->ctwindow;
 843                        rtl92c_set_p2p_ctw_period_cmd(hw, ctwindow);
 844                }
 845                /* hw only support 2 set of NoA */
 846                for (i = 0; i < p2pinfo->noa_num; i++) {
 847                        /* To control the register setting for which NOA*/
 848                        rtl_write_byte(rtlpriv, 0x5cf, (i << 4));
 849                        if (i == 0)
 850                                p2p_ps_offload->noa0_en = 1;
 851                        else
 852                                p2p_ps_offload->noa1_en = 1;
 853
 854                        /* config P2P NoA Descriptor Register */
 855                        rtl_write_dword(rtlpriv, 0x5E0,
 856                                        p2pinfo->noa_duration[i]);
 857                        rtl_write_dword(rtlpriv, 0x5E4,
 858                                        p2pinfo->noa_interval[i]);
 859
 860                        /*Get Current TSF value */
 861                        tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
 862
 863                        start_time = p2pinfo->noa_start_time[i];
 864                        if (p2pinfo->noa_count_type[i] != 1) {
 865                                while (start_time <= (tsf_low+(50*1024))) {
 866                                        start_time += p2pinfo->noa_interval[i];
 867                                        if (p2pinfo->noa_count_type[i] != 255)
 868                                                p2pinfo->noa_count_type[i]--;
 869                                }
 870                        }
 871                        rtl_write_dword(rtlpriv, 0x5E8, start_time);
 872                        rtl_write_dword(rtlpriv, 0x5EC,
 873                                        p2pinfo->noa_count_type[i]);
 874                }
 875
 876                if ((p2pinfo->opp_ps == 1) || (p2pinfo->noa_num > 0)) {
 877                        /* rst p2p circuit */
 878                        rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, BIT(4));
 879
 880                        p2p_ps_offload->offload_en = 1;
 881
 882                        if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) {
 883                                p2p_ps_offload->role = 1;
 884                                p2p_ps_offload->allstasleep = 0;
 885                        } else {
 886                                p2p_ps_offload->role = 0;
 887                        }
 888
 889                        p2p_ps_offload->discovery = 0;
 890                }
 891                break;
 892        case P2P_PS_SCAN:
 893                RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN\n");
 894                p2p_ps_offload->discovery = 1;
 895                break;
 896        case P2P_PS_SCAN_DONE:
 897                RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN_DONE\n");
 898                p2p_ps_offload->discovery = 0;
 899                p2pinfo->p2p_ps_state = P2P_PS_ENABLE;
 900                break;
 901        default:
 902                break;
 903        }
 904
 905        rtl92c_fill_h2c_cmd(hw, H2C_P2P_PS_OFFLOAD, 1, (u8 *)p2p_ps_offload);
 906}
 907EXPORT_SYMBOL_GPL(rtl92c_set_p2p_ps_offload_cmd);
 908