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