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 228 return 0; 229 } 230 231 static bool _rtl88e_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum) 232 { 233 struct rtl_priv *rtlpriv = rtl_priv(hw); 234 u8 val_hmetfr; 235 236 val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR); 237 if (((val_hmetfr >> boxnum) & BIT(0)) == 0) 238 return true; 239 return false; 240 } 241 242 static void _rtl88e_fill_h2c_command(struct ieee80211_hw *hw, 243 u8 element_id, u32 cmd_len, 244 u8 *cmd_b) 245 { 246 struct rtl_priv *rtlpriv = rtl_priv(hw); 247 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); 248 u8 boxnum; 249 u16 box_reg = 0, box_extreg = 0; 250 u8 u1b_tmp; 251 bool isfw_read = false; 252 u8 buf_index = 0; 253 bool write_sucess = false; 254 u8 wait_h2c_limmit = 100; 255 u8 wait_writeh2c_limit = 100; 256 u8 boxcontent[4], boxextcontent[4]; 257 u32 h2c_waitcounter = 0; 258 unsigned long flag; 259 u8 idx; 260 261 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n"); 262 263 while (true) { 264 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag); 265 if (rtlhal->h2c_setinprogress) { 266 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, 267 "H2C set in progress! Wait to set..element_id(%d).\n", 268 element_id); 269 270 while (rtlhal->h2c_setinprogress) { 271 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, 272 flag); 273 h2c_waitcounter++; 274 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, 275 "Wait 100 us (%d times)...\n", 276 h2c_waitcounter); 277 udelay(100); 278 279 if (h2c_waitcounter > 1000) 280 return; 281 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, 282 flag); 283 } 284 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); 285 } else { 286 rtlhal->h2c_setinprogress = true; 287 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); 288 break; 289 } 290 } 291 292 while (!write_sucess) { 293 wait_writeh2c_limit--; 294 if (wait_writeh2c_limit == 0) { 295 pr_err("Write H2C fail because no trigger for FW INT!\n"); 296 break; 297 } 298 299 boxnum = rtlhal->last_hmeboxnum; 300 switch (boxnum) { 301 case 0: 302 box_reg = REG_HMEBOX_0; 303 box_extreg = REG_HMEBOX_EXT_0; 304 break; 305 case 1: 306 box_reg = REG_HMEBOX_1; 307 box_extreg = REG_HMEBOX_EXT_1; 308 break; 309 case 2: 310 box_reg = REG_HMEBOX_2; 311 box_extreg = REG_HMEBOX_EXT_2; 312 break; 313 case 3: 314 box_reg = REG_HMEBOX_3; 315 box_extreg = REG_HMEBOX_EXT_3; 316 break; 317 default: 318 RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD, 319 "switch case %#x not processed\n", boxnum); 320 break; 321 } 322 isfw_read = _rtl88e_check_fw_read_last_h2c(hw, boxnum); 323 while (!isfw_read) { 324 wait_h2c_limmit--; 325 if (wait_h2c_limmit == 0) { 326 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, 327 "Waiting too long for FW read clear HMEBox(%d)!\n", 328 boxnum); 329 break; 330 } 331 332 udelay(10); 333 334 isfw_read = _rtl88e_check_fw_read_last_h2c(hw, boxnum); 335 u1b_tmp = rtl_read_byte(rtlpriv, 0x130); 336 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, 337 "Waiting for FW read clear HMEBox(%d)!!! 0x130 = %2x\n", 338 boxnum, u1b_tmp); 339 } 340 341 if (!isfw_read) { 342 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, 343 "Write H2C register BOX[%d] fail!!!!! Fw do not read.\n", 344 boxnum); 345 break; 346 } 347 348 memset(boxcontent, 0, sizeof(boxcontent)); 349 memset(boxextcontent, 0, sizeof(boxextcontent)); 350 boxcontent[0] = element_id; 351 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, 352 "Write element_id box_reg(%4x) = %2x\n", 353 box_reg, element_id); 354 355 switch (cmd_len) { 356 case 1: 357 case 2: 358 case 3: 359 /*boxcontent[0] &= ~(BIT(7));*/ 360 memcpy((u8 *)(boxcontent) + 1, 361 cmd_b + buf_index, cmd_len); 362 363 for (idx = 0; idx < 4; idx++) { 364 rtl_write_byte(rtlpriv, box_reg + idx, 365 boxcontent[idx]); 366 } 367 break; 368 case 4: 369 case 5: 370 case 6: 371 case 7: 372 /*boxcontent[0] |= (BIT(7));*/ 373 memcpy((u8 *)(boxextcontent), 374 cmd_b + buf_index+3, cmd_len-3); 375 memcpy((u8 *)(boxcontent) + 1, 376 cmd_b + buf_index, 3); 377 378 for (idx = 0; idx < 2; idx++) { 379 rtl_write_byte(rtlpriv, box_extreg + idx, 380 boxextcontent[idx]); 381 } 382 383 for (idx = 0; idx < 4; idx++) { 384 rtl_write_byte(rtlpriv, box_reg + idx, 385 boxcontent[idx]); 386 } 387 break; 388 default: 389 RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD, 390 "switch case %#x not processed\n", cmd_len); 391 break; 392 } 393 394 write_sucess = true; 395 396 rtlhal->last_hmeboxnum = boxnum + 1; 397 if (rtlhal->last_hmeboxnum == 4) 398 rtlhal->last_hmeboxnum = 0; 399 400 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, 401 "pHalData->last_hmeboxnum = %d\n", 402 rtlhal->last_hmeboxnum); 403 } 404 405 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag); 406 rtlhal->h2c_setinprogress = false; 407 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); 408 409 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n"); 410 } 411 412 void rtl88e_fill_h2c_cmd(struct ieee80211_hw *hw, 413 u8 element_id, u32 cmd_len, u8 *cmdbuffer) 414 { 415 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); 416 u32 tmp_cmdbuf[2]; 417 418 if (!rtlhal->fw_ready) { 419 WARN_ONCE(true, 420 "rtl8188ee: error H2C cmd because of Fw download fail!!!\n"); 421 return; 422 } 423 424 memset(tmp_cmdbuf, 0, 8); 425 memcpy(tmp_cmdbuf, cmdbuffer, cmd_len); 426 _rtl88e_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf); 427 428 return; 429 } 430 431 void rtl88e_firmware_selfreset(struct ieee80211_hw *hw) 432 { 433 u8 u1b_tmp; 434 struct rtl_priv *rtlpriv = rtl_priv(hw); 435 436 u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN+1); 437 rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN+1, (u1b_tmp & (~BIT(2)))); 438 rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN+1, (u1b_tmp | BIT(2))); 439 RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, 440 "8051Reset88E(): 8051 reset success\n"); 441 442 } 443 444 void rtl88e_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode) 445 { 446 struct rtl_priv *rtlpriv = rtl_priv(hw); 447 u8 u1_h2c_set_pwrmode[H2C_88E_PWEMODE_LENGTH] = { 0 }; 448 struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 449 u8 rlbm, power_state = 0; 450 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode); 451 452 SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, ((mode) ? 1 : 0)); 453 rlbm = 0;/*YJ, temp, 120316. FW now not support RLBM=2.*/ 454 SET_H2CCMD_PWRMODE_PARM_RLBM(u1_h2c_set_pwrmode, rlbm); 455 SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, 456 (rtlpriv->mac80211.p2p) ? ppsc->smart_ps : 1); 457 SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(u1_h2c_set_pwrmode, 458 ppsc->reg_max_lps_awakeintvl); 459 SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(u1_h2c_set_pwrmode, 0); 460 if (mode == FW_PS_ACTIVE_MODE) 461 power_state |= FW_PWR_STATE_ACTIVE; 462 else 463 power_state |= FW_PWR_STATE_RF_OFF; 464 465 SET_H2CCMD_PWRMODE_PARM_PWR_STATE(u1_h2c_set_pwrmode, power_state); 466 467 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, 468 "rtl92c_set_fw_pwrmode(): u1_h2c_set_pwrmode\n", 469 u1_h2c_set_pwrmode, H2C_88E_PWEMODE_LENGTH); 470 rtl88e_fill_h2c_cmd(hw, H2C_88E_SETPWRMODE, 471 H2C_88E_PWEMODE_LENGTH, u1_h2c_set_pwrmode); 472 } 473 474 void rtl88e_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus) 475 { 476 u8 u1_joinbssrpt_parm[1] = { 0 }; 477 478 SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus); 479 480 rtl88e_fill_h2c_cmd(hw, H2C_88E_JOINBSSRPT, 1, u1_joinbssrpt_parm); 481 } 482 483 void rtl88e_set_fw_ap_off_load_cmd(struct ieee80211_hw *hw, 484 u8 ap_offload_enable) 485 { 486 struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); 487 u8 u1_apoffload_parm[H2C_88E_AP_OFFLOAD_LENGTH] = { 0 }; 488 489 SET_H2CCMD_AP_OFFLOAD_ON(u1_apoffload_parm, ap_offload_enable); 490 SET_H2CCMD_AP_OFFLOAD_HIDDEN(u1_apoffload_parm, mac->hiddenssid); 491 SET_H2CCMD_AP_OFFLOAD_DENYANY(u1_apoffload_parm, 0); 492 493 rtl88e_fill_h2c_cmd(hw, H2C_88E_AP_OFFLOAD, 494 H2C_88E_AP_OFFLOAD_LENGTH, u1_apoffload_parm); 495 496 } 497 498 #define BEACON_PG 0 /* ->1 */ 499 #define PSPOLL_PG 2 500 #define NULL_PG 3 501 #define PROBERSP_PG 4 /* ->5 */ 502 503 #define TOTAL_RESERVED_PKT_LEN 768 504 505 static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = { 506 /* page 0 beacon */ 507 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 508 0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42, 509 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08, 510 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 511 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69, 512 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C, 513 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96, 514 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A, 515 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C, 516 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18, 517 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 518 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 519 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 520 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02, 521 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 522 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 523 524 /* page 1 beacon */ 525 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 526 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 527 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 528 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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 0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00, 538 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 539 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 540 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 541 542 /* page 2 ps-poll */ 543 0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10, 544 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42, 545 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 546 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 547 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 548 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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 0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00, 556 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 557 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 558 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 559 560 /* page 3 null */ 561 0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10, 562 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42, 563 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00, 564 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 565 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 566 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 567 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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 0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00, 574 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 575 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 576 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 577 578 /* page 4 probe_resp */ 579 0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10, 580 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42, 581 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00, 582 0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00, 583 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69, 584 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C, 585 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96, 586 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A, 587 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C, 588 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18, 589 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 590 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 591 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 592 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02, 593 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 594 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 595 596 /* page 5 probe_resp */ 597 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 598 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 599 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 600 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 601 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 }; 614 615 void rtl88e_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished) 616 { 617 struct rtl_priv *rtlpriv = rtl_priv(hw); 618 struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); 619 struct sk_buff *skb = NULL; 620 u32 totalpacketlen; 621 bool rtstatus; 622 u8 u1rsvdpageloc[5] = { 0 }; 623 bool b_dlok = false; 624 u8 *beacon; 625 u8 *p_pspoll; 626 u8 *nullfunc; 627 u8 *p_probersp; 628 629 /*--------------------------------------------------------- 630 * (1) beacon 631 *--------------------------------------------------------- 632 */ 633 beacon = &reserved_page_packet[BEACON_PG * 128]; 634 SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr); 635 SET_80211_HDR_ADDRESS3(beacon, mac->bssid); 636 637 /*------------------------------------------------------- 638 * (2) ps-poll 639 *-------------------------------------------------------- 640 */ 641 p_pspoll = &reserved_page_packet[PSPOLL_PG * 128]; 642 SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000)); 643 SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid); 644 SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr); 645 646 SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1rsvdpageloc, PSPOLL_PG); 647 648 /*-------------------------------------------------------- 649 * (3) null data 650 *--------------------------------------------------------- 651 */ 652 nullfunc = &reserved_page_packet[NULL_PG * 128]; 653 SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid); 654 SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr); 655 SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid); 656 657 SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1rsvdpageloc, NULL_PG); 658 659 /*--------------------------------------------------------- 660 * (4) probe response 661 *---------------------------------------------------------- 662 */ 663 p_probersp = &reserved_page_packet[PROBERSP_PG * 128]; 664 SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid); 665 SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr); 666 SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid); 667 668 SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1rsvdpageloc, PROBERSP_PG); 669 670 totalpacketlen = TOTAL_RESERVED_PKT_LEN; 671 672 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD, 673 "rtl88e_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n", 674 &reserved_page_packet[0], totalpacketlen); 675 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, 676 "rtl88e_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n", 677 u1rsvdpageloc, 3); 678 679 skb = dev_alloc_skb(totalpacketlen); 680 memcpy(skb_put(skb, totalpacketlen), 681 &reserved_page_packet, totalpacketlen); 682 683 rtstatus = rtl_cmd_send_packet(hw, skb); 684 685 if (rtstatus) 686 b_dlok = true; 687 688 if (b_dlok) { 689 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, 690 "Set RSVD page location to Fw.\n"); 691 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, 692 "H2C_RSVDPAGE:\n", u1rsvdpageloc, 3); 693 rtl88e_fill_h2c_cmd(hw, H2C_88E_RSVDPAGE, 694 sizeof(u1rsvdpageloc), u1rsvdpageloc); 695 } else 696 RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, 697 "Set RSVD page location to Fw FAIL!!!!!!.\n"); 698 } 699 700 /*Should check FW support p2p or not.*/ 701 static void rtl88e_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw, u8 ctwindow) 702 { 703 u8 u1_ctwindow_period[1] = { ctwindow}; 704 705 rtl88e_fill_h2c_cmd(hw, H2C_88E_P2P_PS_CTW_CMD, 1, u1_ctwindow_period); 706 707 } 708 709 void rtl88e_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state) 710 { 711 struct rtl_priv *rtlpriv = rtl_priv(hw); 712 struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw)); 713 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); 714 struct rtl_p2p_ps_info *p2pinfo = &(rtlps->p2p_ps_info); 715 struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload; 716 u8 i; 717 u16 ctwindow; 718 u32 start_time, tsf_low; 719 720 switch (p2p_ps_state) { 721 case P2P_PS_DISABLE: 722 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_DISABLE\n"); 723 memset(p2p_ps_offload, 0, sizeof(*p2p_ps_offload)); 724 break; 725 case P2P_PS_ENABLE: 726 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_ENABLE\n"); 727 /* update CTWindow value. */ 728 if (p2pinfo->ctwindow > 0) { 729 p2p_ps_offload->ctwindow_en = 1; 730 ctwindow = p2pinfo->ctwindow; 731 rtl88e_set_p2p_ctw_period_cmd(hw, ctwindow); 732 } 733 734 /* hw only support 2 set of NoA */ 735 for (i = 0 ; i < p2pinfo->noa_num; i++) { 736 /* To control the register setting for which NOA*/ 737 rtl_write_byte(rtlpriv, 0x5cf, (i << 4)); 738 if (i == 0) 739 p2p_ps_offload->noa0_en = 1; 740 else 741 p2p_ps_offload->noa1_en = 1; 742 743 /* config P2P NoA Descriptor Register */ 744 rtl_write_dword(rtlpriv, 0x5E0, 745 p2pinfo->noa_duration[i]); 746 rtl_write_dword(rtlpriv, 0x5E4, 747 p2pinfo->noa_interval[i]); 748 749 /*Get Current TSF value */ 750 tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR); 751 752 start_time = p2pinfo->noa_start_time[i]; 753 if (p2pinfo->noa_count_type[i] != 1) { 754 while (start_time <= (tsf_low+(50*1024))) { 755 start_time += p2pinfo->noa_interval[i]; 756 if (p2pinfo->noa_count_type[i] != 255) 757 p2pinfo->noa_count_type[i]--; 758 } 759 } 760 rtl_write_dword(rtlpriv, 0x5E8, start_time); 761 rtl_write_dword(rtlpriv, 0x5EC, 762 p2pinfo->noa_count_type[i]); 763 } 764 765 if ((p2pinfo->opp_ps == 1) || (p2pinfo->noa_num > 0)) { 766 /* rst p2p circuit */ 767 rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, BIT(4)); 768 769 p2p_ps_offload->offload_en = 1; 770 771 if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) { 772 p2p_ps_offload->role = 1; 773 p2p_ps_offload->allstasleep = -1; 774 } else { 775 p2p_ps_offload->role = 0; 776 } 777 778 p2p_ps_offload->discovery = 0; 779 } 780 break; 781 case P2P_PS_SCAN: 782 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN\n"); 783 p2p_ps_offload->discovery = 1; 784 break; 785 case P2P_PS_SCAN_DONE: 786 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN_DONE\n"); 787 p2p_ps_offload->discovery = 0; 788 p2pinfo->p2p_ps_state = P2P_PS_ENABLE; 789 break; 790 default: 791 break; 792 } 793 794 rtl88e_fill_h2c_cmd(hw, H2C_88E_P2P_PS_OFFLOAD, 1, 795 (u8 *)p2p_ps_offload); 796 797 } 798