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