wl_cfg_btcoex.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593
  1. /*
  2. * Linux cfg80211 driver - Dongle Host Driver (DHD) related
  3. *
  4. * Portions of this code are copyright (c) 2020 Cypress Semiconductor Corporation
  5. *
  6. * Copyright (C) 1999-2020, Broadcom Corporation
  7. *
  8. * Unless you and Broadcom execute a separate written software license
  9. * agreement governing use of this software, this software is licensed to you
  10. * under the terms of the GNU General Public License version 2 (the "GPL"),
  11. * available at http://www.broadcom.com/licenses/GPLv2.php, with the
  12. * following added to such license:
  13. *
  14. * As a special exception, the copyright holders of this software give you
  15. * permission to link this software with independent modules, and to copy and
  16. * distribute the resulting executable under terms of your choice, provided that
  17. * you also meet, for each linked independent module, the terms and conditions of
  18. * the license of that module. An independent module is a module which is not
  19. * derived from this software. The special exception does not apply to any
  20. * modifications of the software.
  21. *
  22. * Notwithstanding the above, under no circumstances may you combine this
  23. * software in any way with any other Broadcom software provided under a license
  24. * other than the GPL, without Broadcom's express prior written consent.
  25. *
  26. *
  27. * <<Broadcom-WL-IPTag/Open:>>
  28. *
  29. * $Id: wl_cfg_btcoex.c 814554 2019-04-11 23:06:22Z $
  30. */
  31. #include <net/rtnetlink.h>
  32. #include <bcmutils.h>
  33. #include <wldev_common.h>
  34. #include <wl_cfg80211.h>
  35. #include <dhd_cfg80211.h>
  36. #include <dngl_stats.h>
  37. #include <dhd.h>
  38. #include <dhdioctl.h>
  39. #include <wlioctl.h>
  40. #ifdef PKT_FILTER_SUPPORT
  41. extern uint dhd_pkt_filter_enable;
  42. extern uint dhd_master_mode;
  43. extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode);
  44. #endif // endif
  45. struct btcoex_info {
  46. timer_list_compat_t timer;
  47. u32 timer_ms;
  48. u32 timer_on;
  49. u32 ts_dhcp_start; /* ms ts ecord time stats */
  50. u32 ts_dhcp_ok; /* ms ts ecord time stats */
  51. bool dhcp_done; /* flag, indicates that host done with
  52. * dhcp before t1/t2 expiration
  53. */
  54. s32 bt_state;
  55. struct work_struct work;
  56. struct net_device *dev;
  57. };
  58. #if defined(OEM_ANDROID)
  59. static struct btcoex_info *btcoex_info_loc = NULL;
  60. /* TODO: clean up the BT-Coex code, it still have some legacy ioctl/iovar functions */
  61. /* use New SCO/eSCO smart YG suppression */
  62. #define BT_DHCP_eSCO_FIX
  63. /* this flag boost wifi pkt priority to max, caution: -not fair to sco */
  64. #define BT_DHCP_USE_FLAGS
  65. /* T1 start SCO/ESCo priority suppression */
  66. #define BT_DHCP_OPPR_WIN_TIME 2500
  67. /* T2 turn off SCO/SCO supperesion is (timeout) */
  68. #define BT_DHCP_FLAG_FORCE_TIME 5500
  69. #define BTCOEXMODE "BTCOEXMODE"
  70. #define POWERMODE "POWERMODE"
  71. enum wl_cfg80211_btcoex_status {
  72. BT_DHCP_IDLE,
  73. BT_DHCP_START,
  74. BT_DHCP_OPPR_WIN,
  75. BT_DHCP_FLAG_FORCE_TIMEOUT
  76. };
  77. /*
  78. * get named driver variable to uint register value and return error indication
  79. * calling example: dev_wlc_intvar_get_reg(dev, "btc_params",66, &reg_value)
  80. */
  81. static int
  82. dev_wlc_intvar_get_reg(struct net_device *dev, char *name,
  83. uint reg, int *retval)
  84. {
  85. union {
  86. char buf[WLC_IOCTL_SMLEN];
  87. int val;
  88. } var;
  89. int error;
  90. bzero(&var, sizeof(var));
  91. error = bcm_mkiovar(name, (char *)(&reg), sizeof(reg), (char *)(&var), sizeof(var.buf));
  92. if (error == 0) {
  93. return BCME_BUFTOOSHORT;
  94. }
  95. error = wldev_ioctl_get(dev, WLC_GET_VAR, (char *)(&var), sizeof(var.buf));
  96. *retval = dtoh32(var.val);
  97. return (error);
  98. }
  99. static int
  100. dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len)
  101. {
  102. char ioctlbuf_local[WLC_IOCTL_SMLEN];
  103. int ret;
  104. ret = bcm_mkiovar(name, buf, len, ioctlbuf_local, sizeof(ioctlbuf_local));
  105. if (ret == 0)
  106. return BCME_BUFTOOSHORT;
  107. return (wldev_ioctl_set(dev, WLC_SET_VAR, ioctlbuf_local, ret));
  108. }
  109. /*
  110. get named driver variable to uint register value and return error indication
  111. calling example: dev_wlc_intvar_set_reg(dev, "btc_params",66, value)
  112. */
  113. static int
  114. dev_wlc_intvar_set_reg(struct net_device *dev, char *name, char *addr, char * val)
  115. {
  116. char reg_addr[8];
  117. bzero(reg_addr, sizeof(reg_addr));
  118. memcpy((char *)&reg_addr[0], (char *)addr, 4);
  119. memcpy((char *)&reg_addr[4], (char *)val, 4);
  120. return (dev_wlc_bufvar_set(dev, name, (char *)&reg_addr[0], sizeof(reg_addr)));
  121. }
  122. static bool btcoex_is_sco_active(struct net_device *dev)
  123. {
  124. int ioc_res = 0;
  125. bool res = FALSE;
  126. int sco_id_cnt = 0;
  127. int param27;
  128. int i;
  129. for (i = 0; i < 12; i++) {
  130. ioc_res = dev_wlc_intvar_get_reg(dev, "btc_params", 27, &param27);
  131. WL_TRACE(("sample[%d], btc params: 27:%x\n", i, param27));
  132. if (ioc_res < 0) {
  133. WL_ERR(("ioc read btc params error\n"));
  134. break;
  135. }
  136. if ((param27 & 0x6) == 2) { /* count both sco & esco */
  137. sco_id_cnt++;
  138. }
  139. if (sco_id_cnt > 2) {
  140. WL_TRACE(("sco/esco detected, pkt id_cnt:%d samples:%d\n",
  141. sco_id_cnt, i));
  142. res = TRUE;
  143. break;
  144. }
  145. OSL_SLEEP(5);
  146. }
  147. return res;
  148. }
  149. #if defined(BT_DHCP_eSCO_FIX)
  150. /* Enhanced BT COEX settings for eSCO compatibility during DHCP window */
  151. static int set_btc_esco_params(struct net_device *dev, bool trump_sco)
  152. {
  153. static bool saved_status = FALSE;
  154. char buf_reg50va_dhcp_on[8] =
  155. { 50, 00, 00, 00, 0x22, 0x80, 0x00, 0x00 };
  156. char buf_reg51va_dhcp_on[8] =
  157. { 51, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
  158. char buf_reg64va_dhcp_on[8] =
  159. { 64, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
  160. char buf_reg65va_dhcp_on[8] =
  161. { 65, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
  162. char buf_reg71va_dhcp_on[8] =
  163. { 71, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
  164. uint32 regaddr;
  165. static uint32 saved_reg50;
  166. static uint32 saved_reg51;
  167. static uint32 saved_reg64;
  168. static uint32 saved_reg65;
  169. static uint32 saved_reg71;
  170. if (trump_sco) {
  171. /* this should reduce eSCO agressive retransmit
  172. * w/o breaking it
  173. */
  174. /* 1st save current */
  175. WL_TRACE(("Do new SCO/eSCO coex algo {save &"
  176. "override}\n"));
  177. if ((!dev_wlc_intvar_get_reg(dev, "btc_params", 50, &saved_reg50)) &&
  178. (!dev_wlc_intvar_get_reg(dev, "btc_params", 51, &saved_reg51)) &&
  179. (!dev_wlc_intvar_get_reg(dev, "btc_params", 64, &saved_reg64)) &&
  180. (!dev_wlc_intvar_get_reg(dev, "btc_params", 65, &saved_reg65)) &&
  181. (!dev_wlc_intvar_get_reg(dev, "btc_params", 71, &saved_reg71))) {
  182. saved_status = TRUE;
  183. WL_TRACE(("saved bt_params[50,51,64,65,71]:"
  184. "0x%x 0x%x 0x%x 0x%x 0x%x\n",
  185. saved_reg50, saved_reg51,
  186. saved_reg64, saved_reg65, saved_reg71));
  187. } else {
  188. WL_ERR((":%s: save btc_params failed\n",
  189. __FUNCTION__));
  190. saved_status = FALSE;
  191. return -1;
  192. }
  193. WL_TRACE(("override with [50,51,64,65,71]:"
  194. "0x%x 0x%x 0x%x 0x%x 0x%x\n",
  195. *(u32 *)(buf_reg50va_dhcp_on+4),
  196. *(u32 *)(buf_reg51va_dhcp_on+4),
  197. *(u32 *)(buf_reg64va_dhcp_on+4),
  198. *(u32 *)(buf_reg65va_dhcp_on+4),
  199. *(u32 *)(buf_reg71va_dhcp_on+4)));
  200. dev_wlc_bufvar_set(dev, "btc_params",
  201. (char *)&buf_reg50va_dhcp_on[0], 8);
  202. dev_wlc_bufvar_set(dev, "btc_params",
  203. (char *)&buf_reg51va_dhcp_on[0], 8);
  204. dev_wlc_bufvar_set(dev, "btc_params",
  205. (char *)&buf_reg64va_dhcp_on[0], 8);
  206. dev_wlc_bufvar_set(dev, "btc_params",
  207. (char *)&buf_reg65va_dhcp_on[0], 8);
  208. dev_wlc_bufvar_set(dev, "btc_params",
  209. (char *)&buf_reg71va_dhcp_on[0], 8);
  210. saved_status = TRUE;
  211. } else if (saved_status) {
  212. /* restore previously saved bt params */
  213. WL_TRACE(("Do new SCO/eSCO coex algo {save &"
  214. "override}\n"));
  215. regaddr = 50;
  216. dev_wlc_intvar_set_reg(dev, "btc_params",
  217. (char *)&regaddr, (char *)&saved_reg50);
  218. regaddr = 51;
  219. dev_wlc_intvar_set_reg(dev, "btc_params",
  220. (char *)&regaddr, (char *)&saved_reg51);
  221. regaddr = 64;
  222. dev_wlc_intvar_set_reg(dev, "btc_params",
  223. (char *)&regaddr, (char *)&saved_reg64);
  224. regaddr = 65;
  225. dev_wlc_intvar_set_reg(dev, "btc_params",
  226. (char *)&regaddr, (char *)&saved_reg65);
  227. regaddr = 71;
  228. dev_wlc_intvar_set_reg(dev, "btc_params",
  229. (char *)&regaddr, (char *)&saved_reg71);
  230. WL_TRACE(("restore bt_params[50,51,64,65,71]:"
  231. "0x%x 0x%x 0x%x 0x%x 0x%x\n",
  232. saved_reg50, saved_reg51, saved_reg64,
  233. saved_reg65, saved_reg71));
  234. saved_status = FALSE;
  235. } else {
  236. WL_ERR((":%s att to restore not saved BTCOEX params\n",
  237. __FUNCTION__));
  238. return -1;
  239. }
  240. return 0;
  241. }
  242. #endif /* BT_DHCP_eSCO_FIX */
  243. static void
  244. wl_cfg80211_bt_setflag(struct net_device *dev, bool set)
  245. {
  246. #if defined(BT_DHCP_USE_FLAGS)
  247. char buf_flag7_dhcp_on[8] = { 7, 00, 00, 00, 0x1, 0x0, 0x00, 0x00 };
  248. char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
  249. #endif // endif
  250. #if defined(BT_DHCP_eSCO_FIX)
  251. /* set = 1, save & turn on 0 - off & restore prev settings */
  252. set_btc_esco_params(dev, set);
  253. #endif // endif
  254. #if defined(BT_DHCP_USE_FLAGS)
  255. WL_TRACE(("WI-FI priority boost via bt flags, set:%d\n", set));
  256. if (set == TRUE)
  257. /* Forcing bt_flag7 */
  258. dev_wlc_bufvar_set(dev, "btc_flags",
  259. (char *)&buf_flag7_dhcp_on[0],
  260. sizeof(buf_flag7_dhcp_on));
  261. else
  262. /* Restoring default bt flag7 */
  263. dev_wlc_bufvar_set(dev, "btc_flags",
  264. (char *)&buf_flag7_default[0],
  265. sizeof(buf_flag7_default));
  266. #endif // endif
  267. }
  268. static void wl_cfg80211_bt_timerfunc(ulong data)
  269. {
  270. struct btcoex_info *bt_local = (struct btcoex_info *)data;
  271. WL_TRACE(("Enter\n"));
  272. bt_local->timer_on = 0;
  273. schedule_work(&bt_local->work);
  274. }
  275. static void wl_cfg80211_bt_handler(struct work_struct *work)
  276. {
  277. struct btcoex_info *btcx_inf;
  278. GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
  279. btcx_inf = container_of(work, struct btcoex_info, work);
  280. GCC_DIAGNOSTIC_POP();
  281. if (btcx_inf->timer_on) {
  282. btcx_inf->timer_on = 0;
  283. del_timer_sync(&btcx_inf->timer);
  284. }
  285. switch (btcx_inf->bt_state) {
  286. case BT_DHCP_START:
  287. /* DHCP started
  288. * provide OPPORTUNITY window to get DHCP address
  289. */
  290. WL_TRACE(("bt_dhcp stm: started \n"));
  291. btcx_inf->bt_state = BT_DHCP_OPPR_WIN;
  292. mod_timer(&btcx_inf->timer,
  293. jiffies + msecs_to_jiffies(BT_DHCP_OPPR_WIN_TIME));
  294. btcx_inf->timer_on = 1;
  295. break;
  296. case BT_DHCP_OPPR_WIN:
  297. if (btcx_inf->dhcp_done) {
  298. WL_TRACE(("DHCP Done before T1 expiration\n"));
  299. goto btc_coex_idle;
  300. }
  301. /* DHCP is not over yet, start lowering BT priority
  302. * enforce btc_params + flags if necessary
  303. */
  304. WL_TRACE(("DHCP T1:%d expired\n", BT_DHCP_OPPR_WIN_TIME));
  305. if (btcx_inf->dev)
  306. wl_cfg80211_bt_setflag(btcx_inf->dev, TRUE);
  307. btcx_inf->bt_state = BT_DHCP_FLAG_FORCE_TIMEOUT;
  308. mod_timer(&btcx_inf->timer,
  309. jiffies + msecs_to_jiffies(BT_DHCP_FLAG_FORCE_TIME));
  310. btcx_inf->timer_on = 1;
  311. break;
  312. case BT_DHCP_FLAG_FORCE_TIMEOUT:
  313. if (btcx_inf->dhcp_done) {
  314. WL_TRACE(("DHCP Done before T2 expiration\n"));
  315. } else {
  316. /* Noo dhcp during T1+T2, restore BT priority */
  317. WL_TRACE(("DHCP wait interval T2:%d msec expired\n",
  318. BT_DHCP_FLAG_FORCE_TIME));
  319. }
  320. /* Restoring default bt priority */
  321. if (btcx_inf->dev)
  322. wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE);
  323. btc_coex_idle:
  324. btcx_inf->bt_state = BT_DHCP_IDLE;
  325. btcx_inf->timer_on = 0;
  326. break;
  327. default:
  328. WL_ERR(("error g_status=%d !!!\n", btcx_inf->bt_state));
  329. if (btcx_inf->dev)
  330. wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE);
  331. btcx_inf->bt_state = BT_DHCP_IDLE;
  332. btcx_inf->timer_on = 0;
  333. break;
  334. }
  335. net_os_wake_unlock(btcx_inf->dev);
  336. }
  337. void* wl_cfg80211_btcoex_init(struct net_device *ndev)
  338. {
  339. struct btcoex_info *btco_inf = NULL;
  340. btco_inf = kmalloc(sizeof(struct btcoex_info), GFP_KERNEL);
  341. if (!btco_inf)
  342. return NULL;
  343. btco_inf->bt_state = BT_DHCP_IDLE;
  344. btco_inf->ts_dhcp_start = 0;
  345. btco_inf->ts_dhcp_ok = 0;
  346. /* Set up timer for BT */
  347. btco_inf->timer_ms = 10;
  348. init_timer_compat(&btco_inf->timer, wl_cfg80211_bt_timerfunc, btco_inf);
  349. btco_inf->dev = ndev;
  350. INIT_WORK(&btco_inf->work, wl_cfg80211_bt_handler);
  351. btcoex_info_loc = btco_inf;
  352. return btco_inf;
  353. }
  354. void wl_cfg80211_btcoex_deinit()
  355. {
  356. if (!btcoex_info_loc)
  357. return;
  358. if (btcoex_info_loc->timer_on) {
  359. btcoex_info_loc->timer_on = 0;
  360. del_timer_sync(&btcoex_info_loc->timer);
  361. }
  362. cancel_work_sync(&btcoex_info_loc->work);
  363. kfree(btcoex_info_loc);
  364. }
  365. int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, dhd_pub_t *dhd, char *command)
  366. {
  367. #ifndef OEM_ANDROID
  368. static int pm = PM_FAST;
  369. int pm_local = PM_OFF;
  370. #endif /* OEM_ANDROID */
  371. struct btcoex_info *btco_inf = btcoex_info_loc;
  372. char powermode_val = 0;
  373. uint8 cmd_len = 0;
  374. char buf_reg66va_dhcp_on[8] = { 66, 00, 00, 00, 0x10, 0x27, 0x00, 0x00 };
  375. char buf_reg41va_dhcp_on[8] = { 41, 00, 00, 00, 0x33, 0x00, 0x00, 0x00 };
  376. char buf_reg68va_dhcp_on[8] = { 68, 00, 00, 00, 0x90, 0x01, 0x00, 0x00 };
  377. uint32 regaddr;
  378. static uint32 saved_reg66;
  379. static uint32 saved_reg41;
  380. static uint32 saved_reg68;
  381. static bool saved_status = FALSE;
  382. char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
  383. /* Figure out powermode 1 or o command */
  384. #ifdef OEM_ANDROID
  385. cmd_len = sizeof(BTCOEXMODE);
  386. #else
  387. cmd_len = sizeof(POWERMODE);
  388. #endif // endif
  389. powermode_val = command[cmd_len];
  390. if (powermode_val == '1') {
  391. WL_TRACE_HW4(("DHCP session starts\n"));
  392. #ifdef PKT_FILTER_SUPPORT
  393. dhd->dhcp_in_progress = 1;
  394. #if defined(APSTA_BLOCK_ARP_DURING_DHCP)
  395. if (DHD_OPMODE_STA_SOFTAP_CONCURR(dhd)) {
  396. /* Block ARP frames while DHCP of STA interface is in
  397. * progress in case of STA/SoftAP concurrent mode
  398. */
  399. wl_cfg80211_block_arp(dev, TRUE);
  400. } else
  401. #endif /* APSTA_BLOCK_ARP_DURING_DHCP */
  402. if (dhd->early_suspended) {
  403. WL_TRACE_HW4(("DHCP in progressing , disable packet filter!!!\n"));
  404. dhd_enable_packet_filter(0, dhd);
  405. }
  406. #endif /* PKT_FILTER_SUPPORT */
  407. /* Retrieve and saved orig regs value */
  408. if ((saved_status == FALSE) &&
  409. #ifndef OEM_ANDROID
  410. (!dev_wlc_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm))) &&
  411. #endif // endif
  412. (!dev_wlc_intvar_get_reg(dev, "btc_params", 66, &saved_reg66)) &&
  413. (!dev_wlc_intvar_get_reg(dev, "btc_params", 41, &saved_reg41)) &&
  414. (!dev_wlc_intvar_get_reg(dev, "btc_params", 68, &saved_reg68))) {
  415. saved_status = TRUE;
  416. WL_TRACE(("Saved 0x%x 0x%x 0x%x\n",
  417. saved_reg66, saved_reg41, saved_reg68));
  418. /* Disable PM mode during dhpc session */
  419. #ifndef OEM_ANDROID
  420. dev_wlc_ioctl(dev, WLC_SET_PM, &pm_local, sizeof(pm_local));
  421. #endif // endif
  422. /* Disable PM mode during dhpc session */
  423. /* Start BT timer only for SCO connection */
  424. if (btcoex_is_sco_active(dev)) {
  425. /* btc_params 66 */
  426. dev_wlc_bufvar_set(dev, "btc_params",
  427. (char *)&buf_reg66va_dhcp_on[0],
  428. sizeof(buf_reg66va_dhcp_on));
  429. /* btc_params 41 0x33 */
  430. dev_wlc_bufvar_set(dev, "btc_params",
  431. (char *)&buf_reg41va_dhcp_on[0],
  432. sizeof(buf_reg41va_dhcp_on));
  433. /* btc_params 68 0x190 */
  434. dev_wlc_bufvar_set(dev, "btc_params",
  435. (char *)&buf_reg68va_dhcp_on[0],
  436. sizeof(buf_reg68va_dhcp_on));
  437. saved_status = TRUE;
  438. btco_inf->bt_state = BT_DHCP_START;
  439. btco_inf->timer_on = 1;
  440. mod_timer(&btco_inf->timer,
  441. timer_expires(&btco_inf->timer));
  442. WL_TRACE(("enable BT DHCP Timer\n"));
  443. }
  444. }
  445. else if (saved_status == TRUE) {
  446. WL_ERR(("was called w/o DHCP OFF. Continue\n"));
  447. }
  448. }
  449. #ifdef OEM_ANDROID
  450. else if (powermode_val == '2') {
  451. #else
  452. else if (powermode_val == '0') {
  453. #endif // endif
  454. #ifdef PKT_FILTER_SUPPORT
  455. dhd->dhcp_in_progress = 0;
  456. WL_TRACE_HW4(("DHCP is complete \n"));
  457. #if defined(APSTA_BLOCK_ARP_DURING_DHCP)
  458. if (DHD_OPMODE_STA_SOFTAP_CONCURR(dhd)) {
  459. /* Unblock ARP frames */
  460. wl_cfg80211_block_arp(dev, FALSE);
  461. } else
  462. #endif /* APSTA_BLOCK_ARP_DURING_DHCP */
  463. if (dhd->early_suspended) {
  464. /* Enable packet filtering */
  465. WL_TRACE_HW4(("DHCP is complete , enable packet filter!!!\n"));
  466. dhd_enable_packet_filter(1, dhd);
  467. }
  468. #endif /* PKT_FILTER_SUPPORT */
  469. /* Restoring PM mode */
  470. #ifndef OEM_ANDROID
  471. dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm));
  472. #endif // endif
  473. /* Stop any bt timer because DHCP session is done */
  474. WL_TRACE(("disable BT DHCP Timer\n"));
  475. if (btco_inf->timer_on) {
  476. btco_inf->timer_on = 0;
  477. del_timer_sync(&btco_inf->timer);
  478. if (btco_inf->bt_state != BT_DHCP_IDLE) {
  479. /* need to restore original btc flags & extra btc params */
  480. WL_TRACE(("bt->bt_state:%d\n", btco_inf->bt_state));
  481. /* wake up btcoex thread to restore btlags+params */
  482. schedule_work(&btco_inf->work);
  483. }
  484. }
  485. /* Restoring btc_flag paramter anyway */
  486. if (saved_status == TRUE)
  487. dev_wlc_bufvar_set(dev, "btc_flags",
  488. (char *)&buf_flag7_default[0], sizeof(buf_flag7_default));
  489. /* Restore original values */
  490. if (saved_status == TRUE) {
  491. regaddr = 66;
  492. dev_wlc_intvar_set_reg(dev, "btc_params",
  493. (char *)&regaddr, (char *)&saved_reg66);
  494. regaddr = 41;
  495. dev_wlc_intvar_set_reg(dev, "btc_params",
  496. (char *)&regaddr, (char *)&saved_reg41);
  497. regaddr = 68;
  498. dev_wlc_intvar_set_reg(dev, "btc_params",
  499. (char *)&regaddr, (char *)&saved_reg68);
  500. WL_TRACE(("restore regs {66,41,68} <- 0x%x 0x%x 0x%x\n",
  501. saved_reg66, saved_reg41, saved_reg68));
  502. }
  503. saved_status = FALSE;
  504. }
  505. else {
  506. WL_ERR(("Unkwown yet power setting, ignored\n"));
  507. }
  508. return (snprintf(command, sizeof("OK"), "OK") + 1);
  509. }
  510. #endif /* defined(OEM_ANDROID) */