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