bcmdhd: Add void argument to old-style zero prototype functions
[GitHub/LineageOS/G12/android_hardware_amlogic_kernel-modules_dhd-driver.git] / bcmdhd-usb.1.363.110.17.x / wl_cfg_btcoex.c
CommitLineData
84813812
LJ
1/*
2 * Linux cfg80211 driver - Dongle Host Driver (DHD) related
3 *
4 * Copyright (C) 1999-2016, Broadcom Corporation
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 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 *
25 * <<Broadcom-WL-IPTag/Open:>>
26 *
27 * $Id: wl_cfg_btcoex.c 514727 2014-11-12 03:02:48Z $
28 */
29
30#include <net/rtnetlink.h>
31
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
41#ifdef PKT_FILTER_SUPPORT
42extern uint dhd_pkt_filter_enable;
43extern uint dhd_master_mode;
44extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode);
45#endif
46
47struct btcoex_info {
48 struct timer_list timer;
49 u32 timer_ms;
50 u32 timer_on;
51 u32 ts_dhcp_start; /* ms ts ecord time stats */
52 u32 ts_dhcp_ok; /* ms ts ecord time stats */
53 bool dhcp_done; /* flag, indicates that host done with
54 * dhcp before t1/t2 expiration
55 */
56 s32 bt_state;
57 struct work_struct work;
58 struct net_device *dev;
59};
60
61#if defined(OEM_ANDROID)
62static struct btcoex_info *btcoex_info_loc = NULL;
63
64/* TODO: clean up the BT-Coex code, it still have some legacy ioctl/iovar functions */
65
66/* use New SCO/eSCO smart YG suppression */
67#define BT_DHCP_eSCO_FIX
68/* this flag boost wifi pkt priority to max, caution: -not fair to sco */
69#define BT_DHCP_USE_FLAGS
70/* T1 start SCO/ESCo priority suppression */
71#define BT_DHCP_OPPR_WIN_TIME 2500
72/* T2 turn off SCO/SCO supperesion is (timeout) */
73#define BT_DHCP_FLAG_FORCE_TIME 5500
74
75enum wl_cfg80211_btcoex_status {
76 BT_DHCP_IDLE,
77 BT_DHCP_START,
78 BT_DHCP_OPPR_WIN,
79 BT_DHCP_FLAG_FORCE_TIMEOUT
80};
81
82/*
83 * get named driver variable to uint register value and return error indication
84 * calling example: dev_wlc_intvar_get_reg(dev, "btc_params",66, &reg_value)
85 */
86static int
87dev_wlc_intvar_get_reg(struct net_device *dev, char *name,
88 uint reg, int *retval)
89{
90 union {
91 char buf[WLC_IOCTL_SMLEN];
92 int val;
93 } var;
94 int error;
95
96 bcm_mkiovar(name, (char *)(&reg), sizeof(reg),
97 (char *)(&var), sizeof(var.buf));
98 error = wldev_ioctl(dev, WLC_GET_VAR, (char *)(&var), sizeof(var.buf), false);
99
100 *retval = dtoh32(var.val);
101 return (error);
102}
103
104static int
105dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len)
106{
107#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
108 char ioctlbuf_local[1024];
109#else
110 static char ioctlbuf_local[1024];
111#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */
112
113 bcm_mkiovar(name, buf, len, ioctlbuf_local, sizeof(ioctlbuf_local));
114
115 return (wldev_ioctl(dev, WLC_SET_VAR, ioctlbuf_local, sizeof(ioctlbuf_local), true));
116}
117/*
118get named driver variable to uint register value and return error indication
119calling example: dev_wlc_intvar_set_reg(dev, "btc_params",66, value)
120*/
121static int
122dev_wlc_intvar_set_reg(struct net_device *dev, char *name, char *addr, char * val)
123{
124 char reg_addr[8];
125
126 memset(reg_addr, 0, sizeof(reg_addr));
127 memcpy((char *)&reg_addr[0], (char *)addr, 4);
128 memcpy((char *)&reg_addr[4], (char *)val, 4);
129
130 return (dev_wlc_bufvar_set(dev, name, (char *)&reg_addr[0], sizeof(reg_addr)));
131}
132
133static 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 */
171static 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 WL_TRACE(("override with [50,51,64,65,71]:"
218 "0x%x 0x%x 0x%x 0x%x 0x%x\n",
219 *(u32 *)(buf_reg50va_dhcp_on+4),
220 *(u32 *)(buf_reg51va_dhcp_on+4),
221 *(u32 *)(buf_reg64va_dhcp_on+4),
222 *(u32 *)(buf_reg65va_dhcp_on+4),
223 *(u32 *)(buf_reg71va_dhcp_on+4)));
224
225 dev_wlc_bufvar_set(dev, "btc_params",
226 (char *)&buf_reg50va_dhcp_on[0], 8);
227 dev_wlc_bufvar_set(dev, "btc_params",
228 (char *)&buf_reg51va_dhcp_on[0], 8);
229 dev_wlc_bufvar_set(dev, "btc_params",
230 (char *)&buf_reg64va_dhcp_on[0], 8);
231 dev_wlc_bufvar_set(dev, "btc_params",
232 (char *)&buf_reg65va_dhcp_on[0], 8);
233 dev_wlc_bufvar_set(dev, "btc_params",
234 (char *)&buf_reg71va_dhcp_on[0], 8);
235
236 saved_status = TRUE;
237 } else if (saved_status) {
238 /* restore previously saved bt params */
239 WL_TRACE(("Do new SCO/eSCO coex algo {save &"
240 "override}\n"));
241
242 regaddr = 50;
243 dev_wlc_intvar_set_reg(dev, "btc_params",
244 (char *)&regaddr, (char *)&saved_reg50);
245 regaddr = 51;
246 dev_wlc_intvar_set_reg(dev, "btc_params",
247 (char *)&regaddr, (char *)&saved_reg51);
248 regaddr = 64;
249 dev_wlc_intvar_set_reg(dev, "btc_params",
250 (char *)&regaddr, (char *)&saved_reg64);
251 regaddr = 65;
252 dev_wlc_intvar_set_reg(dev, "btc_params",
253 (char *)&regaddr, (char *)&saved_reg65);
254 regaddr = 71;
255 dev_wlc_intvar_set_reg(dev, "btc_params",
256 (char *)&regaddr, (char *)&saved_reg71);
257
258 WL_TRACE(("restore bt_params[50,51,64,65,71]:"
259 "0x%x 0x%x 0x%x 0x%x 0x%x\n",
260 saved_reg50, saved_reg51, saved_reg64,
261 saved_reg65, saved_reg71));
262
263 saved_status = FALSE;
264 } else {
265 WL_ERR((":%s att to restore not saved BTCOEX params\n",
266 __FUNCTION__));
267 return -1;
268 }
269 return 0;
270}
271#endif /* BT_DHCP_eSCO_FIX */
272
273static void
274wl_cfg80211_bt_setflag(struct net_device *dev, bool set)
275{
276#if defined(BT_DHCP_USE_FLAGS)
277 char buf_flag7_dhcp_on[8] = { 7, 00, 00, 00, 0x1, 0x0, 0x00, 0x00 };
278 char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
279#endif
280
281
282#if defined(BT_DHCP_eSCO_FIX)
283 /* set = 1, save & turn on 0 - off & restore prev settings */
284 set_btc_esco_params(dev, set);
285#endif
286
287#if defined(BT_DHCP_USE_FLAGS)
288 WL_TRACE(("WI-FI priority boost via bt flags, set:%d\n", set));
289 if (set == TRUE)
290 /* Forcing bt_flag7 */
291 dev_wlc_bufvar_set(dev, "btc_flags",
292 (char *)&buf_flag7_dhcp_on[0],
293 sizeof(buf_flag7_dhcp_on));
294 else
295 /* Restoring default bt flag7 */
296 dev_wlc_bufvar_set(dev, "btc_flags",
297 (char *)&buf_flag7_default[0],
298 sizeof(buf_flag7_default));
299#endif
300}
301
302static void wl_cfg80211_bt_timerfunc(ulong data)
303{
304 struct btcoex_info *bt_local = (struct btcoex_info *)data;
305 WL_TRACE(("Enter\n"));
306 bt_local->timer_on = 0;
307 schedule_work(&bt_local->work);
308}
309
310static void wl_cfg80211_bt_handler(struct work_struct *work)
311{
312 struct btcoex_info *btcx_inf;
313
314 btcx_inf = container_of(work, struct btcoex_info, work);
315
316 if (btcx_inf->timer_on) {
317 btcx_inf->timer_on = 0;
318 del_timer_sync(&btcx_inf->timer);
319 }
320
321 switch (btcx_inf->bt_state) {
322 case BT_DHCP_START:
323 /* DHCP started
324 * provide OPPORTUNITY window to get DHCP address
325 */
326 WL_TRACE(("bt_dhcp stm: started \n"));
327
328 btcx_inf->bt_state = BT_DHCP_OPPR_WIN;
329 mod_timer(&btcx_inf->timer,
330 jiffies + msecs_to_jiffies(BT_DHCP_OPPR_WIN_TIME));
331 btcx_inf->timer_on = 1;
332 break;
333
334 case BT_DHCP_OPPR_WIN:
335 if (btcx_inf->dhcp_done) {
336 WL_TRACE(("DHCP Done before T1 expiration\n"));
337 goto btc_coex_idle;
338 }
339
340 /* DHCP is not over yet, start lowering BT priority
341 * enforce btc_params + flags if necessary
342 */
343 WL_TRACE(("DHCP T1:%d expired\n", BT_DHCP_OPPR_WIN_TIME));
344 if (btcx_inf->dev)
345 wl_cfg80211_bt_setflag(btcx_inf->dev, TRUE);
346 btcx_inf->bt_state = BT_DHCP_FLAG_FORCE_TIMEOUT;
347 mod_timer(&btcx_inf->timer,
348 jiffies + msecs_to_jiffies(BT_DHCP_FLAG_FORCE_TIME));
349 btcx_inf->timer_on = 1;
350 break;
351
352 case BT_DHCP_FLAG_FORCE_TIMEOUT:
353 if (btcx_inf->dhcp_done) {
354 WL_TRACE(("DHCP Done before T2 expiration\n"));
355 } else {
356 /* Noo dhcp during T1+T2, restore BT priority */
357 WL_TRACE(("DHCP wait interval T2:%d msec expired\n",
358 BT_DHCP_FLAG_FORCE_TIME));
359 }
360
361 /* Restoring default bt priority */
362 if (btcx_inf->dev)
363 wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE);
364btc_coex_idle:
365 btcx_inf->bt_state = BT_DHCP_IDLE;
366 btcx_inf->timer_on = 0;
367 break;
368
369 default:
370 WL_ERR(("error g_status=%d !!!\n", btcx_inf->bt_state));
371 if (btcx_inf->dev)
372 wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE);
373 btcx_inf->bt_state = BT_DHCP_IDLE;
374 btcx_inf->timer_on = 0;
375 break;
376 }
377
378 net_os_wake_unlock(btcx_inf->dev);
379}
380
381void* wl_cfg80211_btcoex_init(struct net_device *ndev)
382{
383 struct btcoex_info *btco_inf = NULL;
384
385 btco_inf = kmalloc(sizeof(struct btcoex_info), GFP_KERNEL);
386 if (!btco_inf)
387 return NULL;
388
389 btco_inf->bt_state = BT_DHCP_IDLE;
390 btco_inf->ts_dhcp_start = 0;
391 btco_inf->ts_dhcp_ok = 0;
392 /* Set up timer for BT */
393 btco_inf->timer_ms = 10;
394 init_timer(&btco_inf->timer);
395 btco_inf->timer.data = (ulong)btco_inf;
396 btco_inf->timer.function = wl_cfg80211_bt_timerfunc;
397
398 btco_inf->dev = ndev;
399
400 INIT_WORK(&btco_inf->work, wl_cfg80211_bt_handler);
401
402 btcoex_info_loc = btco_inf;
403 return btco_inf;
404}
405
95987a5c 406void wl_cfg80211_btcoex_deinit(void)
84813812
LJ
407{
408 if (!btcoex_info_loc)
409 return;
410
411 if (btcoex_info_loc->timer_on) {
412 btcoex_info_loc->timer_on = 0;
413 del_timer_sync(&btcoex_info_loc->timer);
414 }
415
416 cancel_work_sync(&btcoex_info_loc->work);
417
418 kfree(btcoex_info_loc);
419}
420
421int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, dhd_pub_t *dhd, char *command)
422{
423
424#ifndef OEM_ANDROID
425 static int pm = PM_FAST;
426 int pm_local = PM_OFF;
427#endif /* OEM_ANDROID */
428 struct btcoex_info *btco_inf = btcoex_info_loc;
429 char powermode_val = 0;
430 char buf_reg66va_dhcp_on[8] = { 66, 00, 00, 00, 0x10, 0x27, 0x00, 0x00 };
431 char buf_reg41va_dhcp_on[8] = { 41, 00, 00, 00, 0x33, 0x00, 0x00, 0x00 };
432 char buf_reg68va_dhcp_on[8] = { 68, 00, 00, 00, 0x90, 0x01, 0x00, 0x00 };
433
434 uint32 regaddr;
435 static uint32 saved_reg66;
436 static uint32 saved_reg41;
437 static uint32 saved_reg68;
438 static bool saved_status = FALSE;
439
440 char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
441
442 /* Figure out powermode 1 or o command */
443#ifdef OEM_ANDROID
444 strncpy((char *)&powermode_val, command + strlen("BTCOEXMODE") +1, 1);
445#else
446 strncpy((char *)&powermode_val, command + strlen("POWERMODE") +1, 1);
447#endif
448
449 if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) {
450 WL_TRACE_HW4(("DHCP session starts\n"));
451
452#if defined(OEM_ANDROID) && defined(DHCP_SCAN_SUPPRESS)
453 /* Suppress scan during the DHCP */
454 wl_cfg80211_scan_suppress(dev, 1);
455#endif /* OEM_ANDROID */
456
457#ifdef PKT_FILTER_SUPPORT
458 dhd->dhcp_in_progress = 1;
459
460 if (dhd->early_suspended) {
461 WL_TRACE_HW4(("DHCP in progressing , disable packet filter!!!\n"));
462 dhd_enable_packet_filter(0, dhd);
463 }
464#endif
465
466 /* Retrieve and saved orig regs value */
467 if ((saved_status == FALSE) &&
468#ifndef OEM_ANDROID
469 (!dev_wlc_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm))) &&
470#endif
471 (!dev_wlc_intvar_get_reg(dev, "btc_params", 66, &saved_reg66)) &&
472 (!dev_wlc_intvar_get_reg(dev, "btc_params", 41, &saved_reg41)) &&
473 (!dev_wlc_intvar_get_reg(dev, "btc_params", 68, &saved_reg68))) {
474 saved_status = TRUE;
475 WL_TRACE(("Saved 0x%x 0x%x 0x%x\n",
476 saved_reg66, saved_reg41, saved_reg68));
477
478 /* Disable PM mode during dhpc session */
479#ifndef OEM_ANDROID
480 dev_wlc_ioctl(dev, WLC_SET_PM, &pm_local, sizeof(pm_local));
481#endif
482
483 /* Disable PM mode during dhpc session */
484 /* Start BT timer only for SCO connection */
485 if (btcoex_is_sco_active(dev)) {
486 /* btc_params 66 */
487 dev_wlc_bufvar_set(dev, "btc_params",
488 (char *)&buf_reg66va_dhcp_on[0],
489 sizeof(buf_reg66va_dhcp_on));
490 /* btc_params 41 0x33 */
491 dev_wlc_bufvar_set(dev, "btc_params",
492 (char *)&buf_reg41va_dhcp_on[0],
493 sizeof(buf_reg41va_dhcp_on));
494 /* btc_params 68 0x190 */
495 dev_wlc_bufvar_set(dev, "btc_params",
496 (char *)&buf_reg68va_dhcp_on[0],
497 sizeof(buf_reg68va_dhcp_on));
498 saved_status = TRUE;
499
500 btco_inf->bt_state = BT_DHCP_START;
501 btco_inf->timer_on = 1;
502 mod_timer(&btco_inf->timer, btco_inf->timer.expires);
503 WL_TRACE(("enable BT DHCP Timer\n"));
504 }
505 }
506 else if (saved_status == TRUE) {
507 WL_ERR(("was called w/o DHCP OFF. Continue\n"));
508 }
509 }
510#ifdef OEM_ANDROID
511 else if (strnicmp((char *)&powermode_val, "2", strlen("2")) == 0)
512#else
513 else if (strnicmp((char *)&powermode_val, "0", strlen("0")) == 0)
514#endif
515 {
516
517#if defined(OEM_ANDROID) && defined(DHCP_SCAN_SUPPRESS)
518 /* Since DHCP is complete, enable the scan back */
519 wl_cfg80211_scan_suppress(dev, 0);
520#endif /* OEM_ANDROID */
521
522#ifdef PKT_FILTER_SUPPORT
523 dhd->dhcp_in_progress = 0;
524 WL_TRACE_HW4(("DHCP is complete \n"));
525
526 /* Enable packet filtering */
527 if (dhd->early_suspended) {
528 WL_TRACE_HW4(("DHCP is complete , enable packet filter!!!\n"));
529 dhd_enable_packet_filter(1, dhd);
530 }
531#endif /* PKT_FILTER_SUPPORT */
532
533 /* Restoring PM mode */
534#ifndef OEM_ANDROID
535 dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm));
536#endif
537
538 /* Stop any bt timer because DHCP session is done */
539 WL_TRACE(("disable BT DHCP Timer\n"));
540 if (btco_inf->timer_on) {
541 btco_inf->timer_on = 0;
542 del_timer_sync(&btco_inf->timer);
543
544 if (btco_inf->bt_state != BT_DHCP_IDLE) {
545 /* need to restore original btc flags & extra btc params */
546 WL_TRACE(("bt->bt_state:%d\n", btco_inf->bt_state));
547 /* wake up btcoex thread to restore btlags+params */
548 schedule_work(&btco_inf->work);
549 }
550 }
551
552 /* Restoring btc_flag paramter anyway */
553 if (saved_status == TRUE)
554 dev_wlc_bufvar_set(dev, "btc_flags",
555 (char *)&buf_flag7_default[0], sizeof(buf_flag7_default));
556
557 /* Restore original values */
558 if (saved_status == TRUE) {
559 regaddr = 66;
560 dev_wlc_intvar_set_reg(dev, "btc_params",
561 (char *)&regaddr, (char *)&saved_reg66);
562 regaddr = 41;
563 dev_wlc_intvar_set_reg(dev, "btc_params",
564 (char *)&regaddr, (char *)&saved_reg41);
565 regaddr = 68;
566 dev_wlc_intvar_set_reg(dev, "btc_params",
567 (char *)&regaddr, (char *)&saved_reg68);
568
569 WL_TRACE(("restore regs {66,41,68} <- 0x%x 0x%x 0x%x\n",
570 saved_reg66, saved_reg41, saved_reg68));
571 }
572 saved_status = FALSE;
573
574 }
575 else {
576 WL_ERR(("Unkwown yet power setting, ignored\n"));
577 }
578
579 snprintf(command, 3, "OK");
580
581 return (strlen("OK"));
582}
583#endif /* defined(OEM_ANDROID) */