| .. | .. |
|---|
| 1 | | -/* SPDX-License-Identifier: GPL-2.0 */ |
|---|
| 2 | 1 | /* |
|---|
| 3 | 2 | * Linux cfg80211 driver - Dongle Host Driver (DHD) related |
|---|
| 4 | 3 | * |
|---|
| 5 | | - * Copyright (C) 1999-2019, Broadcom Corporation |
|---|
| 6 | | - * |
|---|
| 4 | + * Portions of this code are copyright (c) 2022 Cypress Semiconductor Corporation |
|---|
| 5 | + * |
|---|
| 6 | + * Copyright (C) 1999-2017, Broadcom Corporation |
|---|
| 7 | + * |
|---|
| 7 | 8 | * Unless you and Broadcom execute a separate written software license |
|---|
| 8 | 9 | * agreement governing use of this software, this software is licensed to you |
|---|
| 9 | 10 | * under the terms of the GNU General Public License version 2 (the "GPL"), |
|---|
| 10 | 11 | * available at http://www.broadcom.com/licenses/GPLv2.php, with the |
|---|
| 11 | 12 | * following added to such license: |
|---|
| 12 | | - * |
|---|
| 13 | + * |
|---|
| 13 | 14 | * As a special exception, the copyright holders of this software give you |
|---|
| 14 | 15 | * permission to link this software with independent modules, and to copy and |
|---|
| 15 | 16 | * distribute the resulting executable under terms of your choice, provided that |
|---|
| .. | .. |
|---|
| 17 | 18 | * the license of that module. An independent module is a module which is not |
|---|
| 18 | 19 | * derived from this software. The special exception does not apply to any |
|---|
| 19 | 20 | * modifications of the software. |
|---|
| 20 | | - * |
|---|
| 21 | + * |
|---|
| 21 | 22 | * Notwithstanding the above, under no circumstances may you combine this |
|---|
| 22 | 23 | * software in any way with any other Broadcom software provided under a license |
|---|
| 23 | 24 | * other than the GPL, without Broadcom's express prior written consent. |
|---|
| .. | .. |
|---|
| 25 | 26 | * |
|---|
| 26 | 27 | * <<Broadcom-WL-IPTag/Open:>> |
|---|
| 27 | 28 | * |
|---|
| 28 | | - * $Id: wl_cfg_btcoex.c 709309 2019-01-17 09:04:00Z $ |
|---|
| 29 | + * $Id: wl_cfg_btcoex.c 814554 2019-04-11 23:06:22Z $ |
|---|
| 29 | 30 | */ |
|---|
| 30 | 31 | |
|---|
| 31 | 32 | #include <net/rtnetlink.h> |
|---|
| .. | .. |
|---|
| 43 | 44 | extern uint dhd_pkt_filter_enable; |
|---|
| 44 | 45 | extern uint dhd_master_mode; |
|---|
| 45 | 46 | extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode); |
|---|
| 46 | | -#endif |
|---|
| 47 | +#endif // endif |
|---|
| 47 | 48 | |
|---|
| 48 | 49 | struct btcoex_info { |
|---|
| 49 | | - struct timer_list timer; |
|---|
| 50 | + timer_list_compat_t timer; |
|---|
| 50 | 51 | u32 timer_ms; |
|---|
| 51 | 52 | u32 timer_on; |
|---|
| 52 | 53 | u32 ts_dhcp_start; /* ms ts ecord time stats */ |
|---|
| .. | .. |
|---|
| 59 | 60 | struct net_device *dev; |
|---|
| 60 | 61 | }; |
|---|
| 61 | 62 | |
|---|
| 63 | +#if defined(OEM_ANDROID) |
|---|
| 62 | 64 | static struct btcoex_info *btcoex_info_loc = NULL; |
|---|
| 63 | 65 | |
|---|
| 64 | 66 | /* TODO: clean up the BT-Coex code, it still have some legacy ioctl/iovar functions */ |
|---|
| .. | .. |
|---|
| 71 | 73 | #define BT_DHCP_OPPR_WIN_TIME 2500 |
|---|
| 72 | 74 | /* T2 turn off SCO/SCO supperesion is (timeout) */ |
|---|
| 73 | 75 | #define BT_DHCP_FLAG_FORCE_TIME 5500 |
|---|
| 76 | + |
|---|
| 77 | +#define BTCOEXMODE "BTCOEXMODE" |
|---|
| 78 | +#define POWERMODE "POWERMODE" |
|---|
| 74 | 79 | |
|---|
| 75 | 80 | enum wl_cfg80211_btcoex_status { |
|---|
| 76 | 81 | BT_DHCP_IDLE, |
|---|
| .. | .. |
|---|
| 93 | 98 | } var; |
|---|
| 94 | 99 | int error; |
|---|
| 95 | 100 | |
|---|
| 96 | | - bcm_mkiovar(name, (char *)(®), sizeof(reg), |
|---|
| 97 | | - (char *)(&var), sizeof(var.buf)); |
|---|
| 98 | | - error = wldev_ioctl(dev, WLC_GET_VAR, (char *)(&var), sizeof(var.buf), false); |
|---|
| 101 | + bzero(&var, sizeof(var)); |
|---|
| 102 | + error = bcm_mkiovar(name, (char *)(®), 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)); |
|---|
| 99 | 107 | |
|---|
| 100 | 108 | *retval = dtoh32(var.val); |
|---|
| 101 | 109 | return (error); |
|---|
| .. | .. |
|---|
| 104 | 112 | static int |
|---|
| 105 | 113 | dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len) |
|---|
| 106 | 114 | { |
|---|
| 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) */ |
|---|
| 115 | + char ioctlbuf_local[WLC_IOCTL_SMLEN]; |
|---|
| 116 | + int ret; |
|---|
| 112 | 117 | |
|---|
| 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)); |
|---|
| 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)); |
|---|
| 116 | 122 | } |
|---|
| 123 | + |
|---|
| 117 | 124 | /* |
|---|
| 118 | 125 | get named driver variable to uint register value and return error indication |
|---|
| 119 | 126 | calling example: dev_wlc_intvar_set_reg(dev, "btc_params",66, value) |
|---|
| .. | .. |
|---|
| 123 | 130 | { |
|---|
| 124 | 131 | char reg_addr[8]; |
|---|
| 125 | 132 | |
|---|
| 126 | | - memset(reg_addr, 0, sizeof(reg_addr)); |
|---|
| 133 | + bzero(reg_addr, sizeof(reg_addr)); |
|---|
| 127 | 134 | memcpy((char *)®_addr[0], (char *)addr, 4); |
|---|
| 128 | 135 | memcpy((char *)®_addr[4], (char *)val, 4); |
|---|
| 129 | 136 | |
|---|
| .. | .. |
|---|
| 276 | 283 | #if defined(BT_DHCP_USE_FLAGS) |
|---|
| 277 | 284 | char buf_flag7_dhcp_on[8] = { 7, 00, 00, 00, 0x1, 0x0, 0x00, 0x00 }; |
|---|
| 278 | 285 | char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00}; |
|---|
| 279 | | -#endif |
|---|
| 280 | | - |
|---|
| 286 | +#endif // endif |
|---|
| 281 | 287 | |
|---|
| 282 | 288 | #if defined(BT_DHCP_eSCO_FIX) |
|---|
| 283 | 289 | /* set = 1, save & turn on 0 - off & restore prev settings */ |
|---|
| 284 | 290 | set_btc_esco_params(dev, set); |
|---|
| 285 | | -#endif |
|---|
| 291 | +#endif // endif |
|---|
| 286 | 292 | |
|---|
| 287 | 293 | #if defined(BT_DHCP_USE_FLAGS) |
|---|
| 288 | 294 | WL_TRACE(("WI-FI priority boost via bt flags, set:%d\n", set)); |
|---|
| .. | .. |
|---|
| 296 | 302 | dev_wlc_bufvar_set(dev, "btc_flags", |
|---|
| 297 | 303 | (char *)&buf_flag7_default[0], |
|---|
| 298 | 304 | sizeof(buf_flag7_default)); |
|---|
| 299 | | -#endif |
|---|
| 305 | +#endif // endif |
|---|
| 300 | 306 | } |
|---|
| 301 | 307 | |
|---|
| 302 | | -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)) |
|---|
| 303 | | -static void wl_cfg80211_bt_timerfunc(struct timer_list *t) |
|---|
| 304 | | -{ |
|---|
| 305 | | - struct btcoex_info *bt_local = from_timer(bt_local, t, timer); |
|---|
| 306 | | -#else |
|---|
| 307 | 308 | static void wl_cfg80211_bt_timerfunc(ulong data) |
|---|
| 308 | 309 | { |
|---|
| 309 | 310 | struct btcoex_info *bt_local = (struct btcoex_info *)data; |
|---|
| 310 | | -#endif |
|---|
| 311 | 311 | WL_TRACE(("Enter\n")); |
|---|
| 312 | 312 | bt_local->timer_on = 0; |
|---|
| 313 | 313 | schedule_work(&bt_local->work); |
|---|
| .. | .. |
|---|
| 317 | 317 | { |
|---|
| 318 | 318 | struct btcoex_info *btcx_inf; |
|---|
| 319 | 319 | |
|---|
| 320 | + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); |
|---|
| 320 | 321 | btcx_inf = container_of(work, struct btcoex_info, work); |
|---|
| 322 | + GCC_DIAGNOSTIC_POP(); |
|---|
| 321 | 323 | |
|---|
| 322 | 324 | if (btcx_inf->timer_on) { |
|---|
| 323 | 325 | btcx_inf->timer_on = 0; |
|---|
| .. | .. |
|---|
| 397 | 399 | btco_inf->ts_dhcp_ok = 0; |
|---|
| 398 | 400 | /* Set up timer for BT */ |
|---|
| 399 | 401 | btco_inf->timer_ms = 10; |
|---|
| 400 | | -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)) |
|---|
| 401 | | - timer_setup(&btco_inf->timer, wl_cfg80211_bt_timerfunc, 0); |
|---|
| 402 | | -#else |
|---|
| 403 | | - init_timer(&btco_inf->timer); |
|---|
| 404 | | - btco_inf->timer.data = (ulong)btco_inf; |
|---|
| 405 | | - btco_inf->timer.function = wl_cfg80211_bt_timerfunc; |
|---|
| 406 | | -#endif |
|---|
| 402 | + init_timer_compat(&btco_inf->timer, wl_cfg80211_bt_timerfunc, btco_inf); |
|---|
| 407 | 403 | |
|---|
| 408 | 404 | btco_inf->dev = ndev; |
|---|
| 409 | 405 | |
|---|
| .. | .. |
|---|
| 431 | 427 | int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, dhd_pub_t *dhd, char *command) |
|---|
| 432 | 428 | { |
|---|
| 433 | 429 | |
|---|
| 430 | +#ifndef OEM_ANDROID |
|---|
| 431 | + static int pm = PM_FAST; |
|---|
| 432 | + int pm_local = PM_OFF; |
|---|
| 433 | +#endif /* OEM_ANDROID */ |
|---|
| 434 | 434 | struct btcoex_info *btco_inf = btcoex_info_loc; |
|---|
| 435 | 435 | char powermode_val = 0; |
|---|
| 436 | + uint8 cmd_len = 0; |
|---|
| 436 | 437 | char buf_reg66va_dhcp_on[8] = { 66, 00, 00, 00, 0x10, 0x27, 0x00, 0x00 }; |
|---|
| 437 | 438 | char buf_reg41va_dhcp_on[8] = { 41, 00, 00, 00, 0x33, 0x00, 0x00, 0x00 }; |
|---|
| 438 | 439 | char buf_reg68va_dhcp_on[8] = { 68, 00, 00, 00, 0x90, 0x01, 0x00, 0x00 }; |
|---|
| .. | .. |
|---|
| 446 | 447 | char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00}; |
|---|
| 447 | 448 | |
|---|
| 448 | 449 | /* Figure out powermode 1 or o command */ |
|---|
| 449 | | - strncpy((char *)&powermode_val, command + strlen("BTCOEXMODE") +1, 1); |
|---|
| 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]; |
|---|
| 450 | 456 | |
|---|
| 451 | | - if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) { |
|---|
| 457 | + if (powermode_val == '1') { |
|---|
| 452 | 458 | WL_TRACE_HW4(("DHCP session starts\n")); |
|---|
| 453 | | - |
|---|
| 454 | 459 | |
|---|
| 455 | 460 | #ifdef PKT_FILTER_SUPPORT |
|---|
| 456 | 461 | dhd->dhcp_in_progress = 1; |
|---|
| 457 | 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 */ |
|---|
| 458 | 471 | if (dhd->early_suspended) { |
|---|
| 459 | 472 | WL_TRACE_HW4(("DHCP in progressing , disable packet filter!!!\n")); |
|---|
| 460 | 473 | dhd_enable_packet_filter(0, dhd); |
|---|
| 461 | 474 | } |
|---|
| 462 | | -#endif |
|---|
| 475 | +#endif /* PKT_FILTER_SUPPORT */ |
|---|
| 463 | 476 | |
|---|
| 464 | 477 | /* Retrieve and saved orig regs value */ |
|---|
| 465 | 478 | if ((saved_status == FALSE) && |
|---|
| 479 | +#ifndef OEM_ANDROID |
|---|
| 480 | + (!dev_wlc_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm))) && |
|---|
| 481 | +#endif // endif |
|---|
| 466 | 482 | (!dev_wlc_intvar_get_reg(dev, "btc_params", 66, &saved_reg66)) && |
|---|
| 467 | 483 | (!dev_wlc_intvar_get_reg(dev, "btc_params", 41, &saved_reg41)) && |
|---|
| 468 | 484 | (!dev_wlc_intvar_get_reg(dev, "btc_params", 68, &saved_reg68))) { |
|---|
| .. | .. |
|---|
| 471 | 487 | saved_reg66, saved_reg41, saved_reg68)); |
|---|
| 472 | 488 | |
|---|
| 473 | 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 |
|---|
| 474 | 493 | |
|---|
| 475 | 494 | /* Disable PM mode during dhpc session */ |
|---|
| 476 | 495 | /* Start BT timer only for SCO connection */ |
|---|
| .. | .. |
|---|
| 491 | 510 | |
|---|
| 492 | 511 | btco_inf->bt_state = BT_DHCP_START; |
|---|
| 493 | 512 | btco_inf->timer_on = 1; |
|---|
| 494 | | - mod_timer(&btco_inf->timer, btco_inf->timer.expires); |
|---|
| 513 | + mod_timer(&btco_inf->timer, |
|---|
| 514 | + timer_expires(&btco_inf->timer)); |
|---|
| 495 | 515 | WL_TRACE(("enable BT DHCP Timer\n")); |
|---|
| 496 | 516 | } |
|---|
| 497 | 517 | } |
|---|
| .. | .. |
|---|
| 499 | 519 | WL_ERR(("was called w/o DHCP OFF. Continue\n")); |
|---|
| 500 | 520 | } |
|---|
| 501 | 521 | } |
|---|
| 502 | | - else if (strnicmp((char *)&powermode_val, "2", strlen("2")) == 0) { |
|---|
| 503 | | - |
|---|
| 504 | | - |
|---|
| 522 | +#ifdef OEM_ANDROID |
|---|
| 523 | + else if (powermode_val == '2') { |
|---|
| 524 | +#else |
|---|
| 525 | + else if (powermode_val == '0') { |
|---|
| 526 | +#endif // endif |
|---|
| 505 | 527 | |
|---|
| 506 | 528 | #ifdef PKT_FILTER_SUPPORT |
|---|
| 507 | 529 | dhd->dhcp_in_progress = 0; |
|---|
| 508 | 530 | WL_TRACE_HW4(("DHCP is complete \n")); |
|---|
| 509 | 531 | |
|---|
| 510 | | - /* Enable packet filtering */ |
|---|
| 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 */ |
|---|
| 511 | 538 | if (dhd->early_suspended) { |
|---|
| 539 | + /* Enable packet filtering */ |
|---|
| 512 | 540 | WL_TRACE_HW4(("DHCP is complete , enable packet filter!!!\n")); |
|---|
| 513 | 541 | dhd_enable_packet_filter(1, dhd); |
|---|
| 514 | 542 | } |
|---|
| 515 | 543 | #endif /* PKT_FILTER_SUPPORT */ |
|---|
| 516 | 544 | |
|---|
| 517 | 545 | /* Restoring PM mode */ |
|---|
| 546 | +#ifndef OEM_ANDROID |
|---|
| 547 | + dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm)); |
|---|
| 548 | +#endif // endif |
|---|
| 518 | 549 | |
|---|
| 519 | 550 | /* Stop any bt timer because DHCP session is done */ |
|---|
| 520 | 551 | WL_TRACE(("disable BT DHCP Timer\n")); |
|---|
| .. | .. |
|---|
| 557 | 588 | WL_ERR(("Unkwown yet power setting, ignored\n")); |
|---|
| 558 | 589 | } |
|---|
| 559 | 590 | |
|---|
| 560 | | - snprintf(command, 3, "OK"); |
|---|
| 561 | | - |
|---|
| 562 | | - return (strlen("OK")); |
|---|
| 591 | + return (snprintf(command, sizeof("OK"), "OK") + 1); |
|---|
| 563 | 592 | } |
|---|
| 593 | +#endif /* defined(OEM_ANDROID) */ |
|---|