From cde9070d9970eef1f7ec2360586c802a16230ad8 Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Fri, 10 May 2024 07:43:50 +0000 Subject: [PATCH] rtl88x2CE_WiFi_linux driver --- kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/dhd_cfg80211.c | 378 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 files changed, 341 insertions(+), 37 deletions(-) diff --git a/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/dhd_cfg80211.c b/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/dhd_cfg80211.c index 931e6a8..ac9be84 100644 --- a/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/dhd_cfg80211.c +++ b/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/dhd_cfg80211.c @@ -1,15 +1,16 @@ -/* SPDX-License-Identifier: GPL-2.0 */ /* * Linux cfg80211 driver - Dongle Host Driver (DHD) related * - * Copyright (C) 1999-2019, Broadcom Corporation - * + * Portions of this code are copyright (c) 2022 Cypress Semiconductor Corporation + * + * Copyright (C) 1999-2017, Broadcom Corporation + * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2 (the "GPL"), * available at http://www.broadcom.com/licenses/GPLv2.php, with the * following added to such license: - * + * * As a special exception, the copyright holders of this software give you * permission to link this software with independent modules, and to copy and * distribute the resulting executable under terms of your choice, provided that @@ -17,7 +18,7 @@ * the license of that module. An independent module is a module which is not * derived from this software. The special exception does not apply to any * modifications of the software. - * + * * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. @@ -25,7 +26,7 @@ * * <<Broadcom-WL-IPTag/Open:>> * - * $Id: wl_cfg80211.c,v 1.1.4.1.2.14 2011/02/09 01:40:07 Exp $ + * $Id: dhd_cfg80211.c 696903 2017-04-28 19:48:01Z $ */ #include <linux/vmalloc.h> @@ -39,15 +40,13 @@ #ifdef PKT_FILTER_SUPPORT #include <dngl_stats.h> #include <dhd.h> -#endif - -extern struct bcm_cfg80211 *g_bcm_cfg; +#endif // endif #ifdef PKT_FILTER_SUPPORT extern uint dhd_pkt_filter_enable; extern uint dhd_master_mode; extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode); -#endif +#endif // endif static int dhd_dongle_up = FALSE; @@ -60,6 +59,16 @@ static s32 wl_dongle_up(struct net_device *ndev); static s32 wl_dongle_down(struct net_device *ndev); +#ifndef OEM_ANDROID +static s32 wl_dongle_power(struct net_device *ndev, u32 power_mode); +#ifdef BCMSDIO /* glomming is a sdio specific feature */ +static s32 wl_dongle_glom(struct net_device *ndev, s32 glom, u32 dongle_align); +#endif // endif +static s32 wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time, s32 scan_unassoc_time); +static s32 wl_dongle_offload(struct net_device *ndev, s32 arpoe, s32 arp_ol); +static s32 wl_pattern_atoh(s8 *src, s8 *dst); +static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode); +#endif /* OEM_ANDROID */ /** * Function implementations @@ -81,17 +90,19 @@ { struct net_device *ndev; s32 err = 0; + dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); WL_TRACE(("In\n")); - if (!dhd_dongle_up) { - WL_ERR(("Dongle is already down\n")); - return err; + if ((!dhd_dongle_up) || (!dhd->up)) { + WL_INFORM_MEM(("Dongle is already down\n")); + err = 0; + goto done; } - ndev = bcmcfg_to_prmry_ndev(cfg); wl_dongle_down(ndev); +done: dhd_dongle_up = FALSE; - return 0; + return err; } s32 dhd_cfg80211_set_p2p_info(struct bcm_cfg80211 *cfg, int val) @@ -127,27 +138,55 @@ return 0; } -struct net_device* wl_cfg80211_allocate_if(struct bcm_cfg80211 *cfg, int ifidx, char *name, - uint8 *mac, uint8 bssidx, char *dngl_name) +#ifdef WL_STATIC_IF +int32 +wl_cfg80211_update_iflist_info(struct bcm_cfg80211 *cfg, struct net_device *ndev, + int ifidx, uint8 *addr, int bssidx, char *name, int if_state) +{ + return dhd_update_iflist_info(cfg->pub, ndev, ifidx, addr, bssidx, name, if_state); +} +#endif /* WL_STATIC_IF */ + +struct net_device* wl_cfg80211_allocate_if(struct bcm_cfg80211 *cfg, int ifidx, const char *name, + uint8 *mac, uint8 bssidx, const char *dngl_name) { return dhd_allocate_if(cfg->pub, ifidx, name, mac, bssidx, FALSE, dngl_name); } -int wl_cfg80211_register_if(struct bcm_cfg80211 *cfg, int ifidx, struct net_device* ndev) +int wl_cfg80211_register_if(struct bcm_cfg80211 *cfg, + int ifidx, struct net_device* ndev, bool rtnl_lock_reqd) { - return dhd_register_if(cfg->pub, ifidx, FALSE); + return dhd_register_if(cfg->pub, ifidx, rtnl_lock_reqd); } -int wl_cfg80211_remove_if(struct bcm_cfg80211 *cfg, int ifidx, struct net_device* ndev) +int wl_cfg80211_remove_if(struct bcm_cfg80211 *cfg, + int ifidx, struct net_device* ndev, bool rtnl_lock_reqd) { - return dhd_remove_if(cfg->pub, ifidx, FALSE); +#ifdef DHD_PCIE_RUNTIMEPM + dhdpcie_runtime_bus_wake(cfg->pub, CAN_SLEEP(), __builtin_return_address(0)); +#endif /* DHD_PCIE_RUNTIMEPM */ + return dhd_remove_if(cfg->pub, ifidx, rtnl_lock_reqd); +} + +void wl_cfg80211_cleanup_if(struct net_device *net) +{ + struct bcm_cfg80211 *cfg = wl_get_cfg(net); +#ifdef DHD_PCIE_RUNTIMEPM + dhdpcie_runtime_bus_wake(cfg->pub, CAN_SLEEP(), __builtin_return_address(0)); +#else + BCM_REFERENCE(cfg); +#endif /* DHD_PCIE_RUNTIMEPM */ + dhd_cleanup_if(net); } struct net_device * dhd_cfg80211_netdev_free(struct net_device *ndev) { + struct bcm_cfg80211 *cfg; + if (ndev) { + cfg = wl_get_cfg(ndev); if (ndev->ieee80211_ptr) { - kfree(ndev->ieee80211_ptr); + MFREE(cfg->osh, ndev->ieee80211_ptr, sizeof(struct wireless_dev)); ndev->ieee80211_ptr = NULL; } free_netdev(ndev); @@ -161,7 +200,7 @@ { #ifdef WL_CFG80211 ndev = dhd_cfg80211_netdev_free(ndev); -#endif +#endif // endif if (ndev) free_netdev(ndev); } @@ -170,9 +209,9 @@ wl_dongle_up(struct net_device *ndev) { s32 err = 0; - u32 up = 0; + u32 local_up = 0; - err = wldev_ioctl(ndev, WLC_UP, &up, sizeof(up), true); + err = wldev_ioctl_set(ndev, WLC_UP, &local_up, sizeof(local_up)); if (unlikely(err)) { WL_ERR(("WLC_UP error (%d)\n", err)); } @@ -183,23 +222,269 @@ wl_dongle_down(struct net_device *ndev) { s32 err = 0; - u32 down = 0; + u32 local_down = 0; - err = wldev_ioctl(ndev, WLC_DOWN, &down, sizeof(down), true); + err = wldev_ioctl_set(ndev, WLC_DOWN, &local_down, sizeof(local_down)); if (unlikely(err)) { WL_ERR(("WLC_DOWN error (%d)\n", err)); } return err; } +#ifndef OEM_ANDROID +static s32 wl_dongle_power(struct net_device *ndev, u32 power_mode) +{ + s32 err = 0; + + WL_TRACE(("In\n")); + err = wldev_ioctl_set(ndev, WLC_SET_PM, &power_mode, sizeof(power_mode)); + if (unlikely(err)) { + WL_ERR(("WLC_SET_PM error (%d)\n", err)); + } + return err; +} + +#ifdef BCMSDIO +static s32 +wl_dongle_glom(struct net_device *ndev, s32 glom, u32 dongle_align) +{ + s32 err = 0; + + /* Match Host and Dongle rx alignment */ + err = wldev_iovar_setint(ndev, "bus:txglomalign", dongle_align); + if (unlikely(err)) { + WL_ERR(("txglomalign error (%d)\n", err)); + goto dongle_glom_out; + } + /* disable glom option per default */ + if (glom != DEFAULT_GLOM_VALUE) { + err = wldev_iovar_setint(ndev, "bus:txglom", glom); + if (unlikely(err)) { + WL_ERR(("txglom error (%d)\n", err)); + goto dongle_glom_out; + } + } +dongle_glom_out: + return err; +} + +#endif /* BCMSDIO */ +#endif /* OEM_ANDROID */ + +s32 +wl_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout) +{ + s32 err = 0; + + /* Setup timeout if Beacons are lost and roam is off to report link down */ + if (roamvar) { + err = wldev_iovar_setint(ndev, "bcn_timeout", bcn_timeout); + if (unlikely(err)) { + WL_ERR(("bcn_timeout error (%d)\n", err)); + goto dongle_rom_out; + } + } + /* Enable/Disable built-in roaming to allow supplicant to take care of roaming */ + err = wldev_iovar_setint(ndev, "roam_off", roamvar); + if (unlikely(err)) { + WL_ERR(("roam_off error (%d)\n", err)); + goto dongle_rom_out; + } +dongle_rom_out: + return err; +} + +#ifndef OEM_ANDROID +static s32 +wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time, + s32 scan_unassoc_time) +{ + s32 err = 0; + + err = wldev_ioctl_set(ndev, WLC_SET_SCAN_CHANNEL_TIME, &scan_assoc_time, + sizeof(scan_assoc_time)); + if (err) { + if (err == -EOPNOTSUPP) { + WL_INFORM(("Scan assoc time is not supported\n")); + } else { + WL_ERR(("Scan assoc time error (%d)\n", err)); + } + goto dongle_scantime_out; + } + err = wldev_ioctl_set(ndev, WLC_SET_SCAN_UNASSOC_TIME, &scan_unassoc_time, + sizeof(scan_unassoc_time)); + if (err) { + if (err == -EOPNOTSUPP) { + WL_INFORM(("Scan unassoc time is not supported\n")); + } else { + WL_ERR(("Scan unassoc time error (%d)\n", err)); + } + goto dongle_scantime_out; + } + +dongle_scantime_out: + return err; +} + +static s32 +wl_dongle_offload(struct net_device *ndev, s32 arpoe, s32 arp_ol) +{ + s8 iovbuf[WLC_IOCTL_SMLEN]; + s32 err = 0; + s32 len; + + /* Set ARP offload */ + len = bcm_mkiovar("arpoe", (char *)&arpoe, sizeof(arpoe), iovbuf, sizeof(iovbuf)); + if (!len) { + WL_ERR(("%s: bcm_mkiovar failed:%d\n", __FUNCTION__, len)); + return BCME_BADARG; + } + err = wldev_ioctl_set(ndev, WLC_SET_VAR, iovbuf, len); + if (err) { + if (err == -EOPNOTSUPP) + WL_INFORM(("arpoe is not supported\n")); + else + WL_ERR(("arpoe error (%d)\n", err)); + + goto dongle_offload_out; + } + len = bcm_mkiovar("arp_ol", (char *)&arp_ol, sizeof(arp_ol), iovbuf, sizeof(iovbuf)); + if (!len) { + WL_ERR(("%s: bcm_mkiovar failed:%d\n", __FUNCTION__, len)); + return BCME_BADARG; + } + err = wldev_ioctl_set(ndev, WLC_SET_VAR, iovbuf, len); + if (err) { + if (err == -EOPNOTSUPP) + WL_INFORM(("arp_ol is not supported\n")); + else + WL_ERR(("arp_ol error (%d)\n", err)); + + goto dongle_offload_out; + } + +dongle_offload_out: + return err; +} + +static s32 wl_pattern_atoh(s8 *src, s8 *dst) +{ + int i; + if (strncmp(src, "0x", 2) != 0 && strncmp(src, "0X", 2) != 0) { + WL_ERR(("Mask invalid format. Needs to start with 0x\n")); + return -1; + } + src = src + 2; /* Skip past 0x */ + if (strlen(src) % 2 != 0) { + WL_ERR(("Mask invalid format. Needs to be of even length\n")); + return -1; + } + for (i = 0; *src != '\0'; i++) { + char num[3]; + strncpy(num, src, 2); + num[2] = '\0'; + dst[i] = (u8) simple_strtoul(num, NULL, 16); + src += 2; + } + return i; +} + +static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode) +{ + const s8 *str; + struct wl_pkt_filter pkt_filter; + struct wl_pkt_filter *pkt_filterp; + s32 buf_len; + s32 str_len; + u32 mask_size; + u32 pattern_size; + s8 buf[64] = {0}; + s32 err = 0; + + /* add a default packet filter pattern */ + str = "pkt_filter_add"; + str_len = strlen(str); + strncpy(buf, str, sizeof(buf) - 1); + buf[ sizeof(buf) - 1 ] = '\0'; + buf_len = str_len + 1; + + pkt_filterp = (struct wl_pkt_filter *)(buf + str_len + 1); + + /* Parse packet filter id. */ + pkt_filter.id = htod32(100); + + /* Parse filter polarity. */ + pkt_filter.negate_match = htod32(0); + + /* Parse filter type. */ + pkt_filter.type = htod32(0); + + /* Parse pattern filter offset. */ + pkt_filter.u.pattern.offset = htod32(0); + + /* Parse pattern filter mask. */ + mask_size = htod32(wl_pattern_atoh("0xff", + (char *)pkt_filterp->u.pattern. + mask_and_pattern)); + + /* Parse pattern filter pattern. */ + pattern_size = htod32(wl_pattern_atoh("0x00", + (char *)&pkt_filterp->u.pattern.mask_and_pattern[mask_size])); + + if (mask_size != pattern_size) { + WL_ERR(("Mask and pattern not the same size\n")); + err = -EINVAL; + goto dongle_filter_out; + } + + pkt_filter.u.pattern.size_bytes = mask_size; + buf_len += WL_PKT_FILTER_FIXED_LEN; + buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size); + + /* Keep-alive attributes are set in local + * variable (keep_alive_pkt), and + * then memcpy'ed into buffer (keep_alive_pktp) since there is no + * guarantee that the buffer is properly aligned. + */ + memcpy((char *)pkt_filterp, &pkt_filter, + WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN); + + err = wldev_ioctl_set(ndev, WLC_SET_VAR, buf, buf_len); + if (err) { + if (err == -EOPNOTSUPP) { + WL_INFORM(("filter not supported\n")); + } else { + WL_ERR(("filter (%d)\n", err)); + } + goto dongle_filter_out; + } + + /* set mode to allow pattern */ + err = wldev_iovar_setint(ndev, "pkt_filter_mode", filter_mode); + if (err) { + if (err == -EOPNOTSUPP) { + WL_INFORM(("filter_mode not supported\n")); + } else { + WL_ERR(("filter_mode (%d)\n", err)); + } + goto dongle_filter_out; + } + +dongle_filter_out: + return err; +} +#endif /* OEM_ANDROID */ s32 dhd_config_dongle(struct bcm_cfg80211 *cfg) { #ifndef DHD_SDALIGN #define DHD_SDALIGN 32 -#endif +#endif // endif struct net_device *ndev; s32 err = 0; +#if !defined(OEM_ANDROID) && defined(BCMSDIO) + s32 glom = CUSTOM_GLOM_SETTING; +#endif // endif WL_TRACE(("In\n")); if (dhd_dongle_up) { @@ -214,6 +499,32 @@ WL_ERR(("wl_dongle_up failed\n")); goto default_conf_out; } +#ifndef OEM_ANDROID + err = wl_dongle_power(ndev, PM_FAST); + if (unlikely(err)) { + WL_ERR(("wl_dongle_power failed\n")); + goto default_conf_out; + } +#ifdef BCMSDIO + if (glom != DEFAULT_GLOM_VALUE) { + err = wl_dongle_glom(ndev, glom, DHD_SDALIGN); + } else { + err = wl_dongle_glom(ndev, DEFAULT_GLOM_VALUE, DHD_SDALIGN); + } + if (unlikely(err)) { + WL_ERR(("wl_dongle_glom failed\n")); + goto default_conf_out; + } +#endif /* BCMSDIO */ + err = wl_dongle_roam(ndev, (cfg->roam_on ? 0 : 1), 3); + if (unlikely(err)) { + WL_ERR(("wl_dongle_roam failed\n")); + goto default_conf_out; + } + wl_dongle_scantime(ndev, 40, 80); + wl_dongle_offload(ndev, 1, 0xf); + wl_dongle_filter(ndev, 1); +#endif /* OEM_ANDROID */ dhd_dongle_up = true; default_conf_out: @@ -227,7 +538,7 @@ { struct net_device *ndev = NULL; dhd_pub_t *dhd; - dhd_ioctl_t ioc = { 0 }; + dhd_ioctl_t ioc = { 0, NULL, 0, 0, 0, 0, 0}; int ret = 0; int8 index; @@ -235,14 +546,6 @@ dhd = cfg->pub; DHD_OS_WAKE_LOCK(dhd); - - /* send to dongle only if we are not waiting for reload already */ - if (dhd->hang_was_sent) { - WL_ERR(("HANG was sent up earlier\n")); - DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhd, DHD_EVENT_TIMEOUT_MS); - DHD_OS_WAKE_UNLOCK(dhd); - return OSL_ERROR(BCME_DONGLE_DOWN); - } ndev = wdev_to_wlc_ndev(wdev, cfg); index = dhd_net2idx(dhd->info, ndev); @@ -256,6 +559,7 @@ ioc.len = nlioc->len; ioc.set = nlioc->set; ioc.driver = nlioc->magic; + ioc.buf = buf; ret = dhd_ioctl_process(dhd, index, &ioc, buf); if (ret) { WL_TRACE(("dhd_ioctl_process return err %d\n", ret)); -- Gitblit v1.6.2