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