1 /****************************************************************************** 2 * 3 * Copyright(c) 2009-2013 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 34 static void _rtl88e_enable_fw_download(struct ieee80211_hw *hw, bool enable) 35 { 36 struct rtl_priv *rtlpriv = rtl_priv(hw); 37 u8 tmp; 38 39 if (enable) { 40 tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); 41 rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp | 0x04); 42 43 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL); 44 rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01); 45 46 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2); 47 rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7); 48 } else { 49 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL); 50 rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe); 51 52 rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00); 53 } 54 } 55 56 static void _rtl88e_fw_block_write(struct ieee80211_hw *hw, 57 const u8 *buffer, u32 size) 58 { 59 struct rtl_priv *rtlpriv = rtl_priv(hw); 60 u32 blocksize = sizeof(u32); 61 u8 *bufferptr = (u8 *)buffer; 62 u32 *pu4BytePtr = (u32 *)buffer; 63 u32 i, offset, blockcount, remainsize; 64 65 blockcount = size / blocksize; 66 remainsize = size % blocksize; 67 68 for (i = 0; i < blockcount; i++) { 69 offset = i * blocksize; 70 rtl_write_dword(rtlpriv, (FW_8192C_START_ADDRESS + offset), 71 *(pu4BytePtr + i)); 72 } 73 74 if (remainsize) { 75 offset = blockcount * blocksize; 76 bufferptr += offset; 77 for (i = 0; i < remainsize; i++) { 78 rtl_write_byte(rtlpriv, (FW_8192C_START_ADDRESS + 79 offset + i), *(bufferptr + i)); 80 } 81 } 82 } 83 84 static void _rtl88e_fw_page_write(struct ieee80211_hw *hw, 85 u32 page, const u8 *buffer, u32 size) 86 { 87 struct rtl_priv *rtlpriv = rtl_priv(hw); 88 u8 value8; 89 u8 u8page = (u8) (page & 0x07); 90 91 value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page; 92 93 rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8); 94 _rtl88e_fw_block_write(hw, buffer, size); 95 } 96 97 static void _rtl88e_fill_dummy(u8 *pfwbuf, u32 *pfwlen) 98 { 99 u32 fwlen = *pfwlen; 100 u8 remain = (u8) (fwlen % 4); 101 102 remain = (remain == 0) ? 0 : (4 - remain); 103 104 while (remain > 0) { 105 pfwbuf[fwlen] = 0; 106 fwlen++; 107 remain--; 108 } 109 110 *pfwlen = fwlen; 111 } 112 113 static void _rtl88e_write_fw(struct ieee80211_hw *hw, 114 enum version_8188e version, u8 *buffer, u32 size) 115 { 116 struct rtl_priv *rtlpriv = rtl_priv(hw); 117 u8 *bufferptr = (u8 *)buffer; 118 u32 pagenums, remainsize; 119 u32 page, offset; 120 121 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "FW size is %d bytes,\n", size); 122 123 _rtl88e_fill_dummy(bufferptr, &size); 124 125 pagenums = size / FW_8192C_PAGE_SIZE; 126 remainsize = size % FW_8192C_PAGE_SIZE; 127 128 if (pagenums > 8) 129 pr_err("Page numbers should not greater then 8\n"); 130 131 for (page = 0; page < pagenums; page++) { 132 offset = page * FW_8192C_PAGE_SIZE; 133 _rtl88e_fw_page_write(hw, page, (bufferptr + offset), 134 FW_8192C_PAGE_SIZE); 135 } 136 137 if (remainsize) { 138 offset = pagenums * FW_8192C_PAGE_SIZE; 139 page = pagenums; 140 _rtl88e_fw_page_write(hw, page, (bufferptr + offset), 141 remainsize); 142 } 143 } 144 145 static int _rtl88e_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 pr_err("chksum report fail! REG_MCUFWDL:0x%08x .\n", 159 value32); 160 goto exit; 161 } 162 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL); 163 value32 |= MCUFWDL_RDY; 164 value32 &= ~WINTINI_RDY; 165 rtl_write_dword(rtlpriv, REG_MCUFWDL, value32); 166 167 rtl88e_firmware_selfreset(hw); 168 counter = 0; 169 170 do { 171 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL); 172 if (value32 & WINTINI_RDY) 173 return 0; 174 175 udelay(FW_8192C_POLLING_DELAY); 176 177 } while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT); 178 179 pr_err("Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n", 180 value32); 181 182 exit: 183 return err; 184 } 185 186 int rtl88e_download_fw(struct ieee80211_hw *hw, 187 bool buse_wake_on_wlan_fw) 188 { 189 struct rtl_priv *rtlpriv = rtl_priv(hw); 190 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); 191 struct rtlwifi_firmware_header *pfwheader; 192 u8 *pfwdata; 193 u32 fwsize; 194 int err; 195 enum version_8188e version = rtlhal->version; 196 197 if (!rtlhal->pfirmware) 198 return 1; 199 200 pfwheader = (struct rtlwifi_firmware_header *)rtlhal->pfirmware; 201 pfwdata = rtlhal->pfirmware; 202 fwsize = rtlhal->fwsize; 203 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, 204 "normal Firmware SIZE %d\n", fwsize); 205 206 if (IS_FW_HEADER_EXIST(pfwheader)) { 207 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, 208 "Firmware Version(%d), Signature(%#x), Size(%d)\n", 209 pfwheader->version, pfwheader->signature, 210 (int)sizeof(struct rtlwifi_firmware_header)); 211 212 pfwdata = pfwdata + sizeof(struct rtlwifi_firmware_header); 213 fwsize = fwsize - sizeof(struct rtlwifi_firmware_header); 214 } 215 216 if (rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) { 217 rtl_write_byte(rtlpriv, REG_MCUFWDL, 0); 218 rtl88e_firmware_selfreset(hw); 219 } 220 _rtl88e_enable_fw_download(hw, true); 221 _rtl88e_write_fw(hw, version, pfwdata, fwsize); 222 _rtl88e_enable_fw_download(hw, false); 223 224 err = _rtl88e_fw_free_to_go(hw); 225 if (err) { 226 pr_err("Firmware is not ready to run!\n"); 227 } else { 228 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, 229 "Firmware is ready to run!\n"); 230 } 231 232 return 0; 233 } 234 235 static bool _rtl88e_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum) 236 { 237 struct rtl_priv *rtlpriv = rtl_priv(hw); 238 u8 val_hmetfr; 239 240 val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR); 241 if (((val_hmetfr >> boxnum) & BIT(0)) == 0) 242 return true; 243 return false; 244 } 245 246 static void _rtl88e_fill_h2c_command(struct ieee80211_hw *hw, 247 u8 element_id, u32 cmd_len, 248 u8 *cmd_b) 249 { 250 struct rtl_priv *rtlpriv = rtl_priv(hw); 251 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); 252 u8 boxnum; 253 u16 box_reg = 0, box_extreg = 0; 254 u8 u1b_tmp; 255 bool isfw_read = false; 256 u8 buf_index = 0; 257 bool write_sucess = false; 258 u8 wait_h2c_limmit = 100; 259 u8 wait_writeh2c_limit = 100; 260 u8 boxcontent[4], boxextcontent[4]; 261 u32 h2c_waitcounter = 0; 262 unsigned long flag; 263 u8 idx; 264 265 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n"); 266 267 while (true) { 268 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag); 269 if (rtlhal->h2c_setinprogress) { 270 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, 271 "H2C set in progress! Wait to set..element_id(%d).\n", 272 element_id); 273 274 while (rtlhal->h2c_setinprogress) { 275 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, 276 flag); 277 h2c_waitcounter++; 278 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, 279 "Wait 100 us (%d times)...\n", 280 h2c_waitcounter); 281 udelay(100); 282 283 if (h2c_waitcounter > 1000) 284 return; 285 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, 286 flag); 287 } 288 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); 289 } else { 290 rtlhal->h2c_setinprogress = true; 291 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); 292 break; 293 } 294 } 295 296 while (!write_sucess) { 297 wait_writeh2c_limit--; 298 if (wait_writeh2c_limit == 0) { 299 pr_err("Write H2C fail because no trigger for FW INT!\n"); 300 break; 301 } 302 303 boxnum = rtlhal->last_hmeboxnum; 304 switch (boxnum) { 305 case 0: 306 box_reg = REG_HMEBOX_0; 307 box_extreg = REG_HMEBOX_EXT_0; 308 break; 309 case 1: 310 box_reg = REG_HMEBOX_1; 311 box_extreg = REG_HMEBOX_EXT_1; 312 break; 313 case 2: 314 box_reg = REG_HMEBOX_2; 315 box_extreg = REG_HMEBOX_EXT_2; 316 break; 317 case 3: 318 box_reg = REG_HMEBOX_3; 319 box_extreg = REG_HMEBOX_EXT_3; 320 break; 321 default: 322 RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD, 323 "switch case %#x not processed\n", boxnum); 324 break; 325 } 326 isfw_read = _rtl88e_check_fw_read_last_h2c(hw, boxnum); 327 while (!isfw_read) { 328 wait_h2c_limmit--; 329 if (wait_h2c_limmit == 0) { 330 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, 331 "Waiting too long for FW read clear HMEBox(%d)!\n", 332 boxnum); 333 break; 334 } 335 336 udelay(10); 337 338 isfw_read = _rtl88e_check_fw_read_last_h2c(hw, boxnum); 339 u1b_tmp = rtl_read_byte(rtlpriv, 0x130); 340 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, 341 "Waiting for FW read clear HMEBox(%d)!!! 0x130 = %2x\n", 342 boxnum, u1b_tmp); 343 } 344 345 if (!isfw_read) { 346 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, 347 "Write H2C register BOX[%d] fail!!!!! Fw do not read.\n", 348 boxnum); 349 break; 350 } 351 352 memset(boxcontent, 0, sizeof(boxcontent)); 353 memset(boxextcontent, 0, sizeof(boxextcontent)); 354 boxcontent[0] = element_id; 355 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, 356 "Write element_id box_reg(%4x) = %2x\n", 357 box_reg, element_id); 358 359 switch (cmd_len) { 360 case 1: 361 case 2: 362 case 3: 363 /*boxcontent[0] &= ~(BIT(7));*/ 364 memcpy((u8 *)(boxcontent) + 1, 365 cmd_b + buf_index, cmd_len); 366 367 for (idx = 0; idx < 4; idx++) { 368 rtl_write_byte(rtlpriv, box_reg + idx, 369 boxcontent[idx]); 370 } 371 break; 372 case 4: 373 case 5: 374 case 6: 375 case 7: 376 /*boxcontent[0] |= (BIT(7));*/ 377 memcpy((u8 *)(boxextcontent), 378 cmd_b + buf_index+3, cmd_len-3); 379 memcpy((u8 *)(boxcontent) + 1, 380 cmd_b + buf_index, 3); 381 382 for (idx = 0; idx < 2; idx++) { 383 rtl_write_byte(rtlpriv, box_extreg + idx, 384 boxextcontent[idx]); 385 } 386 387 for (idx = 0; idx < 4; idx++) { 388 rtl_write_byte(rtlpriv, box_reg + idx, 389 boxcontent[idx]); 390 } 391 break; 392 default: 393 RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD, 394 "switch case %#x not processed\n", cmd_len); 395 break; 396 } 397 398 write_sucess = true; 399 400 rtlhal->last_hmeboxnum = boxnum + 1; 401 if (rtlhal->last_hmeboxnum == 4) 402 rtlhal->last_hmeboxnum = 0; 403 404 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, 405 "pHalData->last_hmeboxnum = %d\n", 406 rtlhal->last_hmeboxnum); 407 } 408 409 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag); 410 rtlhal->h2c_setinprogress = false; 411 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); 412 413 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n"); 414 } 415 416 void rtl88e_fill_h2c_cmd(struct ieee80211_hw *hw, 417 u8 element_id, u32 cmd_len, u8 *cmdbuffer) 418 { 419 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); 420 u32 tmp_cmdbuf[2]; 421 422 if (!rtlhal->fw_ready) { 423 WARN_ONCE(true, 424 "rtl8188ee: error H2C cmd because of Fw download fail!!!\n"); 425 return; 426 } 427 428 memset(tmp_cmdbuf, 0, 8); 429 memcpy(tmp_cmdbuf, cmdbuffer, cmd_len); 430 _rtl88e_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf); 431 432 return; 433 } 434 435 void rtl88e_firmware_selfreset(struct ieee80211_hw *hw) 436 { 437 u8 u1b_tmp; 438 struct rtl_priv *rtlpriv = rtl_priv(hw); 439 440 u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN+1); 441 rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN+1, (u1b_tmp & (~BIT(2)))); 442 rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN+1, (u1b_tmp | BIT(2))); 443 RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, 444 "8051Reset88E(): 8051 reset success\n"); 445 446 } 447 448 void rtl88e_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode) 449 { 450 struct rtl_priv *rtlpriv = rtl_priv(hw); 451 u8 u1_h2c_set_pwrmode[H2C_88E_PWEMODE_LENGTH] = { 0 }; 452 struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 453 u8 rlbm, power_state = 0; 454 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode); 455 456 SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, ((mode) ? 1 : 0)); 457 rlbm = 0;/*YJ, temp, 120316. FW now not support RLBM=2.*/ 458 SET_H2CCMD_PWRMODE_PARM_RLBM(u1_h2c_set_pwrmode, rlbm); 459 SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, 460 (rtlpriv->mac80211.p2p) ? ppsc->smart_ps : 1); 461 SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(u1_h2c_set_pwrmode, 462 ppsc->reg_max_lps_awakeintvl); 463 SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(u1_h2c_set_pwrmode, 0); 464 if (mode == FW_PS_ACTIVE_MODE) 465 power_state |= FW_PWR_STATE_ACTIVE; 466 else 467 power_state |= FW_PWR_STATE_RF_OFF; 468 469 SET_H2CCMD_PWRMODE_PARM_PWR_STATE(u1_h2c_set_pwrmode, power_state); 470 471 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, 472 "rtl92c_set_fw_pwrmode(): u1_h2c_set_pwrmode\n", 473 u1_h2c_set_pwrmode, H2C_88E_PWEMODE_LENGTH); 474 rtl88e_fill_h2c_cmd(hw, H2C_88E_SETPWRMODE, 475 H2C_88E_PWEMODE_LENGTH, u1_h2c_set_pwrmode); 476 } 477 478 void rtl88e_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus) 479 { 480 u8 u1_joinbssrpt_parm[1] = { 0 }; 481 482 SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus); 483 484 rtl88e_fill_h2c_cmd(hw, H2C_88E_JOINBSSRPT, 1, u1_joinbssrpt_parm); 485 } 486 487 void rtl88e_set_fw_ap_off_load_cmd(struct ieee80211_hw *hw, 488 u8 ap_offload_enable) 489 { 490 struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); 491 u8 u1_apoffload_parm[H2C_88E_AP_OFFLOAD_LENGTH] = { 0 }; 492 493 SET_H2CCMD_AP_OFFLOAD_ON(u1_apoffload_parm, ap_offload_enable); 494 SET_H2CCMD_AP_OFFLOAD_HIDDEN(u1_apoffload_parm, mac->hiddenssid); 495 SET_H2CCMD_AP_OFFLOAD_DENYANY(u1_apoffload_parm, 0); 496 497 rtl88e_fill_h2c_cmd(hw, H2C_88E_AP_OFFLOAD, 498 H2C_88E_AP_OFFLOAD_LENGTH, u1_apoffload_parm); 499 500 } 501 502 #define BEACON_PG 0 /* ->1 */ 503 #define PSPOLL_PG 2 504 #define NULL_PG 3 505 #define PROBERSP_PG 4 /* ->5 */ 506 507 #define TOTAL_RESERVED_PKT_LEN 768 508 509 static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = { 510 /* page 0 beacon */ 511 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 512 0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42, 513 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08, 514 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 515 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69, 516 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C, 517 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96, 518 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A, 519 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C, 520 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18, 521 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 522 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 523 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 524 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02, 525 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 526 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 527 528 /* page 1 beacon */ 529 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 530 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 531 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 532 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 533 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 534 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 535 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 536 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 537 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 538 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 539 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 540 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 541 0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00, 542 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 543 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 544 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 545 546 /* page 2 ps-poll */ 547 0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10, 548 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42, 549 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 550 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 551 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 552 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 553 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 554 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 555 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 556 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 557 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 558 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 559 0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00, 560 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 561 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 562 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 563 564 /* page 3 null */ 565 0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10, 566 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42, 567 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00, 568 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 569 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 570 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 571 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 572 0x00, 0x00, 0x00, 0x00, 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 0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00, 578 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 579 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 580 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 581 582 /* page 4 probe_resp */ 583 0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10, 584 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42, 585 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00, 586 0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00, 587 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69, 588 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C, 589 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96, 590 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A, 591 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C, 592 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18, 593 0x03, 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 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02, 597 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 598 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 599 600 /* page 5 probe_resp */ 601 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 602 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 603 0x00, 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 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 607 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 608 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 609 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 610 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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 }; 618 619 void rtl88e_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished) 620 { 621 struct rtl_priv *rtlpriv = rtl_priv(hw); 622 struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); 623 struct sk_buff *skb = NULL; 624 u32 totalpacketlen; 625 bool rtstatus; 626 u8 u1rsvdpageloc[5] = { 0 }; 627 bool b_dlok = false; 628 u8 *beacon; 629 u8 *p_pspoll; 630 u8 *nullfunc; 631 u8 *p_probersp; 632 633 /*--------------------------------------------------------- 634 * (1) beacon 635 *--------------------------------------------------------- 636 */ 637 beacon = &reserved_page_packet[BEACON_PG * 128]; 638 SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr); 639 SET_80211_HDR_ADDRESS3(beacon, mac->bssid); 640 641 /*------------------------------------------------------- 642 * (2) ps-poll 643 *-------------------------------------------------------- 644 */ 645 p_pspoll = &reserved_page_packet[PSPOLL_PG * 128]; 646 SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000)); 647 SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid); 648 SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr); 649 650 SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1rsvdpageloc, PSPOLL_PG); 651 652 /*-------------------------------------------------------- 653 * (3) null data 654 *--------------------------------------------------------- 655 */ 656 nullfunc = &reserved_page_packet[NULL_PG * 128]; 657 SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid); 658 SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr); 659 SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid); 660 661 SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1rsvdpageloc, NULL_PG); 662 663 /*--------------------------------------------------------- 664 * (4) probe response 665 *---------------------------------------------------------- 666 */ 667 p_probersp = &reserved_page_packet[PROBERSP_PG * 128]; 668 SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid); 669 SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr); 670 SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid); 671 672 SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1rsvdpageloc, PROBERSP_PG); 673 674 totalpacketlen = TOTAL_RESERVED_PKT_LEN; 675 676 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD, 677 "rtl88e_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n", 678 &reserved_page_packet[0], totalpacketlen); 679 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, 680 "rtl88e_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n", 681 u1rsvdpageloc, 3); 682 683 skb = dev_alloc_skb(totalpacketlen); 684 memcpy(skb_put(skb, totalpacketlen), 685 &reserved_page_packet, totalpacketlen); 686 687 rtstatus = rtl_cmd_send_packet(hw, skb); 688 689 if (rtstatus) 690 b_dlok = true; 691 692 if (b_dlok) { 693 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, 694 "Set RSVD page location to Fw.\n"); 695 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, 696 "H2C_RSVDPAGE:\n", u1rsvdpageloc, 3); 697 rtl88e_fill_h2c_cmd(hw, H2C_88E_RSVDPAGE, 698 sizeof(u1rsvdpageloc), u1rsvdpageloc); 699 } else 700 RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, 701 "Set RSVD page location to Fw FAIL!!!!!!.\n"); 702 } 703 704 /*Should check FW support p2p or not.*/ 705 static void rtl88e_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw, u8 ctwindow) 706 { 707 u8 u1_ctwindow_period[1] = { ctwindow}; 708 709 rtl88e_fill_h2c_cmd(hw, H2C_88E_P2P_PS_CTW_CMD, 1, u1_ctwindow_period); 710 711 } 712 713 void rtl88e_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state) 714 { 715 struct rtl_priv *rtlpriv = rtl_priv(hw); 716 struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw)); 717 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); 718 struct rtl_p2p_ps_info *p2pinfo = &(rtlps->p2p_ps_info); 719 struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload; 720 u8 i; 721 u16 ctwindow; 722 u32 start_time, tsf_low; 723 724 switch (p2p_ps_state) { 725 case P2P_PS_DISABLE: 726 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_DISABLE\n"); 727 memset(p2p_ps_offload, 0, sizeof(*p2p_ps_offload)); 728 break; 729 case P2P_PS_ENABLE: 730 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_ENABLE\n"); 731 /* update CTWindow value. */ 732 if (p2pinfo->ctwindow > 0) { 733 p2p_ps_offload->ctwindow_en = 1; 734 ctwindow = p2pinfo->ctwindow; 735 rtl88e_set_p2p_ctw_period_cmd(hw, ctwindow); 736 } 737 738 /* hw only support 2 set of NoA */ 739 for (i = 0 ; i < p2pinfo->noa_num; i++) { 740 /* To control the register setting for which NOA*/ 741 rtl_write_byte(rtlpriv, 0x5cf, (i << 4)); 742 if (i == 0) 743 p2p_ps_offload->noa0_en = 1; 744 else 745 p2p_ps_offload->noa1_en = 1; 746 747 /* config P2P NoA Descriptor Register */ 748 rtl_write_dword(rtlpriv, 0x5E0, 749 p2pinfo->noa_duration[i]); 750 rtl_write_dword(rtlpriv, 0x5E4, 751 p2pinfo->noa_interval[i]); 752 753 /*Get Current TSF value */ 754 tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR); 755 756 start_time = p2pinfo->noa_start_time[i]; 757 if (p2pinfo->noa_count_type[i] != 1) { 758 while (start_time <= (tsf_low+(50*1024))) { 759 start_time += p2pinfo->noa_interval[i]; 760 if (p2pinfo->noa_count_type[i] != 255) 761 p2pinfo->noa_count_type[i]--; 762 } 763 } 764 rtl_write_dword(rtlpriv, 0x5E8, start_time); 765 rtl_write_dword(rtlpriv, 0x5EC, 766 p2pinfo->noa_count_type[i]); 767 } 768 769 if ((p2pinfo->opp_ps == 1) || (p2pinfo->noa_num > 0)) { 770 /* rst p2p circuit */ 771 rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, BIT(4)); 772 773 p2p_ps_offload->offload_en = 1; 774 775 if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) { 776 p2p_ps_offload->role = 1; 777 p2p_ps_offload->allstasleep = -1; 778 } else { 779 p2p_ps_offload->role = 0; 780 } 781 782 p2p_ps_offload->discovery = 0; 783 } 784 break; 785 case P2P_PS_SCAN: 786 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN\n"); 787 p2p_ps_offload->discovery = 1; 788 break; 789 case P2P_PS_SCAN_DONE: 790 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN_DONE\n"); 791 p2p_ps_offload->discovery = 0; 792 p2pinfo->p2p_ps_state = P2P_PS_ENABLE; 793 break; 794 default: 795 break; 796 } 797 798 rtl88e_fill_h2c_cmd(hw, H2C_88E_P2P_PS_OFFLOAD, 1, 799 (u8 *)p2p_ps_offload); 800 801 } 802