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_ip.c | 352 ++++++++++++++++++++++++++++++++++++++++++---------------- 1 files changed, 254 insertions(+), 98 deletions(-) diff --git a/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/dhd_ip.c b/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/dhd_ip.c index 96b1a2f..aef39ba 100644 --- a/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/dhd_ip.c +++ b/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/dhd_ip.c @@ -1,15 +1,16 @@ -/* SPDX-License-Identifier: GPL-2.0 */ /* * IP Packet Parser Module. * - * 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,26 +26,26 @@ * * <<Broadcom-WL-IPTag/Open:>> * - * $Id: dhd_ip.c 709309 2019-01-17 09:04:00Z $ + * $Id: dhd_ip.c 700444 2017-05-19 06:38:00Z $ */ #include <typedefs.h> #include <osl.h> -#include <proto/ethernet.h> -#include <proto/vlan.h> -#include <proto/802.3.h> -#include <proto/bcmip.h> +#include <ethernet.h> +#include <vlan.h> +#include <802.3.h> +#include <bcmip.h> #include <bcmendian.h> #include <dhd_dbg.h> #include <dhd_ip.h> -#ifdef DHDTCPACK_SUPPRESS +#if defined(DHDTCPACK_SUPPRESS) || defined(DHDTCPSYNC_FLOOD_BLK) #include <dhd_bus.h> #include <dhd_proto.h> -#include <proto/bcmtcp.h> -#endif /* DHDTCPACK_SUPPRESS */ +#include <bcmtcp.h> +#endif /* DHDTCPACK_SUPPRESS || DHDTCPSYNC_FLOOD_BLK */ /* special values */ /* 802.3 llc/snap header */ @@ -128,7 +129,15 @@ int ifidx; uint8 supp_cnt; dhd_pub_t *dhdp; - struct timer_list timer; +#ifndef TCPACK_SUPPRESS_HOLD_HRT + timer_list_compat_t timer; +#else +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(5, 1, 21)) + struct tasklet_hrtimer timer; +#else + struct hrtimer timer; +#endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(5, 1, 21) */ +#endif /* TCPACK_SUPPRESS_HOLD_HRT */ } tcpack_info_t; typedef struct _tdata_psh_info_t { @@ -182,7 +191,7 @@ tcpack_sup_mod->tdata_psh_info_free = tdata_psh_info; #ifdef DHDTCPACK_SUP_DBG tcpack_sup_mod->psh_info_enq_num++; -#endif +#endif // endif } static tdata_psh_info_t* @@ -290,44 +299,54 @@ } #endif /* BCMSDIO */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)) -static void dhd_tcpack_send(struct timer_list *t) -{ - tcpack_info_t *cur_tbl = from_timer(cur_tbl, t, timer); -#else +#ifdef BCMPCIE +#ifndef TCPACK_SUPPRESS_HOLD_HRT static void dhd_tcpack_send(ulong data) +#else +static enum hrtimer_restart dhd_tcpack_send(struct hrtimer *timer) +#endif /* TCPACK_SUPPRESS_HOLD_HRT */ { - tcpack_info_t *cur_tbl = (tcpack_info_t *)data; -#endif tcpack_sup_module_t *tcpack_sup_mod; + tcpack_info_t *cur_tbl; dhd_pub_t *dhdp; int ifidx; void* pkt; unsigned long flags; +#ifndef TCPACK_SUPPRESS_HOLD_HRT + cur_tbl = (tcpack_info_t *)data; +#else + cur_tbl = container_of(timer, tcpack_info_t, timer.timer); +#endif /* TCPACK_SUPPRESS_HOLD_HRT */ + if (!cur_tbl) { - return; + goto done; } dhdp = cur_tbl->dhdp; if (!dhdp) { - return; + goto done; } flags = dhd_os_tcpacklock(dhdp); + + if (unlikely(dhdp->tcpack_sup_mode != TCPACK_SUP_HOLD)) { + dhd_os_tcpackunlock(dhdp, flags); + goto done; + } tcpack_sup_mod = dhdp->tcpack_sup_module; if (!tcpack_sup_mod) { DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__, __LINE__)); dhd_os_tcpackunlock(dhdp, flags); - return; + goto done; } pkt = cur_tbl->pkt_in_q; ifidx = cur_tbl->ifidx; if (!pkt) { dhd_os_tcpackunlock(dhdp, flags); - return; + goto done; } cur_tbl->pkt_in_q = NULL; cur_tbl->pkt_ether_hdr = NULL; @@ -341,99 +360,169 @@ dhd_os_tcpackunlock(dhdp, flags); dhd_sendpkt(dhdp, ifidx, pkt); + +done: +#ifndef TCPACK_SUPPRESS_HOLD_HRT + return; +#else + return HRTIMER_NORESTART; +#endif /* TCPACK_SUPPRESS_HOLD_HRT */ } +#endif /* BCMPCIE */ int dhd_tcpack_suppress_set(dhd_pub_t *dhdp, uint8 mode) { int ret = BCME_OK; unsigned long flags; + tcpack_sup_module_t *tcpack_sup_module; + uint8 invalid_mode = FALSE; + int prev_mode; + int i = 0; flags = dhd_os_tcpacklock(dhdp); + tcpack_sup_module = dhdp->tcpack_sup_module; + prev_mode = dhdp->tcpack_sup_mode; - if (dhdp->tcpack_sup_mode == mode) { + if (prev_mode == mode) { DHD_ERROR(("%s %d: already set to %d\n", __FUNCTION__, __LINE__, mode)); goto exit; } - if (mode >= TCPACK_SUP_LAST_MODE || -#ifndef BCMSDIO - mode == TCPACK_SUP_DELAYTX || -#endif /* !BCMSDIO */ - FALSE) { - DHD_ERROR(("%s %d: Invalid mode %d\n", __FUNCTION__, __LINE__, mode)); + invalid_mode |= (mode >= TCPACK_SUP_LAST_MODE); +#ifdef BCMSDIO + invalid_mode |= (mode == TCPACK_SUP_HOLD); +#endif /* BCMSDIO */ +#ifdef BCMPCIE + invalid_mode |= ((mode == TCPACK_SUP_REPLACE) || (mode == TCPACK_SUP_DELAYTX)); +#endif /* BCMPCIE */ + + if (invalid_mode) { + DHD_ERROR(("%s %d: Invalid TCP ACK Suppress mode %d\n", + __FUNCTION__, __LINE__, mode)); ret = BCME_BADARG; goto exit; } - DHD_TRACE(("%s: %d -> %d\n", + DHD_TRACE(("%s: TCP ACK Suppress mode %d -> mode %d\n", __FUNCTION__, dhdp->tcpack_sup_mode, mode)); + /* Pre-process routines to change a new mode as per previous mode */ + switch (prev_mode) { + case TCPACK_SUP_OFF: + if (tcpack_sup_module == NULL) { + tcpack_sup_module = MALLOC(dhdp->osh, sizeof(tcpack_sup_module_t)); + if (tcpack_sup_module == NULL) { + DHD_ERROR(("%s[%d]: Failed to allocate the new memory for " + "tcpack_sup_module\n", __FUNCTION__, __LINE__)); + dhdp->tcpack_sup_mode = TCPACK_SUP_OFF; + ret = BCME_NOMEM; + goto exit; + } + dhdp->tcpack_sup_module = tcpack_sup_module; + } + bzero(tcpack_sup_module, sizeof(tcpack_sup_module_t)); + break; #ifdef BCMSDIO - /* Old tcpack_sup_mode is TCPACK_SUP_DELAYTX */ - if (dhdp->tcpack_sup_mode == TCPACK_SUP_DELAYTX) { - tcpack_sup_module_t *tcpack_sup_mod = dhdp->tcpack_sup_module; - /* We won't need tdata_psh_info pool and tcpddata_info_tbl anymore */ - _tdata_psh_info_pool_deinit(dhdp, tcpack_sup_mod); - tcpack_sup_mod->tcpdata_info_cnt = 0; - bzero(tcpack_sup_mod->tcpdata_info_tbl, - sizeof(tcpdata_info_t) * TCPDATA_INFO_MAXNUM); - /* For half duplex bus interface, tx precedes rx by default */ - if (dhdp->bus) - dhd_bus_set_dotxinrx(dhdp->bus, TRUE); - } + case TCPACK_SUP_DELAYTX: + if (tcpack_sup_module) { + /* We won't need tdata_psh_info pool and + * tcpddata_info_tbl anymore + */ + _tdata_psh_info_pool_deinit(dhdp, tcpack_sup_module); + tcpack_sup_module->tcpdata_info_cnt = 0; + bzero(tcpack_sup_module->tcpdata_info_tbl, + sizeof(tcpdata_info_t) * TCPDATA_INFO_MAXNUM); + } + + /* For half duplex bus interface, tx precedes rx by default */ + if (dhdp->bus) { + dhd_bus_set_dotxinrx(dhdp->bus, TRUE); + } + + if (tcpack_sup_module == NULL) { + DHD_ERROR(("%s[%d]: tcpack_sup_module should not be NULL\n", + __FUNCTION__, __LINE__)); + dhdp->tcpack_sup_mode = TCPACK_SUP_OFF; + goto exit; + } + break; #endif /* BCMSDIO */ + } + + /* Update a new mode */ dhdp->tcpack_sup_mode = mode; - if (mode == TCPACK_SUP_OFF) { - ASSERT(dhdp->tcpack_sup_module != NULL); - /* Clean up timer/data structure for any remaining/pending packet or timer. */ - dhd_tcpack_info_tbl_clean(dhdp); - MFREE(dhdp->osh, dhdp->tcpack_sup_module, sizeof(tcpack_sup_module_t)); - dhdp->tcpack_sup_module = NULL; - goto exit; - } - - if (dhdp->tcpack_sup_module == NULL) { - tcpack_sup_module_t *tcpack_sup_mod = - MALLOC(dhdp->osh, sizeof(tcpack_sup_module_t)); - if (tcpack_sup_mod == NULL) { - DHD_ERROR(("%s %d: No MEM\n", __FUNCTION__, __LINE__)); - dhdp->tcpack_sup_mode = TCPACK_SUP_OFF; - ret = BCME_NOMEM; - goto exit; - } - bzero(tcpack_sup_mod, sizeof(tcpack_sup_module_t)); - dhdp->tcpack_sup_module = tcpack_sup_mod; - } - -#ifdef BCMSDIO - if (mode == TCPACK_SUP_DELAYTX) { - ret = _tdata_psh_info_pool_init(dhdp, dhdp->tcpack_sup_module); - if (ret != BCME_OK) - DHD_ERROR(("%s %d: pool init fail with %d\n", __FUNCTION__, __LINE__, ret)); - else if (dhdp->bus) - dhd_bus_set_dotxinrx(dhdp->bus, FALSE); - } -#endif /* BCMSDIO */ - - if (mode == TCPACK_SUP_HOLD) { - int i; - tcpack_sup_module_t *tcpack_sup_mod = - (tcpack_sup_module_t *)dhdp->tcpack_sup_module; - dhdp->tcpack_sup_ratio = CUSTOM_TCPACK_SUPP_RATIO; - dhdp->tcpack_sup_delay = CUSTOM_TCPACK_DELAY_TIME; - for (i = 0; i < TCPACK_INFO_MAXNUM; i++) - { - tcpack_sup_mod->tcpack_info_tbl[i].dhdp = dhdp; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)) - timer_setup((struct timer_list *)&tcpack_sup_mod->tcpack_info_tbl[i].timer, dhd_tcpack_send, 0); + /* Process for a new mode */ + switch (mode) { + case TCPACK_SUP_OFF: + ASSERT(tcpack_sup_module != NULL); + /* Clean up timer/data structure for + * any remaining/pending packet or timer. + */ + if (tcpack_sup_module) { + /* Check if previous mode is TCAPACK_SUP_HOLD */ + if (prev_mode == TCPACK_SUP_HOLD) { + for (i = 0; i < TCPACK_INFO_MAXNUM; i++) { + tcpack_info_t *tcpack_info_tbl = + &tcpack_sup_module->tcpack_info_tbl[i]; +#ifndef TCPACK_SUPPRESS_HOLD_HRT + del_timer(&tcpack_info_tbl->timer); #else - init_timer(&tcpack_sup_mod->tcpack_info_tbl[i].timer); - tcpack_sup_mod->tcpack_info_tbl[i].timer.data = - (ulong)&tcpack_sup_mod->tcpack_info_tbl[i]; - tcpack_sup_mod->tcpack_info_tbl[i].timer.function = dhd_tcpack_send; -#endif - } + hrtimer_cancel(&tcpack_info_tbl->timer.timer); +#endif /* TCPACK_SUPPRESS_HOLD_HRT */ + if (tcpack_info_tbl->pkt_in_q) { + PKTFREE(dhdp->osh, + tcpack_info_tbl->pkt_in_q, TRUE); + tcpack_info_tbl->pkt_in_q = NULL; + } + } + } + MFREE(dhdp->osh, tcpack_sup_module, sizeof(tcpack_sup_module_t)); + dhdp->tcpack_sup_module = NULL; + } else { + DHD_ERROR(("%s[%d]: tcpack_sup_module should not be NULL\n", + __FUNCTION__, __LINE__)); + } + break; +#ifdef BCMSDIO + case TCPACK_SUP_REPLACE: + /* There is nothing to configure for this mode */ + break; + case TCPACK_SUP_DELAYTX: + ret = _tdata_psh_info_pool_init(dhdp, tcpack_sup_module); + if (ret != BCME_OK) { + DHD_ERROR(("%s %d: pool init fail with %d\n", + __FUNCTION__, __LINE__, ret)); + break; + } + if (dhdp->bus) { + dhd_bus_set_dotxinrx(dhdp->bus, FALSE); + } + break; +#endif /* BCMSDIO */ +#ifdef BCMPCIE + case TCPACK_SUP_HOLD: + dhdp->tcpack_sup_ratio = CUSTOM_TCPACK_SUPP_RATIO; + dhdp->tcpack_sup_delay = CUSTOM_TCPACK_DELAY_TIME; + for (i = 0; i < TCPACK_INFO_MAXNUM; i++) { + tcpack_info_t *tcpack_info_tbl = + &tcpack_sup_module->tcpack_info_tbl[i]; + tcpack_info_tbl->dhdp = dhdp; +#ifndef TCPACK_SUPPRESS_HOLD_HRT + init_timer_compat(&tcpack_info_tbl->timer, + dhd_tcpack_send, tcpack_info_tbl); +#else +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(5, 1, 21)) + tasklet_hrtimer_init(&tcpack_info_tbl->timer, + dhd_tcpack_send, CLOCK_MONOTONIC, HRTIMER_MODE_REL); +#else + hrtimer_init(&tcpack_info_tbl->timer, CLOCK_MONOTONIC, + HRTIMER_MODE_REL_SOFT); +#endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(5, 1, 21) */ +#endif /* TCPACK_SUPPRESS_HOLD_HRT */ + } + break; +#endif /* BCMPCIE */ } exit: @@ -480,7 +569,11 @@ if (dhdp->tcpack_sup_mode == TCPACK_SUP_HOLD) { for (i = 0; i < TCPACK_INFO_MAXNUM; i++) { +#ifndef TCPACK_SUPPRESS_HOLD_HRT del_timer_sync(&tcpack_sup_mod->tcpack_info_tbl[i].timer); +#else + hrtimer_cancel(&tcpack_sup_mod->tcpack_info_tbl[i].timer.timer); +#endif /* TCPACK_SUPPRESS_HOLD_HRT */ } } @@ -649,7 +742,6 @@ bool ret = FALSE; bool set_dotxinrx = TRUE; unsigned long flags; - if (dhdp->tcpack_sup_mode == TCPACK_SUP_OFF) goto exit; @@ -1193,7 +1285,7 @@ for (i = 0; i < TCPACK_INFO_MAXNUM; i++) { void *oldpkt; /* TCPACK packet that is already in txq or DelayQ */ uint8 *old_ether_hdr, *old_ip_hdr, *old_tcp_hdr; - uint32 old_ip_hdr_len, old_tcp_hdr_len; + uint32 old_ip_hdr_len; uint32 old_tcpack_num; /* TCP ACK number of old TCPACK packet in Q */ if ((oldpkt = tcpack_info_tbl[i].pkt_in_q) == NULL) { @@ -1215,7 +1307,6 @@ old_ip_hdr = old_ether_hdr + ETHER_HDR_LEN; old_ip_hdr_len = IPV4_HLEN(old_ip_hdr); old_tcp_hdr = old_ip_hdr + old_ip_hdr_len; - old_tcp_hdr_len = 4 * TCP_HDRLEN(old_tcp_hdr[TCP_HLEN_OFFSET]); DHD_TRACE(("%s %d: oldpkt %p[%d], IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR " TCP port %d %d\n", __FUNCTION__, __LINE__, oldpkt, i, @@ -1254,7 +1345,11 @@ dhd_os_tcpackunlock(dhdp, flags); if (!hold) { +#ifndef TCPACK_SUPPRESS_HOLD_HRT del_timer_sync(&tcpack_info_tbl[i].timer); +#else + hrtimer_cancel(&tcpack_sup_mod->tcpack_info_tbl[i].timer.timer); +#endif /* TCPACK_SUPPRESS_HOLD_HRT */ } goto exit; } @@ -1271,8 +1366,18 @@ tcpack_info_tbl[free_slot].pkt_ether_hdr = new_ether_hdr; tcpack_info_tbl[free_slot].ifidx = ifidx; tcpack_info_tbl[free_slot].supp_cnt = 1; +#ifndef TCPACK_SUPPRESS_HOLD_HRT mod_timer(&tcpack_sup_mod->tcpack_info_tbl[free_slot].timer, jiffies + msecs_to_jiffies(dhdp->tcpack_sup_delay)); +#else +#if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 1, 21) + tasklet_hrtimer_start(&tcpack_sup_mod->tcpack_info_tbl[free_slot].timer, + ktime_set(0, dhdp->tcpack_sup_delay*1000000), HRTIMER_MODE_REL); +#else + hrtimer_start(&tcpack_sup_mod->tcpack_info_tbl[free_slot].timer, + ktime_set(0, dhdp->tcpack_sup_delay*1000000), HRTIMER_MODE_REL_SOFT); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0) */ +#endif /* TCPACK_SUPPRESS_HOLD_HRT */ tcpack_sup_mod->tcpack_info_cnt++; } else { DHD_TRACE(("%s %d: No empty tcp ack info tbl\n", @@ -1284,3 +1389,54 @@ return hold; } #endif /* DHDTCPACK_SUPPRESS */ + +#ifdef DHDTCPSYNC_FLOOD_BLK +tcp_hdr_flag_t +dhd_tcpdata_get_flag(dhd_pub_t *dhdp, void *pkt) +{ + uint8 *ether_hdr; /* Ethernet header of the new packet */ + uint16 ether_type; /* Ethernet type of the new packet */ + uint8 *ip_hdr; /* IP header of the new packet */ + uint8 *tcp_hdr; /* TCP header of the new packet */ + uint32 ip_hdr_len; /* IP header length of the new packet */ + uint32 cur_framelen; + uint8 flags; + + ether_hdr = PKTDATA(dhdp->osh, pkt); + cur_framelen = PKTLEN(dhdp->osh, pkt); + + ether_type = ether_hdr[12] << 8 | ether_hdr[13]; + + if (ether_type != ETHER_TYPE_IP) { + DHD_TRACE(("%s %d: Not a IP packet 0x%x\n", + __FUNCTION__, __LINE__, ether_type)); + return FLAG_OTHERS; + } + + ip_hdr = ether_hdr + ETHER_HDR_LEN; + cur_framelen -= ETHER_HDR_LEN; + + if (cur_framelen < IPV4_MIN_HEADER_LEN) { + return FLAG_OTHERS; + } + + ip_hdr_len = IPV4_HLEN(ip_hdr); + if (IP_VER(ip_hdr) != IP_VER_4 || IPV4_PROT(ip_hdr) != IP_PROT_TCP) { + DHD_TRACE(("%s %d: Not IPv4 nor TCP! ip ver %d, prot %d\n", + __FUNCTION__, __LINE__, IP_VER(ip_hdr), IPV4_PROT(ip_hdr))); + return FLAG_OTHERS; + } + + tcp_hdr = ip_hdr + ip_hdr_len; + + flags = (uint8)tcp_hdr[TCP_FLAGS_OFFSET]; + + if (flags & TCP_FLAG_SYN) { + if (flags & TCP_FLAG_ACK) { + return FLAG_SYNCACK; + } + return FLAG_SYNC; + } + return FLAG_OTHERS; +} +#endif /* DHDTCPSYNC_FLOOD_BLK */ -- Gitblit v1.6.2