1 /****************************************************************************** 2 * 3 * Copyright(c) 2009-2012 Realtek Corporation. 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of version 2 of the GNU General Public License as 7 * published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 * more details. 13 * 14 * 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 "../rtl8192ce/reg.h" 32 #include "../rtl8192ce/def.h" 33 #include "fw_common.h" 34 #include <linux/export.h> 35 #include <linux/kmemleak.h> 36 37 static void _rtl92c_enable_fw_download(struct ieee80211_hw *hw, bool enable) 38 { 39 struct rtl_priv *rtlpriv = rtl_priv(hw); 40 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); 41 42 if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CU) { 43 u32 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL); 44 if (enable) 45 value32 |= MCUFWDL_EN; 46 else 47 value32 &= ~MCUFWDL_EN; 48 rtl_write_dword(rtlpriv, REG_MCUFWDL, value32); 49 } else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CE) { 50 u8 tmp; 51 if (enable) { 52 53 tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); 54 rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, 55 tmp | 0x04); 56 57 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL); 58 rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01); 59 60 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2); 61 rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7); 62 } else { 63 64 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL); 65 rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe); 66 67 rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00); 68 } 69 } 70 } 71 72 static void _rtl92c_write_fw(struct ieee80211_hw *hw, 73 enum version_8192c version, u8 *buffer, u32 size) 74 { 75 struct rtl_priv *rtlpriv = rtl_priv(hw); 76 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); 77 bool is_version_b; 78 u8 *bufferptr = (u8 *)buffer; 79 80 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "FW size is %d bytes,\n", size); 81 is_version_b = IS_NORMAL_CHIP(version); 82 if (is_version_b) { 83 u32 pageNums, remainsize; 84 u32 page, offset; 85 86 if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CE) 87 rtl_fill_dummy(bufferptr, &size); 88 89 pageNums = size / FW_8192C_PAGE_SIZE; 90 remainsize = size % FW_8192C_PAGE_SIZE; 91 92 if (pageNums > 4) 93 pr_err("Page numbers should not greater then 4\n"); 94 95 for (page = 0; page < pageNums; page++) { 96 offset = page * FW_8192C_PAGE_SIZE; 97 rtl_fw_page_write(hw, page, (bufferptr + offset), 98 FW_8192C_PAGE_SIZE); 99 } 100 101 if (remainsize) { 102 offset = pageNums * FW_8192C_PAGE_SIZE; 103 page = pageNums; 104 rtl_fw_page_write(hw, page, (bufferptr + offset), 105 remainsize); 106 } 107 } else { 108 rtl_fw_block_write(hw, buffer, size); 109 } 110 } 111 112 static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw) 113 { 114 struct rtl_priv *rtlpriv = rtl_priv(hw); 115 int err = -EIO; 116 u32 counter = 0; 117 u32 value32; 118 119 do { 120 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL); 121 } while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) && 122 (!(value32 & FWDL_ChkSum_rpt))); 123 124 if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) { 125 pr_err("chksum report fail! REG_MCUFWDL:0x%08x .\n", 126 value32); 127 goto exit; 128 } 129 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL); 130 value32 |= MCUFWDL_RDY; 131 value32 &= ~WINTINI_RDY; 132 rtl_write_dword(rtlpriv, REG_MCUFWDL, value32); 133 134 counter = 0; 135 136 do { 137 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL); 138 if (value32 & WINTINI_RDY) 139 return 0; 140 141 mdelay(FW_8192C_POLLING_DELAY); 142 143 } while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT); 144 145 pr_err("Polling FW ready fail! REG_MCUFWDL:0x%08x.\n", 146 value32); 147 148 exit: 149 return err; 150 } 151 152 int rtl92c_download_fw(struct ieee80211_hw *hw) 153 { 154 struct rtl_priv *rtlpriv = rtl_priv(hw); 155 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); 156 struct rtlwifi_firmware_header *pfwheader; 157 u8 *pfwdata; 158 u32 fwsize; 159 int err; 160 enum version_8192c version = rtlhal->version; 161 162 if (!rtlhal->pfirmware) 163 return 1; 164 165 pfwheader = (struct rtlwifi_firmware_header *)rtlhal->pfirmware; 166 pfwdata = (u8 *)rtlhal->pfirmware; 167 fwsize = rtlhal->fwsize; 168 if (IS_FW_HEADER_EXIST(pfwheader)) { 169 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, 170 "Firmware Version(%d), Signature(%#x),Size(%d)\n", 171 pfwheader->version, pfwheader->signature, 172 (int)sizeof(struct rtlwifi_firmware_header)); 173 174 rtlhal->fw_version = le16_to_cpu(pfwheader->version); 175 rtlhal->fw_subversion = pfwheader->subversion; 176 pfwdata = pfwdata + sizeof(struct rtlwifi_firmware_header); 177 fwsize = fwsize - sizeof(struct rtlwifi_firmware_header); 178 } 179 180 _rtl92c_enable_fw_download(hw, true); 181 _rtl92c_write_fw(hw, version, pfwdata, fwsize); 182 _rtl92c_enable_fw_download(hw, false); 183 184 err = _rtl92c_fw_free_to_go(hw); 185 if (err) 186 pr_err("Firmware is not ready to run!\n"); 187 188 return 0; 189 } 190 EXPORT_SYMBOL(rtl92c_download_fw); 191 192 static bool _rtl92c_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum) 193 { 194 struct rtl_priv *rtlpriv = rtl_priv(hw); 195 u8 val_hmetfr, val_mcutst_1; 196 bool result = false; 197 198 val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR); 199 val_mcutst_1 = rtl_read_byte(rtlpriv, (REG_MCUTST_1 + boxnum)); 200 201 if (((val_hmetfr >> boxnum) & BIT(0)) == 0 && val_mcutst_1 == 0) 202 result = true; 203 return result; 204 } 205 206 static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw, 207 u8 element_id, u32 cmd_len, u8 *cmdbuffer) 208 { 209 struct rtl_priv *rtlpriv = rtl_priv(hw); 210 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); 211 u8 boxnum; 212 u16 box_reg = 0, box_extreg = 0; 213 u8 u1b_tmp; 214 bool isfw_read = false; 215 u8 buf_index = 0; 216 bool bwrite_sucess = false; 217 u8 wait_h2c_limmit = 100; 218 u8 wait_writeh2c_limmit = 100; 219 u8 boxcontent[4], boxextcontent[2]; 220 u32 h2c_waitcounter = 0; 221 unsigned long flag; 222 u8 idx; 223 224 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n"); 225 226 while (true) { 227 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag); 228 if (rtlhal->h2c_setinprogress) { 229 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, 230 "H2C set in progress! Wait to set..element_id(%d).\n", 231 element_id); 232 while (rtlhal->h2c_setinprogress) { 233 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, 234 flag); 235 h2c_waitcounter++; 236 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, 237 "Wait 100 us (%d times)...\n", 238 h2c_waitcounter); 239 udelay(100); 240 241 if (h2c_waitcounter > 1000) 242 return; 243 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, 244 flag); 245 } 246 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); 247 } else { 248 rtlhal->h2c_setinprogress = true; 249 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); 250 break; 251 } 252 } 253 254 while (!bwrite_sucess) { 255 wait_writeh2c_limmit--; 256 if (wait_writeh2c_limmit == 0) { 257 pr_err("Write H2C fail because no trigger for FW INT!\n"); 258 break; 259 } 260 261 boxnum = rtlhal->last_hmeboxnum; 262 switch (boxnum) { 263 case 0: 264 box_reg = REG_HMEBOX_0; 265 box_extreg = REG_HMEBOX_EXT_0; 266 break; 267 case 1: 268 box_reg = REG_HMEBOX_1; 269 box_extreg = REG_HMEBOX_EXT_1; 270 break; 271 case 2: 272 box_reg = REG_HMEBOX_2; 273 box_extreg = REG_HMEBOX_EXT_2; 274 break; 275 case 3: 276 box_reg = REG_HMEBOX_3; 277 box_extreg = REG_HMEBOX_EXT_3; 278 break; 279 default: 280 RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD, 281 "switch case %#x not processed\n", boxnum); 282 break; 283 } 284 285 isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum); 286 while (!isfw_read) { 287 wait_h2c_limmit--; 288 if (wait_h2c_limmit == 0) { 289 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, 290 "Waiting too long for FW read clear HMEBox(%d)!\n", 291 boxnum); 292 break; 293 } 294 295 udelay(10); 296 297 isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum); 298 u1b_tmp = rtl_read_byte(rtlpriv, 0x1BF); 299 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, 300 "Waiting for FW read clear HMEBox(%d)!!! 0x1BF = %2x\n", 301 boxnum, u1b_tmp); 302 } 303 304 if (!isfw_read) { 305 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, 306 "Write H2C register BOX[%d] fail!!!!! Fw do not read.\n", 307 boxnum); 308 break; 309 } 310 311 memset(boxcontent, 0, sizeof(boxcontent)); 312 memset(boxextcontent, 0, sizeof(boxextcontent)); 313 boxcontent[0] = element_id; 314 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, 315 "Write element_id box_reg(%4x) = %2x\n", 316 box_reg, element_id); 317 318 switch (cmd_len) { 319 case 1: 320 boxcontent[0] &= ~(BIT(7)); 321 memcpy((u8 *)(boxcontent) + 1, 322 cmdbuffer + buf_index, 1); 323 324 for (idx = 0; idx < 4; idx++) { 325 rtl_write_byte(rtlpriv, box_reg + idx, 326 boxcontent[idx]); 327 } 328 break; 329 case 2: 330 boxcontent[0] &= ~(BIT(7)); 331 memcpy((u8 *)(boxcontent) + 1, 332 cmdbuffer + buf_index, 2); 333 334 for (idx = 0; idx < 4; idx++) { 335 rtl_write_byte(rtlpriv, box_reg + idx, 336 boxcontent[idx]); 337 } 338 break; 339 case 3: 340 boxcontent[0] &= ~(BIT(7)); 341 memcpy((u8 *)(boxcontent) + 1, 342 cmdbuffer + buf_index, 3); 343 344 for (idx = 0; idx < 4; idx++) { 345 rtl_write_byte(rtlpriv, box_reg + idx, 346 boxcontent[idx]); 347 } 348 break; 349 case 4: 350 boxcontent[0] |= (BIT(7)); 351 memcpy((u8 *)(boxextcontent), 352 cmdbuffer + buf_index, 2); 353 memcpy((u8 *)(boxcontent) + 1, 354 cmdbuffer + buf_index + 2, 2); 355 356 for (idx = 0; idx < 2; idx++) { 357 rtl_write_byte(rtlpriv, box_extreg + idx, 358 boxextcontent[idx]); 359 } 360 361 for (idx = 0; idx < 4; idx++) { 362 rtl_write_byte(rtlpriv, box_reg + idx, 363 boxcontent[idx]); 364 } 365 break; 366 case 5: 367 boxcontent[0] |= (BIT(7)); 368 memcpy((u8 *)(boxextcontent), 369 cmdbuffer + buf_index, 2); 370 memcpy((u8 *)(boxcontent) + 1, 371 cmdbuffer + buf_index + 2, 3); 372 373 for (idx = 0; idx < 2; idx++) { 374 rtl_write_byte(rtlpriv, box_extreg + idx, 375 boxextcontent[idx]); 376 } 377 378 for (idx = 0; idx < 4; idx++) { 379 rtl_write_byte(rtlpriv, box_reg + idx, 380 boxcontent[idx]); 381 } 382 break; 383 default: 384 RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD, 385 "switch case %#x not processed\n", cmd_len); 386 break; 387 } 388 389 bwrite_sucess = true; 390 391 rtlhal->last_hmeboxnum = boxnum + 1; 392 if (rtlhal->last_hmeboxnum == 4) 393 rtlhal->last_hmeboxnum = 0; 394 395 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, 396 "pHalData->last_hmeboxnum = %d\n", 397 rtlhal->last_hmeboxnum); 398 } 399 400 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag); 401 rtlhal->h2c_setinprogress = false; 402 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); 403 404 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n"); 405 } 406 407 void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw, 408 u8 element_id, u32 cmd_len, u8 *cmdbuffer) 409 { 410 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); 411 u32 tmp_cmdbuf[2]; 412 413 if (!rtlhal->fw_ready) { 414 WARN_ONCE(true, 415 "rtl8192c-common: return H2C cmd because of Fw download fail!!!\n"); 416 return; 417 } 418 419 memset(tmp_cmdbuf, 0, 8); 420 memcpy(tmp_cmdbuf, cmdbuffer, cmd_len); 421 _rtl92c_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf); 422 423 return; 424 } 425 EXPORT_SYMBOL(rtl92c_fill_h2c_cmd); 426 427 void rtl92c_firmware_selfreset(struct ieee80211_hw *hw) 428 { 429 u8 u1b_tmp; 430 u8 delay = 100; 431 struct rtl_priv *rtlpriv = rtl_priv(hw); 432 433 rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20); 434 u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); 435 436 while (u1b_tmp & BIT(2)) { 437 delay--; 438 if (delay == 0) { 439 WARN_ONCE(true, "rtl8192c-common: 8051 reset fail.\n"); 440 break; 441 } 442 udelay(50); 443 u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); 444 } 445 } 446 EXPORT_SYMBOL(rtl92c_firmware_selfreset); 447 448 void rtl92c_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[3] = { 0 }; 452 struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 453 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); 457 SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, 458 (rtlpriv->mac80211.p2p) ? ppsc->smart_ps : 1); 459 SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode, 460 ppsc->reg_max_lps_awakeintvl); 461 462 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, 463 "rtl92c_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode\n", 464 u1_h2c_set_pwrmode, 3); 465 rtl92c_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode); 466 } 467 EXPORT_SYMBOL(rtl92c_set_fw_pwrmode_cmd); 468 469 #define BEACON_PG 0 /*->1*/ 470 #define PSPOLL_PG 2 471 #define NULL_PG 3 472 #define PROBERSP_PG 4 /*->5*/ 473 474 #define TOTAL_RESERVED_PKT_LEN 768 475 476 static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = { 477 /* page 0 beacon */ 478 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 479 0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42, 480 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08, 481 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 482 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69, 483 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C, 484 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96, 485 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A, 486 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C, 487 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18, 488 0x03, 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 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02, 492 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 493 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 494 495 /* page 1 beacon */ 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 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 501 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 502 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 503 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 504 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 505 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 506 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 507 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 508 0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00, 509 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 510 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 511 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 512 513 /* page 2 ps-poll */ 514 0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10, 515 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42, 516 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 517 0x00, 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 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 521 0x00, 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 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 525 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 526 0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00, 527 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 528 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 529 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 530 531 /* page 3 null */ 532 0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10, 533 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42, 534 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 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 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 0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00, 545 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 546 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 547 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 548 549 /* page 4 probe_resp */ 550 0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10, 551 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42, 552 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00, 553 0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00, 554 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69, 555 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C, 556 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96, 557 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A, 558 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C, 559 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18, 560 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 561 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 562 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 563 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02, 564 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 565 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 566 567 /* page 5 probe_resp */ 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 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 578 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 579 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 580 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 581 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 582 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 583 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 584 }; 585 586 void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, 587 bool (*cmd_send_packet)(struct ieee80211_hw *, struct sk_buff *)) 588 { 589 struct rtl_priv *rtlpriv = rtl_priv(hw); 590 struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); 591 struct sk_buff *skb = NULL; 592 593 u32 totalpacketlen; 594 bool rtstatus; 595 u8 u1rsvdpageloc[3] = { 0 }; 596 bool b_dlok = false; 597 598 u8 *beacon; 599 u8 *p_pspoll; 600 u8 *nullfunc; 601 u8 *p_probersp; 602 /*--------------------------------------------------------- 603 (1) beacon 604 ---------------------------------------------------------*/ 605 beacon = &reserved_page_packet[BEACON_PG * 128]; 606 SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr); 607 SET_80211_HDR_ADDRESS3(beacon, mac->bssid); 608 609 /*------------------------------------------------------- 610 (2) ps-poll 611 --------------------------------------------------------*/ 612 p_pspoll = &reserved_page_packet[PSPOLL_PG * 128]; 613 SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000)); 614 SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid); 615 SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr); 616 617 SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1rsvdpageloc, PSPOLL_PG); 618 619 /*-------------------------------------------------------- 620 (3) null data 621 ---------------------------------------------------------*/ 622 nullfunc = &reserved_page_packet[NULL_PG * 128]; 623 SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid); 624 SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr); 625 SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid); 626 627 SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1rsvdpageloc, NULL_PG); 628 629 /*--------------------------------------------------------- 630 (4) probe response 631 ----------------------------------------------------------*/ 632 p_probersp = &reserved_page_packet[PROBERSP_PG * 128]; 633 SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid); 634 SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr); 635 SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid); 636 637 SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1rsvdpageloc, PROBERSP_PG); 638 639 totalpacketlen = TOTAL_RESERVED_PKT_LEN; 640 641 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD, 642 "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n", 643 &reserved_page_packet[0], totalpacketlen); 644 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, 645 "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n", 646 u1rsvdpageloc, 3); 647 648 649 skb = dev_alloc_skb(totalpacketlen); 650 skb_put_data(skb, &reserved_page_packet, totalpacketlen); 651 652 if (cmd_send_packet) 653 rtstatus = cmd_send_packet(hw, skb); 654 else 655 rtstatus = rtl_cmd_send_packet(hw, skb); 656 657 if (rtstatus) 658 b_dlok = true; 659 660 if (b_dlok) { 661 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, 662 "Set RSVD page location to Fw.\n"); 663 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, 664 "H2C_RSVDPAGE:\n", 665 u1rsvdpageloc, 3); 666 rtl92c_fill_h2c_cmd(hw, H2C_RSVDPAGE, 667 sizeof(u1rsvdpageloc), u1rsvdpageloc); 668 } else 669 RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, 670 "Set RSVD page location to Fw FAIL!!!!!!.\n"); 671 } 672 EXPORT_SYMBOL(rtl92c_set_fw_rsvdpagepkt); 673 674 void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus) 675 { 676 u8 u1_joinbssrpt_parm[1] = { 0 }; 677 678 SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus); 679 680 rtl92c_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm); 681 } 682 EXPORT_SYMBOL(rtl92c_set_fw_joinbss_report_cmd); 683 684 static void rtl92c_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw, u8 ctwindow) 685 { 686 u8 u1_ctwindow_period[1] = { ctwindow}; 687 688 rtl92c_fill_h2c_cmd(hw, H2C_P2P_PS_CTW_CMD, 1, u1_ctwindow_period); 689 } 690 691 /* refactored routine */ 692 static void set_noa_data(struct rtl_priv *rtlpriv, 693 struct rtl_p2p_ps_info *p2pinfo, 694 struct p2p_ps_offload_t *p2p_ps_offload) 695 { 696 int i; 697 u32 start_time, tsf_low; 698 699 /* hw only support 2 set of NoA */ 700 for (i = 0 ; i < p2pinfo->noa_num ; i++) { 701 /* To control the reg setting for which NOA*/ 702 rtl_write_byte(rtlpriv, 0x5cf, (i << 4)); 703 if (i == 0) 704 p2p_ps_offload->noa0_en = 1; 705 else 706 p2p_ps_offload->noa1_en = 1; 707 708 /* config P2P NoA Descriptor Register */ 709 rtl_write_dword(rtlpriv, 0x5E0, 710 p2pinfo->noa_duration[i]); 711 rtl_write_dword(rtlpriv, 0x5E4, 712 p2pinfo->noa_interval[i]); 713 714 /*Get Current TSF value */ 715 tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR); 716 717 start_time = p2pinfo->noa_start_time[i]; 718 if (p2pinfo->noa_count_type[i] != 1) { 719 while (start_time <= (tsf_low+(50*1024))) { 720 start_time += p2pinfo->noa_interval[i]; 721 if (p2pinfo->noa_count_type[i] != 255) 722 p2pinfo->noa_count_type[i]--; 723 } 724 } 725 rtl_write_dword(rtlpriv, 0x5E8, start_time); 726 rtl_write_dword(rtlpriv, 0x5EC, 727 p2pinfo->noa_count_type[i]); 728 } 729 } 730 731 void rtl92c_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state) 732 { 733 struct rtl_priv *rtlpriv = rtl_priv(hw); 734 struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw)); 735 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); 736 struct rtl_p2p_ps_info *p2pinfo = &(rtlps->p2p_ps_info); 737 struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload; 738 u16 ctwindow; 739 740 switch (p2p_ps_state) { 741 case P2P_PS_DISABLE: 742 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, 743 "P2P_PS_DISABLE\n"); 744 memset(p2p_ps_offload, 0, sizeof(*p2p_ps_offload)); 745 break; 746 case P2P_PS_ENABLE: 747 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, 748 "P2P_PS_ENABLE\n"); 749 /* update CTWindow value. */ 750 if (p2pinfo->ctwindow > 0) { 751 p2p_ps_offload->ctwindow_en = 1; 752 ctwindow = p2pinfo->ctwindow; 753 rtl92c_set_p2p_ctw_period_cmd(hw, ctwindow); 754 } 755 /* call refactored routine */ 756 set_noa_data(rtlpriv, p2pinfo, p2p_ps_offload); 757 758 if ((p2pinfo->opp_ps == 1) || (p2pinfo->noa_num > 0)) { 759 /* rst p2p circuit */ 760 rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, 761 BIT(4)); 762 763 p2p_ps_offload->offload_en = 1; 764 765 if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) { 766 p2p_ps_offload->role = 1; 767 p2p_ps_offload->allstasleep = 0; 768 } else { 769 p2p_ps_offload->role = 0; 770 } 771 772 p2p_ps_offload->discovery = 0; 773 } 774 break; 775 case P2P_PS_SCAN: 776 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN\n"); 777 p2p_ps_offload->discovery = 1; 778 break; 779 case P2P_PS_SCAN_DONE: 780 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, 781 "P2P_PS_SCAN_DONE\n"); 782 p2p_ps_offload->discovery = 0; 783 p2pinfo->p2p_ps_state = P2P_PS_ENABLE; 784 break; 785 default: 786 break; 787 } 788 789 rtl92c_fill_h2c_cmd(hw, H2C_P2P_PS_OFFLOAD, 1, (u8 *)p2p_ps_offload); 790 791 } 792 EXPORT_SYMBOL_GPL(rtl92c_set_p2p_ps_offload_cmd); 793