From e38c766dc7e12adc3a529667a05210c826b78fcb Mon Sep 17 00:00:00 2001 From: Lucas Asvio Date: Sat, 22 Feb 2025 13:19:41 +0100 Subject: [PATCH] package: add qca-nss support for k6.x Before I can get to work a feed repository that work i have included qca-nss source needed on this commit Source author: SqTER-PL --- package/qca-nss/nss-ifb/Makefile | 49 + package/qca-nss/nss-ifb/README.md | 45 + package/qca-nss/nss-ifb/src/Makefile | 3 + package/qca-nss/nss-ifb/src/nss_ifb.c | 304 + .../nss-userspace-oss/libnl-nss/Makefile | 46 + .../nss-userspace-oss/libnl-nss/src/Makefile | 35 + .../libnl-nss/src/include/nss_nlbase.h | 71 + .../libnl-nss/src/include/nss_nldtls_api.h | 119 + .../libnl-nss/src/include/nss_nlipv4_api.h | 253 + .../libnl-nss/src/include/nss_nlipv6_api.h | 253 + .../libnl-nss/src/include/nss_nlist_api.h | 220 + .../libnl-nss/src/include/nss_nlmcast_api.h | 102 + .../libnl-nss/src/include/nss_nlsock_api.h | 197 + .../libnl-nss/src/nss_nldtls_api.c | 138 + .../libnl-nss/src/nss_nlipv4_api.c | 176 + .../libnl-nss/src/nss_nlipv6_api.c | 176 + .../libnl-nss/src/nss_nlmcast_api.c | 146 + .../libnl-nss/src/nss_nlsock.c | 498 + .../nss-userspace-oss/nssinfo/Makefile | 39 + .../nss-userspace-oss/nssinfo/src/Makefile | 35 + .../nssinfo/src/src/nssinfo.c | 714 + .../nssinfo/src/src/nssinfo.h | 233 + .../src/src/nssinfo_dynamic_interface.c | 72 + .../src/src/nssinfo_dynamic_interface.h | 28 + .../nssinfo/src/src/nssinfo_ethrx.c | 215 + .../nssinfo/src/src/nssinfo_ethrx.h | 28 + .../nssinfo/src/src/nssinfo_ipv4.c | 215 + .../nssinfo/src/src/nssinfo_ipv4.h | 30 + .../nssinfo/src/src/nssinfo_ipv6.c | 212 + .../nssinfo/src/src/nssinfo_ipv6.h | 30 + .../nssinfo/src/src/nssinfo_lso_rx.c | 195 + .../nssinfo/src/src/nssinfo_lso_rx.h | 28 + .../nssinfo/src/src/nssinfo_main.c | 191 + .../nssinfo/src/src/nssinfo_n2h.c | 209 + .../nssinfo/src/src/nssinfo_n2h.h | 28 + package/qca-nss/qca-mcs/Makefile | 68 + .../patches/100-kernel-5.15-support.patch | 56 + package/qca-nss/qca-nss-clients/Makefile | 497 + .../qca-nss-clients/files/qca-nss-ipsec | 92 + .../qca-nss-clients/files/qca-nss-mirred.init | 28 + .../qca-nss-clients/files/qca-nss-ovpn.init | 69 + .../patches/100-kernel-5.15-support.patch | 11298 ++++++ .../patches/110-kernel-6.1-support.patch | 460 + .../patches/120-kernel-6.6-support.patch | 195 + package/qca-nss/qca-nss-drv/Config.in | 168 + package/qca-nss/qca-nss-drv/Makefile | 272 + .../files/nss-firmware/LICENSE.TXT | 45 + .../qca-nss-drv/files/nss-firmware/NOTICE.TXT | 217 + .../qca-nss-drv/files/nss-firmware/README.md | 10 + .../files/nss-firmware/nss_fw_version.h | 11 + .../files/nss-firmware/qca-nss0-retail.bin | Bin 0 -> 588512 bytes .../files/nss-firmware/qca-nss1-retail.bin | Bin 0 -> 220780 bytes .../qca-nss-drv/files/qca-nss-drv.conf | 6 + .../qca-nss-drv/files/qca-nss-drv.debug | 4 + .../qca-nss-drv/files/qca-nss-drv.hotplug | 70 + .../qca-nss-drv/files/qca-nss-drv.init | 50 + .../qca-nss-drv/files/qca-nss-drv.sysctl | 4 + .../qca-nss-drv/files/qca-nss-drv.sysdebug | 44 + .../patches/100-kernel-5.15-support.patch | 28331 ++++++++++++++++ .../patches/110-kernel-6.x-support.patch | 654 + .../patches/120-fix-conversion.patch | 237 + package/qca-nss/qca-nss-ecm/Makefile | 362 + package/qca-nss/qca-nss-ecm/files/ecm_dump.sh | 95 + .../qca-nss/qca-nss-ecm/files/on-demand-down | 6 + .../qca-nss-ecm/files/qca-nss-ecm.defaults | 13 + .../qca-nss-ecm/files/qca-nss-ecm.firewall | 33 + .../qca-nss-ecm/files/qca-nss-ecm.init | 122 + .../qca-nss-ecm/files/qca-nss-ecm.sysctl | 2 + .../qca-nss/qca-nss-ecm/files/qca-nss-ecm.uci | 2 + .../patches/100-kernel-5.15-support.patch | 1418 + ...t-issue-for-6.x-kernel-in-ecm-module.patch | 51 + ...ructure-as-params-for-sawf-hdl-query.patch | 178 + ...an-driver-callback-signature-changes.patch | 335 + ...d-dest-dev-in-MSCS-and-SCS-callbacks.patch | 84 + .../patches/220-Fixes-for-kernel-6.6.patch | 212 + package/qca-nss/qca-nss-gmac/Makefile | 51 + .../00-irq_of_parse_and_map-retcode.patch | 11 + .../patches/01-kernel-5.4-support.patch | 345 + .../patches/02-kernel-5.15-support.patch | 95 + .../03-add-tstamp-enable-func-ethtool.patch | 109 + .../patches/04-fix-poll-enabled.patch | 32 + .../patches/05-kernel-6.x-support.patch | 108 + .../patches/06-enable-threaded-napi.patch | 10 + 83 files changed, 51893 insertions(+) create mode 100644 package/qca-nss/nss-ifb/Makefile create mode 100644 package/qca-nss/nss-ifb/README.md create mode 100644 package/qca-nss/nss-ifb/src/Makefile create mode 100644 package/qca-nss/nss-ifb/src/nss_ifb.c create mode 100644 package/qca-nss/nss-userspace-oss/libnl-nss/Makefile create mode 100644 package/qca-nss/nss-userspace-oss/libnl-nss/src/Makefile create mode 100644 package/qca-nss/nss-userspace-oss/libnl-nss/src/include/nss_nlbase.h create mode 100644 package/qca-nss/nss-userspace-oss/libnl-nss/src/include/nss_nldtls_api.h create mode 100644 package/qca-nss/nss-userspace-oss/libnl-nss/src/include/nss_nlipv4_api.h create mode 100644 package/qca-nss/nss-userspace-oss/libnl-nss/src/include/nss_nlipv6_api.h create mode 100644 package/qca-nss/nss-userspace-oss/libnl-nss/src/include/nss_nlist_api.h create mode 100644 package/qca-nss/nss-userspace-oss/libnl-nss/src/include/nss_nlmcast_api.h create mode 100644 package/qca-nss/nss-userspace-oss/libnl-nss/src/include/nss_nlsock_api.h create mode 100644 package/qca-nss/nss-userspace-oss/libnl-nss/src/nss_nldtls_api.c create mode 100644 package/qca-nss/nss-userspace-oss/libnl-nss/src/nss_nlipv4_api.c create mode 100644 package/qca-nss/nss-userspace-oss/libnl-nss/src/nss_nlipv6_api.c create mode 100644 package/qca-nss/nss-userspace-oss/libnl-nss/src/nss_nlmcast_api.c create mode 100644 package/qca-nss/nss-userspace-oss/libnl-nss/src/nss_nlsock.c create mode 100644 package/qca-nss/nss-userspace-oss/nssinfo/Makefile create mode 100644 package/qca-nss/nss-userspace-oss/nssinfo/src/Makefile create mode 100644 package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo.c create mode 100644 package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo.h create mode 100644 package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_dynamic_interface.c create mode 100644 package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_dynamic_interface.h create mode 100644 package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_ethrx.c create mode 100644 package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_ethrx.h create mode 100644 package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_ipv4.c create mode 100644 package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_ipv4.h create mode 100644 package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_ipv6.c create mode 100644 package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_ipv6.h create mode 100644 package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_lso_rx.c create mode 100644 package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_lso_rx.h create mode 100644 package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_main.c create mode 100644 package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_n2h.c create mode 100644 package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_n2h.h create mode 100644 package/qca-nss/qca-mcs/Makefile create mode 100644 package/qca-nss/qca-mcs/patches/100-kernel-5.15-support.patch create mode 100644 package/qca-nss/qca-nss-clients/Makefile create mode 100644 package/qca-nss/qca-nss-clients/files/qca-nss-ipsec create mode 100644 package/qca-nss/qca-nss-clients/files/qca-nss-mirred.init create mode 100644 package/qca-nss/qca-nss-clients/files/qca-nss-ovpn.init create mode 100644 package/qca-nss/qca-nss-clients/patches/100-kernel-5.15-support.patch create mode 100644 package/qca-nss/qca-nss-clients/patches/110-kernel-6.1-support.patch create mode 100644 package/qca-nss/qca-nss-clients/patches/120-kernel-6.6-support.patch create mode 100644 package/qca-nss/qca-nss-drv/Config.in create mode 100644 package/qca-nss/qca-nss-drv/Makefile create mode 100644 package/qca-nss/qca-nss-drv/files/nss-firmware/LICENSE.TXT create mode 100644 package/qca-nss/qca-nss-drv/files/nss-firmware/NOTICE.TXT create mode 100644 package/qca-nss/qca-nss-drv/files/nss-firmware/README.md create mode 100644 package/qca-nss/qca-nss-drv/files/nss-firmware/nss_fw_version.h create mode 100644 package/qca-nss/qca-nss-drv/files/nss-firmware/qca-nss0-retail.bin create mode 100644 package/qca-nss/qca-nss-drv/files/nss-firmware/qca-nss1-retail.bin create mode 100644 package/qca-nss/qca-nss-drv/files/qca-nss-drv.conf create mode 100644 package/qca-nss/qca-nss-drv/files/qca-nss-drv.debug create mode 100644 package/qca-nss/qca-nss-drv/files/qca-nss-drv.hotplug create mode 100644 package/qca-nss/qca-nss-drv/files/qca-nss-drv.init create mode 100644 package/qca-nss/qca-nss-drv/files/qca-nss-drv.sysctl create mode 100644 package/qca-nss/qca-nss-drv/files/qca-nss-drv.sysdebug create mode 100644 package/qca-nss/qca-nss-drv/patches/100-kernel-5.15-support.patch create mode 100644 package/qca-nss/qca-nss-drv/patches/110-kernel-6.x-support.patch create mode 100644 package/qca-nss/qca-nss-drv/patches/120-fix-conversion.patch create mode 100644 package/qca-nss/qca-nss-ecm/Makefile create mode 100644 package/qca-nss/qca-nss-ecm/files/ecm_dump.sh create mode 100644 package/qca-nss/qca-nss-ecm/files/on-demand-down create mode 100644 package/qca-nss/qca-nss-ecm/files/qca-nss-ecm.defaults create mode 100644 package/qca-nss/qca-nss-ecm/files/qca-nss-ecm.firewall create mode 100644 package/qca-nss/qca-nss-ecm/files/qca-nss-ecm.init create mode 100644 package/qca-nss/qca-nss-ecm/files/qca-nss-ecm.sysctl create mode 100644 package/qca-nss/qca-nss-ecm/files/qca-nss-ecm.uci create mode 100644 package/qca-nss/qca-nss-ecm/patches/100-kernel-5.15-support.patch create mode 100644 package/qca-nss/qca-nss-ecm/patches/115-Fix_dev_put-issue-for-6.x-kernel-in-ecm-module.patch create mode 100644 package/qca-nss/qca-nss-ecm/patches/200-Passing-structure-as-params-for-sawf-hdl-query.patch create mode 100644 package/qca-nss/qca-nss-ecm/patches/210-ECM-to-wlan-driver-callback-signature-changes.patch create mode 100644 package/qca-nss/qca-nss-ecm/patches/215-Adding-src-and-dest-dev-in-MSCS-and-SCS-callbacks.patch create mode 100644 package/qca-nss/qca-nss-ecm/patches/220-Fixes-for-kernel-6.6.patch create mode 100644 package/qca-nss/qca-nss-gmac/Makefile create mode 100644 package/qca-nss/qca-nss-gmac/patches/00-irq_of_parse_and_map-retcode.patch create mode 100644 package/qca-nss/qca-nss-gmac/patches/01-kernel-5.4-support.patch create mode 100644 package/qca-nss/qca-nss-gmac/patches/02-kernel-5.15-support.patch create mode 100644 package/qca-nss/qca-nss-gmac/patches/03-add-tstamp-enable-func-ethtool.patch create mode 100644 package/qca-nss/qca-nss-gmac/patches/04-fix-poll-enabled.patch create mode 100644 package/qca-nss/qca-nss-gmac/patches/05-kernel-6.x-support.patch create mode 100644 package/qca-nss/qca-nss-gmac/patches/06-enable-threaded-napi.patch diff --git a/package/qca-nss/nss-ifb/Makefile b/package/qca-nss/nss-ifb/Makefile new file mode 100644 index 0000000000..4606ca25e2 --- /dev/null +++ b/package/qca-nss/nss-ifb/Makefile @@ -0,0 +1,49 @@ +# +# Copyright (C) 2008-2012 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk +include $(INCLUDE_DIR)/kernel.mk + +PKG_NAME:=nss-ifb +PKG_RELEASE:=1 + +include $(INCLUDE_DIR)/package.mk + +define KernelPackage/nss-ifb + SECTION:=kernel + CATEGORY:=Kernel modules + SUBMENU:=Network Devices + TITLE:=NSS IFB Interface + DEPENDS:=+kmod-qca-nss-drv + FILES:=$(PKG_BUILD_DIR)/nss-ifb.ko + KCONFIG:= +endef + +define KernelPackage/nss-ifb/description + Kernel module to register a NSS aware IFB interface. +endef + +EXTRA_KCONFIG:= \ + CONFIG_NET_CLS=y + +EXTRA_CFLAGS:= \ + -I$(STAGING_DIR)/usr/include/qca-nss-drv + +MAKE_OPTS:= \ + $(KERNEL_MAKE_FLAGS) \ + M="$(PKG_BUILD_DIR)" \ + EXTRA_CFLAGS="$(EXTRA_CFLAGS)" \ + $(EXTRA_KCONFIG) + +define Build/Compile + $(MAKE) -C "$(LINUX_DIR)" \ + $(MAKE_OPTS) \ + modules +endef + +$(eval $(call KernelPackage,nss-ifb)) + diff --git a/package/qca-nss/nss-ifb/README.md b/package/qca-nss/nss-ifb/README.md new file mode 100644 index 0000000000..a0af7a5ebf --- /dev/null +++ b/package/qca-nss/nss-ifb/README.md @@ -0,0 +1,45 @@ +NSS Physical Interface Ingress Driver +===================================== + +This driver redirect NSS physical interface (namely GMACs) ingress traffic to itself +and sends it back to the Linux network stack (as the source GMACs packets) as it's +egress traffic. + +This allows the NSS QDISC drivers to manage the egress traffic of this driver's +NSS virtual interface. + +This driver will create a single network interface named 'nssifb'. The default +source interface is defined as 'eth0'. It can be changed using the following module +parameter path: + +/sys/module/nss-ifb/parameter/nss_src_dev + +To change the source NSS physical interface to 'eth1', use the following command: + +printf eth1 > /sys/module/nss-ifb/parameter/nss_src_dev + +You need to change the source interface first before bringing up the 'nssifb' +interface. Changing it after the interface is up will have no effect. You need +to bring down the interface and bring it back up to have the changes take effect. + +CPU load imposed on the Krait CPUs appears negligible with this driver intercepting +the physical interface's ingress traffic. Full line speed of the GMAC interface +could still be achieved. + +The commands below shows an example to shape ingress traffic to 500 Mbps and egress +to 200 Mbps for the 'eth0' interface. + +# Load the module if it's not loaded +modprobe nss-ifb + +# Bring up the nssifb interface to active ingress redirect +ip link set up nssifb + +# Shape ingress traffic to 500 Mbit with chained NSSFQ_CODEL +tc qdisc add dev nssifb root handle 1: nsstbl rate 500Mbit burst 1Mb +tc qdisc add dev nssifb parent 1: handle 10: nssfq_codel limit 10240 flows 1024 quantum 1514 target 5ms interval 100ms set_default + +# Shape egress traffic to 200 Mbit with chained NSSFQ_CODEL +tc qdisc add dev eth0 root handle 1: nsstbl rate 200Mbit burst 1Mb +tc qdisc add dev eth0 parent 1: handle 10: nssfq_codel limit 10240 flows 1024 quantum 1514 target 5ms interval 100ms set_default + diff --git a/package/qca-nss/nss-ifb/src/Makefile b/package/qca-nss/nss-ifb/src/Makefile new file mode 100644 index 0000000000..332b9b4ed6 --- /dev/null +++ b/package/qca-nss/nss-ifb/src/Makefile @@ -0,0 +1,3 @@ +obj-m += nss-ifb.o + +nss-ifb-objs := nss_ifb.o diff --git a/package/qca-nss/nss-ifb/src/nss_ifb.c b/package/qca-nss/nss-ifb/src/nss_ifb.c new file mode 100644 index 0000000000..18c017fe0d --- /dev/null +++ b/package/qca-nss/nss-ifb/src/nss_ifb.c @@ -0,0 +1,304 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* + * This driver is adapted from the Linux /drivers/net/ifb.c file. + * + * Redirect QCA NSS physical interface ingress traffic to this driver's + * virtual interface. This will allow ingress traffic shaping using the + * QCA NSS shaper. + */ + +#include + +#define TX_Q_LIMIT 32 + +struct nss_ifb_dev_private { + struct nss_virt_if_handle *nssctx; + struct net_device *nss_src_dev; + uint32_t nss_src_if_num; + char nss_src_dev_name[32]; +}; + +char nss_dev_name_array[32] = "eth0"; +char *nss_dev_name = nss_dev_name_array; +module_param(nss_dev_name, charp, 0644); +MODULE_PARM_DESC(nss_dev_name, "NSS physical interface source device name"); + +/* + * Virtual interface egress packet callback. + * + * We send it back to the Linux network stack. + */ +static void nss_ifb_data_cb(struct net_device *netdev, struct sk_buff *skb, struct napi_struct *napi) +{ + struct nss_ifb_dev_private *dp = netdev_priv(netdev); + + skb->protocol = eth_type_trans(skb, dp->nss_src_dev); + skb->ip_summed = CHECKSUM_UNNECESSARY; + + napi_gro_receive(napi, skb); +} + +/* + * Virtual interface ingress packet callback. + * + * We just send it back to the NSS firmware to let the shaper work on it. + */ +static void nss_ifb_xmit_cb(struct net_device *netdev, struct sk_buff *skb) +{ + struct nss_ifb_dev_private *dp = netdev_priv(netdev); + int ret; + + ret = nss_virt_if_tx_buf(dp->nssctx, skb); + if (unlikely(ret)) { + pr_warn("Failed [%d] to send skb [len: %d, protocol: 0x%X] to NSS!\n", + ret, skb->len, ntohs(skb->protocol)); + } +} + +static void nss_ifb_stats64(struct net_device *dev, + struct rtnl_link_stats64 *stats) +{ + +} + +static int nss_ifb_dev_init(struct net_device *dev) +{ + struct nss_ifb_dev_private *dp = netdev_priv(dev); + + dp->nssctx = nss_virt_if_create_sync_nexthop(dev, NSS_ETH_RX_INTERFACE, NSS_ETH_RX_INTERFACE); + if (!dp->nssctx) { + dp->nssctx = NULL; + pr_warn("Could not create a NSS virtual interface for dev [%s]\n", + dev->name); + + return -ENODEV; + } + pr_info("Created a NSS virtual interface for dev [%s]\n", dev->name); + + nss_virt_if_register(dp->nssctx, nss_ifb_data_cb, dev); + pr_info("NSS IFB data callback registered\n"); + + nss_virt_if_xmit_callback_register(dp->nssctx, nss_ifb_xmit_cb); + pr_info("NSS IFB transmit callback registered\n"); + + return 0; +} + +static void nss_ifb_dev_uninit(struct net_device *dev) +{ + struct nss_ifb_dev_private *dp = netdev_priv(dev); + int ret; + + nss_virt_if_xmit_callback_unregister(dp->nssctx); + pr_info("NSS IFB transmit callback unregistered\n"); + + ret = nss_virt_if_destroy_sync(dp->nssctx); + if (ret == NSS_TX_SUCCESS) { + pr_info("NSS virtual interface destroyed for dev [%s]\n", dev->name); + } + else { + pr_warn("Unable to destroy NSS virtual interface for dev [%s], error[%d]\n", + dev->name, ret); + } + dp->nssctx = NULL; +} + +static netdev_tx_t nss_ifb_xmit(struct sk_buff *skb, struct net_device *dev) +{ + return NETDEV_TX_OK; +} + +static int nss_ifb_close(struct net_device *dev) +{ + struct nss_ifb_dev_private *dp = netdev_priv(dev); + struct nss_ctx_instance *nss_ctx; + struct net_device *src_dev; + uint32_t src_if_num; + int ret; + + nss_ctx = dp->nssctx->nss_ctx; + src_dev = dp->nss_src_dev; + src_if_num = dp->nss_src_if_num; + + ret = nss_phys_if_set_nexthop(nss_ctx, src_if_num, NSS_ETH_RX_INTERFACE); + if (ret != NSS_TX_SUCCESS) { + pr_warn("%p: Failed to reset next hop for net device [%s].\n", + nss_ctx, src_dev->name); + } + else { + pr_info("%p: Reset nexthop successful for net device [%s].\n", + nss_ctx, src_dev->name); + } + + dev_put(src_dev); + dp->nss_src_dev = NULL; + dp->nss_src_if_num = -1; + + return 0; +} + +static int nss_ifb_open(struct net_device *dev) +{ + struct nss_ifb_dev_private *dp = netdev_priv(dev); + struct net_device *src_dev; + uint32_t src_if_num; + uint32_t nh_if_num; + nss_tx_status_t nss_tx_status; + struct nss_ctx_instance *nss_ctx; + + nss_ctx = dp->nssctx->nss_ctx; + nh_if_num = dp->nssctx->if_num_n2h; + + strcpy(dp->nss_src_dev_name, nss_dev_name); + + src_dev = dev_get_by_name(&init_net, dp->nss_src_dev_name); + if (!src_dev) { + pr_warn("%p: Cannot find the net device [%s]\n", + nss_ctx, dp->nss_src_dev_name); + + return -ENODEV; + } + pr_info("%p: Found net device [%s]\n", nss_ctx, dp->nss_src_dev_name); + + src_if_num = nss_cmn_get_interface_number_by_dev(src_dev); + if (src_if_num < 0) { + pr_warn("%p: Invalid interface number:%d\n", nss_ctx, src_if_num); + dev_put(src_dev); + + return -ENODEV; + } + pr_info("%p: Net device [%s] has NSS intf_num [%d]\n", + nss_ctx, dp->nss_src_dev_name, src_if_num); + + nss_tx_status = nss_phys_if_set_nexthop(nss_ctx, src_if_num, nh_if_num); + if (nss_tx_status != NSS_TX_SUCCESS) { + pr_warn("%p: Sending message failed, cannot change nexthop for [%s]\n", + nss_ctx, dp->nss_src_dev_name); + } + else { + pr_info("Nexthop successfully set for [%s] to [%s]\n", + dp->nss_src_dev_name, dev->name); + } + + dp->nss_src_dev = src_dev; + dp->nss_src_if_num = src_if_num; + + return 0; +} + +static const struct net_device_ops nss_ifb_netdev_ops = { + .ndo_open = nss_ifb_open, + .ndo_stop = nss_ifb_close, + .ndo_get_stats64 = nss_ifb_stats64, + .ndo_start_xmit = nss_ifb_xmit, + .ndo_validate_addr = eth_validate_addr, + .ndo_init = nss_ifb_dev_init, + .ndo_uninit = nss_ifb_dev_uninit, +}; + +#define IFB_FEATURES (NETIF_F_HW_CSUM | NETIF_F_SG | NETIF_F_FRAGLIST | \ + NETIF_F_TSO_ECN | NETIF_F_TSO | NETIF_F_TSO6 | \ + NETIF_F_GSO_ENCAP_ALL | \ + NETIF_F_HIGHDMA | NETIF_F_HW_VLAN_CTAG_TX | \ + NETIF_F_HW_VLAN_STAG_TX) + +static void nss_ifb_dev_free(struct net_device *dev) +{ + +} + +static void nss_ifb_setup(struct net_device *dev) +{ + /* Initialize the device structure. */ + dev->netdev_ops = &nss_ifb_netdev_ops; + + /* Fill in device structure with ethernet-generic values. */ + ether_setup(dev); + dev->tx_queue_len = TX_Q_LIMIT; + + dev->features |= IFB_FEATURES; + dev->hw_features |= dev->features; + dev->hw_enc_features |= dev->features; + dev->vlan_features |= IFB_FEATURES & ~(NETIF_F_HW_VLAN_CTAG_TX | + NETIF_F_HW_VLAN_STAG_TX); + + dev->flags |= IFF_NOARP; + dev->flags &= ~IFF_MULTICAST; + dev->priv_flags &= ~IFF_TX_SKB_SHARING; + netif_keep_dst(dev); + eth_hw_addr_random(dev); + dev->needs_free_netdev = true; + dev->priv_destructor = nss_ifb_dev_free; + + dev->min_mtu = 0; + dev->max_mtu = 0; +} + +static int nss_ifb_validate(struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) +{ + if (tb[IFLA_ADDRESS]) { + if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) + return -EINVAL; + if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) + return -EADDRNOTAVAIL; + } + return 0; +} + +static struct rtnl_link_ops nss_ifb_link_ops __read_mostly = { + .kind = "nss_ifb", + .priv_size = sizeof(struct nss_ifb_dev_private), + .setup = nss_ifb_setup, + .validate = nss_ifb_validate, +}; + +static int __init nss_ifb_init_module(void) +{ + struct net_device *dev; + int err; + + down_write(&pernet_ops_rwsem); + rtnl_lock(); + err = __rtnl_link_register(&nss_ifb_link_ops); + if (err < 0) + goto out; + + dev = alloc_netdev(sizeof(struct nss_ifb_dev_private), "nssifb", + NET_NAME_UNKNOWN, nss_ifb_setup); + + if (dev) { + dev->rtnl_link_ops = &nss_ifb_link_ops; + err = register_netdevice(dev); + } + else { + err = -ENOMEM; + } + + if (err) + __rtnl_link_unregister(&nss_ifb_link_ops); + +out: + rtnl_unlock(); + up_write(&pernet_ops_rwsem); + + if (!err) + pr_info("NSS IFB module loaded.\n"); + else + pr_warn("Failed to load NSS IFB module.\n"); + + return err; +} + +static void __exit nss_ifb_cleanup_module(void) +{ + rtnl_link_unregister(&nss_ifb_link_ops); + + pr_info("NSS IFB module unloaded.\n"); +} + +module_init(nss_ifb_init_module); +module_exit(nss_ifb_cleanup_module); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_RTNL_LINK("nss_ifb"); diff --git a/package/qca-nss/nss-userspace-oss/libnl-nss/Makefile b/package/qca-nss/nss-userspace-oss/libnl-nss/Makefile new file mode 100644 index 0000000000..f831f9e276 --- /dev/null +++ b/package/qca-nss/nss-userspace-oss/libnl-nss/Makefile @@ -0,0 +1,46 @@ +include $(TOPDIR)/rules.mk +include $(INCLUDE_DIR)/kernel.mk + +PKG_NAME:=libnl-nss +PKG_RELEASE:=1 +PKG_BUILD_DEPENDS:=libnl + +include $(INCLUDE_DIR)/package.mk + +define Package/libnl-nss + SECTION:=Libs + CATEGORY:=Libraries + TITLE:=Framework to communicate between userspace applications and the kernel. + DEPENDS:=+libpthread +libnl +@NSS_DRV_CRYPTO_ENABLE +kmod-qca-nss-drv-netlink +endef + +define Package/libnl-nss/description + A framework in the userspace that establishes communication between userspace applications and the kernel. +endef + +TOOL_CFLAGS:= -I$(STAGING_DIR)/usr/include/qca-nss-clients \ + -I$(STAGING_DIR)/usr/include/qca-nss-drv \ + -I$(STAGING_DIR)/usr/include/libnl3 + +TOOL_LDFLAGS:= -L$(STAGING_DIR)/lib + +define Build/Compile + $(MAKE) -C $(PKG_BUILD_DIR) \ + CC="$(TARGET_CC)" \ + AR="$(TARGET_AR) " \ + CFLAGS="$(TOOL_CFLAGS)" \ + LD_LIBRARY_PATH="$(TOOL_LDFLAGS)" +endef + +define Build/InstallDev + $(INSTALL_DIR) $(STAGING_DIR)/usr/include/libnl-nss + $(CP) $(PKG_BUILD_DIR)/obj/libnl-nss.so $(STAGING_DIR)/usr/lib + $(CP) $(PKG_BUILD_DIR)/include/* $(STAGING_DIR)/usr/include/libnl-nss +endef + +define Package/libnl-nss/install + $(INSTALL_DIR) $(1)/lib + $(INSTALL_DATA) $(PKG_BUILD_DIR)/obj/libnl-nss.so $(1)/lib +endef + +$(eval $(call BuildPackage,libnl-nss)) diff --git a/package/qca-nss/nss-userspace-oss/libnl-nss/src/Makefile b/package/qca-nss/nss-userspace-oss/libnl-nss/src/Makefile new file mode 100644 index 0000000000..ad9e3f9682 --- /dev/null +++ b/package/qca-nss/nss-userspace-oss/libnl-nss/src/Makefile @@ -0,0 +1,35 @@ +MKDIR = @mkdir -p $(@D) +SRCPATH = ./ +OBJPATH = obj + +BINARY = $(OBJPATH)/libnl-nss.so +SOURCES = $(wildcard $(SRCPATH)/*.c) +OBJECTS = $(SOURCES:$(SRCPATH)/%.c=$(OBJPATH)/%.o) +HEADERS = $(wildcard $(SRCPATH)/*.h) + +INCLUDE += -I./include +LDFLAGS = -lnl-3 -lnl-genl-3 +EXTRA_CFLAGS = -Wall -Werror -fPIC -Wl,-z,relro -Wl,-z,now +EXTRA_LDFLAGS = -pie -Wl,-z,relro -Wl,-z,now + +all: release + +release: $(BINARY) + +$(OBJPATH)/%.o: $(SRCPATH)/%.c $(HEADERS) + $(MKDIR) + @echo [CC] $@ + @$(CC) -c $(CFLAGS) $(INCLUDE) $(EXTRA_CFLAGS) -o $@ $< + +$(BINARY): $(OBJECTS) + @echo $(BINARY) + @echo [LD] $@ + @$(CC) -shared -o $@ $^ $(LDFLAGS) $(LDLIBS) + +clean: + @echo [Clean] + @rm -f $(OBJECTS) + @rm -f $(BINARY) + @rm -rf $(OBJPATH) + +.PHONY: clean diff --git a/package/qca-nss/nss-userspace-oss/libnl-nss/src/include/nss_nlbase.h b/package/qca-nss/nss-userspace-oss/libnl-nss/src/include/nss_nlbase.h new file mode 100644 index 0000000000..ffc2222676 --- /dev/null +++ b/package/qca-nss/nss-userspace-oss/libnl-nss/src/include/nss_nlbase.h @@ -0,0 +1,71 @@ +/* + ************************************************************************** + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +#ifndef __NSS_NLBASE_H__ +#define __NSS_NLBASE_H__ + +/* + * TODO: Remove inter-dependencies between the header files. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Generic Netlink header */ +#include +#include +#include + +#if !defined (likely) || !defined (unlikely) +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) +#endif + +/* NSS headers */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif /* __NSS_NLBASE_H__ */ diff --git a/package/qca-nss/nss-userspace-oss/libnl-nss/src/include/nss_nldtls_api.h b/package/qca-nss/nss-userspace-oss/libnl-nss/src/include/nss_nldtls_api.h new file mode 100644 index 0000000000..608eea523c --- /dev/null +++ b/package/qca-nss/nss-userspace-oss/libnl-nss/src/include/nss_nldtls_api.h @@ -0,0 +1,119 @@ +/* + ************************************************************************** + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +#ifndef __NSS_NLDTLS_API_H__ +#define __NSS_NLDTLS_API_H__ + +/** @addtogroup chapter_nldtls + This chapter describes Data Transport Layer Security (DTLS) APIs in the user space. + These APIs are wrapper functions for DTLS family specific operations. + */ + +/** @addtogroup nss_nldtls_datatypes @{ */ + +/** + * Response callback for DTLS. + * + * @param[in] user_ctx User context (provided at socket open). + * @param[in] rule DTLS rule. + * @param[in] resp_ctx User data per callback. + * + * @return + * None. + */ +typedef void (*nss_nldtls_resp_t)(void *user_ctx, struct nss_nldtls_rule *rule, void *resp_ctx); + +/** + * Event callback for DTLS. + * + * @param[in] user_ctx User context (provided at socket open). + * @param[in] rule DTLS rule. + * + * @return + * None. + */ +typedef void (*nss_nldtls_event_t)(void *user_ctx, struct nss_nldtls_rule *rule); + +/** + * NSS NL DTLS response. + */ +struct nss_nldtls_resp { + void *data; /**< Response context. */ + nss_nldtls_resp_t cb; /**< Response callback. */ +}; + +/** + * NSS NL DTLS context. + */ +struct nss_nldtls_ctx { + struct nss_nlsock_ctx sock; /**< NSS socket context. */ + nss_nldtls_event_t event; /**< NSS event callback function. */ +}; + +/** @} *//* end_addtogroup nss_nldtls_datatypes */ +/** @addtogroup nss_nldtls_functions @{ */ + +/** + * Opens NSS NL DTLS socket. + * + * @param[in] ctx NSS NL socket context allocated by the caller. + * @param[in] user_ctx User context stored per socket. + * @param[in] event_cb Event callback handler. + * + * @return + * Status of the open call. + */ +int nss_nldtls_sock_open(struct nss_nldtls_ctx *ctx, void *user_ctx, nss_nldtls_event_t event_cb); + +/** + * Closes NSS NL DTLS socket. + * + * @param[in] ctx NSS NL context. + * + * @return + * None. + */ +void nss_nldtls_sock_close(struct nss_nldtls_ctx *ctx); + +/** + * Send a DTLS rule synchronously to NSS NL NETLINK. + * + * @param[in] ctx NSS DTLS NL context. + * @param[in] rule DTLS rule. + * @param[in] cb Response callback handler. + * @param[in] data Data received from sender. + * + * @return + * Send status: + * - 0 -- Success. + * - Negative version error (-ve) -- Failure. + */ +int nss_nldtls_sock_send(struct nss_nldtls_ctx *ctx, struct nss_nldtls_rule *rule, nss_nldtls_resp_t cb, void *data); + +/** + * Initializes create rule message. + * + * @param[in] rule DTLS rule. + * @param[in] type Type of command. + * + * @return + * None. + */ +void nss_nldtls_init_rule(struct nss_nldtls_rule *rule, enum nss_nldtls_cmd_type type); + +/** @} *//* end_addtogroup nss_nldtls_functions */ + +#endif /* __NSS_NLDTLS_API_H__ */ diff --git a/package/qca-nss/nss-userspace-oss/libnl-nss/src/include/nss_nlipv4_api.h b/package/qca-nss/nss-userspace-oss/libnl-nss/src/include/nss_nlipv4_api.h new file mode 100644 index 0000000000..edc55e9db3 --- /dev/null +++ b/package/qca-nss/nss-userspace-oss/libnl-nss/src/include/nss_nlipv4_api.h @@ -0,0 +1,253 @@ +/* + ************************************************************************** + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +#ifndef __NSS_NLIPV4_API_H__ +#define __NSS_NLIPV4_API_H__ + +#define NSS_IPV4_RULE_CREATE_IDENTIFIER_VALID 0x1000 /**< Identifier is valid. */ + +/** @addtogroup chapter_nlipv4 + This chapter describes IPv4 APIs in the user space. + These APIs are wrapper functions for IPv4 family specific operations. +*/ + +/** @addtogroup nss_nlipv4_datatypes @{ */ + +/** + * Response callback for IPv4. + * + * @param[in] user_ctx User context (provided at socket open). + * @param[in] rule IPv4 rule. + * @param[in] resp_ctx User data per callback. + * + * @return + * None. + */ +typedef void (*nss_nlipv4_resp_t)(void *user_ctx, struct nss_nlipv4_rule *rule, void *resp_ctx); + +/** + * Event callback for IPv4. + * + * @param[in] user_ctx User context (provided at socket open). + * @param[in] rule IPv4 rule. + * + * @return + * None. + */ +typedef void (*nss_nlipv4_event_t)(void *user_ctx, struct nss_nlipv4_rule *rule); + +/** + * NSS NL IPv4 response. + */ +struct nss_nlipv4_resp { + void *data; /**< Response context. */ + nss_nlipv4_resp_t cb; /**< Response callback. */ +}; + +/** + * NSS NL IPv4 context. + */ +struct nss_nlipv4_ctx { + struct nss_nlsock_ctx sock; /**< NSS socket context. */ + nss_nlipv4_event_t event; /**< NSS event callback function. */ +}; + +/** @} *//* end_addtogroup nss_nlipv4_datatypes */ +/** @addtogroup nss_nlipv4_functions @{ */ + +/** + * Opens NSS NL IPv4 socket. + * + * @param[in] ctx NSS NL socket context allocated by the caller. + * @param[in] user_ctx User context stored per socket. + * @param[in] event_cb Event callback handler. + * + * @return + * Status of the open call. + */ +int nss_nlipv4_sock_open(struct nss_nlipv4_ctx *ctx, void *user_ctx, nss_nlipv4_event_t event_cb); + +/** + * Closes NSS NL IPv4 socket. + * + * @param[in] ctx NSS NL context. + * + * @return + * None. + */ +void nss_nlipv4_sock_close(struct nss_nlipv4_ctx *ctx); + +/** + * Sends an IPv4 rule synchronously to NSS NETLINK. + * + * @param[in] ctx NSS NL IPv4 context. + * @param[in] rule IPv4 rule. + * @param[in] cb Response callback handler. + * @param[in] data Response data per callback. + * + * @return + * Send status: + * - 0 -- Success. + * - Negative version error (-ve) -- Failure. + */ +int nss_nlipv4_sock_send(struct nss_nlipv4_ctx *ctx, struct nss_nlipv4_rule *rule, nss_nlipv4_resp_t cb, void *data); + +/** + * Initializes IPv4 rule message. + * + * @param[in] rule IPv4 rule. + * @param[in] type Command type. + * + * @return + * None. + */ +void nss_nlipv4_init_rule(struct nss_nlipv4_rule *rule, enum nss_ipv4_message_types type); + +/** + * Initializes connection rule for create message. + * + * @param[in] create Creates message. + * + * @return + * None. + */ +static inline void nss_nlipv4_init_conn_rule(struct nss_ipv4_rule_create_msg *create) +{ + create->valid_flags |= NSS_IPV4_RULE_CREATE_CONN_VALID; +} + +/** + * Enables route flow. + * + * @param[in] create Creates message. + * + * @return + * None. + */ +static inline void nss_nlipv4_init_route_flow_rule(struct nss_ipv4_rule_create_msg *create) +{ + create->rule_flags |= NSS_IPV4_RULE_CREATE_FLAG_ROUTED; +} + +/** + * Enables bridge flow. + * + * @param[in] create Creates message. + * + * @return + * None. + */ +static inline void nss_nlipv4_init_bridge_flow_rule(struct nss_ipv4_rule_create_msg *create) +{ + create->rule_flags |= NSS_IPV4_RULE_CREATE_FLAG_BRIDGE_FLOW; +} + +/** + * Initializes TCP protocol rule for create message. + * + * @param[in] create Creates message. + * + * @return + * None. + */ +static inline void nss_nlipv4_init_tcp_rule(struct nss_ipv4_rule_create_msg *create) +{ + create->valid_flags |= NSS_IPV4_RULE_CREATE_TCP_VALID; +} + +/** + * Initializes PPPoE rule for create message. + * + * @param[in] create Creates message. + * + * @return + * None. + */ +static inline void nss_nlipv4_init_pppoe_rule(struct nss_ipv4_rule_create_msg *create) +{ + create->valid_flags |= NSS_IPV4_RULE_CREATE_PPPOE_VALID; +} + +/** + * Initializes QoS rule for create message. + * + * @param[in] create Creates message. + * + * @return + * None. + */ +static inline void nss_nlipv4_init_qos_rule(struct nss_ipv4_rule_create_msg *create) +{ + create->valid_flags |= NSS_IPV4_RULE_CREATE_QOS_VALID; +} + +/** + * Initializes DSCP rule for create message. + * + * @param[in] create Creates message. + * + * @return + * None. + */ +static inline void nss_nlipv4_init_dscp_rule(struct nss_ipv4_rule_create_msg *create) +{ + create->valid_flags |= NSS_IPV4_RULE_CREATE_DSCP_MARKING_VALID; +} + +/** + * Initializes VLAN rule for create message. + * + * @param[in] create Creates message. + * + * @return + * None. + */ +static inline void nss_nlipv4_init_vlan_rule(struct nss_ipv4_rule_create_msg *create) +{ + struct nss_ipv4_vlan_rule *primary; + struct nss_ipv4_vlan_rule *secondary; + + primary = &create->vlan_primary_rule; + secondary = &create->vlan_secondary_rule; + + create->valid_flags |= NSS_IPV4_RULE_CREATE_VLAN_VALID; + + /* + * set the tags to default values + */ + primary->ingress_vlan_tag = NSS_NLIPV4_VLAN_ID_NOT_CONFIGURED; + primary->egress_vlan_tag = NSS_NLIPV4_VLAN_ID_NOT_CONFIGURED; + + secondary->ingress_vlan_tag = NSS_NLIPV4_VLAN_ID_NOT_CONFIGURED; + secondary->egress_vlan_tag = NSS_NLIPV4_VLAN_ID_NOT_CONFIGURED; +} + +/** + * Initializes Identifier rule for create message. + * + * @param[in] create Creates message. + * + * @return + * None. + */ +static inline void nss_nlipv4_init_identifier_rule(struct nss_ipv4_rule_create_msg *create) +{ + create->valid_flags |= NSS_IPV4_RULE_CREATE_IDENTIFIER_VALID; +} + +/** @} *//* end_addtogroup nss_nlipv4_functions */ + +#endif /* __NSS_NLIPV4_API_H__ */ diff --git a/package/qca-nss/nss-userspace-oss/libnl-nss/src/include/nss_nlipv6_api.h b/package/qca-nss/nss-userspace-oss/libnl-nss/src/include/nss_nlipv6_api.h new file mode 100644 index 0000000000..a503421117 --- /dev/null +++ b/package/qca-nss/nss-userspace-oss/libnl-nss/src/include/nss_nlipv6_api.h @@ -0,0 +1,253 @@ +/* + ************************************************************************** + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +#ifndef __NSS_NLIPV6_API_H__ +#define __NSS_NLIPV6_API_H__ + +#define NSS_IPV6_RULE_CREATE_IDENTIFIER_VALID 0x1000 /**< Identifier is valid. */ + +/** @addtogroup chapter_nlipv6 + This chapter describes IPv6 APIs in the user space. + These APIs are wrapper functions for IPv6 family specific operations. +*/ + +/** @addtogroup nss_nlipv6_datatypes @{ */ + +/** + * Response callback for IPv6. + * + * @param[in] user_ctx User context (provided at socket open). + * @param[in] rule IPv6 rule. + * @param[in] resp_ctx user data per callback. + * + * @return + * None. + */ +typedef void (*nss_nlipv6_resp_t)(void *user_ctx, struct nss_nlipv6_rule *rule, void *resp_ctx); + +/** + * Event callback for IPv6. + * + * @param[in] user_ctx User context (provided at socket open). + * @param[in] rule IPv6 Rule. + * + * @return + * None. + */ +typedef void (*nss_nlipv6_event_t)(void *user_ctx, struct nss_nlipv6_rule *rule); + +/** + * NSS NL IPv6 response. + */ +struct nss_nlipv6_resp { + void *data; /**< Response context. */ + nss_nlipv6_resp_t cb; /**< Response callback. */ +}; + +/** + * NSS NL IPv6 context. + */ +struct nss_nlipv6_ctx { + struct nss_nlsock_ctx sock; /**< NSS socket context. */ + nss_nlipv6_event_t event; /**< NSS event callback function. */ +}; + +/** @} *//* end_addtogroup nss_nlipv6_datatypes */ +/** @addtogroup nss_nlipv6_functions @{ */ + +/** + * Opens NSS NL IPv6 socket. + * + * @param[in] ctx NSS NL socket context allocated by the caller. + * @param[in] user_ctx User context stored per socket. + * @param[in] event_cb Event callback handler. + * + * @return + * Status of the open call. + */ +int nss_nlipv6_sock_open(struct nss_nlipv6_ctx *ctx, void *user_ctx, nss_nlipv6_event_t event_cb); + +/** + * Closes NSS NL IPv6 socket. + * + * @param[in] ctx NSS NL context. + * + * @return + * None. + */ +void nss_nlipv6_sock_close(struct nss_nlipv6_ctx *ctx); + +/** + * Sends an IPv6 rule synchronously to NSS NETLINK. + * + * @param[in] ctx NSS IPv6 NL context. + * @param[in] rule IPv6 rule. + * @param[in] cb Response callback handler. + * @param[in] data Response data per callback. + * + * @return + * Send status: + * - 0 -- Success. + * - Negative version error (-ve) -- Failure. + */ +int nss_nlipv6_sock_send(struct nss_nlipv6_ctx *ctx, struct nss_nlipv6_rule *rule, nss_nlipv6_resp_t cb, void *data); + +/** + * Initializes rule message. + * + * @param[in] rule IPv6 rule. + * @param[in] type Command type. + * + * @return + * None. + */ +void nss_nlipv6_init_rule(struct nss_nlipv6_rule *rule, enum nss_ipv6_message_types type); + +/** + * Initializes connection rule for create message. + * + * @param[in] create Creates message. + * + * @return + * None. + */ +static inline void nss_nlipv6_init_conn_rule(struct nss_ipv6_rule_create_msg *create) +{ + create->valid_flags |= NSS_IPV6_RULE_CREATE_CONN_VALID; +} + +/** + * Enables route flow. + * + * @param[in] create Creates message. + * + * @return + * None. + */ +static inline void nss_nlipv6_init_route_flow_rule(struct nss_ipv6_rule_create_msg *create) +{ + create->rule_flags |= NSS_IPV6_RULE_CREATE_FLAG_ROUTED; +} + +/** + * Enables bridge flow. + * + * @param[in] create create message. + * + * @return + * None. + */ +static inline void nss_nlipv6_init_bridge_flow_rule(struct nss_ipv6_rule_create_msg *create) +{ + create->rule_flags |= NSS_IPV6_RULE_CREATE_FLAG_BRIDGE_FLOW; +} + +/** + * Initializes TCP protocol rule for create message. + * + * @param[in] create Creates message. + * + * @return + * None. + */ +static inline void nss_nlipv6_init_tcp_rule(struct nss_ipv6_rule_create_msg *create) +{ + create->valid_flags |= NSS_IPV6_RULE_CREATE_TCP_VALID; +} + +/** + * Initializes PPPoE rule for create message. + * + * @param[in] create Creates message. + * + * @return + * None. + */ +static inline void nss_nlipv6_init_pppoe_rule(struct nss_ipv6_rule_create_msg *create) +{ + create->valid_flags |= NSS_IPV6_RULE_CREATE_PPPOE_VALID; +} + +/** + * Initializes QoS rule for create message. + * + * @param[in] create Creates message. + * + * @return + * None. + */ +static inline void nss_nlipv6_init_qos_rule(struct nss_ipv6_rule_create_msg *create) +{ + create->valid_flags |= NSS_IPV6_RULE_CREATE_QOS_VALID; +} + +/** + * Initializes DSCP rule for create message. + * + * @param[in] create Creates message. + * + * @return + * None. + */ +static inline void nss_nlipv6_init_dscp_rule(struct nss_ipv6_rule_create_msg *create) +{ + create->valid_flags |= NSS_IPV6_RULE_CREATE_DSCP_MARKING_VALID; +} + +/** + * Initializes VLAN rule for create message. + * + * @param[in] create Creates message. + * + * @return + * None. + */ +static inline void nss_nlipv6_init_vlan_rule(struct nss_ipv6_rule_create_msg *create) +{ + struct nss_ipv6_vlan_rule *primary; + struct nss_ipv6_vlan_rule *secondary; + + primary = &create->vlan_primary_rule; + secondary = &create->vlan_secondary_rule; + + create->valid_flags |= NSS_IPV6_RULE_CREATE_VLAN_VALID; + + /* + * set the tags to default values + */ + primary->ingress_vlan_tag = NSS_NLIPV6_VLAN_ID_NOT_CONFIGURED; + primary->egress_vlan_tag = NSS_NLIPV6_VLAN_ID_NOT_CONFIGURED; + + secondary->ingress_vlan_tag = NSS_NLIPV6_VLAN_ID_NOT_CONFIGURED; + secondary->egress_vlan_tag = NSS_NLIPV6_VLAN_ID_NOT_CONFIGURED; +} + +/** + * Initializes Identifier rule for create message. + * + * @param[in] create Creates message. + * + * @return + * None. + */ +static inline void nss_nlipv6_init_identifier_rule(struct nss_ipv6_rule_create_msg *create) +{ + create->valid_flags |= NSS_IPV6_RULE_CREATE_IDENTIFIER_VALID; +} + +/** @} *//* end_addtogroup nss_nlipv6_functions */ + +#endif /* __NSS_NLIPV6_API_H__ */ diff --git a/package/qca-nss/nss-userspace-oss/libnl-nss/src/include/nss_nlist_api.h b/package/qca-nss/nss-userspace-oss/libnl-nss/src/include/nss_nlist_api.h new file mode 100644 index 0000000000..6b8bb0503b --- /dev/null +++ b/package/qca-nss/nss-userspace-oss/libnl-nss/src/include/nss_nlist_api.h @@ -0,0 +1,220 @@ +/* + ************************************************************************** + * Copyright (c) 2019,2021 The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +#ifndef __NSS_NLIST_H__ +#define __NSS_NLIST_H__ + +/** @addtogroup chapter_nlist + This chapter describes Netlink list APIs in the user space. +*/ + +/** @ingroup nss_nlist_datatypes + * List node + */ +struct nss_nlist { + struct nss_nlist *next; /**< Next node. */ + struct nss_nlist *prev; /**< Previous node. */ +}; + +/** @addtogroup nss_nlist_functions @{ */ + +/** + * Initializes the list node. + * + * @param[in] node List node. + * + * @return + * None. + */ +static inline void nss_nlist_init(struct nss_nlist *node) +{ + node->next = node->prev = node; +} + +/** + * Gets the previous node. + * + * @param[in] node Previous node. + * + * @return + * Previous node or head node. + */ +static inline struct nss_nlist *nss_nlist_prev(struct nss_nlist *node) +{ + return node->prev; +} + +/** + * Gets the next node. + * + * @param[in] node Next node. + * + * @return + * Next node or head node. + */ +static inline struct nss_nlist *nss_nlist_next(struct nss_nlist *node) +{ + return node->next; +} + +/** + * Initializes the head node. + * + * @param[in] head Head of list. + * + * @return + * None. + */ +static inline void nss_nlist_init_head(struct nss_nlist *head) +{ + nss_nlist_init(head); +} + +/** + * Returns first node in the list. + * + * @param[in] head List head. + * + * @return + * First node. + */ +static inline struct nss_nlist *nss_nlist_first(struct nss_nlist *head) +{ + return nss_nlist_next(head); +} + +/** + * Returns last node in the list. + * + * @param[in] head List head. + * + * @return + * Last node. + */ +static inline struct nss_nlist *nss_nlist_last(struct nss_nlist *head) +{ + return nss_nlist_prev(head); +} + +/** + * Checks if list is empty. + * + * @param[in] head List head. + * + * @return + * TRUE if empty. + */ +static inline bool nss_nlist_isempty(struct nss_nlist *head) +{ + struct nss_nlist *first = nss_nlist_first(head); + + return first == head; +} + +/** + * Checks if corresponding node is the last node. + * + * @param[in] head Head node. + * @param[in] node Node to check. + * + * @return + * TRUE if it is the last node. + */ +static inline bool nss_nlist_islast(struct nss_nlist *head, struct nss_nlist *node) +{ + struct nss_nlist *last = nss_nlist_last(head); + + return last == node; +} + +/** + * Adds node to head of the list. + * + * @param[in] head List head. + * @param[in] node Node to add. + * + * @return + * None. + */ +static inline void nss_nlist_add_head(struct nss_nlist *head, struct nss_nlist *node) +{ + struct nss_nlist *first = nss_nlist_first(head); + + node->prev = head; + node->next = first; + + first->prev = node; + head->next = node; + +} + +/** + * Adds node to tail of the list. + * + * @param[in] head List head. + * @param[in] node Node to add. + * + * @return + * None. + */ +static inline void nss_nlist_add_tail(struct nss_nlist *head, struct nss_nlist *node) +{ + struct nss_nlist *last = nss_nlist_last(head); + + node->next = head; + node->prev = last; + + last->next = node; + head->prev = node; +} + +/** + * Unlinks node from the list. + * + * @param[in] node Node to unlink. + * + * @return + * None. + */ +static inline void nss_nlist_unlink(struct nss_nlist *node) +{ + struct nss_nlist *prev = nss_nlist_prev(node); + struct nss_nlist *next = nss_nlist_next(node); + + prev->next = next; + next->prev = prev; + + nss_nlist_init(node); +} + +/** @} *//* end_addtogroup nss_nlist_functions */ + +/** @ingroup nss_nlist_macros + * Lists node iterator. + * + * @hideinitializer + * @param[in] _tmp Temporary node for assignment. + * @param[in] _head Head node to start. + * + * @return + * None. + */ +#define nss_nlist_iterate(_tmp, _head) \ + for ((_tmp) = nss_nlist_first((_head)); \ + !nss_nlist_islast((_head), (_tmp)); \ + (_tmp) = nss_nlist_next((_tmp)) + +#endif /* __NSS_NLIST_H__ */ diff --git a/package/qca-nss/nss-userspace-oss/libnl-nss/src/include/nss_nlmcast_api.h b/package/qca-nss/nss-userspace-oss/libnl-nss/src/include/nss_nlmcast_api.h new file mode 100644 index 0000000000..8fcf5d8624 --- /dev/null +++ b/package/qca-nss/nss-userspace-oss/libnl-nss/src/include/nss_nlmcast_api.h @@ -0,0 +1,102 @@ +/* + ************************************************************************** + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +#ifndef __NSS_NLMCAST_API_H__ +#define __NSS_NLMCAST_API_H__ + +/** @addtogroup chapter_nlmcast + This chapter describes multicast APIs in the user space. + These APIs are wrapper functions for multicast specific operations. +*/ + +/** @addtogroup nss_nlmcast_datatypes @{ */ + +/** + * Event callback for multicast. + * + * @param[in] cmd Command received in generic Netlink header. + * @param[in] data Data received in Netlink message. + */ +typedef void (*nss_nlmcast_event_t)(int cmd, void *data); + +/** + * NSS multicast context. + */ +struct nss_nlmcast_ctx { + struct nss_nlsock_ctx sock; /**< NSS socket context. */ + nss_nlmcast_event_t event; /**< NSS event callback function. */ +}; + +/** @} *//* end_addtogroup nss_nlmcast_datatypes */ +/** @addtogroup nss_nlmcast_functions @{ */ + +/** + * Listens to NSS NL multicast event data. + * + * @param[in] ctx Multicast context. + * + * @return + * Listen status. + */ +int nss_nlmcast_sock_listen(struct nss_nlmcast_ctx *ctx); + +/** + * Subscribe the multicast group to receive responses. + * + * @param[in] ctx Multicast context. + * @param[in] grp_name NSS NL group name. + * + * @return + * Subscription status. + */ +int nss_nlmcast_sock_join_grp(struct nss_nlmcast_ctx *ctx, char *grp_name); + +/** + * Unsubscribe the multicast group to stop receiving responses. + * + * @param[in] ctx Multicast context. + * @param[in] grp_name NSS NL group name. + * + * @return + * Status of the operation. + */ +int nss_nlmcast_sock_leave_grp(struct nss_nlmcast_ctx *ctx, char *grp_name); + +/** + * Opens a socket for listening to NSS NL event data. + * + * @param[in] ctx Multicast context. + * @param[in] cb Callback function. + * @param[in] family_name NSS NL family name. + * + * @return + * Status of the operation. + */ +int nss_nlmcast_sock_open(struct nss_nlmcast_ctx *ctx, nss_nlmcast_event_t cb, const char *family_name); + +/** + * Closes socket. + * + * @param[in] ctx Multicast context. + * + * @return + * None. + */ +void nss_nlmcast_sock_close(struct nss_nlmcast_ctx *ctx); + +/** @} *//* end_addtogroup nss_nlmcast_functions */ + +#endif /* __NSS_NLMCAST_API_H__ */ diff --git a/package/qca-nss/nss-userspace-oss/libnl-nss/src/include/nss_nlsock_api.h b/package/qca-nss/nss-userspace-oss/libnl-nss/src/include/nss_nlsock_api.h new file mode 100644 index 0000000000..7a42071c78 --- /dev/null +++ b/package/qca-nss/nss-userspace-oss/libnl-nss/src/include/nss_nlsock_api.h @@ -0,0 +1,197 @@ +/* + ************************************************************************** + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +#ifndef __NSS_NLSOCK_API_H__ +#define __NSS_NLSOCK_API_H__ + +/** @addtogroup chapter_nlsocket + This chapter describes socket APIs for direct use. + + @note1hang + Use these APIs(s) only if there are no available helpers for the specific family. +*/ + +/** + * @ingroup nss_nlsocket_datatypes + * NSS NL socket context. + */ +struct nss_nlsock_ctx { + /* Public, caller must populate using helpers */ + const char *family_name; /**< Family name. */ + void *user_ctx; /**< Socket user context. */ + + /* Private, maintained by the library */ + pthread_t thread; /**< Response sync. */ + pthread_spinlock_t lock; /**< Context lock. */ + int ref_cnt; /**< References to the socket. */ + + struct nl_sock *nl_sk; /**< Linux NL socket. */ + struct nl_cb *nl_cb; /**< NSS NL callback context. */ + + pid_t pid; /**< Process ID associated with the socket. */ + int family_id; /**< Family identifier. */ + int grp_id; /**< Group indentifier. */ + bool is_avail; /**< Indicates if the socket is available to send or listen. */ +}; + +/** @addtogroup nss_nlsocket_macros @{ */ + +/** + * Prints error log. + * + * @param[in] arg Argument to be printed + */ +#define nss_nlsock_log_error(arg, ...) printf("NSS_NLERROR(%s[%d]):"arg, __func__, __LINE__, ##__VA_ARGS__) + +/** + * Prints arguments + * + * @param[in] arg Argument to be printed + */ +#define nss_nlsock_log_info(arg, ...) printf("NSS_NLINFO(%s[%d]):"arg, __func__, __LINE__, ##__VA_ARGS__) + +/** @} *//* end_addtogroup nss_nlsocket_macros */ + +/** @addtogroup nss_nlsocket_functions @{ */ + +/** + * Sets family name. + * + * @param[in] sock Socket context. + * @param[in] name Family name. + * + * @return + * None. + */ +static inline void nss_nlsock_set_family(struct nss_nlsock_ctx *sock, const char *name) +{ + sock->family_name = name; +} + +/** + * Sets user context. + * + * @param[in] sock Socket context. + * @param[in] user User context. + * + * @return + * None. + */ +static inline void nss_nlsock_set_user_ctx(struct nss_nlsock_ctx *sock, void *user) +{ + sock->user_ctx = user; +} + +/** + * Extracts NSS NL message data. + * + * @param[in] msg NL message. + * + * @return + * Pointer to start of NSS NL message. + */ +static inline void *nss_nlsock_get_data(struct nl_msg *msg) +{ + struct genlmsghdr *genl_hdr = nlmsg_data((nlmsg_hdr(msg))); + + return genlmsg_data(genl_hdr); +} + +/** + * Opens NSS NL family socket. + * + * @param[in] sock Socket context to be allocated by the caller. + * @param[in] cb Callback function for response. + * + * @return + * Status of the operation. + * + * @note The underlying entity should set the sock->family name for the socket to open. + */ +int nss_nlsock_open(struct nss_nlsock_ctx *sock, nl_recvmsg_msg_cb_t cb); + +/** + * Closes NSS NL family socket. + * + * @param[in] sock Socket context. + * + * @return + * None. + */ +void nss_nlsock_close(struct nss_nlsock_ctx *sock); + +/** + * Sends NSS NL message synchronously. + * + * @param[in] sock Socket context. + * @param[in] cm Common message header. + * @param[in] data Message data. + * @param[in] has_resp Determines if response is needed from kernel. + * + * @detdesc The function blocks until ack/error is received from the kernel + * and also blocks for the message response from the kernel if is_resp is TRUE + + * @return + * Status of the send operation. + */ +int nss_nlsock_send(struct nss_nlsock_ctx *sock, struct nss_nlcmn *cm, void *data, bool has_resp); + +/** + * Listens to asynchronous events from kernel. + * + * @param[in] sock Socket context. + * + * @return + * Listen status. + */ +int nss_nlsock_listen(struct nss_nlsock_ctx *sock); + +/** + * Subscribes to multicast group. + * + * @param[in] sock Socket context. + * @param[in] grp_name NSS NL group name. + * + * @return + * Subscription status. + */ +int nss_nlsock_join_grp(struct nss_nlsock_ctx *sock, char *grp_name); + +/** + * Unsubscribes from multicast group. + * + * @param[in] sock Socket context. + * @param[in] grp_name NSS NL group name. + * + * @return + * Status of the operation. + */ +int nss_nlsock_leave_grp(struct nss_nlsock_ctx *sock, char *grp_name); + +/** + * Opens a socket for listening to NSS NL event data. + * + * @param[in] sock Socket context. + * @param[in] cb Callback function. + * + * @return + * Status of the operation. + */ +int nss_nlsock_open_mcast(struct nss_nlsock_ctx *sock, nl_recvmsg_msg_cb_t cb); + +/** @} *//* end_addtogroup nss_nlsocket_functions */ + +#endif /* __NSS_NLSOCK_API_H__ */ diff --git a/package/qca-nss/nss-userspace-oss/libnl-nss/src/nss_nldtls_api.c b/package/qca-nss/nss-userspace-oss/libnl-nss/src/nss_nldtls_api.c new file mode 100644 index 0000000000..4ad42efb9b --- /dev/null +++ b/package/qca-nss/nss-userspace-oss/libnl-nss/src/nss_nldtls_api.c @@ -0,0 +1,138 @@ +/* + ************************************************************************** + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +#include +#include +#include + +/* + * nss_nldtls_sock_cb() + * Callback func for dtls netlink socket + */ +int nss_nldtls_sock_cb(struct nl_msg *msg, void *arg) +{ + pid_t pid = getpid(); + + struct nss_nldtls_rule *rule = nss_nlsock_get_data(msg); + + if (!rule) { + nss_nlsock_log_error("%d:failed to get NSS NL dtls header\n", pid); + return NL_SKIP; + } + + uint8_t cmd = nss_nlcmn_get_cmd(&rule->cm); + + switch (cmd) { + case NSS_NLDTLS_CMD_TYPE_CREATE_TUN: + case NSS_NLDTLS_CMD_TYPE_DESTROY_TUN: + case NSS_NLDTLS_CMD_TYPE_UPDATE_CONFIG: + case NSS_NLDTLS_CMD_TYPE_TX_PKTS: + return NL_OK; + + default: + nss_nlsock_log_error("%d:unsupported message cmd type(%d)\n", pid, cmd); + return NL_SKIP; + } +} + +/* + * nss_nldtls_sock_open() + * Opens the NSS dtls NL socket for usage + */ +int nss_nldtls_sock_open(struct nss_nldtls_ctx *ctx, void *user_ctx, nss_nldtls_event_t event_cb) +{ + pid_t pid = getpid(); + int error; + + if (!ctx) { + nss_nlsock_log_error("%d: invalid parameters passed\n", pid); + return -EINVAL; + } + + memset(ctx, 0, sizeof(*ctx)); + + nss_nlsock_set_family(&ctx->sock, NSS_NLDTLS_FAMILY); + nss_nlsock_set_user_ctx(&ctx->sock, user_ctx); + + /* + * try opening the socket with Linux + */ + error = nss_nlsock_open(&ctx->sock, nss_nldtls_sock_cb); + if (error) { + nss_nlsock_log_error("%d:unable to open NSS dtls socket, error(%d)\n", pid, error); + goto fail; + } + + return 0; +fail: + memset(ctx, 0, sizeof(*ctx)); + return error; +} + +/* + * nss_nldtls_sock_close() + * Close the NSS dtls NL socket + */ +void nss_nldtls_sock_close(struct nss_nldtls_ctx *ctx) +{ + nss_nlsock_close(&ctx->sock); + memset(ctx, 0, sizeof(struct nss_nldtls_ctx)); +} + +/* + * nss_nldtls_sock_send() + * Send the dtls message synchronously through the socket + */ +int nss_nldtls_sock_send(struct nss_nldtls_ctx *ctx, struct nss_nldtls_rule *rule, nss_nldtls_resp_t cb, void *data) +{ + int32_t family_id = ctx->sock.family_id; + struct nss_nldtls_resp *resp; + pid_t pid = getpid(); + bool has_resp = false; + int error = 0; + + if (!rule) { + nss_nlsock_log_error("%d:invalid NSS dtls rule\n", pid); + return -EINVAL; + } + + if (cb) { + nss_nlcmn_set_cb_owner(&rule->cm, family_id); + + resp = nss_nlcmn_get_cb_data(&rule->cm, family_id); + assert(resp); + + resp->data = data; + resp->cb = cb; + has_resp = true; + } + + error = nss_nlsock_send(&ctx->sock, &rule->cm, rule, has_resp); + if (error) { + nss_nlsock_log_error("%d:failed to send NSS dtls rule, error(%d)\n", pid, error); + } + + return error; +} + +/* + * nss_nldtls_init_rule() + * Initialize the dtls rule + */ +void nss_nldtls_init_rule(struct nss_nldtls_rule *rule, enum nss_nldtls_cmd_type type) +{ + nss_nldtls_rule_init(rule, type); +} diff --git a/package/qca-nss/nss-userspace-oss/libnl-nss/src/nss_nlipv4_api.c b/package/qca-nss/nss-userspace-oss/libnl-nss/src/nss_nlipv4_api.c new file mode 100644 index 0000000000..0088d723f3 --- /dev/null +++ b/package/qca-nss/nss-userspace-oss/libnl-nss/src/nss_nlipv4_api.c @@ -0,0 +1,176 @@ +/* + ************************************************************************** + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +#include +#include +#include + +/* + * nss_nlipv4_sock_cb() + * NSS NL IPv4 callback + */ +int nss_nlipv4_sock_cb(struct nl_msg *msg, void *arg) +{ + pid_t pid = getpid(); + + struct nss_nlipv4_ctx *ctx = (struct nss_nlipv4_ctx *)arg; + struct nss_nlsock_ctx *sock = &ctx->sock; + + struct nss_nlipv4_rule *rule = nss_nlsock_get_data(msg); + if (!rule) { + nss_nlsock_log_error("%d:failed to get NSS NL IPv4 header\n", pid); + return NL_SKIP; + } + + uint8_t cmd = nss_nlcmn_get_cmd(&rule->cm); + + switch (cmd) { + case NSS_IPV4_TX_CREATE_RULE_MSG: + case NSS_IPV4_TX_DESTROY_RULE_MSG: + { + void *cb_data = nss_nlcmn_get_cb_data(&rule->cm, sock->family_id); + if (!cb_data) { + return NL_SKIP; + } + + /* + * Note: The callback user can modify the CB content so it + * needs to locally save the response data for further use + * after the callback is completed + */ + struct nss_nlipv4_resp resp; + memcpy(&resp, cb_data, sizeof(struct nss_nlipv4_resp)); + + /* + * clear the ownership of the CB so that callback user can + * use it if needed + */ + nss_nlcmn_clr_cb_owner(&rule->cm); + + if (!resp.cb) { + nss_nlsock_log_info("%d:no IPv4 response callback for cmd(%d)\n", pid, cmd); + return NL_SKIP; + } + + resp.cb(sock->user_ctx, rule, resp.data); + + return NL_OK; + } + + case NSS_IPV4_RX_CONN_STATS_SYNC_MSG: + { + nss_nlipv4_event_t event = ctx->event; + + assert(event); + event(sock->user_ctx, rule); + + return NL_OK; + } + + default: + nss_nlsock_log_error("%d:unsupported message cmd type(%d)\n", pid, cmd); + return NL_SKIP; + } +} + +/* + * nss_nlipv4_sock_open() + * this opens the NSS IPv4 NL socket for usage + */ +int nss_nlipv4_sock_open(struct nss_nlipv4_ctx *ctx, void *user_ctx, nss_nlipv4_event_t event_cb) +{ + pid_t pid = getpid(); + int error; + + if (!ctx) { + nss_nlsock_log_error("%d: invalid parameters passed\n", pid); + return -EINVAL; + } + + memset(ctx, 0, sizeof(*ctx)); + + nss_nlsock_set_family(&ctx->sock, NSS_NLIPV4_FAMILY); + nss_nlsock_set_user_ctx(&ctx->sock, user_ctx); + + /* + * try opening the socket with Linux + */ + error = nss_nlsock_open(&ctx->sock, nss_nlipv4_sock_cb); + if (error) { + nss_nlsock_log_error("%d:unable to open NSS IPv4 socket, error(%d)\n", pid, error); + goto fail; + } + + return 0; +fail: + memset(ctx, 0, sizeof(*ctx)); + return error; +} + +/* + * nss_nlipv4_sock_close() + * close the NSS IPv4 NL socket + */ +void nss_nlipv4_sock_close(struct nss_nlipv4_ctx *ctx) +{ + nss_nlsock_close(&ctx->sock); +} + +/* + * nss_nlipv4_sock_send() + * register callback and send the IPv4 message synchronously through the socket + */ +int nss_nlipv4_sock_send(struct nss_nlipv4_ctx *ctx, struct nss_nlipv4_rule *rule, nss_nlipv4_resp_t cb, void *data) +{ + int32_t family_id = ctx->sock.family_id; + struct nss_nlipv4_resp *resp; + pid_t pid = getpid(); + bool has_resp = false; + int error; + + if (!rule) { + nss_nlsock_log_error("%d:invalid NSS IPv4 rule\n", pid); + return -ENOMEM; + } + + if (cb) { + nss_nlcmn_set_cb_owner(&rule->cm, family_id); + + resp = nss_nlcmn_get_cb_data(&rule->cm, family_id); + assert(resp); + + resp->data = data; + resp->cb = cb; + has_resp = true; + } + + error = nss_nlsock_send(&ctx->sock, &rule->cm, rule, has_resp); + if (error) { + nss_nlsock_log_error("%d:failed to send NSS IPv4 rule, error(%d)\n", pid, error); + return error; + } + + return 0; +} + +/* + * nss_nlipv4_init_rule() + * init the rule message + */ +void nss_nlipv4_init_rule(struct nss_nlipv4_rule *rule, enum nss_ipv4_message_types type) +{ + nss_nlipv4_rule_init(rule, type); +} diff --git a/package/qca-nss/nss-userspace-oss/libnl-nss/src/nss_nlipv6_api.c b/package/qca-nss/nss-userspace-oss/libnl-nss/src/nss_nlipv6_api.c new file mode 100644 index 0000000000..fa0bbf22c1 --- /dev/null +++ b/package/qca-nss/nss-userspace-oss/libnl-nss/src/nss_nlipv6_api.c @@ -0,0 +1,176 @@ +/* + ************************************************************************** + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +#include +#include +#include + +/* + * nss_nlipv6_sock_cb() + * NSS NL IPv6 callback + */ +int nss_nlipv6_sock_cb(struct nl_msg *msg, void *arg) +{ + pid_t pid = getpid(); + + struct nss_nlipv6_ctx *ctx = (struct nss_nlipv6_ctx *)arg; + struct nss_nlsock_ctx *sock = &ctx->sock; + + struct nss_nlipv6_rule *rule = nss_nlsock_get_data(msg); + if (!rule) { + nss_nlsock_log_error("%d:failed to get NSS NL IPv6 header\n", pid); + return NL_SKIP; + } + + uint8_t cmd = nss_nlcmn_get_cmd(&rule->cm); + + switch (cmd) { + case NSS_IPV6_TX_CREATE_RULE_MSG: + case NSS_IPV6_TX_DESTROY_RULE_MSG: + { + void *cb_data = nss_nlcmn_get_cb_data(&rule->cm, sock->family_id); + if (!cb_data) { + return NL_SKIP; + } + + /* + * Note: The callback user can modify the CB content so it + * needs to locally save the response data for further use + * after the callback is completed + */ + struct nss_nlipv6_resp resp; + memcpy(&resp, cb_data, sizeof(struct nss_nlipv6_resp)); + + /* + * clear the ownership of the CB so that callback user can + * use it if needed + */ + nss_nlcmn_clr_cb_owner(&rule->cm); + + if (!resp.cb) { + nss_nlsock_log_info("%d:no IPv6 response callback for cmd(%d)\n", pid, cmd); + return NL_SKIP; + } + + resp.cb(sock->user_ctx, rule, resp.data); + + return NL_OK; + } + + case NSS_IPV6_RX_CONN_STATS_SYNC_MSG: + { + nss_nlipv6_event_t event = ctx->event; + + assert(event); + event(sock->user_ctx, rule); + + return NL_OK; + } + + default: + nss_nlsock_log_error("%d:unsupported message cmd type(%d)\n", pid, cmd); + return NL_SKIP; + } +} + +/* + * nss_nlipv6_sock_open() + * this opens the NSS IPv6 NL socket for usage + */ +int nss_nlipv6_sock_open(struct nss_nlipv6_ctx *ctx, void *user_ctx, nss_nlipv6_event_t event_cb) +{ + pid_t pid = getpid(); + int error; + + if (!ctx) { + nss_nlsock_log_error("%d: invalid parameters passed\n", pid); + return -EINVAL; + } + + memset(ctx, 0, sizeof(*ctx)); + + nss_nlsock_set_family(&ctx->sock, NSS_NLIPV6_FAMILY); + nss_nlsock_set_user_ctx(&ctx->sock, user_ctx); + + /* + * try opening the socket with Linux + */ + error = nss_nlsock_open(&ctx->sock, nss_nlipv6_sock_cb); + if (error) { + nss_nlsock_log_error("%d:unable to open NSS IPv6 socket, error(%d)\n", pid, error); + goto fail; + } + + return 0; +fail: + memset(ctx, 0, sizeof(*ctx)); + return error; +} + +/* + * nss_nlipv6_sock_close() + * close the NSS IPv6 NL socket + */ +void nss_nlipv6_sock_close(struct nss_nlipv6_ctx *ctx) +{ + nss_nlsock_close(&ctx->sock); +} + +/* + * nss_nlipv6_sock_send() + * register callback and send the IPv6 message synchronously through the socket + */ +int nss_nlipv6_sock_send(struct nss_nlipv6_ctx *ctx, struct nss_nlipv6_rule *rule, nss_nlipv6_resp_t cb, void *data) +{ + int32_t family_id = ctx->sock.family_id; + struct nss_nlipv6_resp *resp; + pid_t pid = getpid(); + bool has_resp = false; + int error; + + if (!rule) { + nss_nlsock_log_error("%d:invalid NSS IPv6 rule\n", pid); + return -ENOMEM; + } + + if (cb) { + nss_nlcmn_set_cb_owner(&rule->cm, family_id); + + resp = nss_nlcmn_get_cb_data(&rule->cm, family_id); + assert(resp); + + resp->data = data; + resp->cb = cb; + has_resp = true; + } + + error = nss_nlsock_send(&ctx->sock, &rule->cm, rule, has_resp); + if (error) { + nss_nlsock_log_error("%d:failed to send NSS IPv6 rule, error(%d)\n", pid, error); + return error; + } + + return 0; +} + +/* + * nss_nlipv6_init_rule() + * init the rule message + */ +void nss_nlipv6_init_rule(struct nss_nlipv6_rule *rule, enum nss_ipv6_message_types type) +{ + nss_nlipv6_rule_init(rule, type); +} diff --git a/package/qca-nss/nss-userspace-oss/libnl-nss/src/nss_nlmcast_api.c b/package/qca-nss/nss-userspace-oss/libnl-nss/src/nss_nlmcast_api.c new file mode 100644 index 0000000000..764644054c --- /dev/null +++ b/package/qca-nss/nss-userspace-oss/libnl-nss/src/nss_nlmcast_api.c @@ -0,0 +1,146 @@ +/* + ************************************************************************** + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +#include +#include +#include + +/* + * nss_nlmcast_sock_cb() + * NSS NL mcast callback. + */ +static int nss_nlmcast_sock_cb(struct nl_msg *msg, void *arg) +{ + struct nss_nlmcast_ctx *ctx = (struct nss_nlmcast_ctx *)arg; + struct genlmsghdr *genl_hdr = nlmsg_data((nlmsg_hdr(msg))); + uint8_t cmd = genl_hdr->cmd; + + void *data = nss_nlsock_get_data(msg); + if (!data) { + nss_nlsock_log_error("%d:failed to get NSS NL msg header\n", getpid()); + return NL_SKIP; + } + + nss_nlmcast_event_t event = ctx->event; + assert(event); + event(cmd, data); + return NL_OK; +} + +/* + * nss_nlmcast_sock_open() + * Open the NL socket for listening to MCAST events from kernel. + */ +int nss_nlmcast_sock_open(struct nss_nlmcast_ctx *ctx, nss_nlmcast_event_t event_cb, const char *family_name) +{ + int error; + + if (!ctx || !event_cb) { + nss_nlsock_log_error("Invalid parameters passed\n"); + return -EINVAL; + } + + memset(ctx, 0, sizeof(*ctx)); + + nss_nlsock_set_family(&ctx->sock, family_name); + + /* + * Subscribe to the NSS NL Multicast group. + */ + error = nss_nlsock_open_mcast(&ctx->sock, nss_nlmcast_sock_cb); + if (error) { + nss_nlsock_log_error("Unable to create socket, error(%d)\n", error); + return error; + } + + ctx->event = event_cb; + return 0; +} + +/* + * nss_nlmcast_sock_close() + * Close the NL socket. + */ +void nss_nlmcast_sock_close(struct nss_nlmcast_ctx *ctx) +{ + nss_nlsock_close(&ctx->sock); +} + +/* + * nss_nlmcast_sock_join_grp() + * Subscribe for MCAST group from kernel. + */ +int nss_nlmcast_sock_join_grp(struct nss_nlmcast_ctx *ctx, char *grp_name) +{ + int error; + + if (!ctx || !grp_name) { + nss_nlsock_log_error("Invalid parameters passed\n"); + return -EINVAL; + } + + error = nss_nlsock_join_grp(&ctx->sock, grp_name); + if (error) { + nss_nlsock_log_error("Unable to subscribe for mcast group, error(%d)\n", error); + return error; + } + + return 0; +} + +/* + * nss_nlmcast_sock_leave_grp() + * Unsubscribe for MCAST group from kernel. + */ +int nss_nlmcast_sock_leave_grp(struct nss_nlmcast_ctx *ctx, char *grp_name) +{ + int error; + + if (!ctx || !grp_name) { + nss_nlsock_log_error("Invalid parameters passed\n"); + return -EINVAL; + } + + error = nss_nlsock_leave_grp(&ctx->sock, grp_name); + if (error) { + nss_nlsock_log_error("Unable to unsubscribe for mcast group, error(%d)\n", error); + return error; + } + + return 0; +} + +/* + * nss_nlmcast_sock_listen() + * Listen for MCAST events from kernel + */ +int nss_nlmcast_sock_listen(struct nss_nlmcast_ctx *ctx) +{ + int error; + + if (!ctx) { + nss_nlsock_log_error("Invalid parameters passed\n"); + return -EINVAL; + } + + error = nss_nlsock_listen(&ctx->sock); + if (error) { + nss_nlsock_log_error("Unable to listen to mcast events, error(%d)\n", error); + return error; + } + + return 0; +} diff --git a/package/qca-nss/nss-userspace-oss/libnl-nss/src/nss_nlsock.c b/package/qca-nss/nss-userspace-oss/libnl-nss/src/nss_nlsock.c new file mode 100644 index 0000000000..451982f52c --- /dev/null +++ b/package/qca-nss/nss-userspace-oss/libnl-nss/src/nss_nlsock.c @@ -0,0 +1,498 @@ +/* + ************************************************************************** + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +/* + * @file netlink socket handler + */ + +#include +#include + +/* + * nss_nlsock_deinit() + * de-initialize the socket + */ +static void nss_nlsock_deinit(struct nss_nlsock_ctx *sock) +{ + assert(sock); + + nl_cb_put(sock->nl_cb); + sock->nl_cb = NULL; + + nl_socket_free(sock->nl_sk); + sock->nl_sk = NULL; +} + +/* + * nss_nlsock_init() + * initialize the socket and callback + */ +static int nss_nlsock_init(struct nss_nlsock_ctx *sock, nl_recvmsg_msg_cb_t cb) +{ + int error; + + assert(sock); + + /* + * Initialize spinlock + */ + error = pthread_spin_init(&sock->lock, PTHREAD_PROCESS_PRIVATE); + if (error) { + nss_nlsock_log_error("Failed to init spinlock for family(%s), error %d\n", sock->family_name, error); + return error; + } + + sock->pid = getpid(); + + /* + * create callback + */ + sock->nl_cb = nl_cb_alloc(NL_CB_CUSTOM); + if (!sock->nl_cb) { + nss_nlsock_log_error("%d:failed to alloc callback for family(%s)\n",sock->pid, sock->family_name); + goto fail1; + } + + /* + * register callback + */ + nl_cb_set(sock->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, cb, sock); + + /* + * Create netlink socket + */ + sock->nl_sk = nl_socket_alloc_cb(sock->nl_cb); + if (!sock->nl_sk) { + nss_nlsock_log_error("%d:failed to alloc socket for family(%s)\n", sock->pid, sock->family_name); + goto fail2; + } + + sock->ref_cnt = 1; + + /* + * is_avail is set to indicate the socket is available for send/listen + */ + sock->is_avail = true; + return 0; + +fail2: + nl_cb_put(sock->nl_cb); + sock->nl_cb = NULL; +fail1: + pthread_spin_destroy(&sock->lock); + sock->lock = (pthread_spinlock_t)0; + return -ENOMEM; +} + +/* + * nss_nlsock_deref() + * decrement the reference count and free socket resources if '0' + */ +static inline void nss_nlsock_deref(struct nss_nlsock_ctx *sock) +{ + assert(sock->ref_cnt > 0); + + pthread_spin_lock(&sock->lock); + if (--sock->ref_cnt) { + pthread_spin_unlock(&sock->lock); + return; + } + + /* + * When there are no more references on the socket, + * deinitialize the socket and destroy the spin lock + * created during nss_nlsock_init + */ + nss_nlsock_deinit(sock); + pthread_spin_unlock(&sock->lock); + + pthread_spin_destroy(&sock->lock); + sock->lock = (pthread_spinlock_t)0; +} + +/* + * nss_nlsock_ref() + * Increment the reference count. + * + * if ref_cnt == 0, return false + * if ref_cnt != 0, increment the socket reference count and return true + */ +static inline bool nss_nlsock_ref(struct nss_nlsock_ctx *sock) +{ + /* + * if ref count is 0, it means there are no references + * on the socket and so return false. Socket will eventually be + * freed by nss_nlsock_deinit else increment the ref count + */ + pthread_spin_lock(&sock->lock); + if (sock->ref_cnt == 0) { + pthread_spin_unlock(&sock->lock); + return false; + } + + sock->ref_cnt++; + pthread_spin_unlock(&sock->lock); + + return true; +} + +/* + * nss_nlsock_listen_callback() + * listen to responses from the netlink socket + * + * The API keeps listening for the responses on the netlink socket + * until socket close is initiated and there are no more + * responses on the socket + */ +static void *nss_nlsock_listen_callback(void *arg) +{ + struct nss_nlsock_ctx *sock = (struct nss_nlsock_ctx *)arg; + assert(sock); + + /* + * drain responses on the socket + */ + for (;;) { + /* + * if, socket is freed then break out + */ + if (!nss_nlsock_ref(sock)) { + break; + } + + /* + * get or block for pending messages + */ + nl_recvmsgs(sock->nl_sk, sock->nl_cb); + nss_nlsock_deref(sock); + } + + return NULL; +} + +/* + * nss_nlsock_msg_init() + * Initialize parameters to send message down the socket + */ +static int nss_nlsock_msg_init(struct nss_nlsock_ctx *sock, struct nss_nlcmn *cm, void *data, struct nl_msg *msg) +{ + int pid = sock->pid; + void *user_hdr; + uint32_t ver; + uint8_t cmd; + int len; + + ver = nss_nlcmn_get_ver(cm); + len = nss_nlcmn_get_len(cm); + cmd = nss_nlcmn_get_cmd(cm); + + /* + * create space for user header + */ + user_hdr = genlmsg_put(msg, pid, NL_AUTO_SEQ, sock->family_id, len, 0, cmd, ver); + if (!user_hdr) { + nss_nlsock_log_error("%d:failed to put message header of len(%d)\n", pid, len); + return -ENOMEM; + + } + + memcpy(user_hdr, data, len); + return 0; +} + +/* + * nss_nlsock_leave_grp() + * nl socket unsubscribe for the multicast group + */ +int nss_nlsock_leave_grp(struct nss_nlsock_ctx *sock, char *grp_name) +{ + int error; + + assert(sock->ref_cnt > 0); + + /* + * Resolve the group + */ + sock->grp_id = genl_ctrl_resolve_grp(sock->nl_sk, sock->family_name, grp_name); + if (sock->grp_id < 0) { + nss_nlsock_log_error("failed to resolve group(%s)\n", grp_name); + return -EINVAL; + } + + /* + * Unsubscribe for the mcast async events + */ + error = nl_socket_drop_memberships(sock->nl_sk, sock->grp_id, 0); + if (error < 0) { + nss_nlsock_log_error("failed to deregister grp(%s)\n", grp_name); + return error; + } + + return 0; +} + +/* + * nss_nlsock_join_grp() + * nl socket subscribe for the multicast group + */ +int nss_nlsock_join_grp(struct nss_nlsock_ctx *sock, char *grp_name) +{ + int error; + + assert(sock->ref_cnt > 0); + + /* + * Resolve the group + */ + sock->grp_id = genl_ctrl_resolve_grp(sock->nl_sk, sock->family_name, grp_name); + if (sock->grp_id < 0) { + nss_nlsock_log_error("failed to resolve group(%s)\n", grp_name); + return -EINVAL; + } + + /* + * Subscribe for the mcast async events + */ + error = nl_socket_add_memberships(sock->nl_sk, sock->grp_id, 0); + if (error < 0) { + nss_nlsock_log_error("failed to register grp(%s)\n", grp_name); + return error; + } + + return 0; +} + +/* + * nss_nlsock_open_mcast() + * Open the socket for async events + */ +int nss_nlsock_open_mcast(struct nss_nlsock_ctx *sock, nl_recvmsg_msg_cb_t cb) +{ + int error; + assert(sock); + + error = nss_nlsock_init(sock, cb); + if (error) { + nss_nlsock_log_error("%d:failed to initialize socket(%s)\n", sock->pid, sock->family_name); + return error; + } + + /* + * Disable seq number and auto ack checks for sockets listening for mcast events + */ + nl_socket_disable_seq_check(sock->nl_sk); + nl_socket_disable_auto_ack(sock->nl_sk); + + /* + * Connect the socket with the netlink bus + */ + if (genl_connect(sock->nl_sk)) { + nss_nlsock_log_error("%d:failed to connect socket for family(%s)\n", sock->pid, sock->family_name); + error = -EBUSY; + goto free_sock; + } + return 0; + +free_sock: + nss_nlsock_deref(sock); + return error; +} + +/* + * nss_nlsock_send() + * send a message synchronously through the socket + */ +int nss_nlsock_send(struct nss_nlsock_ctx *sock, struct nss_nlcmn *cm, void *data, bool has_resp) +{ + int pid = sock->pid; + struct nl_msg *msg; + int error; + + /* + * return -EBUSY if the socket is currently unavailable for sending message + */ + pthread_spin_lock(&sock->lock); + if (!sock->is_avail) { + pthread_spin_unlock(&sock->lock); + return -EBUSY; + } + + /* + * To indicate the socket is unavailable until the current thread completes the send/listen. + * This is to prevent other threads from simultaneous send/listen. + */ + sock->is_avail = false; + pthread_spin_unlock(&sock->lock); + + /* + * allocate new message buffer + */ + msg = nlmsg_alloc(); + if (!msg) { + nss_nlsock_log_error("%d:failed to allocate message buffer\n", pid); + sock->is_avail = true; + return -ENOMEM; + } + + /* + * Holds a reference on the socket until msg is sent down to the kernel + */ + if (!nss_nlsock_ref(sock)) { + nss_nlsock_log_error("%d:failed to get NL socket\n", pid); + nlmsg_free(msg); + sock->is_avail = true; + return -EINVAL; + } + + /* + * Initialize message parameters + */ + error = nss_nlsock_msg_init(sock, cm, data, msg); + if (error) { + nss_nlsock_log_error("%d:failed to initialize message structure (family:%s, error:%d)\n", + pid, sock->family_name, error); + nss_nlsock_deref(sock); + nlmsg_free(msg); + sock->is_avail = true; + return error; + } + + /* + * If has_resp is true and msg is sent to FW, then there will be two + * netlink messages coming from kernel - FW response and ACK + * If msg fails in netlink, then error will be returned from kernel. + * If has_resp is false, then there is only one netlink message + * coming from kernel: either ACK or error + * In case firmware response is sent before nl_recvmsgs is invoked, + * the response will be queued until the listener is available. + */ + error = nl_send_sync(sock->nl_sk, msg); + if (error < 0) { + nss_nlsock_log_error("%d:failed to send (family:%s, error:%d)\n", pid, sock->family_name, error); + nss_nlsock_deref(sock); + sock->is_avail = true; + return error; + } + + if (has_resp) { + nl_recvmsgs(sock->nl_sk, sock->nl_cb); + } + + nss_nlsock_deref(sock); + sock->is_avail = true; + return 0; +} + +/* + * nss_nlsock_listen() + * listen for async events on the socket + */ +int nss_nlsock_listen(struct nss_nlsock_ctx *sock) +{ + int error; + + assert(sock->ref_cnt > 0); + + /* + * return -EBUSY if the socket is currently unavailable for listening + */ + if (!sock->is_avail) { + return -EBUSY; + } + + /* + * To indicate the socket is unavailable until the current thread completes the send/listen. + * This is to prevent other threads from simultaneous send/listen. + */ + sock->is_avail = false; + + /* + * Create an async thread for clearing the pending resp on the socket asynchronously + */ + error = pthread_create(&sock->thread, NULL, nss_nlsock_listen_callback, sock); + if (error) { + nss_nlsock_log_error("%d:failed to create sync thread for family(%s)\n", sock->pid, sock->family_name); + return error; + } + + return 0; +} + +/* + * nss_nlsock_close() + * close the allocated socket and all associated memory + */ +void nss_nlsock_close(struct nss_nlsock_ctx *sock) +{ + assert(sock); + assert(sock->nl_sk); + assert(sock->ref_cnt > 0); + + /* + * put the reference down for the socket + */ + nss_nlsock_deref(sock); + + /* + * wait for the async thread to complete + */ + if (sock->thread) { + pthread_join(sock->thread, NULL); + sock->thread = NULL; + } +} + +/* + * nss_nlsock_open() + * open a socket for unicast communication with the generic netlink framework + */ +int nss_nlsock_open(struct nss_nlsock_ctx *sock, nl_recvmsg_msg_cb_t cb) +{ + int error = 0; + assert(sock); + + error = nss_nlsock_init(sock, cb); + if (error) { + nss_nlsock_log_error("%d:failed to initialize socket(%s)\n", sock->pid, sock->family_name); + return error; + } + + /* + * Connect the socket with the netlink bus + */ + if (genl_connect(sock->nl_sk)) { + nss_nlsock_log_error("%d:failed to connect socket for family(%s)\n", sock->pid, sock->family_name); + error = -EBUSY; + goto free_sock; + } + + /* + * resolve the family + */ + sock->family_id = genl_ctrl_resolve(sock->nl_sk, sock->family_name); + if (sock->family_id <= 0) { + nss_nlsock_log_error("%d:failed to resolve family(%s)\n", sock->pid, sock->family_name); + error = -EINVAL; + goto free_sock; + } + + return 0; + +free_sock: + + nss_nlsock_deref(sock); + return error; +} diff --git a/package/qca-nss/nss-userspace-oss/nssinfo/Makefile b/package/qca-nss/nss-userspace-oss/nssinfo/Makefile new file mode 100644 index 0000000000..1339ac86b1 --- /dev/null +++ b/package/qca-nss/nss-userspace-oss/nssinfo/Makefile @@ -0,0 +1,39 @@ +include $(TOPDIR)/rules.mk +include $(INCLUDE_DIR)/kernel.mk + +PKG_NAME:=nssinfo +PKG_RELEASE:=1 + +include $(INCLUDE_DIR)/package.mk + +define Package/nssinfo + SECTION:=utils + CATEGORY:=Utilities + TITLE:=Userspace utility for fetching stats from NSS + DEPENDS:=+libncurses +libnl-nss +endef + +define Package/nssinfo/description + A userspace utility for fetching stats from NSS. +endef + +TOOL_CFLAGS:= -I$(STAGING_DIR)/usr/include/qca-nss-clients \ + -I$(STAGING_DIR)/usr/include/qca-nss-drv \ + -I$(STAGING_DIR)/usr/include/libnl3 \ + -I$(STAGING_DIR)/usr/include/libnl-nss + +TOOL_LDFLAGS:= -L$(STAGING_DIR)/lib + +define Build/Compile + $(MAKE) -C $(PKG_BUILD_DIR) \ + CC="$(TARGET_CC)" \ + CFLAGS="$(TOOL_CFLAGS)" \ + LD_LIBRARY_PATH="$(TOOL_LDFLAGS)" +endef + +define Package/nssinfo/install + $(INSTALL_DIR) $(1)/usr/sbin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/obj/nssinfo $(1)/usr/sbin/ +endef + +$(eval $(call BuildPackage,nssinfo)) diff --git a/package/qca-nss/nss-userspace-oss/nssinfo/src/Makefile b/package/qca-nss/nss-userspace-oss/nssinfo/src/Makefile new file mode 100644 index 0000000000..0ef19b3f3a --- /dev/null +++ b/package/qca-nss/nss-userspace-oss/nssinfo/src/Makefile @@ -0,0 +1,35 @@ +MKDIR = mkdir -p $(@D) +SRCPATH = src +OBJPATH = obj +SRCDIR = ./ + +BINARY = $(OBJPATH)/nssinfo +SOURCES = $(wildcard $(SRCDIR)/src/*.c) +HEADERS = $(wildcard $(SRCDIR)/include/*.h) +OBJECTS = $(SOURCES:$(SRCDIR)/src/%.c=$(OBJPATH)/%.o) + +INCLUDE += -I../lib/include +EXTRA_CFLAGS = -Wall -Wno-error=format-truncation -UENABLE_DEBUG +LDFLAGS = -lnl-nss -lncurses +LDLIBS = -L../lib/obj + +all: release + +release: $(BINARY) + +$(OBJPATH)/%.o: $(SRCPATH)/%.c $(HEADERS) + $(MKDIR) + @echo [CC] $@ + @$(CC) -c $(CFLAGS) $(EXTRA_CFLAGS) $(INCLUDE) -o $@ $< + +$(BINARY): $(OBJECTS) + @echo $(BINARY) + @echo [LD] $@ + @$(CC) -o $@ $^ $(LDFLAGS) $(LDLIBS) +clean: + @echo [Clean] + @rm -f $(OBJECTS) + @rm -f $(BINARY) + @rmdir $(OBJPATH) + +.PHONY: clean diff --git a/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo.c b/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo.c new file mode 100644 index 0000000000..60ce1ced8f --- /dev/null +++ b/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo.c @@ -0,0 +1,714 @@ +/* + ************************************************************************** + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +/* + * @file NSSINFO handler + */ +#include +#include "nssinfo.h" + +static pthread_t nssinfo_display_thread; /* Display statistics thread */ +static char buf[NSSINFO_STR_LEN]; /* Formatted stats buffer */ +bool display_all_stats; /* Display all stats per sub-system */ +int invalid_input; /* Identify invalid input */ +FILE *output_file; /* Output file pointer */ +FILE *flow_file; /* Flow file pointer */ + +/* Array of pointers to node stats */ +struct node *nodes[NSS_MAX_CORES][NSS_MAX_NET_INTERFACES]; + +/* + * NSS subsystems in alphabetical order for nssinfo tool + * - Make sure the order here is the same as in 'enum nss_nlcmn_subsys' + * defined in qca-nss-clients/netlink/include/nss_nlcmn_if.h. + */ +struct nssinfo_subsystem_info nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_MAX] = { + {.subsystem_name = "dynamic_interface", .init = nssinfo_dynamic_interface_init, .deinit = nssinfo_dynamic_interface_deinit}, + {.subsystem_name = "eth_rx", .init = nssinfo_eth_rx_init, .deinit = nssinfo_eth_rx_deinit}, + {.subsystem_name = "ipv4", .init = nssinfo_ipv4_init, .deinit = nssinfo_ipv4_deinit}, + {.subsystem_name = "ipv6", .init = nssinfo_ipv6_init, .deinit = nssinfo_ipv6_deinit}, + {.subsystem_name = "lso_rx", .init = nssinfo_lso_rx_init, .deinit = nssinfo_lso_rx_deinit}, + {.subsystem_name = "n2h", .init = nssinfo_n2h_init, .deinit = nssinfo_n2h_deinit}, +}; + +char *nssinfo_summary_fmt = "%-12s %-13s %-13s %-9s %-9s\n"; + +/* + * nssinfo_print_summary_header() + * Print the summary header. + */ +void nssinfo_print_summary_header(void) +{ + nssinfo_stats_print(nssinfo_summary_fmt, "Node", "RX Pkts", "TX Pkts", "Drops", "Exceptions"); + nssinfo_stats_print(nssinfo_summary_fmt, "----", "-------", "-------", "-----", "----------"); +} + +/* + * nssinfo_print_summary() + * Print the summary of the stats: + * - rx pkts + * - tx pkts + * - rx queue drops + * - exceptions + */ +void nssinfo_print_summary(char *node, uint64_t *cmn_node_stats, uint64_t *exception_stats, uint64_t exception_max) +{ + int i; + uint64_t drops = 0, exceptions = 0; + char str_rx[NSSINFO_STR_LEN], str_tx[NSSINFO_STR_LEN], str_drop[NSSINFO_STR_LEN], str_ex[NSSINFO_STR_LEN]; + + assert(cmn_node_stats); + + memset(str_rx, 0, sizeof(str_rx)); + memset(str_tx, 0, sizeof(str_tx)); + memset(str_drop, 0, sizeof(str_drop)); + memset(str_ex, 0, sizeof(str_ex)); + + for (i = NSS_STATS_NODE_RX_QUEUE_0_DROPPED; i < NSS_STATS_NODE_MAX; i++) { + drops += cmn_node_stats[i]; + } + + if (exception_stats) { + for (i = 0 ; i < exception_max; i++) { + exceptions += exception_stats[i]; + } + } + + if (cmn_node_stats[NSS_STATS_NODE_RX_PKTS] > 0 || cmn_node_stats[NSS_STATS_NODE_TX_PKTS] > 0 || + drops > 0 || exceptions > 0 || arguments.verbose) { + char *format_stats = nssinfo_format_stats(cmn_node_stats[NSS_STATS_NODE_RX_PKTS]); + strlcpy(str_rx, format_stats, sizeof(str_rx)); + format_stats = nssinfo_format_stats(cmn_node_stats[NSS_STATS_NODE_TX_PKTS]); + strlcpy(str_tx, format_stats, sizeof(str_tx)); + format_stats = nssinfo_format_stats(drops); + strlcpy(str_drop, format_stats, sizeof(str_drop)); + if (exception_stats) { + format_stats = nssinfo_format_stats(exceptions); + strlcpy(str_ex, format_stats, sizeof(str_ex)); + } + nssinfo_stats_print(nssinfo_summary_fmt, node, str_rx, str_tx, str_drop, str_ex); + } +} + +/* + * nssinfo_print_all() + * Print detailed statistics. + */ +void nssinfo_print_all(char *node, char *stat_details, struct nssinfo_stats_info *stats_info, uint64_t max, uint64_t *stats_val) +{ + int i; + uint16_t maxlen = 0; + char *type; + + for (i = 0; i < max; i++){ + if (strlen(stats_info[i].stats_name) > maxlen) { + maxlen = strlen(stats_info[i].stats_name); + } + } + + /* + * Display stats header, e.g. "#ipv4 Common Stats\n" + */ + if (stat_details != NULL) { + nssinfo_stats_print("#%s\n", stat_details); + } + + /* Display each stat, e.g. + * ipv4_rx_byts = 32903179 common + * ipv4_mc_create_invalid_interface = 12 special + * ... + */ + for (i = 0; i < max; i++) { + if (arguments.verbose || stats_val[i] > 0) { + + switch (stats_info[i].stats_type) { + case NSS_STATS_TYPE_COMMON: + type = "common"; + break; + + case NSS_STATS_TYPE_SPECIAL: + type = "special"; + break; + + case NSS_STATS_TYPE_DROP: + type = "drop"; + break; + + case NSS_STATS_TYPE_ERROR: + type = "error"; + break; + + case NSS_STATS_TYPE_EXCEPTION: + type = "exception"; + break; + + default: + type = "unknown"; + break; + } + + nssinfo_stats_print("%s_%-*s = %-20llu %-s\n", + node, maxlen, stats_info[i].stats_name, stats_val[i], type); + } + } + nssinfo_stats_print("\n"); + + return; +} + +/* + * nssinfo_parse_stats_strings() + * Parse each line in the debug strings file. + * + * Each line has the following format: + * \t , \n + * for example: + * root@OpenWrt:/sys/kernel/debug/qca-nss-drv/strings# cat n2h + * 0 , rx_pkts + * ... + * 1 , rx_queue[0]_drops + * ... + * 4 , n2h_data_interface_invalid + */ +static void nssinfo_parse_stats_strings(struct nssinfo_stats_info *info, char *line) +{ + char *token; + char *rest = NULL; + + token = strtok_r(line, " ", &rest); + if (token) { + info->stats_type = atoi(token); + token = strtok_r(NULL, ",", &rest); + } + if (token) { + token = strtok_r(token, " ", &rest); + } + if (token) { + token = strtok_r(token, "\n", &rest); + } + if (token) { + strlcpy(info->stats_name, token, sizeof(info->stats_name)); + } +} + +/* + * nssinfo_stats_info_init() + * Init 'struct nssinfo_stats_info' from a file in /sys/kernel/debug/qca-nss-drv/strings/. + */ +int nssinfo_stats_info_init(struct nssinfo_stats_info *info, char *strings_file) +{ + FILE *fptr; + char line[NSS_STATS_MAX_STR_LENGTH]; + + fptr = fopen(strings_file, "r"); + if (!fptr) { + nssinfo_error("Unable to open\n"); + return -1; + } + + while (fgets(line, NSS_STATS_MAX_STR_LENGTH, fptr)) { + nssinfo_parse_stats_strings(info, line); + info++; + } + fclose(fptr); + + return 0; +} + +/* + * nssinfo_node_stats_destroy() + * Release memories used to store the node stats. + */ +void nssinfo_node_stats_destroy(pthread_mutex_t *mutex, uint32_t core_id, uint32_t if_num) +{ + struct node *p, *next; + + if (mutex) { + pthread_mutex_lock(mutex); + } + + p = nodes[core_id][if_num]; + nodes[core_id][if_num] = NULL; + + if (mutex) { + pthread_mutex_unlock(mutex); + } + + while (p) { + next = p->next; + + if (p->cmn_node_stats) { + free(p->cmn_node_stats); + } + + if (p->node_stats) { + free(p->node_stats); + } + + if (p->exception_stats) { + free(p->exception_stats); + } + + free(p); + + p = next; + } + + return; +} + +/* + * nssinfo_add_comma() + * Add commas in thousand's place in statistics. + */ +static char* nssinfo_add_comma(uint64_t num) +{ + if (num < 1000) { + snprintf(buf, sizeof(buf), "%llu", num); + return buf; + } + + nssinfo_add_comma(num/1000); + snprintf(buf + strlen(buf), sizeof(buf[NSSINFO_STR_LEN] + strlen(buf)), ",%03llu", num % 1000); + return buf; +} + +/* + * nssinfo_add_suffix() + * Convert number into K thousands M million and B billion suffix. + */ +static char* nssinfo_add_suffix(uint64_t num) +{ + if (num < 1000) { + snprintf(buf, sizeof(buf), "%llu", num); + return buf; + } + + if (1000 <= num && num < 1000000) { + snprintf(buf , sizeof(buf), "%.2lfK", num / 1000.0); + return buf; + } + + if (1000000 <= num && num < 1000000000) { + snprintf(buf , sizeof(buf), "%.2lfM", num / 1000000.0); + return buf; + } + + if (1000000000 <= num) { + snprintf(buf , sizeof(buf), "%.2lfB", num / 1000000000.0); + return buf; + } + + return buf; +} + +/* + * nssinfo_format_stats() + * Format statistics value. + */ +char* nssinfo_format_stats(uint64_t num) +{ + memset(buf, 0, sizeof(buf)); + if (!arguments.higher_unit) { + return nssinfo_add_comma(num); + } + + return nssinfo_add_suffix(num); +} + +/* + * nssinfo_stats_display() + * Invoke each sub-system's display function. + */ +static void *nssinfo_stats_display(void *arg) +{ + int i, j, core; + char mesg[]="NSS STATS"; + + pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); + + for (;;) { + nssinfo_stats_print("\t\t\t%s\n", mesg); + + /* + * If user does not specify a core id, + * check if the flow file is specified and display stats accordingly. + */ + if (arguments.core < 0) { + /* + * If flow file is not specified (via '-f' option), + * display each node's summary stats in alphabetical order for all the cores. + */ + if (!flow_file) { + for (core = 0 ; core < NSS_MAX_CORES ; core++) { + nssinfo_stats_print("Stats for core %d\n",core); + nssinfo_print_summary_header(); + for (i = 0 ; i < NSS_NLCMN_SUBSYS_MAX; i++) { + if (nssinfo_subsystem_array[i].is_inited && i != NSS_NLCMN_SUBSYS_DYNAMIC_INTERFACE) { + nssinfo_subsystem_array[i].display(core, NULL); + } + } + nssinfo_stats_print("\n"); + } + + goto done; + } + + /* + * Flow file is specified (via '-f' option), + * Parse the network graph from flow file and display the node's summary stats + * For example, the network graph would look like + * ipv4-0 eth_rx-0 n2h-1 + * Where, node = ipv4 , core = 0 + * node = eth_rx , core = 0 + * node = n2h , core = 1 + */ + char *line = NULL; + char *rest = NULL; + size_t len = 0; + ssize_t read; + char *node = NULL; + int matched = 0; + + nssinfo_print_summary_header(); + fseek(flow_file, 0, SEEK_SET); + while ((read = getline(&line, &len, flow_file)) != -1) { + node = strtok_r(line, "-", &rest); + + while (node != NULL) { + core = atoi(strtok_r(NULL, " ", &rest)); + if (core >= NSS_MAX_CORES || core < 0) { + printf("Invalid core id `%d'\n", core); + exit(-1); + } + + for (j = 0; j < NSS_NLCMN_SUBSYS_MAX; j++) { + if (nssinfo_subsystem_array[j].is_inited && + strstr(node, nssinfo_subsystem_array[j].subsystem_name)) { + if (j != NSS_NLCMN_SUBSYS_DYNAMIC_INTERFACE) { + ++matched; + nssinfo_subsystem_array[j].display(core, node); + } + } + } + + node = strtok_r(NULL, "-", &rest); + } + + /* If all NODE names are invalid */ + if (matched == invalid_input) { + nssinfo_error("Invalid input\n"); + return NULL; + } + } + + if (line) { + free(line); + } + + goto done; + } + + if (!arguments.strings[0]) { + /* + * If a core id is specified (via '-c' option) but NODE is not specified, + * display each node's summary stats in alphabetical order for that core. + */ + nssinfo_stats_print("Stats for core %d\n", arguments.core); + nssinfo_print_summary_header(); + for (i = 0 ; i < NSS_NLCMN_SUBSYS_MAX; i++) { + if (nssinfo_subsystem_array[i].is_inited && i != NSS_NLCMN_SUBSYS_DYNAMIC_INTERFACE) { + nssinfo_subsystem_array[i].display(arguments.core, NULL); + } + } + + goto done; + } + + /* + * If a core id is specified and at least one NODE is specified. + */ + nssinfo_stats_print("Stats for core %d\n", arguments.core); + + /* + * If user specifies only one NODE, then display all stats for this NODE. + * For example, if NODE="ipv4", then display: + * - common stats (i.e. enum nss_stats_node) + * - ipv4 special stats (i.e. enum nss_ipv4_stats_types) + * - ipv4 exception stats (i.e. enum nss_ipv4_exception_events) + */ + if (!arguments.strings[1]) { + display_all_stats = true; + } else { + /* + * If user specifies more than one NODEs, then display the summary stats for each node + */ + nssinfo_print_summary_header(); + } + + /* + * Now, display NODEs in the desired order. + */ + int matched = 0; + for (i = 0; arguments.strings[i]; i++) { + for (j = 0; j < NSS_NLCMN_SUBSYS_MAX; j++) { + if (nssinfo_subsystem_array[j].is_inited && + strstr(arguments.strings[i], nssinfo_subsystem_array[j].subsystem_name)) { + if (j != NSS_NLCMN_SUBSYS_DYNAMIC_INTERFACE) { + ++matched; + nssinfo_subsystem_array[j].display(arguments.core, arguments.strings[i]); + } + } + + } + } + + /* + * If all NODE names are invalid. + */ + if (matched == invalid_input) { + nssinfo_error("Invalid input\n"); + return NULL; + } +done: + /* + * If using ncurses, refresh the screen. + */ + if (!output_file) { + refresh(); /* draw on screen */ + clear(); /* clear screen buffer */ + move(0, 0); /* move cursor to (line, column)=(0,0) */ + } + + invalid_input = 0; + sleep(arguments.rate); + } +} + +/* + * nssinfo_curses_init() + * Initialize curses library. + */ +static int nssinfo_curses_init() +{ + int rows, cols; + + if (!initscr()) { /* satrt curses mode */ + nssinfo_error("Unable to initialize curses screen\n"); + return -EOPNOTSUPP; + } + + getmaxyx(stdscr, rows, cols); /* get the size of the screen */ + if (rows < CURSES_ROWS_MIN) { + nssinfo_error("Screen must be at least %d rows in height", CURSES_ROWS_MIN); + goto out; + } + if (cols < CURSES_COLS_MIN) { + nssinfo_error("Screen must be at least %d columns width", CURSES_COLS_MIN); + goto out; + } + + cbreak(); /* disable line buffering */ + noecho(); /* not to echo the input back to the screen */ + nonl(); /* disable 'enter' key translation */ + keypad(stdscr, TRUE); /* enable keypad keys, such as arrow keys, etc. */ + nodelay(stdscr, TRUE); /* cause getch() to be a non-blocking call */ + curs_set(0); /* make the cursor invisible */ + clear(); /* clear screen buffer */ + move(0, 0); /* move cursor to (line, column)=(0,0) */ + return 0; + +out: + endwin(); /* stop curses mode */ + return -1; +} + +/* + * nssinfo_termination_handler() + * Terminates all the modules. + */ +static void nssinfo_termination_handler(int signum) +{ + pthread_cancel(nssinfo_display_thread); +} + +/* + * nssinfo_display_init() + * Handle displaying all the stats. + */ +static int nssinfo_display_init() +{ + int error; + + if (!output_file) { + if (nssinfo_curses_init() != 0) { + return -1; + } + } + + error = pthread_create(&nssinfo_display_thread, NULL, nssinfo_stats_display, NULL); + if (error) { + nssinfo_error("failed to create display thread, error %d\n", error); + if (!output_file) { + endwin(); + } + } + + return error; +} + +/* + * nssinfo_display_wait() + * Wait for the display thread. + */ +static int nssinfo_display_wait() +{ + /* + * waiting for the display thread to be terminated. + */ + pthread_join(nssinfo_display_thread, NULL); + + if (!output_file) { + refresh(); + endwin(); + } + + return 0; +} + +/* + * nssinfo_notify_callback + * Get notified when NL message is received. + */ +static void nssinfo_notify_callback(int cmd, void *data) +{ + if (cmd < NSS_NLCMN_SUBSYS_MAX && nssinfo_subsystem_array[cmd].is_inited) { + nssinfo_subsystem_array[cmd].notify(data); + } else { + nssinfo_error("Unknown message type %d\n", cmd); + } +} + +/* + */ +static void nssinfo_deinit(struct nss_nlmcast_ctx *ctx) +{ + int i, core; + struct node *node; + nssinfo_deinit_t deinit; + + /* + * Close NL socket and terminate ctx->sock.thread + */ + nss_nlmcast_sock_close(ctx); + + /* + * Release memory used for storing stats + */ + for (core = 0; core < NSS_MAX_CORES; ++core) { + for (i = 0; i < NSS_MAX_NET_INTERFACES; ++i) { + node = nodes[core][i]; + if (node) { + assert(node->subsystem_id != NSS_NLCMN_SUBSYS_DYNAMIC_INTERFACE); + nssinfo_subsystem_array[node->subsystem_id].destroy(core, i); + } + } + } + + /* + * Release resources used by each subsystem + */ + for (i = 0; i < NSS_NLCMN_SUBSYS_MAX; i++) { + deinit = nssinfo_subsystem_array[i].deinit; + if (deinit) { + deinit(ctx); + } + } +} + +/* + * nssinfo_init() + * Initialize all the modules. + */ +int nssinfo_init(void) +{ + int error, i; + struct nss_nlmcast_ctx ctx; + nssinfo_init_t init; + + memset(&ctx, 0, sizeof(ctx)); + + /* + * Create NL socket + */ + error = nss_nlmcast_sock_open(&ctx, nssinfo_notify_callback, NULL); + if (error) { + nssinfo_error("Socket creation failed for NSSINFO, error(%d)\n", error); + return error; + } + + /* + * Initialize all the subsystems and subscribe for mcast groups. + */ + for (i = 0; i < NSS_NLCMN_SUBSYS_MAX; i++) { + init = nssinfo_subsystem_array[i].init; + if (init) { + error = init(&ctx); + if (error) { + nssinfo_error("%s init failed, error(%d)\n", nssinfo_subsystem_array[i].subsystem_name, error); + } + } + } + + /* + * Listen for MCAST events from kernel. + */ + error = nss_nlmcast_sock_listen(&ctx); + if (error < 0) { + nssinfo_error("failed to listen for mcast events from kernel\n"); + goto end; + } + + /* + * Create a thread which displays the stats continuously. + */ + error = nssinfo_display_init(); + if (error) { + goto end; + } + + /* + * Install CTRL-C handler + */ + struct sigaction new_action; + new_action.sa_handler = nssinfo_termination_handler; + sigemptyset(&new_action.sa_mask); + new_action.sa_flags = 0; + error = sigaction(SIGINT, &new_action, NULL); + if (error) { + nssinfo_error("failed to install CTRL-C handler\n"); + goto end; + } + + /* + * main thread is waiting here + */ + nssinfo_display_wait(); + +end: + nssinfo_deinit(&ctx); + return error; +} diff --git a/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo.h b/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo.h new file mode 100644 index 0000000000..6a3d10b246 --- /dev/null +++ b/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo.h @@ -0,0 +1,233 @@ +/* + ************************************************************************** + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +#ifndef __NSSINFO_FAMILY_H +#define __NSSINFO_FAMILY_H + +#include "nss_nlbase.h" +#include "ncurses.h" +#include "nssinfo_ipv4.h" +#include "nssinfo_ipv6.h" +#include "nssinfo_ethrx.h" +#include "nssinfo_n2h.h" +#include "nssinfo_dynamic_interface.h" +#include "nssinfo_lso_rx.h" +#include "nss_api_if.h" +#include "nss_dynamic_interface.h" +#include "nss_stats_public.h" + +#define NSSINFO_COLOR_RST "\x1b[0m" +#define NSSINFO_COLOR_GRN "\x1b[32m" +#define NSSINFO_COLOR_RED "\x1b[31m" +#define NSSINFO_COLOR_MGT "\x1b[35m" + +#ifdef ENABLE_DEBUG +#define nssinfo_info(fmt, arg...) printf(NSSINFO_COLOR_GRN"INF "NSSINFO_COLOR_RST fmt, ## arg) +#define nssinfo_trace(fmt, arg...) printf(NSSINFO_COLOR_MGT"TRC(%s:%d) "NSSINFO_COLOR_RST fmt, __func__, __LINE__, ## arg) +#define nssinfo_options(fmt, arg...) printf(NSSINFO_COLOR_MGT"OPT_%d "NSSINFO_COLOR_RST fmt, ## arg) +#define nssinfo_warn(fmt, arg...) printf(NSSINFO_COLOR_RED"WARN(%s:%d) "NSSINFO_COLOR_RST fmt, __func__, __LINE__, ##arg) +#else +#define nssinfo_info(fmt, arg...) +#define nssinfo_trace(fmt, arg...) +#define nssinfo_options(fmt, arg...) +#define nssinfo_warn(fmt, arg...) +#endif +#define nssinfo_error(fmt, arg...) printf(NSSINFO_COLOR_RED"ERR(%s:%d) "NSSINFO_COLOR_RST fmt, __func__, __LINE__, ## arg) + +#define nssinfo_stats_print(fmt, arg...) ({ \ + if (output_file) { \ + fprintf(output_file, fmt, ## arg); \ + } else { \ + wprintw(stdscr, fmt, ## arg); \ + } \ + }) +/* + * Minimum terminal size to use curses library + */ +#define CURSES_ROWS_MIN 4 +#define CURSES_COLS_MIN 48 + +/* + * Maximum formatted statistics length + */ +#define NSSINFO_STR_LEN 30 + +extern bool display_all_stats; +extern FILE *output_file; +extern FILE *flow_file; +extern int invalid_input; +extern struct arguments arguments; +extern char *nssinfo_summary_fmt; + +/** + * @brief display method_t function + * + * @param core[IN] NSS core id + */ +typedef void (*nssinfo_stats_display_t)(int core, char *input); + +/** + * @brief stats notify method_t function + * + * @param data[IN] data received from Netlink client + */ +typedef void (*nssinfo_stats_notify_t)(void *data); + +/** + * @brief init method_t function + * + * @param data[IN] an opague context to be used for initialization + */ +typedef int (*nssinfo_init_t)(void *data); + +/** + * @brief deinit method_t function + * + * @param data[IN] an opague context to be used for deinitialization + */ +typedef void (*nssinfo_deinit_t)(void *data); + +/** + * @brief destroy method_t function + * + * @param core_id[IN] core id of the node to be destroyed + * @param if_num[IN] interface id of the node to be destroyed + */ +typedef void (*nssinfo_destroy_t)(uint32_t core_id, uint32_t if_num); + +/** + * @brief Used by main to communicate with parse_opt + */ +struct arguments { + bool verbose; /*< '-v' >*/ + char *output_file; /*< file arg to '--output' >*/ + char *flow_file; /*< file arg to '--flowfile' >*/ + bool higher_unit; /*< display higher units '-h' >*/ + int core; /*< core id >*/ + char **strings; /*< non-option arguments: [NODE1 [NODE2 ...]] >*/ + int rate; /*< display rate in second >*/ +}; + +/** + * @brief NSSINFO subsystem information + */ +struct nssinfo_subsystem_info { + char *subsystem_name; /**< Subsystem name string */ + nssinfo_init_t init; /**< Initialize method_t */ + nssinfo_deinit_t deinit; /**< Deinitialize method_t */ + nssinfo_stats_display_t display; /**< Display method_t */ + nssinfo_stats_notify_t notify; /**< Stats notify method_t */ + nssinfo_destroy_t destroy; /**< Stats notify method_t */ + bool is_inited; /**< True if the subsystem is initialized */ +}; + +extern struct nssinfo_subsystem_info nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_MAX]; + +/** + * @brief NSSINFO pnode stats + */ +struct node { + struct node *next; /**< Pointer to next node */ + uint64_t id; /**< Dynamic interface number */ + int type; /**< see 'enum nss_dynamic_interface_type' */ + int subsystem_id; /**< see 'enum nss_nlcmn_subsys' */ + void *cmn_node_stats; /**< Common node stats */ + void *node_stats; /**< Special stats */ + void *exception_stats; /**< Exception stats */ +}; + +extern struct node *nodes[NSS_MAX_CORES][NSS_MAX_NET_INTERFACES]; + +/** + * @brief Structure definition carrying stats info. + */ +struct nssinfo_stats_info { + char stats_name[NSS_STATS_MAX_STR_LENGTH]; /* stat name */ + int stats_type; /* enum that tags stat type */ +}; + +/** + * @brief validates core id and interface number + * + * @param core_id[IN] validates the core d + * @param if_num[IN] validates the interface number + * + * @return true on success or false for failure + */ +static inline bool nssinfo_coreid_ifnum_valid(uint32_t core_id, uint32_t if_num) +{ + return (core_id < NSS_MAX_CORES && if_num < NSS_MAX_NET_INTERFACES); +} + +/** + * @brief initialize all the modules + * + * @param flow_file[IN] parse it and display output accordingly + * + * @return 0 on success or -ve for failure + */ +int nssinfo_init(void); + +/** + * @brief Format statistics value + * + * @param num[IN] statistics value in uint64_t + * + * @return comma separated string + */ +char* nssinfo_format_stats(uint64_t num); + +/** + * @brief Init nssinfo_stats_info from kernel debug file. + * + * @param info[IN] pointer to a nssinfo_stats_info array + * @param line[IN] string file in kernel/debug/qca-nss-drv/strings/ + */ +int nssinfo_stats_info_init(struct nssinfo_stats_info *info, char *strings_file); + +/** + * @brief Free all resources used for node stats. + * + * @param mutex[IN] mutex lock + * @param core_id[IN] core id + * @param if_num[IN] node's interface number + */ +void nssinfo_node_stats_destroy(pthread_mutex_t *mutex, uint32_t core_id, uint32_t if_num); + +/** + * @brief Print detailed statistics. + * + * @param node[IN] node for which stats to be printed + * @param stat_details[IN] statistics details to be printed + * @param stats_info[IN] statistics information + * @param max[IN] maximum number of strings + * @param stats_val[IN] statistics values + */ +void nssinfo_print_all(char *node, char *stat_details, struct nssinfo_stats_info *stats_info, uint64_t max, uint64_t *stats_val); + +/** + * @brief Print the summary of the statistics. + * + * @param node[IN] node for which stats to be printed + * @param cmn_node_stats[IN] common node stats + * @param exception_stats[IN] exception stats + * @param exception_max[IN] maximum exception type + */ +void nssinfo_print_summary(char *node, uint64_t *cmn_node_stats, uint64_t *exception_stats, uint64_t exception_max); + +void nssinfo_print_summary_header(void); + +#endif /* __NSSINFO_FAMILY_H*/ diff --git a/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_dynamic_interface.c b/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_dynamic_interface.c new file mode 100644 index 0000000000..3d3c4124ed --- /dev/null +++ b/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_dynamic_interface.c @@ -0,0 +1,72 @@ +/* + ************************************************************************** + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +/* + * @file NSSINFO dynamic interface handler + */ +#include "nssinfo.h" +#include + +/* + * nssinfo_dynamic_interface_destroy_notify() + * Dynamic interface notify callback function. + */ +static void nssinfo_dynamic_interface_destroy_notify(void *data) +{ + struct nss_dynamic_interface_notification *nss_info = (struct nss_dynamic_interface_notification *)data; + struct node *node = nodes[nss_info->core_id][nss_info->if_num]; + + if (!node) { + return; + } + + nssinfo_subsystem_array[node->subsystem_id].destroy(nss_info->core_id, nss_info->if_num); +} + +/* + * nssinfo_dynamic_interface_deinit() + * Deinitialize dynamic_interface module. + */ +void nssinfo_dynamic_interface_deinit(void *data) +{ + struct nss_nlmcast_ctx *ctx = (struct nss_nlmcast_ctx *)data; + + nss_nlmcast_sock_leave_grp(ctx, NSS_NLDYNAMIC_INTERFACE_MCAST_GRP); +} + +/* + * nssinfo_dynamic_interface_init() + * Initialize dynamic interface module. + */ +int nssinfo_dynamic_interface_init(void *data) +{ + int error; + struct nss_nlmcast_ctx *ctx = (struct nss_nlmcast_ctx *)data; + + /* + * Subscribe for dynamic interface multicast group. + */ + nss_nlsock_set_family(&ctx->sock, NSS_NLDYNAMIC_INTERFACE_FAMILY); + error = nss_nlmcast_sock_join_grp(ctx, NSS_NLDYNAMIC_INTERFACE_MCAST_GRP); + if (error) { + nssinfo_warn("Unable to join dynamic interface multicast group.\n"); + return error; + } + + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_DYNAMIC_INTERFACE].notify = nssinfo_dynamic_interface_destroy_notify; + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_DYNAMIC_INTERFACE].is_inited = true; + return 0; +} diff --git a/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_dynamic_interface.h b/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_dynamic_interface.h new file mode 100644 index 0000000000..6e33fa16c7 --- /dev/null +++ b/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_dynamic_interface.h @@ -0,0 +1,28 @@ +/* + ************************************************************************** + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +#ifndef __NSSINFO_DYNAMIC_INTERFACE_H +#define __NSSINFO_DYNAMIC_INTERFACE_H + +/** + * @brief initialize dynamic interface module. + * + * @return 0 on success or -ve for failure + */ +int nssinfo_dynamic_interface_init(void *data); +void nssinfo_dynamic_interface_deinit(void *data); + +#endif /* __NSSINFO_DYNAMIC_INTERFACE_H*/ diff --git a/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_ethrx.c b/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_ethrx.c new file mode 100644 index 0000000000..5b80c15d42 --- /dev/null +++ b/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_ethrx.c @@ -0,0 +1,215 @@ +/* + ************************************************************************** + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +/* + * @file NSSINFO Ethernet Rx handler + */ +#include "nssinfo.h" +#include +#include + +static pthread_mutex_t eth_rx_lock; +static struct nssinfo_stats_info nss_eth_rx_cmn_stats_str[NSS_STATS_NODE_MAX]; +static struct nssinfo_stats_info nss_eth_rx_stats_str[NSS_ETH_RX_STATS_MAX]; +static struct nssinfo_stats_info nss_eth_rx_exception_stats_str[NSS_ETH_RX_EXCEPTION_EVENT_MAX]; + +/* + * nssinfo_eth_rx_stats_display() + * Ethernet Rx display callback function. + */ +static void nssinfo_eth_rx_stats_display(int core, char *input) +{ + struct node *eth_rx_node; + + if (input && strncmp(input, nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_ETHRX].subsystem_name, strlen(input))) { + ++invalid_input; + nssinfo_trace("Invalid node name: %s\n", input); + return; + } + + pthread_mutex_lock(ð_rx_lock); + eth_rx_node = nodes[core][NSS_ETH_RX_INTERFACE]; + if (!eth_rx_node) { + pthread_mutex_unlock(ð_rx_lock); + return; + } + + if (!display_all_stats) { + nssinfo_print_summary("eth_rx", (uint64_t *)eth_rx_node->cmn_node_stats, (uint64_t *)eth_rx_node->exception_stats, NSS_ETH_RX_EXCEPTION_EVENT_MAX); + pthread_mutex_unlock(ð_rx_lock); + return; + } + + nssinfo_print_all("eth_rx", "eth_rx Common Stats", nss_eth_rx_cmn_stats_str, NSS_STATS_NODE_MAX, (uint64_t *)eth_rx_node->cmn_node_stats); + nssinfo_print_all("eth_rx", "eth_rx Special Stats", nss_eth_rx_stats_str, NSS_ETH_RX_STATS_MAX, (uint64_t *)eth_rx_node->node_stats); + nssinfo_print_all("eth_rx", "eth_rx Exception Stats", nss_eth_rx_exception_stats_str, NSS_ETH_RX_EXCEPTION_EVENT_MAX, (uint64_t *)eth_rx_node->exception_stats); + + pthread_mutex_unlock(ð_rx_lock); +} + +/* + * nssinfo_eth_rx_stats_notify() + * Ethernet Rx statistics notify callback function. + */ +static void nssinfo_eth_rx_stats_notify(void *data) +{ + uint64_t *cmn_node_stats, *node_stats, *exception_stats; + struct nss_eth_rx_stats_notification *nss_stats = (struct nss_eth_rx_stats_notification *)data; + struct node *eth_rx_node; + struct node **eth_rx_ptr; + + if (!nssinfo_coreid_ifnum_valid(nss_stats->core_id, NSS_ETH_RX_INTERFACE)) { + return; + } + + pthread_mutex_lock(ð_rx_lock); + eth_rx_ptr = &nodes[nss_stats->core_id][NSS_ETH_RX_INTERFACE]; + eth_rx_node = *eth_rx_ptr; + if (eth_rx_node) { + memcpy(eth_rx_node->cmn_node_stats, &nss_stats->cmn_node_stats, sizeof(nss_stats->cmn_node_stats)); + memcpy(eth_rx_node->node_stats, &nss_stats->special_stats, sizeof(nss_stats->special_stats)); + memcpy(eth_rx_node->exception_stats, &nss_stats->exception_stats, sizeof(nss_stats->exception_stats)); + pthread_mutex_unlock(ð_rx_lock); + return; + } + pthread_mutex_unlock(ð_rx_lock); + + eth_rx_node = (struct node *)calloc(1, sizeof(struct node)); + if (!eth_rx_node) { + nssinfo_warn("Failed to allocate memory for eth rx node\n"); + return; + } + + cmn_node_stats = (uint64_t *)malloc(sizeof(nss_stats->cmn_node_stats)); + if (!cmn_node_stats) { + nssinfo_warn("Failed to allocate memory for eth rx common node statistics\n"); + goto eth_rx_node_free; + } + + node_stats = (uint64_t *)malloc(sizeof(nss_stats->special_stats)); + if (!node_stats) { + nssinfo_warn("Failed to allocate memory for eth rx special stats\n"); + goto cmn_node_stats_free; + } + + exception_stats = (uint64_t *)malloc(sizeof(nss_stats->exception_stats)); + if (!exception_stats) { + nssinfo_warn("Failed to allocate memory for eth rx exception stats\n"); + goto node_stats_free; + } + + memcpy(cmn_node_stats, &nss_stats->cmn_node_stats, sizeof(nss_stats->cmn_node_stats)); + memcpy(node_stats, &nss_stats->special_stats, sizeof(nss_stats->special_stats)); + memcpy(exception_stats, &nss_stats->exception_stats, sizeof(nss_stats->exception_stats)); + eth_rx_node->cmn_node_stats = cmn_node_stats; + eth_rx_node->node_stats = node_stats; + eth_rx_node->exception_stats = exception_stats; + eth_rx_node->subsystem_id = NSS_NLCMN_SUBSYS_ETHRX; + + /* + * Notifify is guaranteed to be single threaded via Netlink listen callback + */ + pthread_mutex_lock(ð_rx_lock); + nodes[nss_stats->core_id][NSS_ETH_RX_INTERFACE] = eth_rx_node; + pthread_mutex_unlock(ð_rx_lock); + return; + +node_stats_free: + free(node_stats); + +cmn_node_stats_free: + free(cmn_node_stats); + +eth_rx_node_free: + free(eth_rx_node); + return; +} + +/* + * nssinfo_eth_rx_destroy() + * Destroy ethernet Rx node. + */ +static void nssinfo_eth_rx_destroy(uint32_t core_id, uint32_t if_num) +{ + if (nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_ETHRX].is_inited) { + nssinfo_node_stats_destroy(ð_rx_lock, core_id, NSS_ETH_RX_INTERFACE); + } +} + +/* + * nssinfo_ethrx_deinit() + * Deinitialize ethrx module. + */ +void nssinfo_eth_rx_deinit(void *data) +{ + struct nss_nlmcast_ctx *ctx = (struct nss_nlmcast_ctx *)data; + + if (nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_ETHRX].is_inited) { + pthread_mutex_destroy(ð_rx_lock); + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_ETHRX].is_inited = false; + } + + nss_nlmcast_sock_leave_grp(ctx, NSS_NLETHRX_MCAST_GRP); +} + +/* + * nssinfo_eth_rx_init() + * Initialize Ethernet Rx module. + */ +int nssinfo_eth_rx_init(void *data) +{ + int error; + struct nss_nlmcast_ctx *ctx = (struct nss_nlmcast_ctx *)data; + + /* + * Subscribe for Ethernet Rx MCAST group. + */ + nss_nlsock_set_family(&ctx->sock, NSS_NLETHRX_FAMILY); + error = nss_nlmcast_sock_join_grp(ctx, NSS_NLETHRX_MCAST_GRP); + if (error) { + nssinfo_warn("Unable to join Ethernet Rx mcast group.\n"); + return error; + } + + if (nssinfo_stats_info_init(nss_eth_rx_cmn_stats_str, + "/sys/kernel/debug/qca-nss-drv/strings/common_node_stats") != 0) { + goto fail; + } + + if (nssinfo_stats_info_init(nss_eth_rx_stats_str, + "/sys/kernel/debug/qca-nss-drv/strings/eth_rx/special_stats_str") != 0) { + goto fail; + } + + if (nssinfo_stats_info_init(nss_eth_rx_exception_stats_str, + "/sys/kernel/debug/qca-nss-drv/strings/eth_rx/exception_stats_str") != 0) { + goto fail; + } + + if (pthread_mutex_init(ð_rx_lock, NULL) != 0) { + nssinfo_warn("Mutex init has failed for Ethernet Rx\n"); + goto fail; + } + + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_ETHRX].display = nssinfo_eth_rx_stats_display; + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_ETHRX].notify = nssinfo_eth_rx_stats_notify; + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_ETHRX].destroy = nssinfo_eth_rx_destroy; + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_ETHRX].is_inited = true; + return 0; +fail: + nss_nlmcast_sock_leave_grp(ctx, NSS_NLETHRX_MCAST_GRP); + return -1; +} diff --git a/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_ethrx.h b/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_ethrx.h new file mode 100644 index 0000000000..e1261f7cc2 --- /dev/null +++ b/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_ethrx.h @@ -0,0 +1,28 @@ +/* + ************************************************************************** + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +#ifndef __NSSINFO_ETHRX_H +#define __NSSINFO_ETHRX_H + +/** + * @brief initialize Ethernet Rx module. + * + * @return 0 on success or -ve for failure + */ +int nssinfo_eth_rx_init(void *data); +void nssinfo_eth_rx_deinit(void *data); + +#endif /* __NSSINFO_ETHRX_H*/ diff --git a/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_ipv4.c b/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_ipv4.c new file mode 100644 index 0000000000..83e8386d0a --- /dev/null +++ b/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_ipv4.c @@ -0,0 +1,215 @@ +/* + ************************************************************************** + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +/* + * @file NSSINFO ipv4 handler + */ +#include "nssinfo.h" + +static pthread_mutex_t ipv4_lock; +static struct nssinfo_stats_info nss_stats_str_node[NSS_STATS_NODE_MAX]; +static struct nssinfo_stats_info nss_ipv4_stats_str[NSS_IPV4_STATS_MAX]; +static struct nssinfo_stats_info nss_ipv4_exception_stats_str[NSS_IPV4_EXCEPTION_EVENT_MAX]; + +/* + * nssinfo_ipv4_stats_display() + * IPv4 display callback function. + */ +static void nssinfo_ipv4_stats_display(int core, char *input) +{ + struct node *ipv4_node; + + if (input && strncmp(input, nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_IPV4].subsystem_name, strlen(input)) != 0) { + ++invalid_input; + nssinfo_trace("Invalid node name: %s\n", input); + return; + } + + pthread_mutex_lock(&ipv4_lock); + ipv4_node = nodes[core][NSS_IPV4_RX_INTERFACE]; + if (!ipv4_node) { + pthread_mutex_unlock(&ipv4_lock); + return; + } + + if (!display_all_stats) { + nssinfo_print_summary("ipv4", (uint64_t *)ipv4_node->cmn_node_stats, (uint64_t *)ipv4_node->exception_stats, NSS_IPV4_EXCEPTION_EVENT_MAX); + pthread_mutex_unlock(&ipv4_lock); + return; + } + + nssinfo_print_all("ipv4", "ipv4 Common Stats", nss_stats_str_node, NSS_STATS_NODE_MAX, (uint64_t *)ipv4_node->cmn_node_stats); + nssinfo_print_all("ipv4", "ipv4 Special Stats", nss_ipv4_stats_str, NSS_IPV4_STATS_MAX, (uint64_t *)ipv4_node->node_stats); + nssinfo_print_all("ipv4", "ipv4 Exception Stats", nss_ipv4_exception_stats_str, NSS_IPV4_EXCEPTION_EVENT_MAX, (uint64_t *)ipv4_node->exception_stats); + + pthread_mutex_unlock(&ipv4_lock); +} + +/* + * nssinfo_ipv4_stats_notify() + * IPv4 stats notify callback function. + */ +static void nssinfo_ipv4_stats_notify(void *data) +{ + uint64_t *cmn_node_stats, *node_stats, *exception_stats; + struct nss_nlipv4_rule *rule = (struct nss_nlipv4_rule *)data; + struct node *ipv4_node; + struct node **ipv4_ptr; + + if (!nssinfo_coreid_ifnum_valid(rule->stats.core_id, NSS_IPV4_RX_INTERFACE)) { + return; + } + + ipv4_ptr = &nodes[rule->stats.core_id][NSS_IPV4_RX_INTERFACE]; + + pthread_mutex_lock(&ipv4_lock); + ipv4_node = *ipv4_ptr; + if (ipv4_node) { + memcpy(ipv4_node->cmn_node_stats, &rule->stats.cmn_node_stats, sizeof(rule->stats.cmn_node_stats)); + memcpy(ipv4_node->node_stats, &rule->stats.special_stats, sizeof(rule->stats.special_stats)); + memcpy(ipv4_node->exception_stats, &rule->stats.exception_stats, sizeof(rule->stats.exception_stats)); + pthread_mutex_unlock(&ipv4_lock); + return; + } + pthread_mutex_unlock(&ipv4_lock); + + ipv4_node = (struct node *)calloc(1, sizeof(struct node)); + if (!ipv4_node) { + nssinfo_warn("Failed to allocate memory for ipv4 node\n"); + return; + } + + cmn_node_stats = (uint64_t *)malloc(sizeof(rule->stats.cmn_node_stats)); + if (!cmn_node_stats) { + nssinfo_warn("Failed to allocate memory for ipv4 common node stats\n"); + goto ipv4_node_free; + } + + node_stats = (uint64_t *)malloc(sizeof(rule->stats.special_stats)); + if (!node_stats) { + nssinfo_warn("Failed to allocate memory for ipv4 special stats\n"); + goto cmn_node_stats_free; + } + + exception_stats = (uint64_t *)malloc(sizeof(rule->stats.exception_stats)); + if (!exception_stats) { + nssinfo_warn("Failed to allocate memory for ipv4 exception stats\n"); + goto node_stats_free; + } + + memcpy(cmn_node_stats, &rule->stats.cmn_node_stats, sizeof(rule->stats.cmn_node_stats)); + memcpy(node_stats, &rule->stats.special_stats, sizeof(rule->stats.special_stats)); + memcpy(exception_stats, &rule->stats.exception_stats, sizeof(rule->stats.exception_stats)); + + ipv4_node->cmn_node_stats = cmn_node_stats; + ipv4_node->node_stats = node_stats; + ipv4_node->exception_stats = exception_stats; + ipv4_node->subsystem_id = NSS_NLCMN_SUBSYS_IPV4; + + /* + * Notifify is guaranteed to be single threaded via Netlink listen callback + */ + pthread_mutex_lock(&ipv4_lock); + *ipv4_ptr = ipv4_node; + pthread_mutex_unlock(&ipv4_lock); + return; + +node_stats_free: + free(node_stats); + +cmn_node_stats_free: + free(cmn_node_stats); + +ipv4_node_free: + free(ipv4_node); +} + +/* + * nssinfo_ipv4_destroy() + * Destroy IPv4 node. + */ +static void nssinfo_ipv4_destroy(uint32_t core_id, uint32_t if_num) +{ + if (nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_IPV4].is_inited) { + nssinfo_node_stats_destroy(&ipv4_lock, core_id, NSS_IPV4_RX_INTERFACE); + } +} + +/* + * nssinfo_ipv4_deinit() + * Initialize IPv4 module. + */ +void nssinfo_ipv4_deinit(void *data) +{ + struct nss_nlmcast_ctx *ctx = (struct nss_nlmcast_ctx *)data; + + if (nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_IPV4].is_inited) { + pthread_mutex_destroy(&ipv4_lock); + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_IPV4].is_inited = false; + } + + nss_nlmcast_sock_leave_grp(ctx, NSS_NLIPV4_MCAST_GRP); +} + +/* + * nssinfo_ipv4_init() + * Initialize IPv4 module. + */ +int nssinfo_ipv4_init(void *data) +{ + int error; + struct nss_nlmcast_ctx *ctx = (struct nss_nlmcast_ctx *)data; + + /* + * Subscribe for IPV4 MCAST group. + */ + nss_nlsock_set_family(&ctx->sock, NSS_NLIPV4_FAMILY); + error = nss_nlmcast_sock_join_grp(ctx, NSS_NLIPV4_MCAST_GRP); + if (error) { + nssinfo_warn("Unable to join IPv4 mcast group\n"); + return error; + } + + if (nssinfo_stats_info_init(nss_stats_str_node, + "/sys/kernel/debug/qca-nss-drv/strings/common_node_stats") != 0) { + goto fail; + } + + if (nssinfo_stats_info_init(nss_ipv4_stats_str, + "/sys/kernel/debug/qca-nss-drv/strings/ipv4/special_stats_str") != 0) { + goto fail; + } + + if (nssinfo_stats_info_init(nss_ipv4_exception_stats_str, + "/sys/kernel/debug/qca-nss-drv/strings/ipv4/exception_stats_str") != 0) { + goto fail; + } + + if (pthread_mutex_init(&ipv4_lock, NULL) != 0) { + nssinfo_warn("Mutex init has failed for IPV4\n"); + goto fail; + } + + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_IPV4].display = nssinfo_ipv4_stats_display; + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_IPV4].notify = nssinfo_ipv4_stats_notify; + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_IPV4].destroy = nssinfo_ipv4_destroy; + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_IPV4].is_inited = true; + return 0; + +fail: + nss_nlmcast_sock_leave_grp(ctx, NSS_NLIPV4_MCAST_GRP); + return -1; +} diff --git a/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_ipv4.h b/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_ipv4.h new file mode 100644 index 0000000000..ca2993994e --- /dev/null +++ b/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_ipv4.h @@ -0,0 +1,30 @@ +/* + ************************************************************************** + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +#ifndef __NSSINFO_IPV4_H +#define __NSSINFO_IPV4_H + +#define NSSINFO_IPV4_HDR_VERSION 4 + +/** + * @brief initialize IPv4 module. + * + * @return 0 on success or -ve for failure + */ +int nssinfo_ipv4_init(void *data); +void nssinfo_ipv4_deinit(void *data); + +#endif /* __NSSINFO_IPV4_H*/ diff --git a/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_ipv6.c b/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_ipv6.c new file mode 100644 index 0000000000..16af31c0fc --- /dev/null +++ b/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_ipv6.c @@ -0,0 +1,212 @@ +/* + ************************************************************************** + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +/* + * @file NSSINFO ipv6 handler + */ +#include "nssinfo.h" + +static pthread_mutex_t ipv6_lock; +static struct nssinfo_stats_info nss_stats_str_node[NSS_STATS_NODE_MAX]; +static struct nssinfo_stats_info nss_ipv6_stats_str[NSS_IPV6_STATS_MAX]; +static struct nssinfo_stats_info nss_ipv6_exception_stats_str[NSS_IPV6_EXCEPTION_EVENT_MAX]; + +/* + * nssinfo_ipv6_stats_display() + * IPv6 display callback function. + */ +static void nssinfo_ipv6_stats_display(int core, char *input) +{ + struct node *ipv6_node; + + if (input && strncmp(input, nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_IPV6].subsystem_name, strlen(input))) { + ++invalid_input; + nssinfo_trace("Invalid node name: %s\n", input); + return; + } + + pthread_mutex_lock(&ipv6_lock); + ipv6_node = nodes[core][NSS_IPV6_RX_INTERFACE]; + if (!ipv6_node) { + pthread_mutex_unlock(&ipv6_lock); + return; + } + + if (display_all_stats) { + nssinfo_print_all("ipv6", "ipv6 Common Stats", nss_stats_str_node, NSS_STATS_NODE_MAX, (uint64_t *)ipv6_node->cmn_node_stats); + nssinfo_print_all("ipv6", "ipv6 Special Stats", nss_ipv6_stats_str, NSS_IPV6_STATS_MAX, (uint64_t *)ipv6_node->node_stats); + nssinfo_print_all("ipv6", "ipv6 Exception Stats", nss_ipv6_exception_stats_str, NSS_IPV6_EXCEPTION_EVENT_MAX, (uint64_t *)ipv6_node->exception_stats); + + pthread_mutex_unlock(&ipv6_lock); + return; + } + + nssinfo_print_summary("ipv6", (uint64_t *)ipv6_node->cmn_node_stats, (uint64_t *)ipv6_node->exception_stats, NSS_IPV6_EXCEPTION_EVENT_MAX); + pthread_mutex_unlock(&ipv6_lock); +} + +/* + * nssinfo_ipv6_stats_notify() + * IPv6 stats notify callback function. + */ +static void nssinfo_ipv6_stats_notify(void *data) +{ + uint64_t *cmn_node_stats, *node_stats, *exception_stats; + struct nss_nlipv6_rule *rule = (struct nss_nlipv6_rule *)data; + struct node *ipv6_node; + struct node **ipv6_ptr; + + if (!nssinfo_coreid_ifnum_valid(rule->stats.core_id, NSS_IPV6_RX_INTERFACE)) { + return; + } + + pthread_mutex_lock(&ipv6_lock); + ipv6_ptr = &nodes[rule->stats.core_id][NSS_IPV6_RX_INTERFACE]; + ipv6_node = *ipv6_ptr; + if (ipv6_node) { + memcpy(ipv6_node->cmn_node_stats, &rule->stats.cmn_node_stats, sizeof(rule->stats.cmn_node_stats)); + memcpy(ipv6_node->node_stats, &rule->stats.special_stats, sizeof(rule->stats.special_stats)); + memcpy(ipv6_node->exception_stats, &rule->stats.exception_stats, sizeof(rule->stats.exception_stats)); + pthread_mutex_unlock(&ipv6_lock); + return; + } + pthread_mutex_unlock(&ipv6_lock); + + ipv6_node = (struct node *)calloc(1, sizeof(struct node)); + if (!ipv6_node) { + nssinfo_warn("Failed to allocate memory for ipv6 node\n"); + return; + } + + cmn_node_stats = (uint64_t *)malloc(sizeof(rule->stats.cmn_node_stats)); + if (!cmn_node_stats) { + nssinfo_warn("Failed to allocate memory for ipv6 common node statistics\n"); + goto ipv6_node_free; + } + + node_stats = (uint64_t *)malloc(sizeof(rule->stats.special_stats)); + if (!node_stats) { + nssinfo_warn("Failed to allocate memory for ipv6 special stats\n"); + goto cmn_node_stats_free; + } + + exception_stats = (uint64_t *)malloc(sizeof(rule->stats.exception_stats)); + if (!exception_stats) { + nssinfo_warn("Failed to allocate memory for ipv6 exception stats\n"); + goto node_stats_free; + } + + memcpy(cmn_node_stats, &rule->stats.cmn_node_stats, sizeof(rule->stats.cmn_node_stats)); + memcpy(node_stats, &rule->stats.special_stats, sizeof(rule->stats.special_stats)); + memcpy(exception_stats, &rule->stats.exception_stats, sizeof(rule->stats.exception_stats)); + ipv6_node->cmn_node_stats = cmn_node_stats; + ipv6_node->node_stats = node_stats; + ipv6_node->exception_stats = exception_stats; + ipv6_node->subsystem_id = NSS_NLCMN_SUBSYS_IPV6; + + /* + * Notifify is guaranteed to be single threaded via Netlink listen callback + */ + pthread_mutex_lock(&ipv6_lock); + *ipv6_ptr = ipv6_node; + pthread_mutex_unlock(&ipv6_lock); + return; + +node_stats_free: + free(node_stats); + +cmn_node_stats_free: + free(cmn_node_stats); + +ipv6_node_free: + free(ipv6_node); +} + +/* + * nssinfo_ipv6_destroy() + * Destroy IPv6 node. + */ +static void nssinfo_ipv6_destroy(uint32_t core_id, uint32_t if_num) +{ + if (nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_IPV6].is_inited) { + nssinfo_node_stats_destroy(&ipv6_lock, core_id, NSS_IPV6_RX_INTERFACE); + } +} + +/* + * nssinfo_ipv6_deinit() + * Deinitialize ipv6 module. + */ +void nssinfo_ipv6_deinit(void *data) +{ + struct nss_nlmcast_ctx *ctx = (struct nss_nlmcast_ctx *)data; + + if (nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_IPV6].is_inited) { + pthread_mutex_destroy(&ipv6_lock); + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_IPV6].is_inited = false; + } + + nss_nlmcast_sock_leave_grp(ctx, NSS_NLIPV6_MCAST_GRP); +} + +/* + * nssinfo_ipv6_init() + * Initialize IPv6 module. + */ +int nssinfo_ipv6_init(void *data) +{ + int error; + struct nss_nlmcast_ctx *ctx = (struct nss_nlmcast_ctx *)data; + + /* + * Subscribe for IPV6 MCAST group. + */ + nss_nlsock_set_family(&ctx->sock, NSS_NLIPV6_FAMILY); + error = nss_nlmcast_sock_join_grp(ctx, NSS_NLIPV6_MCAST_GRP); + if (error) { + nssinfo_warn("Unable to join IPv6 mcast group\n"); + return error; + } + + if (nssinfo_stats_info_init(nss_stats_str_node, + "/sys/kernel/debug/qca-nss-drv/strings/common_node_stats") != 0) { + goto fail; + } + + if (nssinfo_stats_info_init(nss_ipv6_stats_str, + "/sys/kernel/debug/qca-nss-drv/strings/ipv6/special_stats_str") != 0) { + goto fail; + } + + if (nssinfo_stats_info_init(nss_ipv6_exception_stats_str, + "/sys/kernel/debug/qca-nss-drv/strings/ipv6/exception_stats_str") != 0) { + goto fail; + } + + if (pthread_mutex_init(&ipv6_lock, NULL) != 0) { + nssinfo_warn("Mutex init has failed for IPV6\n"); + goto fail; + } + + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_IPV6].display = nssinfo_ipv6_stats_display; + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_IPV6].notify = nssinfo_ipv6_stats_notify; + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_IPV6].destroy = nssinfo_ipv6_destroy; + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_IPV6].is_inited = true; + return 0; +fail: + nss_nlmcast_sock_leave_grp(ctx, NSS_NLIPV6_MCAST_GRP); + return -1; +} diff --git a/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_ipv6.h b/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_ipv6.h new file mode 100644 index 0000000000..5bb5fa53b5 --- /dev/null +++ b/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_ipv6.h @@ -0,0 +1,30 @@ +/* + ************************************************************************** + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +#ifndef __NSSINFO_IPV6_H +#define __NSSINFO_IPV6_H + +#define NSSINFO_IPV6_HDR_VERSION 4 + +/** + * @brief initialize IPv4 module. + * + * @return 0 on success or -ve for failure + */ +int nssinfo_ipv6_init(void *data); +void nssinfo_ipv6_deinit(void *data); + +#endif /* __NSSINFO_IPV6_H*/ diff --git a/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_lso_rx.c b/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_lso_rx.c new file mode 100644 index 0000000000..bbe72743d6 --- /dev/null +++ b/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_lso_rx.c @@ -0,0 +1,195 @@ +/* + ************************************************************************** + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +/* + * @file NSSINFO lso_rx handler + */ +#include "nssinfo.h" +#include +#include + +static pthread_mutex_t lso_rx_lock; +static struct nssinfo_stats_info nss_stats_str_node[NSS_STATS_NODE_MAX]; +static struct nssinfo_stats_info nss_lso_rx_stats_str[NSS_LSO_RX_STATS_MAX]; + +/* + * nssinfo_lso_rx_stats_display() + * LSO Rx display callback function. + */ +static void nssinfo_lso_rx_stats_display(int core, char *input) +{ + struct node *lso_rx_node; + + if (input && strncmp(input, nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_LSO_RX].subsystem_name, strlen(input))) { + ++invalid_input; + nssinfo_trace("Invalid node name: %s\n", input); + return; + } + + pthread_mutex_lock(&lso_rx_lock); + lso_rx_node = nodes[core][NSS_LSO_RX_INTERFACE]; + if (!lso_rx_node) { + pthread_mutex_unlock(&lso_rx_lock); + nssinfo_error("%s is not running on the NPU\n", input); + return; + } + + if (display_all_stats) { + nssinfo_print_all("lso_rx", "lso_rx Common Stats", nss_stats_str_node, NSS_STATS_NODE_MAX, (uint64_t *)lso_rx_node->cmn_node_stats); + nssinfo_print_all("lso_rx", "lso_rx Special Stats", nss_lso_rx_stats_str, NSS_LSO_RX_STATS_MAX, (uint64_t *)lso_rx_node->node_stats); + pthread_mutex_unlock(&lso_rx_lock); + return; + } + + nssinfo_print_summary("lso_rx", (uint64_t *)lso_rx_node->cmn_node_stats, NULL, 0); + pthread_mutex_unlock(&lso_rx_lock); +} + +/* + * nssinfo_lso_rx_stats_notify() + * LSO Rx stats notify callback function. + */ +static void nssinfo_lso_rx_stats_notify(void *data) +{ + uint64_t *cmn_node_stats, *node_stats; + struct nss_lso_rx_stats_notification *nss_stats = (struct nss_lso_rx_stats_notification *)data; + struct node *lso_rx_node; + struct node **lso_rx_ptr; + + if (!nssinfo_coreid_ifnum_valid(nss_stats->core_id, NSS_LSO_RX_INTERFACE)) { + return; + } + + pthread_mutex_lock(&lso_rx_lock); + lso_rx_ptr = &nodes[nss_stats->core_id][NSS_LSO_RX_INTERFACE]; + lso_rx_node = *lso_rx_ptr; + if (lso_rx_node) { + memcpy(lso_rx_node->cmn_node_stats, &nss_stats->cmn_node_stats, sizeof(nss_stats->cmn_node_stats)); + memcpy(lso_rx_node->node_stats, &nss_stats->node_stats, sizeof(nss_stats->node_stats)); + pthread_mutex_unlock(&lso_rx_lock); + return; + } + pthread_mutex_unlock(&lso_rx_lock); + + lso_rx_node = (struct node *)calloc(1, sizeof(struct node)); + if (!lso_rx_node) { + nssinfo_warn("Failed to allocate memory for lso_rx node\n"); + return; + } + + cmn_node_stats = (uint64_t *)malloc(sizeof(nss_stats->cmn_node_stats)); + if (!cmn_node_stats) { + nssinfo_warn("Failed to allocate memory for lso_rx common node statistics\n"); + goto lso_rx_node_free; + } + + node_stats = (uint64_t *)malloc(sizeof(nss_stats->node_stats)); + if (!node_stats) { + nssinfo_warn("Failed to allocate memory for lso_rx connection stats\n"); + goto cmn_node_stats_free; + } + + memcpy(cmn_node_stats, &nss_stats->cmn_node_stats, sizeof(nss_stats->cmn_node_stats)); + memcpy(node_stats, &nss_stats->node_stats, sizeof(nss_stats->node_stats)); + lso_rx_node->cmn_node_stats = cmn_node_stats; + lso_rx_node->node_stats = node_stats; + lso_rx_node->subsystem_id = NSS_NLCMN_SUBSYS_LSO_RX; + + /* + * Notify is guaranteed to be single threaded via Netlink listen callback + */ + pthread_mutex_lock(&lso_rx_lock); + *lso_rx_ptr = lso_rx_node; + pthread_mutex_unlock(&lso_rx_lock); + return; + +cmn_node_stats_free: + free(cmn_node_stats); + +lso_rx_node_free: + free(lso_rx_node); +} + +/* + * nssinfo_lso_rx_destroy() + * Destroy LSO Rx node. + */ +static void nssinfo_lso_rx_destroy(uint32_t core_id, uint32_t if_num) +{ + if (nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_LSO_RX].is_inited) { + nssinfo_node_stats_destroy(&lso_rx_lock, core_id, NSS_LSO_RX_INTERFACE); + } +} + +/* + * nssinfo_lso_rx_deinit() + * Deinitialize lso_rx module. + */ +void nssinfo_lso_rx_deinit(void *data) +{ + struct nss_nlmcast_ctx *ctx = (struct nss_nlmcast_ctx *)data; + + if (nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_LSO_RX].is_inited) { + pthread_mutex_destroy(&lso_rx_lock); + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_LSO_RX].is_inited = false; + } + + nss_nlmcast_sock_leave_grp(ctx, NSS_NLLSO_RX_MCAST_GRP); +} + +/* + * nssinfo_lso_rx_init() + * Initialize LSO Rx module. + */ +int nssinfo_lso_rx_init(void *data) +{ + int error; + struct nss_nlmcast_ctx *ctx = (struct nss_nlmcast_ctx *)data; + + /* + * Subscribe for LSO Rx multicast group. + */ + nss_nlsock_set_family(&ctx->sock, NSS_NLLSO_RX_FAMILY); + error = nss_nlmcast_sock_join_grp(ctx, NSS_NLLSO_RX_MCAST_GRP); + if (error) { + nssinfo_warn("Unable to join LSO Rx multicast group\n"); + return error; + } + + if (nssinfo_stats_info_init(nss_stats_str_node, + "/sys/kernel/debug/qca-nss-drv/strings/common_node_stats") != 0) { + goto fail; + } + + if (nssinfo_stats_info_init(nss_lso_rx_stats_str, + "/sys/kernel/debug/qca-nss-drv/strings/lso_rx") != 0) { + goto fail; + } + + if (pthread_mutex_init(&lso_rx_lock, NULL) != 0) { + nssinfo_warn("Mutex init has failed for LSO Rx\n"); + goto fail; + } + + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_LSO_RX].display = nssinfo_lso_rx_stats_display; + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_LSO_RX].notify = nssinfo_lso_rx_stats_notify; + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_LSO_RX].destroy = nssinfo_lso_rx_destroy; + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_LSO_RX].is_inited = true; + return 0; +fail: + nss_nlmcast_sock_leave_grp(ctx, NSS_NLLSO_RX_MCAST_GRP); + return -1; +} diff --git a/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_lso_rx.h b/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_lso_rx.h new file mode 100644 index 0000000000..98fa80420a --- /dev/null +++ b/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_lso_rx.h @@ -0,0 +1,28 @@ +/* + ************************************************************************** + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +#ifndef __NSSINFO_LSO_RX_H +#define __NSSINFO_LSO_RX_H + +/** + * @brief initialize LSO_RX module. + * + * @return 0 on success or -ve for failure + */ +int nssinfo_lso_rx_init(void *data); +void nssinfo_lso_rx_deinit(void *data); + +#endif /* __NSSINFO_LSO_RX_H*/ diff --git a/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_main.c b/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_main.c new file mode 100644 index 0000000000..6070273960 --- /dev/null +++ b/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_main.c @@ -0,0 +1,191 @@ +/* + ************************************************************************** + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +#include "nssinfo.h" +#include + +static const char *nssinfo_version = "1.0"; + +static struct option long_options[] = { + {"verbose", no_argument, NULL, 'v'}, + {"higherunit", no_argument, NULL, 'u'}, + {"help", no_argument, NULL, 'h'}, + {"version", no_argument, NULL, 'V'}, + {"output", required_argument, NULL, 'o'}, + {"flowfile", required_argument, NULL, 'f'}, + {"core", required_argument, NULL, 'c'}, + {"rate", required_argument, NULL, 'r'}, + {0, 0, 0, 0} +}; +static char *short_options = "vuh?Vo:f:c:r:"; + +static void print_help(void) +{ + printf("nssinfo is an userspace tool used to display NODE stats from NSS-FW\n"); + printf("Usage: nssinfo [OPTION ...] [-c ID [NODE1 NODE2 ...]]\n"); + printf("OPTION:\n"); + printf(" -c, --core=ID Display statistics based on core id\n"); + printf(" -f, --flowfile=FILE Specify output content in FILE\n"); + printf(" -o, --output=FILE Write output to FILE instead of stdout\n"); + printf(" -r, --rate=RATE Update screen every RATE seconds\n"); + printf(" -u, --higherunit Display stats in higher units, i.e. K, M, B\n"); + printf(" -v, --verbose Display all the stats (zero and non-zero stats)\n"); + printf(" -V, --version Print program version\n"); + printf(" -h, --help Give this help message\n"); + printf("Examples:\n"); + printf(" nssinfo\n"); + printf(" nssinfo -c0\n"); + printf(" nssinfo -c0 ipv4 edma[0] edma[4]\n"); + printf(" nssinfo -r5 -o stats.log\n"); +} + +struct arguments arguments; + +/* + * getopt_parse() + * Parse command line arguments using getopt_long(). + */ +static int getopt_parse(int argc, char **argv, void *a) +{ + struct arguments *arguments = (struct arguments *)a; + + while (1) { + int key = getopt_long(argc, argv, short_options, long_options, NULL); + + /* + * Detect the end of the options. + */ + if (key == -1) + break; + + switch (key) { + case 'v': + arguments->verbose = true; + break; + + case 'u': + arguments->higher_unit = true; + break; + + case 'f': + arguments->flow_file = optarg; + break; + + case 'o': + arguments->output_file = optarg; + break; + + case 'r': /* -r5 */ + arguments->rate = atoi(optarg); + if (arguments->rate <= 0) { + printf("Invalid rate `%s'\n", optarg); + exit(-1); + } + break; + + case 'c': /* -c0 */ + arguments->core = atoi(optarg); + if (arguments->core >= NSS_MAX_CORES || arguments->core < 0) { + printf("Invalid core id `%s'\n", optarg); + exit(-1); + } + break; + + case 'h': + print_help(); + exit(0); + + case 'V': + printf("%s\n", nssinfo_version); + exit(0); + + case '?': + default: + /* + * getopt_long already printed an error message. + */ + exit(-1); + } + } + + /* Any remaining non-option arguments start from argv[optind]. + * Init arguments->strings so that + * arguments->strings[0] points to the 1st non-option argument + * arguments->strings[1] points to the 2nd non-option argument + * ... + * arguments->strings[n] points to the last non-option argument + * arguments->strings[n+1] is NULL + * + * For example, + * If user enters 'nssinfo -c1 edma1 edma2', optind is 2 at this point and + * arguments->strings[0] = "edma1", arguments->strings[1] = "edma2", arguments->strings[2] = NULL. + * If user does not specify any non-option argument (e.g. nssinfo -v), + * argv[optind] is NULL so arguments->strings[0] is NULL. + */ + arguments->strings = &argv[optind]; + + return 0; +} + +/* + * main() + */ +int main(int argc, char **argv) +{ + int error; + + arguments.output_file = NULL; + arguments.flow_file = NULL; + arguments.verbose = false; + arguments.higher_unit = false; + arguments.core = -1; /* display stats for all cores */ + arguments.rate = 1; /* 1 sec */ + + getopt_parse(argc, argv, &arguments); + + if (arguments.output_file) { + output_file = fopen(arguments.output_file, "w"); + if (!output_file) { + nssinfo_error("Error opening output file!\n"); + exit(1); + } + } + + if (arguments.flow_file) { + flow_file = fopen(arguments.flow_file, "r"); + if (!flow_file) { + nssinfo_error("Error opening flow file!\n"); + error = -1; + goto end; + } + } + + error = nssinfo_init(); + if (error) { + nssinfo_info("Nssinfo initialization failed(%d)\n", error); + } + + if (flow_file) { + fclose(flow_file); + } + +end: + if (output_file) { + fclose(output_file); + } + + return error; +} diff --git a/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_n2h.c b/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_n2h.c new file mode 100644 index 0000000000..4aac456d3a --- /dev/null +++ b/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_n2h.c @@ -0,0 +1,209 @@ +/* + ************************************************************************** + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +/* + * @file NSSINFO n2h handler + */ +#include "nssinfo.h" +#include +#include + +static pthread_mutex_t n2h_lock; +static uint64_t drv_stats[NSS_STATS_DRV_MAX]; +static struct nssinfo_stats_info nssinfo_n2h_stats_str[NSS_N2H_STATS_MAX]; + +/* + * nssinfo_n2h_stats_display() + * N2H display callback function. + */ +static void nssinfo_n2h_stats_display(int core, char *input) +{ + struct node *n2h_node; + char str_rx[NSSINFO_STR_LEN], str_tx[NSSINFO_STR_LEN]; + + if (input && strncmp(input, nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_N2H].subsystem_name, strlen(input))) { + ++invalid_input; + nssinfo_trace("Invalid node name: %s\n", input); + return; + } + + pthread_mutex_lock(&n2h_lock); + n2h_node = nodes[core][NSS_N2H_INTERFACE]; + if (!n2h_node) { + pthread_mutex_unlock(&n2h_lock); + return; + } + + if (display_all_stats) { + nssinfo_print_all("n2h", "n2h Stats", nssinfo_n2h_stats_str, NSS_N2H_STATS_MAX, (uint64_t *)n2h_node->node_stats); + pthread_mutex_unlock(&n2h_lock); + return; + } + + nssinfo_print_summary("n2h", (uint64_t *)n2h_node->node_stats, NULL, 0); + + if (core == (NSS_MAX_CORES - 1)) { + + char *format_stats = nssinfo_format_stats(drv_stats[NSS_STATS_DRV_RX_CMD_RESP]); + strlcpy(str_rx, format_stats, sizeof(str_rx)); + format_stats = nssinfo_format_stats(drv_stats[NSS_STATS_DRV_TX_CMD_REQ]); + strlcpy(str_tx, format_stats, sizeof(str_tx)); + nssinfo_stats_print(nssinfo_summary_fmt, " buf_cmd", str_rx, str_tx, "", ""); + + memset(str_rx, 0, sizeof(str_rx)); + memset(str_tx, 0, sizeof(str_tx)); + format_stats = nssinfo_format_stats(drv_stats[NSS_STATS_DRV_RX_EMPTY]); + strlcpy(str_rx, format_stats, sizeof(str_rx)); + format_stats = nssinfo_format_stats(drv_stats[NSS_STATS_DRV_TX_EMPTY]); + strlcpy(str_tx, format_stats, sizeof(str_tx)); + nssinfo_stats_print(nssinfo_summary_fmt, " buf_emty", str_rx, str_tx, "", ""); + + memset(str_rx, 0, sizeof(str_rx)); + memset(str_tx, 0, sizeof(str_tx)); + format_stats = nssinfo_format_stats(drv_stats[NSS_STATS_DRV_RX_PACKET]); + strlcpy(str_rx, format_stats, sizeof(str_rx)); + format_stats = nssinfo_format_stats(drv_stats[NSS_STATS_DRV_TX_PACKET]); + strlcpy(str_tx, format_stats, sizeof(str_tx)); + nssinfo_stats_print(nssinfo_summary_fmt, " buf_pkt", str_rx, str_tx, "", ""); + + memset(str_rx, 0, sizeof(str_rx)); + format_stats = nssinfo_format_stats(drv_stats[NSS_STATS_DRV_RX_STATUS]); + strlcpy(str_rx, format_stats, sizeof(str_rx)); + nssinfo_stats_print(nssinfo_summary_fmt, " status_sync", str_rx, "", "", ""); + } + pthread_mutex_unlock(&n2h_lock); +} + +/* + * nssinfo_n2h_stats_notify() + * N2H stats notify callback function. + */ +static void nssinfo_n2h_stats_notify(void *data) +{ + uint64_t *node_stats; + struct nss_n2h_stats_notification *nss_stats = (struct nss_n2h_stats_notification *)data; + struct node *n2h_node; + struct node **n2h_ptr; + + if (!nssinfo_coreid_ifnum_valid(nss_stats->core_id, NSS_N2H_INTERFACE)) { + return; + } + + pthread_mutex_lock(&n2h_lock); + n2h_ptr = &nodes[nss_stats->core_id][NSS_N2H_INTERFACE]; + n2h_node = *n2h_ptr; + if (n2h_node) { + memcpy(n2h_node->node_stats, &nss_stats->n2h_stats, sizeof(nss_stats->n2h_stats)); + memcpy(drv_stats, &nss_stats->drv_stats, sizeof(nss_stats->drv_stats)); + pthread_mutex_unlock(&n2h_lock); + return; + } + pthread_mutex_unlock(&n2h_lock); + + n2h_node = (struct node *)calloc(1, sizeof(struct node)); + if (!n2h_node) { + nssinfo_warn("Failed to allocate memory for N2H node\n"); + return; + } + + node_stats = (uint64_t *)malloc(sizeof(nss_stats->n2h_stats)); + if (!node_stats) { + nssinfo_warn("Failed to allocate memory for n2h node stats\n"); + goto n2h_node_free; + } + + memcpy(node_stats, &nss_stats->n2h_stats, sizeof(nss_stats->n2h_stats)); + memcpy(drv_stats, &nss_stats->drv_stats, sizeof(nss_stats->drv_stats)); + n2h_node->node_stats = node_stats; + n2h_node->subsystem_id = NSS_NLCMN_SUBSYS_N2H; + + /* + * Notify is guaranteed to be single threaded via Netlink listen callback + */ + pthread_mutex_lock(&n2h_lock); + *n2h_ptr = n2h_node; + pthread_mutex_unlock(&n2h_lock); + return; + +n2h_node_free: + free(n2h_node); +} + +/* + * nssinfo_n2h_destroy() + * Destroy N2H node. + */ +static void nssinfo_n2h_destroy(uint32_t core_id, uint32_t if_num) +{ + if (nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_N2H].is_inited) { + nssinfo_node_stats_destroy(&n2h_lock, core_id, NSS_N2H_INTERFACE); + } +} + +/* + * nssinfo_n2h_deinit() + * Deinitialize n2h module. + */ +void nssinfo_n2h_deinit(void *data) +{ + struct nss_nlmcast_ctx *ctx = (struct nss_nlmcast_ctx *)data; + + if (nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_N2H].is_inited) { + pthread_mutex_destroy(&n2h_lock); + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_N2H].is_inited = false; + } + + nss_nlmcast_sock_leave_grp(ctx, NSS_NLN2H_MCAST_GRP); +} + +/* + * nssinfo_n2h_init() + * Initialize N2H module. + */ +int nssinfo_n2h_init(void *data) +{ + int error; + struct nss_nlmcast_ctx *ctx = (struct nss_nlmcast_ctx *)data; + + /* + * Subscribe for N2H MCAST group. + */ + nss_nlsock_set_family(&ctx->sock, NSS_NLN2H_FAMILY); + error = nss_nlmcast_sock_join_grp(ctx, NSS_NLN2H_MCAST_GRP); + if (error) { + nssinfo_warn("Unable to join N2H mcast group.\n"); + return error; + } + + if (nssinfo_stats_info_init(nssinfo_n2h_stats_str, + "/sys/kernel/debug/qca-nss-drv/strings/n2h") != 0) { + goto fail; + } + + if (pthread_mutex_init(&n2h_lock, NULL) != 0) { + nssinfo_warn("Mutex init has failed for n2h\n"); + goto fail; + } + + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_N2H].display = nssinfo_n2h_stats_display; + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_N2H].notify = nssinfo_n2h_stats_notify; + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_N2H].destroy = nssinfo_n2h_destroy; + nssinfo_subsystem_array[NSS_NLCMN_SUBSYS_N2H].is_inited = true; + return 0; +fail: + nss_nlmcast_sock_leave_grp(ctx, NSS_NLN2H_MCAST_GRP); + return -1; +} diff --git a/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_n2h.h b/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_n2h.h new file mode 100644 index 0000000000..eb3897a013 --- /dev/null +++ b/package/qca-nss/nss-userspace-oss/nssinfo/src/src/nssinfo_n2h.h @@ -0,0 +1,28 @@ +/* + ************************************************************************** + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +#ifndef __NSSINFO_N2H_H +#define __NSSINFO_N2H_H + +/** + * @brief initialize N2H module. + * + * @return 0 on success or -ve for failure + */ +int nssinfo_n2h_init(void *data); +void nssinfo_n2h_deinit(void *data); + +#endif /* __NSSINFO_N2H_H*/ diff --git a/package/qca-nss/qca-mcs/Makefile b/package/qca-nss/qca-mcs/Makefile new file mode 100644 index 0000000000..b65216fec3 --- /dev/null +++ b/package/qca-nss/qca-mcs/Makefile @@ -0,0 +1,68 @@ +# NHSS.QSDK.12.2 +# by SqTER + +include $(TOPDIR)/rules.mk +include $(INCLUDE_DIR)/kernel.mk + +PKG_NAME:=qca-mcs +PKG_RELEASE:=1 + +PKG_SOURCE_URL:=https://git.codelinaro.org/clo/qsdk/oss/lklm/qca-mcs.git +PKG_SOURCE_DATE:=2023-06-01 +PKG_SOURCE_PROTO:=git +PKG_SOURCE_VERSION:=678328971a846e02cb49d00b2d86832f02dff072 +PKG_MIRROR_HASH:=6098deddb1fa85a0171344e3b07294df485c32e81fd3c7d9182728373f93a719 +PKG_BUILD_PARALLEL:=1 + +include $(INCLUDE_DIR)/package.mk + +define KernelPackage/qca-mcs + SECTION:=kernel + CATEGORY:=Kernel modules + SUBMENU:=Network Support + URL:=http://www.qca.qualcomm.com + MAINTAINER:=Qualcomm Atheros, Inc. + TITLE:=QCA Multicast Snooping Support + DEPENDS:=+@KERNEL_IPV6_MROUTE +@KERNEL_IP_MROUTE + + KCONFIG:=CONFIG_NETFILTER=y CONFIG_BRIDGE_NETFILTER=y + FILES:=$(PKG_BUILD_DIR)/qca-mcs.ko + AUTOLOAD:=$(call AutoLoad,41,qca-mcs) +endef + +define KernelPackage/qca-mcs/description + This package installs the IGMP/MLD Snooping Module +endef + +QCA_MC_SNOOPING_HEADERS= \ + $(PKG_BUILD_DIR)/mc_api.h \ + $(PKG_BUILD_DIR)/mc_ecm.h \ + +define Build/InstallDev + $(INSTALL_DIR) $(1)/usr/include/qca-mcs + $(foreach header_file,$(QCA_MC_SNOOPING_HEADERS), $(CP) $(header_file) $(1)/usr/include/qca-mcs;) + $(foreach header_file,$(QCA_MC_SNOOPING_HEADERS), $(CP) $(header_file) $(1)/usr/include/;) +endef + +EXTRA_CFLAGS+=-Wno-implicit-fallthrough + +QCA_MC_SNOOPING_MAKE_OPTS:= \ + $(KERNEL_MAKE_FLAGS) \ + CONFIG_SUPPORT_MLD=y \ + MDIR=$(PKG_BUILD_DIR) \ + KBUILDPATH=$(LINUX_DIR) \ + KERNELPATH=$(LINUX_SRC_DIR) \ + KERNELRELEASE=$(LINUX_RELEASE) + +define Build/Compile + +$(MAKE) $(PKG_JOBS) -C $(LINUX_DIR) \ + $(KERNEL_MAKE_FLAGS) \ + KBUILDPATH=$(LINUX_DIR) \ + $(PKG_MAKE_FLAGS) \ + M=$(PKG_BUILD_DIR) \ + EXTRA_CFLAGS="$(EXTRA_CFLAGS)" \ + $(strip $(QCA_MC_SNOOPING_MAKE_OPTS)) \ + modules +endef + +$(eval $(call KernelPackage,qca-mcs)) diff --git a/package/qca-nss/qca-mcs/patches/100-kernel-5.15-support.patch b/package/qca-nss/qca-mcs/patches/100-kernel-5.15-support.patch new file mode 100644 index 0000000000..a05be2e313 --- /dev/null +++ b/package/qca-nss/qca-mcs/patches/100-kernel-5.15-support.patch @@ -0,0 +1,56 @@ +diff --git a/mc_osdep.h b/mc_osdep.h +index 5d47dc6..acde39a 100644 +--- a/mc_osdep.h ++++ b/mc_osdep.h +@@ -24,7 +24,11 @@ + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) + static inline int os_br_pass_frame_up(struct sk_buff *skb) + { ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 157)) ++ return br_pass_frame_up(skb, false); ++#else + return br_pass_frame_up(skb); ++#endif + } + #else + static inline int os_br_pass_frame_up(struct sk_buff *skb) +@@ -189,7 +193,7 @@ static inline struct net_bridge_port *mc_bridge_get_dst(const struct net_bridge_ + + dst = os_br_fdb_get((struct net_bridge *)br, eth_hdr(*skb)->h_dest); + +- if (dst && !dst->is_local) ++ if (dst && !test_bit(BR_FDB_LOCAL, &dst->flags)) + return dst->dst; + + return NULL; +diff --git a/mc_snooping.c b/mc_snooping.c +index 378b0f8..03ec6e8 100644 +--- a/mc_snooping.c ++++ b/mc_snooping.c +@@ -3450,6 +3450,18 @@ static int mc_proc_snooper_open(struct inode *inode, struct file *file) + return single_open(file, mc_proc_snooper_show, NULL); + } + ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,6,0) ++#define HAVE_PROC_OPS ++#endif ++ ++#ifdef HAVE_PROC_OPS ++static const struct proc_ops mc_proc_snooper_fops = { ++ .proc_open = mc_proc_snooper_open, ++ .proc_read = seq_read, ++ .proc_lseek = seq_lseek, ++ .proc_release = single_release, ++}; ++#else + static const struct file_operations mc_proc_snooper_fops = { + .owner = THIS_MODULE, + .open = mc_proc_snooper_open, +@@ -3457,6 +3469,7 @@ static const struct file_operations mc_proc_snooper_fops = { + .llseek = seq_lseek, + .release = single_release, + }; ++#endif + + /* mc_proc_create_snooper_entry + * create proc entry for information show diff --git a/package/qca-nss/qca-nss-clients/Makefile b/package/qca-nss/qca-nss-clients/Makefile new file mode 100644 index 0000000000..cf689e8731 --- /dev/null +++ b/package/qca-nss/qca-nss-clients/Makefile @@ -0,0 +1,497 @@ +# NHSS.QSDK.12.2 +# by SqTER + +include $(TOPDIR)/rules.mk +include $(INCLUDE_DIR)/kernel.mk + +PKG_NAME:=qca-nss-clients +PKG_RELEASE:=2 +PKG_SOURCE_URL:=https://git.codelinaro.org/clo/qsdk/oss/lklm/nss-clients.git +PKG_SOURCE_DATE:=2023-06-01 +PKG_SOURCE_PROTO:=git +PKG_SOURCE_VERSION:=4cc5d7687c69ef1fbc53d5492d9d672d2d8ef030 +PKG_MIRROR_HASH:=cc1904bd90a0fc137b114b3232245c973e84068ea52caeaac66c49d958739a4e +PKG_BUILD_DEPENDS:=qca-nss-drv +PKG_BUILD_PARALLEL:=1 + +include $(INCLUDE_DIR)/package.mk + +# Keep default as ipq806x for branches that does not have subtarget framework +ifeq ($(CONFIG_TARGET_ipq),y) +subtarget:=$(SUBTARGET) +else +subtarget:=$(CONFIG_TARGET_BOARD) +endif + +define KernelPackage/qca-nss-drv-tun6rd + SECTION:=kernel + CATEGORY:=Kernel modules + SUBMENU:=Network Devices + TITLE:=Kernel driver for NSS (connection manager) - tun6rd + DEPENDS:=+@NSS_DRV_TUN6RD_ENABLE +kmod-sit +6rd \ + +PACKAGE_kmod-qca-nss-drv:kmod-qca-nss-drv + FILES:=$(PKG_BUILD_DIR)/qca-nss-tun6rd.ko + AUTOLOAD:=$(call AutoLoad,60,qca-nss-tun6rd) +endef + +define KernelPackage/qca-nss-drv-tun6rd/description +Kernel modules for NSS connection manager - Support for 6rd tunnel +endef + +define KernelPackage/qca-nss-drv-l2tpv2 + SECTION:=kernel + CATEGORY:=Kernel modules + SUBMENU:=Network Devices + TITLE:=Kernel driver for NSS (connection manager) - l2tp + DEPENDS:=+@NSS_DRV_L2TP_ENABLE +kmod-ppp +kmod-l2tp \ + +PACKAGE_kmod-qca-nss-drv:kmod-qca-nss-drv + FILES:=$(PKG_BUILD_DIR)/l2tp/l2tpv2/qca-nss-l2tpv2.ko + KCONFIG:=CONFIG_L2TP=y + AUTOLOAD:=$(call AutoLoad,51,qca-nss-l2tpv2) +endef + +define KernelPackage/qca-nss-drv-l2tp/description +Kernel modules for NSS connection manager - Support for l2tp tunnel +endef + +define KernelPackage/qca-nss-drv-pptp + SECTION:=kernel + CATEGORY:=Kernel modules + SUBMENU:=Network Devices + TITLE:=Kernel driver for NSS (connection manager) - PPTP + DEPENDS:=+@NSS_DRV_PPTP_ENABLE +kmod-pptp \ + +PACKAGE_kmod-qca-nss-drv:kmod-qca-nss-drv + FILES:=$(PKG_BUILD_DIR)/pptp/qca-nss-pptp.ko + AUTOLOAD:=$(call AutoLoad,51,qca-nss-pptp) +endef + +define KernelPackage/qca-nss-drv-pptp/description +Kernel modules for NSS connection manager - Support for PPTP tunnel +endef + +define KernelPackage/qca-nss-drv-pppoe + SECTION:=kernel + CATEGORY:=Kernel modules + SUBMENU:=Network Devices + TITLE:=Kernel driver for NSS (connection manager) - PPPoE + DEPENDS:=+@NSS_DRV_PPPOE_ENABLE +kmod-pppoe \ + +PACKAGE_kmod-bonding:kmod-bonding \ + +PACKAGE_kmod-qca-nss-drv:kmod-qca-nss-drv + FILES:=$(PKG_BUILD_DIR)/pppoe/qca-nss-pppoe.ko + AUTOLOAD:=$(call AutoLoad,51,qca-nss-pppoe) +endef + +define KernelPackage/qca-nss-drv-pppoe/description +Kernel modules for NSS connection manager - Support for PPPoE +endef + +define KernelPackage/qca-nss-drv-gre + SECTION:=kernel + CATEGORY:=Kernel modules + SUBMENU:=Network Devices + TITLE:=Kernel driver for NSS (connection manager) - GRE + DEPENDS:=@TARGET_ipq_ipq806x||TARGET_ipq806x||TARGET_ipq_ipq807x||TARGET_ipq_ipq807x_64||TARGET_ipq807x||TARGET_ipq807x_64||TARGET_ipq_ipq60xx||TARGET_ipq_ipq60xx_64||TARGET_ipq_ipq50xx||TARGET_ipq_ipq50xx_64 \ + +@NSS_DRV_GRE_ENABLE +kmod-gre6 \ + +PACKAGE_kmod-qca-nss-drv:kmod-qca-nss-drv + FILES:=$(PKG_BUILD_DIR)/gre/qca-nss-gre.ko $(PKG_BUILD_DIR)/gre/test/qca-nss-gre-test.ko + AUTOLOAD:=$(call AutoLoad,51,qca-nss-gre) +endef + +define KernelPackage/qca-nss-drv-gre/description +Kernel modules for NSS connection manager - Support for GRE +endef + +define KernelPackage/qca-nss-drv-tunipip6 + SECTION:=kernel + CATEGORY:=Kernel modules + SUBMENU:=Network Devices + TITLE:=Kernel driver for NSS (connection manager) - DS-lite and ipip6 Tunnel + DEPENDS:=+@NSS_DRV_TUNIPIP6_ENABLE +kmod-iptunnel6 +kmod-ip6-tunnel \ + +PACKAGE_kmod-qca-nss-drv:kmod-qca-nss-drv + FILES:=$(PKG_BUILD_DIR)/qca-nss-tunipip6.ko + AUTOLOAD:=$(call AutoLoad,60,qca-nss-tunipip6) +endef + +define KernelPackage/qca-nss-drv-tunipip6/description +Kernel modules for NSS connection manager +Add support for DS-lite and ipip6 tunnel +endef + +define KernelPackage/qca-nss-drv-profile + SECTION:=kernel + CATEGORY:=Kernel modules + SUBMENU:=Network Devices + DEPENDS:=+@NSS_DRV_PROFILE_ENABLE \ + +PACKAGE_kmod-qca-nss-drv:kmod-qca-nss-drv + TITLE:=Profiler for QCA NSS driver (IPQ806x) + FILES:=$(PKG_BUILD_DIR)/profiler/qca-nss-profile-drv.ko +endef + +define KernelPackage/qca-nss-drv-profile/description +This package contains a NSS driver profiler for QCA chipset +endef + +define KernelPackage/qca-nss-drv-portifmgr + SECTION:=kernel + CATEGORY:=Kernel modules + SUBMENU:=Network Devices + TITLE:=Kernel driver for NSS (qca-nss-drv-portifmgr) + DEPENDS:=+@NSS_DRV_PORTID_ENABLE +kmod-qca-nss-gmac \ + +PACKAGE_kmod-qca-nss-drv:kmod-qca-nss-drv + FILES:=$(PKG_BUILD_DIR)/portifmgr/qca-nss-portifmgr.ko +endef + +define KernelPackage/qca-nss-drv-portifmgr/Description +NSS Kernel module for Port interface manager +endef + +define KernelPackage/qca-nss-drv-bridge-mgr + SECTION:=kernel + CATEGORY:=Kernel modules + SUBMENU:=Network Devices + TITLE:=Kernel driver for NSS bridge manager + DEPENDS:=@TARGET_ipq_ipq807x||TARGET_ipq_ipq807x_64||TARGET_ipq807x||TARGET_ipq_ipq60xx||TARGET_ipq_ipq60xx_64||TARGET_ipq60xx \ + +TARGET_ipq_ipq807x:kmod-qca-nss-drv-vlan-mgr \ + +TARGET_ipq_ipq807x_64:kmod-qca-nss-drv-vlan-mgr \ + +TARGET_ipq807x:kmod-qca-nss-drv-vlan-mgr \ + +TARGET_ipq60xx:kmod-qca-nss-drv-vlan-mgr \ + +TARGET_ipq_ipq60xx:kmod-qca-nss-drv-vlan-mgr \ + +TARGET_ipq_ipq60xx_64:kmod-qca-nss-drv-vlan-mgr \ + +PACKAGE_kmod-bonding:kmod-bonding \ + +PACKAGE_kmod-qca-nss-drv:kmod-qca-nss-drv \ + +@NSS_DRV_BRIDGE_ENABLE +ifneq ($(CONFIG_PACKAGE_kmod-qca-ovsmgr),) + DEPENDS+=kmod-qca-ovsmgr +endif + FILES:=$(PKG_BUILD_DIR)/bridge/qca-nss-bridge-mgr.ko + AUTOLOAD:=$(call AutoLoad,51,qca-nss-bridge-mgr) +endef + +define KernelPackage/qca-nss-drv-bridge-mgr/description +Kernel modules for NSS bridge manager +endef + +define KernelPackage/qca-nss-drv-vlan-mgr + SECTION:=kernel + CATEGORY:=Kernel modules + SUBMENU:=Network Devices + TITLE:=Kernel driver for NSS vlan manager + DEPENDS:=@TARGET_ipq_ipq807x||TARGET_ipq_ipq806x||TARGET_ipq807x||TARGET_ipq_ipq60xx||TARGET_ipq_ipq60xx_64||TARGET_ipq60xx \ + +PACKAGE_kmod-qca-nss-drv:kmod-qca-nss-drv \ + +@NSS_DRV_VLAN_ENABLE \ + +PACKAGE_kmod-bonding:kmod-bonding + FILES:=$(PKG_BUILD_DIR)/vlan/qca-nss-vlan.ko + AUTOLOAD:=$(call AutoLoad,51,qca-nss-vlan) +endef + +define KernelPackage/qca-nss-drv-vlan-mgr/description +Kernel modules for NSS vlan manager +endef + +define KernelPackage/qca-nss-drv-qdisc + SECTION:=kernel + CATEGORY:=Kernel modules + SUBMENU:=Network Devices + TITLE:=Qdisc for configuring shapers in NSS + DEPENDS:=+@NSS_DRV_SHAPER_ENABLE +@NSS_DRV_IGS_ENABLE \ + +PACKAGE_kmod-qca-nss-drv:kmod-qca-nss-drv + FILES:=$(PKG_BUILD_DIR)/nss_qdisc/qca-nss-qdisc.ko + KCONFIG:=CONFIG_NET_CLS_ACT=y + AUTOLOAD:=$(call AutoLoad,58,qca-nss-qdisc) +endef + +define KernelPackage/qca-nss-drv-qdisc/description +Linux qdisc that aids in configuring shapers in the NSS +endef + +define KernelPackage/qca-nss-drv-igs + SECTION:=kernel + CATEGORY:=Kernel modules + SUBMENU:=Network Devices + TITLE:=Action for offloading traffic to an IFB interface to perform ingress shaping. + DEPENDS:=@TARGET_ipq806x||TARGET_ipq_ipq807x||TARGET_ipq_ipq807x_64||TARGET_ipq_ipq60xx||TARGET_ipq_ipq60xx_64||TARGET_ipq_ipq50xx||TARGET_ipq_ipq50xx_64 \ + +@NSS_DRV_IGS_ENABLE +kmod-sched-core +kmod-ifb +kmod-qca-nss-drv-qdisc \ + +PACKAGE_kmod-qca-nss-drv:kmod-qca-nss-drv + FILES:=$(PKG_BUILD_DIR)/nss_qdisc/igs/act_nssmirred.ko +endef + +define KernelPackage/qca-nss-drv-igs/description +Linux action that helps in offloading traffic to an IFB interface to perform ingress shaping. +endef + +define KernelPackage/qca-nss-drv-lag-mgr + SECTION:=kernel + CATEGORY:=Kernel modules + SUBMENU:=Network Devices + TITLE:=Kernel driver for NSS LAG manager + DEPENDS:=+@NSS_DRV_LAG_ENABLE \ + +TARGET_ipq_ipq807x:kmod-qca-nss-drv-vlan-mgr \ + +TARGET_ipq_ipq807x_64:kmod-qca-nss-drv-vlan-mgr \ + +TARGET_ipq807x:kmod-qca-nss-drv-vlan-mgr \ + +TARGET_ipq_ipq60xx:kmod-qca-nss-drv-vlan-mgr \ + +TARGET_ipq_ipq60xx_64:kmod-qca-nss-drv-vlan-mgr \ + +TARGET_ipq60xx:kmod-qca-nss-drv-vlan-mgr \ + +PACKAGE_kmod-qca-nss-drv:kmod-qca-nss-drv \ + +kmod-bonding + FILES:=$(PKG_BUILD_DIR)/lag/qca-nss-lag-mgr.ko + AUTOLOAD:=$(call AutoLoad,51,qca-nss-lag-mgr) +endef + +define KernelPackage/qca-nss-drv-lag-mgr/description +Kernel modules for NSS LAG manager +endef + +define KernelPackage/qca-nss-drv-netlink + SECTION:=kernel + CATEGORY:=Kernel modules + SUBMENU:=Network Devices + DEPENDS:=@TARGET_ipq806x||TARGET_ipq807x||TARGET_ipq_ipq807x_64||TARGET_ipq_ipq60xx||TARGET_ipq_ipq60xx_64||TARGET_ipq60xx||TARGET_ipq_ipq50xx||TARGET_ipq_ipq50xx_64||TARGET_ipq50xx \ + +PACKAGE_kmod-qca-nss-drv:kmod-qca-nss-drv \ + +@NSS_DRV_GRE_REDIR_ENABLE + TITLE:=NSS NETLINK Manager for QCA NSS driver + FILES:=$(PKG_BUILD_DIR)/netlink/qca-nss-netlink.ko +endef + +define KernelPackage/qca-nss-drv-netlink/description +Kernel module for NSS netlink manager +endef + +define KernelPackage/qca-nss-drv-pvxlanmgr + SECTION:=kernel + CATEGORY:=Kernel modules + SUBMENU:=Network Devices + DEPENDS:=+@NSS_DRV_PVXLAN_ENABLE +PACKAGE_kmod-qca-nss-drv:kmod-qca-nss-drv + TITLE:=NSS PVXLAN Manager for QCA NSS driver + FILES:=$(PKG_BUILD_DIR)/pvxlanmgr/qca-nss-pvxlanmgr.ko +endef + +define KernelPackage/qca-nss-drv-pvxlanmgr/description +Kernel module for managing NSS PVxLAN +endef + +define KernelPackage/qca-nss-drv-eogremgr + SECTION:=kernel + CATEGORY:=Kernel modules + SUBMENU:=Network Devices + DEPENDS:=+@NSS_DRV_GRE_ENABLE +PACKAGE_kmod-qca-nss-drv:kmod-qca-nss-drv +kmod-qca-nss-drv-gre + TITLE:=NSS EOGRE Manager for QCA NSS driver + FILES:=$(PKG_BUILD_DIR)/eogremgr/qca-nss-eogremgr.ko +endef + +define KernelPackage/qca-nss-drv-eogremgr/description +Kernel module for managing NSS EoGRE +endef + +define KernelPackage/qca-nss-drv-clmapmgr + SECTION:=kernel + CATEGORY:=Kernel modules + SUBMENU:=Network Devices + DEPENDS:=+@NSS_DRV_CLMAP_ENABLE +PACKAGE_kmod-qca-nss-drv:kmod-qca-nss-drv +kmod-qca-nss-drv-eogremgr + TITLE:=NSS clmap Manager for QCA NSS driver + FILES:=$(PKG_BUILD_DIR)/clmapmgr/qca-nss-clmapmgr.ko +endef + +define KernelPackage/qca-nss-drv-clmapmgr/description +Kernel module for managing NSS clmap +endef + +# define KernelPackage/qca-nss-drv-vxlanmgr +# SECTION:=kernel +# CATEGORY:=Kernel modules +# SUBMENU:=Network Devices +# DEPENDS:=+@NSS_DRV_VXLAN_ENABLE +PACKAGE_kmod-qca-nss-drv:kmod-qca-nss-drv +kmod-vxlan +# TITLE:=NSS VxLAN Manager for QCA NSS driver +# FILES:=$(PKG_BUILD_DIR)/vxlanmgr/qca-nss-vxlanmgr.ko +# AUTOLOAD:=$(call AutoLoad,51,qca-nss-vxlanmgr) +# endef +# +# define KernelPackage/qca-nss-drv-vxlanmgr/description +# Kernel module for managing NSS VxLAN +# endef + +# define KernelPackage/qca-nss-drv-match +# SECTION:=kernel +# CATEGORY:=Kernel modules +# SUBMENU:=Network Devices +# DEPENDS:=+@NSS_DRV_MATCH_ENABLE +PACKAGE_kmod-qca-nss-drv:kmod-qca-nss-drv +# TITLE:=NSS Match for QCA NSS driver +# FILES:=$(PKG_BUILD_DIR)/match/qca-nss-match.ko +# endef +# +# define KernelPackage/qca-nss-drv-match/description +# Kernel module for managing NSS Match +# endef +# +# define KernelPackage/qca-nss-drv-mirror +# SECTION:=kernel +# CATEGORY:=Kernel modules +# SUBMENU:=Network Devices +# TITLE:=Module for mirroring packets from NSS to host. +# DEPENDS:=+@NSS_DRV_MIRROR_ENABLE +PACKAGE_kmod-qca-nss-drv:kmod-qca-nss-drv +# FILES:=$(PKG_BUILD_DIR)/mirror/qca-nss-mirror.ko +# endef +# +# define KernelPackage/qca-nss-drv-mirror/Description +# Kernel module for managing NSS Mirror +# endef + +# define KernelPackage/qca-nss-drv-wifi-meshmgr +# SECTION:=kernel +# CATEGORY:=Kernel modules +# SUBMENU:=Network Devices +# DEPENDS:=+@NSS_DRV_WIFI_ENABLE +PACKAGE_kmod-qca-nss-drv:kmod-qca-nss-drv +# TITLE:=NSS WiFi-Mesh Manager for QCA NSS driver +# FILES:=$(PKG_BUILD_DIR)/wifi_meshmgr/qca-nss-wifi-meshmgr.ko +# AUTOLOAD:=$(call AutoLoad,51,qca-nss-wifi-meshmgr) +# endef + +# define KernelPackage/qca-nss-drv-wifi-meshmgr/Description +# Kernel module for WiFi Mesh manager +# endef + +define Build/InstallDev/qca-nss-clients + $(INSTALL_DIR) $(1)/usr/include/qca-nss-clients + $(CP) $(PKG_BUILD_DIR)/netlink/include/* $(1)/usr/include/qca-nss-clients/ + $(CP) $(PKG_BUILD_DIR)/exports/* $(1)/usr/include/qca-nss-clients/ +endef + +define Build/InstallDev + $(call Build/InstallDev/qca-nss-clients,$(1)) +endef + +define KernelPackage/qca-nss-drv-igs/install + $(INSTALL_DIR) $(1)/etc/init.d + $(INSTALL_BIN) ./files/qca-nss-mirred.init $(1)/etc/init.d/qca-nss-mirred +endef + +EXTRA_CFLAGS+= \ + -I$(STAGING_DIR)/usr/include/qca-nss-drv \ + -I$(STAGING_DIR)/usr/include/qca-nss-crypto \ + -I$(STAGING_DIR)/usr/include/qca-nss-cfi \ + -I$(STAGING_DIR)/usr/include/qca-nss-gmac \ + -I$(STAGING_DIR)/usr/include/qca-nss-ecm \ + -I$(STAGING_DIR)/usr/include/qca-ssdk \ + -I$(STAGING_DIR)/usr/include/qca-ssdk/fal + +# Build individual packages if selected +ifneq ($(CONFIG_PACKAGE_kmod-qca-nss-drv-portifmgr),) +MAKE_OPTS+=portifmgr=y +EXTRA_CFLAGS += -DNSS_PORTIFMGR_REF_AP148 -I$(PKG_BUILD_DIR)/portifmgr +endif + +ifneq ($(CONFIG_PACKAGE_kmod-qca-nss-drv-profile),) +MAKE_OPTS+=profile=y +endif + +ifneq ($(CONFIG_PACKAGE_kmod-qca-nss-drv-tun6rd),) +MAKE_OPTS+=tun6rd=m +endif + +ifneq ($(CONFIG_PACKAGE_kmod-qca-nss-drv-l2tpv2),) +MAKE_OPTS+=l2tpv2=y +EXTRA_CFLAGS += -DNSS_L2TPV2_ENABLED +endif + +ifneq ($(CONFIG_PACKAGE_kmod-qca-nss-drv-pptp),) +MAKE_OPTS+=pptp=y +endif + +ifneq ($(CONFIG_PACKAGE_kmod-qca-nss-drv-tunipip6),) +MAKE_OPTS+=tunipip6=m +endif + +ifneq ($(CONFIG_PACKAGE_kmod-qca-nss-drv-qdisc),) +MAKE_OPTS+=qdisc=y +endif + +ifneq ($(CONFIG_PACKAGE_kmod-qca-nss-drv-igs),) +MAKE_OPTS+=igs=y +EXTRA_CFLAGS+=-DNSS_IGS_DEBUG_LEVEL=4 +endif + +ifneq ($(CONFIG_PACKAGE_kmod-qca-nss-drv-bridge-mgr),) +MAKE_OPTS+=bridge-mgr=y +#enable OVS bridge if ovsmgr is enabled +ifneq ($(CONFIG_PACKAGE_kmod-qca-ovsmgr),) +MAKE_OPTS+= NSS_BRIDGE_MGR_OVS_ENABLE=y +EXTRA_CFLAGS+= -I$(STAGING_DIR)/usr/include/qca-ovsmgr +endif +endif + +ifneq ($(CONFIG_PACKAGE_kmod-qca-nss-drv-vlan-mgr),) +MAKE_OPTS+=vlan-mgr=y +endif + +ifneq ($(CONFIG_PACKAGE_kmod-qca-nss-drv-lag-mgr),) +MAKE_OPTS+=lag-mgr=y +endif + +ifneq ($(CONFIG_PACKAGE_kmod-qca-nss-drv-gre),) +EXTRA_CFLAGS+= -I$(PKG_BUILD_DIR)/exports +MAKE_OPTS+=gre=y +endif + +ifneq ($(CONFIG_PACKAGE_kmod-qca-nss-drv-pppoe),) +MAKE_OPTS+=pppoe=y +endif + +ifneq ($(CONFIG_PACKAGE_kmod-qca-nss-drv-netlink),) +MAKE_OPTS+=netlink=y + +ifeq ($(CONFIG_KERNEL_IPQ_MEM_PROFILE),256) +EXTRA_CFLAGS+= -DNSS_NETLINK_UDP_ST_NO_RMNET_SUPPORT +else ifeq ($(CONFIG_LOWMEM_FLASH),y) +EXTRA_CFLAGS+= -DNSS_NETLINK_UDP_ST_NO_RMNET_SUPPORT +endif +endif + +ifneq ($(CONFIG_PACKAGE_kmod-qca-nss-drv-pvxlanmgr),) +MAKE_OPTS+=pvxlanmgr=y +endif + +ifneq ($(CONFIG_PACKAGE_kmod-qca-nss-drv-eogremgr),) +MAKE_OPTS+=eogremgr=y +endif + +ifneq ($(CONFIG_PACKAGE_kmod-qca-nss-drv-clmapmgr),) +MAKE_OPTS+=clmapmgr=y +endif + +# ifneq ($(CONFIG_PACKAGE_kmod-qca-nss-drv-vxlanmgr),) +# MAKE_OPTS+=vxlanmgr=y +# EXTRA_CFLAGS += -DNSS_VXLAN_ENABLED +# endif + +# ifneq ($(CONFIG_PACKAGE_kmod-qca-nss-drv-match),) +# MAKE_OPTS+=match=y +# endif + +define Build/Compile + +$(MAKE) $(PKG_JOBS) -C "$(LINUX_DIR)" $(strip $(MAKE_OPTS)) \ + CROSS_COMPILE="$(TARGET_CROSS)" \ + ARCH="$(LINUX_KARCH)" \ + $(KERNEL_MAKE_FLAGS) \ + $(PKG_MAKE_FLAGS) \ + M="$(PKG_BUILD_DIR)" \ + EXTRA_CFLAGS="$(EXTRA_CFLAGS)" \ + SoC="$(subtarget)" \ + modules +endef + +$(eval $(call KernelPackage,qca-nss-drv-profile)) +$(eval $(call KernelPackage,qca-nss-drv-tun6rd)) +$(eval $(call KernelPackage,qca-nss-drv-l2tpv2)) +$(eval $(call KernelPackage,qca-nss-drv-pptp)) +$(eval $(call KernelPackage,qca-nss-drv-pppoe)) +$(eval $(call KernelPackage,qca-nss-drv-tunipip6)) +$(eval $(call KernelPackage,qca-nss-drv-qdisc)) +$(eval $(call KernelPackage,qca-nss-drv-igs)) +$(eval $(call KernelPackage,qca-nss-drv-portifmgr)) +$(eval $(call KernelPackage,qca-nss-drv-netlink)) +$(eval $(call KernelPackage,qca-nss-drv-bridge-mgr)) +$(eval $(call KernelPackage,qca-nss-drv-vlan-mgr)) +$(eval $(call KernelPackage,qca-nss-drv-lag-mgr)) +$(eval $(call KernelPackage,qca-nss-drv-gre)) +$(eval $(call KernelPackage,qca-nss-drv-pvxlanmgr)) +$(eval $(call KernelPackage,qca-nss-drv-eogremgr)) +$(eval $(call KernelPackage,qca-nss-drv-clmapmgr)) diff --git a/package/qca-nss/qca-nss-clients/files/qca-nss-ipsec b/package/qca-nss/qca-nss-clients/files/qca-nss-ipsec new file mode 100644 index 0000000000..bb202e8e7e --- /dev/null +++ b/package/qca-nss/qca-nss-clients/files/qca-nss-ipsec @@ -0,0 +1,92 @@ +#!/bin/sh /etc/rc.common +# +# Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +NSS_IPSEC_LOG_FILE=/tmp/.nss_ipsec_log +NSS_IPSEC_LOG_STR_ECM="ECM_Loaded" + +ecm_load () { + if [ ! -d /sys/module/ecm ]; then + /etc/init.d/qca-nss-ecm start + if [ -d /sys/module/ecm ]; then + echo ${NSS_IPSEC_LOG_STR_ECM} >> ${NSS_IPSEC_LOG_FILE} + fi + fi +} + +ecm_unload () { + if [ -f /tmp/.nss_ipsec_log ]; then + str=`grep ${NSS_IPSEC_LOG_STR_ECM} ${NSS_IPSEC_LOG_FILE}` + if [[ $str == ${NSS_IPSEC_LOG_STR_ECM} ]]; then + /etc/init.d/qca-nss-ecm stop + `sed 's/${NSS_IPSEC_LOG_STR_ECM}/ /g' $NSS_IPSEC_LOG_FILE > $NSS_IPSEC_LOG_FILE` + fi + fi +} + +ecm_disable() { + + if [ ! -d /sys/module/ecm ]; then + return; + fi + + echo 1 > /sys/kernel/debug/ecm/front_end_ipv4_stop + echo 1 > /sys/kernel/debug/ecm/front_end_ipv6_stop + echo 1 > /sys/kernel/debug/ecm/ecm_db/defunct_all + sleep 2 +} + +ecm_enable() { + if [ ! -d /sys/module/ecm ]; then + return; + fi + + echo 0 > /sys/kernel/debug/ecm/ecm_db/defunct_all + echo 0 > /sys/kernel/debug/ecm/front_end_ipv4_stop + echo 0 > /sys/kernel/debug/ecm/front_end_ipv6_stop +} + +start() { + ecm_load + + local kernel_version=$(uname -r) + + insmod /lib/modules/${kernel_version}/qca-nss-ipsec-klips.ko + if [ "$?" -gt 0 ]; then + echo "Failed to load plugin. Please start ecm if not done already" + ecm_enable + return + fi + + /etc/init.d/ipsec start + sleep 2 + ipsec eroute + + ecm_enable +} + +stop() { + ecm_disable + + /etc/init.d/ipsec stop + rmmod qca-nss-ipsec-klips + + ecm_unload +} + +restart() { + stop + start +} diff --git a/package/qca-nss/qca-nss-clients/files/qca-nss-mirred.init b/package/qca-nss/qca-nss-clients/files/qca-nss-mirred.init new file mode 100644 index 0000000000..1f931f0903 --- /dev/null +++ b/package/qca-nss/qca-nss-clients/files/qca-nss-mirred.init @@ -0,0 +1,28 @@ +#!/bin/sh /etc/rc.common + +########################################################################### +# Copyright (c) 2019, The Linux Foundation. All rights reserved. +# Permission to use, copy, modify, and/or distribute this software for +# any purpose with or without fee is hereby granted, provided that the +# above copyright notice and this permission notice appear in all copies. +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +########################################################################### + +restart() { + rmmod act_nssmirred.ko + insmod act_nssmirred.ko +} + +start() { + insmod act_nssmirred.ko +} + +stop() { + rmmod act_nssmirred.ko +} diff --git a/package/qca-nss/qca-nss-clients/files/qca-nss-ovpn.init b/package/qca-nss/qca-nss-clients/files/qca-nss-ovpn.init new file mode 100644 index 0000000000..622e295eee --- /dev/null +++ b/package/qca-nss/qca-nss-clients/files/qca-nss-ovpn.init @@ -0,0 +1,69 @@ +#!/bin/sh /etc/rc.common + +########################################################################### +# Copyright (c) 2019, The Linux Foundation. All rights reserved. +# Permission to use, copy, modify, and/or distribute this software for +# any purpose with or without fee is hereby granted, provided that the +# above copyright notice and this permission notice appear in all copies. +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +########################################################################### + +ecm_disable() { + if [ ! -d /sys/module/ecm ]; then + return + fi + + echo 1 > /sys/kernel/debug/ecm/front_end_ipv4_stop + echo 1 > /sys/kernel/debug/ecm/front_end_ipv6_stop + echo 1 > /sys/kernel/debug/ecm/ecm_db/defunct_all + sleep 2 +} + +ecm_enable() { + if [ ! -d /sys/module/ecm ]; then + return + fi + + echo 0 > /sys/kernel/debug/ecm/ecm_db/defunct_all + echo 0 > /sys/kernel/debug/ecm/front_end_ipv4_stop + echo 0 > /sys/kernel/debug/ecm/front_end_ipv6_stop +} + +restart() { + ecm_disable + + /etc/init.d/openvpn stop + rmmod qca-nss-ovpn-link + rmmod qca-nss-ovpn-mgr + + insmod qca-nss-ovpn-mgr + insmod qca-nss-ovpn-link + + if [ "$?" -gt 0 ]; then + echo "Failed to load plugin. Please start ecm if not done already" + ecm_enable + return + fi + + ecm_enable +} + +start() { + restart +} + +stop() { + ecm_disable + + /etc/init.d/openvpn stop + rmmod qca-nss-ovpn-link + rmmod qca-nss-ovpn-mgr + + ecm_enable +} diff --git a/package/qca-nss/qca-nss-clients/patches/100-kernel-5.15-support.patch b/package/qca-nss/qca-nss-clients/patches/100-kernel-5.15-support.patch new file mode 100644 index 0000000000..c100d02222 --- /dev/null +++ b/package/qca-nss/qca-nss-clients/patches/100-kernel-5.15-support.patch @@ -0,0 +1,11298 @@ +--- a/Makefile ++++ b/Makefile +@@ -5,27 +5,25 @@ ccflags-y := -I$(obj) -I$(obj)/.. + export BUILD_ID = \"Build Id: $(shell date +'%m/%d/%y, %H:%M:%S')\" + ccflags-y += -DNSS_CLIENT_BUILD_ID="$(BUILD_ID)" + ++qca-nss-tunipip6-objs := nss_connmgr_tunipip6.o + qca-nss-tun6rd-objs := nss_connmgr_tun6rd.o + ++ccflags-y += -DNSS_TUNIPIP6_DEBUG_LEVEL=0 + ccflags-y += -DNSS_TUN6RD_DEBUG_LEVEL=0 +-ccflags-y += -Wall -Werror +- +-KERNELVERSION := $(word 1, $(subst ., ,$(KERNELVERSION))).$(word 2, $(subst ., ,$(KERNELVERSION))) ++ccflags-y += -Werror + + obj-$(bridge-mgr)+= bridge/ + obj-$(capwapmgr)+= capwapmgr/ + obj-$(dtlsmgr)+= dtls/$(DTLSMGR_DIR)/ + obj-$(gre)+= gre/ + obj-$(ipsecmgr)+= ipsecmgr/$(IPSECMGR_DIR)/ +-obj-$(ipsecmgr-klips)+= ipsecmgr/$(IPSECMGR_DIR)/plugins/klips/ +-obj-$(ipsecmgr-xfrm)+= ipsecmgr/$(IPSECMGR_DIR)/plugins/xfrm/ + obj-$(l2tpv2)+= l2tp/l2tpv2/ + obj-$(lag-mgr)+= lag/ + obj-$(map-t)+= map/map-t/ + obj-$(portifmgr)+= portifmgr/ + obj-$(pptp)+= pptp/ + obj-$(profile)+= profiler/ +-obj-$(tunipip6)+= tunipip6/ ++obj-$(tunipip6)+= qca-nss-tunipip6.o + obj-$(tun6rd)+= qca-nss-tun6rd.o + obj-$(qdisc)+= nss_qdisc/ + obj-$(vlan-mgr)+= vlan/ +@@ -38,8 +36,6 @@ obj-$(clmapmgr)+= clmapmgr/ + obj-$(match)+= match/ + obj-$(tlsmgr)+= tls/ + obj-$(mirror)+= mirror/ +-obj-$(mscs)+= mscs/ +-obj-$(wifi-meshmgr)+= wifi_meshmgr/ + + #NSS NETLINK + obj-$(netlink)+= netlink/ +--- a/bridge/Makefile ++++ b/bridge/Makefile +@@ -9,7 +9,7 @@ qca-nss-bridge-mgr-objs += nss_bridge_mg + endif + + ccflags-y += -DNSS_BRIDGE_MGR_DEBUG_LEVEL=0 +-ccflags-y += -Wall -Werror ++ccflags-y += -Werror + + ifeq ($(SoC),$(filter $(SoC),ipq807x ipq807x_64 ipq60xx ipq60xx_64)) + ccflags-y += -DNSS_BRIDGE_MGR_PPE_SUPPORT +--- a/bridge/nss_bridge_mgr.c ++++ b/bridge/nss_bridge_mgr.c +@@ -1,12 +1,9 @@ + /* + ************************************************************************** +- * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. +- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. +- * ++ * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +- * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +@@ -418,37 +415,6 @@ static int nss_bridge_mgr_del_bond_slave + } + + /* +- * nss_bridge_mgr_bond_fdb_join() +- * Update FDB state when a bond interface joining bridge. +- */ +-static int nss_bridge_mgr_bond_fdb_join(struct nss_bridge_pvt *b_pvt) +-{ +- /* +- * If already other bond devices are attached to bridge, +- * only increment bond_slave_num, +- */ +- spin_lock(&br_mgr_ctx.lock); +- if (b_pvt->bond_slave_num) { +- b_pvt->bond_slave_num++; +- spin_unlock(&br_mgr_ctx.lock); +- return NOTIFY_DONE; +- } +- b_pvt->bond_slave_num = 1; +- spin_unlock(&br_mgr_ctx.lock); +- +- /* +- * This is the first bond device being attached to bridge. In order to enforce Linux +- * bond slave selection in bridge flows involving bond interfaces, we need to disable +- * fdb learning on this bridge master to allow flow based bridging. +- */ +- if (nss_bridge_mgr_disable_fdb_learning(b_pvt) < 0) { +- return NOTIFY_BAD; +- } +- +- return NOTIFY_DONE; +-} +- +-/* + * nss_bridge_mgr_bond_master_join() + * Add a bond interface to bridge + */ +@@ -481,7 +447,28 @@ static int nss_bridge_mgr_bond_master_jo + } + } + +- if (nss_bridge_mgr_bond_fdb_join(b_pvt) == NOTIFY_DONE) { ++ /* ++ * If already other bond devices are attached to bridge, ++ * only increment bond_slave_num, ++ */ ++ spin_lock(&br_mgr_ctx.lock); ++ if (b_pvt->bond_slave_num) { ++ b_pvt->bond_slave_num++; ++ spin_unlock(&br_mgr_ctx.lock); ++ return NOTIFY_DONE; ++ } ++ spin_unlock(&br_mgr_ctx.lock); ++ ++ /* ++ * This is the first bond device being attached to bridge. In order to enforce Linux ++ * bond slave selection in bridge flows involving bond interfaces, we need to disable ++ * fdb learning on this bridge master to allow flow based bridging. ++ */ ++ if (!nss_bridge_mgr_disable_fdb_learning(b_pvt)) { ++ spin_lock(&br_mgr_ctx.lock); ++ b_pvt->bond_slave_num = 1; ++ spin_unlock(&br_mgr_ctx.lock); ++ + return NOTIFY_DONE; + } + +@@ -501,40 +488,6 @@ cleanup: + } + + /* +- * nss_bridge_mgr_bond_fdb_leave() +- * Update FDB state when a bond interface leaving bridge. +- */ +-static int nss_bridge_mgr_bond_fdb_leave(struct nss_bridge_pvt *b_pvt) +-{ +- +- nss_bridge_mgr_assert(b_pvt->bond_slave_num == 0); +- +- /* +- * If more than one bond devices are attached to bridge, +- * only decrement the bond_slave_num +- */ +- spin_lock(&br_mgr_ctx.lock); +- if (b_pvt->bond_slave_num > 1) { +- b_pvt->bond_slave_num--; +- spin_unlock(&br_mgr_ctx.lock); +- return NOTIFY_DONE; +- } +- b_pvt->bond_slave_num = 0; +- spin_unlock(&br_mgr_ctx.lock); +- +- /* +- * The last bond interface is removed from bridge, we can switch back to FDB +- * learning mode. +- */ +- if (nss_bridge_mgr_enable_fdb_learning(b_pvt) < 0) { +- return NOTIFY_BAD; +- } +- +- return NOTIFY_DONE; +-} +- +- +-/* + * nss_bridge_mgr_bond_master_leave() + * Remove a bond interface from bridge + */ +@@ -563,7 +516,27 @@ static int nss_bridge_mgr_bond_master_le + } + } + +- if (nss_bridge_mgr_bond_fdb_leave(b_pvt) == NOTIFY_DONE) { ++ /* ++ * If more than one bond devices are attached to bridge, ++ * only decrement the bond_slave_num ++ */ ++ spin_lock(&br_mgr_ctx.lock); ++ if (b_pvt->bond_slave_num > 1) { ++ b_pvt->bond_slave_num--; ++ spin_unlock(&br_mgr_ctx.lock); ++ return NOTIFY_DONE; ++ } ++ spin_unlock(&br_mgr_ctx.lock); ++ ++ /* ++ * The last bond interface is removed from bridge, we can switch back to FDB ++ * learning mode. ++ */ ++ if (!nss_bridge_mgr_enable_fdb_learning(b_pvt)) { ++ spin_lock(&br_mgr_ctx.lock); ++ b_pvt->bond_slave_num = 0; ++ spin_unlock(&br_mgr_ctx.lock); ++ + return NOTIFY_DONE; + } + +@@ -782,6 +755,10 @@ int nss_bridge_mgr_join_bridge(struct ne + * This is done by not sending join message to the bridge in NSS. + */ + if (br_mgr_ctx.wan_if_num == ifnum) { ++ if (!nss_bridge_mgr_l2_exception_acl_enable()) { ++ nss_bridge_mgr_warn("%px: failed to enable ACL\n", br); ++ return -EIO; ++ } + br->wan_if_enabled = true; + br->wan_if_num = ifnum; + nss_bridge_mgr_info("if_num %d is added as WAN interface \n", ifnum); +@@ -830,10 +807,9 @@ int nss_bridge_mgr_join_bridge(struct ne + } + + /* +- * Update FDB state of the bridge. No need to add individual interfaces of bond to the bridge. +- * VLAN interface verifies that all interfaces are physical so, no need to verify again. ++ * Add the bond_master to bridge. + */ +- if (nss_bridge_mgr_bond_fdb_join(br) != NOTIFY_DONE) { ++ if (nss_bridge_mgr_bond_master_join(real_dev, br) != NOTIFY_DONE) { + nss_bridge_mgr_warn("%px: Slaves of bond interface %s join bridge failed\n", br, real_dev->name); + nss_bridge_tx_leave_msg(br->ifnum, dev); + nss_vlan_mgr_leave_bridge(dev, br->vsi); +@@ -888,6 +864,7 @@ int nss_bridge_mgr_leave_bridge(struct n + * Hence a leave message should also be avaoided. + */ + if ((br->wan_if_enabled) && (br->wan_if_num == ifnum)) { ++ nss_bridge_mgr_l2_exception_acl_disable(); + br->wan_if_enabled = false; + br->wan_if_num = -1; + nss_bridge_mgr_info("if_num %d is added as WAN interface\n", ifnum); +@@ -933,10 +910,9 @@ int nss_bridge_mgr_leave_bridge(struct n + } + + /* +- * Update FDB state of the bridge. No need to add individual interfaces of bond to the bridge. +- * VLAN interface verifies that all interfaces are physical so, no need to verify again. ++ * Remove the bond_master from bridge. + */ +- if (nss_bridge_mgr_bond_fdb_leave(br) != NOTIFY_DONE) { ++ if (nss_bridge_mgr_bond_master_leave(real_dev, br) != NOTIFY_DONE) { + nss_bridge_mgr_warn("%px: Slaves of bond interface %s leave bridge failed\n", br, real_dev->name); + nss_vlan_mgr_join_bridge(dev, br->vsi); + nss_bridge_tx_join_msg(br->ifnum, dev); +@@ -1046,45 +1022,44 @@ int nss_bridge_mgr_register_br(struct ne + + b_pvt->dev = dev; + +-#if defined(NSS_BRIDGE_MGR_PPE_SUPPORT) +- err = ppe_vsi_alloc(NSS_BRIDGE_MGR_SWITCH_ID, &vsi_id); +- if (err) { +- nss_bridge_mgr_warn("%px: failed to alloc bridge vsi, error = %d\n", b_pvt, err); +- goto fail; +- } +- +- b_pvt->vsi = vsi_id; +-#endif +- + ifnum = nss_dynamic_interface_alloc_node(NSS_DYNAMIC_INTERFACE_TYPE_BRIDGE); + if (ifnum < 0) { + nss_bridge_mgr_warn("%px: failed to alloc bridge di\n", b_pvt); +- goto fail_1; ++ nss_bridge_mgr_delete_instance(b_pvt); ++ return -EFAULT; + } + + if (!nss_bridge_register(ifnum, dev, NULL, NULL, 0, b_pvt)) { + nss_bridge_mgr_warn("%px: failed to register bridge di to NSS\n", b_pvt); +- goto fail_2; ++ goto fail; + } + + #if defined(NSS_BRIDGE_MGR_PPE_SUPPORT) ++ err = ppe_vsi_alloc(NSS_BRIDGE_MGR_SWITCH_ID, &vsi_id); ++ if (err) { ++ nss_bridge_mgr_warn("%px: failed to alloc bridge vsi, error = %d\n", b_pvt, err); ++ goto fail_1; ++ } ++ ++ b_pvt->vsi = vsi_id; ++ + err = nss_bridge_tx_vsi_assign_msg(ifnum, vsi_id); + if (err != NSS_TX_SUCCESS) { + nss_bridge_mgr_warn("%px: failed to assign vsi msg, error = %d\n", b_pvt, err); +- goto fail_3; ++ goto fail_2; + } + #endif + + err = nss_bridge_tx_set_mac_addr_msg(ifnum, dev->dev_addr); + if (err != NSS_TX_SUCCESS) { + nss_bridge_mgr_warn("%px: failed to set mac_addr msg, error = %d\n", b_pvt, err); +- goto fail_4; ++ goto fail_3; + } + + err = nss_bridge_tx_set_mtu_msg(ifnum, dev->mtu); + if (err != NSS_TX_SUCCESS) { + nss_bridge_mgr_warn("%px: failed to set mtu msg, error = %d\n", b_pvt, err); +- goto fail_4; ++ goto fail_3; + } + + /* +@@ -1092,8 +1067,10 @@ int nss_bridge_mgr_register_br(struct ne + */ + b_pvt->ifnum = ifnum; + b_pvt->mtu = dev->mtu; ++#if defined(NSS_BRIDGE_MGR_PPE_SUPPORT) + b_pvt->wan_if_num = -1; + b_pvt->wan_if_enabled = false; ++#endif + ether_addr_copy(b_pvt->dev_addr, dev->dev_addr); + spin_lock(&br_mgr_ctx.lock); + list_add(&b_pvt->list, &br_mgr_ctx.list); +@@ -1110,29 +1087,25 @@ int nss_bridge_mgr_register_br(struct ne + #endif + return 0; + +-fail_4: ++fail_3: + #if defined(NSS_BRIDGE_MGR_PPE_SUPPORT) + if (nss_bridge_tx_vsi_unassign_msg(ifnum, vsi_id) != NSS_TX_SUCCESS) { + nss_bridge_mgr_warn("%px: failed to unassign vsi\n", b_pvt); + } +-fail_3: +-#endif + ++fail_2: ++ ppe_vsi_free(NSS_BRIDGE_MGR_SWITCH_ID, vsi_id); ++ ++fail_1: ++#endif + nss_bridge_unregister(ifnum); + +-fail_2: ++fail: + if (nss_dynamic_interface_dealloc_node(ifnum, NSS_DYNAMIC_INTERFACE_TYPE_BRIDGE) != NSS_TX_SUCCESS) { + nss_bridge_mgr_warn("%px: failed to dealloc bridge di\n", b_pvt); + } + +-fail_1: +-#if defined(NSS_BRIDGE_MGR_PPE_SUPPORT) +- ppe_vsi_free(NSS_BRIDGE_MGR_SWITCH_ID, vsi_id); +-fail: +-#endif +- + nss_bridge_mgr_delete_instance(b_pvt); +- + return -EFAULT; + } + +@@ -1159,6 +1132,7 @@ static int nss_bridge_mgr_bond_slave_cha + return NOTIFY_DONE; + } + ++#if defined(NSS_BRIDGE_MGR_PPE_SUPPORT) + /* + * Add or remove the slave based based on linking event + */ +@@ -1173,6 +1147,7 @@ static int nss_bridge_mgr_bond_slave_cha + cu_info->upper_dev->name, master->name); + } + } ++#endif + + return NOTIFY_DONE; + } +@@ -1200,7 +1175,7 @@ static int nss_bridge_mgr_changemtu_even + + if (nss_bridge_tx_set_mtu_msg(b_pvt->ifnum, dev->mtu) != NSS_TX_SUCCESS) { + nss_bridge_mgr_warn("%px: Failed to send change MTU message to NSS\n", b_pvt); +- return NOTIFY_DONE; ++ return NOTIFY_BAD; + } + + spin_lock(&br_mgr_ctx.lock); +@@ -1234,7 +1209,7 @@ static int nss_bridge_mgr_changeaddr_eve + + if (nss_bridge_tx_set_mac_addr_msg(b_pvt->ifnum, dev->dev_addr) != NSS_TX_SUCCESS) { + nss_bridge_mgr_warn("%px: Failed to send change MAC address message to NSS\n", b_pvt); +- return NOTIFY_DONE; ++ return NOTIFY_BAD; + } + + spin_lock(&br_mgr_ctx.lock); +@@ -1294,6 +1269,7 @@ static int nss_bridge_mgr_changeupper_ev + nss_bridge_mgr_trace("%px: Interface %s joining bridge %s\n", b_pvt, dev->name, master_dev->name); + if (nss_bridge_mgr_join_bridge(dev, b_pvt)) { + nss_bridge_mgr_warn("%px: Interface %s failed to join bridge %s\n", b_pvt, dev->name, master_dev->name); ++ return NOTIFY_BAD; + } + + return NOTIFY_DONE; +@@ -1302,6 +1278,7 @@ static int nss_bridge_mgr_changeupper_ev + nss_bridge_mgr_trace("%px: Interface %s leaving bridge %s\n", b_pvt, dev->name, master_dev->name); + if (nss_bridge_mgr_leave_bridge(dev, b_pvt)) { + nss_bridge_mgr_warn("%px: Interface %s failed to leave bridge %s\n", b_pvt, dev->name, master_dev->name); ++ return NOTIFY_BAD; + } + + return NOTIFY_DONE; +@@ -1627,14 +1604,6 @@ int __init nss_bridge_mgr_init_module(vo + br_mgr_ctx.wan_if_num = -1; + br_fdb_update_register_notify(&nss_bridge_mgr_fdb_update_notifier); + br_mgr_ctx.nss_bridge_mgr_header = register_sysctl_table(nss_bridge_mgr_root_dir); +- +- /* +- * Enable ACL rule to enable L2 exception. This is needed if PPE Virtual ports is added to bridge. +- * It is assumed that VP is using flow based bridging, hence L2 exceptions will need to be enabled on PPE bridge. +- */ +- if (!nss_bridge_mgr_l2_exception_acl_enable()) { +- nss_bridge_mgr_warn("Failed to enable ACL\n"); +- } + #endif + #if defined (NSS_BRIDGE_MGR_OVS_ENABLE) + nss_bridge_mgr_ovs_init(); +@@ -1656,12 +1625,6 @@ void __exit nss_bridge_mgr_exit_module(v + if (br_mgr_ctx.nss_bridge_mgr_header) { + unregister_sysctl_table(br_mgr_ctx.nss_bridge_mgr_header); + } +- +- /* +- * Disable the PPE L2 exceptions which were enabled during module init for PPE virtual ports. +- */ +- nss_bridge_mgr_l2_exception_acl_disable(); +- + #endif + #if defined (NSS_BRIDGE_MGR_OVS_ENABLE) + nss_bridge_mgr_ovs_exit(); +--- a/capwapmgr/Makefile ++++ b/capwapmgr/Makefile +@@ -14,4 +14,4 @@ qca-nss-capwapmgr-objs := nss_capwapmgr. + ccflags-y += -DNSS_CAPWAPMGR_DEBUG_LEVEL=6 + + ccflags-y += $(NSS_CCFLAGS) -DNSS_DEBUG_LEVEL=0 -DNSS_PKT_STATS_ENABLED=0 +-ccflags-y += -Wall -Werror ++ccflags-y += -Werror +--- a/capwapmgr/nss_capwapmgr.c ++++ b/capwapmgr/nss_capwapmgr.c +@@ -1,12 +1,9 @@ + /* + ************************************************************************** +- * Copyright (c) 2014-2021, The Linux Foundation. All rights reserved. +- * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. +- * ++ * Copyright (c) 2014-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +- * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +@@ -95,16 +92,17 @@ + #define NSS_CAPWAPMGR_BIND_BITMAP 0x7E + + /* +- * We need 4 ACL rules - 2 rules for each v4 and v6 classification. ++ * The number of rules supported by a list is 4. Since we need 2 rules for every ++ * dscp classification (v4 and v6). We set this value to 2. + */ +-#define NSS_CAPWAPMGR_ACL_RULES_PER_LIST 4 ++#define NSS_CAPWAPMGR_ACL_RULES_PER_LIST 2 + + /* +- * We currently have list-id 60 reserved for this purpose. ++ * We currently have list-id 60 and 61 reserved for this purpose. + * TODO: Find a better approach to reserve list-id. + */ + #define NSS_CAPWAPMGR_ACL_LIST_START 60 +-#define NSS_CAPWAPMGR_ACL_LIST_CNT 1 ++#define NSS_CAPWAPMGR_ACL_LIST_CNT 2 + + #define NSS_CAPWAPMGR_NORMAL_FRAME_MTU 1500 + +@@ -234,7 +232,7 @@ static void nss_capwapmgr_decongestion_c + + /* + * nss_capwapmgr_start_xmit() +- * Transmit's skb to NSS FW over CAPWAP if_num_inner. ++ * Transmit's skb to NSS FW over CAPWAP if_num. + * + * Please make sure to leave headroom of NSS_CAPWAP_HEADROOM with every + * packet so that NSS can encap eth,vlan,ip,udp,capwap headers. +@@ -246,7 +244,7 @@ static netdev_tx_t nss_capwapmgr_start_x + struct net_device_stats *stats = &dev->stats; + struct nss_capwapmgr_priv *priv; + struct nss_capwap_metaheader *pre; +- uint32_t if_num_inner; ++ uint32_t if_num; + nss_tx_status_t status; + + priv = netdev_priv(dev); +@@ -259,9 +257,9 @@ static netdev_tx_t nss_capwapmgr_start_x + return NETDEV_TX_OK; + } + +- if_num_inner = priv->tunnel[pre->tunnel_id].if_num_inner; +- if (unlikely(if_num_inner == -1)) { +- nss_capwapmgr_warn("%px: (CAPWAP packet) if_num_inner in the tunnel not set pre->tunnel_id %d\n", dev, ++ if_num = priv->tunnel[pre->tunnel_id].if_num; ++ if (unlikely(if_num == 0)) { ++ nss_capwapmgr_warn("%px: (CAPWAP packet) if_num in the tunnel not set pre->tunnel_id %d\n", dev, + pre->tunnel_id); + kfree_skb(skb); + stats->tx_dropped++; +@@ -277,7 +275,7 @@ static netdev_tx_t nss_capwapmgr_start_x + */ + skb_set_queue_mapping(skb, pre->flow_id & 0x1); + +- status = nss_capwap_tx_buf(priv->nss_ctx, skb, if_num_inner); ++ status = nss_capwap_tx_buf(priv->nss_ctx, skb, if_num); + if (unlikely(status != NSS_TX_SUCCESS)) { + if (status == NSS_TX_FAILURE_QUEUE) { + nss_capwapmgr_warn("%px: netdev :%px queue is full", dev, dev); +@@ -302,7 +300,7 @@ static void nss_capwapmgr_fill_up_stats( + stats->rx_dropped += tstats->pnode_stats.rx_dropped; + + /* rx_fifo_errors will appear as rx overruns in ifconfig */ +- stats->rx_fifo_errors += (tstats->rx_n2h_drops + tstats->rx_n2h_queue_full_drops); ++ stats->rx_fifo_errors += (tstats->rx_queue_full_drops + tstats->rx_n2h_queue_full_drops); + stats->rx_errors += (tstats->rx_mem_failure_drops + tstats->rx_oversize_drops + tstats->rx_frag_timeout_drops); + stats->rx_bytes += tstats->pnode_stats.rx_bytes; + +@@ -370,6 +368,20 @@ static void nss_capwapmgr_dev_tunnel_sta + } + #endif + ++/** ++ * nss_capwapmgr_change_mtu - set new MTU size ++ * @dev: network device ++ * @new_mtu: new Maximum Transfer Unit ++ * ++ * Allow changing MTU size. Needs to be overridden for devices ++ * supporting jumbo frames. ++ */ ++int nss_capwapmgr_change_mtu(struct net_device *dev, int new_mtu) ++{ ++ dev->mtu = new_mtu; ++ return 0; ++} ++ + /* + * nss_capwapmgr_netdev_ops + * Netdev operations. +@@ -379,7 +391,7 @@ static const struct net_device_ops nss_c + .ndo_stop = nss_capwapmgr_close, + .ndo_start_xmit = nss_capwapmgr_start_xmit, + .ndo_set_mac_address = eth_mac_addr, +- .ndo_change_mtu = eth_change_mtu, ++ .ndo_change_mtu = nss_capwapmgr_change_mtu, + .ndo_get_stats64 = nss_capwapmgr_dev_tunnel_stats, + }; + +@@ -559,12 +571,15 @@ static struct nss_capwapmgr_tunnel *nss_ + return NULL; + } + ++ dev_hold(dev); + priv = netdev_priv(dev); + t = &priv->tunnel[tunnel_id]; +- if ( (t->if_num_inner == -1) || (t->if_num_outer == -1) ) { ++ if (t->if_num == 0) { ++ dev_put(dev); + return NULL; + } + ++ dev_put(dev); + return t; + } + +@@ -607,10 +622,6 @@ struct net_device *nss_capwapmgr_netdev_ + goto fail1; + } + memset(priv->tunnel, 0, sizeof(struct nss_capwapmgr_tunnel) * NSS_CAPWAPMGR_MAX_TUNNELS); +- for (i = 0; i < NSS_CAPWAPMGR_MAX_TUNNELS; i++) { +- priv->tunnel[i].if_num_inner = -1; +- priv->tunnel[i].if_num_outer = -1; +- } + + priv->resp = kmalloc(sizeof(struct nss_capwapmgr_response) * NSS_MAX_DYNAMIC_INTERFACES, GFP_ATOMIC); + if (!priv->resp) { +@@ -870,10 +881,6 @@ static nss_tx_status_t nss_capwapmgr_cre + memcpy(nircm->conn_rule.return_mac, unic->dest_mac, 6); + } + +- nircm->valid_flags |= NSS_IPV4_RULE_CREATE_SRC_MAC_VALID; +- nircm->src_mac_rule.mac_valid_flags |=NSS_IPV4_SRC_MAC_FLOW_VALID; +- memcpy(nircm->src_mac_rule.flow_src_mac, nircm->conn_rule.return_mac, 6); +- + /* + * Copy over the DSCP rule parameters + */ +@@ -1009,10 +1016,6 @@ static nss_tx_status_t nss_capwapmgr_cre + memcpy(nircm->conn_rule.return_mac, unic->dest_mac, 6); + nircm->valid_flags |= NSS_IPV6_RULE_CREATE_CONN_VALID; + +- nircm->valid_flags |= NSS_IPV6_RULE_CREATE_SRC_MAC_VALID; +- nircm->src_mac_rule.mac_valid_flags |=NSS_IPV6_SRC_MAC_FLOW_VALID; +- memcpy(nircm->src_mac_rule.flow_src_mac, nircm->conn_rule.return_mac, 6); +- + /* + * Copy over the DSCP rule parameters + */ +@@ -1294,85 +1297,23 @@ static nss_capwapmgr_status_t nss_capwap + } + + /* +- * nss_capwapmgr_tx_msg_enable_tunnel() +- * Common function to send CAPWAP tunnel enable msg +- */ +-static nss_tx_status_t nss_capwapmgr_tx_msg_enable_tunnel(struct nss_ctx_instance *ctx, struct net_device *dev, uint32_t if_num, uint32_t sibling_if_num) +-{ +- struct nss_capwap_msg capwapmsg; +- nss_tx_status_t status; +- +- /* +- * Prepare the tunnel configuration parameter to send to NSS FW +- */ +- memset(&capwapmsg, 0, sizeof(struct nss_capwap_msg)); +- capwapmsg.msg.enable_tunnel.sibling_if_num = sibling_if_num; +- +- /* +- * Send CAPWAP data tunnel command to NSS +- */ +- nss_capwap_msg_init(&capwapmsg, if_num, NSS_CAPWAP_MSG_TYPE_ENABLE_TUNNEL, sizeof(struct nss_capwap_enable_tunnel_msg), nss_capwapmgr_msg_event_receive, dev); +- +- status = nss_capwapmgr_tx_msg_sync(ctx, dev, &capwapmsg); +- if (status != NSS_TX_SUCCESS) { +- nss_capwapmgr_warn("%px: ctx: CMD: %d Tunnel error : %d \n", ctx, NSS_CAPWAP_MSG_TYPE_ENABLE_TUNNEL, status); +- } +- +- return status; +-} +- +-/* +- * nss_capwapmgr_tunnel_action() +- * Common function for CAPWAP tunnel operation messages without +- * any message data structures. +- */ +-static nss_tx_status_t nss_capwapmgr_tunnel_action(struct nss_ctx_instance *ctx, struct net_device *dev, uint32_t if_num, nss_capwap_msg_type_t cmd) +-{ +- struct nss_capwap_msg capwapmsg; +- nss_tx_status_t status; +- +- /* +- * Prepare the tunnel configuration parameter to send to NSS FW +- */ +- memset(&capwapmsg, 0, sizeof(struct nss_capwap_msg)); +- +- /* +- * Send CAPWAP data tunnel command to NSS +- */ +- nss_capwap_msg_init(&capwapmsg, if_num, cmd, 0, nss_capwapmgr_msg_event_receive, dev); +- +- status = nss_capwapmgr_tx_msg_sync(ctx, dev, &capwapmsg); +- if (status != NSS_TX_SUCCESS) { +- nss_capwapmgr_warn("%px: ctx: CMD: %d Tunnel error : %d \n", ctx, cmd, status); +- } +- +- return status; +-} +- +-/* + * nss_capwapmgr_get_dtls_netdev() + * API for getting the dtls netdev associated to the capwap tunnel +- * +- * The caller is expected to do a dev_put() to release the reference. + */ + struct net_device *nss_capwapmgr_get_dtls_netdev(struct net_device *capwap_dev, uint8_t tunnel_id) + { + struct nss_capwapmgr_tunnel *t; + struct net_device *dtls_dev; + +- dev_hold(capwap_dev); + t = nss_capwapmgr_verify_tunnel_param(capwap_dev, tunnel_id); + if (!t) { + nss_capwapmgr_warn("%px: can't find tunnel: %d\n", capwap_dev, tunnel_id); +- dev_put(capwap_dev); + return NULL; + } + + dtls_dev = t->dtls_dev; +- dev_hold(dtls_dev); +- +- dev_put(capwap_dev); + ++ dev_hold(dtls_dev); + return dtls_dev; + } + EXPORT_SYMBOL(nss_capwapmgr_get_dtls_netdev); +@@ -1394,16 +1335,15 @@ nss_capwapmgr_status_t nss_capwapmgr_upd + return NSS_CAPWAPMGR_FAILURE_BAD_PARAM; + } + +- dev_hold(dev); + t = nss_capwapmgr_verify_tunnel_param(dev, tunnel_id); + if (!t) { + nss_capwapmgr_warn("%px: can't find tunnel: %d\n", dev, tunnel_id); +- dev_put(dev); + return NSS_CAPWAPMGR_FAILURE_BAD_PARAM; + } + ++ dev_hold(dev); + priv = netdev_priv(dev); +- nss_capwapmgr_info("%px: %d: tunnel update MTU is being called\n", dev, t->if_num_inner); ++ nss_capwapmgr_info("%px: %d: tunnel update MTU is being called\n", dev, t->if_num); + + /* + * Prepare the tunnel configuration parameter to send to NSS FW +@@ -1413,7 +1353,7 @@ nss_capwapmgr_status_t nss_capwapmgr_upd + /* + * Send CAPWAP data tunnel command to NSS + */ +- nss_capwap_msg_init(&capwapmsg, t->if_num_inner, NSS_CAPWAP_MSG_TYPE_UPDATE_PATH_MTU, ++ nss_capwap_msg_init(&capwapmsg, t->if_num, NSS_CAPWAP_MSG_TYPE_UPDATE_PATH_MTU, + sizeof(struct nss_capwap_path_mtu_msg), nss_capwapmgr_msg_event_receive, dev); + capwapmsg.msg.mtu.path_mtu = htonl(mtu); + status = nss_capwapmgr_tx_msg_sync(priv->nss_ctx, dev, &capwapmsg); +@@ -1473,22 +1413,20 @@ nss_capwapmgr_status_t nss_capwapmgr_upd + { + struct nss_capwapmgr_priv *priv; + struct nss_capwapmgr_tunnel *t; ++ nss_capwapmgr_status_t status; + nss_tx_status_t nss_status; +- nss_capwapmgr_status_t status = NSS_CAPWAPMGR_SUCCESS; + struct nss_ipv6_create *v6; + uint8_t mac_addr_old[ETH_ALEN]; + +- dev_hold(dev); + t = nss_capwapmgr_verify_tunnel_param(dev, tunnel_id); + if (!t) { + nss_capwapmgr_warn("%px: can't find tunnel: %d\n", dev, tunnel_id); +- status = NSS_CAPWAPMGR_FAILURE_BAD_PARAM; +- goto done; ++ return NSS_CAPWAPMGR_FAILURE_BAD_PARAM; + } + +- ++ dev_hold(dev); + priv = netdev_priv(dev); +- nss_capwapmgr_info("%px: %d: tunnel update mac Addr is being called\n", dev, tunnel_id); ++ nss_capwapmgr_info("%px: %d: tunnel update mac Addr is being called\n", dev, t->if_num); + + /* + * Update the IPv4/IPv6 rule with the new destination mac address for flow and return. +@@ -1505,10 +1443,11 @@ nss_capwapmgr_status_t nss_capwapmgr_upd + if (nss_status != NSS_TX_SUCCESS) { + nss_capwapmgr_warn("%px: Update Destination Mac for tunnel error : %d \n", dev, nss_status); + memcpy(t->ip_rule.v4.src_mac, mac_addr_old, ETH_ALEN); +- status = NSS_CAPWAPMGR_FAILURE_IP_RULE; + } + +- goto done; ++ dev_put(dev); ++ return status; ++ + } + + v6 = &t->ip_rule.v6; +@@ -1519,10 +1458,10 @@ nss_capwapmgr_status_t nss_capwapmgr_upd + if (nss_status != NSS_TX_SUCCESS) { + nss_capwapmgr_warn("%px: Update Destination Mac for tunnel error : %d \n", dev, nss_status); + memcpy(t->ip_rule.v6.src_mac, mac_addr_old, ETH_ALEN); +- status = NSS_CAPWAPMGR_FAILURE_IP_RULE; ++ dev_put(dev); ++ return NSS_CAPWAPMGR_FAILURE_IP_RULE; + } + +-done: + dev_put(dev); + return status; + } +@@ -1532,24 +1471,23 @@ EXPORT_SYMBOL(nss_capwapmgr_update_dest_ + * nss_capwapmgr_update_src_interface() + * API for updating Source Interface + */ +-nss_capwapmgr_status_t nss_capwapmgr_update_src_interface(struct net_device *dev, uint8_t tunnel_id, uint32_t src_interface_num) ++nss_capwapmgr_status_t nss_capwapmgr_update_src_interface(struct net_device *dev, uint8_t tunnel_id, int32_t src_interface_num) + { + struct nss_capwapmgr_priv *priv; + struct nss_capwapmgr_tunnel *t; ++ nss_capwapmgr_status_t status; + nss_tx_status_t nss_status; + uint32_t outer_trustsec_enabled, dtls_enabled, forward_if_num, src_interface_num_temp; + +- dev_hold(dev); + t = nss_capwapmgr_verify_tunnel_param(dev, tunnel_id); + if (!t) { + nss_capwapmgr_warn("%px: can't find tunnel: %d\n", dev, tunnel_id); +- dev_put(dev); + return NSS_CAPWAPMGR_FAILURE_BAD_PARAM; + } + +- ++ dev_hold(dev); + priv = netdev_priv(dev); +- nss_capwapmgr_info("%px: %d: tunnel update source interface is being called\n", dev, tunnel_id); ++ nss_capwapmgr_info("%px: %d: tunnel update source interface is being called\n", dev, t->if_num); + outer_trustsec_enabled = t->capwap_rule.enabled_features & NSS_CAPWAPMGR_FEATURE_OUTER_TRUSTSEC_ENABLED; + dtls_enabled = t->capwap_rule.enabled_features & NSS_CAPWAPMGR_FEATURE_DTLS_ENABLED; + +@@ -1558,7 +1496,7 @@ nss_capwapmgr_status_t nss_capwapmgr_upd + */ + if (outer_trustsec_enabled) { + if (!dtls_enabled) { +- forward_if_num = nss_capwap_ifnum_with_core_id(t->if_num_outer); ++ forward_if_num = nss_capwap_ifnum_with_core_id(t->if_num); + } else { + forward_if_num = nss_dtlsmgr_get_interface(t->dtls_dev, NSS_DTLSMGR_INTERFACE_TYPE_OUTER); + } +@@ -1566,7 +1504,6 @@ nss_capwapmgr_status_t nss_capwapmgr_upd + nss_status = nss_trustsec_tx_update_nexthop(forward_if_num, src_interface_num, t->capwap_rule.outer_sgt_value); + if (nss_status != NSS_TX_SUCCESS) { + nss_capwapmgr_warn("%px: unconfigure trustsec_tx failed\n", dev); +- dev_put(dev); + return NSS_CAPWAPMGR_FAILURE_UNCONFIGURE_TRUSTSEC_TX; + } + +@@ -1575,7 +1512,6 @@ nss_capwapmgr_status_t nss_capwapmgr_upd + } else { + t->ip_rule.v6.src_interface_num = src_interface_num; + } +- dev_put(dev); + return NSS_CAPWAPMGR_SUCCESS; + } + +@@ -1659,8 +1595,7 @@ nss_capwapmgr_status_t nss_capwapmgr_upd + } + } + t->tunnel_state |= NSS_CAPWAPMGR_TUNNEL_STATE_IPRULE_CONFIGURED; +- dev_put(dev); +- return NSS_CAPWAPMGR_SUCCESS; ++ return status; + } + EXPORT_SYMBOL(nss_capwapmgr_update_src_interface); + +@@ -1997,7 +1932,7 @@ EXPORT_SYMBOL(nss_capwapmgr_dscp_rule_cr + nss_capwapmgr_status_t nss_capwapmgr_configure_dtls(struct net_device *dev, uint8_t tunnel_id, uint8_t enable_dtls, struct nss_dtlsmgr_config *in_data) + { + struct nss_capwapmgr_priv *priv; +- struct nss_capwap_msg capwapmsg_inner, capwapmsg_outer; ++ struct nss_capwap_msg capwapmsg; + struct nss_capwapmgr_tunnel *t; + struct nss_ipv4_destroy v4; + struct nss_ipv6_destroy v6; +@@ -2005,11 +1940,9 @@ nss_capwapmgr_status_t nss_capwapmgr_con + nss_capwapmgr_status_t status; + uint32_t ip_if_num, dtls_enabled, outer_trustsec_enabled; + +- dev_hold(dev); + t = nss_capwapmgr_verify_tunnel_param(dev, tunnel_id); + if (!t) { + nss_capwapmgr_warn("%px: can't find tunnel: %d\n", dev, tunnel_id); +- dev_put(dev); + return NSS_CAPWAPMGR_FAILURE_BAD_PARAM; + } + +@@ -2017,7 +1950,6 @@ nss_capwapmgr_status_t nss_capwapmgr_con + dtls_enabled = t->capwap_rule.enabled_features & NSS_CAPWAPMGR_FEATURE_DTLS_ENABLED; + if ((enable_dtls && dtls_enabled) || (!enable_dtls && !dtls_enabled)) { + nss_capwapmgr_warn("%px: nothing changed for tunnel: %d\n", dev, tunnel_id); +- dev_put(dev); + return NSS_CAPWAPMGR_FAILURE_BAD_PARAM; + } + +@@ -2027,31 +1959,23 @@ nss_capwapmgr_status_t nss_capwapmgr_con + */ + if (t->tunnel_state & NSS_CAPWAPMGR_TUNNEL_STATE_ENABLED) { + nss_capwapmgr_warn("%px: tunnel %d is already enabled\n", dev, tunnel_id); +- dev_put(dev); + return NSS_CAPWAPMGR_FAILURE_TUNNEL_ENABLED; + } + + /* + * Prepare DTLS configure message + */ +- memset(&capwapmsg_inner, 0, sizeof(struct nss_capwap_msg)); +- nss_capwap_msg_init(&capwapmsg_inner, t->if_num_inner, NSS_CAPWAP_MSG_TYPE_DTLS, +- sizeof(struct nss_capwap_dtls_msg), nss_capwapmgr_msg_event_receive, dev); +- +- memset(&capwapmsg_outer, 0, sizeof(struct nss_capwap_msg)); +- nss_capwap_msg_init(&capwapmsg_outer, t->if_num_outer, NSS_CAPWAP_MSG_TYPE_DTLS, ++ memset(&capwapmsg, 0, sizeof(struct nss_capwap_msg)); ++ nss_capwap_msg_init(&capwapmsg, t->if_num, NSS_CAPWAP_MSG_TYPE_DTLS, + sizeof(struct nss_capwap_dtls_msg), nss_capwapmgr_msg_event_receive, dev); + +- + if (!enable_dtls) { + nss_capwapmgr_info("%px disabling DTLS for tunnel: %d\n", dev, tunnel_id); + +- ip_if_num = nss_capwap_ifnum_with_core_id(t->if_num_outer); +- capwapmsg_inner.msg.dtls.enable = 0; +- capwapmsg_inner.msg.dtls.dtls_inner_if_num = t->capwap_rule.dtls_inner_if_num; +- capwapmsg_inner.msg.dtls.mtu_adjust = 0; +- +- capwapmsg_outer.msg.dtls.enable = 0; ++ ip_if_num = nss_capwap_ifnum_with_core_id(t->if_num); ++ capwapmsg.msg.dtls.enable = 0; ++ capwapmsg.msg.dtls.dtls_inner_if_num = t->capwap_rule.dtls_inner_if_num; ++ capwapmsg.msg.dtls.mtu_adjust = 0; + + /* + * Unconfigure trustsec tx first +@@ -2060,7 +1984,6 @@ nss_capwapmgr_status_t nss_capwapmgr_con + nss_status = nss_trustsec_tx_unconfigure_sgt(t->capwap_rule.dtls_inner_if_num, t->capwap_rule.outer_sgt_value); + if (nss_status != NSS_TX_SUCCESS) { + nss_capwapmgr_warn("%px: unconfigure trustsec_tx failed\n", dev); +- dev_put(dev); + return NSS_CAPWAPMGR_FAILURE_UNCONFIGURE_TRUSTSEC_TX; + } + } +@@ -2075,7 +1998,6 @@ nss_capwapmgr_status_t nss_capwapmgr_con + */ + if (!in_data) { + nss_capwapmgr_info("%px: dtls in_data required to create dtls tunnel\n", dev); +- dev_put(dev); + return NSS_CAPWAPMGR_FAILURE_BAD_PARAM; + } + +@@ -2085,12 +2007,11 @@ nss_capwapmgr_status_t nss_capwapmgr_con + * ensure that the user does not configure this mode accidentally. + */ + in_data->flags &= ~NSS_DTLSMGR_ENCAP_METADATA; +- in_data->decap.nexthop_ifnum = nss_capwap_ifnum_with_core_id(t->if_num_outer); ++ in_data->decap.nexthop_ifnum = nss_capwap_ifnum_with_core_id(t->if_num); + + t->dtls_dev = nss_dtlsmgr_session_create(in_data); + if (!t->dtls_dev) { + nss_capwapmgr_warn("%px: cannot create DTLS session\n", dev); +- dev_put(dev); + return NSS_CAPWAPMGR_FAILURE_DI_ALLOC_FAILED; + } + +@@ -2104,20 +2025,17 @@ nss_capwapmgr_status_t nss_capwapmgr_con + + ip_if_num = nss_dtlsmgr_get_interface(t->dtls_dev, NSS_DTLSMGR_INTERFACE_TYPE_OUTER); + +- capwapmsg_inner.msg.dtls.enable = 1; +- capwapmsg_inner.msg.dtls.dtls_inner_if_num = t->capwap_rule.dtls_inner_if_num; +- capwapmsg_inner.msg.dtls.mtu_adjust = t->capwap_rule.mtu_adjust; +- +- capwapmsg_outer.msg.dtls.enable = 1; ++ capwapmsg.msg.dtls.enable = 1; ++ capwapmsg.msg.dtls.dtls_inner_if_num = t->capwap_rule.dtls_inner_if_num; ++ capwapmsg.msg.dtls.mtu_adjust = t->capwap_rule.mtu_adjust; + + /* + * Unconfigure trustsec tx first + */ + if (outer_trustsec_enabled) { +- nss_status = nss_trustsec_tx_unconfigure_sgt(t->if_num_outer, t->capwap_rule.outer_sgt_value); ++ nss_status = nss_trustsec_tx_unconfigure_sgt(t->if_num, t->capwap_rule.outer_sgt_value); + if (nss_status != NSS_TX_SUCCESS) { + nss_capwapmgr_warn("%px: unconfigure trustsec_tx failed\n", dev); +- dev_put(dev); + return NSS_CAPWAPMGR_FAILURE_UNCONFIGURE_TRUSTSEC_TX; + } + } +@@ -2130,11 +2048,11 @@ nss_capwapmgr_status_t nss_capwapmgr_con + nss_status = nss_trustsec_tx_configure_sgt(ip_if_num, t->capwap_rule.gmac_ifnum, t->capwap_rule.outer_sgt_value); + if (nss_status != NSS_TX_SUCCESS) { + nss_capwapmgr_warn("%px: configure trustsec_tx failed\n", dev); +- dev_put(dev); + return NSS_CAPWAPMGR_FAILURE_CONFIGURE_TRUSTSEC_TX; + } + } + ++ dev_hold(dev); + priv = netdev_priv(dev); + + /* +@@ -2200,18 +2118,11 @@ nss_capwapmgr_status_t nss_capwapmgr_con + * Now configure capwap dtls + */ + t->tunnel_state |= NSS_CAPWAPMGR_TUNNEL_STATE_IPRULE_CONFIGURED; +- status = nss_capwapmgr_tx_msg_sync(priv->nss_ctx, dev, &capwapmsg_inner); +- if (status != NSS_CAPWAPMGR_SUCCESS) { +- nss_capwapmgr_warn("%px: configure DTLS failed for inner node: %d\n", dev, status); +- dev_put(dev); +- return status; +- } +- +- status = nss_capwapmgr_tx_msg_sync(priv->nss_ctx, dev, &capwapmsg_outer); ++ status = nss_capwapmgr_tx_msg_sync(priv->nss_ctx, dev, &capwapmsg); + if (status != NSS_CAPWAPMGR_SUCCESS) { +- nss_capwapmgr_warn("%px: configure DTLS failed for outer node: %d\n", dev, status); ++ nss_capwapmgr_warn("%px: configure DTLS failed : %d\n", dev, status); + dev_put(dev); +- return status; ++ return nss_status; + } + + if (enable_dtls) { +@@ -2227,8 +2138,6 @@ EXPORT_SYMBOL(nss_capwapmgr_configure_dt + /* + * nss_capwapmgr_verify_dtls_rekey_param() + * Validate the rekey param for a DTLS tunnel and return the DTLS netdevice +- * +- * The caller should hold the reference on the net device before calling. + */ + static inline struct net_device *nss_capwapmgr_verify_dtls_rekey_param(struct net_device *dev, uint8_t tunnel_id, + struct nss_dtlsmgr_config_update *udata) +@@ -2261,27 +2170,16 @@ static inline struct net_device *nss_cap + nss_capwapmgr_status_t nss_capwapmgr_dtls_rekey_rx_cipher_update(struct net_device *dev, uint8_t tunnel_id, + struct nss_dtlsmgr_config_update *udata) + { +- struct net_device *dtls_ndev; +- +- dev_hold(dev); +- dtls_ndev = nss_capwapmgr_verify_dtls_rekey_param(dev, tunnel_id, udata); +- dev_put(dev); +- +- if (!dtls_ndev) { +- goto fail; +- } ++ struct net_device *dtls_ndev = nss_capwapmgr_verify_dtls_rekey_param(dev, tunnel_id, udata); + + /* + * Calling dtlsmgr for rekey + */ + if (nss_dtlsmgr_session_update_decap(dtls_ndev, udata) != NSS_DTLSMGR_OK) { +- goto fail; ++ nss_capwapmgr_warn("%px: tunnel: %d rekey rx cipher update failed\n", dtls_ndev, tunnel_id); ++ return NSS_CAPWAPMGR_FAILURE_INVALID_DTLS_CFG; + } + return NSS_CAPWAPMGR_SUCCESS; +- +-fail: +- nss_capwapmgr_warn("%px: tunnel: %d rekey rx cipher update failed\n", dtls_ndev, tunnel_id); +- return NSS_CAPWAPMGR_FAILURE_INVALID_DTLS_CFG; + } + EXPORT_SYMBOL(nss_capwapmgr_dtls_rekey_rx_cipher_update); + +@@ -2292,27 +2190,16 @@ EXPORT_SYMBOL(nss_capwapmgr_dtls_rekey_r + nss_capwapmgr_status_t nss_capwapmgr_dtls_rekey_tx_cipher_update(struct net_device *dev, uint8_t tunnel_id, + struct nss_dtlsmgr_config_update *udata) + { +- struct net_device *dtls_ndev; +- +- dev_hold(dev); +- dtls_ndev = nss_capwapmgr_verify_dtls_rekey_param(dev, tunnel_id, udata); +- dev_put(dev); +- +- if (!dtls_ndev) { +- goto fail; +- } ++ struct net_device *dtls_ndev = nss_capwapmgr_verify_dtls_rekey_param(dev, tunnel_id, udata); + + /* + * Calling dtlsmgr for rekey + */ + if (nss_dtlsmgr_session_update_encap(dtls_ndev, udata) != NSS_DTLSMGR_OK) { +- goto fail; ++ nss_capwapmgr_warn("%px: tunnel: %d rekey tx cipher update failed\n", dtls_ndev, tunnel_id); ++ return NSS_CAPWAPMGR_FAILURE_INVALID_DTLS_CFG; + } + return NSS_CAPWAPMGR_SUCCESS; +- +-fail: +- nss_capwapmgr_warn("%px: tunnel: %d rekey rx cipher update failed\n", dtls_ndev, tunnel_id); +- return NSS_CAPWAPMGR_FAILURE_INVALID_DTLS_CFG; + } + EXPORT_SYMBOL(nss_capwapmgr_dtls_rekey_tx_cipher_update); + +@@ -2323,20 +2210,16 @@ EXPORT_SYMBOL(nss_capwapmgr_dtls_rekey_t + nss_capwapmgr_status_t nss_capwapmgr_dtls_rekey_rx_cipher_switch(struct net_device *dev, uint8_t tunnel_id) + { + struct nss_capwapmgr_tunnel *t; +- nss_capwapmgr_status_t status = NSS_CAPWAPMGR_SUCCESS; + +- dev_hold(dev); + t = nss_capwapmgr_verify_tunnel_param(dev, tunnel_id); + if (!t) { + nss_capwapmgr_warn("%px: can't find tunnel: %d\n", dev, tunnel_id); +- status = NSS_CAPWAPMGR_FAILURE_BAD_PARAM; +- goto done; ++ return NSS_CAPWAPMGR_FAILURE_BAD_PARAM; + } + + if (!(t->capwap_rule.enabled_features & NSS_CAPWAPMGR_FEATURE_DTLS_ENABLED)) { + nss_capwapmgr_warn("%px: tunnel does not enable DTLS: %d\n", dev, tunnel_id); +- status = NSS_CAPWAPMGR_FAILURE_BAD_PARAM; +- goto done; ++ return NSS_CAPWAPMGR_FAILURE_BAD_PARAM; + } + + /* +@@ -2344,12 +2227,10 @@ nss_capwapmgr_status_t nss_capwapmgr_dtl + */ + if (!nss_dtlsmgr_session_switch_decap(t->dtls_dev)) { + nss_capwapmgr_warn("%px: tunnel: %d rekey rx cipher switch failed\n", t->dtls_dev, tunnel_id); +- status = NSS_CAPWAPMGR_FAILURE_INVALID_DTLS_CFG; ++ return NSS_CAPWAPMGR_FAILURE_INVALID_DTLS_CFG; + } + +-done: +- dev_put(dev); +- return status; ++ return NSS_CAPWAPMGR_SUCCESS; + } + EXPORT_SYMBOL(nss_capwapmgr_dtls_rekey_rx_cipher_switch); + +@@ -2360,20 +2241,16 @@ EXPORT_SYMBOL(nss_capwapmgr_dtls_rekey_r + nss_capwapmgr_status_t nss_capwapmgr_dtls_rekey_tx_cipher_switch(struct net_device *dev, uint8_t tunnel_id) + { + struct nss_capwapmgr_tunnel *t; +- nss_capwapmgr_status_t status = NSS_CAPWAPMGR_SUCCESS; + +- dev_hold(dev); + t = nss_capwapmgr_verify_tunnel_param(dev, tunnel_id); + if (!t) { + nss_capwapmgr_warn("%px: can't find tunnel: %d\n", dev, tunnel_id); +- status = NSS_CAPWAPMGR_FAILURE_BAD_PARAM; +- goto done; ++ return NSS_CAPWAPMGR_FAILURE_BAD_PARAM; + } + + if (!(t->capwap_rule.enabled_features & NSS_CAPWAPMGR_FEATURE_DTLS_ENABLED)) { + nss_capwapmgr_warn("%px: tunnel does not enable DTLS: %d\n", dev, tunnel_id); +- status = NSS_CAPWAPMGR_FAILURE_BAD_PARAM; +- goto done; ++ return NSS_CAPWAPMGR_FAILURE_BAD_PARAM; + } + + /* +@@ -2381,12 +2258,10 @@ nss_capwapmgr_status_t nss_capwapmgr_dtl + */ + if (!nss_dtlsmgr_session_switch_encap(t->dtls_dev)) { + nss_capwapmgr_warn("%px: tunnel: %d rekey tx cipher switch failed\n", t->dtls_dev, tunnel_id); +- status = NSS_CAPWAPMGR_FAILURE_INVALID_DTLS_CFG; ++ return NSS_CAPWAPMGR_FAILURE_INVALID_DTLS_CFG; + } + +-done: +- dev_put(dev); +- return status; ++ return NSS_CAPWAPMGR_SUCCESS; + } + EXPORT_SYMBOL(nss_capwapmgr_dtls_rekey_tx_cipher_switch); + +@@ -2400,22 +2275,20 @@ nss_capwapmgr_status_t nss_capwapmgr_cha + struct nss_capwapmgr_priv *priv; + struct nss_capwap_msg capwapmsg; + struct nss_capwapmgr_tunnel *t; +- nss_capwapmgr_status_t status = NSS_CAPWAPMGR_SUCCESS; ++ nss_capwapmgr_status_t status; + +- dev_hold(dev); + t = nss_capwapmgr_verify_tunnel_param(dev, tunnel_id); + if (!t) { + nss_capwapmgr_warn("%px: can't find tunnel: %d\n", dev, tunnel_id); +- status = NSS_CAPWAPMGR_FAILURE_BAD_PARAM; +- goto done; ++ return NSS_CAPWAPMGR_FAILURE_BAD_PARAM; + } + + if (ver > NSS_CAPWAP_VERSION_V2) { + nss_capwapmgr_warn("%px: un-supported Version: %d\n", dev, ver); +- status = NSS_CAPWAPMGR_FAILURE_BAD_PARAM; +- goto done; ++ return NSS_CAPWAPMGR_FAILURE_BAD_PARAM; + } + ++ dev_hold(dev); + priv = netdev_priv(dev); + + /* +@@ -2426,21 +2299,50 @@ nss_capwapmgr_status_t nss_capwapmgr_cha + /* + * Send CAPWAP data tunnel command to NSS + */ +- nss_capwap_msg_init(&capwapmsg, t->if_num_inner, NSS_CAPWAP_MSG_TYPE_VERSION, ++ nss_capwap_msg_init(&capwapmsg, t->if_num, NSS_CAPWAP_MSG_TYPE_VERSION, + sizeof(struct nss_capwap_version_msg), nss_capwapmgr_msg_event_receive, dev); + capwapmsg.msg.version.version = ver; + status = nss_capwapmgr_tx_msg_sync(priv->nss_ctx, dev, &capwapmsg); + if (status != NSS_CAPWAPMGR_SUCCESS) { + nss_capwapmgr_warn("%px: Update Path MTU Tunnel error : %d \n", dev, status); ++ dev_put(dev); ++ return status; + } + +-done: + dev_put(dev); + return status; + } + EXPORT_SYMBOL(nss_capwapmgr_change_version); + + /* ++ * nss_capwapmgr_tunnel_action() ++ * Common function for CAPWAP tunnel operation messages without ++ * any message data structures. ++ */ ++static nss_tx_status_t nss_capwapmgr_tunnel_action(struct nss_ctx_instance *ctx, struct net_device *dev, uint32_t if_num, nss_capwap_msg_type_t cmd) ++{ ++ struct nss_capwap_msg capwapmsg; ++ nss_tx_status_t status; ++ ++ /* ++ * Prepare the tunnel configuration parameter to send to NSS FW ++ */ ++ memset(&capwapmsg, 0, sizeof(struct nss_capwap_msg)); ++ ++ /* ++ * Send CAPWAP data tunnel command to NSS ++ */ ++ nss_capwap_msg_init(&capwapmsg, if_num, cmd, 0, nss_capwapmgr_msg_event_receive, dev); ++ status = nss_capwapmgr_tx_msg_sync(ctx, dev, &capwapmsg); ++ if (status != NSS_TX_SUCCESS) { ++ nss_capwapmgr_warn("%px: ctx: CMD: %d Tunnel error : %d \n", ctx, cmd, status); ++ return status; ++ } ++ ++ return status; ++} ++ ++/* + * nss_capwapmgr_enable_tunnel() + * API for enabling a data tunnel + */ +@@ -2448,41 +2350,28 @@ nss_capwapmgr_status_t nss_capwapmgr_ena + { + struct nss_capwapmgr_priv *priv; + struct nss_capwapmgr_tunnel *t; +- nss_capwapmgr_status_t status = NSS_CAPWAPMGR_SUCCESS; ++ nss_tx_status_t ret; + +- dev_hold(dev); + t = nss_capwapmgr_verify_tunnel_param(dev, tunnel_id); + if (!t) { + nss_capwapmgr_warn("%px: can't find tunnel: %d\n", dev, tunnel_id); +- status = NSS_CAPWAPMGR_FAILURE_BAD_PARAM; +- goto done; ++ return NSS_CAPWAPMGR_FAILURE_BAD_PARAM; + } + + if (t->tunnel_state & NSS_CAPWAPMGR_TUNNEL_STATE_ENABLED) { + nss_capwapmgr_warn("%px: tunnel %d is already enabled\n", dev, tunnel_id); +- status = NSS_CAPWAPMGR_FAILURE_TUNNEL_ENABLED; +- goto done; ++ return NSS_CAPWAPMGR_FAILURE_TUNNEL_ENABLED; + } + ++ dev_hold(dev); + priv = netdev_priv(dev); +- nss_capwapmgr_info("%px: Inner:%d Outer:%d. Tunnel enable is being called\n", dev, t->if_num_inner, t->if_num_outer); +- +- status = nss_capwapmgr_tx_msg_enable_tunnel(priv->nss_ctx, dev, t->if_num_inner,t->if_num_outer); +- if (status != NSS_CAPWAPMGR_SUCCESS) { +- goto done; ++ nss_capwapmgr_info("%px: %d: tunnel enable is being called\n", dev, t->if_num); ++ ret = nss_capwapmgr_tunnel_action(priv->nss_ctx, dev, t->if_num, NSS_CAPWAP_MSG_TYPE_ENABLE_TUNNEL); ++ if (ret == NSS_TX_SUCCESS) { ++ t->tunnel_state |= NSS_CAPWAPMGR_TUNNEL_STATE_ENABLED; + } +- +- status = nss_capwapmgr_tx_msg_enable_tunnel(priv->nss_ctx, dev, t->if_num_outer,t->if_num_inner); +- if(status != NSS_CAPWAPMGR_SUCCESS) { +- nss_capwapmgr_tunnel_action(priv->nss_ctx, dev, t->if_num_inner,NSS_CAPWAP_MSG_TYPE_DISABLE_TUNNEL); +- goto done; +- } +- +- t->tunnel_state |= NSS_CAPWAPMGR_TUNNEL_STATE_ENABLED; +- +-done: + dev_put(dev); +- return status; ++ return ret; + } + EXPORT_SYMBOL(nss_capwapmgr_enable_tunnel); + +@@ -2494,44 +2383,28 @@ nss_capwapmgr_status_t nss_capwapmgr_dis + { + struct nss_capwapmgr_priv *priv; + struct nss_capwapmgr_tunnel *t; +- nss_capwapmgr_status_t status = NSS_CAPWAPMGR_SUCCESS; ++ nss_tx_status_t ret; + +- dev_hold(dev); + t = nss_capwapmgr_verify_tunnel_param(dev, tunnel_id); + if (!t) { + nss_capwapmgr_warn("%px: can't find tunnel: %d\n", dev, tunnel_id); +- status = NSS_CAPWAPMGR_FAILURE_BAD_PARAM; +- goto done; ++ return NSS_CAPWAPMGR_FAILURE_BAD_PARAM; + } + + if (!(t->tunnel_state & NSS_CAPWAPMGR_TUNNEL_STATE_ENABLED)) { +- nss_capwapmgr_warn("%px: tunnel %d is already disabled\n", dev, tunnel_id); +- status = NSS_CAPWAPMGR_FAILURE_TUNNEL_DISABLED; +- goto done; ++ nss_capwapmgr_warn("%px: tunnel %d is already enabled\n", dev, tunnel_id); ++ return NSS_CAPWAPMGR_FAILURE_TUNNEL_DISABLED; + } + ++ dev_hold(dev); + priv = netdev_priv(dev); +- nss_capwapmgr_info("%px: Inner:%d Outer:%d. Tunnel disable is being called\n", dev, t->if_num_inner, t->if_num_outer); +- +- status = nss_capwapmgr_tunnel_action(priv->nss_ctx, dev, t->if_num_inner,NSS_CAPWAP_MSG_TYPE_DISABLE_TUNNEL); +- if (status != NSS_CAPWAPMGR_SUCCESS) { +- status = NSS_CAPWAPMGR_FAILURE_TUNNEL_DISABLED; +- nss_capwapmgr_warn("%px: tunnel %d disable failed\n", dev, tunnel_id); +- goto done; +- } +- +- status = nss_capwapmgr_tunnel_action(priv->nss_ctx, dev, t->if_num_outer,NSS_CAPWAP_MSG_TYPE_DISABLE_TUNNEL); +- if (status != NSS_CAPWAPMGR_SUCCESS) { +- nss_capwapmgr_warn("%px: tunnel %d disable failed\n", dev, tunnel_id); +- nss_capwapmgr_tx_msg_enable_tunnel(priv->nss_ctx, dev, t->if_num_inner, t->if_num_outer); +- goto done; ++ nss_capwapmgr_info("%px: %d: tunnel disable is being called\n", dev, t->if_num); ++ ret = nss_capwapmgr_tunnel_action(priv->nss_ctx, dev, t->if_num, NSS_CAPWAP_MSG_TYPE_DISABLE_TUNNEL); ++ if (ret == NSS_TX_SUCCESS) { ++ t->tunnel_state &= ~NSS_CAPWAPMGR_TUNNEL_STATE_ENABLED; + } +- +- t->tunnel_state &= ~NSS_CAPWAPMGR_TUNNEL_STATE_ENABLED; +- +-done: + dev_put(dev); +- return status; ++ return ret; + } + EXPORT_SYMBOL(nss_capwapmgr_disable_tunnel); + +@@ -2545,7 +2418,7 @@ static nss_capwapmgr_status_t nss_capwap + struct nss_capwapmgr_priv *priv; + struct nss_capwapmgr_tunnel *t; + nss_capwapmgr_status_t status = NSS_CAPWAPMGR_SUCCESS; +- int32_t capwap_if_num_inner, capwap_if_num_outer, forward_if_num; ++ int32_t capwap_if_num, forward_if_num; + uint16_t type_flags = 0; + nss_tx_status_t nss_status = NSS_TX_SUCCESS; + uint32_t dtls_enabled = capwap_rule->enabled_features & NSS_CAPWAPMGR_FEATURE_DTLS_ENABLED; +@@ -2578,44 +2451,28 @@ static nss_capwapmgr_status_t nss_capwap + return NSS_CAPWAPMGR_FAILURE_BAD_PARAM; + } + +- dev_hold(dev); + t = nss_capwapmgr_verify_tunnel_param(dev, tunnel_id); + if (t) { + nss_capwapmgr_warn("%px: tunnel: %d already created\n", dev, tunnel_id); +- status = NSS_CAPWAPMGR_FAILURE_TUNNEL_EXISTS; +- goto done; ++ return NSS_CAPWAPMGR_FAILURE_TUNNEL_EXISTS; + } + +- capwap_if_num_inner = nss_dynamic_interface_alloc_node(NSS_DYNAMIC_INTERFACE_TYPE_CAPWAP_HOST_INNER); +- if (capwap_if_num_inner < 0) { +- nss_capwapmgr_warn("%px: di returned error : %d\n", dev, capwap_if_num_inner); +- status = NSS_CAPWAPMGR_FAILURE_DI_ALLOC_FAILED; +- goto done; ++ capwap_if_num = nss_dynamic_interface_alloc_node(NSS_DYNAMIC_INTERFACE_TYPE_CAPWAP); ++ if (capwap_if_num < 0) { ++ nss_capwapmgr_warn("%px: di returned error : %d\n", dev, capwap_if_num); ++ return NSS_CAPWAPMGR_FAILURE_DI_ALLOC_FAILED; + } + +- if (nss_capwapmgr_register_with_nss(capwap_if_num_inner, dev) != NSS_CAPWAPMGR_SUCCESS) { +- nss_capwapmgr_warn("%d: NSS CAPWAP register with NSS failed", capwap_if_num_inner); +- status = NSS_CAPWAPMGR_FAILURE_REGISTER_NSS; +- goto fail1; +- } +- +- capwap_if_num_outer = nss_dynamic_interface_alloc_node(NSS_DYNAMIC_INTERFACE_TYPE_CAPWAP_OUTER); +- if (capwap_if_num_outer < 0) { +- nss_capwapmgr_warn("%px: di returned error : %d\n", dev, capwap_if_num_outer); +- status = NSS_CAPWAPMGR_FAILURE_DI_ALLOC_FAILED; +- goto fail2; +- } +- +- if (nss_capwapmgr_register_with_nss(capwap_if_num_outer, dev) != NSS_CAPWAPMGR_SUCCESS) { +- nss_capwapmgr_warn("%d: NSS CAPWAP register with NSS failed", capwap_if_num_outer); +- status = NSS_CAPWAPMGR_FAILURE_REGISTER_NSS; +- goto fail3; ++ if (nss_capwapmgr_register_with_nss(capwap_if_num, dev) != NSS_CAPWAPMGR_SUCCESS) { ++ nss_capwapmgr_warn("%d: NSS CAPWAP register with NSS failed", capwap_if_num); ++ (void)nss_dynamic_interface_dealloc_node(capwap_if_num, NSS_DYNAMIC_INTERFACE_TYPE_CAPWAP); ++ return NSS_CAPWAPMGR_FAILURE_REGISTER_NSS; + } + + if (!dtls_enabled) { + capwap_rule->mtu_adjust = 0; + capwap_rule->dtls_inner_if_num = 0; +- forward_if_num = nss_capwap_ifnum_with_core_id(capwap_if_num_outer); ++ forward_if_num = nss_capwap_ifnum_with_core_id(capwap_if_num); + } else { + /* + * We only support the METADATA mode for pure DTLS tunnels; in CAPWAP-DTLS +@@ -2623,13 +2480,14 @@ static nss_capwapmgr_status_t nss_capwap + * ensure that the user does not configure this mode accidentally. + */ + in_data->flags &= ~NSS_DTLSMGR_ENCAP_METADATA; +- in_data->decap.nexthop_ifnum = nss_capwap_ifnum_with_core_id(capwap_if_num_outer); ++ in_data->decap.nexthop_ifnum = nss_capwap_ifnum_with_core_id(capwap_if_num); + + t->dtls_dev = nss_dtlsmgr_session_create(in_data); + if (!t->dtls_dev) { + nss_capwapmgr_warn("%px: NSS DTLS node alloc failed\n", dev); +- status = NSS_CAPWAPMGR_FAILURE_DI_ALLOC_FAILED; +- goto fail4; ++ nss_capwapmgr_unregister_with_nss(capwap_if_num); ++ (void)nss_dynamic_interface_dealloc_node(capwap_if_num, NSS_DYNAMIC_INTERFACE_TYPE_CAPWAP); ++ return NSS_CAPWAPMGR_FAILURE_DI_ALLOC_FAILED; + } + capwap_rule->dtls_inner_if_num = nss_dtlsmgr_get_interface(t->dtls_dev, NSS_DTLSMGR_INTERFACE_TYPE_INNER); + forward_if_num = nss_dtlsmgr_get_interface(t->dtls_dev, NSS_DTLSMGR_INTERFACE_TYPE_OUTER); +@@ -2650,7 +2508,7 @@ static nss_capwapmgr_status_t nss_capwap + if (nss_status != NSS_TX_SUCCESS) { + nss_capwapmgr_warn("%px: configure trustsectx node failed\n", dev); + status = NSS_CAPWAPMGR_FAILURE_CONFIGURE_TRUSTSEC_TX; +- goto fail5; ++ goto fail; + } + } + +@@ -2706,20 +2564,12 @@ static nss_capwapmgr_status_t nss_capwap + capwap_rule->encap.dest_ip.ip.ipv6[3] = htonl(v6->src_ip[3]); + } + +- status = nss_capwapmgr_create_capwap_rule(dev, capwap_if_num_inner, capwap_rule, type_flags); +- nss_capwapmgr_info("%px: dynamic interface if_num is :%d and capwap tunnel status:%d\n", dev, capwap_if_num_inner, status); ++ status = nss_capwapmgr_create_capwap_rule(dev, capwap_if_num, capwap_rule, type_flags); ++ nss_capwapmgr_info("%px: dynamic interface if_num is :%d and capwap tunnel status:%d\n", dev, capwap_if_num, status); + if (status != NSS_CAPWAPMGR_SUCCESS) { +- nss_capwapmgr_warn("%px: %d: CAPWAP rule create failed with status: %d", dev, capwap_if_num_inner, status); ++ nss_capwapmgr_warn("%px: %d: CAPWAP rule create failed with status: %d", dev, capwap_if_num, status); + status = NSS_CAPWAPMGR_FAILURE_CAPWAP_RULE; +- goto fail5; +- } +- +- status = nss_capwapmgr_create_capwap_rule(dev, capwap_if_num_outer, capwap_rule, type_flags); +- nss_capwapmgr_info("%px: dynamic interface if_num is :%d and capwap tunnel status:%d\n", dev, capwap_if_num_outer, status); +- if (status != NSS_CAPWAPMGR_SUCCESS) { +- nss_capwapmgr_warn("%px: %d: CAPWAP rule create failed with status: %d", dev, capwap_if_num_outer, status); +- status = NSS_CAPWAPMGR_FAILURE_CAPWAP_RULE; +- goto fail5; ++ goto fail; + } + + if (v4) { +@@ -2733,12 +2583,13 @@ static nss_capwapmgr_status_t nss_capwap + if (nss_status != NSS_TX_SUCCESS) { + nss_capwapmgr_warn("%px: %d: IPv4/IPv6 rule create failed with status: %d", dev, forward_if_num, nss_status); + status = NSS_CAPWAPMGR_FAILURE_IP_RULE; +- goto fail5; ++ goto fail; + } + ++ dev_hold(dev); + priv = netdev_priv(dev); + t = &priv->tunnel[tunnel_id]; +- nss_capwapmgr_info("%px: %d: %d: CAPWAP TUNNEL CREATE DONE tunnel_id:%d (%px)\n", dev, capwap_if_num_inner, capwap_if_num_outer, tunnel_id, t); ++ nss_capwapmgr_info("%px: %d: CAPWAP TUNNEL CREATE DONE tunnel_id:%d (%px)\n", dev, capwap_if_num, tunnel_id, t); + + /* + * Keep a copy of rule information. +@@ -2754,33 +2605,22 @@ static nss_capwapmgr_status_t nss_capwap + /* + * Make it globally visible inside the netdev. + */ +- t->if_num_inner = capwap_if_num_inner; +- t->if_num_outer = capwap_if_num_outer; +- priv->if_num_to_tunnel_id[capwap_if_num_inner] = tunnel_id; +- priv->if_num_to_tunnel_id[capwap_if_num_outer] = tunnel_id; ++ t->if_num = capwap_if_num; ++ priv->if_num_to_tunnel_id[capwap_if_num] = tunnel_id; + t->tunnel_state |= NSS_CAPWAPMGR_TUNNEL_STATE_CONFIGURED; + t->tunnel_state |= NSS_CAPWAPMGR_TUNNEL_STATE_IPRULE_CONFIGURED; +- t->type_flags = type_flags; + +- goto done; ++ dev_put(dev); ++ return status; + +-fail5: ++fail: ++ nss_capwapmgr_unregister_with_nss(capwap_if_num); ++ (void)nss_dynamic_interface_dealloc_node(capwap_if_num, NSS_DYNAMIC_INTERFACE_TYPE_CAPWAP); + if (dtls_enabled) { + if (nss_dtlsmgr_session_destroy(t->dtls_dev) != NSS_DTLSMGR_OK) { + nss_capwapmgr_warn("%px: failed to destroy DTLS session", t->dtls_dev); + } + } +-fail4: +- nss_capwapmgr_unregister_with_nss(capwap_if_num_outer); +-fail3: +- (void)nss_dynamic_interface_dealloc_node(capwap_if_num_outer, NSS_DYNAMIC_INTERFACE_TYPE_CAPWAP_OUTER); +-fail2: +- nss_capwapmgr_unregister_with_nss(capwap_if_num_inner); +-fail1: +- (void)nss_dynamic_interface_dealloc_node(capwap_if_num_inner, NSS_DYNAMIC_INTERFACE_TYPE_CAPWAP_HOST_INNER); +- +-done: +- dev_put(dev); + return status; + } + +@@ -2819,7 +2659,7 @@ static void nss_capwapmgr_tunnel_save_st + save->rx_dup_frag += fstats->rx_dup_frag; + save->rx_oversize_drops += fstats->rx_oversize_drops; + save->rx_frag_timeout_drops += fstats->rx_frag_timeout_drops; +- save->rx_n2h_drops += fstats->rx_n2h_drops; ++ save->rx_queue_full_drops += fstats->rx_queue_full_drops; + save->rx_n2h_queue_full_drops += fstats->rx_n2h_queue_full_drops; + save->rx_mem_failure_drops += fstats->rx_mem_failure_drops; + save->rx_csum_drops += fstats->rx_csum_drops; +@@ -2857,21 +2697,18 @@ nss_capwapmgr_status_t nss_capwapmgr_tun + struct nss_capwapmgr_priv *priv; + struct nss_capwapmgr_tunnel *t; + nss_tx_status_t nss_status = NSS_TX_SUCCESS; +- uint32_t if_num_inner, if_num_outer; ++ uint32_t if_num; + nss_capwapmgr_status_t status = NSS_CAPWAPMGR_SUCCESS; + +- dev_hold(dev); + t = nss_capwapmgr_verify_tunnel_param(dev, tunnel_id); + if (!t) { + nss_capwapmgr_warn("%px: tunnel %d: wrong argument for tunnel destroy\n", dev, tunnel_id); +- status = NSS_CAPWAPMGR_FAILURE_BAD_PARAM; +- goto done; ++ return NSS_CAPWAPMGR_FAILURE_BAD_PARAM; + } + + if (!(t->tunnel_state & NSS_CAPWAPMGR_TUNNEL_STATE_CONFIGURED)) { + nss_capwapmgr_warn("%px: tunnel %d is not configured yet\n", dev, tunnel_id); +- status = NSS_CAPWAPMGR_FAILURE_TUNNEL_NOT_CFG; +- goto done; ++ return NSS_CAPWAPMGR_FAILURE_TUNNEL_NOT_CFG; + } + + /* +@@ -2879,49 +2716,34 @@ nss_capwapmgr_status_t nss_capwapmgr_tun + */ + if (t->tunnel_state & NSS_CAPWAPMGR_TUNNEL_STATE_ENABLED) { + nss_capwapmgr_warn("%px: no destroy alloed for an eanbled tunnel: %d\n", dev, tunnel_id); +- status = NSS_CAPWAPMGR_FAILURE_TUNNEL_ENABLED; +- goto done; ++ return NSS_CAPWAPMGR_FAILURE_TUNNEL_ENABLED; + } + + if (!(t->capwap_rule.l3_proto == NSS_CAPWAP_TUNNEL_IPV4 || + t->capwap_rule.l3_proto == NSS_CAPWAP_TUNNEL_IPV6)) { + nss_capwapmgr_warn("%px: tunnel %d: wrong argument for l3_proto\n", dev, tunnel_id); +- status = NSS_CAPWAPMGR_FAILURE_BAD_PARAM; +- goto done; ++ return NSS_CAPWAPMGR_FAILURE_BAD_PARAM; + } + + if (!(t->capwap_rule.which_udp == NSS_CAPWAP_TUNNEL_UDP || + t->capwap_rule.which_udp == NSS_CAPWAP_TUNNEL_UDPLite)) { + nss_capwapmgr_warn("%px: tunnel %d: wrong argument for which_udp(%d)\n", dev, tunnel_id, t->capwap_rule.which_udp); +- status = NSS_CAPWAPMGR_FAILURE_BAD_PARAM; +- goto done; ++ return NSS_CAPWAPMGR_FAILURE_BAD_PARAM; + } + ++ dev_hold(dev); + priv = netdev_priv(dev); +- nss_capwapmgr_info("%px: %d: tunnel destroy is being called\n", dev, tunnel_id); +- +- if_num_inner = t->if_num_inner; +- if_num_outer = t->if_num_outer; ++ nss_capwapmgr_info("%px: %d: tunnel destroy is being called\n", dev, t->if_num); ++ if_num = t->if_num; + +- if (priv->if_num_to_tunnel_id[if_num_inner] != tunnel_id) { ++ if (priv->if_num_to_tunnel_id[if_num] != tunnel_id) { + nss_capwapmgr_warn("%px: %d: tunnel_id %d didn't match with tunnel_id :%d\n", +- dev, if_num_inner, tunnel_id, priv->if_num_to_tunnel_id[if_num_inner]); +- status = NSS_CAPWAPMGR_FAILURE_BAD_PARAM; +- goto done; +- } +- +- if (priv->if_num_to_tunnel_id[if_num_outer] != tunnel_id) { +- nss_capwapmgr_warn("%px: %d: tunnel_id %d didn't match with tunnel_id :%d\n", +- dev, if_num_outer, tunnel_id, priv->if_num_to_tunnel_id[if_num_outer]); +- status = NSS_CAPWAPMGR_FAILURE_BAD_PARAM; +- goto done; +- } +- +- if (nss_capwap_get_stats(if_num_inner, &stats) == true) { +- nss_capwapmgr_tunnel_save_stats(&global.tunneld, &stats); ++ dev, if_num, tunnel_id, priv->if_num_to_tunnel_id[if_num]); ++ dev_put(dev); ++ return NSS_CAPWAPMGR_FAILURE_BAD_PARAM; + } + +- if (nss_capwap_get_stats(if_num_outer, &stats) == true) { ++ if (nss_capwap_get_stats(if_num, &stats) == true) { + nss_capwapmgr_tunnel_save_stats(&global.tunneld, &stats); + } + +@@ -2961,10 +2783,9 @@ nss_capwapmgr_status_t nss_capwapmgr_tun + } + + if (nss_status != NSS_TX_SUCCESS) { +- nss_capwapmgr_warn("%px: Unconfigure IP rule failed for tunnel : %d\n", +- dev, tunnel_id); +- status = NSS_CAPWAPMGR_FAILURE_IP_DESTROY_RULE; +- goto done; ++ nss_capwapmgr_warn("%px: %d: Unconfigure IP rule failed for tunnel : %d\n", ++ dev, if_num, tunnel_id); ++ return NSS_CAPWAPMGR_FAILURE_IP_DESTROY_RULE; + } + t->tunnel_state &= ~NSS_CAPWAPMGR_TUNNEL_STATE_IPRULE_CONFIGURED; + } +@@ -2972,45 +2793,36 @@ nss_capwapmgr_status_t nss_capwapmgr_tun + /* + * Destroy CAPWAP rule now. + */ +- status = nss_capwapmgr_tunnel_action(priv->nss_ctx, dev, if_num_outer, NSS_CAPWAP_MSG_TYPE_UNCFG_RULE); ++ status = nss_capwapmgr_tunnel_action(priv->nss_ctx, dev, if_num, NSS_CAPWAP_MSG_TYPE_UNCFG_RULE); + if (status != NSS_CAPWAPMGR_SUCCESS) { + nss_capwapmgr_warn("%px: %d: Unconfigure CAPWAP rule failed for tunnel : %d\n", +- dev, if_num_outer, tunnel_id); +- goto fail; +- +- } ++ dev, if_num, tunnel_id); + +- status = nss_capwapmgr_tunnel_action(priv->nss_ctx, dev, if_num_inner, NSS_CAPWAP_MSG_TYPE_UNCFG_RULE); +- if (status != NSS_CAPWAPMGR_SUCCESS) { +- nss_capwapmgr_warn("%px: %d: Unconfigure CAPWAP rule failed for tunnel : %d\n", +- dev, if_num_inner, tunnel_id); +- status = nss_capwapmgr_create_capwap_rule(dev, if_num_outer, &(t->capwap_rule), t->type_flags); +- if (status != NSS_CAPWAPMGR_SUCCESS) { +- nss_capwapmgr_warn("%px: %d: re creating the CAPWAP rule failed for tunnel : %d\n", +- dev, if_num_inner, tunnel_id); +- goto done; ++ if (t->capwap_rule.l3_proto == NSS_CAPWAP_TUNNEL_IPV4) { ++ nss_status = nss_capwapmgr_configure_ipv4(&t->ip_rule.v4, 0, 0); ++ if (nss_status == NSS_TX_SUCCESS) { ++ t->tunnel_state |= NSS_CAPWAPMGR_TUNNEL_STATE_IPRULE_CONFIGURED; + } + +- goto fail; ++ } else { ++ nss_status = nss_capwapmgr_configure_ipv6(&t->ip_rule.v6, 0, 0); ++ if (nss_status == NSS_TX_SUCCESS) { ++ t->tunnel_state |= NSS_CAPWAPMGR_TUNNEL_STATE_IPRULE_CONFIGURED; ++ } ++ } + ++ return NSS_CAPWAPMGR_FAILURE_CAPWAP_DESTROY_RULE; + } + +- nss_capwapmgr_unregister_with_nss(if_num_outer); +- nss_capwapmgr_unregister_with_nss(if_num_inner); ++ nss_capwapmgr_unregister_with_nss(if_num); + + /* + * Deallocate dynamic interface + */ +- nss_status = nss_dynamic_interface_dealloc_node(if_num_outer, NSS_DYNAMIC_INTERFACE_TYPE_CAPWAP_OUTER); +- if (nss_status != NSS_TX_SUCCESS) { +- nss_capwapmgr_warn("%px: %d: Dealloc of dynamic interface failed for tunnel : %d\n", +- dev, if_num_outer, tunnel_id); +- } +- +- nss_status = nss_dynamic_interface_dealloc_node(if_num_inner, NSS_DYNAMIC_INTERFACE_TYPE_CAPWAP_HOST_INNER); ++ nss_status = nss_dynamic_interface_dealloc_node(if_num, NSS_DYNAMIC_INTERFACE_TYPE_CAPWAP); + if (nss_status != NSS_TX_SUCCESS) { + nss_capwapmgr_warn("%px: %d: Dealloc of dynamic interface failed for tunnel : %d\n", +- dev, if_num_inner, tunnel_id); ++ dev, if_num, tunnel_id); + } + + /* +@@ -3020,9 +2832,8 @@ nss_capwapmgr_status_t nss_capwapmgr_tun + if (t->capwap_rule.enabled_features & NSS_CAPWAPMGR_FEATURE_DTLS_ENABLED) { + nss_status = nss_trustsec_tx_unconfigure_sgt(t->capwap_rule.dtls_inner_if_num, t->capwap_rule.outer_sgt_value); + } else { +- nss_status = nss_trustsec_tx_unconfigure_sgt(t->if_num_outer, t->capwap_rule.outer_sgt_value); ++ nss_status = nss_trustsec_tx_unconfigure_sgt(t->if_num, t->capwap_rule.outer_sgt_value); + } +- + if (nss_status != NSS_TX_SUCCESS) { + nss_capwapmgr_warn("%px: unconfigure trustsec_tx failed\n", dev); + } +@@ -3037,35 +2848,14 @@ nss_capwapmgr_status_t nss_capwapmgr_tun + } + } + ++ t->if_num = 0; + t->tunnel_state &= ~NSS_CAPWAPMGR_TUNNEL_STATE_CONFIGURED; +- priv->if_num_to_tunnel_id[if_num_inner] = -1; +- priv->if_num_to_tunnel_id[if_num_outer] = -1; +- ++ priv->if_num_to_tunnel_id[if_num] = 0; + memset(t, 0, sizeof(struct nss_capwapmgr_tunnel)); + +- t->if_num_inner = -1; +- t->if_num_outer = -1; +- +- nss_capwapmgr_info("%px: Tunnel %d is completely destroyed\n", dev , tunnel_id); +- status = NSS_CAPWAPMGR_SUCCESS; +- goto done; +- +-fail: +- if (t->capwap_rule.l3_proto == NSS_CAPWAP_TUNNEL_IPV4) { +- nss_status = nss_capwapmgr_configure_ipv4(&t->ip_rule.v4, 0, 0); +- } else { +- nss_status = nss_capwapmgr_configure_ipv6(&t->ip_rule.v6, 0, 0); +- } +- +- if (nss_status == NSS_TX_SUCCESS) { +- t->tunnel_state |= NSS_CAPWAPMGR_TUNNEL_STATE_IPRULE_CONFIGURED; +- } +- +- status = NSS_CAPWAPMGR_FAILURE_CAPWAP_DESTROY_RULE; +- +-done: ++ nss_capwapmgr_info("%px: %d: Tunnel %d is completely destroyed\n", dev, if_num, tunnel_id); + dev_put(dev); +- return status; ++ return NSS_CAPWAPMGR_SUCCESS; + } + EXPORT_SYMBOL(nss_capwapmgr_tunnel_destroy); + +@@ -3083,18 +2873,17 @@ static inline nss_capwapmgr_status_t nss + struct nss_capwapmgr_tunnel *t; + nss_capwapmgr_status_t status; + +- dev_hold(dev); + t = nss_capwapmgr_verify_tunnel_param(dev, tunnel_id); + if (!t) { + nss_capwapmgr_warn("%px: can't find tunnel: %d\n", dev, tunnel_id); +- status = NSS_CAPWAPMGR_FAILURE_BAD_PARAM; +- goto done; ++ return NSS_CAPWAPMGR_FAILURE_BAD_PARAM; + } + ++ dev_hold(dev); + priv = netdev_priv(dev); + + memset(&capwapmsg, 0, sizeof(struct nss_capwap_msg)); +- nss_capwap_msg_init(&capwapmsg, t->if_num_outer, cmd, ++ nss_capwap_msg_init(&capwapmsg, t->if_num, cmd, + sizeof(struct nss_capwap_flow_rule_msg), nss_capwapmgr_msg_event_receive, dev); + + /* +@@ -3121,7 +2910,6 @@ static inline nss_capwapmgr_status_t nss + nss_capwapmgr_warn("%px: send flow rule message failed with error: %d\n", dev, status); + } + +-done: + dev_put(dev); + return status; + } +@@ -3160,85 +2948,29 @@ nss_capwapmgr_status_t nss_capwapmgr_tun + uint8_t tunnel_id, struct nss_capwap_tunnel_stats *stats) + { + struct nss_capwapmgr_tunnel *t; +- struct nss_capwap_tunnel_stats stats_temp; +- nss_capwapmgr_status_t status = NSS_CAPWAPMGR_SUCCESS; + + if (!stats) { + nss_capwapmgr_warn("%px: invalid rtnl structure\n", dev); + return NSS_CAPWAPMGR_FAILURE_BAD_PARAM; + } + +- dev_hold(dev); + t = nss_capwapmgr_verify_tunnel_param(dev, tunnel_id); + if (!t) { + nss_capwapmgr_trace("%px: can't find tunnel: %d\n", dev, tunnel_id); +- status = NSS_CAPWAPMGR_FAILURE_BAD_PARAM; +- goto done; ++ return NSS_CAPWAPMGR_FAILURE_BAD_PARAM; + } + + if (!(t->tunnel_state & NSS_CAPWAPMGR_TUNNEL_STATE_CONFIGURED)) { + nss_capwapmgr_trace("%px: tunnel: %d not configured yet\n", dev, tunnel_id); +- status = NSS_CAPWAPMGR_FAILURE_TUNNEL_NOT_CFG; +- goto done; ++ return NSS_CAPWAPMGR_FAILURE_TUNNEL_NOT_CFG; + } + +- /* +- * Copy the inner interface stats. +- */ +- if (nss_capwap_get_stats(t->if_num_inner, &stats_temp) == false) { ++ if (nss_capwap_get_stats(t->if_num, stats) == false) { + nss_capwapmgr_warn("%px: tunnel %d not ready yet\n", dev, tunnel_id); +- status = NSS_CAPWAPMGR_FAILURE_NOT_READY; +- goto done; ++ return NSS_CAPWAPMGR_FAILURE_NOT_READY; + } + +- stats->dtls_pkts += stats_temp.dtls_pkts; +- stats->tx_segments += stats_temp.tx_segments; +- stats->tx_queue_full_drops += stats_temp.tx_queue_full_drops; +- stats->tx_mem_failure_drops += stats_temp.tx_mem_failure_drops; +- stats->tx_dropped_sg_ref += stats_temp.tx_dropped_sg_ref; +- stats->tx_dropped_ver_mis += stats_temp.tx_dropped_ver_mis; +- stats->tx_dropped_hroom += stats_temp.tx_dropped_hroom; +- stats->tx_dropped_dtls += stats_temp.tx_dropped_dtls; +- stats->tx_dropped_nwireless += stats_temp.tx_dropped_nwireless; +- +- /* +- * Pnode tx stats for Inner node. +- */ +- stats->pnode_stats.tx_packets += stats_temp.pnode_stats.tx_packets; +- stats->pnode_stats.tx_bytes += stats_temp.pnode_stats.tx_bytes; +- stats->tx_dropped_inner += stats_temp.tx_dropped_inner; +- +- /* +- * Copy the outer interface stats. +- */ +- if (nss_capwap_get_stats(t->if_num_outer, &stats_temp) == false) { +- nss_capwapmgr_warn("%px: tunnel %d not ready yet\n", dev, tunnel_id); +- status = NSS_CAPWAPMGR_FAILURE_NOT_READY; +- goto done; +- } +- +- stats->rx_segments += stats_temp.rx_segments; +- stats->dtls_pkts += stats_temp.dtls_pkts; +- stats->rx_dup_frag += stats_temp.rx_dup_frag; +- stats->rx_oversize_drops += stats_temp.rx_oversize_drops; +- stats->rx_frag_timeout_drops += stats_temp.rx_frag_timeout_drops; +- stats->rx_n2h_drops += stats_temp.rx_n2h_drops; +- stats->rx_n2h_queue_full_drops += stats_temp.rx_n2h_queue_full_drops; +- stats->rx_mem_failure_drops += stats_temp.rx_mem_failure_drops; +- stats->rx_csum_drops += stats_temp.rx_csum_drops; +- stats->rx_malformed += stats_temp.rx_malformed; +- stats->rx_frag_gap_drops += stats_temp.rx_frag_gap_drops; +- +- /* +- * Pnode rx stats for outer node. +- */ +- stats->pnode_stats.rx_packets += stats_temp.pnode_stats.rx_packets; +- stats->pnode_stats.rx_bytes += stats_temp.pnode_stats.rx_bytes; +- stats->pnode_stats.rx_dropped += stats_temp.pnode_stats.rx_dropped; +- +-done: +- dev_put(dev); +- return status; ++ return NSS_CAPWAPMGR_SUCCESS; + } + EXPORT_SYMBOL(nss_capwapmgr_tunnel_stats); + +@@ -3341,7 +3073,10 @@ EXPORT_SYMBOL(nss_capwapmgr_get_netdev); + */ + static int nss_capwapmgr_netdev_up(struct net_device *netdev) + { ++ struct nss_capwapmgr_priv *priv; + uint8_t i; ++ ++ priv = netdev_priv(netdev); + for (i = 0; i < NSS_CAPWAPMGR_MAX_TUNNELS; i++) { + (void)nss_capwapmgr_enable_tunnel(nss_capwapmgr_ndev, i); + } +@@ -3355,7 +3090,10 @@ static int nss_capwapmgr_netdev_up(struc + */ + static int nss_capwapmgr_netdev_down(struct net_device *netdev) + { ++ struct nss_capwapmgr_priv *priv; + uint8_t i; ++ ++ priv = netdev_priv(netdev); + for (i = 0; i < NSS_CAPWAPMGR_MAX_TUNNELS; i++) { + (void)nss_capwapmgr_disable_tunnel(nss_capwapmgr_ndev, i); + } +@@ -3367,7 +3105,7 @@ static int nss_capwapmgr_netdev_down(str + * nss_capwapmgr_netdev_event() + * Net device notifier for NSS CAPWAP manager module + */ +-static int nss_capwapmgr_netdev_event(struct notifier_block *nb, unsigned long event, void *dev) ++static int nss_capwapmgr_netdev_event(struct notifier_block *nb, unsigned long event, void *dev) + { + struct net_device *netdev = (struct net_device *)dev; + +--- a/clmapmgr/nss_clmapmgr.c ++++ b/clmapmgr/nss_clmapmgr.c +@@ -84,17 +84,16 @@ fail: + } + + /* +- * nss_clmapmgr_get_dev_stats64() ++ * nss_clmapmgr_dev_stats64() + * Netdev ops function to retrieve stats. + */ +-static struct rtnl_link_stats64 *nss_clmapmgr_get_dev_stats64(struct net_device *dev, ++void nss_clmapmgr_dev_stats64(struct net_device *dev, + struct rtnl_link_stats64 *stats) + { + struct nss_clmapmgr_priv_t *priv; + + if (!stats) { + nss_clmapmgr_warning("%px: invalid rtnl structure\n", dev); +- return stats; + } + + dev_hold(dev); +@@ -109,30 +108,7 @@ static struct rtnl_link_stats64 *nss_clm + memcpy(stats, &priv->stats, sizeof(struct rtnl_link_stats64)); + dev_put(dev); + +- return stats; +-} +- +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0)) +-/* +- * nss_clmapmgr_dev_stats64() +- * Netdev ops function to retrieve stats for kernel version < 4.6 +- */ +-static struct rtnl_link_stats64 *nss_clmapmgr_dev_stats64(struct net_device *dev, +- struct rtnl_link_stats64 *tot) +-{ +- return nss_clmapmgr_get_dev_stats64(dev, tot); +-} +-#else +-/* +- * nss_clmapmgr_dev_stats64() +- * Netdev ops function to retrieve stats for kernel version >= 4.6 +- */ +-static void nss_clmapmgr_dev_stats64(struct net_device *dev, +- struct rtnl_link_stats64 *tot) +-{ +- nss_clmapmgr_get_dev_stats64(dev, tot); + } +-#endif + + /* + * nss_clmapmgr_dev_init() +--- a/dtls/v1.0/nss_connmgr_dtls_netdev.c ++++ b/dtls/v1.0/nss_connmgr_dtls_netdev.c +@@ -160,7 +160,7 @@ static void nss_dtlsmgr_dev_setup(struct + dev->ethtool_ops = NULL; + dev->header_ops = NULL; + dev->netdev_ops = &nss_dtlsmgr_session_ops; +- dev->destructor = NULL; ++ dev->priv_destructor = NULL; + + memcpy(dev->dev_addr, "\xaa\xbb\xcc\xdd\xee\xff", dev->addr_len); + memset(dev->broadcast, 0xff, dev->addr_len); +--- a/dtls/v2.0/Makefile ++++ b/dtls/v2.0/Makefile +@@ -3,7 +3,7 @@ + ccflags-y += $(NSS_CCFLAGS) -I$(obj)/../../exports + ccflags-y += -DNSS_DTLSMGR_DEBUG_LEVEL=0 + ccflags-y += -DNSS_DTLSMGR_BUILD_ID=\"'Build_ID - $(shell date +'%m/%d/%y, %H:%M:%S') SoC=$(SoC)'\" +-ccflags-y += -Wall -Werror ++ccflags-y += -Werror + + obj-m += qca-nss-dtlsmgr.o + qca-nss-dtlsmgr-objs += nss_dtlsmgr.o +--- a/dtls/v2.0/nss_dtlsmgr_ctx.c ++++ b/dtls/v2.0/nss_dtlsmgr_ctx.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -627,7 +627,7 @@ struct net_device *nss_dtlsmgr_session_c + * so that the skb data pointer remains 4 byte aligned when the + * headroom/tailroom is adjusted. + */ +- dev->needed_headroom = ALIGN(ctx->encap.headroom, 4); ++ dev->needed_headroom = ALIGN(ctx->encap.headroom + NSS_DTLSMGR_EDMA_PRE_HDR_SZ, 4); + dev->needed_tailroom = ALIGN(ctx->encap.tailroom, 4); + + ctx->app_data = cfg->app_data; +@@ -643,7 +643,7 @@ struct net_device *nss_dtlsmgr_session_c + ctx->app_data = ctx; + } + +- error = register_netdev(dev); ++ error = rtnl_is_locked() ? register_netdevice(dev) : register_netdev(dev); + if (error < 0) { + nss_dtlsmgr_warn("%px: unable register net_device(%s)", ctx, dev->name); + goto destroy_decap; +@@ -708,7 +708,7 @@ nss_dtlsmgr_status_t nss_dtlsmgr_session + + NSS_DTLSMGR_SET_MAGIC(ctx, 0); + +- unregister_netdev(dev); ++ rtnl_is_locked() ? unregister_netdevice(dev) : unregister_netdev(dev); + + return NSS_DTLSMGR_OK; + } +--- a/dtls/v2.0/nss_dtlsmgr_ctx_dev.c ++++ b/dtls/v2.0/nss_dtlsmgr_ctx_dev.c +@@ -349,7 +349,7 @@ static netdev_tx_t nss_dtlsmgr_ctx_dev_t + stats = &encap->stats; + + nhead = dev->needed_headroom; +- ntail = dev->needed_tailroom + nhead; /* Firmware uses tailroom for header add */ ++ ntail = dev->needed_tailroom; + + /* + * Check if skb is shared; unshare in case it is shared +--- a/eogremgr/nss_eogremgr.c ++++ b/eogremgr/nss_eogremgr.c +@@ -19,10 +19,10 @@ + * NSS EOGRE manager + */ + ++#include + #include + #include + #include "nss_connmgr_gre_public.h" +-#include + #include "nss_eogremgr.h" + #include "nss_eogremgr_priv.h" + +@@ -565,15 +565,12 @@ static void __exit nss_eogremgr_exit_mod + */ + static int __init nss_eogremgr_init_module(void) + { +- +-#ifdef CONFIG_OF + /* + * If the node is not compatible, don't do anything. + */ + if (!of_find_node_by_name(NULL, "nss-common")) { + return 0; + } +-#endif + + nss_eogremgr_info("module %s loaded\n", NSS_CLIENT_BUILD_ID); + +--- a/exports/nss_capwapmgr.h ++++ b/exports/nss_capwapmgr.h +@@ -61,10 +61,8 @@ struct nss_capwapmgr_response { + */ + struct nss_capwapmgr_tunnel { + struct net_device *dtls_dev; /**< DTLS netdevice */ +- uint32_t if_num_inner; /**< Interface number of the INNER CAPWAP node */ +- uint32_t if_num_outer; /**< Interface number of the OUTER CAPWAP node */ ++ uint32_t if_num; /**< Interface number of NSS */ + uint32_t tunnel_state; /**< Tunnel state */ +- uint16_t type_flags; /**< Tunnel Type to determine header size */ + union { + struct nss_ipv4_create v4; /**< IPv4 rule structure */ + struct nss_ipv6_create v6; /**< IPv6 rule struture */ +@@ -224,7 +222,7 @@ nss_capwapmgr_status_t nss_capwapmgr_upd + * + * @return nss_capwapmgr_status_t + */ +-extern nss_capwapmgr_status_t nss_capwapmgr_update_src_interface(struct net_device *dev, uint8_t tunnel_id, uint32_t src_interface_num); ++extern nss_capwapmgr_status_t nss_capwapmgr_update_src_interface(struct net_device *dev, uint8_t tunnel_id, int32_t src_interface_num); + + /** + * @brief Delete a DSCP prioritization rule that was created. +--- a/exports/nss_dtlsmgr.h ++++ b/exports/nss_dtlsmgr.h +@@ -60,12 +60,6 @@ + #define NSS_DTLSMGR_METADATA_FLAG_SEQ 0x0002 /**< Metadata has a valid sequence no. */ + #define NSS_DTLSMGR_METADATA_FLAG_CTYPE 0x0004 /**< Metadata has a valid DTLS content type */ + +-/* +- * NSS DTLS manager reserved size of header +- */ +-#define NSS_DTLSMGR_NEEDED_HEADROOM_SZ 128 +-#define NSS_DTLSMGR_NEEDED_TAILROOM_SZ 128 +- + /** + * NSS DTLS manager status + */ +@@ -134,7 +128,7 @@ enum nss_dtlsmgr_metadata_result { + * NSS DTLS manager cryptographic structure to represent key and its length. + */ + struct nss_dtlsmgr_crypto_data { +- const uint8_t *data; /**< Pointer to key or nonce. */ ++ uint8_t *data; /**< Pointer to key or nonce. */ + uint16_t len; /**< Length of the key. */ + }; + +--- a/exports/nss_ipsecmgr.h ++++ b/exports/nss_ipsecmgr.h +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2014-2019, 2021 The Linux Foundation. All rights reserved. ++ * Copyright (c) 2014-2019, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -252,10 +252,7 @@ struct nss_ipsecmgr_sa_stats { + uint32_t pkt_count; /**< Number of packets processed. */ + uint32_t pkt_failed; /**< Number of packets failed in processing. */ + uint16_t window_size; /**< Current size of the window. */ +- uint16_t replay_fail_alarm; /**< Alarm for consecutive hash fail. */ +- uint32_t fail_replay_win; /**< Failure in anti-replay; packet outside the window */ +- uint32_t fail_replay_dup; /**< Failure in anti-replay; duplicate records */ +- uint32_t fail_auth; /**< Failure in authenticating the data */ ++ bool replay_fail_alarm; /**< Alarm for consecutive hash fail. */ + }; + + /** +@@ -270,20 +267,6 @@ struct nss_ipsecmgr_event { + }; + + /** +- * nss_ipsecmgr_sa_info +- * Crypto information for an already created SA. +- */ +-struct nss_ipsecmgr_sa_info { +- uint16_t session_idx; /**< Crypto Session index */ +- uint16_t hdr_len; /**< Encap header length */ +- uint16_t trailer_len; /**< Encap Trailer length */ +- uint8_t blk_len; /**< Cipher Block length */ +- uint8_t iv_len; /**< Cipher IV lengh */ +- uint8_t hash_len; /**< Hash lengh */ +- uint8_t res[3]; /**< Reserved */ +-}; +- +-/** + * nss_ipsecmgr_sa_cmn_init_keys + * Fill and initialize common information for SA creation with crypto keys. + * +@@ -392,20 +375,6 @@ static inline bool nss_ipsecmgr_sa_cmn_i + return true; + } + +-/** +- * nss_ipsecmgr_sa_set_transport +- * Enable transport mode for an SA thats is getting initialized. +- * +- * @datatypes +- * nss_ipsecmgr_sa_cmn \n +- * +- * @param[in/out] cmn Pointer to the common IPsec manager SA configuration information. +- */ +-static inline void nss_ipsecmgr_sa_set_transport(struct nss_ipsecmgr_sa_cmn *cmn) +-{ +- cmn->transport_mode = true; +-} +- + #ifdef __KERNEL__ /* only kernel will use. */ + + /** +@@ -439,7 +408,6 @@ struct nss_ipsecmgr_callback { + struct net_device *skb_dev; /**< Net device to use for Socket Buffer. */ + nss_ipsecmgr_data_callback_t data_cb; /**< Data callback function. */ + nss_ipsecmgr_event_callback_t event_cb; /**< Event callback function. */ +- nss_ipsecmgr_data_callback_t except_cb; /**< Outer exception callback function. */ + }; + + /** +@@ -654,35 +622,5 @@ nss_ipsecmgr_status_t nss_ipsecmgr_sa_tx + nss_ipsecmgr_status_t nss_ipsecmgr_sa_tx_outer(struct net_device *tun, struct nss_ipsecmgr_sa_tuple *sa, + struct sk_buff *skb); + +-/* +- * nss_ipsecmgr_cra_name2algo() +- * Get ipsecmgr algo from cra name. +- * +- * @param[in] cra_name Name of the crypto algo. +- * +- * @return +- * nss_ipsecmgr_algo +- */ +-enum nss_ipsecmgr_algo nss_ipsecmgr_cra_name2algo(const char *cra_name); +- +-/* +- * nss_ipsecmgr_sa_get_info() +- * Get Crypto information for an already created SA. +- * +- * @datatypes +- * net_device \n +- * nss_ipsecmgr_sa_tuple \n +- * nss_ipsecmgr_sa_info +- * +- * @param[in] tun Pointer to the network device associated with the tunnel. +- * @param[in] sa Pointer to the SA tuple for which info is to be retrieved. +- * @param[out] info Pointer to the SA info to fill. +- * +- * @return +- * Success or failure. +- */ +-bool nss_ipsecmgr_sa_get_info(struct net_device *tun, struct nss_ipsecmgr_sa_tuple *sa, +- struct nss_ipsecmgr_sa_info *info); +- + #endif /* __KERNEL__ */ + #endif /* __NSS_IPSECMGR_H */ +--- a/exports/nss_l2tpmgr.h ++++ b/exports/nss_l2tpmgr.h +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2019, 2021 The Linux Foundation. All rights reserved. ++ * Copyright (c) 2019 The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -16,25 +16,22 @@ + #ifndef __NSS_L2TPMGR_H__ + #define __NSS_L2TPMGR_H__ + +-typedef int32_t (*get_ipsec_ifnum_by_dev_callback_t)(struct net_device *); +-typedef int32_t (*get_ipsec_ifnum_by_ip_addr_callback_t)(uint8_t ipversion, uint32_t *src_ip, uint32_t *dest_ip); ++typedef struct net_device *(*get_ipsec_tundev_callback_t)(struct net_device *dev); + + /** + * l2tpmgr_ipsecmgr_cb +- * Callback to get the dummy IPSec interface number that was used to register with NSS +- * by the IPSec manager when given the IPSec Linux dev. +- * get_ifnum_by_dev: passes net_device ptr to get associated IPsec if_num in KLIPS +- * get_ifnum_by_ip_addr: passes IPv4 src & dest addr in Big-endian form to get IPsec if_num in XFRM ++ * Callback to get the dummy IPSec netdev that was ++ * used to register with NSS by the IPSec manager ++ * when given the IPSec Linux dev. + */ + struct l2tpmgr_ipsecmgr_cb { +- get_ipsec_ifnum_by_dev_callback_t get_ifnum_by_dev; +- get_ipsec_ifnum_by_ip_addr_callback_t get_ifnum_by_ip_addr; ++ get_ipsec_tundev_callback_t cb; ++ /**< IPSec mgr Callback> */ + }; + +-#if defined(NSS_L2TP_IPSEC_BIND_BY_NETDEV) + /** +- * l2tpmgr_register_ipsecmgr_callback_by_netdev +- * Register IPSecmgr callback function with l2tpmgr by netdev for KLIPS. ++ * l2tpmgr_register_ipsecmgr_callback ++ * Register IPSecmgr callback function with l2tpmgr. + * + * @datatypes + * l2tpmgr_ipsecmgr_cb \n +@@ -44,38 +41,15 @@ struct l2tpmgr_ipsecmgr_cb { + * @return + * none + */ +-void l2tpmgr_register_ipsecmgr_callback_by_netdev(struct l2tpmgr_ipsecmgr_cb *cb); ++void l2tpmgr_register_ipsecmgr_callback(struct l2tpmgr_ipsecmgr_cb *cb); + + /** + * l2tpmgr_unregister_ipsecmgr_callback +- * Unregister IPSecmgr callback function with l2tpmgr by netdev for KLIPS. ++ * Unregister IPSecmgr callback function with l2tpmgr. + * + * @return + * none + */ +-void l2tpmgr_unregister_ipsecmgr_callback_by_netdev(void); +-#endif ++void l2tpmgr_unregister_ipsecmgr_callback(void); + +-/** +- * l2tpmgr_register_ipsecmgr_callback_by_ipaddr +- * Register IPSecmgr callback function with l2tpmgr by IP address for XFRM. +- * +- * @datatypes +- * l2tpmgr_ipsecmgr_cb \n +- * +- * @param[in] cb IPSecmgr callback function to be registered with l2tpmgr. +- * +- * @return +- * none +- */ +-void l2tpmgr_register_ipsecmgr_callback_by_ipaddr(struct l2tpmgr_ipsecmgr_cb *cb); +- +-/** +- * l2tpmgr_unregister_ipsecmgr_callback_by_ipaddr +- * Unregister IPSecmgr callback function with l2tpmgr by IP address for XFRM. +- * +- * @return +- * none +- */ +-void l2tpmgr_unregister_ipsecmgr_callback_by_ipaddr(void); + #endif +--- a/gre/Makefile ++++ b/gre/Makefile +@@ -1,7 +1,7 @@ + # Makefile for gre client + ccflags-y += -I$(obj)/../../exports -I$(obj)/../.. + ccflags-y += -DNSS_GRE_DEBUG_LEVEL=0 +-ccflags-y += -Wall -Werror ++ccflags-y += -Werror + obj-m += qca-nss-gre.o + qca-nss-gre-objs := nss_connmgr_gre.o nss_connmgr_gre_v4.o nss_connmgr_gre_v6.o + +--- a/gre/nss_connmgr_gre_v4.c ++++ b/gre/nss_connmgr_gre_v4.c +@@ -98,12 +98,9 @@ static int nss_connmgr_gre_v4_get_mac_ad + neigh = neigh_lookup(&arp_tbl, (const void *)&raddr, rt->dst.dev); + } + +- if (neigh) { +- if (!(neigh->nud_state & NUD_VALID) || !is_valid_ether_addr(neigh->ha)) { +- nss_connmgr_gre_info("neigh lookup failed for %pI4, state=%x, neigh->ha=%pM\n", &raddr, neigh->nud_state, neigh->ha); +- neigh_release(neigh); +- neigh = NULL; +- } ++ if (neigh && !is_valid_ether_addr(neigh->ha)) { ++ neigh_release(neigh); ++ neigh = NULL; + } + + /* +@@ -122,13 +119,6 @@ static int nss_connmgr_gre_v4_get_mac_ad + msleep(2000); + } + +- if (!(neigh->nud_state & NUD_VALID) || !is_valid_ether_addr(neigh->ha)) { +- ip_rt_put(rt); +- nss_connmgr_gre_warning("invalid neigh state (%x) or invalid MAC(%pM) for %pI4\n", neigh->nud_state, neigh->ha, &raddr); +- neigh_release(neigh); +- return GRE_ERR_NEIGH_CREATE; +- } +- + if (neigh->dev->type == ARPHRD_LOOPBACK) { + ip_rt_put(rt); + neigh_release(neigh); +@@ -172,14 +162,6 @@ int nss_connmgr_gre_v4_set_config(struct + } + } + +- /* +- * IP address validate +- */ +- if ((cfg->src_ip == 0) || (cfg->dest_ip == 0)) { +- nss_connmgr_gre_warning("Source ip/Destination IP is invalid"); +- return GRE_ERR_INVALID_IP; +- } +- + memset(t, 0, sizeof(struct ip_tunnel)); + + priv->pad_len = (cfg->add_padding) ? GRE_HDR_PAD_LEN : 0; +--- a/gre/nss_connmgr_gre_v6.c ++++ b/gre/nss_connmgr_gre_v6.c +@@ -95,7 +95,8 @@ static int nss_connmgr_gre_v6_get_mac_ad + /* + * Find src MAC address + */ +- local_dev = (struct net_device *)ipv6_dev_find(&init_net, &src_addr, 1); ++ local_dev = NULL; ++ local_dev = (struct net_device *)ipv6_dev_find(&init_net, &src_addr, local_dev); + if (!local_dev) { + nss_connmgr_gre_warning("Unable to find local dev for %pI6", src_ip); + return GRE_ERR_NO_LOCAL_NETDEV; +@@ -106,7 +107,6 @@ static int nss_connmgr_gre_v6_get_mac_ad + /* + * Find dest MAC address + */ +- + rt = nss_connmgr_gre_v6_route_lookup(&init_net, &dst_addr); + if (!rt) { + nss_connmgr_gre_warning("Unable to find route lookup for %pI6", dest_ip); +@@ -118,12 +118,9 @@ static int nss_connmgr_gre_v6_get_mac_ad + #else + neigh = rt->dst.ops->neigh_lookup(&rt->dst, NULL, &dst_addr); + #endif +- if (neigh) { +- if (!(neigh->nud_state & NUD_VALID) || !is_valid_ether_addr(neigh->ha)) { +- nss_connmgr_gre_warning("neigh state is either invalid (%x) or mac address is null (%pM) for %pI6", neigh->nud_state, neigh->ha, dest_ip); +- neigh_release(neigh); +- neigh = NULL; +- } ++ if (neigh && !is_valid_ether_addr(neigh->ha)) { ++ neigh_release(neigh); ++ neigh = NULL; + } + + if (!neigh) { +@@ -143,8 +140,7 @@ static int nss_connmgr_gre_v6_get_mac_ad + * Release hold on existing route entry, and find the route entry again + */ + ip6_rt_put(rt); +- +- rt = nss_connmgr_gre_v6_route_lookup(&init_net, &dst_addr); ++ rt = rt6_lookup(&init_net, &dst_addr, NULL, 0, NULL, 0); + if (!rt) { + nss_connmgr_gre_warning("Unable to find route lookup for %pI6\n", dest_ip); + return GRE_ERR_NEIGH_LOOKUP; +@@ -155,19 +151,11 @@ static int nss_connmgr_gre_v6_get_mac_ad + #else + neigh = rt->dst.ops->neigh_lookup(&rt->dst, NULL, &dst_addr); + #endif +- +- if (!neigh) { ++ if (!neigh || !is_valid_ether_addr(neigh->ha)) { + ip6_rt_put(rt); + nss_connmgr_gre_warning("Err in MAC address, neighbour look up failed\n"); + return GRE_ERR_NEIGH_LOOKUP; + } +- +- if (!(neigh->nud_state & NUD_VALID) || !is_valid_ether_addr(neigh->ha)) { +- ip6_rt_put(rt); +- nss_connmgr_gre_warning("Err in MAC address, invalid neigh state (%x) or invalid mac(%pM)\n", neigh->nud_state, neigh->ha); +- neigh_release(neigh); +- return GRE_ERR_NEIGH_LOOKUP; +- } + } + + ether_addr_copy(dest_mac, neigh->ha); +--- a/gre/test/Makefile ++++ b/gre/test/Makefile +@@ -1,6 +1,6 @@ + # Makefile for custom gre test module + ccflags-y += -I$(obj)/../../../exports -I$(obj)/../../.. -I$(obj)/../ + ccflags-y += -DNSS_GRE_DEBUG_LEVEL=0 +-ccflags-y += -Wall -Werror ++ccflags-y += -Werror + obj-m += qca-nss-gre-test.o + qca-nss-gre-test-objs := nss_connmgr_gre_test.o +--- a/gre/test/nss_connmgr_gre_test.c ++++ b/gre/test/nss_connmgr_gre_test.c +@@ -229,10 +229,12 @@ static int nss_connmgr_gre_test_open_pro + /* + * Proc ops + */ +-static const struct file_operations nss_connmgr_gre_test_proc_ops = { +- .open = nss_connmgr_gre_test_open_proc, +- .write = nss_connmgr_gre_test_write_proc, +- .read = seq_read, ++static const struct proc_ops nss_connmgr_gre_test_proc_ops = { ++ .proc_open = nss_connmgr_gre_test_open_proc, ++ .proc_read = seq_read, ++ .proc_lseek = seq_lseek, ++ .proc_release = single_release, ++ .proc_write = nss_connmgr_gre_test_write_proc, + }; + + /* +--- a/ipsecmgr/v1.0/Makefile ++++ b/ipsecmgr/v1.0/Makefile +@@ -2,7 +2,7 @@ + + ccflags-y := -I$(obj) -I$(obj)/../.. + ccflags-y += -DNSS_CLIENT_BUILD_ID="$(BUILD_ID)" +-ccflags-y += -Wall -Werror ++ccflags-y += -Werror + ifeq ($(SoC), fsm9010) + ccflags-y += -DNSS_IPSECMGR_PMTU_SUPPORT + endif +--- a/ipsecmgr/v1.0/nss_ipsecmgr.c ++++ b/ipsecmgr/v1.0/nss_ipsecmgr.c +@@ -377,7 +377,7 @@ free: + * nss_ipsecmgr_tunnel_stats() + * get tunnel statistics + */ +-static struct rtnl_link_stats64 *nss_ipsecmgr_tunnel_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) ++void nss_ipsecmgr_tunnel_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) + { + struct nss_ipsecmgr_priv *priv = netdev_priv(dev); + +@@ -389,8 +389,6 @@ static struct rtnl_link_stats64 *nss_ips + read_lock_bh(&ipsecmgr_ctx->lock); + memcpy(stats, &priv->stats, sizeof(struct rtnl_link_stats64)); + read_unlock_bh(&ipsecmgr_ctx->lock); +- +- return stats; + } + + /* +@@ -442,7 +440,7 @@ static void nss_ipsecmgr_tunnel_setup(st + dev->header_ops = NULL; + dev->netdev_ops = &nss_ipsecmgr_tunnel_ops; + +- dev->destructor = nss_ipsecmgr_tunnel_free; ++ dev->priv_destructor = nss_ipsecmgr_tunnel_free; + + /* + * get the MAC address from the ethernet device +--- a/ipsecmgr/v2.0/Makefile ++++ b/ipsecmgr/v2.0/Makefile +@@ -2,7 +2,7 @@ + + ccflags-y += $(NSS_CCFLAGS) -I$(obj)/../../exports + ccflags-y += -DNSS_CLIENT_BUILD_ID="$(BUILD_ID)" +-ccflags-y += -Wall -Werror ++ccflags-y += -Werror + + obj-m += qca-nss-ipsecmgr.o + qca-nss-ipsecmgr-objs := nss_ipsecmgr.o +--- a/ipsecmgr/v2.0/nss_ipsecmgr.c ++++ b/ipsecmgr/v2.0/nss_ipsecmgr.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -67,15 +67,6 @@ struct nss_ipsecmgr_drv *ipsecmgr_drv; + static const struct net_device_ops nss_ipsecmgr_dummy_ndev_ops; + + /* +- * nss_ipsecmgr_dummy_free() +- * Setup function for dummy netdevice. +- */ +-static void nss_ipsecmgr_dummy_free(struct net_device *dev) +-{ +- free_netdev(dev); +-} +- +-/* + * nss_ipsecmgr_dummy_setup() + * Setup function for dummy netdevice. + */ +@@ -86,11 +77,6 @@ static void nss_ipsecmgr_dummy_setup(str + * transform. + */ + dev->mtu = ETH_DATA_LEN; +-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(4, 11, 8)) +- dev->destructor = nss_ipsecmgr_dummy_free; +-#else +- dev->priv_destructor = nss_ipsecmgr_dummy_free; +-#endif + } + + /* +@@ -110,9 +96,12 @@ static void nss_ipsecmgr_rx_notify(void + static void nss_ipsecmgr_configure(struct work_struct *work) + { + enum nss_ipsec_cmn_msg_type type = NSS_IPSEC_CMN_MSG_TYPE_NODE_CONFIG; ++ struct nss_ipsecmgr_tunnel *tun = netdev_priv(ipsecmgr_drv->dev); + uint32_t ifnum = ipsecmgr_drv->ifnum; + struct nss_ipsec_cmn_msg nicm = {0}; ++ struct nss_ipsecmgr_ctx *redir; + nss_tx_status_t status; ++ uint32_t vsi_num = 0; + + /* + * By making sure that cryptoapi is registered, +@@ -150,10 +139,6 @@ static void nss_ipsecmgr_configure(struc + if (ipsecmgr_drv->ipsec_inline) { + + #ifdef NSS_IPSECMGR_PPE_SUPPORT +- struct nss_ipsecmgr_tunnel *tun = netdev_priv(ipsecmgr_drv->dev); +- struct nss_ipsecmgr_ctx *redir; +- uint32_t vsi_num = 0; +- + redir = nss_ipsecmgr_ctx_alloc(tun, + NSS_IPSEC_CMN_CTX_TYPE_REDIR, + NSS_DYNAMIC_INTERFACE_TYPE_IPSEC_CMN_REDIRECT, +@@ -213,7 +198,7 @@ static void nss_ipsecmgr_configure(struc + static int __init nss_ipsecmgr_init(void) + { + struct nss_ipsecmgr_tunnel *tun; +- struct net_device *dev = NULL; ++ struct net_device *dev; + int status; + + ipsecmgr_drv = vzalloc(sizeof(*ipsecmgr_drv)); +@@ -251,7 +236,7 @@ static int __init nss_ipsecmgr_init(void + status = register_netdev(dev); + if (status) { + nss_ipsecmgr_info("%px: Failed to register dummy netdevice(%px)", ipsecmgr_drv, dev); +- goto free; ++ goto netdev_free; + } + + ipsecmgr_drv->dev = dev; +@@ -269,31 +254,41 @@ static int __init nss_ipsecmgr_init(void + * Initialize debugfs. + */ + ipsecmgr_drv->dentry = debugfs_create_dir("qca-nss-ipsecmgr", NULL); +- if (ipsecmgr_drv->dentry) { +- tun->dentry = debugfs_create_dir(dev->name, ipsecmgr_drv->dentry); ++ if (!ipsecmgr_drv->dentry) { ++ nss_ipsecmgr_warn("%px: Failed to create root debugfs entry", ipsecmgr_drv); ++ nss_ipsec_cmn_notify_unregister(ipsecmgr_drv->nss_ctx, ipsecmgr_drv->ifnum); ++ goto unregister_dev; + } + + /* ++ * Create debugfs entry for tunnel ++ */ ++ tun->dentry = debugfs_create_dir(dev->name, ipsecmgr_drv->dentry); ++ ++ /* + * Configure inline mode and the DMA rings. + */ + nss_ipsecmgr_configure(&ipsecmgr_drv->cfg_work.work); + +- write_lock_bh(&ipsecmgr_drv->lock); ++ write_lock(&ipsecmgr_drv->lock); + list_add(&tun->list, &ipsecmgr_drv->tun_db); + + ipsecmgr_drv->max_mtu = dev->mtu; +- write_unlock_bh(&ipsecmgr_drv->lock); ++ write_unlock(&ipsecmgr_drv->lock); + + nss_ipsecmgr_info("NSS IPsec manager loaded: %s\n", NSS_CLIENT_BUILD_ID); + return 0; + ++unregister_dev: ++ unregister_netdev(ipsecmgr_drv->dev); ++ ++netdev_free: ++ free_netdev(ipsecmgr_drv->dev); ++ + free: +-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(4, 11, 8)) +- if (dev) +- dev->destructor(dev); +-#endif + vfree(ipsecmgr_drv); + ipsecmgr_drv = NULL; ++ + return -1; + } + +--- a/ipsecmgr/v2.0/nss_ipsecmgr_ctx.c ++++ b/ipsecmgr/v2.0/nss_ipsecmgr_ctx.c +@@ -1,6 +1,6 @@ + /* + * ******************************************************************************** +- * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. +@@ -92,7 +92,6 @@ static const struct nss_ipsecmgr_print i + {"\texceptioned", NSS_IPSECMGR_PRINT_DWORD}, + {"\tlinearized", NSS_IPSECMGR_PRINT_DWORD}, + {"\tredirected", NSS_IPSECMGR_PRINT_DWORD}, +- {"\tdropped", NSS_IPSECMGR_PRINT_DWORD}, + {"\tfail_sa", NSS_IPSECMGR_PRINT_DWORD}, + {"\tfail_flow", NSS_IPSECMGR_PRINT_DWORD}, + {"\tfail_stats", NSS_IPSECMGR_PRINT_DWORD}, +@@ -100,9 +99,6 @@ static const struct nss_ipsecmgr_print i + {"\tfail_transform", NSS_IPSECMGR_PRINT_DWORD}, + {"\tfail_linearized", NSS_IPSECMGR_PRINT_DWORD}, + {"\tfail_mdata_ver", NSS_IPSECMGR_PRINT_DWORD}, +- {"\tfail_ctx_active", NSS_IPSECMGR_PRINT_DWORD}, +- {"\tfail_pbuf_crypto", NSS_IPSECMGR_PRINT_DWORD}, +- {"\tfail_queue_crypto", NSS_IPSECMGR_PRINT_DWORD}, + }; + + /* +@@ -552,8 +548,8 @@ void nss_ipsecmgr_ctx_rx_redir(struct ne + * If, data callback is available then send the packet to the + * callback function + */ +- if (tun->cb.except_cb) { +- tun->cb.except_cb(tun->cb.app_data, skb); ++ if (tun->cb.data_cb) { ++ tun->cb.data_cb(tun->cb.app_data, skb); + ctx->hstats.redir_cb++; + return; + } +@@ -609,11 +605,6 @@ void nss_ipsecmgr_ctx_rx_outer(struct ne + } + + skb_set_transport_header(skb, sizeof(*iph)); +- if (tun->cb.except_cb) { +- tun->cb.except_cb(tun->cb.app_data, skb); +- ctx->hstats.outer_cb++; +- return; +- } + nss_ipsecmgr_ctx_route_ipv4(skb, ctx); + return; + } +@@ -631,11 +622,6 @@ void nss_ipsecmgr_ctx_rx_outer(struct ne + } + + skb_set_transport_header(skb, sizeof(*ip6h)); +- if (tun->cb.except_cb) { +- tun->cb.except_cb(tun->cb.app_data, skb); +- ctx->hstats.outer_cb++; +- return; +- } + nss_ipsecmgr_ctx_route_ipv6(skb, ctx); + return; + } +@@ -731,7 +717,6 @@ void nss_ipsecmgr_ctx_rx_stats(void *app + struct nss_ipsecmgr_sa *sa; + void *app_data; + +- event.type = NSS_IPSECMGR_EVENT_SA_STATS; + write_lock(&ipsecmgr_drv->lock); + + sa = nss_ipsecmgr_sa_find(sa_db, &sync->sa_tuple); +@@ -874,30 +859,13 @@ struct nss_ipsecmgr_ctx *nss_ipsecmgr_ct + } + + /* +- * nss_ipsecmgr_ctx_attach() +- * Attach context to the database +- */ +-void nss_ipsecmgr_ctx_attach(struct list_head *db, struct nss_ipsecmgr_ctx *ctx) +-{ +- struct nss_ipsecmgr_tunnel *tun = ctx->tun; +- +- list_add(&ctx->list, db); +- +- /* +- * Add ctx->ref to tun->ref +- */ +- write_lock_bh(&ipsecmgr_drv->lock); +- nss_ipsecmgr_ref_add(&ctx->ref, &tun->ref); +- write_unlock_bh(&ipsecmgr_drv->lock); +-} +- +-/* + * nss_ipsecmgr_ctx_config() + * Configure context + */ + bool nss_ipsecmgr_ctx_config(struct nss_ipsecmgr_ctx *ctx) + { + enum nss_ipsec_cmn_msg_type msg_type = NSS_IPSEC_CMN_MSG_TYPE_CTX_CONFIG; ++ struct nss_ipsecmgr_tunnel *tun = ctx->tun; + struct nss_ipsec_cmn_ctx *ctx_msg; + struct nss_ipsec_cmn_msg nicm; + nss_tx_status_t status; +@@ -907,7 +875,6 @@ bool nss_ipsecmgr_ctx_config(struct nss_ + ctx_msg = &nicm.msg.ctx; + ctx_msg->type = ctx->state.type; + ctx_msg->except_ifnum = ctx->state.except_ifnum; +- ctx_msg->sibling_ifnum = ctx->state.sibling_ifnum; + + status = nss_ipsec_cmn_tx_msg_sync(ctx->nss_ctx, ctx->ifnum, msg_type, sizeof(*ctx_msg), &nicm); + if (status != NSS_TX_SUCCESS) { +@@ -916,6 +883,10 @@ bool nss_ipsecmgr_ctx_config(struct nss_ + return false; + } + ++ write_lock_bh(&ipsecmgr_drv->lock); ++ nss_ipsecmgr_ref_add(&ctx->ref, &tun->ref); ++ write_unlock_bh(&ipsecmgr_drv->lock); ++ + return true; + } + +@@ -941,7 +912,6 @@ struct nss_ipsecmgr_ctx *nss_ipsecmgr_ct + uint32_t features) + { + struct nss_ipsecmgr_ctx *ctx; +- int32_t ifnum; + + ctx = kzalloc(sizeof(*ctx), in_atomic() ? GFP_ATOMIC : GFP_KERNEL); + if (!ctx) { +@@ -955,14 +925,13 @@ struct nss_ipsecmgr_ctx *nss_ipsecmgr_ct + ctx->state.type = ctx_type; + ctx->state.di_type = di_type; + +- ifnum = nss_dynamic_interface_alloc_node(di_type); +- if (ifnum < 0) { ++ ctx->ifnum = nss_dynamic_interface_alloc_node(di_type); ++ if (ctx->ifnum < 0) { + nss_ipsecmgr_warn("%px: failed to allocate dynamic interface(%d)", tun, di_type); + kfree(ctx); + return NULL; + } + +- ctx->ifnum = ifnum; + ctx->state.stats_len = ctx->state.print_len = nss_ipsecmgr_ctx_stats_size(); + nss_ipsecmgr_ref_init(&ctx->ref, nss_ipsecmgr_ctx_del_ref, nss_ipsecmgr_ctx_free_ref); + nss_ipsecmgr_ref_init_print(&ctx->ref, nss_ipsecmgr_ctx_print_len, nss_ipsecmgr_ctx_print); +--- a/ipsecmgr/v2.0/nss_ipsecmgr_ctx.h ++++ b/ipsecmgr/v2.0/nss_ipsecmgr_ctx.h +@@ -43,7 +43,7 @@ struct nss_ipsecmgr_ctx_host_stats { + uint64_t inner_fail_flow; /* Failed to find flow for inner packet */ + uint64_t outer_exp; /* Host processed inner IPv6 exceptioned packet */ + uint64_t outer_exp_drop; /* Host processed and dropped inner IPv6 exceptioned packet */ +- uint64_t outer_cb; /* Number of times exception call back called for outer packet */ ++ uint64_t outer_cb; /* Number of times data call back called for inner packet */ + uint64_t outer_fail_dev; /* Failed to find netdevice for inner packet */ + uint64_t outer_fail_sa; /* Failed to find SA for outer packet */ + uint64_t outer_fail_flow; /* Failed to find flow for outer packet */ +@@ -70,7 +70,6 @@ struct nss_ipsecmgr_ctx_stats_priv { + uint64_t exceptioned; /* Exceptioned to host */ + uint64_t linearized; /* Linearized packets */ + uint64_t redirected; /* Redirected from inline */ +- uint64_t dropped; /* Total dropped packets */ + uint64_t fail_sa; /* Failed to find SA */ + uint64_t fail_flow; /* Failed to find flow */ + uint64_t fail_stats; /* Failed to send statistics */ +@@ -78,9 +77,6 @@ struct nss_ipsecmgr_ctx_stats_priv { + uint64_t fail_transform; /* Failed to transform */ + uint64_t fail_linearized; /* Failed to linearized */ + uint64_t fail_mdata_ver; /* Invalid meta data version */ +- uint64_t fail_ctx_active; /* Failed to queue as ctx is not active. */ +- uint64_t fail_pbuf_crypto; /* Failed to allocate pbuf for crypto operation */ +- uint64_t fail_queue_crypto; /* Failed to queue pbuf to crypto pnode */ + }; + + /* +@@ -90,7 +86,6 @@ struct nss_ipsecmgr_ctx_state { + ssize_t print_len; /* Print buffer length */ + ssize_t stats_len; /* Total stats length */ + uint32_t except_ifnum; /* Exception interface number */ +- uint32_t sibling_ifnum; /* Sibling interface number */ + enum nss_ipsec_cmn_ctx_type type; /* Type */ + enum nss_dynamic_interface_type di_type; /* Dynamic interface type */ + }; +@@ -112,19 +107,20 @@ struct nss_ipsecmgr_ctx { + }; + + /* +- * Set the exception interface number for context ++ * nss_ipsecmgr_ctx_attach() ++ * Attach context to the database + */ +-static inline void nss_ipsecmgr_ctx_set_except(struct nss_ipsecmgr_ctx *ctx, uint32_t except_ifnum) ++static inline void nss_ipsecmgr_ctx_attach(struct list_head *db, struct nss_ipsecmgr_ctx *ctx) + { +- ctx->state.except_ifnum = except_ifnum; ++ list_add(&ctx->list, db); + } + + /* +- * Set the sibling interface number for context ++ * Set the exception interface number for context + */ +-static inline void nss_ipsecmgr_ctx_set_sibling(struct nss_ipsecmgr_ctx *ctx, uint32_t sibling_ifnum) ++static inline void nss_ipsecmgr_ctx_set_except(struct nss_ipsecmgr_ctx *ctx, uint32_t except_ifnum) + { +- ctx->state.sibling_ifnum = sibling_ifnum; ++ ctx->state.except_ifnum = except_ifnum; + } + + extern const struct file_operations ipsecmgr_ctx_file_ops; +@@ -135,7 +131,6 @@ extern void nss_ipsecmgr_ctx_rx_redir(st + extern void nss_ipsecmgr_ctx_rx_outer(struct net_device *dev, struct sk_buff *skb, struct napi_struct *napi); + extern void nss_ipsecmgr_ctx_rx_inner(struct net_device *dev, struct sk_buff *skb, struct napi_struct *napi); + +-extern void nss_ipsecmgr_ctx_attach(struct list_head *db, struct nss_ipsecmgr_ctx *ctx); + extern bool nss_ipsecmgr_ctx_config(struct nss_ipsecmgr_ctx *ctx); + extern void nss_ipsecmgr_ctx_free(struct nss_ipsecmgr_ctx *ctx); + extern struct nss_ipsecmgr_ctx *nss_ipsecmgr_ctx_alloc(struct nss_ipsecmgr_tunnel *tun, +--- a/ipsecmgr/v2.0/nss_ipsecmgr_flow.c ++++ b/ipsecmgr/v2.0/nss_ipsecmgr_flow.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -149,10 +149,10 @@ static bool nss_ipsecmgr_flow_update_db( + + hash_idx = nss_ipsecmgr_flow_tuple2hash(&flow->state.tuple, NSS_IPSECMGR_FLOW_MAX); + +- write_lock_bh(&ipsecmgr_drv->lock); ++ write_lock(&ipsecmgr_drv->lock); + sa = nss_ipsecmgr_sa_find(ipsecmgr_drv->sa_db, sa_tuple); + if (!sa) { +- write_unlock_bh(&ipsecmgr_drv->lock); ++ write_unlock(&ipsecmgr_drv->lock); + nss_ipsecmgr_trace("%px: failed to find SA during flow update", flow); + return false; + } +@@ -163,7 +163,7 @@ static bool nss_ipsecmgr_flow_update_db( + */ + nss_ipsecmgr_ref_add(&flow->ref, &sa->ref); + list_add(&flow->list, &ipsecmgr_drv->flow_db[hash_idx]); +- write_unlock_bh(&ipsecmgr_drv->lock); ++ write_unlock(&ipsecmgr_drv->lock); + return true; + } + +@@ -215,7 +215,7 @@ static void nss_ipsecmgr_flow_del_ref(st + * Write lock needs to be held by the caller since flow db is + * getting modified. + */ +- nss_ipsecmgr_write_lock_is_held(&ipsecmgr_drv->lock); ++ BUG_ON(write_can_lock(&ipsecmgr_drv->lock)); + list_del_init(&flow->list); + } + +--- a/ipsecmgr/v2.0/nss_ipsecmgr_priv.h ++++ b/ipsecmgr/v2.0/nss_ipsecmgr_priv.h +@@ -1,6 +1,6 @@ + /* + * ******************************************************************************** +- * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. +@@ -20,8 +20,6 @@ + #define __NSS_IPSECMGR_PRIV_H + + #include +-#include +-#include + + #define NSS_IPSECMGR_DEBUG_LVL_ERROR 1 /**< Turn on debug for an error. */ + #define NSS_IPSECMGR_DEBUG_LVL_WARN 2 /**< Turn on debug for a warning. */ +@@ -78,16 +76,6 @@ + #define NSS_IPSECMGR_PRINT_SHORT NSS_IPSECMGR_PRINT_BYTES(2) + #define NSS_IPSECMGR_PRINT_BYTE NSS_IPSECMGR_PRINT_BYTES(1) + #define NSS_IPSECMGR_PRINT_IPADDR (NSS_IPSECMGR_PRINT_WORD * 4) +-/* +- * Check if lock is held +- */ +-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(4, 14, 196)) +-#define nss_ipsecmgr_write_lock_is_held(x) BUG_ON(write_can_lock(x)) +-#define nss_ipsecmgr_lock_is_held(x) BUG_ON(read_can_lock(x)) +-#else +-#define nss_ipsecmgr_lock_is_held(x) lockdep_assert_held(x) +-#define nss_ipsecmgr_write_lock_is_held(x) lockdep_assert_held_write(x) +-#endif + + /* + * Statistics dump information +--- a/ipsecmgr/v2.0/nss_ipsecmgr_ref.c ++++ b/ipsecmgr/v2.0/nss_ipsecmgr_ref.c +@@ -140,7 +140,7 @@ ssize_t nss_ipsecmgr_ref_print(struct ns + /* + * DEBUG check to see if the lock is taken before touching the list + */ +- nss_ipsecmgr_write_lock_is_held(&ipsecmgr_drv->lock); ++ BUG_ON(write_can_lock(&ipsecmgr_drv->lock)); + + len += ref->print(ref, buf); + +@@ -163,7 +163,7 @@ ssize_t nss_ipsecmgr_ref_print_len(struc + /* + * DEBUG check to see if the lock is taken before touching the list + */ +- nss_ipsecmgr_write_lock_is_held(&ipsecmgr_drv->lock); ++ BUG_ON(write_can_lock(&ipsecmgr_drv->lock)); + + list_for_each_entry(entry, &ref->head, node) { + total_len += nss_ipsecmgr_ref_print_len(entry); +@@ -203,7 +203,7 @@ void nss_ipsecmgr_ref_del(struct nss_ips + /* + * DEBUG check to see if the lock is taken before touching the list + */ +- nss_ipsecmgr_write_lock_is_held(&ipsecmgr_drv->lock); ++ BUG_ON(write_can_lock(&ipsecmgr_drv->lock)); + + while (!list_empty(&ref->head)) { + entry = list_first_entry(&ref->head, struct nss_ipsecmgr_ref, node); +@@ -231,7 +231,7 @@ void nss_ipsecmgr_ref_add(struct nss_ips + /* + * DEBUG check to see if the lock is taken before touching the list + */ +- nss_ipsecmgr_write_lock_is_held(&ipsecmgr_drv->lock); ++ BUG_ON(write_can_lock(&ipsecmgr_drv->lock)); + + /* + * if child is already part of an existing chain then remove it before +--- a/ipsecmgr/v2.0/nss_ipsecmgr_ref.h ++++ b/ipsecmgr/v2.0/nss_ipsecmgr_ref.h +@@ -1,6 +1,6 @@ + /* + * ******************************************************************************** +- * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. +@@ -42,12 +42,6 @@ struct nss_ipsecmgr_ref { + nss_ipsecmgr_ref_method_t del; /* unlink function */ + }; + +-/* Check if the reference tree is empty */ +-static inline bool nss_ipsecmgr_ref_is_empty(struct nss_ipsecmgr_ref *ref) +-{ +- return list_empty(&ref->head); +-} +- + /* functions to operate on reference object */ + extern ssize_t nss_ipsecmgr_ref_print_len(struct nss_ipsecmgr_ref *ref); + extern ssize_t nss_ipsecmgr_ref_print(struct nss_ipsecmgr_ref *ref, char *buf); +--- a/ipsecmgr/v2.0/nss_ipsecmgr_sa.c ++++ b/ipsecmgr/v2.0/nss_ipsecmgr_sa.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -130,7 +130,6 @@ static const struct nss_ipsecmgr_print i + {"\tfail_transform", NSS_IPSECMGR_PRINT_DWORD}, + {"\tfail_crypto", NSS_IPSECMGR_PRINT_DWORD}, + {"\tfail_classification", NSS_IPSECMGR_PRINT_DWORD}, +- {"\tis_stopped", NSS_IPSECMGR_PRINT_DWORD}, + }; + + /* +@@ -364,7 +363,6 @@ static nss_ipsecmgr_status_t nss_ipsecmg + if (!rt_keys) { + nss_ipsecmgr_warn("%px: failed to allocate key memory\n", sa); + crypto_free_aead(sa->aead); +- sa->aead = NULL; + return NSS_IPSECMGR_FAIL_NOMEM; + } + +@@ -390,7 +388,6 @@ static nss_ipsecmgr_status_t nss_ipsecmg + if (crypto_aead_setkey(sa->aead, rt_keys, keylen)) { + nss_ipsecmgr_warn("%px: failed to configure keys\n", sa); + crypto_free_aead(sa->aead); +- sa->aead = NULL; + vfree(rt_keys); + return NSS_IPSECMGR_INVALID_KEYLEN; + } +@@ -417,7 +414,6 @@ static nss_ipsecmgr_status_t nss_ipsecmg + if (crypto_ahash_setkey(sa->ahash, keys->auth_key, keys->auth_keylen)) { + nss_ipsecmgr_warn("%px: failed to configure keys\n", sa); + crypto_free_ahash(sa->ahash); +- sa->ahash = NULL; + return NSS_IPSECMGR_INVALID_KEYLEN; + } + +@@ -448,7 +444,6 @@ static nss_ipsecmgr_status_t nss_ipsecmg + if (!rt_keys) { + nss_ipsecmgr_warn("%px: failed to allocate key memory\n", sa); + crypto_free_aead(sa->aead); +- sa->aead = NULL; + return NSS_IPSECMGR_FAIL_NOMEM; + } + +@@ -458,7 +453,6 @@ static nss_ipsecmgr_status_t nss_ipsecmg + if (crypto_aead_setkey(sa->aead, rt_keys, keylen)) { + nss_ipsecmgr_warn("%px: failed to configure keys\n", sa); + crypto_free_aead(sa->aead); +- sa->aead = NULL; + vfree(rt_keys); + return NSS_IPSECMGR_INVALID_KEYLEN; + } +@@ -486,15 +480,11 @@ static nss_ipsecmgr_status_t nss_ipsecmg + */ + static void nss_ipsecmgr_sa_free(struct nss_ipsecmgr_sa *sa) + { +- if (sa->aead) { ++ if (sa->aead) + crypto_free_aead(sa->aead); +- sa->aead = NULL; +- } + +- if (sa->ahash) { ++ if (sa->ahash) + crypto_free_ahash(sa->ahash); +- sa->ahash = NULL; +- } + + kfree(sa); + } +@@ -513,7 +503,7 @@ static void nss_ipsecmgr_sa_del_ref(stru + * Linux does not provide any specific API(s) to test for RW locks. The caller + * being internal is assumed to hold write lock before initiating this. + */ +- nss_ipsecmgr_write_lock_is_held(&ipsecmgr_drv->lock); ++ BUG_ON(write_can_lock(&ipsecmgr_drv->lock)); + + list_del_init(&sa->list); + +@@ -789,10 +779,6 @@ void nss_ipsecmgr_sa_sync2stats(struct n + stats->seq_start = sync->replay.seq_start; + stats->seq_cur = sync->replay.seq_cur; + } +- +- stats->fail_replay_win = sa_stats->fail_replay_win; +- stats->fail_replay_dup = sa_stats->fail_replay_dup; +- stats->fail_auth = sa_stats->fail_auth; + } + + /* +@@ -809,7 +795,7 @@ void nss_ipsecmgr_sa_sync_state(struct n + * DEBUG check to see if the lock is taken before accessing + * SA entry in the database + */ +- nss_ipsecmgr_write_lock_is_held(&ipsecmgr_drv->lock); ++ BUG_ON(write_can_lock(&ipsecmgr_drv->lock)); + + for (num = 0; num < sizeof(sa->stats)/sizeof(*sa_stats); num++) { + sa_stats[num] += msg_stats[num]; +@@ -1082,85 +1068,6 @@ bool nss_ipsecmgr_sa_verify(struct net_d + EXPORT_SYMBOL(nss_ipsecmgr_sa_verify); + + /* +- * nss_ipsecmgr_cra_name2algo() +- * Returns nss_ipsecmgr_algo +- */ +-enum nss_ipsecmgr_algo nss_ipsecmgr_cra_name2algo(const char *cra_name) +-{ +- enum nss_ipsecmgr_algo algo = NSS_IPSECMGR_ALGO_AES_CBC_SHA1_HMAC; +- const char **algo_name = ipsecmgr_algo_name; +- +- for (; algo < NSS_IPSECMGR_ALGO_MAX; algo++, algo_name++) { +- if (!strncmp(cra_name, *algo_name, strlen(*algo_name))) { +- return algo; +- } +- } +- +- return NSS_IPSECMGR_ALGO_MAX; +-} +-EXPORT_SYMBOL(nss_ipsecmgr_cra_name2algo); +- +-/* +- * nss_ipsecmgr_sa_get_info() +- * Get Crypto information for an already created SA. +- */ +-bool nss_ipsecmgr_sa_get_info(struct net_device *dev, struct nss_ipsecmgr_sa_tuple *tuple, +- struct nss_ipsecmgr_sa_info *sa_info) +-{ +- struct nss_ipsec_cmn_sa_tuple sa_tuple = {0}; +- struct nss_ipsecmgr_sa *sa; +- uint32_t mask; +- +- /* +- * Look for an existing SA. +- */ +- nss_ipsecmgr_sa2tuple(tuple, &sa_tuple); +- +- read_lock_bh(&ipsecmgr_drv->lock); +- sa = nss_ipsecmgr_sa_find(ipsecmgr_drv->sa_db, &sa_tuple); +- if (!sa) { +- read_unlock_bh(&ipsecmgr_drv->lock); +- return false; +- } +- +- sa_info->blk_len = sa->state.data.blk_len; +- sa_info->iv_len = sa->state.data.iv_len; +- sa_info->hash_len = sa->state.data.icv_len; +- sa_info->session_idx = sa->state.tuple.crypto_index; +- +- sa_info->hdr_len = sizeof(struct ip_esp_hdr) + sa_info->iv_len; +- mask = NSS_IPSEC_CMN_FLAG_HDR_MASK | NSS_IPSEC_CMN_FLAG_MODE_TRANS; +- +- switch (sa->state.data.flags & mask) { +- case NSS_IPSEC_CMN_FLAG_IPV4_NATT | NSS_IPSEC_CMN_FLAG_MODE_TRANS: +- sa_info->hdr_len += sizeof(struct udphdr); +- break; +- case NSS_IPSEC_CMN_FLAG_IPV6 | NSS_IPSEC_CMN_FLAG_MODE_TRANS: +- case NSS_IPSEC_CMN_FLAG_MODE_TRANS: +- break; +- case NSS_IPSEC_CMN_FLAG_IPV4_NATT: +- sa_info->hdr_len += sizeof(struct iphdr) + sizeof(struct udphdr); +- break; +- case NSS_IPSEC_CMN_FLAG_IPV6: +- sa_info->hdr_len += sizeof(struct ipv6hdr); +- break; +- default: +- sa_info->hdr_len += sizeof(struct iphdr); +- break; +- } +- +- read_unlock_bh(&ipsecmgr_drv->lock); +- +- /* +- * The user of trailer_len should take care of the odd length. +- */ +- sa_info->trailer_len = sa_info->blk_len + 1 + sa_info->hash_len; +- +- return true; +-} +-EXPORT_SYMBOL(nss_ipsecmgr_sa_get_info); +- +-/* + * nss_ipsecmgr_sa_tx_inner() + * Offload given SKB to NSS for inner processing. + */ +--- a/ipsecmgr/v2.0/nss_ipsecmgr_sa.h ++++ b/ipsecmgr/v2.0/nss_ipsecmgr_sa.h +@@ -1,6 +1,6 @@ + /* + * ******************************************************************************** +- * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. +@@ -62,8 +62,7 @@ struct nss_ipsecmgr_sa_stats_priv { + uint64_t fail_hash_len; /**< Failure in decap due to bad hash block len. */ + uint64_t fail_transform; /**< Failure in transformation; general error. */ + uint64_t fail_crypto; /**< Failure in crypto transformation. */ +- uint64_t fail_cle; /**< Failure in classification; general failure */ +- uint64_t is_stopped; /**< Indicates if SA is stopped; eg: seq overflow */ ++ uint64_t fail_cle; /* Failure in classification; general failure */ + }; + + /* +--- a/ipsecmgr/v2.0/nss_ipsecmgr_tunnel.c ++++ b/ipsecmgr/v2.0/nss_ipsecmgr_tunnel.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -128,14 +128,6 @@ static netdev_tx_t nss_ipsecmgr_tunnel_t + } + + /* +- * Linearize the nonlinear SKB. +- */ +- if (skb_linearize(skb)) { +- nss_ipsecmgr_trace("%s: unable to Linearize SKB\n", dev->name); +- goto free; +- } +- +- /* + * For all these cases + * - create a writable copy of buffer + * - increase the head room +@@ -227,10 +219,10 @@ free: + } + + /* +- * nss_ipsecmgr_tunnel_get_stats64() ++ * nss_ipsecmgr_tunnel_stats64() + * Get device statistics + */ +-static struct rtnl_link_stats64 *nss_ipsecmgr_tunnel_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) ++static struct rtnl_link_stats64 *nss_ipsecmgr_tunnel_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) + { + struct nss_ipsecmgr_tunnel *tun = netdev_priv(dev); + struct list_head *head = &tun->ctx_db; +@@ -248,22 +240,6 @@ static struct rtnl_link_stats64 *nss_ips + } + + /* +- * nss_ipsecmgr_tunnel_stats64() +- * Sync statistics to linux +- */ +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0)) +-static struct rtnl_link_stats64 *nss_ipsecmgr_tunnel_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) +-{ +- return nss_ipsecmgr_tunnel_get_stats64(dev, stats); +-} +-#else +-static void nss_ipsecmgr_tunnel_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) +-{ +- nss_ipsecmgr_tunnel_get_stats64(dev, stats); +-} +-#endif +- +-/* + * nss_ipsecmgr_tunnel_mtu_update() + * Update tunnel max MTU + */ +@@ -273,7 +249,7 @@ static void nss_ipsecmgr_tunnel_mtu_upda + uint16_t max_mtu = 0; + bool update_mtu = false; + +- write_lock_bh(&ipsecmgr_drv->lock); ++ write_lock(&ipsecmgr_drv->lock); + list_for_each_entry(tun, head, list) { + if (tun->dev->mtu > max_mtu) + max_mtu = tun->dev->mtu; +@@ -284,7 +260,7 @@ static void nss_ipsecmgr_tunnel_mtu_upda + update_mtu = true; + } + +- write_unlock_bh(&ipsecmgr_drv->lock); ++ write_unlock(&ipsecmgr_drv->lock); + + #ifdef NSS_IPSECMGR_PPE_SUPPORT + /* +@@ -337,29 +313,7 @@ static const struct net_device_ops ipsec + */ + static void nss_ipsecmgr_tunnel_free(struct net_device *dev) + { +- struct nss_ipsecmgr_tunnel *tun = netdev_priv(dev); +- struct nss_ipsecmgr_ref *ref, *tmp; +- struct list_head free_refs; +- + nss_ipsecmgr_info("IPsec tunnel device(%s) freed\n", dev->name); +- +- INIT_LIST_HEAD(&free_refs); +- +- /* +- * Remove context(s) from the tunnel reference tree if it has been +- * added +- */ +- write_lock_bh(&ipsecmgr_drv->lock); +- if (!nss_ipsecmgr_ref_is_empty(&tun->ref)) { +- nss_ipsecmgr_ref_del(&tun->ref, &free_refs); +- } +- +- write_unlock_bh(&ipsecmgr_drv->lock); +- +- list_for_each_entry_safe(ref, tmp, &free_refs, node) { +- ref->free(ref); +- } +- + free_netdev(dev); + } + +@@ -397,14 +351,13 @@ static void nss_ipsecmgr_tunnel_free_ref + { + struct nss_ipsecmgr_tunnel *tun = container_of(ref, struct nss_ipsecmgr_tunnel, ref); + ++ nss_ipsecmgr_tunnel_mtu_update(&ipsecmgr_drv->tun_db); ++ + /* + * The unregister should start here but the expectation is that the free would + * happen when the reference count goes down to '0' + */ +- if (tun->dev->reg_state == NETREG_REGISTERED) { +- nss_ipsecmgr_tunnel_mtu_update(&ipsecmgr_drv->tun_db); +- rtnl_is_locked() ? unregister_netdevice(tun->dev) : unregister_netdev(tun->dev); +- } ++ rtnl_is_locked() ? unregister_netdevice(tun->dev) : unregister_netdev(tun->dev); + } + + /* +@@ -436,11 +389,7 @@ static void nss_ipsecmgr_tunnel_setup(st + dev->header_ops = NULL; + dev->netdev_ops = &ipsecmgr_dev_ops; + +-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(4, 11, 8)) + dev->destructor = nss_ipsecmgr_tunnel_free; +-#else +- dev->priv_destructor = nss_ipsecmgr_tunnel_free; +-#endif + + /* + * Get the MAC address from the ethernet device +@@ -524,11 +473,9 @@ struct net_device *nss_ipsecmgr_tunnel_a + NSS_IPSEC_CMN_FEATURE_INLINE_ACCEL); + if (!inner) { + nss_ipsecmgr_warn("%px: failed to allocate context inner\n", tun); +- goto free; ++ goto free_dev; + } + +- nss_ipsecmgr_ctx_attach(&tun->ctx_db, inner); +- + /* + * Inner Metadata context allocation + */ +@@ -540,10 +487,9 @@ struct net_device *nss_ipsecmgr_tunnel_a + 0); + if (!mdata_inner) { + nss_ipsecmgr_warn("%px: failed to allocate context metadata inner\n", tun); +- goto free; ++ goto free_inner; + } + +- nss_ipsecmgr_ctx_attach(&tun->ctx_db, mdata_inner); + /* + * Outer context allocation + */ +@@ -555,10 +501,9 @@ struct net_device *nss_ipsecmgr_tunnel_a + NSS_IPSEC_CMN_FEATURE_INLINE_ACCEL); + if (!outer) { + nss_ipsecmgr_warn("%px: failed to allocate context outer\n", tun); +- goto free; ++ goto free_mdata_inner; + } + +- nss_ipsecmgr_ctx_attach(&tun->ctx_db, outer); + /* + * Outer metadata context allocation + */ +@@ -570,9 +515,13 @@ struct net_device *nss_ipsecmgr_tunnel_a + 0); + if (!mdata_outer) { + nss_ipsecmgr_warn("%px: failed to allocate context metadata outer\n", tun); +- goto free; ++ goto free_outer; + } + ++ nss_ipsecmgr_ctx_attach(&tun->ctx_db, inner); ++ nss_ipsecmgr_ctx_attach(&tun->ctx_db, mdata_inner); ++ ++ nss_ipsecmgr_ctx_attach(&tun->ctx_db, outer); + nss_ipsecmgr_ctx_attach(&tun->ctx_db, mdata_outer); + + /* +@@ -587,49 +536,35 @@ struct net_device *nss_ipsecmgr_tunnel_a + nss_ipsecmgr_ctx_set_except(outer, inner->ifnum); + nss_ipsecmgr_ctx_set_except(mdata_outer, inner->ifnum); + +- /* +- * We need to setup the sibling interface number for inner & outer; +- * The sibling interface is used by the NSS to configure SA on sibling. +- */ +- nss_ipsecmgr_ctx_set_sibling(inner, mdata_inner->ifnum); +- nss_ipsecmgr_ctx_set_sibling(outer, mdata_outer->ifnum); +- + if (!nss_ipsecmgr_ctx_config(inner)) { + nss_ipsecmgr_warn("%px: failed to configure inner context\n", tun); +- goto free; ++ goto free_mdata_outer; + } + + if (!nss_ipsecmgr_ctx_config(mdata_inner)) { + nss_ipsecmgr_warn("%px: failed to configure metadata inner context\n", tun); +- goto free; ++ goto free_mdata_outer; + } + + if (!nss_ipsecmgr_ctx_config(outer)) { + nss_ipsecmgr_warn("%px: failed to configure outer context\n", tun); +- goto free; ++ goto free_mdata_outer; + } + + if (!nss_ipsecmgr_ctx_config(mdata_outer)) { + nss_ipsecmgr_warn("%px: failed to configure metadata outer context\n", tun); +- goto free; ++ goto free_mdata_outer; + } + + status = rtnl_is_locked() ? register_netdevice(dev) : register_netdev(dev); + if (status < 0) { + nss_ipsecmgr_warn("%px: register net dev failed :%s\n", tun, dev->name); +-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(4, 11, 8)) +- goto free; +-#else +- /* +- * Later kernels invoke the destructor upon failure +- */ +- return NULL; +-#endif ++ goto free_mdata_outer; + } + +- write_lock_bh(&ipsecmgr_drv->lock); ++ write_lock(&ipsecmgr_drv->lock); + list_add(&tun->list, &ipsecmgr_drv->tun_db); +- write_unlock_bh(&ipsecmgr_drv->lock); ++ write_unlock(&ipsecmgr_drv->lock); + + nss_ipsecmgr_tunnel_mtu(dev, skb_dev ? skb_dev->mtu : dev->mtu); + +@@ -645,12 +580,16 @@ struct net_device *nss_ipsecmgr_tunnel_a + } + + return dev; +-free: +-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(4, 11, 8)) +- dev->destructor(dev); +-#else +- dev->priv_destructor(dev); +-#endif ++free_mdata_outer: ++ nss_ipsecmgr_ctx_free(mdata_outer); ++free_outer: ++ nss_ipsecmgr_ctx_free(outer); ++free_mdata_inner: ++ nss_ipsecmgr_ctx_free(mdata_inner); ++free_inner: ++ nss_ipsecmgr_ctx_free(inner); ++free_dev: ++ free_netdev(dev); + return NULL; + } + EXPORT_SYMBOL(nss_ipsecmgr_tunnel_add); +--- a/ipsecmgr/v2.0/plugins/klips/Makefile ++++ b/ipsecmgr/v2.0/plugins/klips/Makefile +@@ -10,7 +10,7 @@ ccflags-y += -I$(obj)/../../include + ccflags-y += -I$(obj)/ + ccflags-y += -DNSS_IPSEC_KLIPS_DEBUG_LEVEL=3 + ccflags-y += -DNSS_IPSEC_KLIPS_BUILD_ID="$(BUILD_ID)" +-ccflags-y += -Wall -Werror ++ccflags-y += -Werror + ifeq ($(SoC),$(filter $(SoC),ipq807x ipq807x_64)) + ccflags-y += -DNSS_CFI_IPQ807X_SUPPORT + endif +@@ -18,7 +18,3 @@ endif + ifeq ($(SoC),$(filter $(SoC),ipq60xx ipq60xx_64)) + ccflags-y += -DNSS_CFI_IPQ60XX_SUPPORT + endif +- +-ifeq ($(SoC),$(filter $(SoC),ipq50xx ipq50xx_64)) +-ccflags-y += -DNSS_CFI_IPQ50XX_SUPPORT +-endif +--- a/ipsecmgr/v2.0/plugins/klips/nss_ipsec_klips.c ++++ b/ipsecmgr/v2.0/plugins/klips/nss_ipsec_klips.c +@@ -1,5 +1,4 @@ +-/* +- * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. ++/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above +@@ -13,10 +12,11 @@ + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. ++ * ++ * + */ + +-/* +- * nss_ipsec_klips.c ++/* nss_ipsec_klips.c + * NSS IPsec offload glue for Openswan/KLIPS + */ + #include +@@ -51,9 +51,6 @@ + #if defined(NSS_L2TPV2_ENABLED) + #include + #endif +-#if defined(NSS_VXLAN_ENABLED) +-#include +-#endif + #include "nss_ipsec_klips.h" + + #define NSS_IPSEC_KLIPS_BASE_NAME "ipsec" +@@ -62,7 +59,6 @@ + #define NSS_IPSEC_KLIPS_FLAG_NATT 0x00000001 + #define NSS_IPSEC_KLIPS_FLAG_TRANSPORT_MODE 0x00000002 + #define NSS_IPSEC_KLIPS_SKB_CB_MAGIC 0xAAAB +-#define NSS_IPSEC_KLIPS_IP6_ADDR_LEN 4 + + /* + * This is used by KLIPS for communicate the device along with the +@@ -348,32 +344,6 @@ static struct net_device *nss_ipsec_klip + return tun_dev; + } + +-#if defined(NSS_L2TPV2_ENABLED) +-/* +- * nss_ipsec_klips_get_inner_ifnum() +- * Get ipsecmgr interface number for klips netdevice +- * +- * Calls nss_ipsec_klips_get_tun_dev(), which holds reference for tunnel, +- * which gets released at the end of this function. +- */ +-static int nss_ipsec_klips_get_inner_ifnum(struct net_device *klips_dev) +-{ +- struct net_device *tun_dev; +- int32_t ipsec_ifnum; +- +- tun_dev = nss_ipsec_klips_get_tun_dev(klips_dev); +- if (!tun_dev) { +- nss_ipsec_klips_warn("%px: Tunnel device not found for klips dev", klips_dev); +- return -1; +- } +- +- ipsec_ifnum = nss_cmn_get_interface_number_by_dev_and_type(tun_dev, NSS_DYNAMIC_INTERFACE_TYPE_IPSEC_CMN_INNER); +- dev_put(tun_dev); +- +- return ipsec_ifnum; +-} +-#endif +- + /* + * nss_ipsec_klips_get_tun_by_addr() + * Get the tunnel entry for given ip header from tunnel map table. +@@ -402,75 +372,6 @@ static struct nss_ipsec_klips_tun *nss_i + return NULL; + } + +-#if defined(NSS_VXLAN_ENABLED) +-/* +- * nss_ipsec_klips_tun_match_ip_addr() +- * Compare tunnel address with source & destination ip addresses. +- */ +-static bool nss_ipsec_klips_tun_match_ip_addr(struct nss_ipsec_klips_tun *tun, uint8_t ip_ver, uint32_t *local_ip, uint32_t *remote_ip) +-{ +- struct nss_ipsec_klips_tun_addr *addr = &tun->addr; +- uint32_t status = 0; +- uint8_t i; +- +- switch (ip_ver) { +- case IPVERSION: +- status += local_ip[0] ^ addr->dest[0]; +- status += remote_ip[0] ^ addr->src[0]; +- status += addr->ver ^ ip_ver; +- nss_ipsec_klips_trace("%px: tun dev comparing with IPV4 tunnel local_ip: %x & remote_ip: %x IP pair.\n", tun, addr->dest[0], addr->src[0]); +- return !status; +- +- case 6: +- status += addr->ver ^ ip_ver; +- for (i = 0; i < NSS_IPSEC_KLIPS_IP6_ADDR_LEN; i++) { +- status += local_ip[i] ^ addr->dest[i]; +- status += remote_ip[i] ^ addr->src[i]; +- nss_ipsec_klips_trace("%px: tun dev comparing with IPV6 tunnel local_ip[%u]: %x & remote_ip[%u]: %x IP pair.\n", tun, i, addr->dest[i], i, addr->src[i]); +- } +- return !status; +- +- default: +- nss_ipsec_klips_warn("%px: non ip version:%u received", tun, ip_ver); +- return false; +- } +-} +- +-/* +- * nss_ipsec_klips_get_ipsec_ifnum() +- * Get ipsecmgr tunnel interface num for klips netdevice +- */ +-static int32_t __maybe_unused nss_ipsec_klips_get_ipsec_ifnum(uint8_t ip_ver, uint32_t *local_ip, uint32_t *remote_ip) +-{ +- struct nss_ipsec_klips_tun *tun; +- struct net_device *tun_dev; +- uint32_t if_num = -1; +- uint32_t i; +- +- read_lock(&tunnel_map.lock); +- +- for (i = 0, tun = tunnel_map.tbl; i < tunnel_map.max; i++, tun++) { +- if (!tun->klips_dev) { +- nss_ipsec_klips_warn("%px: klips dev is NULL.\n", tun); +- continue; +- } +- +- if (nss_ipsec_klips_tun_match_ip_addr(tun, ip_ver, local_ip, remote_ip)) { +- tun_dev = tun->nss_dev; +- if_num = nss_cmn_get_interface_number_by_dev_and_type(tun_dev, NSS_DYNAMIC_INTERFACE_TYPE_IPSEC_CMN_INNER); +- nss_ipsec_klips_warn("%px: tun dev(with ifnum:%d) is mapped with local & remote IP pair.\n", tun, if_num); +- read_unlock(&tunnel_map.lock); +- return if_num; +- } +- } +- +- read_unlock(&tunnel_map.lock); +- +- nss_ipsec_klips_warn("%px: tun dev not found with the local(%pI4) & remote(%pI4) IP pair.\n", tun, local_ip, remote_ip); +- return -1; +-} +-#endif +- + /* + * nss_ipsec_klips_get_index() + * given an interface name retrived the numeric suffix +@@ -2070,14 +1971,7 @@ static struct notifier_block nss_ipsec_k + + #if defined(NSS_L2TPV2_ENABLED) + static struct l2tpmgr_ipsecmgr_cb nss_ipsec_klips_l2tp = { +- .get_ifnum_by_dev = nss_ipsec_klips_get_inner_ifnum, +- .get_ifnum_by_ip_addr = NULL +-}; +-#endif +- +-#if defined(NSS_VXLAN_ENABLED) +-static struct nss_vxlanmgr_get_ipsec_if_num nss_ipsec_klips_vxlan_cb = { +- .get_ifnum_by_ip = nss_ipsec_klips_get_ipsec_ifnum ++ .cb = nss_ipsec_klips_get_tun_dev + }; + #endif + +@@ -2116,11 +2010,7 @@ int __init nss_ipsec_klips_init_module(v + ecm_interface_ipsec_register_callbacks(&nss_ipsec_klips_ecm); + ecm_notifier_register_connection_notify(&nss_ipsec_klips_ecm_conn_notifier); + #if defined(NSS_L2TPV2_ENABLED) +- l2tpmgr_register_ipsecmgr_callback_by_netdev(&nss_ipsec_klips_l2tp); +-#endif +- +-#if defined(NSS_VXLAN_ENABLED) +- nss_vxlanmgr_register_ipsecmgr_callback_by_ip(&nss_ipsec_klips_vxlan_cb); ++ l2tpmgr_register_ipsecmgr_callback(&nss_ipsec_klips_l2tp); + #endif + return 0; + } +@@ -2142,11 +2032,7 @@ void __exit nss_ipsec_klips_exit_module( + ecm_notifier_unregister_connection_notify(&nss_ipsec_klips_ecm_conn_notifier); + ecm_interface_ipsec_unregister_callbacks(); + #if defined(NSS_L2TPV2_ENABLED) +- l2tpmgr_unregister_ipsecmgr_callback_by_netdev(); +-#endif +- +-#if defined(NSS_VXLAN_ENABLED) +- nss_vxlanmgr_unregister_ipsecmgr_callback_by_ip(); ++ l2tpmgr_unregister_ipsecmgr_callback(); + #endif + + nss_cfi_ocf_unregister_ipsec(); +--- a/l2tp/l2tpv2/Makefile ++++ b/l2tp/l2tpv2/Makefile +@@ -1,7 +1,7 @@ + # Makefile for l2tp client + ccflags-y += -I$(obj)/../../exports -I$(obj)/../.. -I$(obj)/nss_hal/include + ccflags-y += -DNSS_L2TP_DEBUG_LEVEL=0 +-ccflags-y += -Wall -Werror ++ccflags-y += -Werror + ifneq (,$(filter $(CONFIG_L2TP),m y)) + obj-m += qca-nss-l2tpv2.o + qca-nss-l2tpv2-objs := nss_connmgr_l2tpv2.o nss_l2tpv2_stats.o +--- a/l2tp/l2tpv2/nss_connmgr_l2tpv2.c ++++ b/l2tp/l2tpv2/nss_connmgr_l2tpv2.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2015-2017, 2019-2021 The Linux Foundation. All rights reserved. ++ * Copyright (c) 2015-2017, 2019-2020 The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -35,7 +35,6 @@ + #include + #include + #include +-#include + #include + + #include +@@ -100,11 +99,8 @@ + + static DEFINE_HASHTABLE(l2tpv2_session_data_hash_table, HASH_BUCKET_SIZE); + static int ip_ttl_max = 255; +- +-#if defined(NSS_L2TP_IPSEC_BIND_BY_NETDEV) + static char l2tpoipsec_config[L2TP_SYSCTL_STR_LEN_MAX]; + static struct ctl_table_header *ctl_tbl_hdr; /* l2tpv2 sysctl */ +-#endif + static struct l2tpmgr_ipsecmgr_cb __rcu ipsecmgr_cb; + + /* +@@ -248,23 +244,24 @@ static struct nss_connmgr_l2tpv2_session + */ + data->l2tpv2.session.session_id = session->session_id; + data->l2tpv2.session.peer_session_id = session->peer_session_id; ++ data->l2tpv2.session.offset = 0; + data->l2tpv2.session.hdr_len = session->hdr_len; + data->l2tpv2.session.reorder_timeout = session->reorder_timeout; + data->l2tpv2.session.recv_seq = session->recv_seq; + data->l2tpv2.session.send_seq = session->send_seq; + +- nss_connmgr_l2tpv2_info("sess %u, peer=%u nr=%u ns=%u hdr_len=%u timeout=%x" ++ nss_connmgr_l2tpv2_info("sess %u, peer=%u nr=%u ns=%u off=%u hdr_len=%u timeout=%x" + " recv_seq=%x send_seq=%x\n", + session->session_id, session->peer_session_id, session->nr, +- session->ns, session->hdr_len, ++ session->ns, 0, session->hdr_len, + session->reorder_timeout, session->recv_seq, + session->send_seq); + +- /* +- * tunnel->sock->sk_no_check/sk_no_check_tx is set to true +- * if UDP checksum is not needed for the L2TP socket. +- */ +- data->l2tpv2.tunnel.udp_csum = !tunnel->sock->sk_no_check_tx; ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 16, 0)) ++ data->l2tpv2.tunnel.udp_csum = tunnel->sock->sk_no_check; ++#else ++ data->l2tpv2.tunnel.udp_csum = tunnel->sock->sk_no_check_tx; ++#endif + + inet = inet_sk(tunnel->sock); + +@@ -359,6 +356,9 @@ static void nss_connmgr_l2tpv2_exception + { + const struct iphdr *iph_outer, *iph_inner; + struct nss_connmgr_l2tpv2_session_data *ptr; ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 8, 0)) ++ struct hlist_node *node; ++#endif + uint16_t *l2tp_hdr; + uint16_t l2tp_flags; + int l2tp_hdr_len = L2TP_HDR_MIN_LEN; +@@ -374,6 +374,9 @@ static void nss_connmgr_l2tpv2_exception + + rcu_read_lock(); + hash_for_each_possible_rcu(l2tpv2_session_data_hash_table, ptr, ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 8, 0)) ++ node, ++#endif + hash_list, dev->ifindex) { + if (ptr->dev == dev) { + tunnel_local_ip = ptr->data.ip.v4.saddr.s_addr; +@@ -477,56 +480,6 @@ static void nss_connmgr_l2tpv2_event_rec + } + + /* +- * nss_connmgr_l2tpv2_bind_ipsec_by_ipaddr() +- * Bind L2TP tunnel with IPsec(xfrm) based on IP Address +- */ +-static void nss_connmgr_l2tpv2_bind_ipsec_by_ipaddr(struct nss_ctx_instance *nss_ctx, struct nss_connmgr_l2tpv2_data *l2tpv2_data, uint32_t l2tp_ifnum) +-{ +- struct nss_l2tpv2_msg l2tpv2msg; +- nss_tx_status_t status; +- struct nss_l2tpv2_bind_ipsec_if_msg *l2tpv2_bind_ipsec_msg; +- int32_t ipsec_ifnum = -1; +- get_ipsec_ifnum_by_ip_addr_callback_t ipsec_cb; +- +- /* +- * Check if the L2TP interface is applied over an IPsec (XFRM) interface by querying the IPsec +- * client by using the L2TP tunnel IPv4 source/destination addresses. +- */ +- rcu_read_lock(); +- ipsec_cb = rcu_dereference(ipsecmgr_cb.get_ifnum_by_ip_addr); +- ipsec_ifnum = ipsec_cb ? ipsec_cb(IPVERSION, &l2tpv2_data->ip.v4.saddr.s_addr, &l2tpv2_data->ip.v4.daddr.s_addr) : -1; +- rcu_read_unlock(); +- +- if (ipsec_ifnum < 0) { +- nss_connmgr_l2tpv2_info("%px: Invalid IPsec interface no.(0x%x) based on local & remote IP-address\n", nss_ctx, ipsec_ifnum); +- return; +- } +- +- /* +- * For, l2tpoipsec, send the command to bind the l2tp session with the IPsec interface. +- */ +- memset(&l2tpv2msg, 0, sizeof(struct nss_l2tpv2_msg)); +- nss_l2tpv2_msg_init(&l2tpv2msg, l2tp_ifnum, NSS_L2TPV2_MSG_BIND_IPSEC_IF, +- sizeof(struct nss_l2tpv2_bind_ipsec_if_msg), (void *)nss_connmgr_l2tpv2_msg_cb, NULL); +- l2tpv2_bind_ipsec_msg = &l2tpv2msg.msg.bind_ipsec_if_msg; +- l2tpv2_bind_ipsec_msg->ipsec_ifnum = ipsec_ifnum; +- +- status = nss_l2tpv2_tx(nss_ctx, &l2tpv2msg); +- if (status != NSS_TX_SUCCESS) { +- /* +- * TODO: Add retry logic. Currently it sends a warning message to user. +- * In case of bind fails, then we don't bring down L2TP tunnel, instead we give a warning log +- * to user, as this introduces a potential risk of not having a per packet check for source +- * interface number in firmware. +- */ +- nss_connmgr_l2tpv2_warning("%px: L2TPv2 interface binding with IPSec interface(0x%x) failed.\n", nss_ctx, ipsec_ifnum); +- return; +- } +- +- nss_connmgr_l2tpv2_info("%px: L2TPv2 interface is bound to IPsec interface with if_num(0x%x)\n", nss_ctx, ipsec_ifnum); +-} +- +-/* + * nss_connmgr_l2tpv2_dev_up() + * pppol2tpv2 interface's up event handler + */ +@@ -630,12 +583,7 @@ static int nss_connmgr_l2tpv2_dev_up(str + return NOTIFY_BAD; + } + +- nss_connmgr_l2tpv2_info("%px: nss_l2tpv2_tx() CREATE successful\n", nss_ctx); +- +- /* +- * Check if we need to bind the L2TP to an IPsec interface. This is required as per RFC3193 +- */ +- nss_connmgr_l2tpv2_bind_ipsec_by_ipaddr(nss_ctx, data, if_number); ++ nss_connmgr_l2tpv2_info("%px: nss_l2tpv2_tx() successful\n", nss_ctx); + + return NOTIFY_DONE; + } +@@ -648,6 +596,9 @@ static int nss_connmgr_l2tpv2_dev_down(s + { + struct nss_connmgr_l2tpv2_session_data *ptr; + struct hlist_node *tmp; ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 8, 0)) ++ struct hlist_node *node; ++#endif + struct nss_l2tpv2_msg l2tpv2msg; + struct nss_l2tpv2_session_destroy_msg *l2tpv2cfg; + int if_number; +@@ -671,6 +622,9 @@ static int nss_connmgr_l2tpv2_dev_down(s + } + + hash_for_each_possible_safe(l2tpv2_session_data_hash_table, ptr, ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 8, 0)) ++ node, ++#endif + tmp, hash_list, dev->ifindex) { + if (ptr->dev == dev) { + dev_put(dev); +@@ -713,7 +667,11 @@ static int nss_connmgr_l2tpv2_dev_event( + unsigned long event, void *dev) + { + struct net_device *netdev; ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 10, 0)) ++ netdev = (struct net_device *)dev; ++#else + netdev = netdev_notifier_info_to_dev(dev); ++#endif + + switch (event) { + case NETDEV_UP: +@@ -736,6 +694,9 @@ static int nss_connmgr_l2tpv2_dev_event( + int nss_connmgr_l2tpv2_get_data(struct net_device *dev, struct nss_connmgr_l2tpv2_data *data) + { + struct nss_connmgr_l2tpv2_session_data *ptr; ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 8, 0)) ++ struct hlist_node *node; ++#endif + if (!data) { + nss_connmgr_l2tpv2_info("nss_connmgr_l2tpv2_data ptr is null\n"); + return -EINVAL; +@@ -743,6 +704,9 @@ int nss_connmgr_l2tpv2_get_data(struct n + + rcu_read_lock(); + hash_for_each_possible_rcu(l2tpv2_session_data_hash_table, ptr, ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 8, 0)) ++ node, ++#endif + hash_list, dev->ifindex) { + if (ptr->dev == dev) { + memcpy(data, &ptr->data, sizeof(struct nss_connmgr_l2tpv2_data)); +@@ -763,9 +727,15 @@ EXPORT_SYMBOL(nss_connmgr_l2tpv2_get_dat + int nss_connmgr_l2tpv2_does_connmgr_track(const struct net_device *dev) + { + struct nss_connmgr_l2tpv2_session_data *ptr; ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 8, 0)) ++ struct hlist_node *node; ++#endif + + rcu_read_lock(); + hash_for_each_possible_rcu(l2tpv2_session_data_hash_table, ptr, ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 8, 0)) ++ node, ++#endif + hash_list, dev->ifindex) { + if (ptr->dev == dev) { + rcu_read_unlock(); +@@ -779,83 +749,6 @@ int nss_connmgr_l2tpv2_does_connmgr_trac + EXPORT_SYMBOL(nss_connmgr_l2tpv2_does_connmgr_track); + + /* +- * l2tpmgr_register_ipsecmgr_callback_by_ipaddr() +- * Register IPSecmgr callback. +- */ +-void l2tpmgr_register_ipsecmgr_callback_by_ipaddr(struct l2tpmgr_ipsecmgr_cb *cb) +-{ +- get_ipsec_ifnum_by_ip_addr_callback_t ipsec_get_ifnum_by_ip_addr; +- +- rcu_read_lock(); +- ipsec_get_ifnum_by_ip_addr = rcu_dereference(ipsecmgr_cb.get_ifnum_by_ip_addr); +- if (ipsec_get_ifnum_by_ip_addr) { +- rcu_read_unlock(); +- nss_connmgr_l2tpv2_info("%px: IPSecmgr Callback get_ifnum_by_ip_addr is already registered\n", cb); +- return; +- } +- rcu_read_unlock(); +- +- if (cb->get_ifnum_by_ip_addr == NULL) { +- nss_connmgr_l2tpv2_warning("%px: IPSecmgr Callback get_ifnum_by_ip_addr is NULL\n", cb); +- return; +- } +- +- rcu_assign_pointer(ipsecmgr_cb.get_ifnum_by_ip_addr, cb->get_ifnum_by_ip_addr); +- synchronize_rcu(); +-} +-EXPORT_SYMBOL(l2tpmgr_register_ipsecmgr_callback_by_ipaddr); +- +-/* +- * l2tpmgr_unregister_ipsecmgr_callback_by_ipaddr +- * Unregister callback. +- */ +-void l2tpmgr_unregister_ipsecmgr_callback_by_ipaddr(void) +-{ +- rcu_assign_pointer(ipsecmgr_cb.get_ifnum_by_ip_addr, NULL); +- synchronize_rcu(); +-} +-EXPORT_SYMBOL(l2tpmgr_unregister_ipsecmgr_callback_by_ipaddr); +- +-#if defined(NSS_L2TP_IPSEC_BIND_BY_NETDEV) +-/* +- * l2tpmgr_register_ipsecmgr_callback_by_netdev() +- * Register IPSecmgr callback. +- */ +-void l2tpmgr_register_ipsecmgr_callback_by_netdev(struct l2tpmgr_ipsecmgr_cb *cb) +-{ +- get_ipsec_ifnum_by_dev_callback_t ipsec_get_ifnum_by_dev; +- +- rcu_read_lock(); +- ipsec_get_ifnum_by_dev = rcu_dereference(ipsecmgr_cb.get_ifnum_by_dev); +- if (ipsec_get_ifnum_by_dev) { +- rcu_read_unlock(); +- nss_connmgr_l2tpv2_info("%px: IPSecmgr Callback get_ifnum_by_dev is already registered\n", cb); +- return; +- } +- rcu_read_unlock(); +- +- if (cb->get_ifnum_by_dev == NULL) { +- nss_connmgr_l2tpv2_warning("%px: IPSecmgr Callback get_ifnum_by_dev is NULL\n", cb); +- return; +- } +- +- rcu_assign_pointer(ipsecmgr_cb.get_ifnum_by_dev, cb->get_ifnum_by_dev); +- synchronize_rcu(); +-} +-EXPORT_SYMBOL(l2tpmgr_register_ipsecmgr_callback_by_netdev); +- +-/* +- * l2tpmgr_unregister_ipsecmgr_callback_by_netdev +- * Unregister callback. +- */ +-void l2tpmgr_unregister_ipsecmgr_callback_by_netdev(void) +-{ +- rcu_assign_pointer(ipsecmgr_cb.get_ifnum_by_dev, NULL); +- synchronize_rcu(); +-} +-EXPORT_SYMBOL(l2tpmgr_unregister_ipsecmgr_callback_by_netdev); +- +-/* + * nss_connmgr_l2tpv2_proc_handler() + * Read and write handler for sysctl. + */ +@@ -866,14 +759,13 @@ static int nss_connmgr_l2tpv2_proc_handl + char *l2tp_device_name, *ipsec_device_name; + char *input_str = l2tpoipsec_config; + int32_t l2tp_ifnum, ipsec_ifnum; +- struct net_device *l2tpdev, *ipsecdev; ++ struct net_device *l2tpdev, *ipsecdev, *ipsectundev; + nss_tx_status_t status; + struct nss_l2tpv2_msg l2tpv2msg; +- get_ipsec_ifnum_by_dev_callback_t ipsec_cb; +- struct nss_l2tpv2_bind_ipsec_if_msg *l2tpv2_bind_ipsec_msg; ++ get_ipsec_tundev_callback_t ipsec_cb; ++ struct nss_l2tpv2_bind_ipsec_if_msg *l2tpv2_bind_ipsec_if; + struct nss_ctx_instance *nss_ctx = nss_l2tpv2_get_context(); + int ret = proc_dostring(ctl, write, buffer, lenp, ppos); +- struct nss_connmgr_l2tpv2_session_data *ptr; + + if (!write) { + nss_connmgr_l2tpv2_info("command to write is echo > \n"); +@@ -900,19 +792,6 @@ static int nss_connmgr_l2tpv2_proc_handl + return -EINVAL; + } + +- rcu_read_lock(); +- hash_for_each_possible_rcu(l2tpv2_session_data_hash_table, ptr, +- hash_list, l2tpdev->ifindex) { +- if (ptr->dev != l2tpdev) { +- continue; +- } +- +- if (ptr->data.l2tpv2.tunnel.udp_csum) { +- nss_connmgr_l2tpv2_info("Enabling UDP checksum in L2TP packet is not supported for l2tpoipsec flow\n"); +- } +- } +- rcu_read_unlock(); +- + ipsecdev = dev_get_by_name(&init_net, ipsec_device_name); + if (!ipsecdev) { + nss_connmgr_l2tpv2_info("Cannot find the netdevice associated with %s\n", ipsec_device_name); +@@ -931,7 +810,7 @@ static int nss_connmgr_l2tpv2_proc_handl + } + + rcu_read_lock(); +- ipsec_cb = rcu_dereference(ipsecmgr_cb.get_ifnum_by_dev); ++ ipsec_cb = rcu_dereference(ipsecmgr_cb.cb); + if (!ipsec_cb) { + rcu_read_unlock(); + nss_connmgr_l2tpv2_info("Callback to get IPsec tun device not registered"); +@@ -940,13 +819,27 @@ static int nss_connmgr_l2tpv2_proc_handl + } + + /* +- * Get NSS ifnum for IPsec interface. ++ * Get the dummy netdevice used to register this IPSec ++ * device with NSS from the ipsecmgr module. This is ++ * needed for looking up the NSS ifnum for the IPSec ++ * netdevice. + */ +- ipsec_ifnum = ipsec_cb(ipsecdev); ++ ipsectundev = ipsec_cb(ipsecdev); + rcu_read_unlock(); ++ if (!ipsectundev) { ++ nss_connmgr_l2tpv2_info("Cannot get the device from IPSecmgr for %s\n", ipsec_device_name); ++ ret = -ENODEV; ++ goto exit; ++ } ++ ++ /* ++ * Get NSS ifnum for IPsec interface. ++ */ ++ ipsec_ifnum = nss_cmn_get_interface_number_by_dev_and_type(ipsectundev, NSS_DYNAMIC_INTERFACE_TYPE_IPSEC_CMN_INNER); + if (ipsec_ifnum == -1) { + nss_connmgr_l2tpv2_info("Cannot find the NSS interface associated with %s\n", ipsec_device_name); + ret = -ENODEV; ++ dev_put(ipsectundev); + goto exit; + } + +@@ -955,14 +848,15 @@ static int nss_connmgr_l2tpv2_proc_handl + */ + memset(&l2tpv2msg, 0, sizeof(struct nss_l2tpv2_msg)); + nss_l2tpv2_msg_init(&l2tpv2msg, l2tp_ifnum, NSS_L2TPV2_MSG_BIND_IPSEC_IF, sizeof(struct nss_l2tpv2_bind_ipsec_if_msg), (void *)nss_connmgr_l2tpv2_msg_cb, NULL); +- l2tpv2_bind_ipsec_msg = &l2tpv2msg.msg.bind_ipsec_if_msg; +- l2tpv2_bind_ipsec_msg->ipsec_ifnum = ipsec_ifnum; ++ l2tpv2_bind_ipsec_if = &l2tpv2msg.msg.bind_ipsec_if_msg; ++ l2tpv2_bind_ipsec_if->ipsec_ifnum = ipsec_ifnum; + status = nss_l2tpv2_tx(nss_ctx, &l2tpv2msg); + if (status != NSS_TX_SUCCESS) { + nss_connmgr_l2tpv2_info("%px IPSec interface bind failed\n", nss_ctx); + ret = -EAGAIN; + } + ++ dev_put(ipsectundev); + exit: + dev_put(l2tpdev); + dev_put(ipsecdev); +@@ -970,6 +864,38 @@ exit: + } + + /* ++ * l2tpmgr_register_ipsecmgr_callback() ++ * Register IPSecmgr callback. ++ */ ++void l2tpmgr_register_ipsecmgr_callback(struct l2tpmgr_ipsecmgr_cb *cb) ++{ ++ get_ipsec_tundev_callback_t ipsec_cb; ++ rcu_read_lock(); ++ ipsec_cb = rcu_dereference(ipsecmgr_cb.cb); ++ if (ipsec_cb) { ++ rcu_read_unlock(); ++ nss_connmgr_l2tpv2_info("IPSecmgr Callback is already registered\n"); ++ return; ++ } ++ ++ rcu_assign_pointer(ipsecmgr_cb.cb, cb->cb); ++ rcu_read_unlock(); ++} ++EXPORT_SYMBOL(l2tpmgr_register_ipsecmgr_callback); ++ ++/* ++ * l2tpmgr_unregister_ipsecmgr_callback ++ * Unregister callback. ++ */ ++void l2tpmgr_unregister_ipsecmgr_callback(void) ++{ ++ rcu_read_lock(); ++ rcu_assign_pointer(ipsecmgr_cb.cb, NULL); ++ rcu_read_unlock(); ++} ++EXPORT_SYMBOL(l2tpmgr_unregister_ipsecmgr_callback); ++ ++/* + * nss_connmgr_l2tpv2_table + */ + static struct ctl_table nss_connmgr_l2tpv2_table[] = { +@@ -1006,7 +932,6 @@ static struct ctl_table nss_connmgr_l2tp + }, + { } + }; +-#endif + + /* + * Linux Net device Notifier +@@ -1029,20 +954,18 @@ int __init nss_connmgr_l2tpv2_init_modul + return 0; + } + #endif +-#if defined(NSS_L2TP_IPSEC_BIND_BY_NETDEV) + ctl_tbl_hdr = register_sysctl_table(nss_connmgr_l2tpv2_sysroot); + if (!ctl_tbl_hdr) { + nss_connmgr_l2tpv2_info("Unable to register sysctl table for L2TP conn mgr\n"); + return -EFAULT; + } + +-#endif + /* + * Initialize ipsecmgr callback. + */ +- rcu_assign_pointer(ipsecmgr_cb.get_ifnum_by_dev, NULL); +- rcu_assign_pointer(ipsecmgr_cb.get_ifnum_by_ip_addr, NULL); +- synchronize_rcu(); ++ rcu_read_lock(); ++ rcu_assign_pointer(ipsecmgr_cb.cb, NULL); ++ rcu_read_unlock(); + register_netdevice_notifier(&nss_connmgr_l2tpv2_notifier); + return 0; + } +--- a/l2tp/l2tpv2/nss_connmgr_l2tpv2.h ++++ b/l2tp/l2tpv2/nss_connmgr_l2tpv2.h +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2015, 2020, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -27,21 +27,13 @@ + #include + #include + #include +-#include + + #define L2TP_V_2 2 + +-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(4, 12, 0)) +-#define tunnel_hold(tunnel) atomic_inc(&tunnel->ref_count) +-#define tunnel_put(tunnel) atomic_dec(&tunnel->ref_count) +-#define session_hold(session) atomic_inc(&session->ref_count) +-#define session_put(session) atomic_dec(&session->ref_count) +-#else + #define tunnel_hold(tunnel) refcount_inc(&tunnel->ref_count) + #define tunnel_put(tunnel) refcount_dec(&tunnel->ref_count) + #define session_hold(session) refcount_inc(&session->ref_count) + #define session_put(session) refcount_dec(&session->ref_count) +-#endif + + /* + * ---------------------------------------------------------------------------------- +@@ -54,6 +46,7 @@ + */ + struct session_info { + u32 session_id, peer_session_id; /* local & remote session id */ ++ u16 offset; /* offset to data */ + u16 hdr_len; /* header length */ + int reorder_timeout; /* reorder timeout */ + unsigned send_seq:1; /* enable tx sequence number ? */ +--- a/l2tp/l2tpv2/nss_l2tpv2_stats.c ++++ b/l2tp/l2tpv2/nss_l2tpv2_stats.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2015, 2020, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -21,9 +21,7 @@ + */ + + #include +-#if IS_ENABLED(CONFIG_NF_FLOW_TABLE) +-#include +-#endif ++#include + #include + #include + #include +@@ -94,8 +92,6 @@ void nss_l2tpv2_update_dev_stats(struct + + dev_hold(dev); + +- memset(&l2tp_stats, 0, sizeof(struct l2tp_stats)); +- + /* + * Get tunnel id + */ +@@ -108,35 +104,37 @@ void nss_l2tpv2_update_dev_stats(struct + /* + * Update tunnel & session stats + */ +-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(4, 12, 0)) +- tunnel = l2tp_tunnel_find(dev_net(dev), data.l2tpv2.tunnel.tunnel_id); ++ tunnel = l2tp_tunnel_get(dev_net(dev), data.l2tpv2.tunnel.tunnel_id); + if (!tunnel) { + dev_put(dev); + return; + } + tunnel_hold(tunnel); + +- session = l2tp_session_find(dev_net(dev), tunnel, data.l2tpv2.session.session_id); ++ session = l2tp_session_get(dev_net(dev), data.l2tpv2.session.session_id); + if (!session) { + tunnel_put(tunnel); + dev_put(dev); + return; + } ++ ++ memset(&l2tp_stats, 0, sizeof(struct l2tp_stats)); ++ + session_hold(session); +-#else +- tunnel = l2tp_tunnel_get(dev_net(dev), data.l2tpv2.tunnel.tunnel_id); +- if (!tunnel) { +- dev_put(dev); +- return; +- } +- session = l2tp_tunnel_get_session(tunnel, data.l2tpv2.session.session_id); +- if (!session) { +- tunnel_put(tunnel); +- dev_put(dev); +- return; +- } +-#endif + ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 8, 0)) ++ /* valid session found. Update stats */ ++ l2tp_stats.tx_packets = (u64)sync_stats->node_stats.tx_packets; ++ l2tp_stats.tx_bytes = (u64)sync_stats->node_stats.tx_bytes; ++ l2tp_stats.tx_errors = (u64)sync_stats->tx_errors; ++ ++ l2tp_stats.rx_packets = (u64)sync_stats->node_stats.rx_packets; ++ l2tp_stats.rx_bytes = (u64)sync_stats->node_stats.rx_bytes; ++ l2tp_stats.rx_errors = (u64)sync_stats->rx_errors; ++ ++ l2tp_stats.rx_seq_discards = (u64)sync_stats->rx_seq_discards; ++ l2tp_stats.rx_oos_packets = (u64)sync_stats->rx_oos_packets; ++#else + atomic_long_set(&l2tp_stats.tx_packets, (long)sync_stats->node_stats.tx_packets); + atomic_long_set(&l2tp_stats.tx_bytes, (long)sync_stats->node_stats.tx_bytes); + atomic_long_set(&l2tp_stats.tx_errors, (long)sync_stats->tx_errors); +@@ -148,6 +146,7 @@ void nss_l2tpv2_update_dev_stats(struct + atomic_long_set(&l2tp_stats.rx_seq_discards, (long)sync_stats->rx_seq_discards); + atomic_long_set(&l2tp_stats.rx_oos_packets, (long)(sync_stats->rx_oos_packets)); + ++#endif + l2tp_stats_update(tunnel, session, &l2tp_stats); + + session_put(session); +--- a/lag/Makefile ++++ b/lag/Makefile +@@ -7,7 +7,7 @@ endif + ccflags-y := -I$(obj) -I$(obj)/.. + ccflags-y += -DNSS_CLIENT_BUILD_ID="$(BUILD_ID)" + ccflags-y += -DNSS_LAG_MGR_DEBUG_LEVEL=0 +-ccflags-y += -Wall -Werror ++ccflags-y += -Werror + + obj-m += qca-nss-lag-mgr.o + qca-nss-lag-mgr-objs := nss_lag.o +--- a/map/map-t/Makefile ++++ b/map/map-t/Makefile +@@ -1,7 +1,7 @@ + # Makefile for map-t client + ccflags-y += -I$(obj)/../../exports -I$(obj)/../.. -I$(obj)/nss_hal/include + ccflags-y += -DNSS_MAP_T_DEBUG_LEVEL=0 +-ccflags-y += -Wall -Werror ++ccflags-y += -Werror + obj-m += qca-nss-map-t.o + qca-nss-map-t-objs := nss_connmgr_map_t.o + +--- a/map/map-t/nss_connmgr_map_t.c ++++ b/map/map-t/nss_connmgr_map_t.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -424,15 +424,12 @@ static void nss_connmgr_map_t_decap_exce + struct ipv6hdr ip6_hdr_r; + uint8_t next_hdr, hop_limit, tclass, l4_proto; + int total_len; +- uint32_t identifier = 0; ++ uint32_t identifier; + bool df_bit = false; + uint16_t skip_sz = 0; +- struct nss_map_t_mdata *mdata; + +- mdata = (struct nss_map_t_mdata *)skb->data; +- +- /* discard meta data header */ +- skb_pull(skb, sizeof(struct nss_map_t_mdata)); ++ /* discard L2 header */ ++ skb_pull(skb, sizeof(struct ethhdr)); + skb_reset_mac_header(skb); + + skb_reset_network_header(skb); +@@ -462,12 +459,7 @@ static void nss_connmgr_map_t_decap_exce + tclass = nss_connmgr_map_t_ipv6_get_tclass(ip6_hdr); + + if (likely(next_hdr != NEXTHDR_FRAGMENT)) { +- +- /* +- * Set DF bit +- */ +- df_bit = !!(mdata->flags & NSS_MAPT_MDATA_FLAG_DF_BIT); +- ++ df_bit = true; + l4_proto = next_hdr; + } else { + struct frag_hdr tmp_fh, *fh; +@@ -504,16 +496,8 @@ static void nss_connmgr_map_t_decap_exce + ip4_hdr->tos = tclass; + if (unlikely(df_bit)) { + ip4_hdr->frag_off = htons(IP_DF); +- } +- +- if (unlikely(identifier)) { +- ip4_hdr->id = htons(identifier & 0xffff); + } else { +- /* +- * Generate the new identifier value and set it +- * in the IPv4 Identification field. +- */ +- __ip_select_ident(dev_net(dev), ip4_hdr, 1); ++ ip4_hdr->id = htons(identifier & 0xffff); + } + + skb->pkt_type = PACKET_HOST; +@@ -531,7 +515,7 @@ static void nss_connmgr_map_t_decap_exce + /* + * nss_connmgr_map_t_encap_exception() + * Exception handler registered to NSS for handling map_t ipv4 pkts +- * Send the translated ipv4 packets to the stack directly. ++ * Translates ipv4 packet back to ipv6 and send to nat46 device directly. + */ + static void nss_connmgr_map_t_encap_exception(struct net_device *dev, + struct sk_buff *skb, +@@ -539,32 +523,147 @@ static void nss_connmgr_map_t_encap_exce + + { + struct iphdr *ip4_hdr; ++ struct ipv6hdr *ip6_hdr; ++ uint8_t v6saddr[16], v6daddr[16]; ++ struct tcphdr *tcph = NULL; ++ struct udphdr *udph = NULL; ++ struct iphdr ip4_hdr_r; ++ __be16 sport, dport; ++ uint8_t nexthdr, hop_limit, tos; ++ int payload_len; ++ bool df_bit = false; ++ uint16_t append_hdr_sz = 0; ++ uint16_t identifier; ++ uint32_t l4_csum; ++ uint16_t csum; + ++ /* discard L2 header */ + skb_pull(skb, sizeof(struct ethhdr)); + skb_reset_mac_header(skb); ++ + skb_reset_network_header(skb); + + ip4_hdr = ip_hdr(skb); +- skb_set_transport_header(skb, ip4_hdr->ihl * 4); ++ skb_set_transport_header(skb, ip4_hdr->ihl*4); ++ ++ if (ip4_hdr->protocol == IPPROTO_TCP) { ++ tcph = tcp_hdr(skb); ++ l4_csum = tcph->check; ++ sport = tcph->source; ++ dport = tcph->dest; ++ } else if (ip4_hdr->protocol == IPPROTO_UDP) { ++ udph = udp_hdr(skb); ++ l4_csum = udph->check; ++ sport = udph->source; ++ dport = udph->dest; ++ } else { ++ nss_connmgr_map_t_warning("%px: Unsupported protocol, free it up\n", dev); ++ dev_kfree_skb_any(skb); ++ return; ++ } + + /* +- * IP Header checksum is not generated yet, calculate it now. ++ * Undo the checksum of the IPv4 source and destinationIPv4 address. + */ +- ip4_hdr->check = 0; +- ip4_hdr->check = ip_fast_csum((unsigned char *)ip4_hdr, ip4_hdr->ihl); ++ csum = ip_compute_csum(&ip4_hdr->saddr, 2 * sizeof(ip4_hdr->saddr)); ++ l4_csum += ((~csum) & 0xFFFF); ++ ++ /* ++ * IPv6 packet is xlated to ipv4 packet by acceleration engine. But there is no ipv4 rule. ++ * Call xlate_4_to_6() [ which is exported by nat46.ko ] to find original ipv6 src and ipv6 dest address. ++ * These functions is designed for packets from lan to wan. Since this packet is from wan, need to call ++ * this function with parameters reversed. ipv4_hdr_r is used for reversing ip addresses. ++ */ ++ ip4_hdr_r.daddr = ip4_hdr->saddr; ++ ip4_hdr_r.saddr = ip4_hdr->daddr; ++ ++ if (unlikely(!xlate_4_to_6(dev, &ip4_hdr_r, dport, sport, v6saddr, v6daddr))) { /* exception happened after packet got xlated */ ++ nss_connmgr_map_t_warning("%px: Martian ipv4 packet !!..free it. (saddr = 0x%x daddr = 0x%x sport = %d dport = %d)\n", dev,\ ++ ip4_hdr->saddr, ip4_hdr->daddr, sport, dport); ++ dev_kfree_skb_any(skb); ++ return; ++ } ++ ++ nexthdr = ip4_hdr->protocol; ++ payload_len = ntohs(ip4_hdr->tot_len) - sizeof(struct iphdr); ++ hop_limit = ip4_hdr->ttl; ++ tos = ip4_hdr->tos; ++ identifier = ntohs(ip4_hdr->id); ++ ++ if (ip4_hdr->frag_off & htons(IP_DF)) { ++ df_bit = true; ++ } else if (map_t_flags & MAPT_FLAG_ADD_DUMMY_HDR) { ++ append_hdr_sz = sizeof(struct frag_hdr); ++ } ++ ++ if (!pskb_may_pull(skb, sizeof(struct ipv6hdr) + append_hdr_sz - sizeof(struct iphdr))) { ++ nss_connmgr_map_t_warning("%px: Not enough headroom for ipv6 packet...Freeing the packet\n", dev); ++ dev_kfree_skb_any(skb); ++ return; ++ } ++ ++ skb_push(skb, sizeof(struct ipv6hdr) + append_hdr_sz - sizeof(struct iphdr)); ++ skb_reset_network_header(skb); ++ skb_reset_mac_header(skb); ++ ++ skb->protocol = htons(ETH_P_IPV6); ++ ++ ip6_hdr = ipv6_hdr(skb); ++ memset(ip6_hdr, 0, sizeof(struct ipv6hdr)); ++ ++ ip6_hdr->version = 6; ++ ip6_hdr->payload_len = htons(payload_len + append_hdr_sz); ++ ip6_hdr->hop_limit = hop_limit; ++ ++ nss_connmgr_map_t_ipv6_set_tclass(ip6_hdr, tos); ++ memcpy(&ip6_hdr->daddr, v6saddr, sizeof(struct in6_addr)); ++ memcpy(&ip6_hdr->saddr, v6daddr, sizeof(struct in6_addr)); ++ ++ if (unlikely(df_bit) || !(map_t_flags & MAPT_FLAG_ADD_DUMMY_HDR)) { ++ ip6_hdr->nexthdr = nexthdr; ++ } else { ++ struct frag_hdr tmp_fh, *fh; ++ const __be32 *fh_addr = skb_header_pointer(skb, sizeof(struct ipv6hdr), sizeof(struct frag_hdr), &tmp_fh); ++ if (!fh_addr) { ++ nss_connmgr_map_t_warning("%px: Not able to offset to frag header\n", dev); ++ dev_kfree_skb_any(skb); ++ return; ++ } ++ fh = (struct frag_hdr *)fh_addr; ++ memset(fh, 0, sizeof(struct frag_hdr)); ++ fh->identification = htonl(identifier); ++ fh->nexthdr = nexthdr; ++ ip6_hdr->nexthdr = NEXTHDR_FRAGMENT; ++ } ++ ++ skb_set_transport_header(skb, sizeof(struct ipv6hdr) + append_hdr_sz); ++ ++ /* ++ * Add the checksum of the IPv6 source and destination address. ++ */ ++ l4_csum += ip_compute_csum(ip6_hdr->saddr.s6_addr16, 2 * sizeof(ip6_hdr->saddr)); ++ ++ /* ++ * Fold the 32 bits checksum to 16 bits ++ */ ++ l4_csum = (l4_csum & 0x0000FFFF) + (l4_csum >> 16); ++ l4_csum = (l4_csum & 0x0000FFFF) + (l4_csum >> 16); ++ ++ if (nexthdr == IPPROTO_TCP) { ++ tcph->check = (uint16_t)l4_csum; ++ } else { ++ udph->check = (uint16_t)l4_csum; ++ } + +- skb->protocol = htons(ETH_P_IP); + skb->pkt_type = PACKET_HOST; + skb->skb_iif = dev->ifindex; + skb->ip_summed = CHECKSUM_NONE; + skb->dev = dev; + +- nss_connmgr_map_t_trace("%px: ipv4 packet exceptioned after v6/v4xlat src=%pI4 dest=%pI4 proto=%d\n", +- dev, &ip4_hdr->saddr, &ip4_hdr->daddr, ip4_hdr->protocol); +- /* +- * Go through Linux network stack. +- */ +- netif_receive_skb(skb); ++ nss_connmgr_map_t_trace("%px: ipv4 packet exceptioned after v6 ---> v4 xlate, created original ipv6 packet\n", dev); ++ nss_connmgr_map_t_trace("%p: Calculted ipv6 params: src_addr=%pI6, dest_addr=%pI6, payload_len=%d, checksum=%x\n", dev, v6saddr, v6daddr, payload_len, l4_csum); ++ ++ dev_queue_xmit(skb); + return; + } + +--- a/match/nss_match_priv.h ++++ b/match/nss_match_priv.h +@@ -29,19 +29,19 @@ + /* + * Statically compile messages at different levels + */ +-#if (NSS_match_DEBUG_LEVEL < 2) ++#if (NSS_MATCH_DEBUG_LEVEL < 2) + #define nss_match_warn(s, ...) + #else + #define nss_match_warn(s, ...) pr_warn("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__) + #endif + +-#if (NSS_match_DEBUG_LEVEL < 3) ++#if (NSS_MATCH_DEBUG_LEVEL < 3) + #define nss_match_info(s, ...) + #else + #define nss_match_info(s, ...) pr_notice("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__) + #endif + +-#if (NSS_match_DEBUG_LEVEL < 4) ++#if (NSS_MATCH_DEBUG_LEVEL < 4) + #define nss_match_trace(s, ...) + #else + #define nss_match_trace(s, ...) pr_info("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__) +--- a/mirror/Makefile ++++ b/mirror/Makefile +@@ -2,7 +2,7 @@ + + ccflags-y += $(NSS_CCFLAGS) -I$(obj)/../../exports + ccflags-y += -DNSS_MIRROR_DEBUG_LEVEL=2 +-ccflags-y += -Wall -Werror ++ccflags-y += -Werror + + obj-m += qca-nss-mirror.o + qca-nss-mirror-objs := \ +--- a/mirror/nss_mirror.c ++++ b/mirror/nss_mirror.c +@@ -1,6 +1,6 @@ + /* + *************************************************************************** +- * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above +@@ -180,28 +180,6 @@ static struct rtnl_link_stats64 *nss_mir + return stats; + } + +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0)) +-/* +- * nss_mirror_netdev_stats64() +- * Netdev ops function to retrieve stats for kernel version < 4.6 +- */ +-static struct rtnl_link_stats64 *nss_mirror_netdev_stats64(struct net_device *dev, +- struct rtnl_link_stats64 *tot) +-{ +- return nss_mirror_get_stats(dev, tot); +-} +-#else +-/* +- * nss_mirror_netdev_stats64() +- * Netdev ops function to retrieve stats +- */ +-static void nss_mirror_netdev_stats64(struct net_device *dev, +- struct rtnl_link_stats64 *tot) +-{ +- nss_mirror_get_stats(dev, tot); +-} +-#endif +- + /* + * nss_mirror_netdev_ops + * Mirror net device operations. +@@ -209,7 +187,7 @@ static void nss_mirror_netdev_stats64(st + static const struct net_device_ops nss_mirror_netdev_ops = { + .ndo_open = nss_mirror_netdev_up, + .ndo_stop = nss_mirror_netdev_down, +- .ndo_get_stats64 = nss_mirror_netdev_stats64, ++ .ndo_get_stats64 = nss_mirror_get_stats, + }; + + /* +@@ -300,6 +278,10 @@ static void nss_mirror_data_cb(struct ne + return; + } + ++ nss_mirror_info("Printing 64 bytes of data\n"); ++ print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 16, 1, ++ skb->data, 64, 0); ++ + dev_hold(netdev); + + /* +--- a/mscs/Makefile ++++ /dev/null +@@ -1,7 +0,0 @@ +-# Makefile for mscs client +-ccflags-y += -I$(obj)/../exports -I$(obj)/.. +-ccflags-y += -DNSS_CLIENT_BUILD_ID="$(BUILD_ID)" +-ccflags-y += -DNSS_MSCS_DEBUG_LEVEL=2 +-ccflags-y += -Wall -Werror +-obj-m += qca-nss-mscs.o +-qca-nss-mscs-objs := nss_mscs.o +--- a/mscs/nss_mscs.c ++++ /dev/null +@@ -1,144 +0,0 @@ +-/* +- ************************************************************************** +- * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- ************************************************************************** +- */ +- +-#include +-#include +-#include +-#include +-#include +- +-#include +-#include +-#include +-#include +-#include +-#include +- +-#if defined(CONFIG_DYNAMIC_DEBUG) +- +-/* +- * Compile messakes for dynamic enable/disable +- */ +-#define nss_mscs_warning(s, ...) pr_debug("%s[%d]:" s, __func__, __LINE__, ##__VA_ARGS__) +-#define nss_mscs_info(s, ...) pr_debug("%s[%d]:" s, __func__, __LINE__, ##__VA_ARGS__) +-#define nss_mscs_trace(s, ...) pr_debug("%s[%d]:" s, __func__, __LINE__, ##__VA_ARGS__) +-#else +- +-/* +- * Statically compile messages at different levels +- */ +-#if (NSS_MSCS_DEBUG_LEVEL < 2) +-#define nss_mscs_warning(s, ...) +-#else +-#define nss_mscs_warning(s, ...) pr_warn("%s[%d]:" s, __func__, __LINE__, ##__VA_ARGS__) +-#endif +- +-#if (NSS_MSCS_DEBUG_LEVEL < 3) +-#define nss_mscs_info(s, ...) +-#else +-#define nss_mscs_info(s, ...) pr_notice("%s[%d]:" s, __func__, __LINE__, ##__VA_ARGS__) +-#endif +- +-#if (NSS_MSCS_DEBUG_LEVEL < 4) +-#define nss_mscs_trace(s, ...) +-#else +-#define nss_mscs_trace(s, ...) pr_info("%s[%d]:" s, __func__, __LINE__, ##__VA_ARGS__) +-#endif +-#endif +- +-/* +- * nss_mscs_ecm +- * Register MSCS client callback with ECM MSCS classifier to support MSCS wifi peer lookup. +- */ +-static struct ecm_classifier_mscs_callbacks nss_mscs_ecm = { +- .get_peer_priority = qca_mscs_peer_lookup_n_get_priority, +- .update_skb_priority = qca_scs_peer_lookup_n_rule_match, +-}; +- +-/* +- * nss_emesh_ecm +- * Register EMESH client callback with ECM EMSH-SAWF classifier to update peer mesh latency parameters. +- */ +-static struct ecm_classifier_emesh_sawf_callbacks nss_emesh_ecm = { +- .update_peer_mesh_latency_params = qca_mesh_latency_update_peer_parameter, +-}; +- +-/* +- * nss_mscs_init_module() +- * MSCS clinet module init function +- */ +-int __init nss_mscs_init_module(void) +-{ +-#ifdef CONFIG_OF +- /* +- * If the node is not compatible, don't do anything. +- */ +- if (!of_find_node_by_name(NULL, "nss-common")) { +- return 0; +- } +-#endif +- +- /* +- * MSCS is enabled only on supported platform +- */ +- if (!nss_cmn_get_nss_enabled()) { +- nss_mscs_warning("MSCS client is not compatible with this Platform\n"); +- return -1; +- } +- +- if (ecm_classifier_mscs_callback_register(&nss_mscs_ecm)) { +- nss_mscs_warning("ecm mscs classifier callback registration failed.\n"); +- return -1; +- } +- +- if (ecm_classifier_emesh_latency_config_callback_register(&nss_emesh_ecm)) { +- ecm_classifier_mscs_callback_unregister(); +- nss_mscs_warning("ecm mesh classifier callback registration failed.\n"); +- return -1; +- } +- +- nss_mscs_info("NSS MSCS Client loaded: %s\n", NSS_CLIENT_BUILD_ID); +- return 0; +- +-} +- +-/* +- * nss_mscs_exit_module() +- * MSCS module exit function +- */ +-void __exit nss_mscs_exit_module(void) +-{ +-#ifdef CONFIG_OF +- +- /* +- * If the node is not compatible, don't do anything. +- */ +- if (!of_find_node_by_name(NULL, "nss-common")) { +- return; +- } +-#endif +- +- ecm_classifier_mscs_callback_unregister(); +- ecm_classifier_emesh_latency_config_callback_unregister(); +- nss_mscs_info("MSCS Client unloaded\n"); +- +-} +- +-module_init(nss_mscs_init_module); +-module_exit(nss_mscs_exit_module); +- +-MODULE_LICENSE("Dual BSD/GPL"); +-MODULE_DESCRIPTION("NSS MSCS client module"); +--- a/netlink/Makefile ++++ b/netlink/Makefile +@@ -1,8 +1,9 @@ ++GRE_ENABLED := $(strip $(if $(filter $(gre), y), 1 , 0)) + CAPWAP_ENABLED := $(strip $(if $(filter $(capwapmgr), y), 1 , 0)) +-IPSEC_ENABLED := $(strip $(if $(filter $(ipsecmgr), y), 1 , 0)) ++IPSEC_ENABLED := 0 + DTLS_ENABLED := $(strip $(if $(filter $(dtlsmgr), y), 1 , 0)) + +-ccflags-y := -Wall -Werror ++ccflags-y := -Werror + ccflags-y += -I$(obj)/include + ccflags-y += -I$(obj)/../exports + ccflags-y += -DNSS_NL_DEBUG_LEVEL=4 +@@ -10,48 +11,39 @@ ccflags-y += -DNSS_CLIENT_BUILD_ID="$(BU + + ccflags-y += -DCONFIG_NSS_NLIPV4=1 + ccflags-y += -DCONFIG_NSS_NLIPV6=1 +-ccflags-y += -DCONFIG_NSS_NLOAM=1 +-ccflags-y += -DCONFIG_NSS_NLGRE_REDIR_FAMILY=1 ++ccflags-y += -DCONFIG_NSS_NLOAM=0 ++ccflags-y += -DCONFIG_NSS_NLGRE_REDIR_FAMILY=${GRE_ENABLED} + ccflags-y += -DCONFIG_NSS_NLETHRX=1 + ccflags-y += -DCONFIG_NSS_NLDYNAMIC_INTERFACE=1 + ccflags-y += -DCONFIG_NSS_NLN2H=1 +-ccflags-y += -DCONFIG_NSS_NLIPV4_REASM=1 +-ccflags-y += -DCONFIG_NSS_NLIPV6_REASM=1 ++ccflags-y += -DCONFIG_NSS_NLIPV4_REASM=0 ++ccflags-y += -DCONFIG_NSS_NLIPV6_REASM=0 + ccflags-y += -DCONFIG_NSS_NLWIFILI=1 + ccflags-y += -DCONFIG_NSS_NLLSO_RX=1 +-ccflags-y += -DCONFIG_NSS_NLMAP_T=1 +-ccflags-y += -DCONFIG_NSS_NLPPPOE=1 +-ccflags-y += -DCONFIG_NSS_NLL2TPV2=1 +-ccflags-y += -DCONFIG_NSS_NLQRFS=1 +-ccflags-y += -DCONFIG_NSS_NLPPTP=1 ++ccflags-y += -DCONFIG_NSS_NLMAP_T=0 ++ccflags-y += -DCONFIG_NSS_NLPPPOE=0 ++ccflags-y += -DCONFIG_NSS_NLL2TPV2=0 ++ccflags-y += -DCONFIG_NSS_NLPPTP=0 + ccflags-y += -DCONFIG_NSS_NLCAPWAP=${CAPWAP_ENABLED} + ccflags-y += -DCONFIG_NSS_NLIPSEC=${IPSEC_ENABLED} + ccflags-y += -DCONFIG_NSS_NLDTLS=${DTLS_ENABLED} +-ccflags-y += -DCONFIG_NSS_NLUDP_ST=1 + + qca-nss-netlink-objs := nss_nl.o +-qca-nss-netlink-objs += nss_nlgre_redir_family.o +-qca-nss-netlink-objs += nss_nlgre_redir_cmd.o +-qca-nss-netlink-objs += nss_nlgre_redir_cmn.o +-qca-nss-netlink-objs += nss_nlgre_redir.o +-qca-nss-netlink-objs += nss_nlgre_redir_lag.o + qca-nss-netlink-objs += nss_nlipv4.o + qca-nss-netlink-objs += nss_nlipv6.o +-qca-nss-netlink-objs += nss_nloam.o ++# qca-nss-netlink-objs += nss_nloam.o + qca-nss-netlink-objs += nss_nlethrx.o + qca-nss-netlink-objs += nss_nldynamic_interface.o + qca-nss-netlink-objs += nss_nln2h.o +-qca-nss-netlink-objs += nss_nlipv4_reasm.o +-qca-nss-netlink-objs += nss_nlipv6_reasm.o ++# qca-nss-netlink-objs += nss_nlipv4_reasm.o ++# qca-nss-netlink-objs += nss_nlipv6_reasm.o + qca-nss-netlink-objs += nss_nlwifili.o + qca-nss-netlink-objs += nss_nllso_rx.o +-qca-nss-netlink-objs += nss_nlmap_t.o +-qca-nss-netlink-objs += nss_nlpppoe.o +-qca-nss-netlink-objs += nss_nll2tpv2.o +-qca-nss-netlink-objs += nss_nlpptp.o +-qca-nss-netlink-objs += nss_nludp_st.o +-qca-nss-netlink-objs += nss_nlqrfs.o +- ++# qca-nss-netlink-objs += nss_nlmap_t.o ++# qca-nss-netlink-objs += nss_nlpppoe.o ++# qca-nss-netlink-objs += nss_nll2tpv2.o ++# qca-nss-netlink-objs += nss_nlpptp.o ++# + ifneq (,$(filter $(capwapmgr), y)) + qca-nss-netlink-objs += nss_nlcapwap.o + endif +@@ -60,8 +52,12 @@ ifneq (,$(filter $(dtlsmgr), y)) + qca-nss-netlink-objs += nss_nldtls.o + endif + +-ifneq (,$(filter $(ipsecmgr), y)) +-qca-nss-netlink-objs += nss_nlipsec.o ++ifneq (,$(filter $(gre), y)) ++qca-nss-netlink-objs += nss_nlgre_redir_family.o ++qca-nss-netlink-objs += nss_nlgre_redir_cmd.o ++qca-nss-netlink-objs += nss_nlgre_redir_cmn.o ++qca-nss-netlink-objs += nss_nlgre_redir.o ++qca-nss-netlink-objs += nss_nlgre_redir_lag.o + endif + + ifeq ($(SoC),$(filter $(SoC),ipq807x ipq807x_64)) +--- a/netlink/nss_nl.c ++++ b/netlink/nss_nl.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2015-2016,2018-2021 The Linux Foundation. All rights reserved. ++ * Copyright (c) 2015-2016,2018-2020 The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -35,8 +35,6 @@ + #include "nss_nlcmn_if.h" + #include "nss_nldtls.h" + #include "nss_nldtls_if.h" +-#include "nss_nlgre_redir_if.h" +-#include "nss_nlgre_redir_family.h" + #include "nss_nlipsec.h" + #include "nss_nlipsec_if.h" + #include "nss_nlipv4.h" +@@ -59,10 +57,6 @@ + #include "nss_nlc2c_tx_if.h" + #include "nss_nlc2c_rx.h" + #include "nss_nlc2c_rx_if.h" +-#include "nss_nlipv4_reasm.h" +-#include "nss_nlipv4_reasm_if.h" +-#include "nss_nlipv6_reasm.h" +-#include "nss_nlipv6_reasm_if.h" + #include "nss_nlwifili.h" + #include "nss_nlwifili_if.h" + #include "nss_nllso_rx.h" +@@ -75,10 +69,6 @@ + #include "nss_nll2tpv2_if.h" + #include "nss_nlpptp.h" + #include "nss_nlpptp_if.h" +-#include "nss_nludp_st.h" +-#include "nss_nludp_st_if.h" +-#include "nss_nlqrfs.h" +-#include "nss_nlqrfs_if.h" + + /* + * nss_nl.c +@@ -110,24 +100,6 @@ static struct nss_nl_family family_handl + }, + { + /* +- * NSS_NLIPSEC +- */ +- .name = NSS_NLIPSEC_FAMILY, /* ipsec */ +- .entry = NSS_NLIPSEC_INIT, /* init */ +- .exit = NSS_NLIPSEC_EXIT, /* exit */ +- .valid = CONFIG_NSS_NLIPSEC /* 1 or 0 */ +- }, +- { +- /* +- * NSS_NLOAM +- */ +- .name = NSS_NLOAM_FAMILY, /* oam */ +- .entry = NSS_NLOAM_INIT, /* init */ +- .exit = NSS_NLOAM_EXIT, /* exit */ +- .valid = CONFIG_NSS_NLOAM /* 1 or 0 */ +- }, +- { +- /* + * NSS_NLIPV6 + */ + .name = NSS_NLIPV6_FAMILY, /* ipv6 */ +@@ -137,24 +109,6 @@ static struct nss_nl_family family_handl + }, + { + /* +- * NSS_NLGRE_REDIR +- */ +- .name = NSS_NLGRE_REDIR_FAMILY, /* gre_redir */ +- .entry = NSS_NLGRE_REDIR_FAMILY_INIT, /* init */ +- .exit = NSS_NLGRE_REDIR_FAMILY_EXIT, /* exit */ +- .valid = CONFIG_NSS_NLGRE_REDIR_FAMILY /* 1 or 0 */ +- }, +- { +- /* +- * NSS_NLCAPWAP +- */ +- .name = NSS_NLCAPWAP_FAMILY, /* capwap */ +- .entry = NSS_NLCAPWAP_INIT, /* init */ +- .exit = NSS_NLCAPWAP_EXIT, /* exit */ +- .valid = CONFIG_NSS_NLCAPWAP /* 1 or 0 */ +- }, +- { +- /* + * NSS_NLDTLS + */ + .name = NSS_NLDTLS_FAMILY, /* dtls */ +@@ -173,15 +127,6 @@ static struct nss_nl_family family_handl + }, + { + /* +- * NSS_NLEDMA +- */ +- .name = NSS_NLEDMA_FAMILY, /* edma */ +- .entry = NSS_NLEDMA_INIT, /* init */ +- .exit = NSS_NLEDMA_EXIT, /* exit */ +- .valid = CONFIG_NSS_NLEDMA /* 1 or 0 */ +- }, +- { +- /* + * NSS_NLDYNAMIC_INTERFACE + */ + .name = NSS_NLDYNAMIC_INTERFACE_FAMILY, /* dynamic interface */ +@@ -200,42 +145,6 @@ static struct nss_nl_family family_handl + }, + { + /* +- * NSS_NLC2C_TX +- */ +- .name = NSS_NLC2C_TX_FAMILY, /* c2c_tx */ +- .entry = NSS_NLC2C_TX_INIT, /* init */ +- .exit = NSS_NLC2C_TX_EXIT, /* exit */ +- .valid = CONFIG_NSS_NLC2C_TX /* 1 or 0 */ +- }, +- { +- /* +- * NSS_NLC2C_RX +- */ +- .name = NSS_NLC2C_RX_FAMILY, /* c2c_rx */ +- .entry = NSS_NLC2C_RX_INIT, /* init */ +- .exit = NSS_NLC2C_RX_EXIT, /* exit */ +- .valid = CONFIG_NSS_NLC2C_RX /* 1 or 0 */ +- }, +- { +- /* +- * NSS_NLIPV4_REASM +- */ +- .name = NSS_NLIPV4_REASM_FAMILY, /* ipv4_reasm */ +- .entry = NSS_NLIPV4_REASM_INIT, /* init */ +- .exit = NSS_NLIPV4_REASM_EXIT, /* exit */ +- .valid = CONFIG_NSS_NLIPV4_REASM /* 1 or 0 */ +- }, +- { +- /* +- * NSS_NLIPV6_REASM +- */ +- .name = NSS_NLIPV6_REASM_FAMILY, /* ipv6_reasm */ +- .entry = NSS_NLIPV6_REASM_INIT, /* init */ +- .exit = NSS_NLIPV6_REASM_EXIT, /* exit */ +- .valid = CONFIG_NSS_NLIPV6_REASM /* 1 or 0 */ +- }, +- { +- /* + * NSS_NLWIFILI + */ + .name = NSS_NLWIFILI_FAMILY, /* wifili */ +@@ -252,62 +161,6 @@ static struct nss_nl_family family_handl + .exit = NSS_NLLSO_RX_EXIT, /* exit */ + .valid = CONFIG_NSS_NLLSO_RX /* 1 or 0 */ + }, +- { +- /* +- * NSS_NLMAP_T +- */ +- .name = NSS_NLMAP_T_FAMILY, /* map_t */ +- .entry = NSS_NLMAP_T_INIT, /* init */ +- .exit = NSS_NLMAP_T_EXIT, /* exit */ +- .valid = CONFIG_NSS_NLMAP_T /* 1 or 0 */ +- }, +- { +- /* +- * NSS_NLPPPOE +- */ +- .name = NSS_NLPPPOE_FAMILY, /* pppoe */ +- .entry = NSS_NLPPPOE_INIT, /* init */ +- .exit = NSS_NLPPPOE_EXIT, /* exit */ +- .valid = CONFIG_NSS_NLPPPOE /* 1 or 0 */ +- }, +- { +- /* +- * NSS_NLL2TPV2 +- */ +- .name = NSS_NLL2TPV2_FAMILY, /* l2tpv2 */ +- .entry = NSS_NLL2TPV2_INIT, /* init */ +- .exit = NSS_NLL2TPV2_EXIT, /* exit */ +- .valid = CONFIG_NSS_NLL2TPV2 /* 1 or 0 */ +- }, +- { +- /* +- * NSS_NLPPTP +- */ +- .name = NSS_NLPPTP_FAMILY, /* pptp */ +- .entry = NSS_NLPPTP_INIT, /* init */ +- .exit = NSS_NLPPTP_EXIT, /* exit */ +- .valid = CONFIG_NSS_NLPPTP /* 1 or 0 */ +- }, +- { +- /* +- * NSS_NLUDP_ST +- */ +- .name = NSS_NLUDP_ST_FAMILY, /* udp_st */ +- .entry = NSS_NLUDP_ST_INIT, /* init */ +- .exit = NSS_NLUDP_ST_EXIT, /* exit */ +- .valid = CONFIG_NSS_NLUDP_ST /* 1 or 0 */ +- }, +- { +- /* +- * NSS_NLQRFS +- */ +- .name = NSS_NLQRFS_FAMILY, /* qrfs */ +- .entry = NSS_NLQRFS_INIT, /* init */ +- .exit = NSS_NLQRFS_EXIT, /* exit */ +- .valid = CONFIG_NSS_NLQRFS /* 1 or 0 */ +- }, +- +- + }; + + #define NSS_NL_FAMILY_HANDLER_SZ ARRAY_SIZE(family_handlers) +--- a/netlink/nss_nl.h ++++ b/netlink/nss_nl.h +@@ -25,6 +25,7 @@ + #define NSS_NL_DEBUG_LVL_WARN 2 + #define NSS_NL_DEBUG_LVL_INFO 3 + #define NSS_NL_DEBUG_LVL_TRACE 4 ++#define GENL_ID_GENERATE 0 + + + #if defined(CONFIG_DYNAMIC_DEBUG) +--- a/netlink/nss_nlcapwap.c ++++ b/netlink/nss_nlcapwap.c +@@ -1,12 +1,9 @@ + /* + ************************************************************************** + * Copyright (c) 2015-2016,2018-2020 The Linux Foundation. All rights reserved. +- * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. +- * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +- * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +@@ -39,7 +36,6 @@ + #include + #include + #include +-#include "nss_crypto_defines.h" + #include "nss_nl.h" + #include "nss_nlcapwap_if.h" + #include "nss_nlcapwap.h" +@@ -162,17 +158,6 @@ struct nss_nlcapwap_hdr { + */ + static struct nss_nlcapwap_global_ctx global_ctx; + +-static int nss_nlcapwap_ops_create_tun(struct sk_buff *skb, struct genl_info *info); +-static int nss_nlcapwap_ops_destroy_tun(struct sk_buff *skb, struct genl_info *info); +-static int nss_nlcapwap_ops_update_mtu(struct sk_buff *skb, struct genl_info *info); +-static int nss_nlcapwap_ops_dtls(struct sk_buff *skb, struct genl_info *info); +-static int nss_nlcapwap_ops_perf(struct sk_buff *skb, struct genl_info *info); +-static int nss_nlcapwap_ops_tx_packets(struct sk_buff *skb, struct genl_info *info); +-static int nss_nlcapwap_ops_meta_header(struct sk_buff *skb, struct genl_info *info); +-static int nss_nlcapwap_ops_ip_flow(struct sk_buff *skb, struct genl_info *info); +-static int nss_nlcapwap_ops_keepalive(struct sk_buff *skb, struct genl_info *info); +-static int nss_nlcapwap_ops_get_stats(struct sk_buff *skb, struct genl_info *info); +- + /* + * nss_nlcapwap_family_mcgrp + * Multicast group for sending message status & events +@@ -182,30 +167,11 @@ static const struct genl_multicast_group + }; + + /* +- * nss_nlcapwap_cmd_ops +- * Operation table called by the generic netlink layer based on the command +- */ +-struct genl_ops nss_nlcapwap_cmd_ops[] = { +- {.cmd = NSS_NLCAPWAP_CMD_TYPE_CREATE_TUN, .doit = nss_nlcapwap_ops_create_tun,}, +- {.cmd = NSS_NLCAPWAP_CMD_TYPE_DESTROY_TUN, .doit = nss_nlcapwap_ops_destroy_tun,}, +- {.cmd = NSS_NLCAPWAP_CMD_TYPE_UPDATE_MTU, .doit = nss_nlcapwap_ops_update_mtu,}, +- {.cmd = NSS_NLCAPWAP_CMD_TYPE_DTLS, .doit = nss_nlcapwap_ops_dtls,}, +- {.cmd = NSS_NLCAPWAP_CMD_TYPE_PERF, .doit = nss_nlcapwap_ops_perf,}, +- {.cmd = NSS_NLCAPWAP_CMD_TYPE_TX_PACKETS, .doit = nss_nlcapwap_ops_tx_packets,}, +- {.cmd = NSS_NLCAPWAP_CMD_TYPE_META_HEADER, .doit = nss_nlcapwap_ops_meta_header,}, +- {.cmd = NSS_NLCAPWAP_CMD_TYPE_IP_FLOW, .doit = nss_nlcapwap_ops_ip_flow,}, +- {.cmd = NSS_NLCAPWAP_CMD_TYPE_KEEPALIVE, .doit = nss_nlcapwap_ops_keepalive,}, +- {.cmd = NSS_STATS_EVENT_NOTIFY, .doit = nss_nlcapwap_ops_get_stats,}, +-}; +- +-/* + * nss_nlcapwap_family + * Capwap family definition + */ + struct genl_family nss_nlcapwap_family = { +-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(4, 9, 0)) + .id = GENL_ID_GENERATE, /* Auto generate ID */ +-#endif + .name = NSS_NLCAPWAP_FAMILY, /* family name string */ + .hdrsize = sizeof(struct nss_nlcapwap_rule), /* NSS NETLINK capwap rule */ + .version = NSS_NL_VER, /* Set it to NSS_NL_VER version */ +@@ -213,10 +179,6 @@ struct genl_family nss_nlcapwap_family = + .netnsok = true, + .pre_doit = NULL, + .post_doit = NULL, +- .ops = nss_nlcapwap_cmd_ops, +- .n_ops = ARRAY_SIZE(nss_nlcapwap_cmd_ops), +- .mcgrps = nss_nlcapwap_family_mcgrp, +- .n_mcgrps = ARRAY_SIZE(nss_nlcapwap_family_mcgrp) + }; + + /* +@@ -601,7 +563,6 @@ static void nss_nlcapwap_create_tun_ipv4 + } + + capwap_rule->enabled_features = features; +- capwap_rule->outer_sgt_value = nl_rule->msg.create.rule.outer_sgt_value; + + /* + * Configure IPv4 rule +@@ -1471,6 +1432,23 @@ static const struct file_operations nss_ + }; + + /* ++ * nss_nlcapwap_cmd_ops ++ * Operation table called by the generic netlink layer based on the command ++ */ ++struct genl_ops nss_nlcapwap_cmd_ops[] = { ++ {.cmd = NSS_NLCAPWAP_CMD_TYPE_CREATE_TUN, .doit = nss_nlcapwap_ops_create_tun,}, ++ {.cmd = NSS_NLCAPWAP_CMD_TYPE_DESTROY_TUN, .doit = nss_nlcapwap_ops_destroy_tun,}, ++ {.cmd = NSS_NLCAPWAP_CMD_TYPE_UPDATE_MTU, .doit = nss_nlcapwap_ops_update_mtu,}, ++ {.cmd = NSS_NLCAPWAP_CMD_TYPE_DTLS, .doit = nss_nlcapwap_ops_dtls,}, ++ {.cmd = NSS_NLCAPWAP_CMD_TYPE_PERF, .doit = nss_nlcapwap_ops_perf,}, ++ {.cmd = NSS_NLCAPWAP_CMD_TYPE_TX_PACKETS, .doit = nss_nlcapwap_ops_tx_packets,}, ++ {.cmd = NSS_NLCAPWAP_CMD_TYPE_META_HEADER, .doit = nss_nlcapwap_ops_meta_header,}, ++ {.cmd = NSS_NLCAPWAP_CMD_TYPE_IP_FLOW, .doit = nss_nlcapwap_ops_ip_flow,}, ++ {.cmd = NSS_NLCAPWAP_CMD_TYPE_KEEPALIVE, .doit = nss_nlcapwap_ops_keepalive,}, ++ {.cmd = NSS_STATS_EVENT_NOTIFY, .doit = nss_nlcapwap_ops_get_stats,}, ++}; ++ ++/* + * nss_nlcapwap_get_ifnum() + * Get the interface number corresponding to netdev + */ +--- a/netlink/nss_nldtls.c ++++ b/netlink/nss_nldtls.c +@@ -1,12 +1,9 @@ + /* + ************************************************************************** +- * Copyright (c) 2015-2016,2018-2021 The Linux Foundation. All rights reserved. +- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. +- * ++ * Copyright (c) 2015-2016,2018-2020 The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +- * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +@@ -449,7 +446,7 @@ static void nss_nldtls_data_callback(voi + * nss_nldtls_create_session() + * Create a DTLS session through dtlsmgr driver API. + */ +-static struct net_device *nss_nldtls_create_session(struct nss_nldtls_rule *nl_rule) ++static struct net_device *nss_nldtls_create_session(struct nss_nldtls_rule *nl_rule, uint32_t flags) + { + struct nss_nldtls_tun_ctx *dtls_tun_data; + struct nss_dtlsmgr_config dcfg; +@@ -466,7 +463,7 @@ static struct net_device *nss_nldtls_cre + + memset(&dcfg, 0, sizeof(struct nss_dtlsmgr_config)); + algo = nl_rule->msg.create.encap.cfg.crypto.algo; +- dcfg.flags = nl_rule->msg.create.flags | NSS_DTLSMGR_ENCAP_METADATA; ++ dcfg.flags = flags | (NSS_DTLSMGR_ENCAP_METADATA | NSS_DTLSMGR_HDR_CAPWAP); + if (algo == NSS_DTLSMGR_ALGO_AES_GCM) + dcfg.flags |= NSS_DTLSMGR_CIPHER_MODE_GCM; + +@@ -608,11 +605,7 @@ static int nss_nldtls_create_ipv4_rule_e + ipv4.dest_port = nl_rule->msg.create.encap.cfg.sport; + ipv4.dest_port_xlate = nl_rule->msg.create.encap.cfg.sport; + +- if (nl_rule->msg.create.flags & NSS_DTLSMGR_HDR_UDPLITE) +- ipv4.protocol = IPPROTO_UDPLITE; +- else +- ipv4.protocol = IPPROTO_UDP; +- ++ ipv4.protocol = IPPROTO_UDP; + ipv4.in_vlan_tag[0] = NSS_NLDTLS_VLAN_INVALID; + ipv4.out_vlan_tag[0] = NSS_NLDTLS_VLAN_INVALID; + ipv4.in_vlan_tag[1] = NSS_NLDTLS_VLAN_INVALID; +@@ -620,8 +613,6 @@ static int nss_nldtls_create_ipv4_rule_e + + memcpy(&ipv4.src_mac[0], &nl_rule->msg.create.gmac_ifmac[0], sizeof(ipv4.src_mac)); + +- dev_put(ndev); +- + /* + * Create an ipv4 rule entry + */ +@@ -663,11 +654,7 @@ static int nss_nldtls_create_ipv6_rule_e + */ + memcpy(ipv6.src_ip, nl_rule->msg.create.encap.cfg.dip, sizeof(ipv6.src_ip)); + memcpy(ipv6.dest_ip, nl_rule->msg.create.encap.cfg.sip, sizeof(ipv6.dest_ip)); +- +- if (nl_rule->msg.create.flags & NSS_DTLSMGR_HDR_UDPLITE) +- ipv6.protocol = IPPROTO_UDPLITE; +- else +- ipv6.protocol = IPPROTO_UDP; ++ ipv6.protocol = IPPROTO_UDP; + + ipv6.in_vlan_tag[0] = NSS_NLDTLS_VLAN_INVALID; + ipv6.in_vlan_tag[1] = NSS_NLDTLS_VLAN_INVALID; +@@ -676,8 +663,6 @@ static int nss_nldtls_create_ipv6_rule_e + + memcpy(&ipv6.src_mac[0], &nl_rule->msg.create.gmac_ifmac[0], sizeof(ipv6.src_mac)); + +- dev_put(ndev); +- + /* + * Create an ipv6 rule entry + */ +@@ -744,7 +729,7 @@ static int nss_nldtls_ops_create_tun(str + * Create tunnel based on ip version + */ + if (nl_rule->msg.create.ip_version == NSS_NLDTLS_IP_VERS_4) { +- dtls_dev = nss_nldtls_create_session(nl_rule); ++ dtls_dev = nss_nldtls_create_session(nl_rule, NSS_NLDTLS_IPV4_SESSION); + if (!dtls_dev) { + nss_nl_error("%px: Unable to create dtls session for v4\n", skb); + return -EINVAL; +@@ -763,7 +748,7 @@ static int nss_nldtls_ops_create_tun(str + atomic_inc(&gbl_ctx.num_tun); + nss_nl_info("%px: Successfully created ipv4 dtls tunnel\n", skb); + } else { +- dtls_dev = nss_nldtls_create_session(nl_rule); ++ dtls_dev = nss_nldtls_create_session(nl_rule, NSS_DTLSMGR_HDR_IPV6); + if (!dtls_dev) { + nss_nl_error("%px: Unable to create dtls session for v6\n", skb); + return -EINVAL; +@@ -886,7 +871,6 @@ static int nss_nldtls_ops_update_config( + key_len = nl_rule->msg.update_config.config_update.crypto.cipher_key.len; + if (key_len > NSS_NLDTLS_CIPHER_KEY_MAX) { + nss_nl_error("Invalid cipher length: %u\n", key_len); +- dev_put(dev); + return -EINVAL; + } + +@@ -894,7 +878,6 @@ static int nss_nldtls_ops_update_config( + key_len = nl_rule->msg.update_config.config_update.crypto.auth_key.len; + if (key_len > NSS_NLDTLS_AUTH_KEY_MAX) { + nss_nl_error("Invalid authentication length: %u\n", key_len); +- dev_put(dev); + return -EINVAL; + } + +@@ -902,7 +885,6 @@ static int nss_nldtls_ops_update_config( + key_len = nl_rule->msg.update_config.config_update.crypto.nonce.len; + if (key_len > NSS_NLDTLS_NONCE_SIZE_MAX) { + nss_nl_error("Invalid nonce length: %u\n", key_len); +- dev_put(dev); + return -EINVAL; + } + +--- a/netlink/nss_nlgre_redir_cmn.c ++++ b/netlink/nss_nlgre_redir_cmn.c +@@ -1,6 +1,6 @@ + /* + *************************************************************************** +- * Copyright (c) 2015-2016, 2018-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2015-2016,2018-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -325,7 +325,7 @@ static struct rtnl_link_stats64 *nss_nlg + int i; + + for (i = 0; i < NSS_GRE_REDIR_MAX_INTERFACES; i++) { +- if (!nss_gre_redir_stats_get(i, &get_stats)) { ++ if (!nss_gre_redir_get_stats(i, &get_stats)) { + continue; + } + +@@ -340,15 +340,15 @@ static struct rtnl_link_stats64 *nss_nlg + if (found == false) + return NULL; + +- stats->tx_bytes = get_stats.tstats.tx_bytes; +- stats->tx_packets = get_stats.tstats.tx_packets; +- stats->rx_bytes = get_stats.tstats.rx_bytes; +- stats->rx_packets = get_stats.tstats.rx_packets; +- for (i = 0;i < ARRAY_SIZE(get_stats.tstats.rx_dropped); i++) { +- stats->rx_dropped += get_stats.tstats.rx_dropped[i]; ++ stats->tx_bytes = get_stats.node_stats.tx_bytes; ++ stats->tx_packets = get_stats.node_stats.tx_packets; ++ stats->rx_bytes = get_stats.node_stats.rx_bytes; ++ stats->rx_packets = get_stats.node_stats.rx_packets; ++ for (i = 0;i < ARRAY_SIZE(get_stats.node_stats.rx_dropped); i++) { ++ stats->rx_dropped += get_stats.node_stats.rx_dropped[i]; + } + +- stats->tx_dropped = get_stats.tstats.tx_dropped; ++ stats->tx_dropped = get_stats.tx_dropped; + + return stats; + } +--- a/netlink/nss_nlipsec.c ++++ b/netlink/nss_nlipsec.c +@@ -1,12 +1,9 @@ + /* + ************************************************************************** +- * Copyright (c) 2015-2016,2018-2021 The Linux Foundation. All rights reserved. +- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. +- * ++ * Copyright (c) 2015-2016,2018-2020 The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +- * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +@@ -52,8 +49,8 @@ static int nss_nlipsec_op_create_tunnel( + static int nss_nlipsec_op_destroy_tunnel(struct sk_buff *skb, struct genl_info *info); + static int nss_nlipsec_op_add_sa(struct sk_buff *skb, struct genl_info *info); + static int nss_nlipsec_op_delete_sa(struct sk_buff *skb, struct genl_info *info); +-static int nss_nlipsec_op_add_flow(struct sk_buff *skb, struct genl_info *info); +-static int nss_nlipsec_op_delete_flow(struct sk_buff *skb, struct genl_info *info); ++// static int nss_nlipsec_op_add_flow(struct sk_buff *skb, struct genl_info *info); ++// static int nss_nlipsec_op_delete_flow(struct sk_buff *skb, struct genl_info *info); + + /* + * Hold netdevice references +@@ -111,14 +108,14 @@ static struct genl_ops nss_nlipsec_ops[] + .cmd = NSS_NLIPSEC_CMD_DEL_SA, + .doit = nss_nlipsec_op_delete_sa, + }, +- { /* Add flow */ +- .cmd = NSS_NLIPSEC_CMD_ADD_FLOW, +- .doit = nss_nlipsec_op_add_flow, +- }, +- { /* Delete flow */ +- .cmd = NSS_NLIPSEC_CMD_DEL_FLOW, +- .doit = nss_nlipsec_op_delete_flow, +- }, ++ // { /* Add flow */ ++ // .cmd = NSS_NLIPSEC_CMD_ADD_FLOW, ++ // .doit = nss_nlipsec_op_add_flow, ++ // }, ++ // { /* Delete flow */ ++ // .cmd = NSS_NLIPSEC_CMD_DEL_FLOW, ++ // .doit = nss_nlipsec_op_delete_flow, ++ // }, + }; + + /* +@@ -329,7 +326,7 @@ int nss_nlipsec_get_mtu(struct net_devic + static int nss_nlipsec_op_create_tunnel(struct sk_buff *skb, struct genl_info *info) + { + struct nss_nlipsec_rule *nl_rule; +- struct nss_ipsecmgr_callback cb = {0}; ++ struct nss_ipsecmgr_callback cb; + struct nss_nlcmn *nl_cm; + struct net_device *dev; + struct sk_buff *resp; +@@ -511,8 +508,6 @@ static struct nss_nlipsec_rule *nss_nlip + dev_put(*dev); + return NULL; + } +- +- dev_put(*dev); + return nl_rule; + } + +@@ -552,7 +547,7 @@ static int nss_nlipsec_op_add_sa(struct + sa_data->cmn.keys.auth_key = sa_rule->auth_key; + sa_data->cmn.keys.nonce = sa_rule->nonce; + +- error = nss_ipsecmgr_sa_add_sync(dev, &sa_rule->tuple, sa_data, &if_num); ++ error = nss_ipsecmgr_sa_add(dev, &sa_rule->tuple, sa_data, &if_num); + if (error) { + nss_nl_error("%d: Failed to add SA for net device(%s), error:%d\n", pid, nl_rule->ifname, error); + goto free_dev; +@@ -630,72 +625,73 @@ static int nss_nlipsec_op_delete_sa(stru + * nss_nlipsec_op_add_flow() + * Add a flow + */ +-static int nss_nlipsec_op_add_flow(struct sk_buff *skb, struct genl_info *info) +-{ +- struct nss_ipsecmgr_flow_tuple *flow_tuple; +- struct nss_ipsecmgr_sa_tuple *sa_tuple; +- struct nss_nlipsec_rule *nl_rule; +- struct net_device *dev; +- uint32_t pid; +- int error = 0; +- +- nl_rule = nss_nlipsec_get_rule(info, NSS_NLIPSEC_CMD_ADD_FLOW, &dev); +- if (!nl_rule) { +- nss_nl_error("Failed to extract SA data\n"); +- return -EINVAL; +- } +- +- pid = nl_rule->cm.pid; +- nss_nl_error("%d: device(%s)", pid, dev->name); +- +- flow_tuple = &nl_rule->rule.flow.tuple; +- sa_tuple = &nl_rule->rule.flow.sa; +- +- error = nss_ipsecmgr_flow_add_sync(dev, flow_tuple, sa_tuple); +- if (error) { +- nss_nl_error("%d: Failed to add subnet for net_device(%s)", pid, nl_rule->ifname); +- } +- +- /* +- * dev_put for dev_get done on nss_nlipsec_get_rule +- */ +- dev_put(dev); +- return error; +-} ++// static int nss_nlipsec_op_add_flow(struct sk_buff *skb, struct genl_info *info) ++// { ++// struct nss_ipsecmgr_flow_tuple *flow_tuple; ++// struct nss_ipsecmgr_sa_tuple *sa_tuple; ++// struct nss_nlipsec_rule *nl_rule; ++// struct net_device *dev; ++// uint32_t pid; ++// int error = 0; ++// ++// nl_rule = nss_nlipsec_get_rule(info, NSS_NLIPSEC_CMD_ADD_FLOW, &dev); ++// if (!nl_rule) { ++// nss_nl_error("Failed to extract SA data\n"); ++// return -EINVAL; ++// } ++// ++// pid = nl_rule->cm.pid; ++// nss_nl_error("%d: device(%s)", pid, dev->name); ++// ++// flow_tuple = &nl_rule->rule.flow.tuple; ++// sa_tuple = &nl_rule->rule.flow.sa; ++// ++// //struct nss_ipsecmgr_ref *nss_ipsecmgr_flow_alloc(struct nss_ipsecmgr_priv *priv, struct nss_ipsecmgr_key *key) ++// error = nss_ipsecmgr_flow_add_sync(dev, flow_tuple, sa_tuple); ++// if (error) { ++// nss_nl_error("%d: Failed to add subnet for net_device(%s)", pid, nl_rule->ifname); ++// } ++// ++// /* ++// * dev_put for dev_get done on nss_nlipsec_get_rule ++// */ ++// dev_put(dev); ++// return error; ++// } + + /* + * nss_nlipsec_op_delete_flow() + * Delete a flow + */ +-static int nss_nlipsec_op_delete_flow(struct sk_buff *skb, struct genl_info *info) +-{ +- struct nss_ipsecmgr_flow_tuple *flow_tuple; +- struct nss_ipsecmgr_sa_tuple *sa_tuple; +- struct nss_nlipsec_rule *nl_rule; +- struct net_device *dev; +- uint32_t pid; +- int error = 0; +- +- nl_rule = nss_nlipsec_get_rule(info, NSS_NLIPSEC_CMD_DEL_FLOW, &dev); +- if (!nl_rule) { +- nss_nl_error("Failed to extract SA data\n"); +- return -EINVAL; +- } +- +- pid = nl_rule->cm.pid; +- nss_nl_error("%d: device(%s)", pid, dev->name); +- +- flow_tuple = &nl_rule->rule.flow.tuple; +- sa_tuple = &nl_rule->rule.flow.sa; +- +- nss_ipsecmgr_flow_del(dev, flow_tuple, sa_tuple); +- +- /* +- * dev_put for dev_get done on nss_nlipsec_get_rule +- */ +- dev_put(dev); +- return error; +-} ++// static int nss_nlipsec_op_delete_flow(struct sk_buff *skb, struct genl_info *info) ++// { ++// struct nss_ipsecmgr_flow_tuple *flow_tuple; ++// struct nss_ipsecmgr_sa_tuple *sa_tuple; ++// struct nss_nlipsec_rule *nl_rule; ++// struct net_device *dev; ++// uint32_t pid; ++// int error = 0; ++// ++// nl_rule = nss_nlipsec_get_rule(info, NSS_NLIPSEC_CMD_DEL_FLOW, &dev); ++// if (!nl_rule) { ++// nss_nl_error("Failed to extract SA data\n"); ++// return -EINVAL; ++// } ++// ++// pid = nl_rule->cm.pid; ++// nss_nl_error("%d: device(%s)", pid, dev->name); ++// ++// flow_tuple = &nl_rule->rule.flow.tuple; ++// sa_tuple = &nl_rule->rule.flow.sa; ++// ++// nss_ipsecmgr_flow_del(dev, flow_tuple, sa_tuple); ++// ++// /* ++// * dev_put for dev_get done on nss_nlipsec_get_rule ++// */ ++// dev_put(dev); ++// return error; ++// } + + /* + * nss_nlipsec_init() +--- a/netlink/nss_nlipv4.c ++++ b/netlink/nss_nlipv4.c +@@ -336,20 +336,6 @@ static int nss_nlipv4_verify_conn_rule(s + tuple->return_ident, tuple->flow_ident); + break; + +- case NSS_NL_IFTYPE_TUNNEL_GRE: +- /* +- * Currently this implementation is only for gre_redir +- */ +- conn->flow_interface_num = nss_nlgre_redir_cmd_get_ifnum(flow_dev, tuple->protocol); +- if (conn->flow_interface_num < 0 ) { +- nss_nl_error("%px: Failed to get flow interface number (dev:%s, type:%d)\n", +- flow_dev, flow_dev->name, flow_iftype); +- return -EINVAL; +- } +- +- conn->flow_mtu = nss_nlgre_redir_cmd_get_mtu(flow_dev, NSS_GRE_REDIR_IP_HDR_TYPE_IPV4, conn->flow_interface_num); +- break; +- + case NSS_NL_IFTYPE_VLAN: + conn->flow_interface_num = nss_cmn_get_interface_number_by_dev(vlan_dev_real_dev(flow_dev)); + if (conn->flow_interface_num < 0 ) { +@@ -396,17 +382,6 @@ static int nss_nlipv4_verify_conn_rule(s + tuple->return_ident, tuple->flow_ident); + break; + +- case NSS_NL_IFTYPE_TUNNEL_GRE: +- conn->return_interface_num = nss_nlgre_redir_cmd_get_ifnum(return_dev, tuple->protocol); +- if (conn->return_interface_num < 0 ) { +- nss_nl_error("%px: Failed to get return interface number (dev:%s, type:%d)\n", +- return_dev, return_dev->name, return_iftype); +- return -EINVAL; +- } +- +- conn->return_mtu = nss_nlgre_redir_cmd_get_mtu(return_dev, NSS_GRE_REDIR_IP_HDR_TYPE_IPV4, conn->return_interface_num); +- break; +- + case NSS_NL_IFTYPE_VLAN: + conn->return_interface_num = nss_cmn_get_interface_number_by_dev(vlan_dev_real_dev(return_dev)); + if (conn->return_interface_num < 0 ) { +@@ -623,27 +598,6 @@ static int nss_nlipv4_verify_vlan_rule(s + } + + /* +- * nss_nlipv4_verify_identifier() +- * verify and override identifier rule entries +- */ +-static int nss_nlipv4_verify_identifier(struct nss_ipv4_rule_create_msg *msg) +-{ +- struct nss_ipv4_identifier_rule *identifier = &msg->identifier; +- const size_t rule_sz = sizeof(struct nss_ipv4_identifier_rule); +- uint16_t valid; +- +- /* +- * if identifier is not valid, set identifier rule to 0 +- */ +- valid = msg->valid_flags & NSS_IPV4_RULE_CREATE_IDENTIFIER_VALID; +- if (!valid) { +- memset(identifier, 0, rule_sz); +- } +- +- return 0; +-} +- +-/* + * nss_nlipv4_process_notify() + * process notification messages from NSS + */ +@@ -823,15 +777,6 @@ static int nss_nlipv4_ops_create_rule(st + } + + /* +- * check identifier +- */ +- error = nss_nlipv4_verify_identifier(&nim->msg.rule_create); +- if (error < 0) { +- nss_nl_error("%d:invalid identifier rule information passed\n", pid); +- goto done; +- } +- +- /* + * copy the NL message for response + */ + resp = nss_nl_copy_msg(skb); +@@ -855,10 +800,6 @@ static int nss_nlipv4_ops_create_rule(st + * Push Rule to NSS + */ + tx_status = nss_ipv4_tx_sync(gbl_ctx.nss, nim); +- +- /* TODO: Handle the case where firmware has received the response +- * and there is a failure in firmware. +- */ + if (tx_status != NSS_TX_SUCCESS) { + nss_nl_error("%d:unable to send IPv4 rule create, status(%d)\n", pid, tx_status); + error = -EBUSY; +@@ -933,10 +874,6 @@ static int nss_nlipv4_ops_destroy_rule(s + * Push rule to NSS + */ + tx_status = nss_ipv4_tx_sync(gbl_ctx.nss, nim); +- +- /* TODO: Handle the case where firmware has received the response +- * and there is a failure in firmware. +- */ + if (tx_status != NSS_TX_SUCCESS) { + nss_nl_error("%d:unable to send IPv4 rule delete, status(%d)\n", pid, tx_status); + return -EBUSY; +--- a/netlink/nss_nlipv6.c ++++ b/netlink/nss_nlipv6.c +@@ -353,17 +353,6 @@ static int nss_nlipv6_verify_conn_rule(s + tuple->return_ident, tuple->flow_ident); + break; + +- case NSS_NL_IFTYPE_TUNNEL_GRE: +- conn->flow_interface_num = nss_nlgre_redir_cmd_get_ifnum(flow_dev, tuple->protocol); +- if (conn->flow_interface_num < 0 ) { +- nss_nl_error("%px: Failed to get flow interface number (dev:%s, type:%d)\n", +- flow_dev, flow_dev->name, flow_iftype); +- return -EINVAL; +- } +- +- conn->flow_mtu = nss_nlgre_redir_cmd_get_mtu(flow_dev, NSS_GRE_REDIR_IP_HDR_TYPE_IPV6, conn->flow_interface_num); +- break; +- + case NSS_NL_IFTYPE_VLAN: + conn->flow_interface_num = nss_cmn_get_interface_number_by_dev(vlan_dev_real_dev(flow_dev)); + if (conn->flow_interface_num < 0 ) { +@@ -411,17 +400,6 @@ static int nss_nlipv6_verify_conn_rule(s + tuple->return_ident, tuple->flow_ident); + break; + +- case NSS_NL_IFTYPE_TUNNEL_GRE: +- conn->return_interface_num = nss_nlgre_redir_cmd_get_ifnum(return_dev, tuple->protocol); +- if (conn->return_interface_num < 0 ) { +- nss_nl_error("%px: Failed to get return interface number (dev:%s, type:%d)\n", +- return_dev, return_dev->name, return_iftype); +- return -EINVAL; +- } +- +- conn->return_mtu = nss_nlgre_redir_cmd_get_mtu(return_dev, NSS_GRE_REDIR_IP_HDR_TYPE_IPV6, conn->return_interface_num); +- break; +- + case NSS_NL_IFTYPE_VLAN: + conn->return_interface_num = nss_cmn_get_interface_number_by_dev(vlan_dev_real_dev(return_dev)); + if (conn->return_interface_num < 0 ) { +@@ -624,27 +602,6 @@ static int nss_nlipv6_verify_vlan_rule(s + } + + /* +- * nss_nlipv6_verify_identifier() +- * verify and override identifier rule entries +- */ +-static int nss_nlipv6_verify_identifier(struct nss_ipv6_rule_create_msg *msg) +-{ +- struct nss_ipv6_identifier_rule *identifier = &msg->identifier; +- const size_t rule_sz = sizeof(struct nss_ipv6_identifier_rule); +- uint16_t valid; +- +- /* +- * if identifier is not valid, set identifier rule to 0 +- */ +- valid = msg->valid_flags & NSS_IPV6_RULE_CREATE_IDENTIFIER_VALID; +- if (!valid) { +- memset(identifier, 0, rule_sz); +- } +- +- return 0; +-} +- +-/* + * nss_nlipv6_process_notify() + * process notification messages from NSS + */ +@@ -817,15 +774,6 @@ static int nss_nlipv6_ops_create_rule(st + } + + /* +- * check identifier +- */ +- error = nss_nlipv6_verify_identifier(&nim->msg.rule_create); +- if (error < 0) { +- nss_nl_error("%d:invalid identifier rule information passed\n", pid); +- goto done; +- } +- +- /* + * copy the NL message for response + */ + resp = nss_nl_copy_msg(skb); +@@ -855,10 +803,6 @@ static int nss_nlipv6_ops_create_rule(st + * Push Rule to NSS + */ + tx_status = nss_ipv6_tx_sync(gbl_ctx.nss, nim); +- +- /* TODO: Handle the case where firmware has received the response +- * and there is a failure in firmware. +- */ + if (tx_status != NSS_TX_SUCCESS) { + nss_nl_error("%d:unable to send IPV6 rule create, status(%d)\n", pid, tx_status); + error = -EBUSY; +@@ -938,10 +882,6 @@ static int nss_nlipv6_ops_destroy_rule(s + * Push rule to NSS + */ + tx_status = nss_ipv6_tx_sync(gbl_ctx.nss, nim); +- +- /* TODO: Handle the case where firmware has received the response +- * and there is a failure in firmware. +- */ + if (tx_status != NSS_TX_SUCCESS) { + nss_nl_error("%d:unable to send IPV6 rule delete, status(%d)\n", pid, tx_status); + return -EBUSY; +--- /dev/null ++++ b/nss_connmgr_tunipip6.c +@@ -0,0 +1,503 @@ ++/* ++ ************************************************************************** ++ * Copyright (c) 2014, 2017-2018, The Linux Foundation. All rights reserved. ++ * Permission to use, copy, modify, and/or distribute this software for ++ * any purpose with or without fee is hereby granted, provided that the ++ * above copyright notice and this permission notice appear in all copies. ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT ++ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ************************************************************************** ++ */ ++ ++/* ++ * nss_tunipip6.c ++ * ++ * This file is the NSS DS-lit and IPP6 tunnel module ++ * ------------------------REVISION HISTORY----------------------------- ++ * Qualcomm Atheros 15/sep/2013 Created ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3,9,0)) ++#include ++#else ++#include ++#endif ++#include ++#include ++#include ++ ++/* ++ * NSS tunipip6 debug macros ++ */ ++#if (NSS_TUNIPIP6_DEBUG_LEVEL < 1) ++#define nss_tunipip6_assert(fmt, args...) ++#else ++#define nss_tunipip6_assert(c) if (!(c)) { BUG_ON(!(c)); } ++#endif ++ ++#if defined(CONFIG_DYNAMIC_DEBUG) ++ ++/* ++ * Compile messages for dynamic enable/disable ++ */ ++#define nss_tunipip6_warning(s, ...) pr_debug("%s[%d]:" s, __func__, __LINE__, ##__VA_ARGS__) ++#define nss_tunipip6_info(s, ...) pr_debug("%s[%d]:" s, __func__, __LINE__, ##__VA_ARGS__) ++#define nss_tunipip6_trace(s, ...) pr_debug("%s[%d]:" s, __func__, __LINE__, ##__VA_ARGS__) ++#else ++ ++/* ++ * Statically compile messages at different levels ++ */ ++#if (NSS_TUNIPIP6_DEBUG_LEVEL < 2) ++#define nss_tunipip6_warning(s, ...) ++#else ++#define nss_tunipip6_warning(s, ...) pr_warn("%s[%d]:" s, __func__, __LINE__, ##__VA_ARGS__) ++#endif ++ ++#if (NSS_TUNIPIP6_DEBUG_LEVEL < 3) ++#define nss_tunipip6_info(s, ...) ++#else ++#define nss_tunipip6_info(s, ...) pr_notice("%s[%d]:" s, __func__, __LINE__, ##__VA_ARGS__) ++#endif ++ ++#if (NSS_TUNIPIP6_DEBUG_LEVEL < 4) ++#define nss_tunipip6_trace(s, ...) ++#else ++#define nss_tunipip6_trace(s, ...) pr_info("%s[%d]:" s, __func__, __LINE__, ##__VA_ARGS__) ++#endif ++#endif ++ ++/* ++ * tunipip6 stats structure ++ */ ++struct nss_tunipip6_stats { ++ uint32_t rx_packets; /* Number of received packets */ ++ uint32_t rx_bytes; /* Number of received bytes */ ++ uint32_t tx_packets; /* Number of transmitted packets */ ++ uint32_t tx_bytes; /* Number of transmitted bytes */ ++}; ++ ++/* ++ * nss_tunipip6_encap_exception() ++ * Exception handler registered to NSS driver. ++ * ++ * This function is called when no rule is found for successful encapsulation. ++ */ ++static void nss_tunipip6_encap_exception(struct net_device *dev, struct sk_buff *skb, __attribute__((unused)) struct napi_struct *napi) ++{ ++ skb->dev = dev; ++ nss_tunipip6_info("received - %d bytes name %s ver %x\n", ++ skb->len, dev->name, (skb->data[0] >> 4)); ++ ++ skb->protocol = htons(ETH_P_IP); ++ skb_reset_network_header(skb); ++ skb->pkt_type = PACKET_HOST; ++ skb->skb_iif = dev->ifindex; ++ skb->ip_summed = CHECKSUM_NONE; ++ netif_receive_skb(skb); ++} ++ ++/* ++ * nss_tunipip6_decap_exception() ++ * Exception handler registered to NSS driver. ++ * ++ * This function is called when no rule is found for successful decapsulation. ++ */ ++static void nss_tunipip6_decap_exception(struct net_device *dev, struct sk_buff *skb, __attribute__((unused)) struct napi_struct *napi) ++{ ++ skb->dev = dev; ++ nss_tunipip6_info("received - %d bytes name %s ver %x\n", ++ skb->len, dev->name, (skb->data[0] >> 4)); ++ ++ skb->protocol = htons(ETH_P_IPV6); ++ skb_reset_network_header(skb); ++ skb->pkt_type = PACKET_HOST; ++ skb->skb_iif = dev->ifindex; ++ skb->ip_summed = CHECKSUM_NONE; ++ netif_receive_skb(skb); ++} ++ ++/* ++ * nss_tunipip6_update_dev_stats ++ * Update the Dev stats received from NetAp ++ */ ++static void nss_tunipip6_update_dev_stats(struct net_device *dev, ++ struct nss_tunipip6_stats_sync_msg *sync_stats) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) ++ struct pcpu_sw_netstats stats; ++ ++ u64_stats_init(&stats.syncp); ++ u64_stats_update_begin(&stats.syncp); ++ stats.rx_packets = sync_stats->node_stats.rx_packets; ++ stats.rx_bytes = sync_stats->node_stats.rx_bytes; ++ stats.tx_packets = sync_stats->node_stats.tx_packets; ++ stats.tx_bytes = sync_stats->node_stats.tx_bytes; ++ u64_stats_update_end(&stats.syncp); ++#else ++ struct nss_tunipip6_stats stats; ++ ++ stats.rx_packets = sync_stats->node_stats.rx_packets; ++ stats.rx_bytes = sync_stats->node_stats.rx_bytes; ++ stats.tx_packets = sync_stats->node_stats.tx_packets; ++ stats.tx_bytes = sync_stats->node_stats.tx_bytes; ++#endif ++ ++ dev->stats.rx_dropped += nss_cmn_rx_dropped_sum(&sync_stats->node_stats); ++ ip6_update_offload_stats(dev, (void *)&stats); ++ ++} ++ ++/* ++ * nss_tunipip6_event_receive() ++ * Event Callback to receive events from NSS. ++ */ ++void nss_tunipip6_event_receive(void *if_ctx, struct nss_tunipip6_msg *tnlmsg) ++{ ++ struct net_device *netdev = NULL; ++ netdev = (struct net_device *)if_ctx; ++ ++ switch (tnlmsg->cm.type) { ++ case NSS_TUNIPIP6_RX_STATS_SYNC: ++ nss_tunipip6_update_dev_stats(netdev, (struct nss_tunipip6_stats_sync_msg *)&tnlmsg->msg.stats_sync); ++ break; ++ ++ default: ++ nss_tunipip6_info("%s: Unknown Event from NSS", __func__); ++ break; ++ } ++} ++ ++/* ++ * nss_tunipip6_dev_up() ++ * IPIP6 Tunnel device i/f up handler ++ */ ++int nss_tunipip6_dev_up(struct net_device *netdev) ++{ ++ struct ip6_tnl *tunnel; ++ struct nss_tunipip6_msg tnlmsg; ++ struct nss_tunipip6_create_msg *tnlcfg; ++ struct flowi6 *fl6; ++ uint32_t fmr_number = 0; ++ int inner_ifnum, outer_ifnum; ++ uint32_t features = 0; ++ nss_tx_status_t status; ++ struct nss_ctx_instance *nss_ctx; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) ++ struct __ip6_tnl_fmr *fmr; ++#endif ++ ++ /* ++ * Validate netdev for ipv6-in-ipv4 Tunnel ++ */ ++ if (netdev->type != ARPHRD_TUNNEL6 ) { ++ return NOTIFY_DONE; ++ } ++ ++ tunnel = (struct ip6_tnl *)netdev_priv(netdev); ++ ++ /* ++ * Find the Tunnel device flow information ++ */ ++ fl6 = &tunnel->fl.u.ip6; ++ ++ nss_tunipip6_trace("%p: Tunnel Param srcaddr %x:%x:%x:%x daddr %x:%x:%x:%x\n", netdev, ++ fl6->saddr.s6_addr32[0], fl6->saddr.s6_addr32[1], ++ fl6->saddr.s6_addr32[2], fl6->saddr.s6_addr32[3], ++ fl6->daddr.s6_addr32[0], fl6->daddr.s6_addr32[1], ++ fl6->daddr.s6_addr32[2], fl6->daddr.s6_addr32[3] ); ++ nss_tunipip6_trace("%p: Hop limit %d\n", netdev, tunnel->parms.hop_limit); ++ nss_tunipip6_trace("%p: Tunnel param flag %x fl6.flowlabel %x\n", netdev, tunnel->parms.flags, fl6->flowlabel); ++ ++ inner_ifnum = nss_dynamic_interface_alloc_node(NSS_DYNAMIC_INTERFACE_TYPE_TUNIPIP6_INNER); ++ if (inner_ifnum < 0) { ++ nss_tunipip6_warning("%p: Request interface number failed\n", netdev); ++ goto inner_alloc_fail; ++ } ++ ++ outer_ifnum = nss_dynamic_interface_alloc_node(NSS_DYNAMIC_INTERFACE_TYPE_TUNIPIP6_OUTER); ++ if (outer_ifnum < 0) { ++ nss_tunipip6_warning("%p: Request interface number failed\n", netdev); ++ goto outer_alloc_fail; ++ } ++ ++ /* ++ * Register ipip6 tunnel with NSS ++ */ ++ nss_ctx = nss_register_tunipip6_if(inner_ifnum, ++ NSS_DYNAMIC_INTERFACE_TYPE_TUNIPIP6_INNER, ++ nss_tunipip6_encap_exception, ++ nss_tunipip6_event_receive, ++ netdev, ++ features); ++ if (!nss_ctx) { ++ nss_tunipip6_warning("%p: nss_register_tunipip6_if Failed\n", netdev); ++ goto inner_reg_fail; ++ } ++ ++ nss_ctx = nss_register_tunipip6_if(outer_ifnum, ++ NSS_DYNAMIC_INTERFACE_TYPE_TUNIPIP6_OUTER, ++ nss_tunipip6_decap_exception, ++ nss_tunipip6_event_receive, ++ netdev, ++ features); ++ if (!nss_ctx) { ++ nss_tunipip6_warning("%p: nss_register_tunipip6_if Failed\n", netdev); ++ goto outer_reg_fail; ++ } ++ ++ nss_tunipip6_trace("%p: nss_register_tunipip6_if Success\n", netdev); ++ ++ /* ++ * Prepare The Tunnel configuration parameter to send to nss ++ */ ++ memset(&tnlmsg, 0, sizeof(struct nss_tunipip6_msg)); ++ tnlcfg = &tnlmsg.msg.tunipip6_create; ++ ++ tnlcfg->saddr[0] = ntohl(fl6->saddr.s6_addr32[0]); ++ tnlcfg->saddr[1] = ntohl(fl6->saddr.s6_addr32[1]); ++ tnlcfg->saddr[2] = ntohl(fl6->saddr.s6_addr32[2]); ++ tnlcfg->saddr[3] = ntohl(fl6->saddr.s6_addr32[3]); ++ tnlcfg->daddr[0] = ntohl(fl6->daddr.s6_addr32[0]); ++ tnlcfg->daddr[1] = ntohl(fl6->daddr.s6_addr32[1]); ++ tnlcfg->daddr[2] = ntohl(fl6->daddr.s6_addr32[2]); ++ tnlcfg->daddr[3] = ntohl(fl6->daddr.s6_addr32[3]); ++ tnlcfg->hop_limit = tunnel->parms.hop_limit; ++ tnlcfg->flags = ntohl(tunnel->parms.flags); ++ ++ /* ++ * Flow Label In kernel is stored in big endian format. ++ */ ++ tnlcfg->flowlabel = fl6->flowlabel; ++ tnlcfg->draft03 = tunnel->parms.draft03; ++ ++ /* ++ * Configure FMR table up to MAX_FMR_NUMBER, the rest will be forwarded to BR ++ */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) ++ for (fmr = tunnel->parms.fmrs; fmr && fmr_number < NSS_TUNIPIP6_MAX_FMR_NUMBER; fmr = fmr->next, fmr_number++) { ++ tnlcfg->fmr[fmr_number].ip6_prefix[0] = ntohl(fmr->ip6_prefix.s6_addr32[0]); ++ tnlcfg->fmr[fmr_number].ip6_prefix[1] = ntohl(fmr->ip6_prefix.s6_addr32[1]); ++ tnlcfg->fmr[fmr_number].ip6_prefix[2] = ntohl(fmr->ip6_prefix.s6_addr32[2]); ++ tnlcfg->fmr[fmr_number].ip6_prefix[3] = ntohl(fmr->ip6_prefix.s6_addr32[3]); ++ tnlcfg->fmr[fmr_number].ip4_prefix = ntohl(fmr->ip4_prefix.s_addr); ++ tnlcfg->fmr[fmr_number].ip6_prefix_len = fmr->ip6_prefix_len; ++ tnlcfg->fmr[fmr_number].ip4_prefix_len = fmr->ip4_prefix_len; ++ tnlcfg->fmr[fmr_number].ea_len = fmr->ea_len; ++ tnlcfg->fmr[fmr_number].offset = fmr->offset; ++ } ++#endif ++ tnlcfg->fmr_number = fmr_number; ++ ++ /* ++ * Updating sibling_if_num for encap interface. ++ */ ++ tnlcfg->sibling_if_num = outer_ifnum; ++ ++ nss_tunipip6_trace("%p: Tunnel Param srcaddr %x:%x:%x:%x daddr %x:%x:%x:%x\n", netdev, ++ tnlcfg->saddr[0], tnlcfg->saddr[1], ++ tnlcfg->saddr[2], tnlcfg->saddr[3], ++ tnlcfg->daddr[0], tnlcfg->daddr[1], ++ tnlcfg->daddr[2], tnlcfg->daddr[3] ); ++ ++ /* ++ * Send configure message to encap interface. ++ */ ++ nss_tunipip6_msg_init(&tnlmsg, inner_ifnum, NSS_TUNIPIP6_TX_ENCAP_IF_CREATE, ++ sizeof(struct nss_tunipip6_create_msg), NULL, NULL); ++ ++ nss_tunipip6_trace("%p: Sending IPIP6 tunnel i/f up command to NSS %p\n", netdev, nss_ctx); ++ status = nss_tunipip6_tx(nss_ctx, &tnlmsg); ++ if (status != NSS_TX_SUCCESS) { ++ nss_tunipip6_warning("%p: Tunnel up command error %d\n", netdev, status); ++ goto config_fail; ++ } ++ ++ /* ++ * Updating sibling_if_num for decap interface. ++ */ ++ tnlcfg->sibling_if_num = inner_ifnum; ++ ++ /* ++ * Send configure message to decap interface. ++ */ ++ nss_tunipip6_msg_init(&tnlmsg, outer_ifnum, NSS_TUNIPIP6_TX_DECAP_IF_CREATE, ++ sizeof(struct nss_tunipip6_create_msg), NULL, NULL); ++ ++ nss_tunipip6_trace("%p: Sending IPIP6 tunnel i/f up command to NSS %p\n", netdev, nss_ctx); ++ status = nss_tunipip6_tx(nss_ctx, &tnlmsg); ++ if (status != NSS_TX_SUCCESS) { ++ nss_tunipip6_warning("%p: Tunnel up command error %d\n", netdev, status); ++ goto config_fail; ++ } ++ return NOTIFY_DONE; ++ ++config_fail: ++ nss_unregister_tunipip6_if(outer_ifnum); ++outer_reg_fail: ++ nss_unregister_tunipip6_if(inner_ifnum); ++inner_reg_fail: ++ status = nss_dynamic_interface_dealloc_node(outer_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_TUNIPIP6_OUTER); ++ if (status != NSS_TX_SUCCESS) { ++ nss_tunipip6_warning("%p: Unable to dealloc the node[%d] in the NSS fw!\n", netdev, outer_ifnum); ++ } ++outer_alloc_fail: ++ status = nss_dynamic_interface_dealloc_node(inner_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_TUNIPIP6_INNER); ++ if (status != NSS_TX_SUCCESS) { ++ nss_tunipip6_warning("%p: Unable to dealloc the node[%d] in the NSS fw!\n", netdev, inner_ifnum); ++ } ++inner_alloc_fail: ++ return NOTIFY_DONE; ++} ++ ++/* ++ * nss_tunipip6_dev_down() ++ * IPP6 Tunnel device i/f down handler ++ */ ++int nss_tunipip6_dev_down(struct net_device *netdev) ++{ ++ int inner_ifnum, outer_ifnum; ++ nss_tx_status_t status; ++ ++ /* ++ * Validate netdev for ipv6-in-ipv4 Tunnel ++ */ ++ if (netdev->type != ARPHRD_TUNNEL6) { ++ return NOTIFY_DONE; ++ } ++ ++ /* ++ * Check if tunnel ipip6 is registered ? ++ */ ++ inner_ifnum = nss_cmn_get_interface_number_by_dev_and_type(netdev, NSS_DYNAMIC_INTERFACE_TYPE_TUNIPIP6_INNER); ++ if (inner_ifnum < 0) { ++ nss_tunipip6_warning("%p: Net device is not registered with nss\n", netdev); ++ return NOTIFY_DONE; ++ } ++ ++ outer_ifnum = nss_cmn_get_interface_number_by_dev_and_type(netdev, NSS_DYNAMIC_INTERFACE_TYPE_TUNIPIP6_OUTER); ++ if (outer_ifnum < 0) { ++ nss_tunipip6_warning("%p: Net device is not registered with nss\n", netdev); ++ return NOTIFY_DONE; ++ } ++ ++ /* ++ * Un-Register IPIP6 tunnel with NSS ++ */ ++ nss_unregister_tunipip6_if(inner_ifnum); ++ nss_unregister_tunipip6_if(outer_ifnum); ++ ++ status = nss_dynamic_interface_dealloc_node(inner_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_TUNIPIP6_INNER); ++ if (status != NSS_TX_SUCCESS) { ++ nss_tunipip6_warning("%p: Dealloc node failure\n", netdev); ++ return NOTIFY_DONE; ++ } ++ ++ status = nss_dynamic_interface_dealloc_node(outer_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_TUNIPIP6_OUTER); ++ if (status != NSS_TX_SUCCESS) { ++ nss_tunipip6_warning("%p: Dealloc node failure\n", netdev); ++ return NOTIFY_DONE; ++ } ++ ++ return NOTIFY_DONE; ++} ++ ++/* ++ * nss_tunipip6_dev_event() ++ * Net device notifier for ipip6 module ++ */ ++static int nss_tunipip6_dev_event(struct notifier_block *nb, ++ unsigned long event, void *dev) ++{ ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 10, 0)) ++ struct net_device *netdev = (struct net_device *)dev; ++#else ++ struct net_device *netdev = netdev_notifier_info_to_dev(dev); ++#endif ++ ++ switch (event) { ++ case NETDEV_UP: ++ nss_tunipip6_trace("%p: NETDEV_UP :event %lu name %s\n", netdev, event, netdev->name); ++ return nss_tunipip6_dev_up(netdev); ++ ++ case NETDEV_DOWN: ++ nss_tunipip6_trace("%p: NETDEV_DOWN :event %lu name %s\n", netdev, event, netdev->name); ++ return nss_tunipip6_dev_down(netdev); ++ ++ default: ++ nss_tunipip6_trace("%p: Unhandled notifier dev %s event %x\n", netdev, netdev->name, (int)event); ++ break; ++ } ++ ++ return NOTIFY_DONE; ++} ++ ++/* ++ * Linux Net device Notifier ++ */ ++struct notifier_block nss_tunipip6_notifier = { ++ .notifier_call = nss_tunipip6_dev_event, ++}; ++ ++/* ++ * nss_tunipip6_init_module() ++ * Tunnel ipip6 module init function ++ */ ++int __init nss_tunipip6_init_module(void) ++{ ++#ifdef CONFIG_OF ++ /* ++ * If the node is not compatible, don't do anything. ++ */ ++ if (!of_find_node_by_name(NULL, "nss-common")) { ++ return 0; ++ } ++#endif ++ nss_tunipip6_info("module (platform - IPQ806x , %s) loaded\n", ++ NSS_CLIENT_BUILD_ID); ++ ++ register_netdevice_notifier(&nss_tunipip6_notifier); ++ nss_tunipip6_trace("Netdev Notifier registerd\n"); ++ ++ ++ return 0; ++} ++ ++/* ++ * nss_tunipip6_exit_module() ++ * Tunnel ipip6 module exit function ++ */ ++void __exit nss_tunipip6_exit_module(void) ++{ ++#ifdef CONFIG_OF ++ ++ /* ++ * If the node is not compatible, don't do anything. ++ */ ++ if (!of_find_node_by_name(NULL, "nss-common")) { ++ return; ++ } ++#endif ++ ++ unregister_netdevice_notifier(&nss_tunipip6_notifier); ++ nss_tunipip6_info("module unloaded\n"); ++} ++ ++module_init(nss_tunipip6_init_module); ++module_exit(nss_tunipip6_exit_module); ++ ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_DESCRIPTION("NSS tunipip6 offload manager"); +--- a/nss_qdisc/Makefile ++++ b/nss_qdisc/Makefile +@@ -9,18 +9,16 @@ endif + ccflags-y += -Wall -Werror + + obj-m += qca-nss-qdisc.o +-qca-nss-qdisc-objs := nss_bf.o \ +- nss_blackhole.o \ +- nss_codel.o \ ++qca-nss-qdisc-objs := nss_qdisc.o \ + nss_fifo.o \ +- nss_htb.o \ +- nss_prio.o \ +- nss_qdisc.o \ +- nss_qdisc_htable.o \ +- nss_qdisc_stats.o \ ++ nss_codel.o \ + nss_tbl.o \ +- nss_wred.o \ +- nss_wrr.o ++ nss_prio.o \ ++ nss_bf.o \ ++ nss_wrr.o \ ++ nss_htb.o \ ++ nss_blackhole.o \ ++ nss_wred.o + + ifeq ($(SoC),$(filter $(SoC),ipq807x ipq807x_64 ipq60xx ipq60xx_64)) + qca-nss-qdisc-objs += nss_ppe.o \ +--- a/nss_qdisc/igs/Makefile ++++ b/nss_qdisc/igs/Makefile +@@ -1,7 +1,6 @@ + # Makefile for IGS (Ingress Shaping) + + ccflags-y += $(NSS_CCFLAGS) -I$(obj)/../../exports +-ccflags-y += -DNSS_IGS_DEBUG_LEVEL=2 + ccflags-y += -Wall -Werror + + obj-m += act_nssmirred.o +--- a/nss_qdisc/igs/nss_mirred.c ++++ b/nss_qdisc/igs/nss_mirred.c +@@ -82,20 +82,24 @@ static const struct nla_policy nss_mirre + * nss_mirred_init() + * Initialize the nss mirred action. + */ +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 4, 0)) + static int nss_mirred_init(struct net *net, struct nlattr *nla, +- struct nlattr *est, struct tc_action *tc_act, int ovr, +- int bind) ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 4, 0)) ++ struct nlattr *est, struct tc_action *tc_act, int ovr, ++ int bind) ++{ ++#elif (LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0)) ++ struct nlattr *est, struct tc_action **tc_act, int ovr, ++ int bind, bool rtnl_held, struct tcf_proto *tp, ++ u32 flags, struct netlink_ext_ack *extack) + { + #else +-static int nss_mirred_init(struct net *net, struct nlattr *nla, +- struct nlattr *est, struct tc_action **tc_act, int ovr, +- int bind, bool rtnl_held, struct tcf_proto *tp, +- struct netlink_ext_ack *extack) ++ struct nlattr *est, struct tc_action **tc_act, ++ struct tcf_proto *tp, u32 flags, struct netlink_ext_ack *extack) + { ++ bool bind = flags & TCA_ACT_FLAGS_BIND; ++#endif + struct tc_action_net *tn = net_generic(net, nss_mirred_net_id); + u32 index; +-#endif + struct nlattr *arr[TC_NSS_MIRRED_MAX + 1]; + struct tc_nss_mirred *parm; + struct nss_mirred_tcf *act; +@@ -239,8 +243,13 @@ static int nss_mirred_init(struct net *n + } + + if (!ret) { ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 5, 0)) + ret = tcf_idr_create(tn, index, est, tc_act, &nss_mirred_act_ops, + bind, true); ++#else ++ ret = tcf_idr_create(tn, index, est, tc_act, &nss_mirred_act_ops, ++ bind, true, 0); ++#endif + if (ret) { + tcf_idr_cleanup(tn, index); + return ret; +--- a/nss_qdisc/nss_bf.c ++++ b/nss_qdisc/nss_bf.c +@@ -1,13 +1,9 @@ + /* + ************************************************************************** +- * Copyright (c) 2014-2017, 2019-2021, The Linux Foundation. All rights reserved. +- * +- * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. +- * ++ * Copyright (c) 2014-2017, 2019-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +- * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +@@ -178,6 +174,11 @@ static int nss_bf_change_class(struct Qd + */ + qdisc_class_hash_grow(sch, &q->clhash); + ++ /* ++ * Start the stats polling timer ++ */ ++ nss_qdisc_start_basic_stats_polling(&cl->nq); ++ + nss_qdisc_info("Class %u successfully allocated\n", classid); + } + +@@ -276,6 +277,11 @@ static void nss_bf_destroy_class(struct + nss_qdisc_put(cl->qdisc); + + /* ++ * Stop the stats polling timer and free class ++ */ ++ nss_qdisc_stop_basic_stats_polling(&cl->nq); ++ ++ /* + * Destroy the shaper in NSS + */ + nss_qdisc_destroy(&cl->nq); +@@ -290,7 +296,11 @@ static void nss_bf_destroy_class(struct + * nss_bf_delete_class() + * Detaches a class from operation, but does not destroy it. + */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) ++static int nss_bf_delete_class(struct Qdisc *sch, unsigned long arg, struct netlink_ext_ack *extack) ++#else + static int nss_bf_delete_class(struct Qdisc *sch, unsigned long arg) ++#endif + { + struct nss_bf_sched_data *q = qdisc_priv(sch); + struct nss_bf_class_data *cl = (struct nss_bf_class_data *)arg; +@@ -299,14 +309,11 @@ static int nss_bf_delete_class(struct Qd + struct nss_qdisc *nq_child = (struct nss_qdisc *)qdisc_priv(cl->qdisc); + + /* +- * If the class is the root class or has qdiscs attached, we do not +- * support deleting it. ++ * Since all classes are leaf nodes in our case, we dont have to make ++ * that check. + */ +- if ((cl == &q->root) || (cl->qdisc != &noop_qdisc)) { +- nss_qdisc_warning("Cannot delete bf class %x as it is the root " +- "class or has child qdisc attached\n", cl->nq.qos_tag); ++ if (cl == &q->root) + return -EBUSY; +- } + + /* + * The message to NSS should be sent to the parent of this class +@@ -320,22 +327,14 @@ static int nss_bf_delete_class(struct Qd + } + + sch_tree_lock(sch); ++ qdisc_reset(cl->qdisc); + qdisc_class_hash_remove(&q->clhash, &cl->cl_common); + refcnt = nss_qdisc_atomic_sub_return(&cl->nq); + sch_tree_unlock(sch); +- +- /* +- * For 5.4 and above kernels, calling nss_htb_destroy_class +- * explicitly as there is no put_class which would have called +- * nss_bf_destroy_class when refcnt becomes zero. +- */ +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)) +- nss_bf_destroy_class(sch, cl); +-#else + if (!refcnt) { + nss_qdisc_error("Reference count should not be zero for class %px\n", cl); + } +-#endif ++ + return 0; + } + +@@ -635,11 +634,6 @@ static int nss_bf_change_qdisc(struct Qd + */ + static void nss_bf_reset_class(struct nss_bf_class_data *cl) + { +- if (cl->qdisc == &noop_qdisc) { +- nss_qdisc_trace("Class %x has no child qdisc to reset\n", cl->nq.qos_tag); +- return; +- } +- + nss_qdisc_reset(cl->qdisc); + nss_qdisc_info("Nssbf class resetted %px\n", cl->qdisc); + } +@@ -721,6 +715,11 @@ static void nss_bf_destroy_qdisc(struct + qdisc_class_hash_destroy(&q->clhash); + + /* ++ * Stop the polling of basic stats ++ */ ++ nss_qdisc_stop_basic_stats_polling(&q->nq); ++ ++ /* + * Now we can go ahead and destroy the qdisc. + * Note: We dont have to detach ourself from our parent because this + * will be taken care of by the graft call. +@@ -799,6 +798,11 @@ static int nss_bf_init_qdisc(struct Qdis + return -EINVAL; + } + ++ /* ++ * Start the stats polling timer ++ */ ++ nss_qdisc_start_basic_stats_polling(&q->nq); ++ + return 0; + } + +--- a/nss_qdisc/nss_blackhole.c ++++ b/nss_qdisc/nss_blackhole.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2014, 2016-2017, 2020-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2014, 2016-2017, 2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -90,6 +90,11 @@ static void nss_blackhole_destroy(struct + { + struct nss_qdisc *nq = (struct nss_qdisc *)qdisc_priv(sch); + ++ /* ++ * Stop the polling of basic stats ++ */ ++ nss_qdisc_stop_basic_stats_polling(nq); ++ + nss_qdisc_info("destroying qdisc %x\n", sch->handle); + nss_qdisc_destroy(nq); + } +@@ -219,6 +224,11 @@ static int nss_blackhole_init(struct Qdi + return -EINVAL; + } + ++ /* ++ * Start the stats polling timer ++ */ ++ nss_qdisc_start_basic_stats_polling(nq); ++ + return 0; + } + +--- a/nss_qdisc/nss_codel.c ++++ b/nss_qdisc/nss_codel.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2014, 2016-2018, 2020-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2014, 2016-2018, 2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -155,6 +155,10 @@ static void nss_codel_destroy(struct Qdi + { + struct nss_codel_sched_data *q = qdisc_priv(sch); + ++ /* ++ * Stop the polling of basic stats ++ */ ++ nss_qdisc_stop_basic_stats_polling(&q->nq); + nss_qdisc_destroy(&q->nq); + nss_codel_flow_queues_free(q); + nss_qdisc_info("nss_codel destroyed"); +@@ -451,6 +455,11 @@ static int nss_codel_init(struct Qdisc * + return -EINVAL; + } + ++ /* ++ * Start the stats polling timer ++ */ ++ nss_qdisc_start_basic_stats_polling(nq); ++ + return 0; + } + +--- a/nss_qdisc/nss_fifo.c ++++ b/nss_qdisc/nss_fifo.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2014, 2016-2017, 2020-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2014, 2016-2017, 2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -66,6 +66,11 @@ static void nss_fifo_destroy(struct Qdis + { + struct nss_qdisc *nq = (struct nss_qdisc *)qdisc_priv(sch); + ++ /* ++ * Stop the polling of basic stats ++ */ ++ nss_qdisc_stop_basic_stats_polling(nq); ++ + nss_qdisc_destroy(nq); + nss_qdisc_info("nss_fifo destroyed"); + } +@@ -291,6 +296,11 @@ static int nss_fifo_init(struct Qdisc *s + return -EINVAL; + } + ++ /* ++ * Start the stats polling timer ++ */ ++ nss_qdisc_start_basic_stats_polling(nq); ++ + return 0; + } + +--- a/nss_qdisc/nss_htb.c ++++ b/nss_qdisc/nss_htb.c +@@ -1,13 +1,9 @@ + /* + ************************************************************************** +- * Copyright (c) 2014-2017, 2019-2021, The Linux Foundation. All rights reserved. +- * +- * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. +- * ++ * Copyright (c) 2014-2017, 2019-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +- * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +@@ -413,6 +409,11 @@ static int nss_htb_change_class(struct Q + */ + qdisc_class_hash_grow(sch, &q->clhash); + ++ /* ++ * Start the stats polling timer ++ */ ++ nss_qdisc_start_basic_stats_polling(&cl->nq); ++ + nss_qdisc_trace("class %x successfully allocated and initialized\n", classid); + } + +@@ -502,6 +503,11 @@ static void nss_htb_destroy_class(struct + nss_qdisc_put(cl->qdisc); + + /* ++ * Stop the stats polling timer and free class ++ */ ++ nss_qdisc_stop_basic_stats_polling(&cl->nq); ++ ++ /* + * Destroy the shaper in NSS + */ + nss_qdisc_destroy(&cl->nq); +@@ -516,7 +522,11 @@ static void nss_htb_destroy_class(struct + * nss_htb_delete_class() + * Detaches a class from operation, but does not destroy it. + */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) ++static int nss_htb_delete_class(struct Qdisc *sch, unsigned long arg, struct netlink_ext_ack *extack) ++#else + static int nss_htb_delete_class(struct Qdisc *sch, unsigned long arg) ++#endif + { + struct nss_htb_sched_data *q = qdisc_priv(sch); + struct nss_htb_class_data *cl = (struct nss_htb_class_data *)arg; +@@ -524,12 +534,10 @@ static int nss_htb_delete_class(struct Q + int refcnt; + + /* +- * If the class still has child nodes or qdiscs, then we do not ++ * If the class still has child nodes, then we do not + * support deleting it. + */ +- if ((cl->children) || (cl->qdisc != &noop_qdisc)) { +- nss_qdisc_warning("Cannot delete htb class %x with child nodes " +- "or qdisc attached\n", cl->nq.qos_tag); ++ if (cl->children) { + return -EBUSY; + } + +@@ -560,21 +568,16 @@ static int nss_htb_delete_class(struct Q + } + + sch_tree_lock(sch); ++ qdisc_reset(cl->qdisc); + qdisc_class_hash_remove(&q->clhash, &cl->sch_common); + + /* + * If we are root class, we dont have to update our parent. + * We simply deduct refcnt and return. +- * For 5.4 and above kernels, calling nss_htb_destroy_class +- * explicitly as there is no put_class which would have called +- * nss_htb_destroy_class when refcnt becomes zero. + */ + if (!cl->parent) { + refcnt = nss_qdisc_atomic_sub_return(&cl->nq); + sch_tree_unlock(sch); +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)) +- nss_htb_destroy_class(sch, cl); +-#endif + return 0; + } + +@@ -593,14 +596,6 @@ static int nss_htb_delete_class(struct Q + refcnt = nss_qdisc_atomic_sub_return(&cl->nq); + sch_tree_unlock(sch); + +- /* +- * For 5.4 and above kernels, calling nss_htb_destroy_class +- * explicitly as there is no put_class which would have called +- * nss_htb_destroy_class when refcnt becomes zero. +- */ +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)) +- nss_htb_destroy_class(sch, cl); +-#endif + return 0; + } + +@@ -903,11 +898,6 @@ static int nss_htb_change_qdisc(struct Q + */ + static void nss_htb_reset_class(struct nss_htb_class_data *cl) + { +- if (cl->qdisc == &noop_qdisc) { +- nss_qdisc_trace("Class %x has no child qdisc to reset\n", cl->nq.qos_tag); +- return; +- } +- + nss_qdisc_reset(cl->qdisc); + nss_qdisc_trace("htb class %x reset\n", cl->nq.qos_tag); + } +@@ -991,6 +981,11 @@ static void nss_htb_destroy_qdisc(struct + qdisc_class_hash_destroy(&q->clhash); + + /* ++ * Stop the polling of basic stats ++ */ ++ nss_qdisc_stop_basic_stats_polling(&q->nq); ++ ++ /* + * Now we can go ahead and destroy the qdisc. + * Note: We dont have to detach ourself from our parent because this + * will be taken care of by the graft call. +@@ -1066,6 +1061,11 @@ static int nss_htb_init_qdisc(struct Qdi + return -EINVAL; + } + ++ /* ++ * Start the stats polling timer ++ */ ++ nss_qdisc_start_basic_stats_polling(&q->nq); ++ + return 0; + } + +--- a/nss_qdisc/nss_ppe.c ++++ b/nss_qdisc/nss_ppe.c +@@ -1,8 +1,6 @@ + /* + ************************************************************************** + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. +- * +- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -128,7 +126,7 @@ static struct nss_ppe_res *nss_ppe_res_e + + spin_lock_bh(&ppe_port->lock); + for (i = max; i > 0; i--) { +- res = kzalloc(sizeof(struct nss_ppe_res), GFP_ATOMIC); ++ res = kzalloc(sizeof(struct nss_ppe_res), GFP_KERNEL); + if (!res) { + nss_qdisc_error("Free queue list allocation failed for port %u\n", port); + goto fail; +--- a/nss_qdisc/nss_prio.c ++++ b/nss_qdisc/nss_prio.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2014-2017, 2019-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2014-2017, 2019-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -136,6 +136,11 @@ static void nss_prio_destroy(struct Qdis + } + + /* ++ * Stop the polling of basic stats ++ */ ++ nss_qdisc_stop_basic_stats_polling(&q->nq); ++ ++ /* + * Destroy the qdisc in NSS + */ + nss_qdisc_destroy(&q->nq); +@@ -279,6 +284,10 @@ static int nss_prio_init(struct Qdisc *s + return -EINVAL; + } + ++ /* ++ * Start the stats polling timer ++ */ ++ nss_qdisc_start_basic_stats_polling(&q->nq); + return 0; + } + +--- a/nss_qdisc/nss_qdisc.c ++++ b/nss_qdisc/nss_qdisc.c +@@ -29,6 +29,9 @@ + + void *nss_qdisc_ctx; /* Shaping context for nss_qdisc */ + ++#define NSS_QDISC_COMMAND_TIMEOUT (10*HZ) /* We set 10sec to be the command */ ++ /* timeout value for messages */ ++ + /* + * Defines related to root hash maintenance + */ +@@ -36,53 +39,6 @@ void *nss_qdisc_ctx; /* Shaping contex + #define NSS_QDISC_ROOT_HASH_MASK (NSS_QDISC_ROOT_HASH_SIZE - 1) + + /* +- * nss_qdisc_get_interface_msg() +- * Returns the correct message that needs to be sent down to the NSS interface. +- */ +-int nss_qdisc_get_interface_msg(bool is_bridge, uint32_t msg_type) +-{ +- /* +- * We re-assign the message based on whether this is for the I shaper +- * or the B shaper. The is_bridge flag tells if we are on a bridge interface. +- */ +- if (is_bridge) { +- switch (msg_type) { +- case NSS_QDISC_IF_SHAPER_ASSIGN: +- return NSS_IF_BSHAPER_ASSIGN; +- case NSS_QDISC_IF_SHAPER_UNASSIGN: +- return NSS_IF_BSHAPER_UNASSIGN; +- case NSS_QDISC_IF_SHAPER_CONFIG: +- return NSS_IF_BSHAPER_CONFIG; +- default: +- nss_qdisc_info("Unknown message type for a bridge - type %d", msg_type); +- return -1; +- } +- } else { +- switch (msg_type) { +- case NSS_QDISC_IF_SHAPER_ASSIGN: +- return NSS_IF_ISHAPER_ASSIGN; +- case NSS_QDISC_IF_SHAPER_UNASSIGN: +- return NSS_IF_ISHAPER_UNASSIGN; +- case NSS_QDISC_IF_SHAPER_CONFIG: +- return NSS_IF_ISHAPER_CONFIG; +- default: +- nss_qdisc_info("Unknown message type for an interface - type %d", msg_type); +- return -1; +- } +- } +-} +- +-/* +- * nss_qdisc_msg_init() +- * Initialize the qdisc specific message +- */ +-void nss_qdisc_msg_init(struct nss_if_msg *nim, uint16_t if_num, uint32_t msg_type, uint32_t len, +- nss_if_msg_callback_t cb, void *app_data) +-{ +- nss_cmn_msg_init(&nim->cm, if_num, msg_type, len, (void *)cb, app_data); +-} +- +-/* + * nss_qdisc_interface_is_virtual() + * Return true if it is redirect or bridge interface. + */ +@@ -165,6 +121,53 @@ static int nss_qdisc_ppe_init(struct Qdi + #endif + + /* ++ * nss_qdisc_msg_init() ++ * Initialize the qdisc specific message ++ */ ++static void nss_qdisc_msg_init(struct nss_if_msg *nim, uint16_t if_num, uint32_t msg_type, uint32_t len, ++ nss_if_msg_callback_t cb, void *app_data) ++{ ++ nss_cmn_msg_init(&nim->cm, if_num, msg_type, len, (void*)cb, app_data); ++} ++ ++/* ++ * nss_qdisc_get_interface_msg() ++ * Returns the correct message that needs to be sent down to the NSS interface. ++ */ ++static inline int nss_qdisc_get_interface_msg(bool is_bridge, uint32_t msg_type) ++{ ++ /* ++ * We re-assign the message based on whether this is for the I shaper ++ * or the B shaper. The is_bridge flag tells if we are on a bridge interface. ++ */ ++ if (is_bridge) { ++ switch(msg_type) { ++ case NSS_QDISC_IF_SHAPER_ASSIGN: ++ return NSS_IF_BSHAPER_ASSIGN; ++ case NSS_QDISC_IF_SHAPER_UNASSIGN: ++ return NSS_IF_BSHAPER_UNASSIGN; ++ case NSS_QDISC_IF_SHAPER_CONFIG: ++ return NSS_IF_BSHAPER_CONFIG; ++ default: ++ nss_qdisc_info("Unknown message type for a bridge - type %d", msg_type); ++ return -1; ++ } ++ } else { ++ switch(msg_type) { ++ case NSS_QDISC_IF_SHAPER_ASSIGN: ++ return NSS_IF_ISHAPER_ASSIGN; ++ case NSS_QDISC_IF_SHAPER_UNASSIGN: ++ return NSS_IF_ISHAPER_UNASSIGN; ++ case NSS_QDISC_IF_SHAPER_CONFIG: ++ return NSS_IF_ISHAPER_CONFIG; ++ default: ++ nss_qdisc_info("Unknown message type for an interface - type %d", msg_type); ++ return -1; ++ } ++ } ++} ++ ++/* + * nss_qdisc_attach_bshaper_callback() + * Call back funtion for bridge shaper attach to an interface. + */ +@@ -609,6 +612,7 @@ static void nss_qdisc_root_cleanup_free_ + nss_qdisc_info("Root qdisc %px (type %d) free SUCCESS - response " + "type: %d\n", nq->qdisc, nq->type, + nim->msg.shaper_configure.config.response_type); ++ + nss_qdisc_root_cleanup_shaper_unassign(nq); + } + +@@ -1162,15 +1166,8 @@ unsigned int nss_qdisc_drop(struct Qdisc + */ + void nss_qdisc_reset(struct Qdisc *sch) + { +- struct nss_qdisc *nq; +- +- if(!(sch->flags & TCQ_F_NSS)) { +- qdisc_reset_queue(sch); +- nss_qdisc_info("Qdisc %px resetting non NSS qdisc\n", sch); +- return; +- } ++ struct nss_qdisc *nq = qdisc_priv(sch); + +- nq = qdisc_priv(sch); + nss_qdisc_info("Qdisc %px (type %d) resetting\n", + sch, nq->type); + +@@ -1209,10 +1206,10 @@ static bool nss_qdisc_iterate_fl(struct + return 0; + } + +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 4, 0)) +- status = tc_classify(skb, tcf, &res, false); +-#else ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0)) + status = tcf_classify(skb, tcf, &res, false); ++#else ++ status = tcf_classify(skb, NULL, tcf, &res, false); + #endif + if ((status == TC_ACT_STOLEN) || (status == TC_ACT_QUEUED)) { + return 1; +@@ -1892,7 +1889,6 @@ int nss_qdisc_configure(struct nss_qdisc + return 0; + } + +- + /* + * nss_qdisc_register_configure_callback() + * Register shaper configure callback, which gets invoked on receiving a response. +@@ -1949,11 +1945,6 @@ void nss_qdisc_destroy(struct nss_qdisc + } + + /* +- * Delete node from stats list +- */ +- nss_qdisc_stats_qdisc_detach(nq); +- +- /* + * How we begin to tidy up depends on whether we are root or child + */ + nq->pending_final_state = NSS_QDISC_STATE_IDLE; +@@ -1972,11 +1963,6 @@ void nss_qdisc_destroy(struct nss_qdisc + } + + /* +- * Stop stats polling +- */ +- nss_qdisc_stats_stop_polling(nq); +- +- /* + * Begin by freeing the root shaper node + */ + nss_qdisc_root_cleanup_free_node(nq); +@@ -2129,8 +2115,6 @@ int __nss_qdisc_init(struct Qdisc *sch, + */ + if ((sch->parent == TC_H_ROOT) && (!nq->is_class)) { + nss_qdisc_info("Qdisc %px (type %d) is root\n", nq->qdisc, nq->type); +- nss_qdisc_info("Qdisc %px dev-name %s qdisc_dev(sch)->qdisc %px, qdisc_dev(sch)->qdisc->handle %x\n", qdisc_dev(sch), qdisc_dev(sch)->name, qdisc_dev(sch)->qdisc, qdisc_dev(sch)->qdisc->handle); +- nss_qdisc_info("Qdisc %px (sch %px) is root, sch->handle %x\n", nq->qdisc, sch, sch->handle); + nq->is_root = true; + root = sch; + } else { +@@ -2188,6 +2172,8 @@ int __nss_qdisc_init(struct Qdisc *sch, + * This is to prevent mixing NSS and PPE qdisc with linux qdisc. + */ + if ((parent != TC_H_ROOT) && (root->ops->owner != THIS_MODULE)) { ++ nss_qdisc_warning("parent (%d) and TC_H_ROOT (%d))", parent, TC_H_ROOT); ++ nss_qdisc_warning("root->ops->owner (%px) and THIS_MODULE (%px))", root->ops->owner , THIS_MODULE); + nss_qdisc_warning("NSS qdisc %px (type %d) used along with non-nss qdiscs," + " or the interface is currently down", nq->qdisc, nq->type); + } +@@ -2288,11 +2274,6 @@ int __nss_qdisc_init(struct Qdisc *sch, + * If state is positive, return success + */ + if (state > 0) { +- +- /* +- * Qdisc successfully initialized, add it to stats list if its not a class +- */ +- nss_qdisc_stats_qdisc_attach(nq); + return 0; + } + +@@ -2460,15 +2441,6 @@ int __nss_qdisc_init(struct Qdisc *sch, + goto init_fail; + } + #endif +- /* +- * Initialize the stats management only for root node +- */ +- if (!nss_qdisc_stats_sync_many_init(nq)) { +- nss_qdisc_error("Qdisc %px (type %d) stats sync init failed", nq->qdisc, nq->type); +- nss_shaper_unregister_shaping(nq->nss_shaping_ctx); +- atomic_set(&nq->state, NSS_QDISC_STATE_INIT_FAILED); +- goto init_fail; +- } + + /* + * Create and send the shaper assign message to the NSS interface +@@ -2498,7 +2470,7 @@ int __nss_qdisc_init(struct Qdisc *sch, + if (igs_put) { + nss_igs_module_put(); + } +- nss_qdisc_error("init for qdisc %x timedout!\n", nq->qos_tag); ++ nss_qdisc_error("init for qdisc %x timedout!\n", nq->qos_tag); + return -1; + } + +@@ -2509,16 +2481,6 @@ int __nss_qdisc_init(struct Qdisc *sch, + if (state > 0) { + + /* +- * Qdisc successfully initialized add it to stats list if its not a class +- */ +- nss_qdisc_stats_qdisc_attach(nq); +- +- /* +- * Root node is successfully configured, start stats polling +- */ +- nss_qdisc_stats_start_polling(nq); +- +- /* + * Return if this is not a root qdisc on a bridge interface. + */ + if (!nq->is_root || !nq->is_bridge) { +@@ -2559,14 +2521,6 @@ init_fail: + } + #endif + +- +- /* +- * Clean up stats sync objects if initialized. +- */ +- if (nq->stats_wq) { +- nss_qdisc_stats_sync_many_exit(nq); +- } +- + /* + * Destroy any virtual interfaces created by us before returning a failure. + */ +@@ -2601,6 +2555,210 @@ int nss_qdisc_init(struct Qdisc *sch, st + } + + /* ++ * nss_qdisc_basic_stats_callback() ++ * Invoked after getting basic stats ++ */ ++static void nss_qdisc_basic_stats_callback(void *app_data, ++ struct nss_if_msg *nim) ++{ ++ struct nss_qdisc *nq = (struct nss_qdisc *)app_data; ++ struct Qdisc *qdisc = nq->qdisc; ++ struct gnet_stats_basic_packed *bstats; ++ struct gnet_stats_queue *qstats; ++ struct nss_shaper_node_stats_response *response; ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0)) ++ atomic_t *refcnt; ++#else ++ refcount_t *refcnt; ++#endif ++ ++ if (nim->cm.response != NSS_CMN_RESPONSE_ACK) { ++ nss_qdisc_warning("Qdisc %px (type %d): Receive stats FAILED - " ++ "response: type: %d\n", qdisc, nq->type, ++ nim->msg.shaper_configure.config.response_type); ++ atomic_sub(1, &nq->pending_stat_requests); ++ wake_up(&nq->wait_queue); ++ return; ++ } ++ ++ response = &nim->msg.shaper_configure.config.msg.shaper_node_stats_get.response; ++ ++ /* ++ * Get the right stats pointers based on whether it is a class ++ * or a qdisc. ++ */ ++ if (nq->is_class) { ++ bstats = &nq->bstats; ++ qstats = &nq->qstats; ++ refcnt = &nq->refcnt; ++ } else { ++ bstats = &qdisc->bstats; ++ qstats = &qdisc->qstats; ++ refcnt = &qdisc->refcnt; ++ qdisc->q.qlen = response->sn_stats.qlen_packets; ++ } ++ ++ /* ++ * Update qdisc->bstats ++ */ ++ spin_lock_bh(&nq->lock); ++ bstats->bytes += (__u64)response->sn_stats.delta.dequeued_bytes; ++ bstats->packets += response->sn_stats.delta.dequeued_packets; ++ ++ /* ++ * Update qdisc->qstats ++ */ ++ qstats->backlog = response->sn_stats.qlen_bytes; ++ ++ qstats->drops += (response->sn_stats.delta.enqueued_packets_dropped + ++ response->sn_stats.delta.dequeued_packets_dropped); ++ ++ /* ++ * Update qdisc->qstats ++ */ ++ qstats->qlen = response->sn_stats.qlen_packets; ++ qstats->requeues = 0; ++ qstats->overlimits += response->sn_stats.delta.queue_overrun; ++ spin_unlock_bh(&nq->lock); ++ ++ /* ++ * Shapers that maintain additional unique statistics will process them ++ * via a registered callback. So invoke if its been registered. ++ */ ++ if (nq->stats_cb) { ++ nq->stats_cb(nq, response); ++ } ++ ++ /* ++ * All access to nq fields below do not need lock protection. They ++ * do not get manipulated on different thread contexts. ++ */ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0)) ++ if (atomic_read(refcnt) == 0) { ++#else ++ if (refcount_read(refcnt) == 0) { ++#endif ++ atomic_sub(1, &nq->pending_stat_requests); ++ wake_up(&nq->wait_queue); ++ return; ++ } ++ ++ /* ++ * Requests for stats again, after 1 sec. ++ */ ++ nq->stats_get_timer.expires += HZ; ++ if (nq->stats_get_timer.expires <= jiffies) { ++ nss_qdisc_info("losing time %lu, jiffies = %lu\n", ++ nq->stats_get_timer.expires, jiffies); ++ nq->stats_get_timer.expires = jiffies + HZ; ++ } ++ add_timer(&nq->stats_get_timer); ++} ++ ++/* ++ * nss_qdisc_get_stats_timer_callback() ++ * Invoked periodically to get updated stats ++ */ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)) ++static void nss_qdisc_get_stats_timer_callback(unsigned long int data) ++#else ++static void nss_qdisc_get_stats_timer_callback(struct timer_list *tm) ++#endif ++{ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)) ++ struct nss_qdisc *nq = (struct nss_qdisc *)data; ++#else ++ struct nss_qdisc *nq = from_timer(nq, tm, stats_get_timer); ++#endif ++ ++ nss_tx_status_t rc; ++ struct nss_if_msg nim; ++ int msg_type; ++ ++ /* ++ * Create and send the shaper configure message to the NSS interface ++ */ ++ msg_type = nss_qdisc_get_interface_msg(nq->is_bridge, NSS_QDISC_IF_SHAPER_CONFIG); ++ nss_qdisc_msg_init(&nim, nq->nss_interface_number, msg_type, sizeof(struct nss_if_shaper_configure), ++ nss_qdisc_basic_stats_callback, ++ nq); ++ nim.msg.shaper_configure.config.request_type = NSS_SHAPER_CONFIG_TYPE_SHAPER_NODE_BASIC_STATS_GET; ++ nim.msg.shaper_configure.config.msg.shaper_node_stats_get.qos_tag = nq->qos_tag; ++ rc = nss_if_tx_msg(nq->nss_shaping_ctx, &nim); ++ ++ /* ++ * Check if we failed to send the stats request to NSS. ++ */ ++ if (rc != NSS_TX_SUCCESS) { ++ nss_qdisc_info("%px: stats fetch request dropped, causing " ++ "delay in stats fetch\n", nq->qdisc); ++ ++ /* ++ * Schedule the timer once again for re-trying. Since this is a ++ * re-try we schedule it 100ms from now, instead of a whole second. ++ */ ++ nq->stats_get_timer.expires = jiffies + HZ/10; ++ add_timer(&nq->stats_get_timer); ++ } ++} ++ ++/* ++ * nss_qdisc_start_basic_stats_polling() ++ * Call to initiate the stats polling timer ++ */ ++void nss_qdisc_start_basic_stats_polling(struct nss_qdisc *nq) ++{ ++ /* ++ * In case the stats polling timer is already ++ * initiated, return. This can happen only when ++ * there is a fallback from PPE to NSS qdisc. ++ */ ++ if (atomic_read(&nq->pending_stat_requests)) { ++ return; ++ } ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)) ++ init_timer(&nq->stats_get_timer); ++ nq->stats_get_timer.function = nss_qdisc_get_stats_timer_callback; ++ nq->stats_get_timer.data = (unsigned long)nq; ++#else ++ timer_setup(&nq->stats_get_timer, nss_qdisc_get_stats_timer_callback, 0); ++#endif ++ ++ nq->stats_get_timer.expires = jiffies + HZ; ++ atomic_set(&nq->pending_stat_requests, 1); ++ add_timer(&nq->stats_get_timer); ++} ++ ++/* ++ * nss_qdisc_stop_basic_stats_polling() ++ * Call to stop polling of basic stats ++ */ ++void nss_qdisc_stop_basic_stats_polling(struct nss_qdisc *nq) ++{ ++ /* ++ * If the timer was active, then delete timer and return. ++ */ ++ if (del_timer(&nq->stats_get_timer) > 0) { ++ /* ++ * The timer was still active (counting down) when it was deleted. ++ * Therefore we are sure that there are no pending stats request ++ * for which we need to wait for. We can therefore return. ++ */ ++ return; ++ } ++ ++ /* ++ * The timer has already fired, which means we have a pending stat response. ++ * We will have to wait until we have received the pending response. ++ */ ++ if (!wait_event_timeout(nq->wait_queue, atomic_read(&nq->pending_stat_requests) == 0, ++ NSS_QDISC_COMMAND_TIMEOUT)) { ++ nss_qdisc_error("Stats request command for %x timedout!\n", nq->qos_tag); ++ } ++} ++ ++/* + * nss_qdisc_gnet_stats_copy_basic() + * Wrapper around gnet_stats_copy_basic() + */ +@@ -2876,10 +3034,6 @@ static int __init nss_qdisc_module_init( + return ret; + nss_qdisc_info("nss qdisc device notifiers registered\n"); + +- if (!nss_qdisc_stats_work_queue_init()) { +- nss_qdisc_error("Failed to initialized stats workqueue thread\n"); +- } +- + #if defined(NSS_QDISC_PPE_SUPPORT) + nss_ppe_port_res_alloc(); + nss_qdisc_info("nss ppe qdsic configured"); +@@ -2899,8 +3053,6 @@ static void __exit nss_qdisc_module_exit + } + #endif + +- nss_qdisc_stats_work_queue_exit(); +- + unregister_qdisc(&nss_pfifo_qdisc_ops); + nss_qdisc_info("nsspfifo unregistered\n"); + +--- a/nss_qdisc/nss_qdisc.h ++++ b/nss_qdisc/nss_qdisc.h +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2014-2018, 2020-2021 The Linux Foundation. All rights reserved. ++ * Copyright (c) 2014-2018, 2020 The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -35,17 +35,12 @@ + #if defined(NSS_QDISC_PPE_SUPPORT) + #include "nss_ppe.h" + #endif +-#include "nss_qdisc_stats.h" +-#include "nss_qdisc_htable.h" + + #define NSS_QDISC_DEBUG_LEVEL_ERROR 1 + #define NSS_QDISC_DEBUG_LEVEL_WARN 2 + #define NSS_QDISC_DEBUG_LEVEL_INFO 3 + #define NSS_QDISC_DEBUG_LEVEL_TRACE 4 + +-#define NSS_QDISC_COMMAND_TIMEOUT (10*HZ) /* We set 10sec to be the command */ +- /* timeout value for messages */ +- + /* + * Debug message for module init and exit + */ +@@ -92,9 +87,6 @@ + #endif + #endif + +-#define NSS_QDISC_STATS_SYNC_MANY_PERIOD msecs_to_jiffies(1000) +-#define NSS_QDISC_STATS_SYNC_MANY_UDELAY 5000 /* Delay for 5 ms */ +- + /* + * State values + */ +@@ -144,27 +136,6 @@ struct nss_qdisc; + typedef void (*nss_qdisc_stats_callback_t)(struct nss_qdisc *nq, struct nss_shaper_node_stats_response *response); + typedef void (*nss_qdisc_configure_callback_t)(struct nss_qdisc *nq, struct nss_shaper_configure *response); + +- +-/* +- * Qdisc stats sync info object +- */ +-struct nss_qdisc_stats_wq { +- struct nss_qdisc *nq; /* Pointer to root nss_qdisc */ +- struct list_head stats_list; /* List head stats sync management work */ +- struct nss_if_msg stats_sync_req_msg; /* FW sync message */ +- struct timer_list stats_get_timer; /* Timer used to start fresh iter */ +- unsigned long int next_req_time; /* Time at which next sync iteration starts */ +- unsigned long int stats_request_success; /* Number of success stats request */ +- unsigned long int stats_request_fail; /* Number of failed stats request */ +- unsigned long int stats_request_nack; /* Number of NACK'd stats request */ +- atomic_t pending_stat_work; /* Pending work queue status */ +- atomic_t pending_stat_resp; /* Pending statistics response from FW */ +- bool stats_polling_stopped; /* True when polling is stopped due to qdisc delete */ +- wait_queue_head_t stats_work_waitqueue; /* Wait queue to wait on work queue processing */ +- wait_queue_head_t stats_resp_waitqueue; /* Wait queue used to wait on response from the NSS */ +- struct nss_qdisc_htable nqt; /* Struct to manage hash table of Qdiscs for stats */ +-}; +- + struct nss_qdisc { + struct Qdisc *qdisc; /* Handy pointer back to containing qdisc */ + struct nss_qdisc *parent; /* Pointer to parent nss qdisc */ +@@ -226,8 +197,6 @@ struct nss_qdisc { + #endif + struct timer_list stats_get_timer; /* Timer used to poll for stats */ + atomic_t pending_stat_requests; /* Number of pending stats responses */ +- struct nss_qdisc_stats_wq *stats_wq; /* Stats info and state work object */ +- struct hlist_node hlist; /* Hlist node for managing stats hash list */ + wait_queue_head_t wait_queue; /* Wait queue used to wait on responses from the NSS */ + spinlock_t lock; /* Lock to protect the nss qdisc structure */ + uint16_t mode; /* Mode of Qdisc/class */ +@@ -460,6 +429,18 @@ extern int nss_qdisc_init(struct Qdisc * + void *extack); + + /* ++ * nss_qdisc_start_basic_stats_polling() ++ * Call to initiate the stats polling timer ++ */ ++extern void nss_qdisc_start_basic_stats_polling(struct nss_qdisc *nq); ++ ++/* ++ * nss_qdisc_stop_basic_stats_polling() ++ * Call to stop polling of basic stats ++ */ ++extern void nss_qdisc_stop_basic_stats_polling(struct nss_qdisc *nq); ++ ++/* + * nss_qdisc_gnet_stats_copy_basic() + * Wrapper around gnet_stats_copy_basic() + */ +@@ -505,15 +486,3 @@ extern unsigned long nss_qdisc_tcf_bind( + * Unbind the filter from the qdisc. + */ + extern void nss_qdisc_tcf_unbind(struct Qdisc *sch, unsigned long arg); +- +-/* +- * nss_qdisc_get_interface_msg() +- * Returns the correct message that needs to be sent down to the NSS interface. +- */ +-extern int nss_qdisc_get_interface_msg(bool is_bridge, uint32_t msg_type); +- +-/* +- * nss_qdisc_msg_init() +- * Initialize the qdisc specific message +- */ +-extern void nss_qdisc_msg_init(struct nss_if_msg *nim, uint16_t if_num, uint32_t msg_type, uint32_t len, nss_if_msg_callback_t cb, void *app_data); +--- a/nss_qdisc/nss_tbl.c ++++ b/nss_qdisc/nss_tbl.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2014-2017, 2019-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2014-2017, 2019-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -88,7 +88,12 @@ static void nss_tbl_destroy(struct Qdisc + /* + * Now we can destroy our child qdisc + */ +- nss_qdisc_put(q->qdisc); ++ nss_qdisc_put(q->qdisc); ++ ++ /* ++ * Stop the polling of basic stats and destroy qdisc. ++ */ ++ nss_qdisc_stop_basic_stats_polling(&q->nq); + nss_qdisc_destroy(&q->nq); + } + +@@ -287,6 +292,11 @@ static int nss_tbl_init(struct Qdisc *sc + return -EINVAL; + } + ++ /* ++ * Start the stats polling timer ++ */ ++ nss_qdisc_start_basic_stats_polling(&q->nq); ++ + return 0; + } + +--- a/nss_qdisc/nss_wred.c ++++ b/nss_qdisc/nss_wred.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2014-2017, 2020-2021 The Linux Foundation. All rights reserved. ++ * Copyright (c) 2014-2017, 2020 The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -108,6 +108,11 @@ static void nss_wred_destroy(struct Qdis + { + struct nss_qdisc *nq = (struct nss_qdisc *)qdisc_priv(sch); + ++ /* ++ * Stop the polling of basic stats ++ */ ++ nss_qdisc_stop_basic_stats_polling(nq); ++ + nss_qdisc_destroy(nq); + nss_qdisc_info("nsswred destroyed"); + } +@@ -370,6 +375,11 @@ static int nss_wred_init(struct Qdisc *s + return -EINVAL; + } + ++ /* ++ * Start the stats polling timer ++ */ ++ nss_qdisc_start_basic_stats_polling(nq); ++ + return 0; + } + +--- a/nss_qdisc/nss_wrr.c ++++ b/nss_qdisc/nss_wrr.c +@@ -1,13 +1,9 @@ + /* + ************************************************************************** +- * Copyright (c) 2014-2017, 2019-2021, The Linux Foundation. All rights reserved. +- * +- * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. +- * ++ * Copyright (c) 2014-2017, 2019-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +- * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +@@ -91,6 +87,11 @@ static void nss_wrr_destroy_class(struct + nss_qdisc_put(cl->qdisc); + + /* ++ * Stop the stats polling timer and free class ++ */ ++ nss_qdisc_stop_basic_stats_polling(&cl->nq); ++ ++ /* + * Destroy the shaper in NSS + */ + nss_qdisc_destroy(&cl->nq); +@@ -351,6 +352,11 @@ static int nss_wrr_change_class(struct Q + */ + qdisc_class_hash_grow(sch, &q->clhash); + ++ /* ++ * Start the stats polling timer ++ */ ++ nss_qdisc_start_basic_stats_polling(&cl->nq); ++ + nss_qdisc_info("Class %u successfully allocated\n", classid); + } + +@@ -400,7 +406,11 @@ failure: + return -EINVAL; + } + ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) ++static int nss_wrr_delete_class(struct Qdisc *sch, unsigned long arg, struct netlink_ext_ack *extack) ++#else + static int nss_wrr_delete_class(struct Qdisc *sch, unsigned long arg) ++#endif + { + struct nss_wrr_sched_data *q = qdisc_priv(sch); + struct nss_wrr_class_data *cl = (struct nss_wrr_class_data *)arg; +@@ -408,14 +418,11 @@ static int nss_wrr_delete_class(struct Q + int refcnt; + + /* +- * If the class is a root class or has a child qdisc attached +- * we do not support deleting it. ++ * Since all classes are leaf nodes in our case, we dont have to make ++ * that check. + */ +- if ((cl == &q->root) || (cl->qdisc != &noop_qdisc)) { +- nss_qdisc_warning("Cannot delete wrr class %x as it is the " +- "root class or has a child qdisc attached\n", cl->nq.qos_tag); ++ if (cl == &q->root) + return -EBUSY; +- } + + /* + * The message to NSS should be sent to the parent of this class +@@ -429,24 +436,16 @@ static int nss_wrr_delete_class(struct Q + } + + sch_tree_lock(sch); ++ qdisc_reset(cl->qdisc); + qdisc_class_hash_remove(&q->clhash, &cl->cl_common); + + refcnt = nss_qdisc_atomic_sub_return(&cl->nq); + + sch_tree_unlock(sch); +- +- /* +- * For 5.4 and above kernels, calling nss_htb_destroy_class +- * explicitly as there is no put_class which would have called +- * nss_wrr_destroy_class when refcnt becomes zero. +- */ +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)) +- nss_wrr_destroy_class(sch, cl); +-#else + if (!refcnt) { + nss_qdisc_error("Reference count should not be zero for class %px\n", cl); + } +-#endif ++ + return 0; + } + +@@ -722,6 +721,11 @@ static int nss_wrr_init_qdisc(struct Qdi + + nss_qdisc_info("Nsswrr initialized - handle %x parent %x\n", sch->handle, sch->parent); + ++ /* ++ * Start the stats polling timer ++ */ ++ nss_qdisc_start_basic_stats_polling(&q->nq); ++ + return 0; + } + +@@ -760,11 +764,6 @@ static int nss_wrr_change_qdisc(struct Q + + static void nss_wrr_reset_class(struct nss_wrr_class_data *cl) + { +- if (cl->qdisc == &noop_qdisc) { +- nss_qdisc_trace("Class %x has no child qdisc to reset\n", cl->nq.qos_tag); +- return; +- } +- + nss_qdisc_reset(cl->qdisc); + nss_qdisc_info("Nsswrr class resetted %px\n", cl->qdisc); + } +@@ -837,6 +836,11 @@ static void nss_wrr_destroy_qdisc(struct + qdisc_class_hash_destroy(&q->clhash); + + /* ++ * Stop the polling of basic stats ++ */ ++ nss_qdisc_stop_basic_stats_polling(&q->nq); ++ ++ /* + * Now we can go ahead and destroy the qdisc. + * Note: We dont have to detach ourself from our parent because this + * will be taken care of by the graft call. +--- a/openvpn/plugins/Makefile ++++ b/openvpn/plugins/Makefile +@@ -1,12 +1,11 @@ + + # Makefile for the ovpn plugins + +-ccflags-y := $(NSS_CCFLAGS) -I$(obj) -I$(obj)/../../exports -I$(obj)/include -I$(obj)/../src -I$(STAGING_DIR)/usr/include/qca-nss-ecm +- ++ccflags-y := $(NSS_CCFLAGS) -I$(obj) -I$(obj)/../../exports -I$(obj)/include -I$(obj)/../src + ccflags-y += -DNSS_CLIENT_BUILD_ID="$(BUILD_ID)" + ccflags-y += -DNSS_OVPNMGR_DEBUG_LEVEL=0 + ccflags-y += -DNSS_OVPN_LINK_DEBUG_LEVEL=0 +-ccflags-y += -Wall -Werror ++ccflags-y += -Werror + + obj-m += qca-nss-ovpn-link.o + qca-nss-ovpn-link-objs := nss_ovpn_link.o +--- a/openvpn/plugins/nss_ovpn_sk.c ++++ b/openvpn/plugins/nss_ovpn_sk.c +@@ -19,7 +19,6 @@ + * Socket implementation for OVPN. + */ + +-#include + #include + #include + #include +@@ -264,12 +263,7 @@ static int nss_ovpn_sk_update_ipv6_tuple + struct rt6_info *rt6; + int addr_type; + +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0)) + rt6 = rt6_lookup(dev_net(pinfo->dev), (struct in6_addr *)tun_data->tun_hdr.dst_ip, NULL, 0, 0); +-#else +- rt6 = rt6_lookup(dev_net(pinfo->dev), (struct in6_addr *)tun_data->tun_hdr.dst_ip, NULL, 0, 0, 0); +-#endif +- + if (!rt6) { + nss_ovpn_sk_warn("%px: Failed to find IPv6 route.\n", pinfo); + return -EINVAL; +@@ -411,11 +405,7 @@ static int nss_ovpn_sk_tun_add(struct so + * Bring up tunnel device. + */ + rtnl_lock(); +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0)) + err = dev_open(tun_dev); +-#else +- err = dev_open(tun_dev, NULL); +-#endif + rtnl_unlock(); + + if (err) { +@@ -642,11 +632,11 @@ static int nss_ovpn_sk_sendmsg(struct so + */ + static int nss_ovpn_sk_recvmsg(struct socket *sock, struct msghdr *msg, size_t size, int flags) + { +- struct nss_ovpn_sk_pkt_info *pkt_info_data, pkt_data; ++ struct nss_ovpn_sk_pkt_info *pkt_info_data; + struct nss_ovpnmgr_metadata pkt_info; + int copied, ret; + struct sk_buff *skb; +- struct cmsghdr *cmsg, k_cmsg; ++ struct cmsghdr *cmsg; + struct sock *sk = sock->sk; + + if (flags & ~(MSG_PEEK | MSG_DONTWAIT | MSG_TRUNC | MSG_CMSG_COMPAT)) { +@@ -666,13 +656,6 @@ static int nss_ovpn_sk_recvmsg(struct so + return -EINVAL; + } + +- if (copy_from_user(&k_cmsg, cmsg, sizeof(struct cmsghdr))) { +- nss_ovpn_sk_warn("Copy from user failed\n"); +- return -EINVAL; +- } +- +- cmsg = &k_cmsg; +- + if (!CMSG_OK(msg, cmsg)) { + nss_ovpn_sk_warn("%px: Incorrect message format\n", sock); + return -EINVAL; +@@ -700,15 +683,8 @@ static int nss_ovpn_sk_recvmsg(struct so + * Send control information to application. + */ + memcpy(&pkt_info, skb->cb, sizeof(pkt_info)); +- +- pkt_data.tunnel_id = pkt_info.tunnel_id; +- pkt_data.flags = pkt_info.flags; +- +- if (copy_to_user(pkt_info_data, &pkt_data, sizeof(pkt_data))) { +- nss_ovpn_sk_warn("Copy from user failed\n"); +- return -EINVAL; +- } +- ++ pkt_info_data->tunnel_id = pkt_info.tunnel_id; ++ pkt_info_data->flags = pkt_info.flags; + put_cmsg(msg, SOL_IP, IP_PKTINFO, sizeof(*pkt_info_data), pkt_info_data); + + copied = skb->len; +@@ -864,12 +840,7 @@ int nss_ovpn_sk_send(struct sk_buff *skb + * for indefinite time. + */ + skb_orphan(skb); +- +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 4, 0)) + nf_reset(skb); +-#else +- nf_reset_ct(skb); +-#endif + + /* Enqueue packet */ + if (sock_queue_rcv_skb(sk, skb) < 0) { +--- a/openvpn/src/Makefile ++++ b/openvpn/src/Makefile +@@ -3,7 +3,7 @@ + ccflags-y := $(NSS_CCFLAGS) -I$(obj) -I$(obj)/../../exports -I$(obj)/include -I$(obj)/../plugins + ccflags-y += -DNSS_CLIENT_BUILD_ID="$(BUILD_ID)" + ccflags-y += -DNSS_OVPNMGR_DEBUG_LEVEL=0 -DNSS_OVPNMGR_DEBUG_ENABLE_PKT_DUMP=0 +-ccflags-y += -Wall -Werror ++ccflags-y += -Werror + + obj-m += qca-nss-ovpn-mgr.o + qca-nss-ovpn-mgr-objs := nss_ovpnmgr.o nss_ovpnmgr_app.o nss_ovpnmgr_tun.o nss_ovpnmgr_crypto.o \ +--- a/openvpn/src/nss_ovpnmgr.c ++++ b/openvpn/src/nss_ovpnmgr.c +@@ -99,12 +99,7 @@ static int nss_ovpnmgr_netdevice_event(s + */ + read_unlock_bh(&ovpnmgr_ctx.lock); + if (event == NETDEV_UP) { +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0)) + dev_open(nss_dev); +-#else +- dev_open(nss_dev, NULL); +-#endif +- + } else { + dev_close(nss_dev); + } +--- a/openvpn/src/nss_ovpnmgr_app.c ++++ b/openvpn/src/nss_ovpnmgr_app.c +@@ -62,12 +62,7 @@ static struct net_device *nss_ovpnmgr_ap + return dev; + } + +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0)) + rt6 = rt6_lookup(&init_net, (const struct in6_addr *)rt->ip_addr, NULL, 0, 0); +-#else +- rt6 = rt6_lookup(&init_net, (const struct in6_addr *)rt->ip_addr, NULL, 0, 0, 0); +-#endif +- + if (!rt6) { + return NULL; + } +--- a/openvpn/src/nss_ovpnmgr_route.c ++++ b/openvpn/src/nss_ovpnmgr_route.c +@@ -80,7 +80,7 @@ int nss_ovpnmgr_route_set_active(struct + /* + * This API should be called under lock. + */ +- lockdep_assert_held(&ovpnmgr_ctx.lock); ++ BUG_ON(write_can_lock(&ovpnmgr_ctx.lock)); + + /* + * Search for route entry with from_addr. +--- a/openvpn/src/nss_ovpnmgr_tun.c ++++ b/openvpn/src/nss_ovpnmgr_tun.c +@@ -130,11 +130,7 @@ static void nss_ovpnmgr_tun_ipv6_forward + skb->protocol = htons(ETH_P_IPV6); + ip6h = ipv6_hdr(skb); + +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0)) + rt6 = rt6_lookup(dev_net(app->dev), &ip6h->daddr, &ip6h->saddr, 0, 0); +-#else +- rt6 = rt6_lookup(dev_net(app->dev), &ip6h->daddr, &ip6h->saddr, 0, 0, 0); +-#endif + if (!rt6) { + nss_ovpnmgr_warn("%px: Failed to find IPv6 route.\n", skb); + tun->outer.stats.host_pkt_drop++; +@@ -488,11 +484,7 @@ static void nss_ovpnmgr_tun_dev_setup(st + dev->header_ops = NULL; + dev->netdev_ops = &ovpnmgr_dev_ops; + dev->ethtool_ops = NULL; +-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(4, 11, 8)) + dev->destructor = nss_ovpnmgr_tun_free; +-#else +- dev->priv_destructor = nss_ovpnmgr_tun_free; +-#endif + } + + /* +--- a/portifmgr/Makefile ++++ b/portifmgr/Makefile +@@ -11,4 +11,4 @@ obj-m += qca-nss-portifmgr.o + qca-nss-portifmgr-objs := nss_portifmgr.o + + ccflags-y += -DNSS_PORTIFMGR_DEBUG_LEVEL=2 #-DNSS_PORTIFMGR_REF_AP148 +-ccflags-y += -Wall -Werror ++ccflags-y += -Werror +\ No newline at end of file +--- a/portifmgr/nss_portifmgr.c ++++ b/portifmgr/nss_portifmgr.c +@@ -187,16 +187,20 @@ drop: + } + + /* +- * nss_portifmgr_get_stats() ++ * nss_portifmgr_get_stats64() + * Netdev get stats function to get port stats + */ +-static struct rtnl_link_stats64 *nss_portifmgr_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats) ++/* ++ * nss_nlgre_redir_cmn_dev_stats64 ++ * Report packet statistics to linux ++ */ ++static void nss_portifmgr_get_stats64(struct net_device *dev, ++ struct rtnl_link_stats64 *stats) + { + struct nss_portifmgr_priv *priv = (struct nss_portifmgr_priv *)netdev_priv(dev); + BUG_ON(priv == NULL); + + nss_portid_get_stats(priv->if_num, stats); +- return stats; + } + + /* +@@ -225,7 +229,7 @@ static const struct net_device_ops nss_p + .ndo_start_xmit = nss_portifmgr_start_xmit, + .ndo_set_mac_address = eth_mac_addr, + .ndo_change_mtu = nss_portifmgr_change_mtu, +- .ndo_get_stats64 = nss_portifmgr_get_stats, ++ .ndo_get_stats64 = nss_portifmgr_get_stats64, + }; + + /* +--- a/pppoe/Makefile ++++ b/pppoe/Makefile +@@ -1,10 +1,12 @@ + # Makefile for pppoe client + ccflags-y += -I$(obj)/../exports -I$(obj)/.. -I$(obj)/nss_hal/include + ccflags-y += -DNSS_PPPOE_DEBUG_LEVEL=0 +-ccflags-y += -Wall -Werror ++ccflags-y += -Werror + obj-m += qca-nss-pppoe.o + qca-nss-pppoe-objs := nss_connmgr_pppoe.o + + ifneq (,$(filter $(CONFIG_BONDING),y m)) ++ifneq ($(findstring 4.4, $(KERNELVERSION)),) + ccflags-y += -DBONDING_SUPPORT + endif ++endif +--- a/pppoe/nss_connmgr_pppoe.c ++++ b/pppoe/nss_connmgr_pppoe.c +@@ -69,11 +69,7 @@ static int nss_connmgr_pppoe_get_session + return -1; + } + +- if (pppoe_channel_addressing_get(channel[0], addressing)) { +- nss_connmgr_pppoe_warn("%px: failed to get addressing information\n", dev); +- ppp_release_channels(channel, 1); +- return -1; +- } ++ pppoe_channel_addressing_get(channel[0], addressing); + + dev_put(addressing->dev); + ppp_release_channels(channel, 1); +--- a/pptp/Makefile ++++ b/pptp/Makefile +@@ -1,6 +1,6 @@ + # Makefile for pptp client + ccflags-y += -I$(obj)/../exports -I$(obj)/.. -I$(obj)/nss_hal/include + ccflags-y += -DNSS_PPTP_DEBUG_LEVEL=0 +-ccflags-y += -Wall -Werror ++ccflags-y += -Werror + obj-m += qca-nss-pptp.o + qca-nss-pptp-objs := nss_connmgr_pptp.o +--- a/pptp/nss_connmgr_pptp.c ++++ b/pptp/nss_connmgr_pptp.c +@@ -156,11 +156,6 @@ static int nss_connmgr_pptp_get_session( + return -1; + } + +- if (ppp_is_cp_enabled(dev)) { +- nss_connmgr_pptp_warning("%px: rx or tx compression is enabled for PPP\n", dev); +- return -1; +- } +- + ppp_ch_count = ppp_hold_channels(dev, channel, 1); + nss_connmgr_pptp_info("%px: PPP hold channel ret %d\n", dev, ppp_ch_count); + if (ppp_ch_count != 1) { +--- a/profiler/Makefile ++++ b/profiler/Makefile +@@ -1,5 +1,5 @@ + ccflags-y := -I$(obj) -I$(obj)/.. -I$(obj)/../exports -DNSS_DEBUG_LEVEL=0 #-DPROFILE_DEBUG +-ccflags-y += -Wall -Werror ++ccflags-y += -Werror + + obj-m += qca-nss-profile-drv.o + qca-nss-profile-drv-objs := profile.o +--- a/profiler/profile.c ++++ b/profiler/profile.c +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -937,12 +938,26 @@ static ssize_t debug_if(struct file *fil + return count; + } + ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,6,0) ++#define HAVE_PROC_OPS ++#endif ++ ++#ifdef HAVE_PROC_OPS ++static const struct proc_ops profile_fops = { ++ .proc_open = profile_open, ++ .proc_read = profile_read, ++ .proc_lseek = seq_lseek, ++ .proc_release = profile_release, ++ .proc_write = debug_if, ++}; ++#else + static const struct file_operations profile_fops = { + .open = profile_open, + .read = profile_read, + .release = profile_release, + .write = debug_if, + }; ++#endif + + /* + * showing sample status on Linux console +@@ -971,6 +986,15 @@ static ssize_t profile_rate_write(struct + return 0; + } + ++#ifdef HAVE_PROC_OPS ++static const struct proc_ops profile_rate_fops = { ++ .proc_open = profile_rate_open, ++ .proc_read = seq_read, ++ .proc_lseek = seq_lseek, ++ .proc_release = single_release, ++ .proc_write = profile_rate_write, ++}; ++#else + static const struct file_operations profile_rate_fops = { + .open = profile_rate_open, + .read = seq_read, +@@ -978,6 +1002,7 @@ static const struct file_operations prof + .release = single_release, + .write = profile_rate_write, + }; ++#endif + + /* + * hexdump +@@ -1269,25 +1294,15 @@ void netap_profile_release_resource(void + remove_proc_entry("rate", pdir); + remove_proc_entry("data", pdir); + remove_proc_entry("data1", pdir); +- proc_remove(pdir); +- pdir = NULL; +- } +- +- if (node[0]->ctx) { +- nss_profile_dma_deregister_cb(node[0]->ctx, 0); +- if (node[1] && node[1]->ctx) { +- nss_profile_dma_deregister_cb(node[1]->ctx, 0); +- nss_profiler_release_dma(node[1]->ctx); +- /* +- * node[1] memory is part of node[0] allocation; same as the ccl. +- */ +- node[1] = NULL; +- } +- nss_profiler_release_dma(node[0]->ctx); + } ++ nss_profile_dma_deregister_cb(node[0]->ctx, 0); ++ nss_profile_dma_deregister_cb(node[1]->ctx, 0); ++ nss_profiler_release_dma(node[1]->ctx); ++ nss_profiler_release_dma(node[0]->ctx); + kfree(node[0]->ccl); + kfree(node[0]); + node[0] = NULL; ++ + } + + /* +--- a/tls/Makefile ++++ b/tls/Makefile +@@ -4,7 +4,7 @@ ccflags-y += $(NSS_CCFLAGS) -I$(obj)/../ + #ccflags-y += -DNSS_TLSMGR_DEBUG_DUMP + ccflags-y += -DNSS_TLSMGR_DEBUG_LEVEL=3 + ccflags-y += -DNSS_TLSMGR_BUILD_ID=\"'Build_ID - $(shell date +'%m/%d/%y, %H:%M:%S') SoC=$(SoC)'\" +-ccflags-y += -Wall -Werror ++ccflags-y += -Werror + + obj-m += qca-nss-tlsmgr.o + qca-nss-tlsmgr-objs += nss_tlsmgr.o +--- a/tls/nss_tlsmgr_buf.c ++++ b/tls/nss_tlsmgr_buf.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above +@@ -52,15 +52,6 @@ + #define NSS_TLSMGR_REC_MAX_SIZE (sizeof(struct nss_tlsmgr_rec) * NSS_TLSMGR_MDATA_REC_MAX) + + /* +- * nss_tlsmgr_buf_get_rec_start() +- * Get record start +- */ +-struct nss_tlsmgr_rec *nss_tlsmgr_buf_get_rec_start(struct nss_tlsmgr_buf *buf) +-{ +- return (struct nss_tlsmgr_rec *)((uint8_t *)buf + sizeof(*buf)); +-} +- +-/* + * nss_tlsmgr_buf_set_rec() + * Reserve space for a record in a buffer. + */ +@@ -181,7 +172,7 @@ EXPORT_SYMBOL(nss_tlsmgr_buf_encap); + */ + nss_tlsmgr_status_t nss_tlsmgr_buf_decap(struct nss_tlsmgr_buf *buf, nss_tlsmgr_data_callback_t cb, void *app_data) + { +- struct nss_tlsmgr_tun *tun = buf->tun; ++ struct nss_tlsmgr_tun *tun; + struct nss_tlsmgr_ctx *ctx; + struct sk_buff *skb; + struct nss_tlsmgr_rec *rec; +@@ -216,6 +207,7 @@ nss_tlsmgr_status_t nss_tlsmgr_buf_decap + skb = buf->skb; + skb_pull(skb, mdata_start - skb->data); + ++ tun = buf->tun; + ctx = &tun->ctx_dec; + + return nss_tlsmgr_ctx_tx(ctx, skb, rec); +--- a/tls/nss_tlsmgr_buf.h ++++ b/tls/nss_tlsmgr_buf.h +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above +@@ -41,6 +41,13 @@ struct nss_tlsmgr_buf { + + void nss_tlsmgr_buf_rx(struct nss_tlsmgr_buf *buf, nss_tlsmgr_status_t status); + +-struct nss_tlsmgr_rec *nss_tlsmgr_buf_get_rec_start(struct nss_tlsmgr_buf *buf); ++/* ++ * nss_tlsmgr_buf_get_rec_start() ++ * Get record start ++ */ ++static struct nss_tlsmgr_rec *nss_tlsmgr_buf_get_rec_start(struct nss_tlsmgr_buf *buf) ++{ ++ return (struct nss_tlsmgr_rec *)((uint8_t *)buf + sizeof(*buf)); ++} + + #endif /* !__NSS_TLSMGR_BUF_H_ */ +--- a/tls/nss_tlsmgr_tun.c ++++ b/tls/nss_tlsmgr_tun.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above +@@ -102,7 +102,7 @@ static int nss_tlsmgr_tun_open(struct ne + * nss_tlsmgr_tun_stats64() + * TLS manager tunnel device + */ +-static struct rtnl_link_stats64 *nss_tlsmgr_get_tun_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) ++void nss_tlsmgr_tun_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) + { + struct nss_tlsmgr_tun *tun = netdev_priv(dev); + +@@ -113,29 +113,8 @@ static struct rtnl_link_stats64 *nss_tls + nss_tlsmgr_ctx_stats_copy(&tun->ctx_dec, stats); + read_unlock_bh(&tun->lock); + +- return stats; + } + +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0)) +-/* +- * nss_tlsmgr_tun_stats64() +- * Netdev ops function to retrieve stats for kernel version < 4.6 +- */ +-static struct rtnl_link_stats64 *nss_tlsmgr_tun_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) +-{ +- return nss_tlsmgr_get_tun_stats64(dev, stats); +-} +-#else +-/* +- * nss_tlsmgr_tun_stats64() +- * Netdev ops function to retrieve stats for kernel version >= 4.6 +- */ +-static void nss_tlsmgr_tun_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) +-{ +- nss_tlsmgr_get_tun_stats64(dev, stats); +-} +-#endif +- + /* + * nss_tlsmgr_tun_change_mtu() + * Change MTU size of TLS context device. +@@ -211,22 +190,13 @@ static void nss_tlsmgr_tun_free_work(str + read_unlock_bh(&tun->lock); + } + +- + /* + * nss_tlsmgr_notify_event() + * TLS manager notification timer handler + */ +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)) + static void nss_tlsmgr_notify_event(unsigned long data) +-#else +-static void nss_tlsmgr_notify_event(struct timer_list *tm) +-#endif + { +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)) + struct nss_tlsmgr_tun *tun = (struct nss_tlsmgr_tun *)data; +-#else +- struct nss_tlsmgr_tun *tun = from_timer(tun, tm, notify.timer); +-#endif + nss_tlsmgr_notify_callback_t cb; + struct nss_tlsmgr_stats stats; + void *app_data; +@@ -248,17 +218,9 @@ static void nss_tlsmgr_notify_event(stru + * nss_tlsmgr_notify_decongestion() + * TLS manager decongestion notification + */ +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)) + static void nss_tlsmgr_notify_decongestion(unsigned long data) +-#else +-static void nss_tlsmgr_notify_decongestion(struct timer_list *tm) +-#endif + { +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)) + struct nss_tlsmgr_tun *tun = (struct nss_tlsmgr_tun *)data; +-#else +- struct nss_tlsmgr_tun *tun = from_timer(tun, tm, notify.timer); +-#endif + nss_tlsmgr_decongest_callback_t cb; + void *app_data; + +@@ -393,7 +355,6 @@ struct net_device *nss_tlsmgr_tun_add(ns + /* + * Initialize Event notification and Decongestion timer + */ +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)) + init_timer(&tun->notify.timer); + tun->notify.timer.function = nss_tlsmgr_notify_event; + tun->notify.timer.data = (unsigned long)tun; +@@ -401,10 +362,6 @@ struct net_device *nss_tlsmgr_tun_add(ns + init_timer(&tun->decongest.timer); + tun->decongest.timer.function = nss_tlsmgr_notify_decongestion; + tun->decongest.timer.data = (unsigned long)tun; +-#else +- timer_setup(&tun->notify.timer, nss_tlsmgr_notify_event, 0); +- timer_setup(&tun->decongest.timer, nss_tlsmgr_notify_decongestion, 0); +-#endif + + INIT_LIST_HEAD(&tun->free_list); + INIT_WORK(&tun->free_work, nss_tlsmgr_tun_free_work); +--- a/tunipip6/Makefile ++++ b/tunipip6/Makefile +@@ -2,7 +2,6 @@ + ccflags-y += -I$(obj)/../exports -I$(obj)/.. + ccflags-y += -DNSS_CLIENT_BUILD_ID="$(BUILD_ID)" + ccflags-y += -DNSS_TUNIPIP6_DEBUG_LEVEL=0 +-ccflags-y += -Wall -Werror + obj-m += qca-nss-tunipip6.o + qca-nss-tunipip6-objs := nss_connmgr_tunipip6.o nss_connmgr_tunipip6_sysctl.o nss_connmgr_tunipip6_stats.o + ifneq ($(findstring 4.4, $(KERNELVERSION)),) +--- a/tunipip6/nss_connmgr_tunipip6.c ++++ b/tunipip6/nss_connmgr_tunipip6.c +@@ -194,7 +194,6 @@ static void nss_tunipip6_encap_exception + skb->pkt_type = PACKET_HOST; + skb->skb_iif = dev->ifindex; + skb->ip_summed = CHECKSUM_NONE; +- ip_rt_put(rt); + netif_receive_skb(skb); + return; + } +@@ -348,7 +347,7 @@ static void nss_tunipip6_update_dev_stat + { + struct pcpu_sw_netstats stats; + enum nss_dynamic_interface_type interface_type; +- struct nss_tunipip6_stats_sync_msg *sync_stats = (struct nss_tunipip6_stats_sync_msg *)&tnlmsg->msg.stats; ++ struct nss_tunipip6_stats_sync_msg *sync_stats = (struct nss_tunipip6_stats_sync_msg *)&tnlmsg->msg.stats_sync; + + interface_type = nss_dynamic_interface_get_type(nss_tunipip6_get_context(), tnlmsg->cm.interface); + +@@ -381,7 +380,7 @@ void nss_tunipip6_event_receive(void *if + netdev = (struct net_device *)if_ctx; + + switch (tnlmsg->cm.type) { +- case NSS_TUNIPIP6_STATS_SYNC: ++ case NSS_TUNIPIP6_RX_STATS_SYNC: + /* + * Update netdevice statistics. + */ +@@ -627,7 +626,6 @@ configure_tunnel: + tnlcreate->ttl_inherit = tnlcfg->ttl_inherit; + tnlcreate->tos_inherit = tnlcfg->tos_inherit; + tnlcreate->frag_id_update = tnlcfg->frag_id_update; +- tnlcreate->fmr_max = tnlcfg->fmr_max; + + /* + * Set "draft03" based on "tunnel_type". draft03 should be +--- a/tunipip6/nss_connmgr_tunipip6_stats.c ++++ b/tunipip6/nss_connmgr_tunipip6_stats.c +@@ -132,7 +132,7 @@ static void nss_tunipip6_stats_update(ui + void nss_tunipip6_stats_sync(struct net_device *dev, struct nss_tunipip6_msg *ntm) + { + uint32_t ifnum = ntm->cm.interface; +- struct nss_tunipip6_stats_sync_msg *stats = &ntm->msg.stats; ++ struct nss_tunipip6_stats_sync_msg *stats = &ntm->msg.stats_sync; + struct nss_tunipip6_instance *ntii; + struct nss_tunipip6_stats *s; + +@@ -147,7 +147,6 @@ void nss_tunipip6_stats_sync(struct net_ + s = &ntii->stats; + if (ntii->inner_ifnum == ifnum) { + nss_tunipip6_stats_update(s->inner_stats, stats); +- s->inner_stats[NSS_TUNIPIP6_STATS_CONFIG_ENCAP_TOTAL_FMR] = stats->tun_stats.encap.cfg.total_fmr; + } else if (ntii->outer_ifnum == ifnum) { + nss_tunipip6_stats_update(s->outer_stats, stats); + } else { +--- a/vlan/Makefile ++++ b/vlan/Makefile +@@ -8,8 +8,8 @@ ifeq ($(SoC),$(filter $(SoC),ipq807x ipq + ccflags-y += -DNSS_VLAN_MGR_PPE_SUPPORT + endif + +-ccflags-y += -DNSS_VLAN_MGR_DEBUG_LEVEL=0 +-ccflags-y += -Wall -Werror ++ccflags-y += -DNSS_VLAN_MGR_DEBUG_LEVEL=4 ++ccflags-y += -Werror + + ifneq (,$(filter $(CONFIG_BONDING),y m)) + ccflags-y += -DBONDING_SUPPORT +--- a/vlan/nss_vlan_mgr.c ++++ b/vlan/nss_vlan_mgr.c +@@ -1,12 +1,9 @@ + /* + ************************************************************************** + * Copyright (c) 2017-2018, 2020 The Linux Foundation. All rights reserved. +- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. +- * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +- * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +@@ -368,16 +365,22 @@ static void nss_vlan_mgr_port_role_event + * nss_vlan_mgr_bond_configure_ppe() + * Configure PPE for bond device + */ +-static int nss_vlan_mgr_bond_configure_ppe(struct nss_vlan_pvt *v, struct net_device *bond_dev, uint32_t vsi) ++static int nss_vlan_mgr_bond_configure_ppe(struct nss_vlan_pvt *v, struct net_device *bond_dev) + { ++ uint32_t vsi; + int ret = 0; + struct net_device *slave; + int32_t port; + int vlan_mgr_bond_port_role = -1; + ++ if (ppe_vsi_alloc(NSS_VLAN_MGR_SWITCH_ID, &vsi)) { ++ nss_vlan_mgr_warn("%s: failed to allocate VSI for bond vlan device", bond_dev->name); ++ return -1; ++ } ++ + if (nss_vlan_tx_vsi_attach_msg(v->nss_if, vsi) != NSS_TX_SUCCESS) { + nss_vlan_mgr_warn("%s: failed to attach VSI to bond vlan interface\n", bond_dev->name); +- return -1; ++ goto free_vsi; + } + + /* +@@ -390,7 +393,7 @@ static int nss_vlan_mgr_bond_configure_p + if (!NSS_VLAN_PHY_PORT_CHK(port)) { + rcu_read_unlock(); + nss_vlan_mgr_warn("%s: %d is not valid physical port\n", slave->name, port); +- return -1; ++ goto free_vsi; + } + + /* +@@ -406,7 +409,7 @@ static int nss_vlan_mgr_bond_configure_p + * In case the bond interface has no slaves, we do not want to proceed further + */ + if (vlan_mgr_bond_port_role == -1) { +- return -1; ++ goto free_vsi; + } + + /* +@@ -510,6 +513,7 @@ static int nss_vlan_mgr_bond_configure_p + ret = NSS_VLAN_PORT_ROLE_CHANGED; + } + ++ v->ppe_vsi = vsi; + return ret; + + delete_egress_rule: +@@ -541,19 +545,30 @@ detach_vsi: + nss_vlan_mgr_warn("%px: Failed to detach vsi %d\n", v, vsi); + } + ++free_vsi: ++ if (ppe_vsi_free(NSS_VLAN_MGR_SWITCH_ID, vsi)) { ++ nss_vlan_mgr_warn("%px: Failed to free VLAN VSI\n", v); ++ } ++ + return -1; + } + /* + * nss_vlan_mgr_configure_ppe() + * Configure PPE for physical devices + */ +-static int nss_vlan_mgr_configure_ppe(struct nss_vlan_pvt *v, struct net_device *dev, uint32_t vsi) ++static int nss_vlan_mgr_configure_ppe(struct nss_vlan_pvt *v, struct net_device *dev) + { ++ uint32_t vsi; + int ret = 0; + ++ if (ppe_vsi_alloc(NSS_VLAN_MGR_SWITCH_ID, &vsi)) { ++ nss_vlan_mgr_warn("%s: failed to allocate VSI for vlan device", dev->name); ++ return -1; ++ } ++ + if (nss_vlan_tx_vsi_attach_msg(v->nss_if, vsi) != NSS_TX_SUCCESS) { + nss_vlan_mgr_warn("%s: failed to attach VSI to vlan interface\n", dev->name); +- return -1; ++ goto free_vsi; + } + + /* +@@ -637,6 +652,7 @@ static int nss_vlan_mgr_configure_ppe(st + ret = NSS_VLAN_PORT_ROLE_CHANGED; + } + ++ v->ppe_vsi = vsi; + return ret; + + delete_egress_rule: +@@ -658,6 +674,11 @@ detach_vsi: + nss_vlan_mgr_warn("%px: Failed to detach vsi %d\n", v, vsi); + } + ++free_vsi: ++ if (ppe_vsi_free(NSS_VLAN_MGR_SWITCH_ID, vsi)) { ++ nss_vlan_mgr_warn("%px: Failed to free VLAN VSI\n", v); ++ } ++ + return -1; + } + #endif +@@ -800,8 +821,10 @@ static struct nss_vlan_pvt *nss_vlan_mgr + */ + static void nss_vlan_mgr_instance_free(struct nss_vlan_pvt *v) + { ++#ifdef NSS_VLAN_MGR_PPE_SUPPORT + int32_t i; + int ret = 0; ++#endif + + spin_lock(&vlan_mgr_ctx.lock); + BUG_ON(--v->refs); +@@ -847,8 +870,7 @@ static void nss_vlan_mgr_instance_free(s + } + + /* +- * We will always have a VSI since this is allocated in beginning +- * of the code. ++ * Free PPE VSI + */ + if (ppe_vsi_free(NSS_VLAN_MGR_SWITCH_ID, v->ppe_vsi)) { + nss_vlan_mgr_warn("%px: Failed to free VLAN VSI\n", v); +@@ -957,12 +979,14 @@ static int nss_vlan_mgr_register_event(s + struct nss_vlan_pvt *v; + int if_num; + #ifdef NSS_VLAN_MGR_PPE_SUPPORT +- uint32_t vsi; + int ret; + #endif + uint32_t vlan_tag; ++#ifdef NSS_VLAN_MGR_PPE_SUPPORT + struct net_device *slave; +- int32_t port, port_if; ++ int32_t port; ++#endif ++ int32_t port_if; + struct vlan_dev_priv *vlan; + struct net_device *real_dev; + bool is_bond_master = false; +@@ -971,25 +995,19 @@ static int nss_vlan_mgr_register_event(s + if (!v) + return NOTIFY_DONE; + +- /* +- * Allocate the VSI here. +- */ +-#ifdef NSS_VLAN_MGR_PPE_SUPPORT +- if (ppe_vsi_alloc(NSS_VLAN_MGR_SWITCH_ID, &vsi)) { +- nss_vlan_mgr_warn("%s: failed to allocate VSI for vlan device", dev->name); +- return NOTIFY_DONE; +- } +-#endif +- + if_num = nss_dynamic_interface_alloc_node(NSS_DYNAMIC_INTERFACE_TYPE_VLAN); + if (if_num < 0) { + nss_vlan_mgr_warn("%s: failed to alloc NSS dynamic interface\n", dev->name); +- goto vsi_alloc_free; ++ nss_vlan_mgr_instance_free(v); ++ return NOTIFY_DONE; + } + + if (!nss_register_vlan_if(if_num, NULL, dev, 0, v)) { + nss_vlan_mgr_warn("%s: failed to register NSS dynamic interface", dev->name); +- goto free_dynamic_interface; ++ if (nss_dynamic_interface_dealloc_node(if_num, NSS_DYNAMIC_INTERFACE_TYPE_VLAN) != NSS_TX_SUCCESS) ++ nss_vlan_mgr_warn("%px: Failed to dealloc vlan dynamic interface\n", v); ++ nss_vlan_mgr_instance_free(v); ++ return NOTIFY_DONE; + } + v->nss_if = if_num; + +@@ -1003,25 +1021,26 @@ static int nss_vlan_mgr_register_event(s + + #ifdef NSS_VLAN_MGR_PPE_SUPPORT + if (!is_bond_master) +- ret = nss_vlan_mgr_configure_ppe(v, dev, vsi); ++ ret = nss_vlan_mgr_configure_ppe(v, dev); + else +- ret = nss_vlan_mgr_bond_configure_ppe(v, real_dev, vsi); ++ ret = nss_vlan_mgr_bond_configure_ppe(v, real_dev); + + if (ret < 0) { +- goto vlan_instance_free; ++ nss_vlan_mgr_instance_free(v); ++ return NOTIFY_DONE; + } +- +- v->ppe_vsi = vsi; + #endif + + if (nss_vlan_tx_set_mac_addr_msg(v->nss_if, v->dev_addr) != NSS_TX_SUCCESS) { + nss_vlan_mgr_warn("%s: failed to set mac_addr msg\n", dev->name); +- goto vlan_instance_free; ++ nss_vlan_mgr_instance_free(v); ++ return NOTIFY_DONE; + } + + if (nss_vlan_tx_set_mtu_msg(v->nss_if, v->mtu) != NSS_TX_SUCCESS) { + nss_vlan_mgr_warn("%s: failed to set mtu msg\n", dev->name); +- goto vlan_instance_free; ++ nss_vlan_mgr_instance_free(v); ++ return NOTIFY_DONE; + } + + vlan_tag = (v->tpid << NSS_VLAN_TPID_SHIFT | v->vid); +@@ -1030,7 +1049,8 @@ static int nss_vlan_mgr_register_event(s + (v->parent ? v->parent->nss_if : port_if), + port_if) != NSS_TX_SUCCESS) { + nss_vlan_mgr_warn("%s: failed to add vlan in nss\n", dev->name); +- goto vlan_instance_free; ++ nss_vlan_mgr_instance_free(v); ++ return NOTIFY_DONE; + } + + spin_lock(&vlan_mgr_ctx.lock); +@@ -1058,21 +1078,6 @@ static int nss_vlan_mgr_register_event(s + } + #endif + return NOTIFY_DONE; +- +-free_dynamic_interface: +- if (nss_dynamic_interface_dealloc_node(if_num, NSS_DYNAMIC_INTERFACE_TYPE_VLAN) != NSS_TX_SUCCESS) +- nss_vlan_mgr_warn("%px: Failed to dealloc vlan dynamic interface\n", v); +- +-vsi_alloc_free: +-#ifdef NSS_VLAN_MGR_PPE_SUPPORT +- if (ppe_vsi_free(NSS_VLAN_MGR_SWITCH_ID, v->ppe_vsi)) { +- nss_vlan_mgr_warn("%px: Failed to free VLAN VSI\n", v); +- } +-#endif +- +-vlan_instance_free: +- nss_vlan_mgr_instance_free(v); +- return NOTIFY_DONE; + } + + /* +@@ -1355,8 +1360,10 @@ return_with_error: + int nss_vlan_mgr_join_bridge(struct net_device *dev, uint32_t bridge_vsi) + { + struct nss_vlan_pvt *v = nss_vlan_mgr_instance_find_and_ref(dev); ++#ifdef NSS_VLAN_MGR_PPE_SUPPORT + struct net_device *real_dev; + int ret; ++#endif + + if (!v) + return 0; +@@ -1416,8 +1423,10 @@ EXPORT_SYMBOL(nss_vlan_mgr_join_bridge); + int nss_vlan_mgr_leave_bridge(struct net_device *dev, uint32_t bridge_vsi) + { + struct nss_vlan_pvt *v = nss_vlan_mgr_instance_find_and_ref(dev); ++#ifdef NSS_VLAN_MGR_PPE_SUPPORT + struct net_device *real_dev; + int ret; ++#endif + + if (!v) + return 0; +--- a/vxlanmgr/nss_vxlanmgr.c ++++ b/vxlanmgr/nss_vxlanmgr.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -22,18 +22,15 @@ + #include + #include + #include +-#include + #include + #include + #include "nss_vxlanmgr.h" +-#include "nss_vxlanmgr_priv.h" + #include "nss_vxlanmgr_tun_stats.h" + + /* + * VxLAN context + */ + struct nss_vxlanmgr_ctx vxlan_ctx; +-static struct nss_vxlanmgr_get_ipsec_if_num __rcu ipsecmgr_cb; + + /* + * nss_vxlanmgr_netdev_event() +@@ -77,77 +74,6 @@ static struct notifier_block nss_vxlanmg + }; + + /* +- * nss_vxlanmgr_bind_ipsec_by_ip() +- * Bind VxLAN tunnel with IPsec based on IP Address +- */ +-int32_t nss_vxlanmgr_bind_ipsec_by_ip(union vxlan_addr *src_ip, union vxlan_addr *dest_ip) +-{ +- int32_t ipsec_if_num; +- nss_vxlanmgr_get_ipsec_if_num_by_ip_callback_t ipsec_cb; +- struct nss_ctx_instance *nss_ctx = nss_vxlan_get_ctx(); +- +- /* +- * Check if the VxLAN interface is applied over an IPsec interface by querying the IPsec. +- */ +- rcu_read_lock(); +- ipsec_cb = rcu_dereference(ipsecmgr_cb.get_ifnum_by_ip); +- if (!ipsec_cb) { +- rcu_read_unlock(); +- nss_vxlanmgr_info("%px: IPsec get_ifnum_by_ip callback is not registered\n", nss_ctx); +- return -1; +- } +- +- if (dest_ip->sa.sa_family == AF_INET) { +- ipsec_if_num = ipsec_cb(IPVERSION, &src_ip->sin.sin_addr.s_addr, &dest_ip->sin.sin_addr.s_addr); +- } else { +- ipsec_if_num = ipsec_cb(6, src_ip->sin6.sin6_addr.in6_u.u6_addr32, dest_ip->sin6.sin6_addr.in6_u.u6_addr32); +- } +- +- rcu_read_unlock(); +- nss_vxlanmgr_info("%px: VxLAN interface is bound to IPsec interface with if_num(0x%x)\n", nss_ctx, ipsec_if_num); +- +- return ipsec_if_num; +-} +- +-/* +- * nss_vxlanmgr_unregister_ipsecmgr_callback_by_ip +- * Unregister callback. +- */ +-void nss_vxlanmgr_unregister_ipsecmgr_callback_by_ip(void) +-{ +- rcu_assign_pointer(ipsecmgr_cb.get_ifnum_by_ip, NULL); +- synchronize_rcu(); +-} +-EXPORT_SYMBOL(nss_vxlanmgr_unregister_ipsecmgr_callback_by_ip); +- +-/* +- * nss_vxlanmgr_register_ipsecmgr_callback_by_ip() +- * Register IPSecmgr callback. +- */ +-void nss_vxlanmgr_register_ipsecmgr_callback_by_ip(struct nss_vxlanmgr_get_ipsec_if_num *cb) +-{ +- nss_vxlanmgr_get_ipsec_if_num_by_ip_callback_t ipsec_get_ifnum_by_ip; +- +- rcu_read_lock(); +- ipsec_get_ifnum_by_ip = rcu_dereference(ipsecmgr_cb.get_ifnum_by_ip); +- if (ipsec_get_ifnum_by_ip) { +- rcu_read_unlock(); +- nss_vxlanmgr_info("%px: IPSecmgr Callback get_ifnum_by_ip is already registered\n", cb); +- return; +- } +- rcu_read_unlock(); +- +- if (cb->get_ifnum_by_ip == NULL) { +- nss_vxlanmgr_warn("%px: IPSecmgr Callback get_ifnum_by_ip is NULL\n", cb); +- return; +- } +- +- rcu_assign_pointer(ipsecmgr_cb.get_ifnum_by_ip, cb->get_ifnum_by_ip); +- synchronize_rcu(); +-} +-EXPORT_SYMBOL(nss_vxlanmgr_register_ipsecmgr_callback_by_ip); +- +-/* + * nss_vxlanmgr_exit_module() + * Tunnel vxlan module exit function + */ +@@ -194,12 +120,6 @@ int __init nss_vxlanmgr_init_module(void + return -1; + } + +- /* +- * Initialize ipsecmgr callback. +- */ +- rcu_assign_pointer(ipsecmgr_cb.get_ifnum_by_ip, NULL); +- synchronize_rcu(); +- + INIT_LIST_HEAD(&vxlan_ctx.list); + vxlan_ctx.nss_ctx = nss_vxlan_get_ctx(); + spin_lock_init(&vxlan_ctx.tun_lock); +--- /dev/null ++++ b/vxlanmgr/nss_vxlanmgr.h +@@ -0,0 +1,85 @@ ++/* ++ ************************************************************************** ++ * Copyright (c) 2019, The Linux Foundation. All rights reserved. ++ * Permission to use, copy, modify, and/or distribute this software for ++ * any purpose with or without fee is hereby granted, provided that the ++ * above copyright notice and this permission notice appear in all copies. ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT ++ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ************************************************************************** ++ */ ++ ++/* ++ * nss_vxlanmgr.h ++ * VxLAN manager header ++ */ ++#ifndef __NSS_VXLANMGR_H ++#define __NSS_VXLANMGR_H ++ ++/* ++ * Compile messages for dynamic enable/disable ++ */ ++#if defined(CONFIG_DYNAMIC_DEBUG) ++#define nss_vxlanmgr_warn(s, ...) pr_debug("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__) ++#define nss_vxlanmgr_info(s, ...) pr_debug("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__) ++#define nss_vxlanmgr_trace(s, ...) pr_debug("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__) ++#else /* CONFIG_DYNAMIC_DEBUG */ ++/* ++ * Statically compile messages at different levels ++ */ ++#if (NSS_VXLANMGR_DEBUG_LEVEL < 2) ++#define nss_vxlanmgr_warn(s, ...) ++#else ++#define nss_vxlanmgr_warn(s, ...) pr_warn("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__) ++#endif ++ ++#if (NSS_VXLANMGR_DEBUG_LEVEL < 3) ++#define nss_vxlanmgr_info(s, ...) ++#else ++#define nss_vxlanmgr_info(s, ...) pr_notice("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__) ++#endif ++ ++#if (NSS_VXLANMGR_DEBUG_LEVEL < 4) ++#define nss_vxlanmgr_trace(s, ...) ++#else ++#define nss_vxlanmgr_trace(s, ...) pr_info("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__) ++#endif ++#endif /* CONFIG_DYNAMIC_DEBUG */ ++ ++struct nss_vxlanmgr_ctx { ++ struct list_head list; /* vxlanmgr context list head */ ++ struct dentry *dentry; /* debugfs entry for qca-nss-vxlanmgr */ ++ struct nss_ctx_instance *nss_ctx; /* nss context for vxlan tunnel */ ++ uint32_t tun_count; /* active vxlan tunnel count */ ++ spinlock_t tun_lock; /* spinlock */ ++}; ++ ++struct nss_vxlanmgr_tun_ctx { ++ struct list_head head; /* tunnel context list entry */ ++ struct net_device *dev; /* tunnel netdevice pointer */ ++ struct dentry *dentry; /* per tunnel debugfs entry */ ++ struct nss_vxlanmgr_ctx *vxlan_ctx; /* pointer to vxlanmgr context */ ++ struct nss_vxlanmgr_tun_stats *stats; /* tunnel statistics structure */ ++ uint32_t inner_ifnum; /* inner node interface number */ ++ uint32_t outer_ifnum; /* outer node interface number */ ++ uint32_t vni; /* vnet identifier */ ++ uint16_t tunnel_flags; /* vxlan tunnel flags */ ++ uint16_t flow_label; /* flowlabel */ ++ uint16_t src_port_min; /* minimum source port */ ++ uint16_t src_port_max; /* maximum source port*/ ++ uint16_t dest_port; /* destination port */ ++ uint8_t tos; /* tos value */ ++ uint8_t ttl; /* time to live */ ++}; ++ ++extern int nss_vxlanmgr_tunnel_create(struct net_device *dev); ++extern int nss_vxlanmgr_tunnel_destroy(struct net_device *dev); ++extern int nss_vxlanmgr_tunnel_config(struct net_device *dev); ++extern int nss_vxlanmgr_tunnel_deconfig(struct net_device *dev); ++ ++#endif /* __NSS_VXLANMGR_H */ +--- a/vxlanmgr/nss_vxlanmgr_tun_stats.c ++++ b/vxlanmgr/nss_vxlanmgr_tun_stats.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -18,7 +18,7 @@ + #include + #include + #include +-#include "nss_vxlanmgr_priv.h" ++#include "nss_vxlanmgr.h" + #include "nss_vxlanmgr_tun_stats.h" + + /* +@@ -47,8 +47,6 @@ static int8_t *nss_vxlanmgr_tun_stats_st + "Except VNI Look-up failed", + "Dropped packet malformed", + "Dropped next node queue is full", +- "Except Inner hash calculation failed", +- "Decap IPSec source interface invalid" + }; + + /* +@@ -90,7 +88,7 @@ static int nss_vxlanmgr_tun_stats_show(s + seq_printf(m, "\t\tflow_label = %u\n", tun_ctx->flow_label); + seq_printf(m, "\t\tsrc_port_min = %u\n", tun_ctx->src_port_min); + seq_printf(m, "\t\tsrc_port_max = %u\n", tun_ctx->src_port_max); +- seq_printf(m, "\t\tdest_port = %u\n", tun_ctx->dest_port); ++ seq_printf(m, "\t\tdest_port = %u\n", ntohs(tun_ctx->dest_port)); + seq_printf(m, "\t\ttos = %u\n", tun_ctx->tos); + seq_printf(m, "\t\tttl = %u\n", tun_ctx->ttl); + +@@ -167,16 +165,11 @@ void nss_vxlanmgr_tun_stats_update(uint6 + stats_msg->dropped_malformed; + stats[NSS_VXLANMGR_TUN_STATS_TYPE_DROP_NEXT_NODE_QUEUE_FULL] += + stats_msg->dropped_next_node_queue_full; +- stats[NSS_VXLANMGR_TUN_STATS_TYPE_EXCEPT_INNER_HASH] += +- stats_msg->except_inner_hash; +- stats[NSS_VXLANMGR_TUN_STATS_TYPE_DECAP_IPSEC_SRC_INVALID] += +- stats_msg->decap_ipsec_src_err; + } + + /* + * nss_vxlanmgr_tun_macdb_stats_sync() + * Sync function for vxlan fdb entries +- * Note: Reference on the netdevice is expected to be held by the caller at the time this function is called. + */ + void nss_vxlanmgr_tun_macdb_stats_sync(struct nss_vxlanmgr_tun_ctx *tun_ctx, struct nss_vxlan_msg *nvm) + { +@@ -187,8 +180,11 @@ void nss_vxlanmgr_tun_macdb_stats_sync(s + db_stats = &nvm->msg.db_stats; + nentries = db_stats->cnt; + ++ dev_hold(tun_ctx->dev); ++ + if (nentries > NSS_VXLAN_MACDB_ENTRIES_PER_MSG) { + nss_vxlanmgr_warn("%px: No more than 20 entries allowed per message.\n", tun_ctx->dev); ++ dev_put(tun_ctx->dev); + return; + } + +@@ -204,6 +200,7 @@ void nss_vxlanmgr_tun_macdb_stats_sync(s + } + } + } ++ dev_put(tun_ctx->dev); + } + + /* +--- a/vxlanmgr/nss_vxlanmgr_tun_stats.h ++++ b/vxlanmgr/nss_vxlanmgr_tun_stats.h +@@ -1,6 +1,6 @@ + /* + ****************************************************************************** +- * Copyright (c) 2019, 2021 The Linux Foundation. All rights reserved. ++ * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -37,8 +37,6 @@ enum nss_vxlanmgr_tun_stats_type { + NSS_VXLANMGR_TUN_STATS_TYPE_EXCEPT_VNI_LOOKUP_FAILED, + NSS_VXLANMGR_TUN_STATS_TYPE_DROP_MALFORMED, + NSS_VXLANMGR_TUN_STATS_TYPE_DROP_NEXT_NODE_QUEUE_FULL, +- NSS_VXLANMGR_TUN_STATS_TYPE_EXCEPT_INNER_HASH, +- NSS_VXLANMGR_TUN_STATS_TYPE_DECAP_IPSEC_SRC_INVALID, + NSS_VXLANMGR_TUN_STATS_TYPE_MAX, + }; + +--- a/vxlanmgr/nss_vxlanmgr_tunnel.c ++++ b/vxlanmgr/nss_vxlanmgr_tunnel.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -27,7 +27,7 @@ + #include + #include + #include +-#include "nss_vxlanmgr_priv.h" ++#include "nss_vxlanmgr.h" + #include "nss_vxlanmgr_tun_stats.h" + + /* +@@ -91,23 +91,18 @@ static uint16_t nss_vxlanmgr_tunnel_flag + uint16_t flags = 0; + uint32_t priv_flags = priv->flags; + +- if (priv_flags & VXLAN_F_RSC) +- return flags; + if (priv_flags & VXLAN_F_GBP) + flags |= NSS_VXLAN_RULE_FLAG_GBP_ENABLED; +- +- if (priv_flags & VXLAN_F_IPV6) { ++ if (priv_flags & VXLAN_F_IPV6) + flags |= NSS_VXLAN_RULE_FLAG_IPV6; +- if (!(priv_flags & VXLAN_F_UDP_ZERO_CSUM6_TX)) +- flags |= NSS_VXLAN_RULE_FLAG_ENCAP_L4_CSUM_REQUIRED; +- } else { ++ else if (!(priv_flags & VXLAN_F_IPV6)) + flags |= NSS_VXLAN_RULE_FLAG_IPV4; +- if (priv_flags & VXLAN_F_UDP_CSUM) +- flags |= NSS_VXLAN_RULE_FLAG_ENCAP_L4_CSUM_REQUIRED; +- } +- + if (priv->cfg.tos == 1) + flags |= NSS_VXLAN_RULE_FLAG_INHERIT_TOS; ++ if (priv_flags & VXLAN_F_UDP_CSUM) ++ flags |= NSS_VXLAN_RULE_FLAG_ENCAP_L4_CSUM_REQUIRED; ++ else if (!(priv_flags & VXLAN_F_UDP_ZERO_CSUM6_TX)) ++ flags |= NSS_VXLAN_RULE_FLAG_ENCAP_L4_CSUM_REQUIRED; + + return (flags | NSS_VXLAN_RULE_FLAG_UDP); + } +@@ -118,25 +113,18 @@ static uint16_t nss_vxlanmgr_tunnel_flag + struct vxlan_config *cfg = &priv->cfg; + uint32_t priv_flags = cfg->flags; + +- if (priv_flags & VXLAN_F_RSC) +- return flags; +- if (priv_flags & VXLAN_F_GPE) +- return flags; + if (priv_flags & VXLAN_F_GBP) + flags |= NSS_VXLAN_RULE_FLAG_GBP_ENABLED; +- +- if (priv_flags & VXLAN_F_IPV6) { ++ if (priv_flags & VXLAN_F_IPV6) + flags |= NSS_VXLAN_RULE_FLAG_IPV6; +- if (!(priv_flags & VXLAN_F_UDP_ZERO_CSUM6_TX)) +- flags |= NSS_VXLAN_RULE_FLAG_ENCAP_L4_CSUM_REQUIRED; +- } else { ++ else if (!(priv_flags & VXLAN_F_IPV6)) + flags |= NSS_VXLAN_RULE_FLAG_IPV4; +- if (!(priv_flags & VXLAN_F_UDP_ZERO_CSUM_TX)) +- flags |= NSS_VXLAN_RULE_FLAG_ENCAP_L4_CSUM_REQUIRED; +- } +- + if (cfg->tos == 1) + flags |= NSS_VXLAN_RULE_FLAG_INHERIT_TOS; ++ if (priv_flags & VXLAN_F_UDP_ZERO_CSUM_TX) ++ flags |= NSS_VXLAN_RULE_FLAG_ENCAP_L4_CSUM_REQUIRED; ++ else if (!(priv_flags & VXLAN_F_UDP_ZERO_CSUM6_TX)) ++ flags |= NSS_VXLAN_RULE_FLAG_ENCAP_L4_CSUM_REQUIRED; + + return (flags | NSS_VXLAN_RULE_FLAG_UDP); + } +@@ -323,7 +311,6 @@ static nss_tx_status_t nss_vxlanmgr_tunn + union vxlan_addr *remote_ip, *src_ip; + uint32_t i, inner_ifnum; + uint32_t new_src_ip[4] = {0}; +- int32_t ipsec_if_num; + nss_tx_status_t status = NSS_TX_FAILURE; + + dev = vfe->dev; +@@ -380,17 +367,6 @@ static nss_tx_status_t nss_vxlanmgr_tunn + } + + /* +- * Check if this is a VxLAN over IPsec use case. If so, we need to bind the IPsec interface to the VxLAN. +- * When the IPsec interface is deleted in NSS, user is expected to bring the vxlan interface down as well, thereby flushing the MAC entries in NSS. +- */ +- ipsec_if_num = nss_vxlanmgr_bind_ipsec_by_ip(src_ip, remote_ip); +- if (ipsec_if_num > 0) { +- mac_add_msg->ipsec_if_num = (uint32_t)ipsec_if_num; +- mac_add_msg->flags = mac_add_msg->flags | NSS_VXLAN_MAC_ENABLE_IPSEC_BIND; +- nss_vxlanmgr_trace("%px: VxLAN interface is bound to IPsec interface with if_num(0x%x)\n", dev, ipsec_if_num); +- } +- +- /* + * Send MAC add message asynchronously as it is called by chain + * notifier in atomic context from the vxlan driver. + */ +@@ -460,8 +436,7 @@ static struct notifier_block nss_vxlanmg + + /* + * nss_vxlanmgr_tunnel_inner_stats() +- * Update vxlan netdev stats with inner node stats. +- * Note: Reference on the netdevice is expected to be held by the caller at the time this function is called. ++ * Update vxlan netdev stats with inner node stats + */ + static void nss_vxlanmgr_tunnel_inner_stats(struct nss_vxlanmgr_tun_ctx *tun_ctx, struct nss_vxlan_msg *nvm) + { +@@ -475,6 +450,7 @@ static void nss_vxlanmgr_tunnel_inner_st + stats = &nvm->msg.stats; + dev = tun_ctx->dev; + ++ dev_hold(dev); + netdev_stats = (struct net_device_stats *)&dev->stats; + + /* +@@ -493,6 +469,7 @@ static void nss_vxlanmgr_tunnel_inner_st + tstats->tx_bytes += stats->node_stats.tx_bytes; + u64_stats_update_end(&tstats->syncp); + netdev_stats->tx_dropped += dropped; ++ dev_put(dev); + } + + /* +@@ -537,7 +514,7 @@ static void nss_vxlanmgr_tunnel_outer_st + * nss_vxlanmgr_tunnel_fdb_update() + * Update vxlan fdb entries + */ +-static void nss_vxlanmgr_tunnel_fdb_update(struct net_device *dev, uint32_t vni, struct nss_vxlan_msg *nvm) ++static void nss_vxlanmgr_tunnel_fdb_update(struct nss_vxlanmgr_tun_ctx *tun_ctx, struct nss_vxlan_msg *nvm) + { + uint8_t *mac; + uint16_t i, nentries; +@@ -546,10 +523,13 @@ static void nss_vxlanmgr_tunnel_fdb_upda + + db_stats = &nvm->msg.db_stats; + nentries = db_stats->cnt; +- priv = netdev_priv(dev); ++ priv = netdev_priv(tun_ctx->dev); ++ ++ dev_hold(tun_ctx->dev); + + if (nentries > NSS_VXLAN_MACDB_ENTRIES_PER_MSG) { +- nss_vxlanmgr_warn("%px: No more than 20 entries allowed per message.\n", dev); ++ nss_vxlanmgr_warn("%px: No more than 20 entries allowed per message.\n", tun_ctx->dev); ++ dev_put(tun_ctx->dev); + return; + } + +@@ -559,10 +539,11 @@ static void nss_vxlanmgr_tunnel_fdb_upda + #if (LINUX_VERSION_CODE <= KERNEL_VERSION(4, 5, 7)) + vxlan_fdb_update_mac(priv, mac); + #else +- vxlan_fdb_update_mac(priv, mac, vni); ++ vxlan_fdb_update_mac(priv, mac, tun_ctx->vni); + #endif + } + } ++ dev_put(tun_ctx->dev); + } + + /* +@@ -574,29 +555,20 @@ static void nss_vxlanmgr_tunnel_inner_no + struct net_device *dev = (struct net_device *)app_data; + struct nss_vxlanmgr_tun_ctx *tun_ctx; + struct nss_vxlan_msg *nvm; +- uint32_t vni; + + if (!ncm) { + nss_vxlanmgr_info("%px: NULL msg received.\n", dev); + return; + } + +- if (!dev) { +- nss_vxlanmgr_info("%px: NULL device received.\n", dev); +- return; +- } +- + spin_lock_bh(&vxlan_ctx.tun_lock); +- dev_hold(dev); + tun_ctx = nss_vxlanmgr_tunnel_ctx_dev_get(dev); + if (!tun_ctx) { + spin_unlock_bh(&vxlan_ctx.tun_lock); + nss_vxlanmgr_warn("%px: Invalid tunnel context\n", dev); +- dev_put(dev); + return; + } + +- vni = tun_ctx->vni; + nvm = (struct nss_vxlan_msg *)ncm; + switch (nvm->cm.type) { + case NSS_VXLAN_MSG_TYPE_STATS_SYNC: +@@ -604,24 +576,14 @@ static void nss_vxlanmgr_tunnel_inner_no + nss_vxlanmgr_tun_stats_sync(tun_ctx, nvm); + break; + case NSS_VXLAN_MSG_TYPE_MACDB_STATS: ++ nss_vxlanmgr_tunnel_fdb_update(tun_ctx, nvm); + nss_vxlanmgr_tun_macdb_stats_sync(tun_ctx, nvm); +- +- /* +- * Release the lock before updating the Linux FDB entry. +- * This will ensure there is no deadlock when a potential +- * MAC add event occurs at same time, which needs to hold +- * the kernel's hash lock followed by the tunnel ctx lock. +- */ +- spin_unlock_bh(&vxlan_ctx.tun_lock); +- +- nss_vxlanmgr_tunnel_fdb_update(dev, vni, nvm); +- dev_put(dev); +- return; ++ break; + default: ++ spin_unlock_bh(&vxlan_ctx.tun_lock); + nss_vxlanmgr_info("%px: Unknown Event from NSS", dev); ++ return; + } +- +- dev_put(dev); + spin_unlock_bh(&vxlan_ctx.tun_lock); + } + +@@ -867,7 +829,7 @@ done: + */ + int nss_vxlanmgr_tunnel_destroy(struct net_device *dev) + { +- uint32_t inner_ifnum, outer_ifnum, tun_count; ++ uint32_t inner_ifnum, outer_ifnum; + struct nss_vxlanmgr_tun_ctx *tun_ctx; + struct nss_vxlan_msg vxlanmsg; + nss_tx_status_t ret; +@@ -904,21 +866,16 @@ int nss_vxlanmgr_tunnel_destroy(struct n + + nss_vxlanmgr_tun_stats_deinit(tun_ctx); + nss_vxlanmgr_tun_stats_dentry_remove(tun_ctx); +- dev_put(tun_ctx->dev); + kfree(tun_ctx); + +- /* +- * Unregister fdb notifier chain if +- * all vxlan tunnels are destroyed. +- */ +- spin_lock_bh(&vxlan_ctx.tun_lock); +- tun_count = vxlan_ctx.tun_count; +- spin_unlock_bh(&vxlan_ctx.tun_lock); +- if (!tun_count) { ++ if (!vxlan_ctx.tun_count) { ++ /* ++ * Unregister fdb notifier chain if ++ * all vxlan tunnels are destroyed. ++ */ + vxlan_fdb_unregister_notify(&nss_vxlanmgr_tunnel_fdb_notifier); + } +- +- nss_vxlanmgr_info("%px: VxLAN interface count is #%d\n", dev, tun_count); ++ nss_vxlanmgr_info("%px: VxLAN interface count is #%d\n", dev, vxlan_ctx.tun_count); + + memset(&vxlanmsg, 0, sizeof(struct nss_vxlan_msg)); + ret = nss_vxlanmgr_tunnel_tx_msg_sync(vxlan_ctx.nss_ctx, +@@ -972,7 +929,6 @@ int nss_vxlanmgr_tunnel_create(struct ne + struct nss_vxlan_rule_msg *vxlan_cfg; + struct nss_ctx_instance *nss_ctx; + uint32_t inner_ifnum, outer_ifnum; +- uint16_t parse_flags; + nss_tx_status_t ret; + + spin_lock_bh(&vxlan_ctx.tun_lock); +@@ -983,20 +939,7 @@ int nss_vxlanmgr_tunnel_create(struct ne + } + spin_unlock_bh(&vxlan_ctx.tun_lock); + +- /* +- * The reference to the dev will be released in nss_vxlanmgr_tunnel_destroy() +- */ + dev_hold(dev); +- priv = netdev_priv(dev); +- parse_flags = nss_vxlanmgr_tunnel_flags_parse(priv); +- +- /* +- * Check if the tunnel is supported. +- */ +- if (!parse_flags) { +- nss_vxlanmgr_warn("%px: Tunnel offload not supported\n", dev); +- goto ctx_alloc_fail; +- } + + tun_ctx = kzalloc(sizeof(struct nss_vxlanmgr_tun_ctx), GFP_ATOMIC); + if (!tun_ctx) { +@@ -1045,11 +988,12 @@ int nss_vxlanmgr_tunnel_create(struct ne + memset(&vxlanmsg, 0, sizeof(struct nss_vxlan_msg)); + vxlan_cfg = &vxlanmsg.msg.vxlan_create; + ++ priv = netdev_priv(dev); + vxlan_cfg->vni = vxlan_get_vni(priv); +- vxlan_cfg->tunnel_flags = parse_flags; ++ vxlan_cfg->tunnel_flags = nss_vxlanmgr_tunnel_flags_parse(priv); + vxlan_cfg->src_port_min = priv->cfg.port_min; + vxlan_cfg->src_port_max = priv->cfg.port_max; +- vxlan_cfg->dest_port = ntohs(priv->cfg.dst_port); ++ vxlan_cfg->dest_port = priv->cfg.dst_port; + vxlan_cfg->tos = priv->cfg.tos; + vxlan_cfg->ttl = (priv->cfg.ttl ? priv->cfg.ttl : IPDEFTTL); + +@@ -1115,6 +1059,7 @@ int nss_vxlanmgr_tunnel_create(struct ne + spin_unlock_bh(&vxlan_ctx.tun_lock); + nss_vxlanmgr_info("%px: VxLAN interface count is #%d\n", dev, vxlan_ctx.tun_count); + ++ dev_put(dev); + return NOTIFY_DONE; + + config_fail: +--- a/wifi_meshmgr/Makefile ++++ /dev/null +@@ -1,7 +0,0 @@ +-ccflags-y += -I$(obj)/../exports -I$(obj)/.. -I$(obj)/nss_hal/include +-ccflags-y += -DNSS_CLIENT_BUILD_ID="$(BUILD_ID)" +-ccflags-y += -DNSS_WIFI_MESHMGR_DEBUG_LEVEL=4 +-ccflags-y += -Wall -Werror +- +-obj-m += qca-nss-wifi-meshmgr.o +-qca-nss-wifi-meshmgr-objs := nss_wifi_meshmgr.o +--- a/wifi_meshmgr/nss_wifi_mesh_priv.h ++++ /dev/null +@@ -1,83 +0,0 @@ +-/* +- ************************************************************************** +- * Copyright (c) 2021, The Linux Foundation. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for any +- * purpose with or without fee is hereby granted, provided that the above +- * copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- ************************************************************************** +- */ +- +-/* +- * nss_wifi_mesh_priv.h +- * Mesh manager header +- */ +-#ifndef __NSS_WIFI_MESH_PRIV_H_ +-#define __NSS_WIFI_MESH_PRIV_H_ +- +-#define NSS_WIFI_MESH_MAX 16 +- +-/* +- * Compile messages for dynamic enable/disable +- */ +-#if defined(CONFIG_DYNAMIC_DEBUG) +-#define nss_wifi_meshmgr_warn(s, ...) pr_debug("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__) +-#define nss_wifi_meshmgr_info(s, ...) pr_debug("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__) +-#define nss_wifi_meshmgr_trace(s, ...) pr_debug("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__) +-#else /* CONFIG_DYNAMIC_DEBUG */ +-/* +- * Statically compile messages at different levels +- */ +-#if (NSS_WIFI_MESHMGR_DEBUG_LEVEL < 2) +-#define nss_wifi_meshmgr_warn(s, ...) +-#else +-#define nss_wifi_meshmgr_warn(s, ...) pr_warn("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__) +-#endif +- +-#if (NSS_WIFI_MESHMGR_DEBUG_LEVEL < 3) +-#define nss_wifi_meshmgr_info(s, ...) +-#else +-#define nss_wifi_meshmgr_info(s, ...) pr_notice("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__) +-#endif +- +-#if (NSS_WIFI_MESHMGR_DEBUG_LEVEL < 4) +-#define nss_wifi_meshmgr_trace(s, ...) +-#else +-#define nss_wifi_meshmgr_trace(s, ...) pr_info("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__) +-#endif +-#endif /* CONFIG_DYNAMIC_DEBUG */ +- +-/* +- * nss_wifi_meshmgr_mesh_ctx +- * Mesh context per interface. +- */ +-struct nss_wifi_meshmgr_mesh_ctx { +- struct net_device *dev; /* Netdevice pointer */ +- atomic_t ref; /* Atomic reference count */ +- int32_t encap_ifnum; /* Encap interface number */ +- int32_t decap_ifnum; /* Decap interface number */ +- struct semaphore sem; /* Semaphore for message synchronization */ +- struct completion complete; /* Per context complete */ +- nss_tx_status_t response; /* Response type */ +-}; +- +-/* +- * nss_wifi_meshmgr_ctx +- * Global mesh context. +- */ +-struct nss_wifi_meshmgr_ctx { +- struct nss_ctx_instance *nss_ctx; /* Nss context for mesh */ +- uint32_t mesh_count; /* Active mesh count */ +- spinlock_t ref_lock; /* Spinlock */ +- struct nss_wifi_meshmgr_mesh_ctx *mesh_ctx[NSS_WIFI_MESH_MAX]; +- /* Mesh handle table */ +-}; +-#endif /* __NSS_WIFI_MESH_PRIV_H_ */ +--- a/wifi_meshmgr/nss_wifi_meshmgr.c ++++ /dev/null +@@ -1,2005 +0,0 @@ +-/* +- ************************************************************************** +- * Copyright (c) 2021, The Linux Foundation. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for any +- * purpose with or without fee is hereby granted, provided that the above +- * copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- ************************************************************************** +- */ +- +-/* +- * nss_wifi_meshmgr.c +- * NSS to HLOS WiFi-Mesh manager +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include "nss_wifi_mesh_priv.h" +- +-/* +- * WiFi-Mesh context +- */ +-static struct nss_wifi_meshmgr_ctx wmgr_ctx; +- +-/* +- * nss_wifi_meshmgr_verify_if_num() +- * Verify interface number. +- */ +-static bool nss_wifi_meshmgr_verify_if_num(int32_t if_num, enum nss_dynamic_interface_type di_type) +-{ +- return (nss_is_dynamic_interface(if_num) && +- (nss_dynamic_interface_get_type(wmgr_ctx.nss_ctx, if_num) == di_type)); +-} +- +-/* +- * nss_wifi_meshmgr_tx_msg() +- * WiFi-Mesh message send API +- */ +-static nss_wifi_meshmgr_status_t nss_wifi_meshmgr_tx_msg(struct nss_wifi_mesh_msg *msg) +-{ +- return nss_wifi_mesh_tx_msg(wmgr_ctx.nss_ctx, msg); +-} +- +-/* +- * nss_wifi_meshmgr_ctx_insert() +- * Insert the mesh context into global table +- */ +-static int32_t nss_wifi_meshmgr_ctx_insert(struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx) +-{ +- int32_t i, idx = -1; +- struct net_device *dev; +- +- assert_spin_locked(&wmgr_ctx.ref_lock); +- +- /* +- * Check if the context already exist for the same netdev. +- */ +- for (i = 0; i < NSS_WIFI_MESH_MAX; i++) { +- if (!wmgr_ctx.mesh_ctx[i]) { +- idx = i; +- continue; +- } +- +- dev = (wmgr_ctx.mesh_ctx[i])->dev; +- if (dev == wmesh_ctx->dev) { +- nss_wifi_meshmgr_warn("%px: The mesh context already exist for dev:%s", +- &wmgr_ctx, wmesh_ctx->dev->name); +- return -1; +- } +- } +- +- if (idx == -1) { +- return idx; +- } +- +- wmgr_ctx.mesh_ctx[idx] = wmesh_ctx; +- return idx; +-} +- +-/* +- * nss_wifi_meshmgr_ctx_remove() +- * Remove the mesh context from global table +- */ +-static void nss_wifi_meshmgr_ctx_remove(struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx) +-{ +- int32_t i; +- +- assert_spin_locked(&wmgr_ctx.ref_lock); +- +- for (i = 0; i < NSS_WIFI_MESH_MAX; i++) { +- if (wmgr_ctx.mesh_ctx[i] != wmesh_ctx) { +- continue; +- } +- +- wmgr_ctx.mesh_ctx[i] = NULL; +- return; +- } +-} +- +-/* +- * nss_wifi_meshmgr_cleanup() +- * Clean up the mesh context. +- */ +-static void nss_wifi_meshmgr_cleanup(struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx) +-{ +- int32_t encap_ifnum, decap_ifnum; +- nss_wifi_meshmgr_status_t nss_status; +- +- nss_wifi_meshmgr_trace("%px: Mesh handle cleanup called for: %s\n", &wmgr_ctx, wmesh_ctx->dev->name); +- +- encap_ifnum = wmesh_ctx->encap_ifnum; +- decap_ifnum = wmesh_ctx->decap_ifnum; +- +- /* +- * Unregister and dealloc decap DI. +- */ +- nss_unregister_wifi_mesh_if(decap_ifnum); +- nss_status = nss_dynamic_interface_dealloc_node(decap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_OUTER); +- if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { +- nss_wifi_meshmgr_warn("%px: Failed to dealloc decap: %d\n", &wmgr_ctx, nss_status); +- } +- +- /* +- * Unregister and dealloc encap DI. +- */ +- nss_unregister_wifi_mesh_if(encap_ifnum); +- nss_status = nss_dynamic_interface_dealloc_node(encap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER); +- if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { +- nss_wifi_meshmgr_warn("%px: Failed to dealloc encap: %d\n", &wmgr_ctx, nss_status); +- } +- +- dev_put(wmesh_ctx->dev); +- kfree(wmesh_ctx); +-} +- +-/* +- * nss_wifi_meshmgr_ref_dec() +- * Find and decrement the reference counter. +- */ +-static void nss_wifi_meshmgr_ref_dec(struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx) +-{ +- if (atomic_dec_and_test(&wmesh_ctx->ref)) { +- nss_wifi_meshmgr_cleanup(wmesh_ctx); +- } +-} +- +-/* +- * nss_wifi_meshmgr_find_and_ref_inc() +- * Find and inreae the reference counter. +- */ +-static struct nss_wifi_meshmgr_mesh_ctx *nss_wifi_meshmgr_find_and_ref_inc(nss_wifi_mesh_handle_t mesh_handle) +-{ +- struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; +- +- if ((mesh_handle < 0) || (mesh_handle >= NSS_WIFI_MESH_MAX)) { +- nss_wifi_meshmgr_warn("%px: Invalid mesh handle: %d\n", &wmgr_ctx, mesh_handle); +- return NULL; +- } +- +- spin_lock_bh(&wmgr_ctx.ref_lock); +- wmesh_ctx = wmgr_ctx.mesh_ctx[mesh_handle]; +- if (wmesh_ctx && atomic_inc_and_test(&wmesh_ctx->ref)) { +- BUG_ON(1); +- } +- spin_unlock_bh(&wmgr_ctx.ref_lock); +- return wmesh_ctx; +-} +- +-/* +- * nss_wifi_meshmgr_remap_error() +- * Remap the error code. +- */ +-static nss_wifi_meshmgr_status_t nss_wifi_meshmgr_remap_error(enum nss_wifi_mesh_error_types error) +-{ +- switch (error) { +- case NSS_WIFI_MESH_ERROR_UNKNOWN_MSG: +- return NSS_WIFI_MESHMGR_FAILURE_UNKNOWN_MSG; +- case NSS_WIFI_MESH_ERROR_TTL_CONFIG: +- return NSS_WIFI_MESHMGR_FAILURE_TTL_CONFIG; +- case NSS_WIFI_MESH_ERROR_REFRESH_TIME_CONFIG: +- return NSS_WIFI_MESHMGR_FAILURE_REFRESH_TIME_CONFIG; +- case NSS_WIFI_MESH_ERROR_MPP_LEARNING_MODE_CONFIG: +- return NSS_WIFI_MESHMGR_FAILURE_MPP_LEARNING_MODE_CONFIG; +- case NSS_WIFI_MESH_ERROR_PATH_ADD_MAX_RADIO_CNT: +- return NSS_WIFI_MESHMGR_FAILURE_PATH_ADD_MAX_RADIO_CNT; +- case NSS_WIFI_MESH_ERROR_PATH_ADD_INVALID_INTERFACE_NUM: +- return NSS_WIFI_MESHMGR_FAILURE_PATH_ADD_INVALID_INTERFACE_NUM; +- case NSS_WIFI_MESH_ERROR_PATH_ADD_INTERFACE_NUM_NOT_FOUND: +- return NSS_WIFI_MESHMGR_FAILURE_PATH_ADD_INTERFACE_NUM_NOT_FOUND; +- case NSS_WIFI_MESH_ERROR_PATH_TABLE_FULL: +- return NSS_WIFI_MESHMGR_FAILURE_PATH_TABLE_FULL; +- case NSS_WIFI_MESH_ERROR_PATH_ALLOC_FAIL: +- return NSS_WIFI_MESHMGR_FAILURE_PATH_ALLOC_FAIL; +- case NSS_WIFI_MESH_ERROR_PATH_INSERT_FAIL: +- return NSS_WIFI_MESHMGR_FAILURE_PATH_INSERT_FAIL; +- case NSS_WIFI_MESH_ERROR_PATH_NOT_FOUND: +- return NSS_WIFI_MESHMGR_FAILURE_PATH_NOT_FOUND; +- case NSS_WIFI_MESH_ERROR_PATH_UNHASHED: +- return NSS_WIFI_MESHMGR_FAILURE_PATH_UNHASHED; +- case NSS_WIFI_MESH_ERROR_PATH_DELETE_FAIL: +- return NSS_WIFI_MESHMGR_FAILURE_PATH_DELETE_FAIL; +- case NSS_WIFI_MESH_ERROR_PROXY_PATH_NOT_FOUND: +- return NSS_WIFI_MESHMGR_FAILURE_PROXY_PATH_NOT_FOUND; +- case NSS_WIFI_MESH_ERROR_PROXY_PATH_UNHASHED: +- return NSS_WIFI_MESHMGR_FAILURE_PROXY_PATH_UNHASHED; +- case NSS_WIFI_MESH_ERROR_PROXY_PATH_DELETE_FAIL: +- return NSS_WIFI_MESHMGR_FAILURE_PROXY_PATH_DELETE_FAIL; +- case NSS_WIFI_MESH_ERROR_PROXY_PATH_EXISTS: +- return NSS_WIFI_MESHMGR_FAILURE_PROXY_PATH_EXISTS; +- case NSS_WIFI_MESH_ERROR_PROXY_PATH_ALLOC_FAIL: +- return NSS_WIFI_MESHMGR_FAILURE_PROXY_PATH_ALLOC_FAIL; +- case NSS_WIFI_MESH_ERROR_PROXY_PATH_INSERT_FAIL: +- return NSS_WIFI_MESHMGR_FAILURE_PROXY_PATH_INSERT_FAIL; +- case NSS_WIFI_MESH_ERROR_PROXY_PATH_TABLE_FULL: +- return NSS_WIFI_MESHMGR_FAILURE_PROXY_PATH_TABLE_FULL; +- case NSS_WIFI_MESH_ERROR_PB_ALLOC_FAIL: +- return NSS_WIFI_MESHMGR_FAILURE_PB_ALLOC_FAIL; +- case NSS_WIFI_MESH_ERROR_ENQUEUE_TO_HOST_FAIL: +- return NSS_WIFI_MESHMGR_FAILURE_ENQUEUE_TO_HOST_FAIL; +- case NSS_WIFI_MESH_ERROR_ENABLE_INTERFACE_FAIL: +- return NSS_WIFI_MESHMGR_FAILURE_ENABLE_INTERFACE_FAIL; +- case NSS_WIFI_MESH_ERROR_DISABLE_INTERFACE_FAIL: +- return NSS_WIFI_MESHMGR_FAILURE_DISABLE_INTERFACE_FAIL; +- case NSS_WIFI_MESH_ERROR_INVALID_EXCEPTION_NUM: +- return NSS_WIFI_MESHMGR_FAILURE_INVALID_EXCEPTION_NUM; +- case NSS_WIFI_MESH_ERROR_ONESHOT_ALREADY_ATTACHED: +- return NSS_WIFI_MESHMGR_FAILURE_ONESHOT_ALREADY_ATTACHED; +- case NSS_WIFI_MESH_ERROR_DUMMY_PATH_ADD_FAILED: +- return NSS_WIFI_MESHMGR_FAILURE_DUMMY_PATH_ADD; +- case NSS_WIFI_MESH_ERROR_DUMMY_PROXY_PATH_ADD_FAILED: +- return NSS_WIFI_MESHMGR_FAILURE_DUMMY_PROXY_PATH_ADD; +- default: +- return NSS_WIFI_MESHMGR_FAILURE; +- }; +-} +- +-/* +- * nss_wifi_meshmgr_tx_msg_cb() +- * Callback to handle the completion of NSS->HLOS messages. +- */ +-static void nss_wifi_meshmgr_tx_msg_cb(void *app_data, struct nss_cmn_msg *ncm) +-{ +- struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx = (struct nss_wifi_meshmgr_mesh_ctx *)app_data; +- uint32_t error_code = ncm->error; +- +- /* +- * FIXME: The wmesh_ctx can be invalid if the memory goes away with the caller being timedout. +- */ +- wmesh_ctx->response = NSS_WIFI_MESHMGR_SUCCESS; +- if (ncm->response != NSS_CMN_RESPONSE_ACK) { +- nss_wifi_meshmgr_warn("%px: WiFi-Mesh error response %d error_code: %u\n", &wmgr_ctx, ncm->response, error_code); +- wmesh_ctx->response = nss_wifi_meshmgr_remap_error(error_code); +- } +- +- complete(&wmesh_ctx->complete); +-} +- +- /* +- * nss_wifi_meshmgr_tx_msg_sync() +- * Transmit a WiFi mesh message to NSS firmware synchronously. +- */ +-static nss_wifi_meshmgr_status_t nss_wifi_meshmgr_tx_msg_sync(struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx, struct nss_wifi_mesh_msg *wmesh_msg) +-{ +- nss_wifi_meshmgr_status_t status; +- int ret; +- +- down(&wmesh_ctx->sem); +- status = nss_wifi_meshmgr_tx_msg(wmesh_msg); +- if (status != NSS_WIFI_MESHMGR_SUCCESS) { +- nss_wifi_meshmgr_warn("%px: WiFi mesh tx sync msg failed: %d\n", &wmgr_ctx, status); +- up(&wmesh_ctx->sem); +- return status; +- } +- +- /* +- * Wait for the acknowledgement. +- */ +- ret = wait_for_completion_timeout(&wmesh_ctx->complete, msecs_to_jiffies(NSS_WIFI_MESH_TX_TIMEOUT)); +- if (!ret) { +- nss_wifi_meshmgr_warn("%px: WiFi mesh msg tx failed due to timeout\n", &wmgr_ctx); +- wmesh_ctx->response = NSS_WIFI_MESHMGR_FAILURE_SYNC_TIMEOUT; +- } +- +- status = wmesh_ctx->response; +- up(&wmesh_ctx->sem); +- return status; +-} +- +-/* +- * nss_wifi_meshmgr_tx_buf() +- * Send packets to mesh I/F +- */ +-nss_wifi_meshmgr_status_t nss_wifi_meshmgr_tx_buf(nss_wifi_mesh_handle_t mesh_handle, struct sk_buff *os_buf) +-{ +- struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; +- int32_t encap_ifnum; +- nss_wifi_meshmgr_status_t nss_status; +- +- wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); +- if (!wmesh_ctx) { +- nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); +- return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; +- } +- +- encap_ifnum = wmesh_ctx->encap_ifnum; +- +- /* +- * Verify the encap I/F number against it types. +- */ +- if (!(nss_wifi_meshmgr_verify_if_num(encap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER))) { +- nss_wifi_meshmgr_warn("%px: I/F num: 0x%x verification failed\n", &wmgr_ctx, encap_ifnum); +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return NSS_WIFI_MESHMGR_FAILURE; +- } +- +- nss_status = nss_wifi_mesh_tx_buf(wmgr_ctx.nss_ctx, os_buf, encap_ifnum); +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return nss_status; +-} +-EXPORT_SYMBOL(nss_wifi_meshmgr_tx_buf); +- +-/* +- * nss_wifi_meshmgr_if_down() +- * Make the NSS interface down synchronously. +- */ +-nss_wifi_meshmgr_status_t nss_wifi_meshmgr_if_down(nss_wifi_mesh_handle_t mesh_handle) +-{ +- struct nss_wifi_mesh_msg wmesh_msg; +- struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; +- nss_wifi_meshmgr_status_t nss_status; +- int32_t encap_ifnum, decap_ifnum; +- +- wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); +- if (!wmesh_ctx) { +- nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); +- return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; +- } +- +- encap_ifnum = wmesh_ctx->encap_ifnum; +- decap_ifnum = wmesh_ctx->decap_ifnum; +- +- /* +- * Verify the I/F encap and decap number against it types. +- */ +- if (!(nss_wifi_meshmgr_verify_if_num(encap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER) || +- nss_wifi_meshmgr_verify_if_num(decap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_OUTER))) { +- nss_wifi_meshmgr_warn("%px: Interface verification failed\n", &wmgr_ctx); +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return NSS_WIFI_MESHMGR_FAILURE; +- } +- +- /* +- * Initialize the encap I/F down message. +- */ +- memset(&wmesh_msg, 0, sizeof(struct nss_wifi_mesh_msg)); +- nss_wifi_mesh_msg_init(&wmesh_msg, encap_ifnum, NSS_IF_CLOSE, +- sizeof(struct nss_if_close), nss_wifi_meshmgr_tx_msg_cb, wmesh_ctx); +- +- /* +- * Send the I/F down message to the encap I/F. +- */ +- nss_status = nss_wifi_meshmgr_tx_msg_sync(wmesh_ctx, &wmesh_msg); +- if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { +- nss_wifi_meshmgr_warn("%px: Mesh link encap I/F down failed: %d.\n", &wmgr_ctx, nss_status); +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return nss_status; +- } +- +- /* +- * Initialize the decap I/F down message. +- */ +- memset(&wmesh_msg, 0, sizeof(struct nss_wifi_mesh_msg)); +- nss_wifi_mesh_msg_init(&wmesh_msg, decap_ifnum, NSS_IF_CLOSE, +- sizeof(struct nss_if_close), nss_wifi_meshmgr_tx_msg_cb, wmesh_ctx); +- +- /* +- * Send the I/F down message to the decap I/F. +- */ +- nss_status = nss_wifi_meshmgr_tx_msg_sync(wmesh_ctx, &wmesh_msg); +- if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { +- nss_wifi_meshmgr_warn("%px: Mesh link decap I/F down failed: %d.\n", &wmgr_ctx, nss_status); +- } +- +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return nss_status; +-} +-EXPORT_SYMBOL(nss_wifi_meshmgr_if_down); +- +-/* +- * nss_wifi_meshmgr_if_up() +- * Make the NSS interface up synchronously. +- */ +-nss_wifi_meshmgr_status_t nss_wifi_meshmgr_if_up(nss_wifi_mesh_handle_t mesh_handle) +-{ +- struct nss_wifi_mesh_msg wmesh_msg; +- struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; +- nss_wifi_meshmgr_status_t nss_status; +- int32_t encap_ifnum, decap_ifnum; +- +- wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); +- if (!wmesh_ctx) { +- nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); +- return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; +- } +- +- encap_ifnum = wmesh_ctx->encap_ifnum; +- decap_ifnum = wmesh_ctx->decap_ifnum; +- +- /* +- * Verify the I/F encap and decap number against it types. +- */ +- if (!(nss_wifi_meshmgr_verify_if_num(encap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER) || +- nss_wifi_meshmgr_verify_if_num(decap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_OUTER))) { +- nss_wifi_meshmgr_warn("%px: Interface verification failed\n", &wmgr_ctx); +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return NSS_WIFI_MESHMGR_FAILURE; +- } +- +- /* +- * Initialize the encap I/F up message. +- */ +- memset(&wmesh_msg, 0, sizeof(struct nss_wifi_mesh_msg)); +- nss_wifi_mesh_msg_init(&wmesh_msg, encap_ifnum, NSS_IF_OPEN, +- sizeof(struct nss_if_open), nss_wifi_meshmgr_tx_msg_cb, wmesh_ctx); +- +- /* +- * Send the I/F up message to the encap I/F. +- */ +- nss_status = nss_wifi_meshmgr_tx_msg_sync(wmesh_ctx, &wmesh_msg); +- if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { +- nss_wifi_meshmgr_warn("%px: Mesh link encap I/F up failed: %d.\n", &wmgr_ctx, nss_status); +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return nss_status; +- } +- +- /* +- * Initialize the I/F decap up message. +- */ +- memset(&wmesh_msg, 0, sizeof(struct nss_wifi_mesh_msg)); +- nss_wifi_mesh_msg_init(&wmesh_msg, decap_ifnum, NSS_IF_OPEN, +- sizeof(struct nss_if_open), nss_wifi_meshmgr_tx_msg_cb, wmesh_ctx); +- +- /* +- * Send the I/F up message to the decap interface. +- */ +- nss_status = nss_wifi_meshmgr_tx_msg_sync(wmesh_ctx, &wmesh_msg); +- if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { +- nss_wifi_meshmgr_warn("%px: Mesh link decap I/F up failed: %d.\n", &wmgr_ctx, nss_status); +- } +- +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return nss_status; +-} +-EXPORT_SYMBOL(nss_wifi_meshmgr_if_up); +- +-/* +- * nss_wifi_meshmgr_dump_mesh_path() +- * Dump mesh path table request asynchronously. +- */ +-nss_wifi_meshmgr_status_t +-nss_wifi_meshmgr_dump_mesh_path(nss_wifi_mesh_handle_t mesh_handle, nss_wifi_mesh_msg_callback_t msg_cb, void *app_data) +-{ +- struct nss_wifi_mesh_msg wmesh_msg; +- struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; +- nss_wifi_meshmgr_status_t nss_status; +- int32_t encap_ifnum; +- +- wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); +- if (!wmesh_ctx) { +- nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); +- return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; +- } +- +- encap_ifnum = wmesh_ctx->encap_ifnum; +- +- /* +- * Verify the encap I/F number against it types. +- */ +- if (!(nss_wifi_meshmgr_verify_if_num(encap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER))) { +- nss_wifi_meshmgr_warn("%px: I/F num: 0x%x verification failed\n", &wmgr_ctx, encap_ifnum); +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return NSS_WIFI_MESHMGR_FAILURE; +- } +- +- /* +- * Initialize the path dump request message. +- */ +- memset(&wmesh_msg, 0, sizeof(struct nss_wifi_mesh_msg)); +- nss_wifi_mesh_msg_init(&wmesh_msg, encap_ifnum, NSS_WIFI_MESH_MSG_PATH_TABLE_DUMP, +- sizeof(struct nss_wifi_mesh_path_table_dump), msg_cb, app_data); +- +- /* +- * Send the path dump request mesage to the NSS asynchronously. +- */ +- nss_status = nss_wifi_meshmgr_tx_msg(&wmesh_msg); +- if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { +- nss_wifi_meshmgr_warn("%px: Mesh dump mesh path failed: %d.\n", &wmgr_ctx, nss_status); +- } +- +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return nss_status; +-} +-EXPORT_SYMBOL(nss_wifi_meshmgr_dump_mesh_path); +- +-/* +- * nss_wifi_meshmgr_dump_mesh_path_sync() +- * Dump mesh path table request synchronously. +- */ +-nss_wifi_meshmgr_status_t +-nss_wifi_meshmgr_dump_mesh_path_sync(nss_wifi_mesh_handle_t mesh_handle) +-{ +- struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; +- nss_wifi_meshmgr_status_t nss_status; +- int32_t ret; +- +- wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); +- if (!wmesh_ctx) { +- nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); +- return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; +- } +- +- /* +- * Send the path dump request mesage to the NSS synchronously. +- */ +- down(&wmesh_ctx->sem); +- nss_status = nss_wifi_meshmgr_dump_mesh_path(mesh_handle, nss_wifi_meshmgr_tx_msg_cb, wmesh_ctx); +- if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { +- nss_wifi_meshmgr_warn("%px: WiFi mesh path dump msg failed: %d.\n", &wmgr_ctx, nss_status); +- up(&wmesh_ctx->sem); +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return nss_status; +- } +- +- /* +- * Wait for the acknowledgement +- */ +- ret = wait_for_completion_timeout(&wmesh_ctx->complete, msecs_to_jiffies(NSS_WIFI_MESH_TX_TIMEOUT)); +- if (!ret) { +- nss_wifi_meshmgr_warn("%px: WiFi mesh msg tx failed due to timeout\n", &wmgr_ctx); +- wmesh_ctx->response = NSS_WIFI_MESHMGR_FAILURE_SYNC_TIMEOUT; +- } +- +- nss_status = wmesh_ctx->response; +- up(&wmesh_ctx->sem); +- +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return nss_status; +-} +-EXPORT_SYMBOL(nss_wifi_meshmgr_dump_mesh_path_sync); +- +-/* +- * nss_wifi_meshmgr_dump_mesh_proxy_path() +- * Dump mesh proxy path table request asynchronously. +- */ +-nss_wifi_meshmgr_status_t +-nss_wifi_meshmgr_dump_mesh_proxy_path(nss_wifi_mesh_handle_t mesh_handle, nss_wifi_mesh_msg_callback_t msg_cb, void *app_data) +-{ +- struct nss_wifi_mesh_msg wmesh_msg; +- struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; +- nss_wifi_meshmgr_status_t nss_status; +- int32_t encap_ifnum; +- +- wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); +- if (!wmesh_ctx) { +- nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); +- return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; +- } +- +- encap_ifnum = wmesh_ctx->encap_ifnum; +- +- /* +- * Verify the encap I/F number against it types. +- */ +- if (!(nss_wifi_meshmgr_verify_if_num(encap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER))) { +- nss_wifi_meshmgr_warn("%px: I/F num: 0x%x verification failed\n", &wmgr_ctx, encap_ifnum); +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return NSS_WIFI_MESHMGR_FAILURE; +- } +- +- /* +- * Initialize the proxy path table message. +- */ +- memset(&wmesh_msg, 0, sizeof(struct nss_wifi_mesh_msg)); +- nss_wifi_mesh_msg_init(&wmesh_msg, encap_ifnum, NSS_WIFI_MESH_MSG_PROXY_PATH_TABLE_DUMP, +- sizeof(struct nss_wifi_mesh_proxy_path_table_dump), msg_cb, app_data); +- +- /* +- * Send the proxy path dump message to NSS asynchronously. +- */ +- nss_status = nss_wifi_meshmgr_tx_msg(&wmesh_msg); +- if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { +- nss_wifi_meshmgr_warn("%px: Mesh link vap proxy path dump failed: %d.\n", &wmgr_ctx, nss_status); +- } +- +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return nss_status; +-} +-EXPORT_SYMBOL(nss_wifi_meshmgr_dump_mesh_proxy_path); +- +-/* +- * nss_wifi_meshmgr_dump_mesh_path_sync() +- * Dump mesh proxy path table request synchronously. +- */ +-nss_wifi_meshmgr_status_t +-nss_wifi_meshmgr_dump_mesh_proxy_path_sync(nss_wifi_mesh_handle_t mesh_handle) +-{ +- struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; +- nss_wifi_meshmgr_status_t nss_status; +- int32_t ret; +- +- wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); +- if (!wmesh_ctx) { +- nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); +- return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; +- } +- +- /* +- * Send the path dump request to the NSS synchronously. +- */ +- down(&wmesh_ctx->sem); +- nss_status = nss_wifi_meshmgr_dump_mesh_proxy_path(mesh_handle, nss_wifi_meshmgr_tx_msg_cb, wmesh_ctx); +- if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { +- nss_wifi_meshmgr_warn("%px: WiFi mesh proxy path dump msg failed: %d.\n", &wmgr_ctx, nss_status); +- up(&wmesh_ctx->sem); +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return nss_status; +- } +- +- /* +- * Wait for the acknowledgement +- */ +- ret = wait_for_completion_timeout(&wmesh_ctx->complete, msecs_to_jiffies(NSS_WIFI_MESH_TX_TIMEOUT)); +- if (!ret) { +- nss_wifi_meshmgr_warn("%px: WiFi mesh msg tx failed due to timeout\n", &wmgr_ctx); +- wmesh_ctx->response = NSS_WIFI_MESHMGR_FAILURE_SYNC_TIMEOUT; +- } +- +- nss_status = wmesh_ctx->response; +- up(&wmesh_ctx->sem); +- +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return nss_status; +-} +-EXPORT_SYMBOL(nss_wifi_meshmgr_dump_mesh_proxy_path_sync); +- +-/* +- * nss_wifi_meshmgr_assoc_link_vap() +- * Associate the link interface to the mesh I/F asynchronously. +- */ +-nss_wifi_meshmgr_status_t +-nss_wifi_meshmgr_assoc_link_vap(nss_wifi_mesh_handle_t mesh_handle, struct nss_wifi_mesh_assoc_link_vap *wmalv, +- nss_wifi_mesh_msg_callback_t msg_cb, void *app_data) +-{ +- struct nss_wifi_vdev_msg *wifivdevmsg; +- struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; +- struct nss_wifi_vdev_set_next_hop_msg *next_hop_msg = NULL; +- int32_t decap_ifnum, link_ifnum; +- nss_wifi_meshmgr_status_t nss_status; +- +- wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); +- if (!wmesh_ctx) { +- nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); +- return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; +- } +- +- wifivdevmsg = kzalloc(sizeof(*wifivdevmsg), GFP_ATOMIC); +- if (!wifivdevmsg) { +- nss_wifi_meshmgr_warn("%px: Failed to allocate message memmory", &wmgr_ctx); +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return NSS_WIFI_MESHMGR_FAILURE; +- } +- +- decap_ifnum = wmesh_ctx->decap_ifnum; +- +- /* +- * Verify the decap I/F number against it types. +- */ +- if (!(nss_wifi_meshmgr_verify_if_num(decap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_OUTER))) { +- nss_wifi_meshmgr_warn("%px: I/F num: 0x%x verification failed\n", &wmgr_ctx, decap_ifnum); +- kfree(wifivdevmsg); +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return NSS_WIFI_MESHMGR_FAILURE; +- } +- +- +- link_ifnum = wmalv->link_vap_id; +- +- /* +- * Verify the link VAP I/F number against it types. +- */ +- if (!(nss_wifi_meshmgr_verify_if_num(link_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_VAP))) { +- nss_wifi_meshmgr_warn("%px: I/F num: 0x%x verification failed\n", &wmgr_ctx, link_ifnum); +- kfree(wifivdevmsg); +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return NSS_WIFI_MESHMGR_FAILURE; +- } +- +- +- next_hop_msg = &wifivdevmsg->msg.next_hop; +- next_hop_msg->ifnumber = decap_ifnum; +- nss_cmn_msg_init(&wifivdevmsg->cm, link_ifnum, NSS_WIFI_VDEV_SET_NEXT_HOP, sizeof(*next_hop_msg), +- msg_cb, app_data); +- +- /* +- * Send the link vap mesage to the NSS synchronously. +- */ +- nss_status = nss_wifi_vdev_tx_msg(wmgr_ctx.nss_ctx, wifivdevmsg); +- if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { +- nss_wifi_meshmgr_warn("%px: Mesh link vap association failed: %d.\n", &wmgr_ctx, nss_status); +- } +- +- kfree(wifivdevmsg); +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return nss_status; +-} +-EXPORT_SYMBOL(nss_wifi_meshmgr_assoc_link_vap); +- +-/* +- * nss_wifi_meshmgr_assoc_link_vap_sync() +- * Associate the link VAP to the mesh I/F synchronously. +- */ +-nss_wifi_meshmgr_status_t +-nss_wifi_meshmgr_assoc_link_vap_sync(nss_wifi_mesh_handle_t mesh_handle, struct nss_wifi_mesh_assoc_link_vap *wmalv) +-{ +- struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; +- nss_wifi_meshmgr_status_t nss_status; +- int32_t ret; +- +- wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); +- if (!wmesh_ctx) { +- nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); +- return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; +- } +- +- /* +- * Send the link vap mesage to the NSS synchronously. +- */ +- down(&wmesh_ctx->sem); +- nss_status = nss_wifi_meshmgr_assoc_link_vap(mesh_handle, wmalv, nss_wifi_meshmgr_tx_msg_cb, wmesh_ctx); +- if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { +- nss_wifi_meshmgr_warn("%px: Mesh link vap association failed: %d.\n", &wmgr_ctx, nss_status); +- up(&wmesh_ctx->sem); +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return nss_status; +- } +- +- /* +- * Wait for the acknowledgement +- */ +- ret = wait_for_completion_timeout(&wmesh_ctx->complete, msecs_to_jiffies(NSS_WIFI_MESH_TX_TIMEOUT)); +- if (!ret) { +- nss_wifi_meshmgr_warn("%px: WiFi mesh msg tx failed due to timeout\n", &wmgr_ctx); +- wmesh_ctx->response = NSS_WIFI_MESHMGR_FAILURE_SYNC_TIMEOUT; +- } +- +- nss_status = wmesh_ctx->response; +- up(&wmesh_ctx->sem); +- +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return nss_status; +-} +-EXPORT_SYMBOL(nss_wifi_meshmgr_assoc_link_vap_sync); +- +-/* +- * nss_wifi_meshmgr_mesh_config_update() +- * Update mesh configuration message asynchronously. +- */ +-nss_wifi_meshmgr_status_t +-nss_wifi_meshmgr_mesh_config_update(nss_wifi_mesh_handle_t mesh_handle, struct nss_wifi_mesh_config_msg *wmcum, +- nss_wifi_mesh_msg_callback_t msg_cb, void *app_data) +-{ +- struct nss_wifi_mesh_msg wmesh_msg; +- struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; +- struct nss_wifi_mesh_config_msg *nwmcum; +- int32_t encap_ifnum, decap_ifnum; +- nss_wifi_meshmgr_status_t nss_status; +- +- wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); +- if (!wmesh_ctx) { +- nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); +- return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; +- } +- +- encap_ifnum = wmesh_ctx->encap_ifnum; +- decap_ifnum = wmesh_ctx->decap_ifnum; +- +- /* +- * Verify the encap I/F number against it types. +- */ +- if (!(nss_wifi_meshmgr_verify_if_num(encap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER))) { +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- nss_wifi_meshmgr_warn("%px: I/F num: 0x%x verification failed\n", &wmgr_ctx, encap_ifnum); +- return NSS_WIFI_MESHMGR_FAILURE; +- } +- +- /* +- * Verify the decap I/F number against it types. +- */ +- if (!(nss_wifi_meshmgr_verify_if_num(decap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_OUTER))) { +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- nss_wifi_meshmgr_warn("%px: I/F num: 0x%x verification failed\n", &wmgr_ctx, decap_ifnum); +- return NSS_WIFI_MESHMGR_FAILURE; +- } +- +- /* +- * Initialize the mesh configuration messsage. +- */ +- memset(&wmesh_msg, 0, sizeof(struct nss_wifi_mesh_msg)); +- nwmcum = &wmesh_msg.msg.mesh_config; +- memcpy(nwmcum, wmcum, sizeof(*nwmcum)); +- nss_wifi_mesh_msg_init(&wmesh_msg, encap_ifnum, NSS_WIFI_MESH_MSG_INTERFACE_CONFIGURE, +- sizeof(*nwmcum), msg_cb, app_data); +- +- /* +- * Send the configuration message to encap I/F. +- */ +- nss_status = nss_wifi_meshmgr_tx_msg(&wmesh_msg); +- if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { +- nss_wifi_meshmgr_warn("%px: Mesh configuration message failed: %d.\n", &wmgr_ctx, nss_status); +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return nss_status; +- } +- +- /* +- * Initialize the mesh configuration messsage. +- */ +- nss_wifi_mesh_msg_init(&wmesh_msg, decap_ifnum, NSS_WIFI_MESH_MSG_INTERFACE_CONFIGURE, +- sizeof(*nwmcum), msg_cb, app_data); +- +- /* +- * Send the configuration message decap I/F. +- */ +- nss_status = nss_wifi_meshmgr_tx_msg(&wmesh_msg); +- if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { +- nss_wifi_meshmgr_warn("%px: Mesh configuration message failed: %d.\n", &wmgr_ctx, nss_status); +- } +- +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return nss_status; +-} +-EXPORT_SYMBOL(nss_wifi_meshmgr_mesh_config_update); +- +-/* +- * nss_wifi_meshmgr_mesh_config_update_sync() +- * Update mesh configuration message synchronously. +- */ +-nss_wifi_meshmgr_status_t +-nss_wifi_meshmgr_mesh_config_update_sync(nss_wifi_mesh_handle_t mesh_handle, struct nss_wifi_mesh_config_msg *wmcum) +-{ +- struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; +- nss_wifi_meshmgr_status_t nss_status; +- int32_t ret; +- +- wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); +- if (!wmesh_ctx) { +- nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); +- return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; +- } +- +- /* +- * Send the message to NSS synchronously. +- */ +- down(&wmesh_ctx->sem); +- nss_status = nss_wifi_meshmgr_mesh_config_update(mesh_handle, wmcum, nss_wifi_meshmgr_tx_msg_cb, wmesh_ctx); +- if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { +- nss_wifi_meshmgr_warn("%px: Mesh proxy path update failed: %d.\n", &wmgr_ctx, nss_status); +- up(&wmesh_ctx->sem); +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return nss_status; +- } +- +- /* +- * Wait for the acknowledgement +- */ +- ret = wait_for_completion_timeout(&wmesh_ctx->complete, msecs_to_jiffies(NSS_WIFI_MESH_TX_TIMEOUT)); +- if (!ret) { +- nss_wifi_meshmgr_warn("%px: WiFi mesh msg tx failed due to timeout\n", &wmgr_ctx); +- wmesh_ctx->response = NSS_WIFI_MESHMGR_FAILURE_SYNC_TIMEOUT; +- } +- +- nss_status = wmesh_ctx->response; +- up(&wmesh_ctx->sem); +- +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return nss_status; +-} +-EXPORT_SYMBOL(nss_wifi_meshmgr_mesh_config_update_sync); +- +-/* +- * nss_wifi_meshmgr_mesh_proxy_path_delete() +- * Delete the mesh proxy path asynchronously. +- */ +-nss_wifi_meshmgr_status_t +-nss_wifi_meshmgr_mesh_proxy_path_delete(nss_wifi_mesh_handle_t mesh_handle, struct nss_wifi_mesh_proxy_path_del_msg *wmppdm, +- nss_wifi_mesh_msg_callback_t msg_cb, void *app_data) +-{ +- struct nss_wifi_mesh_msg wmesh_msg; +- struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; +- struct nss_wifi_mesh_proxy_path_del_msg *nwmppdm; +- int32_t encap_ifnum; +- nss_wifi_meshmgr_status_t nss_status; +- +- wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); +- if (!wmesh_ctx) { +- nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); +- return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; +- } +- +- encap_ifnum = wmesh_ctx->encap_ifnum; +- +- /* +- * Verify the encap I/F number against it types. +- */ +- if (!(nss_wifi_meshmgr_verify_if_num(encap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER))) { +- nss_wifi_meshmgr_warn("%px: I/F num: 0x%x verification failed\n", &wmgr_ctx, encap_ifnum); +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return NSS_WIFI_MESHMGR_FAILURE; +- } +- +- /* +- * Initialize the message. +- */ +- memset(&wmesh_msg, 0, sizeof(struct nss_wifi_mesh_msg)); +- nwmppdm = &wmesh_msg.msg.proxy_del_msg; +- memcpy(nwmppdm, wmppdm, sizeof(*nwmppdm)); +- nss_wifi_mesh_msg_init(&wmesh_msg, encap_ifnum, NSS_WIFI_MESH_MSG_PROXY_PATH_DELETE, +- sizeof(*nwmppdm), msg_cb, app_data); +- +- /* +- * Send the message to NSS asynchronously. +- */ +- nss_status = nss_wifi_meshmgr_tx_msg(&wmesh_msg); +- if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { +- nss_wifi_meshmgr_warn("%px: Mesh proxy path delete failed: %d.\n", &wmgr_ctx, nss_status); +- } +- +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return nss_status; +-} +-EXPORT_SYMBOL(nss_wifi_meshmgr_mesh_proxy_path_delete); +- +-/* +- * nss_wifi_meshmgr_mesh_proxy_path_delete_sync() +- * Delete the mesh proxy path synchronously. +- */ +-nss_wifi_meshmgr_status_t +-nss_wifi_meshmgr_mesh_proxy_path_delete_sync(nss_wifi_mesh_handle_t mesh_handle, struct nss_wifi_mesh_proxy_path_del_msg *wmppdm) +-{ +- struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; +- nss_wifi_meshmgr_status_t nss_status; +- int32_t ret; +- +- wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); +- if (!wmesh_ctx) { +- nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); +- return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; +- } +- +- /* +- * Send the message to NSS synchronously. +- */ +- down(&wmesh_ctx->sem); +- nss_status = nss_wifi_meshmgr_mesh_proxy_path_delete(mesh_handle, wmppdm, nss_wifi_meshmgr_tx_msg_cb, wmesh_ctx); +- if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { +- nss_wifi_meshmgr_warn("%px: Mesh proxy path delete failed: %d.\n", &wmgr_ctx, nss_status); +- up(&wmesh_ctx->sem); +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return nss_status; +- } +- +- /* +- * Wait for the acknowledgement +- */ +- ret = wait_for_completion_timeout(&wmesh_ctx->complete, msecs_to_jiffies(NSS_WIFI_MESH_TX_TIMEOUT)); +- if (!ret) { +- nss_wifi_meshmgr_warn("%px: WiFi mesh msg tx failed due to timeout\n", &wmgr_ctx); +- wmesh_ctx->response = NSS_WIFI_MESHMGR_FAILURE_SYNC_TIMEOUT; +- } +- +- nss_status = wmesh_ctx->response; +- up(&wmesh_ctx->sem); +- +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return nss_status; +-} +-EXPORT_SYMBOL(nss_wifi_meshmgr_mesh_proxy_path_delete_sync); +- +-/* +- * nss_wifi_meshmgr_mesh_proxy_path_update() +- * Mesh prpxy path update message asynchronously. +- */ +-nss_wifi_meshmgr_status_t +-nss_wifi_meshmgr_mesh_proxy_path_update(nss_wifi_mesh_handle_t mesh_handle, struct nss_wifi_mesh_proxy_path_update_msg *wmppum, +- nss_wifi_mesh_msg_callback_t msg_cb, void *app_data) +-{ +- struct nss_wifi_mesh_msg wmesh_msg; +- struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; +- struct nss_wifi_mesh_proxy_path_update_msg *nwmppum; +- int32_t encap_ifnum; +- nss_wifi_meshmgr_status_t nss_status; +- +- wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); +- if (!wmesh_ctx) { +- nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); +- return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; +- } +- +- encap_ifnum = wmesh_ctx->encap_ifnum; +- +- /* +- * Verify the encap I/F number against it types. +- */ +- if (!(nss_wifi_meshmgr_verify_if_num(encap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER))) { +- nss_wifi_meshmgr_warn("%px: I/F num: 0x%x verification failed\n", &wmgr_ctx, encap_ifnum); +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return NSS_WIFI_MESHMGR_FAILURE; +- } +- +- /* +- * Initialize the message. +- */ +- memset(&wmesh_msg, 0, sizeof(struct nss_wifi_mesh_msg)); +- nwmppum = &wmesh_msg.msg.proxy_update_msg; +- memcpy(nwmppum, wmppum, sizeof(*nwmppum)); +- nss_wifi_mesh_msg_init(&wmesh_msg, encap_ifnum, NSS_WIFI_MESH_MSG_PROXY_PATH_UPDATE, +- sizeof(*nwmppum), msg_cb, app_data); +- +- /* +- * Send the message to NSS asynchronously +- */ +- nss_status = nss_wifi_meshmgr_tx_msg(&wmesh_msg); +- if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { +- nss_wifi_meshmgr_warn("%px: Mesh proxy path update failed: %d.\n", &wmgr_ctx, nss_status); +- } +- +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return nss_status; +-} +-EXPORT_SYMBOL(nss_wifi_meshmgr_mesh_proxy_path_update); +- +-/* +- * nss_wifi_meshmgr_mesh_proxy_path_update_sync() +- * Send proxy update message synchronously. +- */ +-nss_wifi_meshmgr_status_t +-nss_wifi_meshmgr_mesh_proxy_path_update_sync(nss_wifi_mesh_handle_t mesh_handle, struct nss_wifi_mesh_proxy_path_update_msg *wmppum) +-{ +- struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; +- nss_wifi_meshmgr_status_t nss_status; +- int32_t ret; +- +- wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); +- if (!wmesh_ctx) { +- nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); +- return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; +- } +- +- /* +- * Send the message to NSS synchronously. +- */ +- down(&wmesh_ctx->sem); +- nss_status = nss_wifi_meshmgr_mesh_proxy_path_update(mesh_handle, wmppum, nss_wifi_meshmgr_tx_msg_cb, wmesh_ctx); +- if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { +- nss_wifi_meshmgr_warn("%px: Mesh proxy path update failed: %d.\n", &wmgr_ctx, nss_status); +- up(&wmesh_ctx->sem); +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return nss_status; +- } +- +- /* +- * Wait for the acknowledgement +- */ +- ret = wait_for_completion_timeout(&wmesh_ctx->complete, msecs_to_jiffies(NSS_WIFI_MESH_TX_TIMEOUT)); +- if (!ret) { +- nss_wifi_meshmgr_warn("%px: WiFi mesh msg tx failed due to timeout\n", &wmgr_ctx); +- wmesh_ctx->response = NSS_WIFI_MESHMGR_FAILURE_SYNC_TIMEOUT; +- } +- +- nss_status = wmesh_ctx->response; +- up(&wmesh_ctx->sem); +- +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return nss_status; +-} +-EXPORT_SYMBOL(nss_wifi_meshmgr_mesh_proxy_path_update_sync); +- +-/* +- * nss_wifi_meshmgr_mesh_proxy_path_add() +- * Send mesh proxy add message asynchronously. +- */ +-nss_wifi_meshmgr_status_t +-nss_wifi_meshmgr_mesh_proxy_path_add(nss_wifi_mesh_handle_t mesh_handle, struct nss_wifi_mesh_proxy_path_add_msg *wmppam, +- nss_wifi_mesh_msg_callback_t msg_cb, void *app_data) +-{ +- struct nss_wifi_mesh_msg wmesh_msg; +- struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; +- struct nss_wifi_mesh_proxy_path_add_msg *nwmppam; +- int32_t encap_ifnum; +- nss_wifi_meshmgr_status_t nss_status; +- +- wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); +- if (!wmesh_ctx) { +- nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); +- return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; +- } +- +- encap_ifnum = wmesh_ctx->encap_ifnum; +- +- /* +- * Verify the encap I/F number against it types. +- */ +- if (!(nss_wifi_meshmgr_verify_if_num(encap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER))) { +- nss_wifi_meshmgr_warn("%px: I/F num: 0x%x verification failed\n", &wmgr_ctx, encap_ifnum); +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return NSS_WIFI_MESHMGR_FAILURE; +- } +- +- /* +- * Initialize the message +- */ +- memset(&wmesh_msg, 0, sizeof(struct nss_wifi_mesh_msg)); +- nwmppam = &wmesh_msg.msg.proxy_add_msg; +- memcpy(nwmppam, wmppam, sizeof(*nwmppam)); +- nss_wifi_mesh_msg_init(&wmesh_msg, encap_ifnum, NSS_WIFI_MESH_MSG_PROXY_PATH_ADD, +- sizeof(*nwmppam), msg_cb, app_data); +- +- /* +- * Send the message to NSS asynchronously. +- */ +- nss_status = nss_wifi_meshmgr_tx_msg(&wmesh_msg); +- if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { +- nss_wifi_meshmgr_warn("%px: Mesh proxy path add failed: %d.\n", &wmgr_ctx, nss_status); +- } +- +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return nss_status; +-} +-EXPORT_SYMBOL(nss_wifi_meshmgr_mesh_proxy_path_add); +- +-/* +- * nss_wifi_meshmgr_mesh_proxy_path_add_sync() +- * Send mesh proxy add message synchronously. +- */ +-nss_wifi_meshmgr_status_t +-nss_wifi_meshmgr_mesh_proxy_path_add_sync(nss_wifi_mesh_handle_t mesh_handle, struct nss_wifi_mesh_proxy_path_add_msg *wmppam) +-{ +- struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; +- int32_t ret; +- nss_wifi_meshmgr_status_t nss_status; +- +- wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); +- if (!wmesh_ctx) { +- nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); +- return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; +- } +- +- /* +- * Send the message to NSS synchronously. +- */ +- down(&wmesh_ctx->sem); +- nss_status = nss_wifi_meshmgr_mesh_proxy_path_add(mesh_handle, wmppam, nss_wifi_meshmgr_tx_msg_cb, wmesh_ctx); +- if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { +- nss_wifi_meshmgr_warn("%px: Mesh proxy path add failed: %d.\n", &wmgr_ctx, nss_status); +- up(&wmesh_ctx->sem); +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return nss_status; +- } +- +- /* +- * Wait for the acknowledgement +- */ +- ret = wait_for_completion_timeout(&wmesh_ctx->complete, msecs_to_jiffies(NSS_WIFI_MESH_TX_TIMEOUT)); +- if (!ret) { +- nss_wifi_meshmgr_warn("%px: WiFi mesh msg tx failed due to timeout\n", &wmgr_ctx); +- wmesh_ctx->response = NSS_WIFI_MESHMGR_FAILURE_SYNC_TIMEOUT; +- } +- +- nss_status = wmesh_ctx->response; +- up(&wmesh_ctx->sem); +- +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return nss_status; +-} +-EXPORT_SYMBOL(nss_wifi_meshmgr_mesh_proxy_path_add_sync); +- +-/* +- * nss_wifi_meshmgr_mesh_path_delete() +- * Send the mesh path delete message asynchronously. +- */ +-nss_wifi_meshmgr_status_t +-nss_wifi_meshmgr_mesh_path_delete(nss_wifi_mesh_handle_t mesh_handle, struct nss_wifi_mesh_mpath_del_msg *wmpdm, +- nss_wifi_mesh_msg_callback_t msg_cb, void *app_data) +-{ +- struct nss_wifi_mesh_msg wmesh_msg; +- struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; +- struct nss_wifi_mesh_mpath_del_msg *nwmpdm; +- int32_t encap_ifnum; +- nss_wifi_meshmgr_status_t nss_status; +- +- wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); +- if (!wmesh_ctx) { +- nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); +- return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; +- } +- +- encap_ifnum = wmesh_ctx->encap_ifnum; +- +- /* +- * Verify the encap I/F number against it types. +- */ +- if (!(nss_wifi_meshmgr_verify_if_num(encap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER))) { +- nss_wifi_meshmgr_warn("%px: I/F num: 0x%x verification failed\n", &wmgr_ctx, encap_ifnum); +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return NSS_WIFI_MESHMGR_FAILURE; +- } +- +- /* +- * Initialize the message. +- */ +- memset(&wmesh_msg, 0, sizeof(struct nss_wifi_mesh_msg)); +- nwmpdm = &wmesh_msg.msg.mpath_del; +- memcpy(nwmpdm, wmpdm, sizeof(*nwmpdm)); +- nss_wifi_mesh_msg_init(&wmesh_msg, encap_ifnum, NSS_WIFI_MESH_MSG_MPATH_DELETE, +- sizeof(*nwmpdm), msg_cb, app_data); +- +- /* +- * Send the message to NSS asynchronously. +- */ +- nss_status = nss_wifi_meshmgr_tx_msg(&wmesh_msg); +- if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { +- nss_wifi_meshmgr_warn("%px: Mesh path delete failed: %d.\n", &wmgr_ctx, nss_status); +- } +- +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return nss_status; +-} +-EXPORT_SYMBOL(nss_wifi_meshmgr_mesh_path_delete); +- +-/* +- * nss_wifi_meshmgr_mesh_path_delete_sync() +- * Send the mesh path delete message synchronously. +- */ +-nss_wifi_meshmgr_status_t +-nss_wifi_meshmgr_mesh_path_delete_sync(nss_wifi_mesh_handle_t mesh_handle, struct nss_wifi_mesh_mpath_del_msg *wmpdm) +-{ +- struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; +- int32_t ret; +- nss_wifi_meshmgr_status_t nss_status; +- +- wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); +- if (!wmesh_ctx) { +- nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); +- return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; +- } +- +- /* +- * Send the message to NSS synchronously. +- */ +- down(&wmesh_ctx->sem); +- nss_status = nss_wifi_meshmgr_mesh_path_delete(mesh_handle, wmpdm, nss_wifi_meshmgr_tx_msg_cb, wmesh_ctx); +- if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { +- nss_wifi_meshmgr_warn("%px: Mesh path delete failed: %d.\n", &wmgr_ctx, nss_status); +- up(&wmesh_ctx->sem); +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return nss_status; +- } +- +- /* +- * Wait for the acknowledgement +- */ +- ret = wait_for_completion_timeout(&wmesh_ctx->complete, msecs_to_jiffies(NSS_WIFI_MESH_TX_TIMEOUT)); +- if (!ret) { +- nss_wifi_meshmgr_warn("%px: WiFi mesh msg tx failed due to timeout\n", &wmgr_ctx); +- wmesh_ctx->response = NSS_WIFI_MESHMGR_FAILURE_SYNC_TIMEOUT; +- } +- +- nss_status = wmesh_ctx->response; +- up(&wmesh_ctx->sem); +- +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return nss_status; +-} +-EXPORT_SYMBOL(nss_wifi_meshmgr_mesh_path_delete_sync); +- +-/* +- * nss_wifi_meshmgr_mesh_path_add() +- * Mesh path add message asynchronously. +- */ +-nss_wifi_meshmgr_status_t +-nss_wifi_meshmgr_mesh_path_add(nss_wifi_mesh_handle_t mesh_handle, struct nss_wifi_mesh_mpath_add_msg *wmpam, +- nss_wifi_mesh_msg_callback_t msg_cb, void *app_data) +-{ +- struct nss_wifi_mesh_msg wmesh_msg; +- struct nss_wifi_mesh_mpath_add_msg *nwmpam; +- struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; +- int32_t encap_ifnum; +- nss_wifi_meshmgr_status_t nss_status; +- +- wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); +- if (!wmesh_ctx) { +- nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); +- return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; +- } +- +- encap_ifnum = wmesh_ctx->encap_ifnum; +- +- /* +- * Verify the encap I/F number against it types. +- */ +- if (!(nss_wifi_meshmgr_verify_if_num(encap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER))) { +- nss_wifi_meshmgr_warn("%px: I/F num: 0x%x verification failed\n", &wmgr_ctx, encap_ifnum); +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return NSS_WIFI_MESHMGR_FAILURE; +- } +- +- /* +- * Initialize the message. +- */ +- memset(&wmesh_msg, 0, sizeof(struct nss_wifi_mesh_msg)); +- nwmpam = &wmesh_msg.msg.mpath_add; +- memcpy(nwmpam, wmpam, sizeof(*nwmpam)); +- nss_wifi_mesh_msg_init(&wmesh_msg, encap_ifnum, NSS_WIFI_MESH_MSG_MPATH_ADD, +- sizeof(*nwmpam), msg_cb, app_data); +- +- /* +- * Send the message to NSS asynchronously. +- */ +- nss_status = nss_wifi_meshmgr_tx_msg(&wmesh_msg); +- if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { +- nss_wifi_meshmgr_warn("%px: Mesh path addition failed: %d.\n", &wmgr_ctx, nss_status); +- } +- +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return nss_status; +-} +-EXPORT_SYMBOL(nss_wifi_meshmgr_mesh_path_add); +- +-/* +- * nss_wifi_meshmgr_mesh_path_add_sync() +- * Mesh path add message synchronously. +- */ +-nss_wifi_meshmgr_status_t +-nss_wifi_meshmgr_mesh_path_add_sync(nss_wifi_mesh_handle_t mesh_handle, struct nss_wifi_mesh_mpath_add_msg *wmpam) +-{ +- struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; +- int32_t ret; +- nss_wifi_meshmgr_status_t nss_status; +- +- wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); +- if (!wmesh_ctx) { +- nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); +- return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; +- } +- +- /* +- * Send the message to NSS synchronously. +- */ +- down(&wmesh_ctx->sem); +- nss_status = nss_wifi_meshmgr_mesh_path_add(mesh_handle, wmpam, nss_wifi_meshmgr_tx_msg_cb, wmesh_ctx); +- if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { +- nss_wifi_meshmgr_warn("%px: Mesh path addition failed: %d.\n", &wmgr_ctx, nss_status); +- up(&wmesh_ctx->sem); +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return nss_status; +- } +- +- /* +- * Wait for the acknowledgement +- */ +- ret = wait_for_completion_timeout(&wmesh_ctx->complete, msecs_to_jiffies(NSS_WIFI_MESH_TX_TIMEOUT)); +- if (!ret) { +- nss_wifi_meshmgr_warn("%px: WiFi mesh msg tx failed due to timeout\n", &wmgr_ctx); +- wmesh_ctx->response = NSS_WIFI_MESHMGR_FAILURE_SYNC_TIMEOUT; +- } +- +- nss_status = wmesh_ctx->response; +- up(&wmesh_ctx->sem); +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return nss_status; +-} +-EXPORT_SYMBOL(nss_wifi_meshmgr_mesh_path_add_sync); +- +-/* +- * nss_wifi_meshmgr_mpath_update() +- * Send mesh path update message asynchronously. +- */ +-nss_wifi_meshmgr_status_t +-nss_wifi_meshmgr_mesh_path_update(nss_wifi_mesh_handle_t mesh_handle, struct nss_wifi_mesh_mpath_update_msg *wmpum, +- nss_wifi_mesh_msg_callback_t msg_cb, void *app_data) +-{ +- struct nss_wifi_mesh_msg wmesh_msg; +- struct nss_wifi_mesh_mpath_update_msg *nwmpum; +- struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; +- int32_t encap_ifnum; +- nss_wifi_meshmgr_status_t nss_status; +- +- wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); +- if (!wmesh_ctx) { +- nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); +- return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; +- } +- +- encap_ifnum = wmesh_ctx->encap_ifnum; +- +- /* +- * Verify the encap I/F number against it types. +- */ +- if (!(nss_wifi_meshmgr_verify_if_num(encap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER))) { +- nss_wifi_meshmgr_warn("%px: I/F num: 0x%x verification failed\n", &wmgr_ctx, encap_ifnum); +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return NSS_WIFI_MESHMGR_FAILURE; +- } +- +- /* +- * Initialize the mesh path update message. +- */ +- memset(&wmesh_msg, 0, sizeof(struct nss_wifi_mesh_msg)); +- nwmpum = &wmesh_msg.msg.mpath_update; +- memcpy(nwmpum, wmpum, sizeof(*nwmpum)); +- nss_wifi_mesh_msg_init(&wmesh_msg, encap_ifnum, NSS_WIFI_MESH_MSG_MPATH_UPDATE, +- sizeof(*nwmpum), msg_cb, app_data); +- +- /* +- * Send the message to NSS asynchronously. +- */ +- nss_status = nss_wifi_meshmgr_tx_msg(&wmesh_msg); +- if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { +- nss_wifi_meshmgr_warn("%px: Mesh MPath update failed: %d.\n", &wmgr_ctx, nss_status); +- } +- +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return nss_status; +-} +-EXPORT_SYMBOL(nss_wifi_meshmgr_mesh_path_update); +- +-/* +- * nss_wifi_meshmgr_mpath_update_sync() +- * Send mesh path update message sychronously. +- */ +-nss_wifi_meshmgr_status_t +-nss_wifi_meshmgr_mesh_path_update_sync(nss_wifi_mesh_handle_t mesh_handle, struct nss_wifi_mesh_mpath_update_msg *wmpum) +-{ +- nss_wifi_meshmgr_status_t nss_status; +- int32_t ret; +- struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; +- +- wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); +- if (!wmesh_ctx) { +- nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); +- return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; +- } +- +- /* +- * Send the message to NSS synchronously. +- */ +- down(&wmesh_ctx->sem); +- nss_status = nss_wifi_meshmgr_mesh_path_update(mesh_handle, wmpum, nss_wifi_meshmgr_tx_msg_cb, wmesh_ctx); +- if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { +- nss_wifi_meshmgr_warn("%px: Mesh MPath update failed: %d.\n", &wmgr_ctx, nss_status); +- up(&wmesh_ctx->sem); +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return nss_status; +- } +- +- /* +- * Wait for the acknowledgement +- */ +- ret = wait_for_completion_timeout(&wmesh_ctx->complete, msecs_to_jiffies(NSS_WIFI_MESH_TX_TIMEOUT)); +- if (!ret) { +- nss_wifi_meshmgr_warn("%px: WiFi mesh msg tx failed due to timeout\n", &wmgr_ctx); +- wmesh_ctx->response = NSS_WIFI_MESHMGR_FAILURE_SYNC_TIMEOUT; +- } +- +- nss_status = wmesh_ctx->response; +- up(&wmesh_ctx->sem); +- +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return nss_status; +-} +-EXPORT_SYMBOL(nss_wifi_meshmgr_mesh_path_update_sync); +- +-/* +- * nss_wifi_meshmgr_mesh_path_exception() +- * Mesh path exception msg asynchronously. +- */ +-nss_wifi_meshmgr_status_t +-nss_wifi_meshmgr_mesh_path_exception(nss_wifi_mesh_handle_t mesh_handle, struct nss_wifi_mesh_exception_flag_msg *wmefm, +- nss_wifi_mesh_msg_callback_t msg_cb, void *app_data) +-{ +- struct nss_wifi_mesh_msg wmesh_msg; +- struct nss_wifi_mesh_exception_flag_msg *nwmefm; +- struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; +- int32_t encap_ifnum; +- nss_wifi_meshmgr_status_t nss_status; +- +- wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); +- if (!wmesh_ctx) { +- nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); +- return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; +- } +- +- encap_ifnum = wmesh_ctx->encap_ifnum; +- +- /* +- * Verify the encap I/F number against it types. +- */ +- if (!(nss_wifi_meshmgr_verify_if_num(encap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER))) { +- nss_wifi_meshmgr_warn("%px: I/F num: 0x%x verification failed\n", &wmgr_ctx, encap_ifnum); +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return NSS_WIFI_MESHMGR_FAILURE; +- } +- +- /* +- * Initialize the message. +- */ +- memset(&wmesh_msg, 0, sizeof(struct nss_wifi_mesh_msg)); +- nwmefm = &wmesh_msg.msg.exception_msg; +- memcpy(nwmefm, wmefm, sizeof(*nwmefm)); +- nss_wifi_mesh_msg_init(&wmesh_msg, encap_ifnum, NSS_WIFI_MESH_MSG_EXCEPTION_FLAG, +- sizeof(*nwmefm), msg_cb, app_data); +- +- /* +- * Send the message to NSS asynchronously. +- */ +- nss_status = nss_wifi_meshmgr_tx_msg(&wmesh_msg); +- if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { +- nss_wifi_meshmgr_warn("%px: Mesh path exception message failed: %d.\n", &wmgr_ctx, nss_status); +- } +- +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return nss_status; +-} +-EXPORT_SYMBOL(nss_wifi_meshmgr_mesh_path_exception); +- +-/* +- * nss_wifi_meshmgr_mesh_path_exception_sync() +- * Send mesh path exception message sychronously. +- */ +-nss_wifi_meshmgr_status_t +-nss_wifi_meshmgr_mesh_path_exception_sync(nss_wifi_mesh_handle_t mesh_handle,struct nss_wifi_mesh_exception_flag_msg *wmefm) +-{ +- nss_wifi_meshmgr_status_t nss_status; +- int32_t ret; +- struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; +- +- wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); +- if (!wmesh_ctx) { +- nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); +- return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; +- } +- +- /* +- * Send the message to NSS synchronously. +- */ +- down(&wmesh_ctx->sem); +- nss_status = nss_wifi_meshmgr_mesh_path_exception(mesh_handle, wmefm, nss_wifi_meshmgr_tx_msg_cb, wmesh_ctx); +- if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { +- nss_wifi_meshmgr_warn("%px: Mesh path exception message failed: %d.\n", &wmgr_ctx, nss_status); +- up(&wmesh_ctx->sem); +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return nss_status; +- } +- +- /* +- * Wait for the acknowledgement +- */ +- ret = wait_for_completion_timeout(&wmesh_ctx->complete, msecs_to_jiffies(NSS_WIFI_MESH_TX_TIMEOUT)); +- if (!ret) { +- nss_wifi_meshmgr_warn("%px: WiFi mesh msg tx failed due to timeout\n", &wmgr_ctx); +- wmesh_ctx->response = NSS_WIFI_MESHMGR_FAILURE_SYNC_TIMEOUT; +- } +- +- nss_status = wmesh_ctx->response; +- up(&wmesh_ctx->sem); +- +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return nss_status; +-} +-EXPORT_SYMBOL(nss_wifi_meshmgr_mesh_path_exception_sync); +- +-/* +- * nss_wifi_meshmgr_config_mesh_exception() +- * Configure mesh exception asynchronously. +- */ +-nss_wifi_meshmgr_status_t +-nss_wifi_meshmgr_config_mesh_exception(nss_wifi_mesh_handle_t mesh_handle, struct nss_wifi_mesh_rate_limit_config *wmrlc, +- nss_wifi_mesh_msg_callback_t msg_cb, void *app_data) +-{ +- struct nss_wifi_mesh_msg wmesh_msg; +- struct nss_wifi_mesh_rate_limit_config *nwmrlc; +- struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; +- int32_t encap_ifnum, decap_ifnum, ifnum; +- nss_wifi_meshmgr_status_t nss_status; +- +- wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); +- if (!wmesh_ctx) { +- nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); +- return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; +- } +- +- encap_ifnum = wmesh_ctx->encap_ifnum; +- +- /* +- * Verify the encap I/F number against it types. +- */ +- if (!(nss_wifi_meshmgr_verify_if_num(encap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER))) { +- nss_wifi_meshmgr_warn("%px: I/F num: 0x%x verification failed\n", &wmgr_ctx, encap_ifnum); +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return NSS_WIFI_MESHMGR_FAILURE; +- } +- +- decap_ifnum = wmesh_ctx->decap_ifnum; +- +- /* +- * Verify the decap I/F number against it types. +- */ +- if (!(nss_wifi_meshmgr_verify_if_num(decap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_OUTER))) { +- nss_wifi_meshmgr_warn("%px: I/F num: 0x%x verification failed\n", &wmgr_ctx, decap_ifnum); +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return NSS_WIFI_MESHMGR_FAILURE; +- } +- +- switch(wmrlc->exception_num) { +- case NSS_WIFI_MESH_DS_MESH_PATH_NOT_FOUND: +- ifnum = encap_ifnum; +- break; +- +- case NSS_WIFI_MESH_US_MESH_PROXY_NOT_FOUND: +- ifnum = decap_ifnum; +- break; +- +- case NSS_WIFI_MESH_US_MESH_PATH_NOT_FOUND: +- ifnum = decap_ifnum; +- break; +- } +- +- /* +- * Initialize the message. +- */ +- memset(&wmesh_msg, 0, sizeof(struct nss_wifi_mesh_msg)); +- nwmrlc = &wmesh_msg.msg.exc_cfg; +- memcpy(nwmrlc, wmrlc, sizeof(*nwmrlc)); +- nss_wifi_mesh_msg_init(&wmesh_msg, ifnum, NSS_WIFI_MESH_CONFIG_EXCEPTION, +- sizeof(*nwmrlc), msg_cb, app_data); +- +- /* +- * Send the message to NSS asynchronously. +- */ +- nss_status = nss_wifi_meshmgr_tx_msg(&wmesh_msg); +- if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { +- nss_wifi_meshmgr_warn("%px: Mesh config exception message failed: %d.\n", &wmgr_ctx, nss_status); +- } +- +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return nss_status; +-} +-EXPORT_SYMBOL(nss_wifi_meshmgr_config_mesh_exception); +- +-/* +- * nss_wifi_meshmgr_config_mesh_exception_sync() +- * Configure mesh exception synchronously. +- */ +-nss_wifi_meshmgr_status_t +-nss_wifi_meshmgr_config_mesh_exception_sync(nss_wifi_mesh_handle_t mesh_handle,struct nss_wifi_mesh_rate_limit_config *wmrlc) +-{ +- nss_wifi_meshmgr_status_t nss_status; +- int32_t ret; +- struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; +- +- wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); +- if (!wmesh_ctx) { +- nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); +- return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; +- } +- +- /* +- * Send the message to NSS synchronously. +- */ +- down(&wmesh_ctx->sem); +- nss_status = nss_wifi_meshmgr_config_mesh_exception(mesh_handle, wmrlc, nss_wifi_meshmgr_tx_msg_cb, wmesh_ctx); +- if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { +- nss_wifi_meshmgr_warn("%px: Mesh config exception message failed: %d.\n", &wmgr_ctx, nss_status); +- up(&wmesh_ctx->sem); +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return nss_status; +- } +- +- /* +- * Wait for the acknowledgement +- */ +- ret = wait_for_completion_timeout(&wmesh_ctx->complete, msecs_to_jiffies(NSS_WIFI_MESH_TX_TIMEOUT)); +- if (!ret) { +- nss_wifi_meshmgr_warn("%px: WiFi mesh msg tx failed due to timeout\n", &wmgr_ctx); +- wmesh_ctx->response = NSS_WIFI_MESHMGR_FAILURE_SYNC_TIMEOUT; +- } +- +- nss_status = wmesh_ctx->response; +- up(&wmesh_ctx->sem); +- +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return nss_status; +-} +-EXPORT_SYMBOL(nss_wifi_meshmgr_config_mesh_exception_sync); +- +-/* +- * nss_wifi_meshmgr_if_destroy_sync() +- * Function to unregister and destroy dynamic interfaces synchronously. +- */ +-nss_wifi_meshmgr_status_t nss_wifi_meshmgr_if_destroy_sync(nss_wifi_mesh_handle_t mesh_handle) +-{ +- int32_t encap_ifnum, decap_ifnum; +- nss_wifi_meshmgr_status_t nss_status; +- struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; +- +- wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); +- if (!wmesh_ctx) { +- nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); +- return NSS_WIFI_MESHMGR_FAILURE_BAD_PARAM; +- } +- +- encap_ifnum = wmesh_ctx->encap_ifnum; +- decap_ifnum = wmesh_ctx->decap_ifnum; +- +- /* +- * Verify the encap I/F number against it types. +- */ +- if (!(nss_wifi_meshmgr_verify_if_num(encap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER))) { +- nss_wifi_meshmgr_warn("%px: I/F num: 0x%x verification failed\n", &wmgr_ctx, encap_ifnum); +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return NSS_WIFI_MESHMGR_FAILURE; +- } +- +- /* +- * Verify the decap I/F number against it types. +- */ +- if (!(nss_wifi_meshmgr_verify_if_num(decap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_OUTER))) { +- nss_wifi_meshmgr_warn("%px: I/F num: 0x%x verification failed\n", &wmgr_ctx, decap_ifnum); +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return NSS_WIFI_MESHMGR_FAILURE; +- } +- +- /* +- * Send the I/F down message to NSS. +- */ +- nss_status = nss_wifi_meshmgr_if_down(mesh_handle); +- if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { +- nss_wifi_meshmgr_warn("%px: Sending mesh I/F down to NSS failed: %d\n", &wmgr_ctx, nss_status); +- } +- +- /* +- * Remove mesh context from the table. +- */ +- spin_lock_bh(&wmgr_ctx.ref_lock); +- nss_wifi_meshmgr_ctx_remove(wmesh_ctx); +- wmgr_ctx.mesh_count--; +- spin_unlock_bh(&wmgr_ctx.ref_lock); +- +- /* +- * Release the reference taken during alloc. +- */ +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- +- /* +- * Release the reference for the find taken at the beginning of the function. +- */ +- nss_wifi_meshmgr_ref_dec(wmesh_ctx); +- return nss_status; +-} +-EXPORT_SYMBOL(nss_wifi_meshmgr_if_destroy_sync); +- +-/* +- * nss_wifi_meshmgr_if_create_sync() +- * Create and register dynamic interface synchronously. +- * +- * Note: Synchronous create message, callbacks are used for driver registration not message handling. +- */ +-nss_wifi_mesh_handle_t nss_wifi_meshmgr_if_create_sync(struct net_device *dev, struct nss_wifi_mesh_config_msg *wmcm, +- nss_wifi_mesh_data_callback_t data_cb, +- nss_wifi_mesh_ext_data_callback_t ext_data_cb, +- nss_wifi_mesh_msg_callback_t event_cb) +-{ +- struct nss_wifi_mesh_msg wmesh_msg; +- struct nss_wifi_mesh_config_msg *nwmcm; +- int32_t encap_ifnum, decap_ifnum; +- uint32_t features = 0; +- nss_wifi_mesh_handle_t mesh_handle; +- nss_wifi_meshmgr_status_t nss_status; +- struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; +- +- spin_lock_bh(&wmgr_ctx.ref_lock); +- if (wmgr_ctx.mesh_count == NSS_WIFI_MESH_MAX) { +- nss_wifi_meshmgr_warn("%px: Reached maxed number of mesh interface\n", dev); +- spin_unlock_bh(&wmgr_ctx.ref_lock); +- return -1; +- } +- +- wmgr_ctx.mesh_count++; +- spin_unlock_bh(&wmgr_ctx.ref_lock); +- +- dev_hold(dev); +- wmesh_ctx = kzalloc(sizeof(*wmesh_ctx), GFP_ATOMIC); +- if (!wmesh_ctx) { +- nss_wifi_meshmgr_warn("%px: Failed to allocate memory for mesh context\n", dev); +- goto ctx_alloc_fail; +- } +- +- wmesh_ctx->dev = dev; +- sema_init(&wmesh_ctx->sem, 1); +- init_completion(&wmesh_ctx->complete); +- +- /* +- * Alloc the encap dynamic interface node. +- */ +- encap_ifnum = nss_dynamic_interface_alloc_node(NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER); +- if (encap_ifnum < 0) { +- nss_wifi_meshmgr_warn("%px: Encap allocation failed.\n", dev); +- goto encap_alloc_fail; +- } +- +- if (nss_register_wifi_mesh_if(encap_ifnum, data_cb, ext_data_cb, event_cb, +- NSS_WIFI_MESH_DP_INNER, dev, features) != NSS_WIFI_MESHMGR_SUCCESS) { +- nss_wifi_meshmgr_warn("%px: Encap registration failed.\n", dev); +- goto encap_reg_fail; +- } +- +- /* +- * Allocate and register decap interface. +- */ +- decap_ifnum = nss_dynamic_interface_alloc_node(NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_OUTER); +- if (decap_ifnum < 0) { +- nss_wifi_meshmgr_warn("%px: Decap allocation failed.\n", dev); +- goto decap_alloc_fail; +- } +- +- +- if (nss_register_wifi_mesh_if(decap_ifnum, data_cb, ext_data_cb, event_cb, +- NSS_WIFI_MESH_DP_OUTER, dev, features) != NSS_WIFI_MESHMGR_SUCCESS) { +- nss_wifi_meshmgr_warn("%px: Decap registration failed.\n", dev); +- goto decap_reg_fail; +- } +- +- wmesh_ctx->encap_ifnum = encap_ifnum; +- wmesh_ctx->decap_ifnum = decap_ifnum; +- +- nss_wifi_meshmgr_trace("%px: Successfully registered encap and decap iface for Mesh\n", dev); +- +- /* +- * Initialize the encap configuration message. +- */ +- memset(&wmesh_msg, 0, sizeof(struct nss_wifi_mesh_msg)); +- nwmcm = &wmesh_msg.msg.mesh_config; +- nwmcm->ttl = wmcm->ttl; +- nwmcm->mesh_path_refresh_time = wmcm->mesh_path_refresh_time; +- nwmcm->mpp_learning_mode = wmcm->mpp_learning_mode; +- nwmcm->config_flags = wmcm->config_flags | NSS_WIFI_MESH_CONFIG_FLAG_SIBLING_IF_NUM_VALID; +- nwmcm->sibling_ifnum = decap_ifnum; +- +- ether_addr_copy(nwmcm->local_mac_addr, wmcm->local_mac_addr); +- nss_wifi_mesh_msg_init(&wmesh_msg, encap_ifnum, NSS_WIFI_MESH_MSG_INTERFACE_CONFIGURE, +- sizeof(*nwmcm), nss_wifi_meshmgr_tx_msg_cb, wmesh_ctx); +- +- /* +- * Send the encap configuration message. +- */ +- nss_status = nss_wifi_meshmgr_tx_msg_sync(wmesh_ctx, &wmesh_msg); +- if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { +- nss_wifi_meshmgr_warn("%px: Encap configuration message failed: %d.\n", dev, nss_status); +- goto config_failed; +- } +- +- /* +- * Initialize the decap configuration message. +- */ +- nwmcm->sibling_ifnum = encap_ifnum; +- nwmcm->block_mesh_forwarding = wmcm->block_mesh_forwarding; +- nss_wifi_mesh_msg_init(&wmesh_msg, decap_ifnum, NSS_WIFI_MESH_MSG_INTERFACE_CONFIGURE, +- sizeof(*nwmcm), nss_wifi_meshmgr_tx_msg_cb, wmesh_ctx); +- +- /* +- * Send the decap configuration message. +- */ +- nss_status = nss_wifi_meshmgr_tx_msg_sync(wmesh_ctx, &wmesh_msg); +- if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { +- nss_wifi_meshmgr_warn("%px: Decap configuration message failed: %d.\n", dev, nss_status); +- goto config_failed; +- } +- +- /* +- * Take the self reference on the mesh context. +- */ +- atomic_set(&wmesh_ctx->ref, 1); +- +- /* +- * Add the Mesh context to the mesh manager's list. +- */ +- spin_lock_bh(&wmgr_ctx.ref_lock); +- mesh_handle = nss_wifi_meshmgr_ctx_insert(wmesh_ctx); +- if (mesh_handle < 0) { +- spin_unlock_bh(&wmgr_ctx.ref_lock); +- nss_wifi_meshmgr_warn("%px: Insertion for mesh context failed", &wmgr_ctx); +- goto config_failed; +- } +- +- spin_unlock_bh(&wmgr_ctx.ref_lock); +- +- nss_wifi_meshmgr_trace("%px: WiFi Mesh interface count:%d.\n", dev, wmgr_ctx.mesh_count); +- return mesh_handle; +- +-config_failed: +- nss_unregister_wifi_mesh_if(decap_ifnum); +-decap_reg_fail: +- nss_dynamic_interface_dealloc_node(decap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_OUTER); +- if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { +- nss_wifi_meshmgr_warn("%px: Decap interface dealloc failed: %d\n", dev, nss_status); +- } +-decap_alloc_fail: +- nss_unregister_wifi_mesh_if(encap_ifnum); +-encap_reg_fail: +- nss_dynamic_interface_dealloc_node(encap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER); +- if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { +- nss_wifi_meshmgr_warn("%px: Encap interface dealloc failed: %d\n", dev, nss_status); +- } +-encap_alloc_fail: +- kfree(wmesh_ctx); +-ctx_alloc_fail: +- spin_lock_bh(&wmgr_ctx.ref_lock); +- wmgr_ctx.mesh_count--; +- spin_unlock_bh(&wmgr_ctx.ref_lock); +- dev_put(dev); +- return -1; +-} +-EXPORT_SYMBOL(nss_wifi_meshmgr_if_create_sync); +- +-/* +- * nss_wifi_meshmgr_exit_module() +- * WiFi-Mesh module exit function +- */ +-static void __exit nss_wifi_meshmgr_exit_module(void) +-{ +- int32_t i; +- +- /* +- * Check if there are any mesh I/F. Delete all the mesh I/F from NSS FW and free. +- */ +- for (i = 0; i < NSS_WIFI_MESH_MAX; i++) { +- if (nss_wifi_meshmgr_if_destroy_sync(i) != NSS_WIFI_MESHMGR_SUCCESS) { +- nss_wifi_meshmgr_warn("%px Destroy failed or context does not exist", &wmgr_ctx); +- } +- } +- nss_wifi_meshmgr_info("Module %s unloaded\n", NSS_CLIENT_BUILD_ID); +-} +- +-/* +- * nss_wifi_meshmgr_init_module() +- * Wi-Fi mesh manager module init function +- */ +-static int __init nss_wifi_meshmgr_init_module(void) +-{ +- struct nss_ctx_instance *nss_ctx; +- int32_t idx; +- +-#ifdef CONFIG_OF +- /* +- * If the node is not compatible, don't do anything. +- */ +- if (!of_find_node_by_name(NULL, "nss-common")) { +- nss_wifi_meshmgr_warn("NSS common not found.\n"); +- return -1; +- } +-#endif +- +- nss_ctx = nss_wifi_mesh_get_context(); +- if (!nss_ctx) { +- nss_wifi_meshmgr_warn("NSS SoC context is NULL.\n"); +- return -1; +- } +- +- wmgr_ctx.nss_ctx = nss_ctx; +- for (idx = 0; idx < NSS_WIFI_MESH_MAX; idx++) { +- wmgr_ctx.mesh_ctx[idx] = NULL; +- } +- +- wmgr_ctx.mesh_count = 0; +- spin_lock_init(&wmgr_ctx.ref_lock); +- +- nss_wifi_meshmgr_info("Module %s loaded\n", NSS_CLIENT_BUILD_ID); +- return 0; +-} +- +-module_init(nss_wifi_meshmgr_init_module); +-module_exit(nss_wifi_meshmgr_exit_module); +- +-MODULE_LICENSE("Dual BSD/GPL"); +-MODULE_DESCRIPTION("NSS WiFi-Mesh manager"); diff --git a/package/qca-nss/qca-nss-clients/patches/110-kernel-6.1-support.patch b/package/qca-nss/qca-nss-clients/patches/110-kernel-6.1-support.patch new file mode 100644 index 0000000000..4d8fd7416b --- /dev/null +++ b/package/qca-nss/qca-nss-clients/patches/110-kernel-6.1-support.patch @@ -0,0 +1,460 @@ +--- a/bridge/nss_bridge_mgr.c ++++ b/bridge/nss_bridge_mgr.c +@@ -18,6 +18,7 @@ + * nss_bridge_mgr.c + * NSS to HLOS Bridge Interface manager + */ ++#include + #include + #include + #include +@@ -1050,7 +1051,11 @@ int nss_bridge_mgr_register_br(struct ne + } + #endif + ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ err = nss_bridge_tx_set_mac_addr_msg(ifnum, (uint8_t *)dev->dev_addr); ++#else + err = nss_bridge_tx_set_mac_addr_msg(ifnum, dev->dev_addr); ++#endif + if (err != NSS_TX_SUCCESS) { + nss_bridge_mgr_warn("%px: failed to set mac_addr msg, error = %d\n", b_pvt, err); + goto fail_3; +@@ -1207,7 +1212,12 @@ static int nss_bridge_mgr_changeaddr_eve + + nss_bridge_mgr_trace("%px: MAC changed to %pM, update NSS\n", b_pvt, dev->dev_addr); + +- if (nss_bridge_tx_set_mac_addr_msg(b_pvt->ifnum, dev->dev_addr) != NSS_TX_SUCCESS) { ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ if (nss_bridge_tx_set_mac_addr_msg(b_pvt->ifnum, (uint8_t *)dev->dev_addr) != NSS_TX_SUCCESS) ++#else ++ if (nss_bridge_tx_set_mac_addr_msg(b_pvt->ifnum, dev->dev_addr) != NSS_TX_SUCCESS) ++#endif ++ { + nss_bridge_mgr_warn("%px: Failed to send change MAC address message to NSS\n", b_pvt); + return NOTIFY_BAD; + } +--- a/dtls/v2.0/nss_dtlsmgr_ctx_dev.c ++++ b/dtls/v2.0/nss_dtlsmgr_ctx_dev.c +@@ -526,7 +526,11 @@ void nss_dtlsmgr_ctx_dev_setup(struct ne + #else + dev->priv_destructor = nss_dtlsmgr_ctx_dev_free; + #endif ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ memcpy((void *)dev->dev_addr, "\xaa\xbb\xcc\xdd\xee\xff", dev->addr_len); ++#else + memcpy(dev->dev_addr, "\xaa\xbb\xcc\xdd\xee\xff", dev->addr_len); ++#endif + memset(dev->broadcast, 0xff, dev->addr_len); + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); + } +--- a/gre/test/nss_connmgr_gre_test.c ++++ b/gre/test/nss_connmgr_gre_test.c +@@ -223,7 +223,11 @@ static int nss_connmgr_gre_test_show_pro + */ + static int nss_connmgr_gre_test_open_proc(struct inode *inode, struct file *filp) + { ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ return single_open(filp, nss_connmgr_gre_test_show_proc, pde_data(inode)); ++#else + return single_open(filp, nss_connmgr_gre_test_show_proc, PDE_DATA(inode)); ++#endif + } + + /* +--- a/gre/nss_connmgr_gre.c ++++ b/gre/nss_connmgr_gre.c +@@ -279,10 +279,17 @@ static struct rtnl_link_stats64 *nss_con + #else + start = u64_stats_fetch_begin_irq(&tstats->syncp); + #endif ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ rx_packets = u64_stats_read(&tstats->rx_packets); ++ tx_packets = u64_stats_read(&tstats->tx_packets); ++ rx_bytes = u64_stats_read(&tstats->rx_bytes); ++ tx_bytes = u64_stats_read(&tstats->tx_bytes); ++#else + rx_packets = tstats->rx_packets; + tx_packets = tstats->tx_packets; + rx_bytes = tstats->rx_bytes; + tx_bytes = tstats->tx_bytes; ++#endif + #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0)) + } while (u64_stats_fetch_retry_bh(&tstats->syncp, start)); + #else +@@ -697,11 +704,21 @@ static void nss_connmgr_gre_event_receiv + tstats = this_cpu_ptr(dev->tstats); + u64_stats_update_begin(&tstats->syncp); + if (interface_type == NSS_DYNAMIC_INTERFACE_TYPE_GRE_INNER) { ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ u64_stats_add(&tstats->tx_packets, stats->tx_packets); ++ u64_stats_add(&tstats->tx_bytes, stats->tx_bytes); ++#else + tstats->tx_packets += stats->tx_packets; + tstats->tx_bytes += stats->tx_bytes; ++#endif + } else if (interface_type == NSS_DYNAMIC_INTERFACE_TYPE_GRE_OUTER) { ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ u64_stats_add(&tstats->rx_packets, stats->rx_packets); ++ u64_stats_add(&tstats->rx_bytes, stats->rx_bytes); ++#else + tstats->rx_packets += stats->rx_packets; + tstats->rx_bytes += stats->rx_bytes; ++#endif + } + u64_stats_update_end(&tstats->syncp); + dev->stats.rx_dropped += nss_cmn_rx_dropped_sum(stats); +--- a/tunipip6/nss_connmgr_tunipip6.c ++++ b/tunipip6/nss_connmgr_tunipip6.c +@@ -353,11 +353,21 @@ static void nss_tunipip6_update_dev_stat + + memset(&stats, 0, sizeof(stats)); + if (interface_type == NSS_DYNAMIC_INTERFACE_TYPE_TUNIPIP6_INNER) { ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ u64_stats_set(&stats.tx_packets, sync_stats->node_stats.tx_packets); ++ u64_stats_set(&stats.tx_bytes, sync_stats->node_stats.tx_bytes); ++#else + stats.tx_packets = sync_stats->node_stats.tx_packets; + stats.tx_bytes = sync_stats->node_stats.tx_bytes; ++#endif + } else if (interface_type == NSS_DYNAMIC_INTERFACE_TYPE_TUNIPIP6_OUTER) { ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ u64_stats_set(&stats.rx_packets, sync_stats->node_stats.rx_packets); ++ u64_stats_set(&stats.rx_bytes, sync_stats->node_stats.rx_bytes); ++#else + stats.rx_packets = sync_stats->node_stats.rx_packets; + stats.rx_bytes = sync_stats->node_stats.rx_bytes; ++#endif + } else { + nss_tunipip6_warning("%px: Invalid interface type received from NSS\n", dev); + return; +--- a/nss_qdisc/igs/nss_mirred.c ++++ b/nss_qdisc/igs/nss_mirred.c +@@ -317,7 +317,11 @@ static int nss_mirred_act(struct sk_buff + * Update the last use of action. + */ + tcf_lastuse_update(&act->tcf_tm); ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ bstats_update(this_cpu_ptr(act->common.cpu_bstats), skb); ++#else + bstats_cpu_update(this_cpu_ptr(act->common.cpu_bstats), skb); ++#endif + + rcu_read_lock(); + retval = READ_ONCE(act->tcf_action); +--- a/nss_qdisc/nss_qdisc.h ++++ b/nss_qdisc/nss_qdisc.h +@@ -188,7 +188,11 @@ struct nss_qdisc { + /* Shaper configure callback for reading shaper specific + * responses (e.g. memory size). + */ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ struct gnet_stats_basic_sync bstats; /* Basic class statistics */ ++#else + struct gnet_stats_basic_packed bstats; /* Basic class statistics */ ++#endif + struct gnet_stats_queue qstats; /* Qstats for use by classes */ + #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0)) + atomic_t refcnt; /* Reference count for class use */ +@@ -444,8 +448,13 @@ extern void nss_qdisc_stop_basic_stats_p + * nss_qdisc_gnet_stats_copy_basic() + * Wrapper around gnet_stats_copy_basic() + */ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++extern int nss_qdisc_gnet_stats_copy_basic(struct Qdisc *sch, ++ struct gnet_dump *d, struct gnet_stats_basic_sync *b); ++#else + extern int nss_qdisc_gnet_stats_copy_basic(struct Qdisc *sch, + struct gnet_dump *d, struct gnet_stats_basic_packed *b); ++#endif + + /* + * nss_qdisc_gnet_stats_copy_queue() +--- a/nss_qdisc/igs/nss_ifb.c ++++ b/nss_qdisc/igs/nss_ifb.c +@@ -544,8 +544,15 @@ static void nss_ifb_update_dev_stats(str + * post shaping. Therefore IFB interface's stats should be updated + * with NSS firmware's IFB TX stats only. + */ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ u64_stats_set(&stats.rx_packets, node_stats->tx_packets); ++ u64_stats_set(&stats.tx_packets, node_stats->tx_packets); ++ u64_stats_set(&stats.rx_bytes, node_stats->tx_bytes); ++ u64_stats_set(&stats.tx_bytes, node_stats->tx_bytes); ++#else + stats.rx_packets = stats.tx_packets = node_stats->tx_packets; + stats.rx_bytes = stats.tx_bytes = node_stats->tx_bytes; ++#endif + dev->stats.rx_dropped = dev->stats.tx_dropped += sync_stats->igs_stats.tx_dropped; + u64_stats_update_end(&stats.syncp); + +--- a/nss_qdisc/nss_qdisc.c ++++ b/nss_qdisc/nss_qdisc.c +@@ -26,6 +26,9 @@ + #include "nss_htb.h" + #include "nss_blackhole.h" + #include "nss_wred.h" ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++#include "net/gen_stats.h" ++#endif + + void *nss_qdisc_ctx; /* Shaping context for nss_qdisc */ + +@@ -2563,7 +2566,11 @@ static void nss_qdisc_basic_stats_callba + { + struct nss_qdisc *nq = (struct nss_qdisc *)app_data; + struct Qdisc *qdisc = nq->qdisc; ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ struct gnet_stats_basic_sync *bstats; ++#else + struct gnet_stats_basic_packed *bstats; ++#endif + struct gnet_stats_queue *qstats; + struct nss_shaper_node_stats_response *response; + #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0)) +@@ -2602,8 +2609,13 @@ static void nss_qdisc_basic_stats_callba + * Update qdisc->bstats + */ + spin_lock_bh(&nq->lock); ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ u64_stats_add(&bstats->bytes, (__u64)response->sn_stats.delta.dequeued_bytes); ++ u64_stats_add(&bstats->packets, response->sn_stats.delta.dequeued_packets); ++#else + bstats->bytes += (__u64)response->sn_stats.delta.dequeued_bytes; + bstats->packets += response->sn_stats.delta.dequeued_packets; ++#endif + + /* + * Update qdisc->qstats +@@ -2763,12 +2775,18 @@ void nss_qdisc_stop_basic_stats_polling( + * Wrapper around gnet_stats_copy_basic() + */ + int nss_qdisc_gnet_stats_copy_basic(struct Qdisc *sch, struct gnet_dump *d, ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ struct gnet_stats_basic_sync *b) ++#else + struct gnet_stats_basic_packed *b) ++#endif + { + #if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 18, 0)) + return gnet_stats_copy_basic(d, b); + #elif (LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0)) + return gnet_stats_copy_basic(d, NULL, b); ++#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0)) ++ return gnet_stats_copy_basic(d, NULL, b, true); + #else + return gnet_stats_copy_basic(qdisc_root_sleeping_running(sch), d, NULL, b); + #endif +@@ -2799,7 +2817,9 @@ static int nss_qdisc_if_event_cb(struct + struct net_device *br; + struct Qdisc *br_qdisc; + int if_num, br_num; ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0)) + struct nss_qdisc *nq; ++#endif + + dev = nss_qdisc_get_dev(ptr); + if (!dev) { +@@ -2842,7 +2862,9 @@ static int nss_qdisc_if_event_cb(struct + break; + } + ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0)) + nq = (struct nss_qdisc *)qdisc_priv(br_qdisc); ++#endif + + /* + * Call attach or detach according as per event type. +--- a/vlan/nss_vlan_mgr.c ++++ b/vlan/nss_vlan_mgr.c +@@ -18,6 +18,7 @@ + * nss_vlan_mgr.c + * NSS to HLOS vlan Interface manager + */ ++#include + #include + #include + #include +@@ -808,7 +809,11 @@ static struct nss_vlan_pvt *nss_vlan_mgr + } + + v->mtu = dev->mtu; ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ ether_addr_copy(v->dev_addr, (uint8_t *)dev->dev_addr); ++#else + ether_addr_copy(v->dev_addr, dev->dev_addr); ++#endif + v->ifindex = dev->ifindex; + v->refs = 1; + +@@ -956,14 +961,23 @@ static int nss_vlan_mgr_changeaddr_event + } + spin_unlock(&vlan_mgr_ctx.lock); + +- if (nss_vlan_tx_set_mac_addr_msg(v_pvt->nss_if, dev->dev_addr) != NSS_TX_SUCCESS) { ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ if (nss_vlan_tx_set_mac_addr_msg(v_pvt->nss_if, (uint8_t *)dev->dev_addr) != NSS_TX_SUCCESS) ++#else ++ if (nss_vlan_tx_set_mac_addr_msg(v_pvt->nss_if, dev->dev_addr) != NSS_TX_SUCCESS) ++#endif ++ { + nss_vlan_mgr_warn("%s: Failed to send change MAC address message to NSS\n", dev->name); + nss_vlan_mgr_instance_deref(v_pvt); + return NOTIFY_BAD; + } + + spin_lock(&vlan_mgr_ctx.lock); ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ ether_addr_copy(v_pvt->dev_addr, (uint8_t *)dev->dev_addr); ++#else + ether_addr_copy(v_pvt->dev_addr, dev->dev_addr); ++#endif + spin_unlock(&vlan_mgr_ctx.lock); + nss_vlan_mgr_trace("%s: MAC changed to %pM, updated NSS\n", dev->name, dev->dev_addr); + nss_vlan_mgr_instance_deref(v_pvt); +--- a/vxlanmgr/nss_vxlanmgr_tunnel.c ++++ b/vxlanmgr/nss_vxlanmgr_tunnel.c +@@ -465,8 +465,13 @@ static void nss_vxlanmgr_tunnel_inner_st + + tstats = this_cpu_ptr(dev->tstats); + u64_stats_update_begin(&tstats->syncp); ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ u64_stats_add(&tstats->tx_packets, stats->node_stats.tx_packets); ++ u64_stats_add(&tstats->tx_bytes, stats->node_stats.tx_bytes); ++#else + tstats->tx_packets += stats->node_stats.tx_packets; + tstats->tx_bytes += stats->node_stats.tx_bytes; ++#endif + u64_stats_update_end(&tstats->syncp); + netdev_stats->tx_dropped += dropped; + dev_put(dev); +@@ -503,8 +508,13 @@ static void nss_vxlanmgr_tunnel_outer_st + + tstats = this_cpu_ptr(dev->tstats); + u64_stats_update_begin(&tstats->syncp); ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ u64_stats_add(&tstats->rx_packets, stats->node_stats.tx_packets); ++ u64_stats_add(&tstats->rx_bytes, stats->node_stats.tx_bytes); ++#else + tstats->rx_packets += stats->node_stats.tx_packets; + tstats->rx_bytes += stats->node_stats.tx_bytes; ++#endif + u64_stats_update_end(&tstats->syncp); + netdev_stats->rx_dropped += dropped; + dev_put(dev); +--- a/pvxlanmgr/nss_pvxlanmgr.c ++++ b/pvxlanmgr/nss_pvxlanmgr.c +@@ -177,7 +177,11 @@ static struct rtnl_link_stats64 *nss_pvx + * Netdev seems to be incrementing rx_dropped because we don't give IP header. + * So reset it as it's of no use for us. + */ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ atomic_long_set(&(dev)->stats.__rx_dropped, 0); ++#else + atomic_long_set(&dev->rx_dropped, 0); ++#endif + priv = netdev_priv(dev); + memset(stats, 0, sizeof(struct rtnl_link_stats64)); + memcpy(stats, &priv->stats, sizeof(struct rtnl_link_stats64)); +@@ -305,7 +309,11 @@ static void nss_pvxlanmgr_dummy_netdev_s + dev->priv_destructor = NULL; + #endif + ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ memcpy((void *)dev->dev_addr, "\x00\x00\x00\x00\x00\x00", dev->addr_len); ++#else + memcpy(dev->dev_addr, "\x00\x00\x00\x00\x00\x00", dev->addr_len); ++#endif + memset(dev->broadcast, 0xff, dev->addr_len); + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); + } +--- a/clmapmgr/nss_clmapmgr.c ++++ b/clmapmgr/nss_clmapmgr.c +@@ -102,7 +102,11 @@ void nss_clmapmgr_dev_stats64(struct net + * Netdev seems to be incrementing rx_dropped because we don't give IP header. + * So reset it as it's of no use for us. + */ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ atomic_long_set(&(dev)->stats.__rx_dropped, 0); ++#else + atomic_long_set(&dev->rx_dropped, 0); ++#endif + priv = netdev_priv(dev); + memset(stats, 0, sizeof(struct rtnl_link_stats64)); + memcpy(stats, &priv->stats, sizeof(struct rtnl_link_stats64)); +--- a/tls/nss_tlsmgr_tun.c ++++ b/tls/nss_tlsmgr_tun.c +@@ -158,7 +158,11 @@ static void nss_tlsmgr_tun_setup(struct + /* + * Get the MAC address from the ethernet device + */ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ eth_random_addr((u8 *) dev->dev_addr); ++#else + random_ether_addr(dev->dev_addr); ++#endif + + memset(dev->broadcast, 0xff, dev->addr_len); + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); +--- a/netlink/nss_nlgre_redir_cmn.c ++++ b/netlink/nss_nlgre_redir_cmn.c +@@ -384,7 +384,11 @@ static int nss_nlgre_redir_cmn_set_mac_a + return -EINVAL; + } + ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ memcpy((void *) dev->dev_addr, addr->sa_data, ETH_ALEN); ++#else + memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); ++#endif + return 0; + } + +--- a/nss_connmgr_tun6rd.c ++++ b/nss_connmgr_tun6rd.c +@@ -101,10 +101,17 @@ static void nss_tun6rd_update_dev_stats( + + u64_stats_init(&stats.syncp); + u64_stats_update_begin(&stats.syncp); ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ u64_stats_set(&stats.rx_packets, sync_stats->node_stats.rx_packets); ++ u64_stats_set(&stats.rx_bytes, sync_stats->node_stats.rx_bytes); ++ u64_stats_set(&stats.tx_packets, sync_stats->node_stats.tx_packets); ++ u64_stats_set(&stats.tx_bytes, sync_stats->node_stats.tx_bytes); ++#else + stats.rx_packets = sync_stats->node_stats.rx_packets; + stats.rx_bytes = sync_stats->node_stats.rx_bytes; + stats.tx_packets = sync_stats->node_stats.tx_packets; + stats.tx_bytes = sync_stats->node_stats.tx_bytes; ++#endif + u64_stats_update_end(&stats.syncp); + #else + struct nss_tun6rd_stats stats; +--- a/ipsecmgr/v1.0/nss_ipsecmgr.c ++++ b/ipsecmgr/v1.0/nss_ipsecmgr.c +@@ -445,7 +445,11 @@ static void nss_ipsecmgr_tunnel_setup(st + /* + * get the MAC address from the ethernet device + */ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ eth_random_addr((u8 *) dev->dev_addr); ++#else + random_ether_addr(dev->dev_addr); ++#endif + + memset(dev->broadcast, 0xff, dev->addr_len); + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); +--- a/ipsecmgr/v2.0/nss_ipsecmgr_tunnel.c ++++ b/ipsecmgr/v2.0/nss_ipsecmgr_tunnel.c +@@ -394,7 +394,11 @@ static void nss_ipsecmgr_tunnel_setup(st + /* + * Get the MAC address from the ethernet device + */ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ eth_random_addr((u8 *) dev->dev_addr); ++#else + random_ether_addr(dev->dev_addr); ++#endif + + memset(dev->broadcast, 0xff, dev->addr_len); + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); diff --git a/package/qca-nss/qca-nss-clients/patches/120-kernel-6.6-support.patch b/package/qca-nss/qca-nss-clients/patches/120-kernel-6.6-support.patch new file mode 100644 index 0000000000..2352c1ed2d --- /dev/null +++ b/package/qca-nss/qca-nss-clients/patches/120-kernel-6.6-support.patch @@ -0,0 +1,195 @@ +--- a/gre/nss_connmgr_gre.c ++++ b/gre/nss_connmgr_gre.c +@@ -276,6 +276,8 @@ static struct rtnl_link_stats64 *nss_con + do { + #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0)) + start = u64_stats_fetch_begin_bh(&tstats->syncp); ++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(6, 6, 0)) ++ start = u64_stats_fetch_begin(&tstats->syncp); + #else + start = u64_stats_fetch_begin_irq(&tstats->syncp); + #endif +@@ -292,6 +294,8 @@ static struct rtnl_link_stats64 *nss_con + #endif + #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0)) + } while (u64_stats_fetch_retry_bh(&tstats->syncp, start)); ++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(6, 6, 0)) ++ } while (u64_stats_fetch_retry(&tstats->syncp, start)); + #else + } while (u64_stats_fetch_retry_irq(&tstats->syncp, start)); + #endif +--- a/l2tp/l2tpv2/nss_connmgr_l2tpv2.c ++++ b/l2tp/l2tpv2/nss_connmgr_l2tpv2.c +@@ -954,7 +954,11 @@ int __init nss_connmgr_l2tpv2_init_modul + return 0; + } + #endif ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 6, 0)) ++ ctl_tbl_hdr = register_sysctl("dev/nss/l2tpv2", nss_connmgr_l2tpv2_table); ++#else + ctl_tbl_hdr = register_sysctl_table(nss_connmgr_l2tpv2_sysroot); ++#endif + if (!ctl_tbl_hdr) { + nss_connmgr_l2tpv2_info("Unable to register sysctl table for L2TP conn mgr\n"); + return -EFAULT; +--- a/match/nss_match_cmd.c ++++ b/match/nss_match_cmd.c +@@ -20,6 +20,7 @@ + * nss_match_cmd.c + */ + ++#include + #include + #include + #include +@@ -692,6 +693,7 @@ static struct ctl_table nss_match_table[ + { } + }; + ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0)) + static struct ctl_table nss_match_root_dir[] = { + { + .procname = "match", +@@ -718,6 +720,7 @@ static struct ctl_table nss_match_root[] + }, + { } + }; ++#endif + + static struct ctl_table_header *nss_match_ctl_header; + +@@ -726,7 +729,11 @@ static struct ctl_table_header *nss_matc + * Register command line interface for match. + */ + bool nss_match_ctl_register(void) { ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 6, 0)) ++ nss_match_ctl_header = register_sysctl("dev/nss/match", nss_match_table); ++#else + nss_match_ctl_header = register_sysctl_table(nss_match_root); ++#endif + if (!nss_match_ctl_header) { + nss_match_warn("Unable to register command line interface.\n"); + return false; +--- a/mirror/nss_mirror_ctl.c ++++ b/mirror/nss_mirror_ctl.c +@@ -16,6 +16,7 @@ + *************************************************************************** + */ + ++#include + #include + #include + +@@ -918,6 +919,7 @@ static struct ctl_table nss_mirror_table + { } + }; + ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0)) + /* + * nss mirror dir + */ +@@ -953,6 +955,7 @@ static struct ctl_table nss_mirror_root[ + }, + { } + }; ++#endif + + /* + * nss_mirror_ctl_register() +@@ -960,7 +963,11 @@ static struct ctl_table nss_mirror_root[ + */ + int nss_mirror_ctl_register(void) + { ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 6, 0)) ++ nss_mirror_ctl_header = register_sysctl("dev/nss/mirror", nss_mirror_table); ++#else + nss_mirror_ctl_header = register_sysctl_table(nss_mirror_root); ++#endif + if (!nss_mirror_ctl_header) { + nss_mirror_warn("Creating sysctl directory table header for mirror failed\n"); + return -1; +--- a/netlink/nss_nl.c ++++ b/netlink/nss_nl.c +@@ -328,7 +328,11 @@ struct nss_nlcmn *nss_nl_get_msg(struct + /* + * validate the common message header version & magic + */ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0)) + cm = info->userhdr; ++#else ++ cm = genl_info_userhdr(info); ++#endif + if (nss_nlcmn_chk_ver(cm, family->version) == false) { + nss_nl_error("%d, %s: version mismatch (%d)\n", pid, family->name, cm->version); + return NULL; +--- a/nss_qdisc/nss_wred.c ++++ b/nss_qdisc/nss_wred.c +@@ -296,7 +296,7 @@ static int nss_wred_change(struct Qdisc + + nim.msg.shaper_configure.config.msg.shaper_node_config.qos_tag = q->nq.qos_tag; + nim.msg.shaper_configure.config.msg.shaper_node_config.snc.wred_param.limit = qopt->limit; +- nim.msg.shaper_configure.config.msg.shaper_node_config.snc.wred_param.weight_mode = qopt->weight_mode; ++ nim.msg.shaper_configure.config.msg.shaper_node_config.snc.wred_param.weight_mode = (nss_shaper_config_wred_weight_mode_t)qopt->weight_mode; + nim.msg.shaper_configure.config.msg.shaper_node_config.snc.wred_param.weight_mode_value = qopt->weight_mode_value; + nim.msg.shaper_configure.config.msg.shaper_node_config.snc.wred_param.rap.min = qopt->rap.min; + nim.msg.shaper_configure.config.msg.shaper_node_config.snc.wred_param.rap.max = qopt->rap.max; +--- a/tunipip6/nss_connmgr_tunipip6_sysctl.c ++++ b/tunipip6/nss_connmgr_tunipip6_sysctl.c +@@ -449,6 +449,7 @@ static struct ctl_table nss_tunipip6_tab + { } + }; + ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0)) + static struct ctl_table nss_tunipip6_root_dir[] = { + { + .procname = "ipip6", +@@ -475,6 +476,7 @@ static struct ctl_table nss_tunipip6_roo + }, + { } + }; ++#endif + + static struct ctl_table_header *nss_tunipip6_ctl_header; + +@@ -483,7 +485,11 @@ static struct ctl_table_header *nss_tuni + * Register command line interface for tunipip6. + */ + bool nss_tunipip6_sysctl_register(void) { ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 6, 0)) ++ nss_tunipip6_ctl_header = register_sysctl("drv/nss/ipip6", nss_tunipip6_table); ++#else + nss_tunipip6_ctl_header = register_sysctl_table(nss_tunipip6_root); ++#endif + if (!nss_tunipip6_ctl_header) { + return false; + } +--- a/vlan/nss_vlan_mgr.c ++++ b/vlan/nss_vlan_mgr.c +@@ -1557,6 +1557,7 @@ static struct ctl_table nss_vlan_table[] + { } + }; + ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0)) + /* + * nss_vlan sysctl dir + */ +@@ -1580,6 +1581,7 @@ static struct ctl_table nss_vlan_root_di + }, + { } + }; ++#endif + + /* + * nss_vlan_mgr_add_bond_slave() +@@ -1920,7 +1922,11 @@ int __init nss_vlan_mgr_init_module(void + vlan_mgr_ctx.stpid = ETH_P_8021Q; + + #ifdef NSS_VLAN_MGR_PPE_SUPPORT ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 6, 0)) ++ vlan_mgr_ctx.sys_hdr = register_sysctl("nss/vlan_client", nss_vlan_table); ++#else + vlan_mgr_ctx.sys_hdr = register_sysctl_table(nss_vlan_root_dir); ++#endif + if (!vlan_mgr_ctx.sys_hdr) { + nss_vlan_mgr_warn("Unabled to register sysctl table for vlan manager\n"); + return -EFAULT; diff --git a/package/qca-nss/qca-nss-drv/Config.in b/package/qca-nss/qca-nss-drv/Config.in new file mode 100644 index 0000000000..1438627de1 --- /dev/null +++ b/package/qca-nss/qca-nss-drv/Config.in @@ -0,0 +1,168 @@ +menu "Configuration" + depends on PACKAGE_kmod-qca-nss-drv + +comment "Build Options" + +config NSS_DRV_BRIDGE_ENABLE + bool + default n + prompt "Enable BRIDGE" +config NSS_DRV_C2C_ENABLE + bool + default n + prompt "Enable C2C" +config NSS_DRV_CAPWAP_ENABLE + bool + default n + prompt "Enable CAPWAP" +config NSS_DRV_CLMAP_ENABLE + bool + default n + prompt "Enable CLMAP" +config NSS_DRV_CRYPTO_ENABLE + bool + default n + prompt "Enable CRYPTO" +config NSS_DRV_DTLS_ENABLE + bool + default n + prompt "Enable DTLS" +config NSS_DRV_EDMA_ENABLE + bool + default n + prompt "Enable EDMA" +config NSS_DRV_GRE_ENABLE + bool + default n + prompt "Enable GRE" +config NSS_DRV_GRE_REDIR_ENABLE + bool + default n + depends on NSS_DRV_GRE_ENABLE + prompt "Enable GRE_REDIR" +config NSS_DRV_GRE_TUNNEL_ENABLE + bool + default n + depends on NSS_DRV_GRE_ENABLE + prompt "Enable GRE_TUNNEL" +config NSS_DRV_IGS_ENABLE + bool + default n + prompt "Enable IGS" +config NSS_DRV_IPSEC_ENABLE + bool + default n + prompt "Enable IPSEC" +config NSS_DRV_IPV4_REASM_ENABLE + bool + default n + prompt "Enable IPV4_REASM" +config NSS_DRV_IPV6_ENABLE + bool + default n + prompt "Enable IPV6" +config NSS_DRV_IPV6_REASM_ENABLE + bool + default n + prompt "Enable IPV6_REASM" +config NSS_DRV_L2TP_ENABLE + bool + default n + prompt "Enable L2TP" +config NSS_DRV_LAG_ENABLE + bool + default n + prompt "Enable LAG" +config NSS_DRV_MAPT_ENABLE + bool + default n + prompt "Enable MAPT" +config NSS_DRV_MATCH_ENABLE + bool + default n + prompt "Enable MATCH" +config NSS_DRV_MIRROR_ENABLE + bool + default n + prompt "Enable MIRROR" +config NSS_DRV_OAM_ENABLE + bool + default n + prompt "Enable OAM" +config NSS_DRV_PORTID_ENABLE + bool + default n + prompt "Enable PORTID" +config NSS_DRV_PPE_ENABLE + bool + default n + prompt "Enable PPE" +config NSS_DRV_PPPOE_ENABLE + bool + default n + prompt "Enable PPPOE" +config NSS_DRV_PPTP_ENABLE + bool + default y + prompt "Enable PPTP" +config NSS_DRV_PVXLAN_ENABLE + bool + default n + prompt "Enable PVXLAN" +config NSS_DRV_QRFS_ENABLE + bool + default n + prompt "Enable QRFS" +config NSS_DRV_QVPN_ENABLE + bool + default n + prompt "Enable QVPN" +config NSS_DRV_RMNET_ENABLE + bool + default n + prompt "Enable RMNET" +config NSS_DRV_SHAPER_ENABLE + bool + default n + prompt "Enable SHAPER" +config NSS_DRV_SJACK_ENABLE + bool + default n + prompt "Enable SJACK (ipq807x)" +config NSS_DRV_TLS_ENABLE + bool + default n + prompt "Enable TLS" +config NSS_DRV_TRUSTSEC_ENABLE + bool + default n + prompt "Enable TRUSTSEC" +config NSS_DRV_TSTAMP_ENABLE + bool + default n + prompt "Enable TSTAMP" +config NSS_DRV_TUN6RD_ENABLE + bool + default n + prompt "Enable TUN6RD" +config NSS_DRV_TUNIPIP6_ENABLE + bool + default n + prompt "Enable TUNIPIP6" +config NSS_DRV_VIRT_IF_ENABLE + bool + default y + prompt "Enable VIRT_IF" +config NSS_DRV_VLAN_ENABLE + bool + default n + prompt "Enable VLAN (ipq807x)" +config NSS_DRV_VXLAN_ENABLE + bool + default n + prompt "Enable VXLAN (ipq807x)" +config NSS_DRV_WIFI_ENABLE + bool + default n + prompt "Enable WIFI" +endmenu diff --git a/package/qca-nss/qca-nss-drv/Makefile b/package/qca-nss/qca-nss-drv/Makefile new file mode 100644 index 0000000000..7f4b6d71e0 --- /dev/null +++ b/package/qca-nss/qca-nss-drv/Makefile @@ -0,0 +1,272 @@ +# NHSS.QSDK.12.2 +# by SqTER + +include $(TOPDIR)/rules.mk +include $(INCLUDE_DIR)/kernel.mk + +PKG_NAME:=qca-nss-drv +PKG_RELEASE:=$(AUTORELEASE) + +PKG_SOURCE_URL:=https://git.codelinaro.org/clo/qsdk/oss/lklm/nss-drv.git +PKG_SOURCE_PROTO:=git +PKG_SOURCE_DATE:=2023-06-01 +PKG_SOURCE_VERSION:=fe0bc6b077b842d13a06053271115bb9b3dcc505 +PKG_MIRROR_HASH:=1011fb113ba40d7919c0718d055ae6be8600fc8e02c1472f7425b7da47372a8a +PKG_BUILD_PARALLEL:=1 + +PKG_CONFIG_DEPENDS:= \ + CONFIG_NSS_DRV_BRIDGE_ENABLE \ + CONFIG_NSS_DRV_C2C_ENABLE \ + CONFIG_NSS_DRV_CAPWAP_ENABLE \ + CONFIG_NSS_DRV_CLMAP_ENABLE \ + CONFIG_NSS_DRV_CRYPTO_ENABLE \ + CONFIG_NSS_DRV_DMA_ENABLE \ + CONFIG_NSS_DRV_EDMA_ENABLE \ + CONFIG_NSS_DRV_GRE_ENABLE \ + CONFIG_NSS_DRV_GRE_REDIR_ENABLE \ + CONFIG_NSS_DRV_GRE_TUNNEL_ENABLE \ + CONFIG_NSS_DRV_IGS_ENABLE \ + CONFIG_NSS_DRV_IPV4_REASM_ENABLE \ + CONFIG_NSS_DRV_IPV6_ENABLE \ + CONFIG_NSS_DRV_IPV6_REASM_ENABLE \ + CONFIG_NSS_DRV_L2TP_ENABLE \ + CONFIG_NSS_DRV_LAG_ENABLE \ + CONFIG_NSS_DRV_MAPT_ENABLE \ + CONFIG_NSS_DRV_MATCH_ENABLE \ + CONFIG_NSS_DRV_MIRROR_ENABLE \ + CONFIG_NSS_DRV_OAM_ENABLE \ + CONFIG_NSS_DRV_PORTID_ENABLE \ + CONFIG_NSS_DRV_PPE_ENABLE \ + CONFIG_NSS_DRV_PPPOE_ENABLE \ + CONFIG_NSS_DRV_PPTP_ENABLE \ + CONFIG_NSS_DRV_PVXLAN_ENABLE \ + CONFIG_NSS_DRV_QRFS_ENABLE \ + CONFIG_NSS_DRV_QVPN_ENABLE \ + CONFIG_NSS_DRV_RMNET_ENABLE \ + CONFIG_NSS_DRV_SHAPER_ENABLE \ + CONFIG_NSS_DRV_SJACK_ENABLE \ + CONFIG_NSS_DRV_TRUSTSEC_ENABLE \ + CONFIG_NSS_DRV_TSTAMP_ENABLE \ + CONFIG_NSS_DRV_TUN6RD_ENABLE \ + CONFIG_NSS_DRV_TUNIPIP6_ENABLE \ + CONFIG_NSS_DRV_VIRT_IF_ENABLE \ + CONFIG_NSS_DRV_VLAN_ENABLE \ + CONFIG_NSS_DRV_VXLAN_ENABLE \ + CONFIG_NSS_DRV_WIFI_ENABLE + +include $(INCLUDE_DIR)/package.mk + +define KernelPackage/qca-nss-drv + SECTION:=kernel + CATEGORY:=Kernel modules + SUBMENU:=Network Devices + DEPENDS:=@TARGET_ipq806x||TARGET_ipq_ipq806x||TARGET_ipq_ipq807x||TARGET_ipq_ipq807x_64||TARGET_ipq807x||TARGET_ipq807x_64||TARGET_ipq_ipq60xx||TARGET_ipq_ipq60xx_64||TARGET_ipq_ipq50xx||TARGET_ipq_ipq50xx_64 \ + +kmod-qca-nss-gmac + TITLE:=Kernel driver for NSS (core driver) + FILES:=$(PKG_BUILD_DIR)/qca-nss-drv.ko + AUTOLOAD:=$(call AutoLoad,32,qca-nss-drv,1) +endef + +define KernelPackage/qca-nss-drv/config + source "$(SOURCE)/Config.in" +endef + +define KernelPackage/qca-nss-drv/install + $(INSTALL_DIR) $(1)/sbin + $(INSTALL_DIR) $(1)/lib/debug + $(INSTALL_DIR) $(1)/etc/init.d + $(INSTALL_DIR) $(1)/etc/sysctl.d + $(INSTALL_DIR) $(1)/etc/hotplug.d/firmware + $(INSTALL_DIR) $(1)/etc/config + $(INSTALL_DIR) $(1)/lib/firmware + + $(INSTALL_BIN) ./files/qca-nss-drv.sysdebug $(1)/sbin/sysdebug + $(INSTALL_BIN) ./files/qca-nss-drv.debug $(1)/lib/debug/qca-nss-drv + $(INSTALL_BIN) ./files/qca-nss-drv.init $(1)/etc/init.d/qca-nss-drv + $(INSTALL_DATA) ./files/qca-nss-drv.sysctl $(1)/etc/sysctl.d/99-qca-nss-drv.conf + $(INSTALL_BIN) ./files/qca-nss-drv.hotplug $(1)/etc/hotplug.d/firmware/10-qca-nss-fw + $(INSTALL_DATA) ./files/qca-nss-drv.conf $(1)/etc/config/nss + $(INSTALL_DATA) ./files/nss-firmware/qca-nss0-retail.bin $(1)/lib/firmware/qca-nss0.bin + $(INSTALL_DATA) ./files/nss-firmware/qca-nss1-retail.bin $(1)/lib/firmware/qca-nss1.bin + +endef + +define KernelPackage/qca-nss-drv/Description +This package contains a NSS driver for QCA chipset +endef + +define Build/InstallDev + mkdir -p $(1)/usr/include/qca-nss-drv + $(CP) $(PKG_BUILD_DIR)/exports/* $(1)/usr/include/qca-nss-drv/ +ifneq (, $(findstring $(subtarget), "ipq807x" "ipq807x_64" "ipq60xx" "ipq60xx_64" "ipq50xx" "ipq50xx_64")) + $(INSTALL_DIR) $(1)/usr/include/qca-nss-clients +endif +endef + +EXTRA_CFLAGS+= -I$(STAGING_DIR)/usr/include/qca-nss-gmac -I$(STAGING_DIR)/usr/include/qca-nss-dp + +# Keeping default as ipq806x for branches that does not have subtarget framework +ifeq ($(CONFIG_TARGET_ipq),y) +subtarget:=$(SUBTARGET) +else +subtarget:=$(CONFIG_TARGET_BOARD) +endif + +ifeq ($(CONFIG_KERNEL_IPQ_MEM_PROFILE),256) +EXTRA_CFLAGS+= -DNSS_MEM_PROFILE_LOW +endif + +ifeq ($(CONFIG_KERNEL_IPQ_MEM_PROFILE),512) +EXTRA_CFLAGS+= -DNSS_MEM_PROFILE_MEDIUM +endif + +ifeq ($(CONFIG_KERNEL_SKB_FIXED_SIZE_2K),y) +EXTRA_CFLAGS+= -DNSS_SKB_FIXED_SIZE_2K +endif + +ifeq ($(CONFIG_TARGET_BOARD), "ipq807x") + SOC="ipq807x_64" +else ifeq ($(CONFIG_TARGET_BOARD), "ipq60xx") + SOC="ipq60xx_64" +else + SOC=$(CONFIG_TARGET_BOARD) +endif + +ifndef CONFIG_NSS_DRV_BRIDGE_ENABLE + DRV_MAKE_OPTS += NSS_DRV_BRIDGE_ENABLE=n +endif +ifndef CONFIG_NSS_DRV_C2C_ENABLE + DRV_MAKE_OPTS += NSS_DRV_C2C_ENABLE=n +endif +ifndef CONFIG_NSS_DRV_CAPWAP_ENABLE + DRV_MAKE_OPTS += NSS_DRV_CAPWAP_ENABLE=n +endif +ifndef CONFIG_NSS_DRV_CLMAP_ENABLE + DRV_MAKE_OPTS += NSS_DRV_CLMAP_ENABLE=n +endif +ifndef CONFIG_NSS_DRV_CRYPTO_ENABLE + DRV_MAKE_OPTS += NSS_DRV_CRYPTO_ENABLE=n +endif +ifndef CONFIG_NSS_DRV_DMA_ENABLE + DRV_MAKE_OPTS += NSS_DRV_DMA_ENABLE=n +endif +ifndef CONFIG_NSS_DRV_EDMA_ENABLE + DRV_MAKE_OPTS += NSS_DRV_EDMA_ENABLE=n +endif +ifndef CONFIG_NSS_DRV_GRE_ENABLE + DRV_MAKE_OPTS += NSS_DRV_GRE_ENABLE=n +endif +ifndef CONFIG_NSS_DRV_GRE_REDIR_ENABLE + DRV_MAKE_OPTS += NSS_DRV_GRE_REDIR_ENABLE=n +endif +ifndef CONFIG_NSS_DRV_GRE_TUNNEL_ENABLE + DRV_MAKE_OPTS += NSS_DRV_GRE_TUNNEL_ENABLE=n +endif +ifndef CONFIG_NSS_DRV_IGS_ENABLE + DRV_MAKE_OPTS += NSS_DRV_IGS_ENABLE=n +endif +ifndef CONFIG_NSS_DRV_IPV4_REASM_ENABLE + DRV_MAKE_OPTS += NSS_DRV_IPV4_REASM_ENABLE=n +endif +ifndef CONFIG_NSS_DRV_IPV6_ENABLE + DRV_MAKE_OPTS += NSS_DRV_IPV6_ENABLE=n +endif +ifndef CONFIG_NSS_DRV_IPV6_REASM_ENABLE + DRV_MAKE_OPTS += NSS_DRV_IPV6_REASM_ENABLE=n +endif +ifndef CONFIG_NSS_DRV_L2TP_ENABLE + DRV_MAKE_OPTS += NSS_DRV_L2TP_ENABLE=n +endif +ifndef CONFIG_NSS_DRV_LAG_ENABLE + DRV_MAKE_OPTS += NSS_DRV_LAG_ENABLE=n +endif +ifndef CONFIG_NSS_DRV_MAPT_ENABLE + DRV_MAKE_OPTS += NSS_DRV_MAPT_ENABLE=n +endif +ifndef CONFIG_NSS_DRV_MATCH_ENABLE + DRV_MAKE_OPTS += NSS_DRV_MATCH_ENABLE=n +endif +ifndef CONFIG_NSS_DRV_MIRROR_ENABLE + DRV_MAKE_OPTS += NSS_DRV_MIRROR_ENABLE=n +endif +ifndef CONFIG_NSS_DRV_OAM_ENABLE + DRV_MAKE_OPTS += NSS_DRV_OAM_ENABLE=n +endif +ifndef CONFIG_NSS_DRV_PORTID_ENABLE + DRV_MAKE_OPTS += NSS_DRV_PORTID_ENABLE=n +endif +ifndef CONFIG_NSS_DRV_PPE_ENABLE + DRV_MAKE_OPTS += NSS_DRV_PPE_ENABLE=n +endif +ifndef CONFIG_NSS_DRV_PPPOE_ENABLE + DRV_MAKE_OPTS += NSS_DRV_PPPOE_ENABLE=n +endif +ifndef CONFIG_NSS_DRV_PPTP_ENABLE + DRV_MAKE_OPTS += NSS_DRV_PPTP_ENABLE=n +endif +ifndef CONFIG_NSS_DRV_PVXLAN_ENABLE + DRV_MAKE_OPTS += NSS_DRV_PVXLAN_ENABLE=n +endif +ifndef CONFIG_NSS_DRV_QRFS_ENABLE + DRV_MAKE_OPTS += NSS_DRV_QRFS_ENABLE=n +endif +ifndef CONFIG_NSS_DRV_QVPN_ENABLE + DRV_MAKE_OPTS += NSS_DRV_QVPN_ENABLE=n +endif +ifndef CONFIG_NSS_DRV_RMNET_ENABLE + DRV_MAKE_OPTS += NSS_DRV_RMNET_ENABLE=n +endif +ifndef CONFIG_NSS_DRV_SHAPER_ENABLE + DRV_MAKE_OPTS += NSS_DRV_SHAPER_ENABLE=n +endif +ifndef CONFIG_NSS_DRV_SJACK_ENABLE + DRV_MAKE_OPTS += NSS_DRV_SJACK_ENABLE=n +endif +ifndef CONFIG_NSS_DRV_TRUSTSEC_ENABLE + DRV_MAKE_OPTS += NSS_DRV_TRUSTSEC_ENABLE=n +endif +ifndef CONFIG_NSS_DRV_TSTAMP_ENABLE + DRV_MAKE_OPTS += NSS_DRV_TSTAMP_ENABLE=n +endif +ifndef CONFIG_NSS_DRV_TUN6RD_ENABLE + DRV_MAKE_OPTS += NSS_DRV_TUN6RD_ENABLE=n +endif +ifndef CONFIG_NSS_DRV_TUNIPIP6_ENABLE + DRV_MAKE_OPTS += NSS_DRV_TUNIPIP6_ENABLE=n +endif +ifndef CONFIG_NSS_DRV_VIRT_IF_ENABLE + DRV_MAKE_OPTS += NSS_DRV_VIRT_IF_ENABLE=n +endif +ifndef CONFIG_NSS_DRV_VLAN_ENABLE + DRV_MAKE_OPTS += NSS_DRV_VLAN_ENABLE=n +endif +ifndef CONFIG_NSS_DRV_VXLAN_ENABLE + DRV_MAKE_OPTS += NSS_DRV_VXLAN_ENABLE=n +endif +ifndef CONFIG_NSS_DRV_WIFI_ENABLE + DRV_MAKE_OPTS += NSS_DRV_WIFI_ENABLE=n +endif + +ifeq ($(CONFIG_TARGET_BOARD), "ipq806x") + TARGET_NSS_MINOR_VERSION=2 + DRV_MAKE_OPTS+= TARGET_NSS_MINOR_VERSION=$(TARGET_NSS_MINOR_VERSION) +endif + +define Build/Configure + $(CP) $(TOPDIR)/$(SOURCE)/files/nss-firmware/nss_fw_version.h $(PKG_BUILD_DIR)/exports/nss_fw_version.h + sed -i "s/define NSS_FW_VERSION_MAJOR.*/define NSS_FW_VERSION_MAJOR 11/" $(PKG_BUILD_DIR)/exports/nss_fw_version.h + sed -i "s/define NSS_FW_VERSION_MINOR.*/define NSS_FW_VERSION_MINOR $(TARGET_NSS_MINOR_VERSION)/" $(PKG_BUILD_DIR)/exports/nss_fw_version.h + $(LN) arch/nss_$(SOC).h $(PKG_BUILD_DIR)/exports/nss_arch.h +endef + +define Build/Compile + +$(MAKE) $(PKG_JOBS) -C "$(LINUX_DIR)" $(strip $(DRV_MAKE_OPTS)) \ + CROSS_COMPILE="$(TARGET_CROSS)" \ + ARCH="$(LINUX_KARCH)" \ + M="$(PKG_BUILD_DIR)" \ + EXTRA_CFLAGS="$(EXTRA_CFLAGS)" SoC=$(SOC) \ + $(KERNEL_MAKE_FLAGS) \ + modules +endef + +$(eval $(call KernelPackage,qca-nss-drv)) diff --git a/package/qca-nss/qca-nss-drv/files/nss-firmware/LICENSE.TXT b/package/qca-nss/qca-nss-drv/files/nss-firmware/LICENSE.TXT new file mode 100644 index 0000000000..41631989a0 --- /dev/null +++ b/package/qca-nss/qca-nss-drv/files/nss-firmware/LICENSE.TXT @@ -0,0 +1,45 @@ +Copyright (c) 2014 Qualcomm Atheros, Inc. + +All rights reserved. + +Redistribution and use in binary forms, without +modification, are permitted (subject to the limitations in the +disclaimer below) provided that the following conditions are met: + +*Redistributions must reproduce the above copyright + notice, this list of conditions, and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +*Neither the name of Qualcomm Atheros, Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +*No Reverse engineering, decompiling, decrypting, or disassembling of this + software is permitted. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. NO LICENSES OR OTHER RIGHTS, +WHETHER EXPRESS, IMPLIED, BASED ON ESTOPPEL OR OTHERWISE, ARE GRANTED +TO ANY PARTY'S PATENTS, PATENT APPLICATIONS, OR PATENTABLE INVENTIONS +BY VIRTUE OF THIS LICENSE OR THE DELIVERY OR PROVISION BY QUALCOMM +ATHEROS, INC. OF THE SOFTWARE. + +IN NO EVENT SHALL THE COPYRIGHT OWNER OR ANY CONTRIBUTOR BE LIABLE FOR +ANY INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND REGARDLESS OF ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF OR RESULTING FROM THE USE OF THE +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. IN ANY +EVENT, THE TOTAL AGGREGATE LIABILITY THAT MAY BE IMPOSED ON QUALCOMM +ATHEROS, INC. FOR ANY DIRECT DAMAGES ARISING UNDER OR RESULTING FROM +THIS AGREEMENT OR IN CONNECTION WITH ANY USE OF THE SOFTWARE SHALL NOT +EXCEED A TOTAL AMOUNT OF US$5.00. + +IF ANY OF THE ABOVE PROVISIONS ARE HELD TO BE VOID, INVALID, +UNENFORCEABLE, OR ILLEGAL, THE OTHER PROVISIONS SHALL CONTINUE IN FULL +FORCE AND EFFECT. + diff --git a/package/qca-nss/qca-nss-drv/files/nss-firmware/NOTICE.TXT b/package/qca-nss/qca-nss-drv/files/nss-firmware/NOTICE.TXT new file mode 100644 index 0000000000..ab54aa019c --- /dev/null +++ b/package/qca-nss/qca-nss-drv/files/nss-firmware/NOTICE.TXT @@ -0,0 +1,217 @@ +============================================================================= + +This Notice.txt file contains certain notices of software components included +with the software that Qualcomm Atheros, Inc. ("Qualcomm Atheros") is required +to provide you. Except where prohibited by the open source license, the content +of this notices file is only provided to satisfy Qualcomm Atheros's attribution +and notice requirement; your use of these software components together with the +Qualcomm Atheros software (Qualcomm Atheros software hereinafter referred to as +"Software") is subject to the terms of your license from Qualcomm Atheros. +Compliance with all copyright laws and software license agreements included in +the notice section of this file are the responsibility of the user. Except as +may be granted by separate express written agreement, this file provides no +license to any Qualcomm Atheros patents, trademarks, copyrights, or other +intellectual property. + +Copyright (c) 2014 Qualcomm Atheros, Inc. All rights reserved. + +Qualcomm is a trademark of Qualcomm Incorporated, registered in the United +States and other countries. All Qualcomm Incorporated trademarks are used with +permission. Atheros is a trademark of Qualcomm Atheros, Inc., registered in the +United States and other countries. Other products and brand names may be +trademarks or registered trademarks of their respective owners. + +NOTICES: + +============================================================================= + +/* + * doprint.c + * Formatted string print support. + * + * Copyright 2001-2012 Qualcomm Atheros, Inc. All Rights Reserved. + * + * Qualcomm Atheros Confidential and Proprietary. + * + * This code originates with BSD Unix however it has been extensively + * modified. The original copyright is reproduced below: + * + * Copyright (c) 1988 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted provided + * that: (1) source distributions retain this entire copyright notice and + * comment, and (2) distributions including binaries display the following + * acknowledgement: ``This product includes software developed by the + * University of California, Berkeley and its contributors'' in the + * documentation or other materials provided with the distribution and in + * all advertising materials mentioning features or use of this software. + * Neither the name of the University nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * math.c + * Support for the standard C library. + * + * Copyright 2006-2012 Qualcomm Atheros, Inc. All Rights Reserved. + * + * Qualcomm Atheros Confidential and Proprietary. + * + * Software contained within this file was originally released with the + * following + * copyright and license statement: + * + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + + +/* + * stdlib.c + * Routines from stdlib.h. + * + * Copyright 2004-2012 Qualcomm Atheros, Inc. All Rights Reserved. + * + * Qualcomm Atheros Confidential and Proprietary. + * + * The code for strtol() and strtoul() are also subject to the following: + * + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +drr_alg_utils.h: +/****************************************************************************/ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +shaper_list_utils.h: +/****************************************************************************/ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +codel_alg_inv_sqrt.h +/****************************************************************************/ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ diff --git a/package/qca-nss/qca-nss-drv/files/nss-firmware/README.md b/package/qca-nss/qca-nss-drv/files/nss-firmware/README.md new file mode 100644 index 0000000000..2d0b47508a --- /dev/null +++ b/package/qca-nss/qca-nss-drv/files/nss-firmware/README.md @@ -0,0 +1,10 @@ +NSS FIRMWARE +============ + +This repo contains firmware files to enable the NSS MAC on QCA IPQ806x SoC. + +This product includes software developed by the University of California, +Berkeley and its contributors. + +NSS firmware extracted from Synology RT2600ac SRM 1.2 - Version: 1.2-7742-4 + diff --git a/package/qca-nss/qca-nss-drv/files/nss-firmware/nss_fw_version.h b/package/qca-nss/qca-nss-drv/files/nss-firmware/nss_fw_version.h new file mode 100644 index 0000000000..4b1bd41586 --- /dev/null +++ b/package/qca-nss/qca-nss-drv/files/nss-firmware/nss_fw_version.h @@ -0,0 +1,11 @@ +#ifndef __NSS_FW_VERSION_H +#define __NSS_FW_VERSION_H + +#define NSS_FW_VERSION_MAJOR 11 +#define NSS_FW_VERSION_MINOR 4 + +#define NSS_FW_VERSION(a,b) (((a) << 8) + (b)) + +#define NSS_FW_VERSION_CODE NSS_FW_VERSION(NSS_FW_VERSION_MAJOR, NSS_FW_VERSION_MINOR) + +#endif /* __NSS_FW_VERSION_H */ diff --git a/package/qca-nss/qca-nss-drv/files/nss-firmware/qca-nss0-retail.bin b/package/qca-nss/qca-nss-drv/files/nss-firmware/qca-nss0-retail.bin new file mode 100644 index 0000000000000000000000000000000000000000..6222fd535dda641d361d6a2c4e2beaa6fb0a8046 GIT binary patch literal 588512 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

pAcidxq)Bs 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 literal 0 HcmV?d00001 diff --git a/package/qca-nss/qca-nss-drv/files/nss-firmware/qca-nss1-retail.bin b/package/qca-nss/qca-nss-drv/files/nss-firmware/qca-nss1-retail.bin new file mode 100644 index 0000000000000000000000000000000000000000..92f646daa728656a6d522137203ad1e5dcc823d2 GIT binary patch literal 220780 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≥0uoq~Bzrl?$n}T|isu%sC zJr9$Vb^b;d@i)80_$}y}SQ5U{c*AjB0WQ?G+RdO-)ZTAt>vZZL3yjGF)Zr@ehqkV- zj9$q8Z};|9Monxfd9@~*06*+sK;C6&b{L#+4ZRZRz%2YKo~}pdCW>@Z-3O_AJaj#t z`js;(p4QsfO8>XuDq(xh>tU_>3-0fMNx2c4pD5`by*~=ssN!8cKY{CcMVJMDq-xK&fkKbP@{+4cT=l6~Lw#iFf4?HaS&^|ZP-G+6S zPk^V8d@nIsqN14Io7ePoN|9ZF`D#=yJR!Vp7rf-7zL+F^f;N$rZ zv#0Y1sKWt+MQvw7et1)emQwg-Iv znzoFo%r`RsZ`yZ9BIq!O&fGC}N5&F=uSAz={?ks!=RtPS2baB#?^vl^aP~B?&Cz(Y z=x>~XPCEzPcBUU4(re1eGnb_@yU~Nvae_m95%t3XPe_&p*B!vMguYA1{T_b#E^tY9 zesI9#1HNc6mwgS~K1Cf`2dVuE@x0j!4LwWFyx_*>Y0cxt*}=2IK9K&5a7(x)S4~V| zeG;CEwnUp|K~uFWe%ym@d1pOT(8=FEIazgz$F=--8b4leOV3D1EpFXH+~w7L6V*)jXzmW}&T*cxCB zNpF|s^lMx#o}67ZJ3|udrk{Wl$@o(6SHh=Yd=wbN$ea3k0r07R+o8Go8^(?bAHs$D zu6~P;Rfcs08-3_ds5d->s}c|W1NGidTd&aOlw!SlUwIjNFT#3rwy>X>a3R@H+a+FUhd;h6{(x_*X>T`sjj27ArJbt= zFEeS*_eImYBih43b)H3Csz+t?{!h3T-^mYAy?0UH0pcDXV}45I)xK~ynfFR{{~hm$ zHw(O4kkQ}pUWz(OeEJG?sC;x`Piz9b_}9E68BiO+rgWa)r<)@pRGuk(}m#j_k^1bnKF{yWiWQSNJx zt$IHMFWu=Bmn-)d6q766*E{w89d7vZ65P_kg8NQ%o$z=+a4VjtoZG+;BvvK96wi2m zM=0e|nQr)V$VV)DZjwhn5B4NejLr8$hrKscf$(zx*YWTeL6GYTA9yu3Hk%O0B>_%y z8Nuf0zxJ;*$yGt$OJm?t%x0)+E*ktnPy4G{@HLBmEJ40})`zPO##>H(e+hiaH|mhC zVBWLZ)Uvk-d9<@V_8c%7)`F5Nb_!>8N2>4(Gx9kG@y`oN4g+6z><^h6C!=R1S9 zJ|{b*Ix(IZKnSkOVLI#@*kofz#*IoQx2pe&Gf1NELkx2W8|H)W3)habWZdq*Cq1y9g=R)<%9{1Dt+^xyslE`H&hb$`*v6SM9+#dxzEGYmwgr{?5Uk#^J5|D!Vt=an`*g_rAk# zey}${t<(Otb$%0a7k8@zJLIr$CRnc#4`gz+v&5ISCCJr)<|g?BFswUF&NQBj`>W{B zYNvI=LpUqH06(m?AdPwFU#-S=)-I`d&<%Ix_|_g7Z2WzPAM!H?P>C7c)OAy~9`VRt}}WJY7J zAvnP60pUJr9rk312Ct2fyC_~4e=4`sRPV~L&*1tH_Kv6|zLj+4Hh6|H7C5Qr{;iA+ z{8`4nIxkvZ4^C|+kLVRQz?v$fHHfS$F^ts={-wqNuYiwWj}^N! z!yCb#;5!u?L*67~@^8xJY!pK6oXV8MlvS(D#@;N_&`zC z2EhMLVA#!mEU&WO%)u)=_`SVqd&Zg_8SNp(da%xo;3ww_a|RlJOQz8j!9LlNt39bK zu&#ELVP7aJVISnRZf&M8MyRtTyRyHS|0rAuKf=i_XdEXl@jT}}?3JQ=wEn-q)rbCn zKm8U$w^?60?vK}R=NuSWzxl)P{sn&jpVn`ZKiN0=U(!!}7seIt%?{48OU;y-%b4}) z3fZ_pFNwYTxfja+1Mygu%^WoL>448!FN$+!c&0Kh5nH?N;19MO!uAMP(Agw!W1o<3 zvxm(x;`U#2cfbQR!T!ozwSS9yOI-*2Skgbj(Hu7?lcJpD-=G^4#C?bB$Gdn(`vwPe zPpV97Q0~n#K9FxC9V45q_+}?DvD`3ShXo7va#@88Y5q-oS_?lKvnr#w)e^S^onP3y zT{05bcFM}%!5^E_$h`%OkFhps#h03p(K=wO=Y9wJ;UV`=p;wea5eaW<7y^DB}N*+9&wWhb|2glAhs)#M+DH5#?GE3= zyNP}D)#gKLGmsJJSGFhmw`g}b53AhjvVFs~|5*u6;s-0m8y>KhJEC5YjfBv`>ffQt?v*FJogw6 zXukr*lW$}G@=Ft$FK4Yr_IPZ1jcMr!nNICp@Dp;Ql|%j*cC_BF2vbX-i_S1N^_t{7 z?A?vMtj+E+Jch}-d@He&Ct7K<`NEh#o49NTd!ENb=?H6dO!Ok=RM{(>T>IlmpgC4P zRn7D>{o`5ltJR$7k|z7aEv0eTldZ+F$UOuRP|#{>fd_nPYy`#q)Q%8;&(O$Gl+4Pn12b;9We9q6~cx8M+&`{4O$d zKQi=#@ZEcGSIwd)6RgjcJ|23PehB`51gEv!pNBtWH6M-sdz1Wy?MKl=vX6>w2&WNz z0`*b6(f#lV{RUbXXnztoX8j#G+NSeV@Fe?edUCOcyR%#G0WXSqXs#iYOfcYd6Iab=AJZPr#Kz7%P+yccr87#!Aj)gHJig%d(JZM zvwpXGO81&f&f}hP#n&pgV(9lJG4l@j-{elQez*f&&?S8kj)t$Ik@OOLm`cWU5ASEp zh>p-a9rLj<=@ZSpNN-m*Js#6Mo_;&-S2kS|i!`l?*{PAVavKIYoBhmZG(}>{e7DTG zR5VvyrMaVuY1x^|$zku3Sh($5?i0iwQqZLE?WL6Su?NDvd@1!)Jl_ew2{z@A2tJ=& z65+VJ_gIzhe2X#6<3*mjmUquENAi?(Y&l_S}eTY}a_fk8W zhVqu@K00MQ@dNR&kK7x^TK*Y+reyodz&YZwWZz10Kdrr!ZZ5%U{HMZW@YPJ)hKPA* z@NvPo1fBa5dR=QzlLwGg;ttXsqPgf`+dccc268<3UB_?f_)q*{`IcwBO;3Hd<@u-j zm{U+(^`>H6)%Z_`uRJCmeACF_8?%i^kSF^nbr^qbSn>Hf^g$Y&O{YG?dQZz-`5b=!`B(aW?sjoiDikOWYSZi?@Gs_MQF4Z*#Y!2itltac%fsn}7MpR)Y?a zU0I6!XW@61@qX1D>!uuQvH}|~J@zNR*IWp?@e20cXUp&_p&++0pQ9PemJU4O{?6t{j$TKFk%$(5# z#_-28mak*a>^O3gU<`a>a*q4PWcq9Jw}`i7cZGM^UG@JVU`!p<9`qWQu8WB8Y86w* zUolOrHAV-Li$^SIR)`ouXtwwW+nGckn#yJ9j_>qVCch4w8m?`xe3rl$O+Fs(L&uhK zCAPu4hBam3EV+77bJYWqC;eVp_#OE3{H`cI57zYa+uUd3-=^#a_8EDuk$%8uit&{E zml8h~e1n&R{J;-CW{bWDd*86f*y-riYG~QfyV!}A9lf^}&&hD%w_iNZDxPN-&#B_M zH9YE5i+Vr($s2mrj$x$i~}y{qU0BS>Zc+XNT|XO@+VO+Zz7xDsnHYGM_Q#!@W;~w^86g{lBd@ z8GcA8@%3iT|u}Kg*su*2jI1K7SWFdE{%EHojdO4|m~9bTWo|?#k$)JRDof zXJY4k&zQg#%9eG3=MXfWJFm+L*D2}FX_kBF&Zzvtlv`Bv*&;=H=)F$b#F}*OX6=#k z=#6=XJ^Jg2U&T2Zt@2SzxzWMcBmF?Qd({K(;Z=X*T6<}g-0HXYj|y_WABNYbg#7;Q z{dLF|{QxJ%jLz>s4-RgQ#@^jr85`VsOsrz1+a zDO|v3%#}T(oLY^G_M6&tEoGRm+-Oo&$n#lg#qrN-Il1NJX4AQt>yxiCo!=I{h-o`? zDY2U8zDGOXW%sWXxL?~^Yip%*;rm7NJ)5YWepq%lHzY&?B=s@Bz_*Gw|*E^Nhr zUDxUqH?L)Ft9ar8Xzl?o^{)Thi5IX}$BLLo-s_JiUc~-7t75Lnu@==`^%L}J=)u!I zqny`=62U%u>$B}u_O$-fJ~MOisf=In8-WXqwV0lS6E6PNc`b&y^&dIz)tIYHPeXA3 z$Hn`P4Bc;Z1^ChD(sON#!r!BRry28{#sZ?Lcv-oZA>ZVPYiyLxweWMC^}KTvb2C@^ zNAjoi-w*Ei!3~`W#v8VC=J$|&@i&ch0Zs1e!NF$_JuMS z*~?R=lkvd%9gNjnAN$S2W0Lhy(l~v0%}%#_%>mVAI=@7J3gxQozGR`CVH}~o`^A@v z?GCSpkD|IS@Lc-#iv7#CjOE(6su(fejhe%=_)%K33*QHSL;e+G%8%?^{-WLs{2p-q z(!2O&l0S4;g4`IzC{1KB>m=Z!V7&x;0b?hVQe#>4Yum!B?Sl=;=Zw4{nR9~|)Mqbgz`nc(QnYGFF$n@*%=~chb zbZ+IWciC$Wom-!;r_bHW381gKPJmdRCjVkn(K8SKZuypPGoIJ?*0adRSZvl;mwfdzL5zvmdU=c~X8xs5K9+oW z6kPt;-Xu25cOSPOZyRgA(l;G?;G-}PY3yj*y_xvt=ErKgH`nX?p3U8xr^UNBZ>{Uz zd>a13IC9|U6H~t^+P(Sjn2*1PXFcqRJej$Obf3Ud-Tn&6BB~ zUFhXx2H!bTuvM?2XH=ihyB)l{wIBll4$AdwV@)B)M*1J$HQ1kSG}n#z9lEEwgZ(tY zpKzAEITr$_tcEGX1%`ApGNkK;$Z`3-1Hh{~-UU9b4T7tO)){4QPKE|$yK9I)v36N; zhVplZVRh)IH_hZO#6NU~Z)T!XB~RW2?Tv6@%#0t?bz=LN78`wub-+ExS$OcCzJ&dD zKe3FOr-Qv!v&<8WVXP^?lZ|~n{kCb=h?wlNrQcrR`3C)-WOA%uWL*im)GowH`rm!{ zv~iSUEBt{^@ob2_9QbB=5RX^?P4$>A{KWMY>U*)zx6|iR-vs~Bjv=`yVpw$Mug!wn z3&peGyE(u&u|N1(@~<^c9(zHX$|Amv**pe+;zRwlHc`Yg)eYgVtFVHhr=!UgXH z^C`u?mv9jDkv^;6|9>5&J~B>dd0~i`7!$%vH*hQm1_SlC`+6(^< z=Q-*=^e6uFzY;!LnQ<0dPo6Bv+1UIr+iDcna~pj7VI4k{4dxT1r49SXYkiE#|&@b!dYbZZB#Mm{)c+N1-=jzixH*{#I;wioNH?1-T||XiTem?xU>y=TOoGwpaJ`r}&>qzJ#3w2TA&#><1U% z6kjsQ_l`a6hxW&wjQ*SF<^^{6TKtWx7l0#+F2--YRC57U*Jc(J{p^px4XYA zhdORn{fd==qa**I<$iMD1heRP(qVMudnM43u`_#6W7EyG8PQ$zD$vrz{yd-swDj56 zmv#j2NHh#+2Mv{zLVY>Svy^DKZ~vrVd{Uz0q2C2s9{OFNr{Yz@mta}O`sB*7%$>o< zL$uUfWk5^Tz%m|GtnwblTp`9v8lTzm_YCy|%*mG;%3ZYnH(fx#WoGGUlVwb8@}en| zw2Unm(9ij9jjp-B)ol%ESE3U>Z01RxdC2z+0eQ=#e5oZmA|-e`Ia1OvQDub{quOH zxNerXZZmpEF^Kn!^Fx0ZwA&u`{B$_v-y9D6w}d19;_&PN+D?8Y%zDQ#k(K<%#~tZ| zZ!P9eY7Js(jzGF{Ma0C$*zWa@kFxvn@Nunwz^z5L*YMk!zvx>z@CR4#zl*QG-_`nW zxZIw1;NLw?F_vD}8|aZOj0^BaV#>cv>e}Dp^jkcXL{13kV-t&OcS_%1dX(?$kt?Bn z`SlIAcT$D#lizK#8_7(LEd{10iH9hU>uL9NF^}uX%wKY!cBhzg$ajZV>L-}Xrdals zAm_3%wcDLN?{#<9yx+MvxMCb-U;dNs&D!^NWn^Wea)af??nWj$AOSw~}HwFJ7@GnU1a|_8|_|k&@@V+x%&CFl$a(M279pSbG1K~Q}?VlgA zyPfHJb)roxZnu}X-Rp`S`@7ulIBV}vj8zvD>N0n^+`r>P?53~e!;@25$x-dp$E(9O zJr6wXs*(m_?=jwko4S(Q!5p!&+6fh1FVAO9e^A%n%r_Um8yUQ{uOdV&T6(tvn?w2h zbe14lze6u8KSlF+&s0ofZ!eyqf%9K>U(Q@#b^Ver_g?2T&!+Y35%{nIdbxXqGcJQG6%Io3v+0b=?^zJm~ahcPqi0@psmv8&&eXYY0{&-IXK}pwlt98lk4ff~Mo2I@5aE;@A z_3uL3dnjW2&4Iwr86odiG%_xLh4N!Qs@xDb!z9vU;lo@iF_icBGBMR1^Ut=gjI~{7 zvnPn=3TkqfQ&IVtvQpe`jTJU$L+nKt<_0NysD;R60+OAOQp!4F(?w-Q-hbpVS zh~Ju`-(Iw5{&(El^SAK4 zknv28p*8CP$1ck3fd}mPJ)9$U#aZMAfaj79$Q8fWFcBO-O+TR#xjm*MkX2%7qqv`& z11s~b2Yv5F<4cR33C`G=V7xi>y@vSEJk-`b1)F2=9T@v=Vjj@G6`U^({Ge6HOfa70 zd)9mdaMSf_n|Vdk<2l=7-I743hw?W~yeT7|6b>3(Ln8I>%U>+e6}^j&2id)W41KLWmFzI?37^1U_B?t%|h&LV@!{qdmRlZt(|#37X1eE^u+ zt8TiRQ6JxpoRcvVO{NtZ>stUO`IP$+XVo#G3|Hg0UL5pcF@1O-$SGb1%-uzpH!z;p zJ5`ihM7f2;)fN$-n5-B+-?S+4i{`lH%Lx|EL98HlsP9?eeZ>}uH~d=qIUjq&oFIO( zXQr>$cM3F5zUr)1H;S)(>X+RZNBye1RA;F^)%7MZi1~pXDSR)ZmVWDd8Kjz#1G#`b zdl)-R(>F70e%0tzd^4lgj^Vwl50<`}QGoLd!HH}NPSYOIT>sJw`Ci6grI(%s&h*U; z#WPMop2UwH{SzOF_Gz}36c34Zm%wYnkN9LII1}A!gL2YIeDA)hJ@XODl;lZyo+X^A zF4;oaNAZRUaP*}6O%V?!JN_69#vx>uwRlx+3W;;38{^uy`EG2wz+IIh0|GLO!ALp>nFk|qC&gQ(qZCG|L=S^qHZMDm^S`-&TlNvozjeP|_EF9+ zxEGdfhiAmg_ppZ5p@)*_p$O;Ed_Vg<<_^~Np6sR^sI^b@TG!j_xhH!=ZcXoL?(yCZ zx3>2-m+!sZZOWVxQ9Y`|q|c1}oPN%s{-=9S5AgAY*0}xLZ15_{cBvzS^9~bJ1xU_!}R#`MN0IatEe8^8b>Xob}ha=iv*+f6K(% zo1ulix%6-J>C#aT?(25l%YMuCW%$}H_}tivWiRks{m#1VvM;oAzxPC?;+s1w$9Q~AQ;rV-9%f^}!{)VqFxbm2u{$EDo{hvFgxqmI|9?m-uw=)?t zh<7gnZ-V3NzV9U6Mbu{@$NI#URS&(o>p$Tw?>|K>Ef+bgKIUaF3?ITnq5sm2qSK(K{F9t3tQpJUdrv?gtlGcb zJ(U{Zn@Q}~j1B7rjs)_d90*Hap5}TMF{mez6JpKS&?ns!(p~IB22GyvCOo;!nqGF% z^82@oPvE2EUXW?@PfFfsu(JhNOa0=lSTl7QzmY!G+tyS=@hrVGC%BHY zmT4X93#J7;a3MKp(%A(bkna96bkH|uL(o+@X~8#Lu+L2sLid^RA-)??mqx}}lLNhZ zuMR$F<(;}>`G6M+_MEs+fe*e=r0u98A8ea<{#W96?&N-)wRds9fuqr_=64A{8rQCK>w<4oox_~0 z_~2#c(gL4gNG^*P$lEOHyoi`kNtUET6w_UczEwPz`4QktvfX`Sy41#OH#?Dsj*Na| zp8`*JVBcIS<<@c5Ju97t9=;0d2IFzuu2H_#sAoKafx9IQ3uhSp^P*9Kk?7 z>!{;M`K+s{ODiT-$2+3S;En=aO7baQ^PoXVKHuWGk}PJ08nmzLA&LGbfIXr=uR>!@F}TJ}D)y1R&T=0yWt zDjI2g{9bgrwfN5KMLH?AsP_~T9R6Mc+-v>WaN6u4CpfUN$ee8CHRL##+7``5q>XMu zAM0No?kom+cn--PGLDNl(R<$MXZ+ll8q+Lt+K-l z>xkd6hLgHhSFKK*hYw(qtKfr`?mYBa9b-fGD0Cja@}$JC$ zloPqAl`)A=U;RazxMTnF+mt`cT(j4e8<$&5r9(Kto@^|wRo0j(H>aPR9L7JJHC~FR zm3P$$9ps~*SLU0muXVJky@x{Z>_x|kZXa`v;6&^BO!Zv%cx%B2n4Q|@ge&RS5?{pV zgZ5EPk(+u9bJB|49}Va7H-z&)2j}H{RM@8i{sUI+X#=hf{T1a;G<{@{e70eKijxdx z7cJ^Oiu~%iXiwwi#fsIT5Ve1^N1BZu;~XcmabRs_`#Oa^*-(o>(XIArCU7wZShj5)5TiJ z4JCFiS8fmuQWan(f1(txh+JW z2R-3Iacz&f!s$V$Jt1t{9^k06pAT|cy)OA*@-a^{-5XpRQ8wZ{o92NF{Hl|W2b~vp|=Do|vk=i&wnM+t} zsIniWY%o_;miH{ala0}S8S+D0u&a0A->%-jI?>0y%fY4SuW@M{JZwEs;NL63sp<-N zRr3erPu&&h5Y{Lh&zyrthD#)`^ z?wRTq9CP8n96S|AC;lNA#~m7{9Bq!hWM4}9DWD^57<57qJHFS%wSKz+oJqf4#o z8~9dRKoXmdFNmLe*tk*l=acMLJ_CF4d-nWQ&VcNOd_cWBdzSS4fKwgvF*MKc$?uq@ zZw-F&x$?DyCH@odiSIP`Azt+C$`1v3ZmgTv{FwM%<2}LJNc|sk*1fs@ADqr>ng=NtV;+1`;KD2_hN_oCD)d*1U5u# zXXDgKZrBlZs;wEcxea?IoNNv7!OXgHpqkLzr664VyTO+*S&O;u3BmR^=i9y>u-0SWC8>Of|7B#WfYU@^9 z?XS9Zd)aoo+siH!2;kT#Mv2;L@*XVIFpdXJ z$7J$LPhkvJ+8e+@T~KA`+ew|POYiBONu~0)9sdzD0WpAa9ZT8D+mD{29{?^P^ z`iJp|zC->N?ybJxYw(bj)xQ(*$VjIOWwLrxbmL(ox!Io4YCYQKL|rd99Kzr(q1 z`06UY*=3O@>GRf%>VX-6$9vGbIfs84_?bZ-xMTGl*R=r`{A_vX&mw<6Z#Pc=wFQ!duPd)rT!p&bg-1w%NbsJ_3Zt5IvYN>w~->R)5>2X`mrqPpys}Mi4 zG7Z!p;^%ts!+9BgmaJZKot~HD=YighQG@+o|=CzBxEYn z>9<+>#Iuzj^)5rU8ft)VO?q%vCeBzda$X^?KXcFIFHNQ|@M+CCb(B`0U;g~^7x*_B z7{nXxGTS==(1fI7bn6T zb8B^D@)~>19PAj$iRvu>hUTYFvc6Aq)J%PY_p{1TRI-7Jf6E>+S!2KI);V3wS4c19 z99}oro$IsRjCUk3my@y{zBa{9arTC2j?lHn1MwW_b%E8pk}LYDcN2Uf#}brJVlUHp zuM5c03}er-9%93cbuZvEbahG2(|7Pm6*EDz%TFX7TXq?j)3m%n*(9hhn$eG7ax*T}; z&YVbp%aO;fb*6Xko7lRAPtj7EIg6Ib>(vS zrJG3(+_Y*_M!LuxJIC?7*{!uYpCes~xqB$OFCVY&hu<1@@lf@_G24lB)bTP@Ex6eD z$E@F?O&(!^F_AZ{LqzOqNH`4!LU!yfF}8n5Q2ZR=lhIpE4Wwsbxr{GDUrKjZ&r z_`mpj;8**~;s5a4z<(mT8f_{zCCS=qr{;3aBcr;m_$+j$SoY82!$giSv!Sz(6DKl^ z-lP}<@w{uqh=a$i;zZ?>Q7+f|pun#Wp1Xw~edgi^!g$ml?+N#B8Q*uKFqNH@uP>L5 zOKv?!GX>~QeaDQ~lLCgm9Q46Fx}SL^V*=t{cDwJ(p4ugy(PYsB3ii*MGp-%*6=LGo zvGxs}JG+W`FyJSi-fipP;a;}O@~t^H^ZXX*P&6KWdpCSZxKJI;UqdQaz81U;d}kjQ z9kx-&>!(b>YnZRQ_NI*T6m+phI>Nu#F|FdEM0(ikV&yD8?A!3k%TAI#Jj=9qB6A%{ z88TfNbDy`SigngLIX=6HwOL7AEjH3Hk5=jVZ$`F1t-6#0I_>%yMe_0JyqHE|K!TdV#22ssw~s_X|N9Yxp3ZFYnl@4CzYUd$m{bp3UzZet(*fy$0K8#q*2@cdq;t9(Z_?mKtdBlJJCX|ivm z&3o^>efe1*>)iUW53Sg0yp>z00Q-vF>$g9YpgocUC+sKsPc~`vpqB;D*(MpTEtUM* z#*d6R9V_E~E_X*Lr+V2O_gncb;J1+9B7S&Ivec9PLWN|C>{05%W{Zq63_m+i zu>pH(0h;rI>nxaXahH1-1NXx}#FKxH&r0LB+;1M*6VI~Whi2*-GwM&tjHffNY3)fw zGv&ufK0IdsV-{hax%e=#4$cRwIRG1^d}P4t#s)A5mXA(_kD~v-HL`uMk@Xaw@=cL{ zO3!3-`!4;?J3aWNvCqkucFbPrV5QBLv8MWuQon3R(h-j0*vr+0gV;VSKxysaVDXvt zFDbTW0DU0c?GRw@V*ZJU-vkI}cKR_7VIeEAi235hV9_k5OWv7u(tGG78>SX@@442^;=)Ea6jJ{Oh0n)sNc3%s6MrQ z`xNCr39Rai`Yf!w+1@a&&Z4VxY=7Ltn2P%2G1h{pKUS3b<6+j+ME&u#5C=V9=NR<| z=cE0x0eHsu$KUY%Ev?8N*d9N^Sbet}%k_Ebp|g(|GlH*L_`4q+Mq?50DLwESzXSYU zAMiR3+EYvX<{)bTenokeYvA5VC49e^Z=8t?-1uv~e_`S8f$8MZvkQ1uY-P_+!=7dM z=eiD~2hm>H_%8RZ9*|$|R(P+*jvI?zYgy}`wX2Xvyc%pyWEr}LXLHQaCp>Q_xnn}S zd*EF-XHitq(FEf|xPPaEg?_~+b~)?HRPVbPFY`E`!}0wb-^1||ju9Q3{L_g!D+UvD zS3HwAcg3@bNz~D3{*GAb_wKfgcgfJLwl&i~xc;S&U^hD#-{wa-=X-hL+sF7m<@fwR z>Dm8f?aBac1}Ud{4P7n{LjH2aRfy+b#4%c@^*S-Qu@cT+<-D?VzK`=!I6H_B<66Gf zxkq9~xuMTwjQk(hr(W?To~dtkCBrq7vcEmgx$rVnR*w%)8Z5gu@Q)|Co?QCo6P#C- z&bM$LFP-;uZcFEVoJVWQ{*&`W>Hd#7uPB}WyDRg4HzxkoonPwC|AlkGdG9{@9iBf2 zIy{+qN^pLYXH!b=Kf*cpPWUJN%21E^zR$e%*e};_-v~a$FA9v|O2$rq={l})glw(v zMfRDpXU`g*X`YIn`Qxr90wP*B+6Ax4@*VzMo`Pohu>9cK>xs4BZhYaB8`_CX=xDku zkEpvhQRUoo`eRKP^QhdTnwz!fACgwJA$CqUbnrIMGQXHe*Oq(?Y>N38tan430kHkc zc$h3>XabmA9szjhGS)pzLmrLtfoZ-C*LcFUfJytRPOJ6~dY#0l!AsQEyH?=Cdm}|m zu*be5#0WA?R3k(G4bMDe-Ny`h6u4#~jmzTm>I+@)a@|a{Xfl8*@XrXKI#Q9O8u^dpeBc zwtA1a>U)7pFoZkCNEDws@2M49Q$fYW7b)wV9jCqQ zWp{QwzX?1=cr`T*eNW=4;;JvnkL7)<_Br1i9Z>$K@g?5j>_~zY-9hV^#Us9tOk2rVS<5<> zmC8+C6|NIjj>o$x*HxnR>!9Z(v>w@b40GF}lNYTx4Zr=>Cttln_8!rg*8g7WXy4FB z%<)sn@*rH5Xg_|SPy^l>8z!my-I67scQ5PNX7XJ}^lvI3ys265bbU1XOY*_aktyu*oH~%PyiD()>wWDe0KP|2Gj`*IwxnK!?0!IdZ z`U~RY9%HUW!pytx+pam~ZC-Nn64zGIqHNaD7>MeP=>OPtNc+ydNSjZDlZ;>mrbX}t zefRUgL%d7REXiTqk1vmBVqOit0pTe_r+xmW+bRsP8;n=hk*9)n;O4f95I5L5!MkuH zI7N5LIZGcbk9FK^J?qVp{v@6ySrA$&ex9Rnn+nz^9?`v0{|FA*NL6<#SW_V%?%UyK z*~!aB@$+@n!=LQWim?dwmR;D6c9XM6yp}ceth*L(6)j3GYKIQ*6CDCufibaMb54l{ zdq??go#VA%ZYQPEBRcc2;iM0n3ay>WIzH>WnA;5a z%pjkI_|zC4%Ugf<)bYIaRPk0Dt~)kfqFCGJnJ3PBV#QD6KXv@8obSs2C>kYx!qMn- z^<#-fcbDmqia8PQeRbrfZ4vKPY)3?QsRa~L?;A4ipmdK615nTCX$f3N$v6(KuE1oHSX_Fhpchlm{b*5rT+^n1r zuWj&p-Yq#L;Hkugsh5OIA(DS?fSHTS+sC&e$)`M&^$dSt{^;KtHNvPsG>rFJWB z^gHI*nyw#_6Havx{4(6z?T+DaubgdMODFm~*H>_S6MgmD2SQugp4`iE;dF0qdtA0n zp7dHHQ`DDKjjM_*@M0N?iLS3Ub*Tua_4k4^PzmSPj^kX%%m4?}Em~N6LATV%o<4IsJz3I~ir1{9omdmH*@HA#(it zzx9Q8_rA0J?zZz^^zx`j-^< z5?~8cY>0RTD*_DvuB_)=bJLr|)}@KLm_!|ym(iMh9OCDapUdTF)%^lFCUq>wgZ2#n zr^63y7a!NNttTk+peu8!k?%?LCmCAhKL}ntVEZZ8<$OW@Gx^PY@V}Y9KYIZC9_8!R zAMgwDnB9E)#xguc{$c4mVT^p}KU5rQs@f~Ollk>|;x*FKyfxSxpM5{NMH+nlnWO2t zJn>TaZsluXWII2fmv?voABrI;_u*(hi)CxA_J|mBADEs(w=+B|zprxIJ7$aYKAx%V zf<@mdFQ+p9Ng4Zl%4q)uzf?wbsQ#BH7}Mo6Cj5$biN1s*jcp%Ws&v#eyev!KY5dMN zp^eT;9-(|k>G|9e9Zmul*8fa=5PAeVC8tfWEg>I{;BTFo#*Y(Are~z*rGw_!GYJ=SG)R2o_HFP~ zvkdzuusEL&G?X^!-ZXYX#R-?gqIqd+h4!GYGtVZx9_9VU7V+$Y#|%EQXA+t(9(|cH zm?f`!_SuAJSI>0c@cd?;`S1tfO1NYes+J93d_Bs=KpeKq#UOYLJe(L3*0fz_T%Um( zC!2tap9>f8=@&{kDeu1?`n>#l{CNa}`b#jZ3u$KkA$Hwtz`SgX4a$co-$_b$F{0D9JvW?C!@D{kPWBw{Y z-}0e)UM7z%aFD#0ncH$H<1O{*6K0EDbqwUL$ z-N$Wn`#rWuTl$FG*^pab_2m zG1+)E#+K&Dg+t%&otBYpARoJky^6@I-!(JLRkTliKz@Cs`+PU&w^IIdxfr(S6m8M^ z#Bgu8TiGX$Nznc3z!~C{{r0QjT2Jv3&4nYZ+ue8yGvGy-hJuYT^Qe*SZAfkUFX-+S z>M!iB7x(LA$FM&LC*^VCk^_7rf8Yay8z≧m9ccUuNG^49ndk*u`kqUD3EMdk!}& z-Ys(}&p%&!uJL8KAB``~Yfe_chx-b8oa6${rHe;p1Ic9d#f`{SwZaeOwo^_t70LtN zJjjB4KI!}VkQElApEB#Z+{tO=1g%rn_|aUeu_M}2+*70nNMB#gIP{3Q`)kH=jQYDg z>@LU^AJg2ivrzLP$t+EUnh)sMC0hs2!Pmul-d$R|NWM#QiYDFu%Zzo|*{L;o4t#pi zW5g|Ew?}VH=4>k8qVGW~-po{9O9*nfmRe$Z~A3u7OfmRP$g2TgRGVrL-}XYi3J zU&z(%ahG2hJ5Ks;Y@_S`A$hT$Hxtt(ADfwB(vQ+M)5aJF7tvmXKIvrzLS2OLl4_%9qMar_oXQILyUL08n=SJisVe>!&`rbA5)){@|4Uy%S)!> zjMb%CaInv+(*iqS=dV@lhT)#i7<|6HmHYGIjSIlzI;&X7@4*k2!V8+% z<4ZI>ce0ni$(#EjC+FkuksWCmyovW2=oP+qHy);>;JA%z#lsglN?!4@0sYZz=i-;D zg|?nnE@9@axqH*Zaikd2=J)2G5)9>fUAasq+7~Ro;2_V$3FR#MMtLVCo1X@KqlX*W z8hmUHvNw1$>hiS1*&1|D*NUkQ{v^2RrbH}x9&J+|zZkXvgDx-oIbueUIAZdQxp(Ji zPIq-ucT}&-o2|NdSF~N}@;O@JEVOH+F34XH$exT{B1O&`Y#SF~*YFxLd1seM3l8?9 zsQ=o^n-aFPCv^&)E`o#DiK@E%V(6?H`!f4@JRQP@onmSx?~_+d&sB$PbX_I8uwYHp zz~5b4;q}4~c0aYvAUh~7JeF^^&i)AR^RSN?>==5kHB}|9IeI8xvlz*Vk*qI2-lv`j zbyL}*BwL>ke`k(ba~iV#26V{H8QZJ1K|b~@%Q~|dnh^xnL-}ovj-Y{b5Q9&~%_Zb! zmkd(DxX`ojQg@o88{_aq#S7{Bo7@lIO&1^GT(SgGR8cbGDB#gaKF%H#D|fT!7KG`Y zs(ktJ(moenR=DAI77ETn-&x@UZ%I(k?+oMfErU!zUQ2#Jo<(%Y#`z`qRq$hPvMjOs z*-89}FURHNWl!cuJbQKuzq$O*=64RiKQ)QqTw4AfDqKerl|l{j>5%tPV?I&!iFsF; zE3Wi{51Wshk6)=i{Dk?$mE-S4O)5X87^_a!wo~%0onFt#$X^Wwva49HO7$o&qUH=g zNSQOBt;02Ev0;eU|w_fZ~UDfr=-`c?jT`2UgeU!nXzQT|8Al|LT-hbaG5 z%72scKR&MfGTM7B?fnexm8|Fo4^#er%EJwVpBz{II?7*9`5P#|+?D@2<^O^5|4jM+ z7%d<5b2-h9IdAX^9%G-ijn8=LL=yW)l5v_Bp2QQ>_W9UvV}Wncdtx?-SpyxzNgWNT zoDV&z92vYcR}C%VC|ytWXueCpQ;1Oz*3_ zyl5oP$IK>wog3?%}zVx%((QiE@lKw;zexq#XJxCmG7=fxj_@qr}In3~RbrgWnbUAF^xX zlEuHo{DA-UIgfI$Qcm9-cI7;qVorc>xpME=mkM>`vJQ&kW1TLEPUGYi^qaB!!0e_D zhEgO^Tr%@iug3p%c$5bZV|`kAB&c{SpGU- zsw4Jt194`|Q$zbXR`TwJt>HTNL&(;xk_$o}qV>%~drD<4DwR1ft_*&?A<0XM2bBE1 zvl*$o%DXSLDb^Kb1JF0MCf51e=C#fdY=V(h^_{fN#Vu(4O9+rSR_d=_;#u838Oi(7vz5_90Ijwxl zW&C~A{$XP-Ml%Nf(8S$(ph|o<^6i;sYr1Rwwh?HXaqITt)-e{)UxEo*e+xNY?{xH||^xNE8UfM32_67?z@GxY_3^~xd z?0mk}240m9y?a{o)Fqva*r`7I0-|%>w&aR+(5}jKWtykj9;|HA%?4XD@+IlLuKt+m z?x)@v8&6A6N9?=g^_?0^F2V2VPu-A=^)9(Webdm9wW_OZ$c{OU?6Z;ns#tqp;}_mi zY4P=9BdP_@e@C2An&TYu6e(W+Go`h$UbfM#gOoi=@%!!UU*mb`A;6^gIBIh1lAgn_ zz=w-3wla>vWnJ)MT&a0R@OZmfh3qQGPDT0lSgwqTF1v?;iK3@4~nAJs-J5 zZ52NiFAZ9tyOO-U5Sry*0sjB2=*S~42W{+SjCWJU$?(V3tsCG_eWw0}8mkMH5P<#QKK^U;=ooRjPe=9I;P!YtxFcQ>^u|9&&RNlgm-c#0gLg0S zJ)`B$xzHn5#9cNXe9^Mk?WtXV+VyE*d{5M7q~oN%%@`SaP2+?d&%`_5=cVslVH$c? zpJ@Gyn_tmUBzq(n4>$Mw=9Ye@h^ZS+Ll)@KJicHFV}~{N^d_k(NgIkVAI zYW!2PErP|n%<-kF?5FwGXq$B&!J_&bne!FnFow>cuZWJco@`-!;fgWzDBAYwh?!1p zt7H6?(|5LvzJYo4-Kd=V&L8;x)$D1mF(Q7Z@9Udxji6hPhmFJw;TlsnANX(btE-Rd zgPnGKj&(nHmAIw7c2RDheN}S^WAP|7``j;IAvbR=G6K0GkOx%ff8rl_A7h=d?{wWW zb98a|_W z_?2AR<+%8-qoFNVF(}FlY%2G6D!;qtTp}L}%)jK}c5u(xLHx#eesti-8LmIlz>uOG zk|6ntk)D7v13&W|9Fj>wIP_f4(mWFk{Tc`0PIKUa8dlTvwOP}*+%6J*i|+askw2T( zLH~D=GY$L2pmH*NYg%^dx0o-M!Rr~pM*LoKvDdro3b$v?ZQr^=?|qSX61<~v<28E4 zTU4)s*YsU&8=)6c{+t%K@vAh4s@~p}o>9H!doeiw6yI0>O0TaTK`vtbhv1%hl=;wG zG@x%~I&Z-4=bLjnuD98TO0#e-F3V+2kbNMgKb=Vi}(oZbBZAG0G)g4UCW-ar9kD?9mOEVCxbLU2n`X z4|jIhbGq`xA$jJjeE-XQf7z;K7n5m=JQZ#H77v^PPAqfjzhVy(PJGR);6gZg0Jx?B zhrXk>RKKfn>I?vT+xIR3Y z?+MT9x9sEe#&_wrD(}h{hY$QN?3>Fq-mB=pJLq%82^{wk`lhNhKe$*y zZ0Lp@_tE^IIiaW37mw<}2Z+3rLjN-MPVV)z#>`S|t;<+H%iO7aH=W|y`libH6O<$0 z$sl#Q^%#Oh^f8^eB%+VVM{F3=nkzoSTDt~f`)02&#+Gb136A26_uq$RaTlN&oOkJbAx?b^g%Adn|oTJ8K`MaKYJ@;nk`eF=T7bD8LYqy8A>_WAS z>9j4hr*bhf7ule0W?#GP{93~n%-q=SH~Gm7*DW*q+Y>b#u8Q;Rb$nCb-i>Z}&cka9 zI?m2*WV#?fo88<=V!!9a|HSvA_G|5o@?RVje*+H1RM&zF;pk*=G3SWKwK1uiSl=VQ z1}^@X_Gmr^oyAwtP34zt!lNVI>?l0QZ)()|Zo_7uEZ9P5t7PuhT7trE&-@9o5aN&W z0k`EYu#|DKhIm%F%{1aydJZc_7O!=(c;xHl`^WwL-xIV?d7e|)RjMc~1!+QJc&0a;U_|H8-?_ zOX*_)b4!+S*T{Oa@$<`Gp2@!b&QV$Royf8wZ?6lw?E(66FPoC+`?bND@kP0J$B)e) zwWD+!eOKkwAJ0KgI^R|{&JUFKFF7Wk!+*iO)*OoN-aHb@>lPnkocUI?CcKK?mVx(v zVm>ANRU<#dv;E*=8@L!M;ev6-nAr{Ajb!YDN5eTydDsW&uWOlO)OX6u8v{T7Z{C-T z(SOQaB-;IiXjeKV-~3gnADfQrM=ZQe_%zU;Q#R%3cOUbuPu_6V`6g=@QoCQXuQ5hD z=}T9)SDQbFKKuap@H6!&4n$?G>mS+_e85I>eoL7gv=Dx0DnnW29NM<+R&UK}U@QuOR zoJw%~4f;>#hVzFx?>}k^ldyLSr!~N|m{=dyzCOG7C*Z*E+R=R&ovo@c4cTi*?^)iv zhxghkcX;IVXYpN7F1thfhcM!&N!Q)v_J2S|_%E;UD{`KACRO+^%7U$e_#@oH*)f<~ zE_)4GX^1&TZAOnA6b|;n%LLC2%!9gj9mk#cV0G{M(!J#zU*ewDmfqNkZweZ}mwq@A zuGBx5F+SCw!dHm5c~<$t>!HPcIWo1Rlq)>!zZCrz;xiR1$LDLgCVLz0{~2@dL*B0k zx{e-zzTO&8AAYg(kOc|K4K^rT#e$#4_vM}_8(+uM^3SQ~!LoX!Yp5>a#LKU?H*zi5 zmoj&Xj+Gx?Fe z`3Zg!bSAe(R5FTbYfEfevLJCsXLX`SWh&vHk{ek=>R0-`CVz55HicfE`N1+<{@mmz zC%j6pN9{<-9+F)U7cAL*^fKSPyYr)odpbXs_;TmR69*UrBO|u>9Qgpf8rv)1N?kym zX}^1aPO@w>@_k$UwcMh(+Nt(;AwwMc$wv}TgL{3W3)~8q(Av;5+|#ueTw8G`xMyuI zP80U4;#_^2$oAXkO6!*1oM8UZx>^^vO?zx{L=p|6|%KTnfF^o*l;R zi_d^vXJdM^G!Gp=_k{DU<^rF&R&kJ7=GrUBd9S&q5qPC53GO!A*13o}$IrJ1OY=%S z`=M^8Kj(qx4Fkq(9I&Q;0GsfDZ#J{d-j;z%^Y}o8DGtQp1Fy7KUbLq@(XhAO&e-2B zZ&*D0nl()Zd%?b|9>+ei4tku!7|t+m&*50laVp0r7}G&NZF_KSVGHLpviKVL6LaXy zt;qgf@S63zu`$WtR<-}C^`d*~E{f)mgCqm_Q}<>z_s7f@-idX`kU}_4<-6P~j=8tz zs%_vdTY}|fzL&kYY3ja<3+UGSt`ZMC$ofMwqbZp|Hy>tCxCovs^#sSk({aR3gb>8&& zX;1f8m_eOiwB@vC`m4;dI-j@cG{NST{v!LM>?>`W*Oz*v5lfjb(4T8__&T&F-%(Ts zWMPAk;qxo1-E+kmd|}1O?)EJP*Qb3w z<7K~5y8mt4oy*xS#?NiJ7V_tPhBf}n;USCc&7#qu)vj&7-rka%Z&&9Q+S}W2u&Z(l zut~ON?r86@Ut4?aB|B@QmYm>-p4P_rm7lj}N8uElVYbzJ^Q!osKgTpc75EifZH#Z| zyO#PRIO2TsWWK5IP3C)&uiv%m+DlFXwrX(WA?ujnW?Qx54%(M7lUA&C$CFmv&XJfR z?7(*)&DwR+Cr7QTjvBT5m$%c?KK$dw1WG^G!c^+=z}Q zTj~aEf_$Y!tazyWV?%d9p z+gEakc!AfM*PrA1E^?;5%DL8qdD$+zVJ4byu)+4xpIE*fk2KgcRL3^WBiPuapG0kz zO;*ng>!#i2{drx@p#DBeY^{crI( z3J%fpH2EG`%Wy8R33ln6zb-w`BCoBayy_ZeY-@b%$rTgBxfkF?TN6_lD~BkXrJm7u zFw5Kq9IF2&jxp$O&tA=qPm%)0_@tD=xb0ut|y2^ zc|0LMg!=k^#_hw2rs2zv)|!vx1`^-vTmRCB>1!|eS^OiwduKuW+5P^w$@7Wxs1K~m zVV$O}8vE&BOG4wHy*?8E`fSJpJ}CV9r8Ov42tgt;V%%1LZtQWA+#5suzGS@saXa8pY1sMms&$b(|@D<`h>L+79Ldx7Krf zsw@w<`u`I08efJ!_}nkaTT0!H_~3l_M9|#rkI2^lQO`SqZViM*-_+%snz6}nU-463 zH%sDpHhyi!r@;Ns;7fIU`#kWxB}bkk#+qOe4x@2~Z_@c|%ki>@K3BU`_IgLNWAlCJ zxyIaj+9_O2wEhK|^;Ge(g=-gH5%J717}hiRp;y&)Dlw18cYSQ*8={I~Lel-`NHQAxX$e@Ff_<>DC`X~y>1!dlU0 znd|ur7_qqlvp=s09lss6;J>p(t@H)}C zNjD{{E4|C~uCHriT#0X;H&Tfe#A5{Dw>7NqGQ?b&8MzN4$IZd+mXBa)1O^`%w!8UD zdXs!;)~y>Cj2_qG!Oxe?A;RBswf%64qMmEN$3BqIwe$UT$GSgFUW_?oX$ojcf0Igd zl`5wzudqYwa9$)PR{J4nossD5WJhD3%R8OJ9K6n~&G zBmabMZ2?N^Q-J$VQa6_tReGiuAI*>`A_i@v+qMq(|}f;;rR)ix3j&AHbVO)^s{s zga_%|?_@r2$$0seIjmKs9l0D-o~Dhn6M1vC%_lyZU@uxb&tl1LwH55a$JoafbgKNC z4VAr>7rp<~#Dx|41uc^2DwW@G@YdXd*jtG6cRqaQ#j*Sy&TkV`n_j=|R^+(AcCZhP zkG+tXC&7=eyi0vEN4(>DbR)9%CedZxcVt)epzm%5w82k$3fHS7I|gJyYVvyUB@cx- z3wcr8J*yZkUqSiRx<}pwt#OIUYORjOOrjw%&sJ6RDvv>eGVi2arrP#S>5LoJINIMm zGUa0OuQ$Y}7HTYO(k=Rk&8;H->rUFzZ5iuB-CEy^?skK8?!5R%d|$ApnB!ERMSsf#U$@r_R%Br2JL+LNq3x;{pEkM8Zy>H} zHNRC>axHHr`)HGRwD9vJ_htoglVZKHc+jlidMjGXl!}W zi~ms{KZP`QZ=NxkUU25djk6PRx2ndwOtyyZTnyhv(Af%nniJqqy&kl&-1U*#3lGD# zx`b!=PicqOGoSO-=&iy>RNtzcwLbWj9;G^O0iRPe=Mtluq`Yu53;5%?uiH51CV1Ei zZ`VUdm-D=vxy4iyb4-7D)YHN}SNBwtHtHu}#{OBO@hiO-tkb_?{gUks-|VKn9{nA@ zSE%_LeV2K8%Bm?>h-O5aX3d>fg!Jj=ltJ}x*tfKrK9NsLeXR2GZR?2F(&ZDD?@aTh z1y<=eRqT^`l44QmyH%xom4XEx={-87ptu9FD7bh!pK^@n;`Qh@KJC_hSC)98hfD7Y z|L)xfrxcKVpY?c0bQ03b^$w=3z+`EE3Z9Xmya#;<58vT_3flTgiB@#)o9;Zkm*X4E z`@LSe>C}Yw;-vD^WK$Mi8PnO8TWxC19m^}RS=_ny&MSz&iK*?vnfg*VjWIsd4_{Ng z-1E3rnSavt+x(4;pm#u{qDRrFlS5{TS7GB#+j+vDKO+Wz!q!i_;49DSyN(uEuYn&} z-wEeM;PyK1u%{iS@9_hAz^-u$G;R-xWBobH^=Ae;Yn~a)Yuv@)Rk5Ji!JL7r>Y(SH z$mDZbrxW3Mq8xtXWr)s^VF{(@Yk?MB$x&8*%k^__jQEM6LP>49k{L*UGPS38~-Hs08 zC06d#F%h1Z&Wm29_jtg*{TFW|kJ9&w zrxibwter*YA2ZK!&kwGK7ca77?ni*|90Qd#$mgaFDX^_&Y&qzs3!jA7kso`%^nSJQ z(vh=@d1ZDS@JzrDImEOK=zF35g`iE_wDwNz(b_xZ@Q$NnD~~ssM{Oe5Ywwr*7VNPP z(O%iA_vR8t_^qce65!$pexlGH;IWP^?qu35b5ylr;sutP(G#NW2tG&)EeyIVR~$g$1VLgViMhqcIRS#myABO|ZsthS2z9qF8I zyW1Bew8rh`_JxUbkh8b6w{fjD%(seF6`UY|T!}O6s`f>RJ@ol^4?ln{e1V;C-9s7v zG)BE2hB&N1R_iNS)bUIx}Yg8{7UDOJxzXI={nn$JKtL{ zpz#%rE!n=t`%m4yGB~60yst_4{E%Q1jcL5ft{6M|fYS*LHiI4i zvHqo9@b~d$etYDB?XJ9Fc)LH1N#>LZ`%dp^{2iy$mQ~1e51mGJXkFB~zZz@f5S{jD z>_N{O3tmabdG>!DeWJNWxdx4Ce#|pVsvFP4=ZTCvefR9Mo08|Sj#)9I@oMkJRd&^! zX0@@>Kh==qubMuQ9xIzC`WLb+`Wox9TY%wAbZ6;Vim4Y|mu+RueQ?Qy&zjt`ODBBx zXYSei-5xS!tv&9v8vV6~_Lb|eYV%^`2F2w^I*LzQpqK&`6qC|XD$8^f+HEG#JqkPg5WOA zt<}{{!%u3z1Utn zXM>}IFb9fk8R{p=fa)h5m1CgX1|++m@(hf>r@F@9Q!W(goXS7oV zuTyWgw_gRvI-%Yib>u|vuLcjRXvZJ^K6EV@O7@G%W$$YJgKW0aUxj1kpOT$Y^N3+i zX&loBeZ%UTr*pEQX*@mMIS78iu#0)ry+(YSSf_ewyd8tnkrA7@7f`0rHqO}t+NajA%-Q;ki0F8C~`^RMrXk&U-UgN@Db9NK z+3#bH>ewB$Am1}TWNc;*HQ`IYBq=|*H#^>KX2;#0Wa2OQ&Aa^u?=s80FZ)z2K1@UG ziz{2>cN6>DTgzC2x{ItE?p6%&4V05zLhyW&IV~D{Ptj*Sy0K*Xul9R8PZ4a$h_lbW zI4Suff>H3*n&3vkCf*j>^2zC1MnnCX{?1KvHmy<_joU8l(i*4bWj4TX#cMU*Ri|SA zvMr2v_xFALf{o&(NTOwvC|PwH#`7ld8$YAQOij!CH&(@ zK_nG!*YVwQ{6^mkzqM}X_r`rI!oTXw0#j{O*44@6==u~q7Qf*5+@z6I z8r_;c?}@QyAgKsKPy*@!o?5H0UbH{IBACe#CEztcBD{?|7g=}!2KfIEbJWXjKx zon9R1`ov2EkEect?f7YAszLTQea6m~zR`vxL|%HyfgVoU6l=mH+w5ZQ_&Pq9b{1sG z_wqB=!nY&CJ&T{?SSzzTR-o^M_V*EAHci>!Wz#GouS>?0u3j$7$!=Z8949>#oafb# zY6JFJC6<1nfHHiSY@+9belID8pEYO{0?us*)C4zmn zg1M`b@lwTDnM7>iNyHnz=kfL1cf(tUb5+JxRVM9>L~?Jg!X%n(zG7ay+mh4n754qY z9!FfzNv>}9jS1>k-4|_Mzg;-N)?j2mSKVF>a8Ey}dl&lEzFflW$yLfzt%ZZ6PEIT~?sOu(V=cT;+7WafFm9K|pnERfd1YBv_8pa%z=_Dg(I9Wfc zZ$IxUrl#oVm%6t1(?c?ab}-EiH(@1c8%H-4@)_Ug2w&GwTWUm5<&Vc9d9?Z}0~ zt+S^&BuDYD(fD$>WsE7t`T%yA!cRPN26Q3({9VbfJu5s8^?eo_6gU&#KmTVTzo$}X zlh!zIzt^o<99+opUC8XRIq97d=t%L*45qxwsDH*j>q;K>ym|67$&U>Thy`7PX~xY@ z@G0!eF~))GMcz|C{Tug=iw!Hq*?t_q{EN(EtVCNQi|((83+2kVb?is+x72xF<}h)y zx&5{eJQq5#Zm4~xYp|W;A9372u-}f9#+X~XBK|iO+wcrC?-2a;EMTbg(#0GQfjlQq>X+P`zl|P7%F7{FW&nR;f zWh9p(6XlVa3glZD+RykC-0|5?w<-RBvcik(>a$&Yj7dWi-znYyKKCnW&pT*Oin{c! z|C?Kq$Q?c2bno5Wp z>*&vKc!i;eH$>mRoATnneas)t#Qdk2Zx2vkJLf*-#n+uo-OauQeNEQ%HL|t|YIoPa z;rfu3tR7zfj_cprmeK1YTpxzMiI8UQ_c}Po|DyeLDkbMuvd=PoE_(Bt!n~~}PpmBW zJl4}DsxBoKep51@CRYVk)Ju`&{NPvCZ+PFS%-sd)h4waY%~zCTnmSaMiwU7F{18Jv z&%W#E$~TAco5ZKmPx&3}Q%XJ57prPa#;VBols3smbU=@~y((yfx_iLiVe+Yd8C0XL^Sg?}k z;&V(fUe2K%2jD4Z|A_re7(06BtWqCGw6A^<{dcKvIDU;|wtrVV=-(Z0?jMdD=yDi7 z`bQ<&e1ZD*aIO3ADBXLOd#@fHwtJ7Jnakj#$Umn5Lplh{om47Uq+A+$(7Orl)iO4Q z;eFDfD;OW5{Q_m=3)I-3#r03P7Tg~9B)cq!XMUd}-Vc1WzDXm)JVae#`=J4BDwci_ zU4EMO`|xUrq-gnOOgN`6D=WQTGS)Dk{nBbpo#yz%$U*Vopr!xwn!Cwx&huA@!;PC) znE&E44qj!a{_?69h?f^UFDah3ji!vC+aSZAUmD*%C3v^-Tz&I%U?_)8JW2c6iO0x> zx|edXD)v+c=2-r){W#B{pyVpi8T28X+(@0`2RHHT06a|hTV4zKuur?b2TXb{+F3>! zy|aXO4#P*)<{c|A*Ou-tk563^a=X(c${}}DXl3zLs?Kyp^FmxBs#PdGLH_!ej=Io;n5JxYZ*`ft! zzrmMxG0(L2T{P#uU!uEaeP8fRXHBbRd;=aZ`uB&TINpe(G4BBJxpxcE7X!-!yxNvkLtf> zE*G79(8C^RsTv+o4^GqIR<=*s3?wTl&**e)mE|@B*?aySdS6Pv8}N`r{}KJyGVe%^ z?`Q5mQC)HBDjzfC@-Rz}`sP!NndhLHaZPiV{}cSZdDsHC){Pn3;4_wE=HG$m?eG}I zKdceoMrW2RqcPn;{8W}XCz2J$>je?4>NmZUThHtXZA<4c9l44#p$XmRs+djqMb){Q zxF5A&IZ2f7at3;`p4SCmvfebmC^)l6Sk3gw>_Epz;9_u6*r#uJ{(%W`BN)o_59&Sn zKJ>23Ll^|sqt6Ypy<{)tDjmz)6(uFLJUd-1Dx=l0l}p|3sk5fJtK4R(Y5xmRp0bSJwQI(*OHVlQ|_dKxhp z^5tvYuK4zQw@AK&W@YatMg<_qrR61u?Y_=ho}bTik9yX@7xq!V^U3cvFju6l29w-N zuFDmQyFz}Iy+<)_lBL#p4aElR11a?bdje>$RoMyNhraO;ef9ftH4f9RHT35nnhQ?& z$Y{?paOKskarpX*{Yq(nKYV)ldSs`o1y1%w!AIvAqC|VPu@Aju;Cf(t1;6{#TubLv zeajh(S#aD)UN`BV--B1}DZ}d?%72r*FT(o>zQ0F!uD0v^>*8x~^XKe$%x%&Bc%rN0 z$4uYwHaBMK^99DtS@=m$ukq)Jw<2OJzeVzB+H2#V8&7@Yt(-L7w8io;ALc)|rp0)l zij#X#KCdv>Bm4(Egfhvn-AqnA)h!$BWzd&$w0j-5U}p{a?pS(DI~&wm;&!@dXE$_% zZ3cZg-W_8+)WHMO+*93_*q1nQ3$>K9jFUL?{6pxGF6T!Xo$UwIeayYWuMJX^OWOyP zr!UCZL!CbQp6aW!=ORxO$b+`)xzLxW7}Rq=nPEK7VoZwOOz}F&IMbRtfA+6`SX^s3 zhKPgwAJCcbG6|W(O7HOs1AlA(cFv>pbu8bHP!e9N?^SmKpH0HMcX#FC>#eR=9lpUv z{4P44kVF`d3tKhb>dccRA6gXi)sow3ques^IoTGwW%C*Pm)&tAvQ8KWN31+{o%&!W zJRzLV`*c-Uk`6vDKaEku@1oxun z+WYD%uxyL9Q88Sly&i<<=>B<|K|yw z{~`S!jlC>;p{xdOuIG%tCw^U;3*2*fk@j%$iSzXPT<(&#SkuO2d^&M^u`rj6;&?Rv zSk%B;gdIb~>JX=sGWX-73GZPq=K1HaKVY|X@y^jV>D?Y;padzgApR z8F)H<+cx~Z_C@|-A6a1`^e&oHUh}^ldY~k8gzFbR%NW%hpz-Ns3-BRXLw?B2bW@!F zmfF6j^CsG^zRPC!+OEp^2OG2Kfmw75beM2|&jt2u`crH5K0#TqmrT)yxjLtx<`Qc$ zld&v5-H`V38n4WM=sfc^ipmJqunf8eWytl4E_CdYu%3&ui%uJx@?h z@BatS#W!Q@EjZW7CgdWa@Aks`jp)hS-)SoMb(+-P&XMW0`C5DzPth-p4*uie7R;(w z@jc~mN8c6vdj7yTxTEKSU(dh%d*Hsa1UCY~b6H@~K9@7~F6*P9v!dkmTPgFu;gf@0 zD}G3_Kohy?8M9b?m2w&0^N3-SO!~>6(!b~n=n8{5$9I*xMQeW0 z0jTTJ7xk`Jn!7cJhx4~&wlw{^S^34Ydu*7i6RM5=8g5M{W^7J+O{lt}(ir%A6t*7WZ#Y@gF)jj$?@}r?0_*e}Y&BR)-Icq4OK zJ$1dAFvUl{cj7f8it~q|jM=L}YeEuU(|P`*rqBQ!JSXRI<9P`GMZd73L z;)R_XxQ@tn^qBWp`=8pjLpioC@(KygaU|ru+q^<0=ah5&nTa|t*(xjDs6}$%x`XS` zFBDgw#ReQbYekmQv*=oO_44cdxa-f3yS{PUb?3P272~c~j=R2T+;w&wJi)l@=5g08 zrs4-J7E?qOcDMn*~c)#pL90xH(B_@zM}TW7;j#Xi)q}+Ul)zv2v1%R#B^U} zg;(ukEZh3A=Pe`?9g9oW#ZGW9TnAf@b1%SHd)&L9MYq23xcid1j(u~*anHSAW^%-tX7r&8DM)S3NETV78+3aP2{=D1PSJ$udSwG&I zd&ACwC#VhnJdd0nzqDSHm(G$GiZx91!Fv#~){)E9_iwcy@4;JvYe4&kKV1`9X91f}kaSVUUYo zM4x)zd+@Wbd#=zbzK?zVXP3CS)fso@kPD=yj2|=&kt3h0rhY4KIs+x&IP6 zSOwn|AO9I;cM$J7tTiPaH`oGmYdv;e#UCuqb^D5Q1S}=d>>*bLN#ymsQ@p$6M$!`p`S%7e{Jb zUOjSzdFj>6<1glX`gEDi5&v@lxHh$}^kth^?RO8aQcMsw3Y{yr%PQtB-|5JE=-*-b zc`yC;s@=Cywvyj(8&a;dy1<%0g0>F8XCzzg=lfc>`bqo^Ua&hZfAb#n>?5pc8K&=q zUrXB(Me;w92ki~vqfdMmd~{!$Ok7Fc8RF=K@8`KU+`1_){3`FsxqjD>Wu7a%qp;$& zPHalcy!3b)mRt}3M>B9JcXbX~ua)o5=i3W_Wg+uP8}rH4_`4V3`)QED+hkkMHO;N( zo0irKOl#{!^mI6$G&Wm-V-E9=Y^e$MvU>xVehEzMpU{i^(<>Ref&D;z_W7vAhO&Sd zMbVz(f0%cOGxUoMQ`t|i^jx|Bn~?S9vKMIsb=L7t7X8atS;ns9%<^Xooo&xAE}CZZ zS5J#~v$lh{A66G;uVx&E?=LRJf4HnHGRUVM_9OhM&*>e* zx~Q-YXtL~mzlq!`$T&oecKb6fPR3p_Nn5q(su*hs4DZV(2TrvgH?b@S>?E$mgTD-H z8uw>Z*}V4AiwDQXUM2pZD#qV1F8sGv81o)%=x?!yxpX>>A&no6r&pliSE1p*hCl6k z1Kq5%%Lbj@wz>0W+tPW9-PwA;zJcE&3$Obj16%yA6@J&xy+-b7PD?1i6M3d8*o^7R z^wAm6;V|&j;HU7=3u^J_sSh<@tN$Wd>=nSd z7dX2*v$nf4us3%$+gmzYY!z^n-;X=E;EBMslYFw{adRK|P}@EDr0^ho2ru8GT?ZT< z?)Qa}vN$)*E*#u)!H1ZwJb=2P6nkOE_x1=>EiASM2D9&zc3dC&p;?YrXbB|iUK1#Kjr{e34#Nmp!-=;o#6kAe5A^GD{ zAINSfd(x-r12^BQ-QfA{`XcIs&aytp>HLSl2kzDPA>Qe4^v03TF*d6b^AcAk(gpA? zd^)_tV}y4kk9ih7Bhj=hv#IrdKg4a;;r8wDoBbv;9d%cEux5l|>TJ;X&?|Tj0pvCcfEAEwzdwoxP;tWr~qjt5%Oe1w` zJh=4(jES#uJq*3R9Xy*U6SeJyqhZ^=Sk|`B{}18a_Pb+zO7OB4-~>E1Mjphme5Uq3 z_TnX9-(+aA_BPtVG4?2S`f=r6{T6bF;1=IuE)d=I9-*!9VXa zm;EQbNi^7%yU6$f@(1!rfIQNiI}>^5eB_-AjNv=8kp~)(<_VG8Xb?s&F463&5Z2z*&_+~;!foMT`q5i@_{Js;L|UK zHuOCE!EC0z-@!k;g!6Q;Jzl8nJIKq$4MXd zd}K7)z-5<&HjCzBTZnwM39e(vE39*V_G{=1DeAjruW!E6YR&zvp1BXY%Q9!YcfZ?@ zv<)f1#g$@6hB+N?PmjJE9cBCRvOAG;Xk&IazhSp#U$*HibnY|Ptc9n|W=uwFsI=$E zf+fUTVF!sJ+r1yy{OW5um(cIDAo-V?7i8DYNq+MAdHjsknyS`G-3PlYGv|DC7y|HqCL0w+6@g;|r0o3Cvh(+ko_l;-`@VmloI@`3b5UH#WmGt z9vT^Y-DXVpZetFTtE>wglNY7awO=sgw7%~cE?=hZVU>?{-zdDkDi|jEgT4+EBPy8H zk7thQNA{##46U5EWCAA;~DSnkGmS;;=?NT`?{qD z&2&~2m)Zg5v|kA}f7#hQ+HnW#8|gn{$|i^LYDM*__6t`V4SIrjvf8=B?r?n<^%Fjs zPOYK$>2t+gsV)=T?$$R#%f%fh?Qnfj?gNppQ9MMpRq-+MP9?~1mAIDq(+f}&8PDWZ zaO?Oc17{EXr;o8Ao+KM+J+%7mK77lS!NG_9?%{Tx$yd`g!r~EljC2z5lwD;!rJM}* zmc?fu^I6uL4djyA#P_yLG6##$;p2?U&66HHm$=+yh?5v{>)%iE@Hr1znEw_Dp{Y(4BXSn{a zDeGQnI$UdNIj226z1TCz_v6O+;%1&YQi^{tCWa&6pu3bm&Rw=sUdoBs^Vl4O{Kj&XnYE@5#=SOqf5ZqQ^_lvfgFe zk;&?FuiFdS58LzG58=Ci&EaDoeKwQ!Z%k~gSDq2c&5CamZr-G>*4IQ62W=hgrOa8< zlc1R7kNECulzF}SwYy&fcZb`pIfM^?F}zIrU%V}4(7AiBUNRi-qRv$ChF!SikZoJC zE1sHR@=JKfN1p#O`z4h3mq$PSJ2-Ux;brnsf2c2R;G1@a?cKF_maz@--dPQe=e^Ea zciVP>jRo~CN4agQFg4^eZ)igvR_@kZhTMIBN)Ewu$=h|Nt(^Y3&bi)&1DW6qdo}nb zBS~H{7Oyd%-2yC!+L=PAHW3 zzPOwiH{wz%?F+3b`t%mc5!aVHWOpq7l3nMUVefE?IdYXfL?4HAXb1^ichJ!xzUco= z-+y+j#uqrUkvGI8M0+WKLzw2^4>D}bPa8F{fs_Oe1P&v$!0bQK3XW7!<@_q z|NArWCjO_R_@8vn-O!BU)-+D{m*V3!r=958GW;*gJCS+Flj!9eOazm7T{U(WXGdZD zDNf~@Y1eeh=JAaCUJ5!}%y=b-F1dSsuW``JUymFREB3#u|9ZjxxZ`b#=^_lQx}#I; zx1zT0q7S2Q=^I<8ZS54@|3GaDRQHosb^M#-eV1a$6Ayep`&Wx!n&J)BH*~gBpT?=i z>nq<{|I&2#%qtQU?8bAB=h0Z+$@72UIan^P;P_%|ow?tuAMm_01_WOV{dx#mybwA$ zBUjJb{0o4Ac`=mbdTw-m=@oxXUqTg~N6-`GyJ|G=+FhSJV9#I-%71lX`vvfydN&Sh z@F9Pk?|NQczJqqXM&H(f*VnD>jrbOwUc7+uWjf;KGU8+$?ZB_*!}ng#`R2eh)2lWZ zbk6MIw4<|cQK!ni$~YCi-vXwN>KoP?VvOcj&+qhRdY!)mKJvWT|K=#(aw>hS{*{eN z@`>zI+A~-E`6XoU#g5m+ir37%23|w8m5VzWH_oP2U)7KwL2vFqwg38tfP5&tv;FAE zkYr5{+pFq37dT{(bNlcjw=#;>EM;%r5#qg-dw#`R_*RLX{UCVMdp>X|_TUY^Wvf!X zsTrxf_(h7iGx2xHp2CrMvTT3i`w94c3OqbTT*<4n>2>H`d_+9`jSN1Mxx|*kCmtN| z>>JhCl;}gBcl2%r?`iz5e=OwbA^t-9s_GD5dWG-23cezmxdJ?EZvO95pLYSTo_(l< zf6>hcIsYv0G@7sNR{qrcu@QV9IvD!ru-~sF{=&uUW<}FajnXxYo&M3iCHxj!#eVn0 zw;WEj9)oN3o0mV;#^4RN9DQI=c=qYX0(w*Et7J?9^I~X0a+S}V$z2fz*= zL7oriA?3I%pM&O?_Da_LL*aZE_IAk=n!gs5=*H*!InK%XY&CAE^MrpcK8|@ru@Nos zAH_xl(3SQWRD6VBdlJ~^=W5LbjI&yJyX-26A@F(4@q26?G;s8riUs@qHuSx;TYWHT zvSN7U$H%@h)9bATYof0wkvG3cOcMa-iLV&a^}cC-uNU;iw;)?w0$=?pI45BmGo$a` zE9|Q?TUw1-!d&y`JU`0VZDySKY z`OsdmHDfJnDl&}a298x6MNdDoKkF17iFf@NI;rRUqP^?4pNh=$P>CmP&^*9={3c^l zb8`!8Qufo{a-Q@$^LofTptos5ojzO7dhiooM3y5TeD$`@I_fRoFIsUmvG2~xJXrcp zAK%$azgpI3{FLJ}3ur6-A^7USq4=M0D;cU1dBhZ>?a5Hq~XU~VO&xEd_`BvXN)rwpcq@kDE_`Y1qq|ghV29BDQciU%q=NWJu z3sP}E_$#}GF%s5Y7Z?3rNFNQ^p}Q~OxXo_6`~S6fHsDoNXTIP2oPClYQ6Z(4cC_6m z2@yu1V5KUT>IsP-%&0Jcqs-WHc5)674M~~=n=>~`qOH>Ev^d2XZE1@io$J((+G#u2 z)(-*&C5oe{s2$sa1;x+GwDU}-EtvcJ?|pW13}BsSo<4W(bKmpi&E9+Mwb#dgy=$#^ zz3W|TozC@H@7Z;;xjyGTx9)#%ecpS1-5jp)*1At{rCipX!IiRFSDSZS%IHSLt9I{L z%EzNTv+!dX*JD`oGxebFKDzxRZw_-4k8O9o?b{RH2LHm=)K1=)asP`Ov!}xcd>e=&@Lv})T-H*xBIgC*@ zcpKLJ3-{+TcA3Yxg}#5?3p^{|eO}+XPv)5m=6MQvexz7Om8a5r`XTZvTVBo}CQ!|m@}SJYvR-v709kLo`L56O12N7bIU8e^W$7in3`E9_R6#PCMbAt_pWMwc}1-I3DbKRebnptJA*ZMO=Fuv9Y|PDlppvr);;+pnCrdD zq#c|~^-VM35f{B~tZ#a+_^O`7_(t~;zR~?TuI&0obV{s8Esm{X9+2!Ud}FB}B;-QS|y9PVExI)huww_c>SU*D)tRsXa%w~f8%o=;sn5Ph3Pzjjv~ z26iQGF`vIi{zy{ZpL{~;+J4ym;iYF+-25N4KYXeFcCbu)!>^}bN(2v=sh^zjE#y`9 zfmc6y@BzXPw!TBBJC5>L=v=u+{io&`rO%b$+4xm_Pm;F#N%MBxlz!#wk0?LsbzSy( ze>dH($||~4-UV-`(m(+_jiBrjw9RZq8ks#Ii-ES%1k^V9Nz{<;5fvVSG;l#`4kq~+iNs` zhjV?j!K!cK>*QLuN?2x*IRoSZcN{Xo%p|rpwS`orb8ahR%|)c;1L$BUwle1E=<}S8 zHJ&?;K6obUzc%cWcBG~bjQc3p zG05IqkdqT(`X({Qc%PS;iCxh6Nrlb0YaDsUP?~n_e)`h~ynpUZd-`U3Z*_Qmy!Xy> z$JzL}<2(R82tD*TE89J1%^EL<98yo&q$*RF2)i}QYTZ6$>n!7P&1^YX5;K`@9y6(+IDFFbQ}8ZzbF%kEXOa`H{K$S;=YE#uQrJHy-EX1u@jjTm0ek8j zzEv!%ho~Fz7*lIpG``f{icY}33x)q6UyMv?n_R|wZ&2secKEDA`XO@W9xz~U^@4Lc zwgccoJ{X6}X4Lnj6C3zlo%=TRZ1pv(&vw=fkne4t#su-&0P#v3x8jY)xZ)Koz|r+< zJ~)rQ|1$XDGmKq&&>3n@z-28Tdtz5@(LT1E=i_uBZSdTbbG$9c6uI0D-sP>=rZOA9-kPCm&RebL ztei>iUA=R|>)pNA!4uzr7uG{xgT4+=kcTxDq=5#U{Q~@{MNGl54%{`5ARWB2OqKS{yYTmBY&B@;6Z3_7)F(`lcbFXuPmcbXx!RQO5#Tk$8NqZNgpSz*R zbMI&)B%i^X?!>4})!(XJsH3fL(te?p{VbZmHZJG5t&mK+W@r+9+pX-iaSL=^`FiTU zljV$R>bKLg8GXhL(9O_|@b5bGQ(r{aLV1C`%Q@Bw_+YpU!ZNx3aVPs#{I91xqB3!* zOR9%i))E(9E$RqN@Gkb*`(mqQ@iq4n#E%T^R9aLRZKi91CE3q5U{3(S+VQ5S* zei<2~Uz&TYOm3Iu&@zVaOWzfFlJROe`daym!l-t2M#XS@Alry6{Lb1j2fww96K}z2 zsOKO&QbVY$Bhy)w(b=o%LH1A#*D>#d-=@R+(iJLPv|@~TvffMJDNH^`x@#EogzJ8# zOW08!&Y!Da+f92`jZE-G)<;REQ@xVA&K{Nfnxgy5*f(w^{QZ2d_ocdy2fAZaZPx3d`T>)5vKBV4Tys|l3+#NcP>_iiOWaz9*tm`^w)KR-riTAH7~ zD2A^yZPgD5H>D}Y?tLM4HSWGq@qYGQ;zfsXNWAwK?E0~jCLSuWA=ph4mFfr0-jwC&nCIf z=ZeBH34dJJsZa~ z?yq*oY+~%Tb4zirhG*&XR8KS?q_I!fmjye@o<)!L4067+=IOfGKiIhIsh5$d?uzyY zeR>&vr_-~Cq8pZB^Am#qskS}BrJD44ZZ$TLQ|ZSif=}jU=AD|EZ{a))^qKI!<7%Ex zeX;UgNg6!(>`M>J<|4AWR`{uw<=!i;%e-6Qt;7+^fhEyl`P_sbw|IXe_gV*E&3X>$ z>#9ftjoxm>(ZSeIagQTj?VI`q#tM5$uXOpc@sLed=4EUuiQ8*gM*19dz?+hqzti4{ z9fbEL_o-rBf5kn1oDfs?D!m_)M8U z?(!?$pt~#?^pq9A`%TJ1IvmL#KfUi8hm3Qzzngemw$z>XM0TTe5aGU_lY;16ZS|R7 z$h*u%{A=&O=CaA-J>=n3W|sD|xi-Han-}t#eGNW(mHXE{-~VOre(-(`UjC&pnCuR& zNYxcy=XnczU<@GRyxQtiwdH8@#=O$2wsnP9TWICl=OIC*+4B^=kJ>ZMBMuyV+0(hg znrmF1f0H<53j!9{c}&JW=hMe#_e(}`(k?P?x{yA7OO^V~ee^q5SLF8BjHxMTEx1RR z(^;?1Su10lj5p|}opYu4)tW1%A%pEpwitgJznYg+zahQrFUZH6wKZWL6kjsPdXk^h z!FF%$ICoI?ysuTh*6aGO_P$D3vVqu0UoTtGzRK+W_T>)sG1|BJVvXgne~8wUV8`Pj zf6)(K!u}egZ6f0Hppi|mq z@;+5%wU$0dWu-l@Bon0+CuN|k>`=amyUYI8w}sbpT-E(I2zMoX#r)iHE@wi8dMmyS zZTI*#wCUqp*)dBd4AYt2?Cs>)$!_s9H|b#i@#XM(b|gPju3yq~@h3jKmUyJ6P#+;) zV{_?nZQrVJyb!LTo~5}7t<}@|TFFL}sV@wuQgPX;{8f%0AU^}lhp8MVD34+JB}d8+ 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 W+tJ~ch8N$DjyHCHuh#)QivADWMn~!Z literal 0 HcmV?d00001 diff --git a/package/qca-nss/qca-nss-drv/files/qca-nss-drv.conf b/package/qca-nss/qca-nss-drv/files/qca-nss-drv.conf new file mode 100644 index 0000000000..a8a1fbf406 --- /dev/null +++ b/package/qca-nss/qca-nss-drv/files/qca-nss-drv.conf @@ -0,0 +1,6 @@ +config nss_firmware 'qca_nss_0' + +config nss_firmware 'qca_nss_1' + +config general + option enable_rps '1' diff --git a/package/qca-nss/qca-nss-drv/files/qca-nss-drv.debug b/package/qca-nss/qca-nss-drv/files/qca-nss-drv.debug new file mode 100644 index 0000000000..b220159bbc --- /dev/null +++ b/package/qca-nss/qca-nss-drv/files/qca-nss-drv.debug @@ -0,0 +1,4 @@ +#!/bin/sh /sbin/sysdebug +# +log cat /sys/kernel/debug/qca-nss-drv/stats/cpu_load_ubi +log cat $(grep -lE "= [1-9]" /sys/kernel/debug/qca-nss-drv/stats/* 2>/dev/null ) diff --git a/package/qca-nss/qca-nss-drv/files/qca-nss-drv.hotplug b/package/qca-nss/qca-nss-drv/files/qca-nss-drv.hotplug new file mode 100644 index 0000000000..1e4813838c --- /dev/null +++ b/package/qca-nss/qca-nss-drv/files/qca-nss-drv.hotplug @@ -0,0 +1,70 @@ +#!/bin/sh +# +# Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# + +KERNEL=`uname -r` +case "${KERNEL}" in + 3.4*) + select_or_load=load_nss_fw + ;; + *) + select_or_load=select_nss_fw + ;; +esac + +load_nss_fw () { + ls -l $1 | awk ' { print $9,$5 } '> /dev/console + echo 1 > /sys/class/firmware/$DEVICENAME/loading + cat $1 > /sys/class/firmware/$DEVICENAME/data + echo 0 > /sys/class/firmware/$DEVICENAME/loading +} + +select_nss_fw () { + rm -f /lib/firmware/$DEVICENAME + ln -s $1 /lib/firmware/$DEVICENAME + ls -l /lib/firmware/$DEVICENAME | awk ' { print $9,$5 } '> /dev/console +} + +[ "$ACTION" != "add" ] && exit + +# dev name for UCI, since it doesn't let you use . or - +SDEVNAME=$(echo ${DEVICENAME} | sed s/[.-]/_/g) + +SELECTED_FW=$(uci get nss.${SDEVNAME}.firmware 2>/dev/null) +[ -e "${SELECTED_FW}" ] && { + $select_or_load ${SELECTED_FW} + exit +} + +case $DEVICENAME in + qca-nss0* | qca-nss.0*) + if [ -e /lib/firmware/qca-nss0-enterprise.bin ] ; then + $select_or_load /lib/firmware/qca-nss0-enterprise.bin + else + $select_or_load /lib/firmware/qca-nss0-retail.bin + fi + exit + ;; + qca-nss1* | qca-nss.1*) + if [ -e /lib/firmware/qca-nss1-enterprise.bin ] ; then + $select_or_load /lib/firmware/qca-nss1-enterprise.bin + else + $select_or_load /lib/firmware/qca-nss1-retail.bin + fi + exit + ;; +esac + diff --git a/package/qca-nss/qca-nss-drv/files/qca-nss-drv.init b/package/qca-nss/qca-nss-drv/files/qca-nss-drv.init new file mode 100644 index 0000000000..de12cb6d12 --- /dev/null +++ b/package/qca-nss/qca-nss-drv/files/qca-nss-drv.init @@ -0,0 +1,50 @@ +#!/bin/sh /etc/rc.common +# +# Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# + +START=70 + +enable_rps() { + irq_nss_rps=`grep nss_queue1 /proc/interrupts | cut -d ':' -f 1 | tr -d ' '` + for entry in $irq_nss_rps + do + echo 2 > /proc/irq/$entry/smp_affinity + done + + irq_nss_rps=`grep nss_queue2 /proc/interrupts | cut -d ':' -f 1 | tr -d ' '` + for entry in $irq_nss_rps + do + echo 4 > /proc/irq/$entry/smp_affinity + done + + irq_nss_rps=`grep nss_queue3 /proc/interrupts | cut -d ':' -f 1 | tr -d ' '` + for entry in $irq_nss_rps + do + echo 8 > /proc/irq/$entry/smp_affinity + done + + # Enable NSS RPS + sysctl -w dev.nss.rps.enable=1 >/dev/null 2>/dev/null + +} + + +start() { + local rps_enabled="$(uci_get nss @general[0] enable_rps)" + if [ "$rps_enabled" -eq 1 ]; then + enable_rps + fi +} diff --git a/package/qca-nss/qca-nss-drv/files/qca-nss-drv.sysctl b/package/qca-nss/qca-nss-drv/files/qca-nss-drv.sysctl new file mode 100644 index 0000000000..fc36c33eb5 --- /dev/null +++ b/package/qca-nss/qca-nss-drv/files/qca-nss-drv.sysctl @@ -0,0 +1,4 @@ +# Default Number of connection configuration +dev.nss.ipv4cfg.ipv4_conn=4096 +dev.nss.ipv6cfg.ipv6_conn=4096 + diff --git a/package/qca-nss/qca-nss-drv/files/qca-nss-drv.sysdebug b/package/qca-nss/qca-nss-drv/files/qca-nss-drv.sysdebug new file mode 100644 index 0000000000..39f8386484 --- /dev/null +++ b/package/qca-nss/qca-nss-drv/files/qca-nss-drv.sysdebug @@ -0,0 +1,44 @@ +#!/bin/sh + +. /lib/functions.sh + +DEBUG_DIR=/lib/debug + +log() { + echo -n " "; printf "%0.s*" $(seq 1 76); echo "" + echo " * cmd:" "$@" + echo -n " "; printf "%0.s*" $(seq 1 76); echo "" + eval "$@" | sed 's,^\(.*\), | \1,' + echo -n " \\"; printf "%0.s-" $(seq 1 75); echo "" + echo "" +} + +run_pkg_debug() { + local pkg="$1" + echo -n "/"; printf "%0.s=" $(seq 1 79); echo "" + printf "| Start: ${pkg}\n" + echo -n "\\"; printf "%0.s=" $(seq 1 79); echo "" + . ${DEBUG_DIR}/"${pkg}" + echo -n "/"; printf "%0.s=" $(seq 1 79); echo "" + printf "| End: ${pkg}\n" + echo -n "\\"; printf "%0.s=" $(seq 1 79); echo "" + echo "" +} + +help() { + cat < NSS_FW_VERSION(11,0)) + NSS_DYNAMIC_INTERFACE_TYPE_VXLAN_INNER, + NSS_DYNAMIC_INTERFACE_TYPE_VXLAN_OUTER, + NSS_DYNAMIC_INTERFACE_TYPE_MATCH, ++#endif + NSS_DYNAMIC_INTERFACE_TYPE_RMNET_RX_N2H, + NSS_DYNAMIC_INTERFACE_TYPE_RMNET_RX_H2N, ++#if (NSS_FW_VERSION_CODE > NSS_FW_VERSION(11,0)) + NSS_DYNAMIC_INTERFACE_TYPE_WIFILI_EXTERNAL0, + NSS_DYNAMIC_INTERFACE_TYPE_WIFILI_EXTERNAL1, + NSS_DYNAMIC_INTERFACE_TYPE_TLS_INNER, + NSS_DYNAMIC_INTERFACE_TYPE_TLS_OUTER, + NSS_DYNAMIC_INTERFACE_TYPE_MIRROR, +- NSS_DYNAMIC_INTERFACE_TYPE_WIFI_EXT_VDEV_WDS, +- NSS_DYNAMIC_INTERFACE_TYPE_CAPWAP_HOST_INNER, +- NSS_DYNAMIC_INTERFACE_TYPE_CAPWAP_OUTER, +- NSS_DYNAMIC_INTERFACE_TYPE_WIFI_EXT_VDEV_VLAN, +- NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER, +- NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_OUTER, ++#endif + NSS_DYNAMIC_INTERFACE_TYPE_MAX + }; + +--- a/exports/nss_edma.h ++++ b/exports/nss_edma.h +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -84,7 +84,6 @@ enum nss_edma_stats_rx_t { + NSS_EDMA_STATS_RX_DESC, + NSS_EDMA_STATS_RX_QOS_ERR, + NSS_EDMA_STATS_RX_SRC_PORT_INVALID, +- NSS_EDMA_STATS_RX_SRC_IF_INVALID, + NSS_EDMA_STATS_RX_MAX + }; + +@@ -144,7 +143,6 @@ struct nss_edma_rx_ring_stats { + uint32_t desc_cnt; /**< Number of descriptors processed. */ + uint32_t qos_err; /**< Number of QoS errors. */ + uint32_t rx_src_port_invalid; /**< Number of source port invalid errors. */ +- uint32_t rx_src_if_invalid; /**< Number of source interface invalid errors. */ + }; + + /** +@@ -330,7 +328,7 @@ extern void nss_edma_notify_unregister(v + * nss_edma_get_stats + * Sends EDMA statistics to NSS clients. + * +- * @param[in] stats EDMA statistics to be sent to netlink. ++ * @param[in] stats EDMA statistics to be sent to Netlink. + * @param[in] port_id EDMA port ID. + * + * @return +--- /dev/null ++++ b/exports/nss_fw_version.h +@@ -0,0 +1,11 @@ ++#ifndef __NSS_FW_VERSION_H ++#define __NSS_FW_VERSION_H ++ ++#define NSS_FW_VERSION_MAJOR 11 ++#define NSS_FW_VERSION_MINOR 0 ++ ++#define NSS_FW_VERSION(a,b) (((a) << 8) + (b)) ++ ++#define NSS_FW_VERSION_CODE NSS_FW_VERSION(NSS_FW_VERSION_MAJOR, NSS_FW_VERSION_MINOR) ++ ++#endif /* __NSS_FW_VERSION_H */ +--- a/exports/nss_gre.h ++++ b/exports/nss_gre.h +@@ -1,9 +1,6 @@ + /* +- **************************************************************************** +- * Copyright (c) 2017-2019, 2021, The Linux Foundation. All rights reserved. +- * +- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. +- * ++ ************************************************************************** ++ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -14,7 +11,7 @@ + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- **************************************************************************** ++ ************************************************************************** + */ + + /** +@@ -104,16 +101,16 @@ enum nss_gre_msg_types { + }; + + /** +- * GRE mode types. ++ * GRE Mode Types + */ + enum nss_gre_mode { +- NSS_GRE_MODE_TUN, /**< GRE tunnel interface. */ +- NSS_GRE_MODE_TAP, /**< GRE TAP interface. */ ++ NSS_GRE_MODE_TUN, /**< GRE Tunnel interface. */ ++ NSS_GRE_MODE_TAP, /**< GRE Tap interface. */ + NSS_GRE_MODE_MAX /**< Maxmum GRE mode. */ + }; + + /** +- * GRE IP types. ++ * GRE IP Types + */ + enum nss_gre_ip_types { + NSS_GRE_IP_IPV4, /**< Outer Tunnel is IPV4. */ +@@ -122,60 +119,58 @@ enum nss_gre_ip_types { + }; + + /** +- * nss_gre_base_types +- * GRE base debug statistics. ++ * GRE Base debug statistics + */ +-enum nss_gre_base_types { +- NSS_GRE_BASE_RX_PACKETS, /**< Receive packet count. */ +- NSS_GRE_BASE_RX_DROPPED, /**< Number of packet dropped at receive. */ +- NSS_GRE_BASE_EXP_ETH_HDR_MISSING, /**< Ethernet header missing. */ +- NSS_GRE_BASE_EXP_ETH_TYPE_NON_IP, /**< Packet is not IPV4 or IPV6. */ +- NSS_GRE_BASE_EXP_IP_UNKNOWN_PROTOCOL, /**< Packet protocol is unknown. */ +- NSS_GRE_BASE_EXP_IP_HEADER_INCOMPLETE, /**< Bad IP header. */ +- NSS_GRE_BASE_EXP_IP_BAD_TOTAL_LENGTH, /**< IP total length is invalid. */ +- NSS_GRE_BASE_EXP_IP_BAD_CHECKSUM, /**< IP checksum is bad. */ +- NSS_GRE_BASE_EXP_IP_DATAGRAM_INCOMPLETE,/**< Bad packet. */ +- NSS_GRE_BASE_EXP_IP_FRAGMENT, /**< IP packet is a fragment. */ +- NSS_GRE_BASE_EXP_IP_OPTIONS_INCOMPLETE, /**< IP option is invalid. */ +- NSS_GRE_BASE_EXP_IP_WITH_OPTIONS, /**< IP packet with options. */ +- NSS_GRE_BASE_EXP_IPV6_UNKNOWN_PROTOCOL, /**< Protocol is unknown. */ +- NSS_GRE_BASE_EXP_IPV6_HEADER_INCOMPLETE,/**< Incomplete ipv6 header. */ +- NSS_GRE_BASE_EXP_GRE_UNKNOWN_SESSION, /**< Unknown GRE session. */ +- NSS_GRE_BASE_EXP_GRE_NODE_INACTIVE, /**< GRE node is inactive. */ +- NSS_GRE_BASE_DEBUG_MAX, /**< GRE base debug maximum. */ ++enum nss_gre_base_debug_types { ++ GRE_BASE_RX_PACKETS, /**< Rx packet count. */ ++ GRE_BASE_RX_DROPPED, /**< Number of packet dropped at Rx. */ ++ GRE_BASE_EXP_ETH_HDR_MISSING, /**< Ethernet header missing. */ ++ GRE_BASE_EXP_ETH_TYPE_NON_IP, /**< Packet is not IPV4 or IPV6. */ ++ GRE_BASE_EXP_IP_UNKNOWN_PROTOCOL, /**< Packet protocol is unknown. */ ++ GRE_BASE_EXP_IP_HEADER_INCOMPLETE, /**< Bad IP header. */ ++ GRE_BASE_EXP_IP_BAD_TOTAL_LENGTH, /**< IP total lenghth is invalid. */ ++ GRE_BASE_EXP_IP_BAD_CHECKSUM, /**< IP checksum is bad. */ ++ GRE_BASE_EXP_IP_DATAGRAM_INCOMPLETE, /**< Bad packet. */ ++ GRE_BASE_EXP_IP_FRAGMENT, /**< IP packet is a fragment. */ ++ GRE_BASE_EXP_IP_OPTIONS_INCOMPLETE, /**< IP option is invalid. */ ++ GRE_BASE_EXP_IP_WITH_OPTIONS, /**< IP packet with options. */ ++ GRE_BASE_EXP_IPV6_UNKNOWN_PROTOCOL, /**< Protocol is unknown. */ ++ GRE_BASE_EXP_IPV6_HEADER_INCOMPLETE, /**< Incomplete ipv6 header. */ ++ GRE_BASE_EXP_GRE_UNKNOWN_SESSION, /**< Unknown GRE session. */ ++ GRE_BASE_EXP_GRE_NODE_INACTIVE, /**< GRE node is inactive. */ ++ GRE_BASE_DEBUG_MAX, /**< GRE base debug max. */ + }; + +-/** +- * nss_gre_session_types +- * GRE session packet drop and exception events. +- */ +-enum nss_gre_session_types { +- NSS_GRE_SESSION_PBUF_ALLOC_FAIL, /**< Pbuf allocation failure. */ +- NSS_GRE_SESSION_DECAP_FORWARD_ENQUEUE_FAIL, /**< Receive forward enqueue failure. */ +- NSS_GRE_SESSION_ENCAP_FORWARD_ENQUEUE_FAIL, /**< Transmit forward enqueue failure. */ +- NSS_GRE_SESSION_DECAP_TX_FORWARDED, /**< Number of packets forwarded after decapsulation. */ +- NSS_GRE_SESSION_ENCAP_RX_RECEIVED, /**< Number of packets received for encapsulation. */ +- NSS_GRE_SESSION_ENCAP_RX_DROPPED, /**< Packets dropped while enqueuing for encapsulation. */ +- NSS_GRE_SESSION_ENCAP_RX_LINEAR_FAIL, /**< Packets dropped during encapsulation linearization. */ +- NSS_GRE_SESSION_EXP_RX_KEY_ERROR, /**< Receive key error. */ +- NSS_GRE_SESSION_EXP_RX_SEQ_ERROR, /**< Receive Sequence number error. */ +- NSS_GRE_SESSION_EXP_RX_CS_ERROR, /**< Receive checksum error */ +- NSS_GRE_SESSION_EXP_RX_FLAG_MISMATCH, /**< Receive flag mismatch. */ +- NSS_GRE_SESSION_EXP_RX_MALFORMED, /**< Receive packet is malformed. */ +- NSS_GRE_SESSION_EXP_RX_INVALID_PROTOCOL, /**< Receive packet protocol is invalid. */ +- NSS_GRE_SESSION_EXP_RX_NO_HEADROOM, /**< Packet does not have enough headroom. */ +- NSS_GRE_SESSION_DEBUG_MAX, /**< Session debug maximum. */ ++/* ++ * GRE session Packet drop and exception events. ++ */ ++enum gre_session_debug_types { ++ GRE_SESSION_PBUF_ALLOC_FAIL, /**< Pbuf allocation failure. */ ++ GRE_SESSION_DECAP_FORWARD_ENQUEUE_FAIL, /**< Rx forward enqueue failure. */ ++ GRE_SESSION_ENCAP_FORWARD_ENQUEUE_FAIL, /**< Tx forward enqueue failure. */ ++ GRE_SESSION_DECAP_TX_FORWARDED, /**< Number of packets forwarded after decap. */ ++ GRE_SESSION_ENCAP_RX_RECEIVED, /**< Number of packets received for encap. */ ++ GRE_SESSION_ENCAP_RX_DROPPED, /**< Packets dropped while enqueuing for encap. */ ++ GRE_SESSION_ENCAP_RX_LINEAR_FAIL, /**< Packets dropped during encap linearization. */ ++ GRE_SESSION_EXP_RX_KEY_ERROR, /**< Rx KEY error. */ ++ GRE_SESSION_EXP_RX_SEQ_ERROR, /**< Rx Sequence number error. */ ++ GRE_SESSION_EXP_RX_CS_ERROR, /**< Rx checksum error */ ++ GRE_SESSION_EXP_RX_FLAG_MISMATCH, /**< Rx flag mismatch. */ ++ GRE_SESSION_EXP_RX_MALFORMED, /**< Rx packet is malformed. */ ++ GRE_SESSION_EXP_RX_INVALID_PROTOCOL, /**< Rx packet protocol is invalid. */ ++ GRE_SESSION_EXP_RX_NO_HEADROOM, /**< Packet does not have enough headroom. */ ++ GRE_SESSION_DEBUG_MAX, /**< Session debug max. */ + }; + + /** + * GRE create message structure. + */ + struct nss_gre_config_msg { +- uint32_t src_ip[4]; /**< Source IPv4 or IPv6 address. */ +- uint32_t dest_ip[4]; /**< Destination IPv4 or IPv6 address. */ ++ uint32_t src_ip[4]; /**< Source IPv4 or IPv6 Adddress. */ ++ uint32_t dest_ip[4]; /**< Destination IPv4 or IPv6 Adddress. */ + uint32_t flags; /**< GRE Flags. */ +- uint32_t ikey; /**< GRE Rx key.*/ +- uint32_t okey; /**< GRE Tx key. */ ++ uint32_t ikey; /**< GRE rx KEY.*/ ++ uint32_t okey; /**< GRE tx KEY. */ + uint32_t mode; /**< GRE TUN or TAP. */ + uint32_t ip_type; /**< IPv4 or IPv6 type. */ + uint32_t next_node_if_num; /**< To whom to forward packets. */ +@@ -188,7 +183,7 @@ struct nss_gre_config_msg { + }; + + /** +- * GRE link up message structure. ++ * GRE link up message structure + */ + struct nss_gre_linkup_msg { + int if_number; /**< Interface number. */ +@@ -205,49 +200,30 @@ struct nss_gre_linkdown_msg { + * GRE deconfig message structure + */ + struct nss_gre_deconfig_msg { +- int if_number; /**< Interface number. */ ++ int if_number; /**< Interface number */ + }; + + /** +- * GRE session statistics message. ++ * GRE session statistics message + */ + struct nss_gre_session_stats_msg { +- struct nss_cmn_node_stats node_stats; /**< Common node statistics. */ +- uint32_t stats[NSS_GRE_SESSION_DEBUG_MAX]; /**< Session debug statistics. */ ++ struct nss_cmn_node_stats node_stats; /**< Common node statistics. */ ++ uint32_t stats[GRE_SESSION_DEBUG_MAX]; /**< Session debug statistics. */ + }; + + /** +- * GRE base statistics message. ++ * GRE base statistics message + */ + struct nss_gre_base_stats_msg { +- uint32_t stats[NSS_GRE_BASE_DEBUG_MAX]; /**< Base debug statistics. */ +-}; +- +-/** +- * nss_gre_base_stats_notification +- * GRE transmission statistics structure. +- */ +-struct nss_gre_base_stats_notification { +- uint64_t stats_base_ctx[NSS_GRE_BASE_DEBUG_MAX]; /**< Base debug transmission statistics. */ +- uint32_t core_id; /**< Core ID. */ +-}; +- +-/** +- * nss_gre_session_stats_notification +- * GRE transmission statistics structure. +- */ +-struct nss_gre_session_stats_notification { +- uint64_t stats_session_ctx[NSS_GRE_SESSION_DEBUG_MAX]; /**< Session debug transmission statistics. */ +- uint32_t core_id; /**< Core ID. */ +- uint32_t if_num; /**< Interface number. */ ++ uint32_t stats[GRE_BASE_DEBUG_MAX]; /**< Base debug statistics. */ + }; + + /** + * nss_gre_msg +- * Message structure to send/receive GRE messages. ++ * Message structure to send/receive GRE messages + */ + struct nss_gre_msg { +- struct nss_cmn_msg cm; /**< Common message header. */ ++ struct nss_cmn_msg cm; /**< Common message header */ + + /** + * Payload of a GRE message. +@@ -307,7 +283,7 @@ extern nss_tx_status_t nss_gre_tx_msg_sy + + /** + * nss_gre_tx_buf +- * Sends a packet to the NSS. ++ * Sends packet to the NSS + * + * @datatypes + * nss_ctx_instance \n +@@ -448,17 +424,7 @@ typedef void (*nss_gre_pkt_callback_t)(s + * @return + * None. + */ +-#ifdef NSS_DRV_GRE_ENABLE + extern void nss_gre_register_pkt_callback(nss_gre_pkt_callback_t cb); +-#else +-static inline void nss_gre_register_pkt_callback(nss_gre_pkt_callback_t cb) +-{ +- /* +- * Dummy registration function for external modules when GRE +- * is disabled +- */ +-} +-#endif + + /** + * nss_gre_unregister_pkt_callback +@@ -470,45 +436,7 @@ static inline void nss_gre_register_pkt_ + * @return + * None. + */ +-#ifdef NSS_DRV_GRE_ENABLE + extern void nss_gre_unregister_pkt_callback(void); +-#else +-static inline void nss_gre_unregister_pkt_callback(void) +-{ +- /* +- * Dummy registration function for external modules when GRE +- * is disabled +- */ +-} +-#endif +- +-/** +- * nss_gre_stats_unregister_notifier +- * Deregisters a statistics notifier. +- * +- * @datatypes +- * notifier_block +- * +- * @param[in] nb Notifier block. +- * +- * @return +- * 0 on success or non-zero on failure. +- */ +-extern int nss_gre_stats_unregister_notifier(struct notifier_block *nb); +- +-/** +- * nss_gre_stats_register_notifier +- * Registers a statistics notifier. +- * +- * @datatypes +- * notifier_block +- * +- * @param[in] nb Notifier block. +- * +- * @return +- * 0 on success or non-zero on failure. +- */ +-extern int nss_gre_stats_register_notifier(struct notifier_block *nb); + + /** + * @} +--- a/exports/nss_gre_redir.h ++++ b/exports/nss_gre_redir.h +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2014-2015, 2017-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2014-2015, 2017-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -93,60 +93,6 @@ enum nss_gre_redir_tunnel_types { + }; + + /** +- * nss_gre_redir_stats_types +- * GRE redirect statistics types. +- */ +-enum nss_gre_redir_stats_types { +- NSS_GRE_REDIR_STATS_TX_DROPS = NSS_STATS_NODE_MAX, +- /**< Dropped transmit packets. */ +- NSS_GRE_REDIR_STATS_SJACK_RX_PKTS, /**< SJACK receive packet counter. */ +- NSS_GRE_REDIR_STATS_SJACK_TX_PKTS, /**< SJACK transmit packet counter. */ +- NSS_GRE_REDIR_STATS_OFFLOAD_RX_PKTS_0, /**< Offload receive packet counter 0. */ +- NSS_GRE_REDIR_STATS_OFFLOAD_RX_PKTS_1, /**< Offload receive packet counter 1. */ +- NSS_GRE_REDIR_STATS_OFFLOAD_RX_PKTS_2, /**< Offload receive packet counter 2. */ +- NSS_GRE_REDIR_STATS_OFFLOAD_RX_PKTS_3, /**< Offload receive packet counter 3. */ +- NSS_GRE_REDIR_STATS_OFFLOAD_RX_PKTS_4, /**< Offload receive packet counter 4. */ +- NSS_GRE_REDIR_STATS_OFFLOAD_TX_PKTS_0, /**< Offload transmit packet counter 0. */ +- NSS_GRE_REDIR_STATS_OFFLOAD_TX_PKTS_1, /**< Offload transmit packet counter 1. */ +- NSS_GRE_REDIR_STATS_OFFLOAD_TX_PKTS_2, /**< Offload transmit packet counter 2. */ +- NSS_GRE_REDIR_STATS_OFFLOAD_TX_PKTS_3, /**< Offload transmit packet counter 3. */ +- NSS_GRE_REDIR_STATS_OFFLOAD_TX_PKTS_4, /**< Offload transmit packet counter 4. */ +- NSS_GRE_REDIR_STATS_EXCEPTION_US_RX_PKTS, +- /**< Upstream exception receive packet counter. */ +- NSS_GRE_REDIR_STATS_EXCEPTION_US_TX_PKTS, +- /**< Upstream exception transmit packet counter. */ +- NSS_GRE_REDIR_STATS_EXCEPTION_DS_RX_PKTS, +- /**< Downstream exception receive packet counter. */ +- NSS_GRE_REDIR_STATS_EXCEPTION_DS_TX_PKTS, +- /**< Downstream exception transmit packet counter. */ +- NSS_GRE_REDIR_STATS_ENCAP_SG_ALLOC_DROP, +- /**< Encapsulation drop counters due to scatter gather buffer allocation failure. */ +- NSS_GRE_REDIR_STATS_DECAP_FAIL_DROP, +- /**< Decapsulation drop counters due to invalid IP header. */ +- NSS_GRE_REDIR_STATS_DECAP_SPLIT_DROP, +- /**< Decapsulation drop counters due to split flow processing. */ +- NSS_GRE_REDIR_STATS_SPLIT_SG_ALLOC_FAIL, +- /**< Split processing fail counter due to scatter gather buffer allocation failure. */ +- NSS_GRE_REDIR_STATS_SPLIT_LINEAR_COPY_FAIL, +- /**< Split processing fail counter due to linear copy fail. */ +- NSS_GRE_REDIR_STATS_SPLIT_NOT_ENOUGH_TAILROOM, +- /**< Split processing fail counter due to insufficient tailroom. */ +- NSS_GRE_REDIR_STATS_EXCEPTION_DS_INVALID_DST_DROP, +- /**< Downstream exception handling fail counter due to invalid destination. */ +- NSS_GRE_REDIR_STATS_DECAP_EAPOL_FRAMES, +- /**< Decapsulation EAPoL frame counters. */ +- NSS_GRE_REDIR_STATS_EXCEPTION_DS_INV_APPID, +- /**< Invalid application ID for the transmit completion packets on exception downstream node. */ +- NSS_GRE_REDIR_STATS_HEADROOM_UNAVAILABLE, +- /**< Packet headroom unavailable to write metadata. */ +- NSS_GRE_REDIR_STATS_TX_COMPLETION_SUCCESS, +- /**< Host enqueue success count for the transmit completion packets. */ +- NSS_GRE_REDIR_STATS_TX_COMPLETION_DROP, +- /**< Host enqueue drop count for the transmit completion packets. */ +- NSS_GRE_REDIR_STATS_MAX /**< Maximum statistics type. */ +-}; +- +-/** + * nss_gre_redir_inner_configure_msg + * Message information for configuring GRE inner node. + */ +@@ -301,63 +247,34 @@ struct nss_gre_redir_stats_sync_msg { + }; + + /** +- * nss_gre_redir_tun_stats +- * GRE redirect statistics to accumulate all stats values. +- */ +-struct nss_gre_redir_tun_stats { +- uint64_t rx_packets; /**< Number of packets received. */ +- uint64_t rx_bytes; /**< Number of bytes received. */ +- uint64_t tx_packets; /**< Number of packets transmitted. */ +- uint64_t tx_bytes; /**< Number of bytes transmitted. */ +- uint64_t rx_dropped[NSS_MAX_NUM_PRI]; +- /**< Packets dropped on receive due to queue full. */ +- uint64_t tx_dropped; /**< Dropped transmit packets. */ +- uint64_t sjack_rx_packets; /**< SJACK receive packet counter. */ +- uint64_t sjack_tx_packets; /**< SJACK transmit packet counter. */ +- uint64_t offl_rx_pkts[NSS_GRE_REDIR_MAX_RADIO]; /**< Offload receive packet counter per radio. */ +- uint64_t offl_tx_pkts[NSS_GRE_REDIR_MAX_RADIO]; /**< Offload transmit packet counter per radio. */ +- uint64_t exception_us_rx; /**< Upstream exception receive packet counter. */ +- uint64_t exception_us_tx; /**< Upstream exception transmit packet counter. */ +- uint64_t exception_ds_rx; /**< Downstream exception receive packet counter. */ +- uint64_t exception_ds_tx; /**< Downstream exception transmit packet counter. */ +- uint64_t encap_sg_alloc_drop; +- /**< Encapsulation drop counters due to scatter gather buffer allocation failure. */ +- uint64_t decap_fail_drop; /**< Decapsulation drop counters due to invalid IP header. */ +- uint64_t decap_split_drop; /**< Decapsulation drop counters due to split flow processing. */ +- uint64_t split_sg_alloc_fail; +- /**< Split processing fail counter due to scatter gather buffer allocation failure. */ +- uint64_t split_linear_copy_fail; +- /**< Split processing fail counter due to linear copy fail. */ +- uint64_t split_not_enough_tailroom; +- /**< Split processing fail counter due to insufficient tailroom. */ +- uint64_t exception_ds_invalid_dst_drop; +- /**< Downstream exception handling fail counter due to invalid destination. */ +- uint64_t decap_eapol_frames; /**< Decapsulation EAPoL frame counters. */ +- uint64_t exception_ds_inv_appid; +- /**< Invalid application ID for the transmit completion packets on exception downstream node. */ +- uint64_t headroom_unavail; /**< Packet headroom unavailable to write metadata. */ +- uint64_t tx_completion_success; /**< Host enqueue success count for the transmit completion packets. */ +- uint64_t tx_completion_drop; /**< Host enqueue drop count for the transmit completion packets. */ +-}; +- +-/** + * nss_gre_redir_tunnel_stats + * GRE redirect statistics as seen by the HLOS. + */ + struct nss_gre_redir_tunnel_stats { +- struct net_device *dev; /**< Net device. */ +- struct nss_gre_redir_tun_stats tstats; /**< Structure to accumulate all the statistics. */ +- uint32_t ref_count; /**< Reference count for statistics. */ +-}; +- +-/** +- * nss_gre_redir_stats_notification +- * GRE redirect transmission statistics structure. +- */ +-struct nss_gre_redir_stats_notification { +- struct nss_gre_redir_tunnel_stats stats_ctx; /**< Context transmission statistics. */ +- uint32_t core_id; /**< Core ID. */ +- uint32_t if_num; /**< Interface number. */ ++ struct net_device *dev; /**< Net device. */ ++ struct nss_cmn_node_stats node_stats; /**< Common node statistics. */ ++ uint64_t tx_dropped; /**< Dropped Tx packets. */ ++ uint64_t sjack_rx_packets; /**< SJACK Rx packet counter. */ ++ uint64_t sjack_tx_packets; /**< SJACK Tx packet counter. */ ++ uint64_t offl_rx_pkts[NSS_GRE_REDIR_MAX_RADIO]; /**< Offload Rx packet counter per radio. */ ++ uint64_t offl_tx_pkts[NSS_GRE_REDIR_MAX_RADIO]; /**< Offload Tx packet counter per radio. */ ++ uint64_t exception_us_rx; /**< Upstream exception Rx packet counter. */ ++ uint64_t exception_us_tx; /**< Upstream exception Tx packet counter. */ ++ uint64_t exception_ds_rx; /**< Downstream exception Rx packet counter. */ ++ uint64_t exception_ds_tx; /**< Downstream exception Tx packet counter. */ ++ uint64_t encap_sg_alloc_drop; /**< Encapsulation drop counters due to scatter gather buffer allocation failure. */ ++ uint64_t decap_fail_drop; /**< Decapsulation drop counters due to invalid IP header. */ ++ uint64_t decap_split_drop; /**< Decapsulation drop counters due to split flow processing. */ ++ uint64_t split_sg_alloc_fail; /**< Split processing fail counter due to scatter gather buffer allocation failure. */ ++ uint64_t split_linear_copy_fail; /**< Split processing fail counter due to linear copy fail. */ ++ uint64_t split_not_enough_tailroom; /**< Split processing fail counter due to insufficient tailroom. */ ++ uint64_t exception_ds_invalid_dst_drop; /**< Downstream exception handling fail counter due to invalid destination. */ ++ uint64_t decap_eapol_frames; /**< Decapsulation EAPoL frame counters. */ ++ uint64_t exception_ds_inv_appid; /**< Invalid application ID for the Tx completion packets on exception downstream node. */ ++ uint64_t headroom_unavail; /**< Packet headroom unavailable to write metadata. */ ++ uint64_t tx_completion_success; /**< Host enqueue success count for the Tx completion packets. */ ++ uint64_t tx_completion_drop; /**< Host enqueue drop count for the Tx completion packets. */ ++ uint32_t ref_count; /**< Reference count for statistics. */ + }; + + /** +@@ -549,7 +466,7 @@ extern nss_tx_status_t nss_gre_redir_tx_ + uint32_t if_num); + + /** +- * nss_gre_redir_stats_get ++ * nss_gre_redir_get_stats + * Gets GRE redirect tunnel statistics. + * + * @datatypes +@@ -561,7 +478,7 @@ extern nss_tx_status_t nss_gre_redir_tx_ + * @return + * TRUE or FALSE. + */ +-extern bool nss_gre_redir_stats_get(int index, struct nss_gre_redir_tunnel_stats *stats); ++extern bool nss_gre_redir_get_stats(int index, struct nss_gre_redir_tunnel_stats *stats); + + /** + * nss_gre_redir_alloc_and_register_node +@@ -678,34 +595,6 @@ extern struct dentry *nss_gre_redir_get_ + extern struct device *nss_gre_redir_get_device(void); + + /** +- * nss_gre_redir_stats_unregister_notifier +- * Deregisters a statistics notifier. +- * +- * @datatypes +- * notifier_block +- * +- * @param[in] nb Notifier block. +- * +- * @return +- * 0 on success or non-zero on failure. +- */ +-extern int nss_gre_redir_stats_unregister_notifier(struct notifier_block *nb); +- +-/** +- * nss_gre_redir_stats_register_notifier +- * Registers a statistics notifier. +- * +- * @datatypes +- * notifier_block +- * +- * @param[in] nb Notifier block. +- * +- * @return +- * 0 on success or non-zero on failure. +- */ +-extern int nss_gre_redir_stats_register_notifier(struct notifier_block *nb); +- +-/** + * @} + */ + +--- a/exports/nss_gre_redir_lag.h ++++ b/exports/nss_gre_redir_lag.h +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2018, 2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -73,39 +73,6 @@ enum nss_gre_redir_lag_ds_message_types + }; + + /** +- * nss_gre_redir_lag_ds_stats_types +- * GRE redirect LAG downstream statistics. +- */ +-enum nss_gre_redir_lag_ds_stats_types { +- NSS_GRE_REDIR_LAG_DS_STATS_DST_INVALID = NSS_STATS_NODE_MAX, +- /**< Packets that do not have a valid destination. */ +- NSS_GRE_REDIR_LAG_DS_STATS_EXCEPTION_PKT, /**< Packets that are exceptioned to host. */ +- NSS_GRE_REDIR_LAG_DS_STATS_MAX, /**< Maximum statistics type. */ +-}; +- +-/** +- * nss_gre_redir_lag_us_stats_types +- * GRE redirect LAG upstream statistics. +- */ +-enum nss_gre_redir_lag_us_stats_types { +- NSS_GRE_REDIR_LAG_US_STATS_AMSDU_PKTS = NSS_STATS_NODE_MAX, +- /**< Number of AMSDU packets seen. */ +- NSS_GRE_REDIR_LAG_US_STATS_AMSDU_PKTS_ENQUEUED, /**< Number of AMSDU packets enqueued. */ +- NSS_GRE_REDIR_LAG_US_STATS_AMSDU_PKTS_EXCEPTIONED, +- /**< Number of AMSDU packets exceptioned. */ +- NSS_GRE_REDIR_LAG_US_STATS_EXCEPTIONED, /**< Number of exceptioned packets. */ +- NSS_GRE_REDIR_LAG_US_STATS_FREED, /**< Freed packets when equeue to NSS to host fails. */ +- NSS_GRE_REDIR_LAG_US_STATS_ADD_ATTEMPT, /**< Add hash attempts. */ +- NSS_GRE_REDIR_LAG_US_STATS_ADD_SUCCESS, /**< Add hash success. */ +- NSS_GRE_REDIR_LAG_US_STATS_ADD_FAIL_TABLE_FULL, /**< Add hash failed due to full table. */ +- NSS_GRE_REDIR_LAG_US_STATS_ADD_FAIL_EXISTS, /**< Add hash failed as entry already exists. */ +- NSS_GRE_REDIR_LAG_US_STATS_DEL_ATTEMPT, /**< Delete hash attempts. */ +- NSS_GRE_REDIR_LAG_US_STATS_DEL_SUCCESS, /**< Delete hash success. */ +- NSS_GRE_REDIR_LAG_US_STATS_DEL_FAIL_NOT_FOUND, /**< Delete hash failed as entry not found in hash table. */ +- NSS_GRE_REDIR_LAG_US_STATS_MAX, /**< Maximum statistics type. */ +-}; +- +-/** + * nss_gre_redir_lag_us_hash_mode + * GRE redirect LAG upstream hash modes. + */ +@@ -287,16 +254,6 @@ struct nss_gre_redir_lag_us_tunnel_stats + }; + + /** +- * nss_gre_redir_lag_us_stats_notification +- * GRE redirect LAG upstream transmission statistics structure. +- */ +-struct nss_gre_redir_lag_us_stats_notification { +- struct nss_gre_redir_lag_us_tunnel_stats stats_ctx; /**< Context transmission statistics. */ +- uint32_t core_id; /**< Core ID. */ +- uint32_t if_num; /**< Interface number. */ +-}; +- +-/** + * nss_gre_redir_lag_ds_add_sta_msg + * Message to add station in LAG deployment. + */ +@@ -363,26 +320,15 @@ struct nss_gre_redir_lag_ds_msg { + * Downstream statistics. + */ + struct nss_gre_redir_lag_ds_tun_stats { +- uint64_t rx_packets; /**< Received packets. */ +- uint64_t rx_bytes; /**< Received bytes. */ +- uint64_t tx_packets; /**< Transmit packets. */ +- uint64_t tx_bytes; /**< Transmit bytes. */ +- uint64_t rx_dropped[NSS_MAX_NUM_PRI]; +- /**< Packets dropped on receive due to queue full. */ +- uint64_t dst_invalid; /**< Packets that do not have a valid destination. */ +- uint64_t exception_cnt; /**< Packets that are exceptioned to host. */ +- uint32_t ifnum; /**< NSS interface number. */ +- bool valid; /**< Valid flag. */ +-}; +- +-/** +- * nss_gre_redir_lag_ds_stats_notification +- * GRE redirect LAG downstream transmission statistics structure. +- */ +-struct nss_gre_redir_lag_ds_stats_notification { +- struct nss_gre_redir_lag_ds_tun_stats stats_ctx; /**< Context transmission statistics. */ +- uint32_t core_id; /**< Core ID. */ +- uint32_t if_num; /**< Interface number. */ ++ uint64_t rx_packets; /**< Received packets. */ ++ uint64_t rx_bytes; /**< Received bytes. */ ++ uint64_t tx_packets; /**< Transmit packets. */ ++ uint64_t tx_bytes; /**< Transmit bytes. */ ++ uint64_t rx_dropped[NSS_MAX_NUM_PRI]; /**< Packets dropped on receive due to queue full. */ ++ uint64_t dst_invalid; /**< Packets that do not have a valid destination. */ ++ uint64_t exception_cnt; /**< Packets that are exceptioned to host. */ ++ uint32_t ifnum; /**< NSS interface number. */ ++ bool valid; /**< Valid flag. */ + }; + + /** +@@ -622,7 +568,7 @@ extern nss_tx_status_t nss_gre_redir_lag + extern nss_tx_status_t nss_gre_redir_lag_ds_tx_msg_sync(struct nss_ctx_instance *nss_ctx, struct nss_gre_redir_lag_ds_msg *ngrm); + + /** +- * nss_gre_redir_lag_us_stats_get ++ * nss_gre_redir_lag_us_get_cmn_stats + * Fetches common node statistics for upstream GRE Redir LAG. + * + * @datatypes +@@ -634,10 +580,10 @@ extern nss_tx_status_t nss_gre_redir_lag + * @return + * True if successful, else false. + */ +-extern bool nss_gre_redir_lag_us_stats_get(struct nss_gre_redir_lag_us_tunnel_stats *cmn_stats, uint32_t index); ++extern bool nss_gre_redir_lag_us_get_cmn_stats(struct nss_gre_redir_lag_us_tunnel_stats *cmn_stats, uint32_t index); + + /** +- * nss_gre_redir_lag_ds_stats_get ++ * nss_gre_redir_lag_ds_get_stats + * Fetches common node statistics for downstream GRE Redir LAG. + * + * @datatypes +@@ -649,7 +595,7 @@ extern bool nss_gre_redir_lag_us_stats_g + * @return + * True if successful, else false. + */ +-extern bool nss_gre_redir_lag_ds_stats_get(struct nss_gre_redir_lag_ds_tun_stats *cmn_stats, uint32_t index); ++extern bool nss_gre_redir_lag_ds_get_cmn_stats(struct nss_gre_redir_lag_ds_tun_stats *cmn_stats, uint32_t index); + + /** + * nss_gre_redir_lag_us_get_context +@@ -670,62 +616,6 @@ extern struct nss_ctx_instance *nss_gre_ + extern struct nss_ctx_instance *nss_gre_redir_lag_ds_get_context(void); + + /** +- * nss_gre_redir_lag_ds_stats_unregister_notifier +- * Deregisters a statistics notifier. +- * +- * @datatypes +- * notifier_block +- * +- * @param[in] nb Notifier block. +- * +- * @return +- * 0 on success or non-zero on failure. +- */ +-extern int nss_gre_redir_lag_ds_stats_unregister_notifier(struct notifier_block *nb); +- +-/** +- * nss_gre_redir_lag_ds_stats_register_notifier +- * Registers a statistics notifier. +- * +- * @datatypes +- * notifier_block +- * +- * @param[in] nb Notifier block. +- * +- * @return +- * 0 on success or non-zero on failure. +- */ +-extern int nss_gre_redir_lag_ds_stats_register_notifier(struct notifier_block *nb); +- +-/** +- * nss_gre_redir_lag_us_stats_unregister_notifier +- * Deregisters a statistics notifier. +- * +- * @datatypes +- * notifier_block +- * +- * @param[in] nb Notifier block. +- * +- * @return +- * 0 on success or non-zero on failure. +- */ +-extern int nss_gre_redir_lag_us_stats_unregister_notifier(struct notifier_block *nb); +- +-/** +- * nss_gre_redir_lag_us_stats_register_notifier +- * Registers a statistics notifier. +- * +- * @datatypes +- * notifier_block +- * +- * @param[in] nb Notifier block. +- * +- * @return +- * 0 on success or non-zero on failure. +- */ +-extern int nss_gre_redir_lag_us_stats_register_notifier(struct notifier_block *nb); +- +-/** + * @} + */ + +--- a/exports/nss_gre_redir_mark.h ++++ b/exports/nss_gre_redir_mark.h +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2019, 2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -25,8 +25,6 @@ + #define NSS_GRE_REDIR_MARK_HLOS_MAGIC 0xaade /**< Metadata magic set by HLOS. */ + #define NSS_GRE_REDIR_MARK_NSS_MAGIC 0xaadf /**< Metadata magic set by NSS. */ + +-extern struct nss_gre_redir_mark_stats gre_mark_stats; +- + /** + * nss_gre_redir_mark messages + * Message types for GRE redirect mark requests and responses. +@@ -49,23 +47,6 @@ enum nss_gre_redir_mark_error_types { + }; + + /** +- * nss_gre_redir_mark_stats_types +- * GRE redirect mark statistics types. +- */ +-enum nss_gre_redir_mark_stats_types { +- NSS_GRE_REDIR_MARK_STATS_HLOS_MAGIC_FAILED = NSS_STATS_NODE_MAX, +- /**< HLOS magic fail count. */ +- NSS_GRE_REDIR_MARK_STATS_INV_DST_IF_DROPS, /**< Invalid transmit interface drop count. */ +- NSS_GRE_REDIR_MARK_STATS_DST_IF_ENQUEUE, /**< Next egress interface enqueue success count. */ +- NSS_GRE_REDIR_MARK_STATS_DST_IF_ENQUEUE_DROPS, /**< Next egress interface enqueue drop count. */ +- NSS_GRE_REDIR_MARK_STATS_INV_APPID, /**< Invalid application ID for the transmit completion packets. */ +- NSS_GRE_REDIR_MARK_STATS_HEADROOM_UNAVAILABLE, /**< Packet headroom unavailable to write metadata. */ +- NSS_GRE_REDIR_MARK_STATS_TX_COMPLETION_SUCCESS, /**< Transmit completion host enqueue success count. */ +- NSS_GRE_REDIR_MARK_STATS_TX_COMPLETION_DROPS, /**< Transmit completion host enqueue drop count. */ +- NSS_GRE_REDIR_MARK_STATS_MAX /**< Maximum statistics type. */ +-}; +- +-/** + * nss_gre_redir_mark_metadata + * HLOS to NSS per packet downstream metadata. + */ +@@ -74,7 +55,7 @@ struct nss_gre_redir_mark_metadata { + uint8_t wifi_tid; /**< TID value. */ + uint8_t app_id; /**< Application ID. */ + uint16_t hw_hash_idx; /**< Hardware AST hash index value. */ +- uint32_t tx_status; /**< Transmit status. */ ++ uint32_t tx_status; /**< Tx status. */ + uint16_t offset; /**< Buffer offset from the metadata. */ + uint16_t magic; /**< Metadata magic. */ + }; +@@ -86,31 +67,21 @@ struct nss_gre_redir_mark_metadata { + struct nss_gre_redir_mark_stats_sync_msg { + struct nss_cmn_node_stats node_stats; /**< Common node statistics. */ + uint32_t hlos_magic_fail; /**< HLOS magic fail count. */ +- uint32_t invalid_dst_drop; /**< Invalid transmit interface drop count. */ ++ uint32_t invalid_dst_drop; /**< Invalid Tx interface drop count. */ + uint32_t dst_enqueue_success; /**< Next egress interface enqueue success count. */ + uint32_t dst_enqueue_drop; /**< Next egress interface enqueue drop count. */ +- uint32_t inv_appid; /**< Invalid application ID for the transmit completion packets. */ ++ uint32_t inv_appid; /**< Invalid application ID for the Tx completion packets. */ + uint32_t headroom_unavail; /**< Packet headroom unavailable to write metadata. */ +- uint32_t tx_completion_success; /**< Transmit completion host enqueue success count. */ +- uint32_t tx_completion_drop; /**< Transmit completion host enqueue drop count. */ ++ uint32_t tx_completion_success; /**< Tx completion host enqueue success count. */ ++ uint32_t tx_completion_drop; /**< Tx completion host enqueue drop count. */ + }; + + /** + * nss_gre_redir_mark_register_cb_msg +- * Transmit completion function register configuration message. ++ * Tx completion function register configuration message. + */ + struct nss_gre_redir_mark_register_cb_msg { +- uint32_t nss_if_num; /**< NSS transmit interface number on which callback needs to be registered. */ +-}; +- +-/** +- * nss_gre_redir_mark_stats_notification +- * GRE redirect mark transmission statistics structure. +- */ +-struct nss_gre_redir_mark_stats_notification { +- uint64_t stats_ctx[NSS_GRE_REDIR_MARK_STATS_MAX]; /**< Context transmission statistics. */ +- uint32_t core_id; /**< Core ID. */ +- uint32_t if_num; /**< Interface number. */ ++ uint32_t nss_if_num; /**< NSS Tx interface number on which callback needs to be registered. */ + }; + + /** +@@ -240,7 +211,7 @@ extern nss_tx_status_t nss_gre_redir_mar + extern nss_tx_status_t nss_gre_redir_mark_tx_msg_sync(struct nss_ctx_instance *nss_ctx, struct nss_gre_redir_mark_msg *ngrm); + + /** +- * nss_gre_redir_mark_stats_get ++ * nss_gre_redir_mark_get_stats + * Gets GRE redirect mark statistics. + * + * @datatypes +@@ -252,7 +223,7 @@ extern nss_tx_status_t nss_gre_redir_mar + * @return + * TRUE or FALSE. + */ +-extern bool nss_gre_redir_mark_stats_get(struct nss_gre_redir_mark_stats *stats); ++extern bool nss_gre_redir_mark_get_stats(void *stats); + + /** + * nss_gre_redir_alloc_and_register_node +@@ -304,34 +275,6 @@ extern struct dentry *nss_gre_redir_mark + extern struct device *nss_gre_redir_mark_get_device(void); + + /** +- * nss_gre_redir_mark_stats_unregister_notifier +- * Deregisters a statistics notifier. +- * +- * @datatypes +- * notifier_block +- * +- * @param[in] nb Notifier block. +- * +- * @return +- * 0 on success or non-zero on failure. +- */ +-extern int nss_gre_redir_mark_stats_unregister_notifier(struct notifier_block *nb); +- +-/** +- * nss_gre_redir_mark_stats_register_notifier +- * Registers a statistics notifier. +- * +- * @datatypes +- * notifier_block +- * +- * @param[in] nb Notifier block. +- * +- * @return +- * 0 on success or non-zero on failure. +- */ +-extern int nss_gre_redir_mark_stats_register_notifier(struct notifier_block *nb); +- +-/** + * @} + */ + +--- a/exports/nss_gre_tunnel.h ++++ b/exports/nss_gre_tunnel.h +@@ -1,6 +1,6 @@ + /* +- **************************************************************************** +- * Copyright (c) 2016-2018, 2020-2021, The Linux Foundation. All rights reserved. ++ ************************************************************************** ++ * Copyright (c) 2016-2018,2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -11,7 +11,7 @@ + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- **************************************************************************** ++ ************************************************************************** + */ + + /** +@@ -98,41 +98,6 @@ enum nss_gre_tunnel_error_types { + }; + + /** +- * nss_gre_tunnel_stats_type +- * GRE tunnel session debug statistic counters. +- */ +-enum nss_gre_tunnel_stats_type { +- NSS_GRE_TUNNEL_STATS_SESSION_RX_PKTS, /**< Number of packets received. */ +- NSS_GRE_TUNNEL_STATS_SESSION_TX_PKTS, /**< Number of packets transmitted. */ +- NSS_GRE_TUNNEL_STATS_SESSION_RX_QUEUE_0_DROPPED, /**< Dropped receive packets 0. */ +- NSS_GRE_TUNNEL_STATS_SESSION_RX_QUEUE_1_DROPPED, /**< Dropped receive packets 1. */ +- NSS_GRE_TUNNEL_STATS_SESSION_RX_QUEUE_2_DROPPED, /**< Dropped receive packets 2. */ +- NSS_GRE_TUNNEL_STATS_SESSION_RX_QUEUE_3_DROPPED, /**< Dropped receive packets 3. */ +- NSS_GRE_TUNNEL_STATS_SESSION_RX_MALFORMED, /**< Malformed packet was received. */ +- NSS_GRE_TUNNEL_STATS_SESSION_RX_INVALID_PROT, /**< Invalid protocol was received. */ +- NSS_GRE_TUNNEL_STATS_SESSION_DECAP_QUEUE_FULL, /**< Decapsulation queue is full. */ +- NSS_GRE_TUNNEL_STATS_SESSION_RX_SINGLE_REC_DGRAM, /**< Single fragment was received. */ +- NSS_GRE_TUNNEL_STATS_SESSION_RX_INVALID_REC_DGRAM, /**< Invalid fragment was received. */ +- NSS_GRE_TUNNEL_STATS_SESSION_BUFFER_ALLOC_FAIL, /**< Buffer memory allocation failed. */ +- NSS_GRE_TUNNEL_STATS_SESSION_BUFFER_COPY_FAIL, /**< Buffer memory copy failed. */ +- NSS_GRE_TUNNEL_STATS_SESSION_OUTFLOW_QUEUE_FULL, /**< Outflow queue is full. */ +- NSS_GRE_TUNNEL_STATS_SESSION_RX_DROPPED_HROOM, /**< Packets dropped because of insufficent headroom. */ +- NSS_GRE_TUNNEL_STATS_SESSION_RX_CBUFFER_ALLOC_FAIL, /**< Receive crypto buffer allocation failed. */ +- NSS_GRE_TUNNEL_STATS_SESSION_RX_CENQUEUE_FAIL, /**< Receive enqueue-to-crypto failed. */ +- NSS_GRE_TUNNEL_STATS_SESSION_RX_DECRYPT_DONE, /**< Receive decryption is complete. */ +- NSS_GRE_TUNNEL_STATS_SESSION_RX_FORWARD_ENQUEUE_FAIL, /**< Receive forward enqueue failed. */ +- NSS_GRE_TUNNEL_STATS_SESSION_TX_CBUFFER_ALLOC_FAIL, /**< Receive crypto buffer allocation failed. */ +- NSS_GRE_TUNNEL_STATS_SESSION_TX_CENQUEUE_FAIL, /**< Transmit enqueue-to-crypto failed. */ +- NSS_GRE_TUNNEL_STATS_SESSION_RX_DROPPED_TROOM, /**< Packets dropped because of insufficent tailroom. */ +- NSS_GRE_TUNNEL_STATS_SESSION_TX_FORWARD_ENQUEUE_FAIL, /**< Transmit forward enqueue failed. */ +- NSS_GRE_TUNNEL_STATS_SESSION_TX_CIPHER_DONE, /**< Transmit cipher is complete. */ +- NSS_GRE_TUNNEL_STATS_SESSION_CRYPTO_NOSUPP, /**< Error count for non-supported crypto packets. */ +- NSS_GRE_TUNNEL_STATS_SESSION_RX_DROPPED_MH_VERSION, /**< Receive drop: bad meta header. */ +- NSS_GRE_TUNNEL_STATS_SESSION_RX_UNALIGNED_PKT, /**< Counter for unaligned packets. */ +- NSS_GRE_TUNNEL_STATS_SESSION_MAX, /**< Maximum statistics type. */ +-}; +- +-/** + * nss_gre_tunnel_di_to_wlan_id + * Dynamic interface to WLAN ID message structure. + */ +@@ -186,20 +151,20 @@ struct nss_gre_tunnel_stats { + uint32_t rx_dropped_hroom; + /**< Packets dropped because of insufficent headroom. */ + uint32_t rx_cbuf_alloc_fail; +- /**< Receive crypto buffer allocation failed. */ +- uint32_t rx_cenqueue_fail; /**< Receive enqueue-to-crypto failed. */ +- uint32_t rx_decrypt_done; /**< Receive decryption is complete. */ +- uint32_t rx_forward_enqueue_fail; /**< Receive forward enqueue failed. */ ++ /**< Rx crypto buffer allocation failed. */ ++ uint32_t rx_cenqueue_fail; /**< Rx enqueue-to-crypto failed. */ ++ uint32_t rx_decrypt_done; /**< Rx decryption is complete. */ ++ uint32_t rx_forward_enqueue_fail; /**< Rx forward enqueue failed. */ + uint32_t tx_cbuf_alloc_fail; +- /**< Receive crypto buffer allocation failed. */ +- uint32_t tx_cenqueue_fail; /**< Transmit enqueue-to-crypto failed. */ ++ /**< Rx crypto buffer allocation failed. */ ++ uint32_t tx_cenqueue_fail; /**< Tx enqueue-to-crypto failed. */ + uint32_t rx_dropped_troom; + /**< Packets dropped because of insufficent tailroom. */ +- uint32_t tx_forward_enqueue_fail; /**< Transmit forward enqueue failed. */ +- uint32_t tx_cipher_done; /**< Transmit cipher is complete. */ ++ uint32_t tx_forward_enqueue_fail; /**< Tx forward enqueue failed. */ ++ uint32_t tx_cipher_done; /**< Tx cipher is complete. */ + uint32_t crypto_nosupp; + /**< Error count for non-supported crypto packets. */ +- uint32_t rx_dropped_mh_ver; /**< Receive drop: bad meta header. */ ++ uint32_t rx_dropped_mh_ver; /**< Rx drop: bad meta header. */ + uint32_t rx_unaligned_pkt; /**< Counter for unaligned packets. */ + #if defined(NSS_HAL_IPQ807x_SUPPORT) + uint32_t crypto_resp_error[NSS_CRYPTO_CMN_RESP_ERROR_MAX]; +@@ -208,17 +173,6 @@ struct nss_gre_tunnel_stats { + }; + + /** +- * nss_gre_tunnel_stats_notification +- * GRE tunnel transmission statistics structure. +- */ +-struct nss_gre_tunnel_stats_notification { +- uint64_t stats_ctx[NSS_GRE_TUNNEL_STATS_SESSION_MAX + NSS_CRYPTO_CMN_RESP_ERROR_MAX]; +- /**< Context transmission statistics. */ +- uint32_t core_id; /**< Core ID. */ +- uint32_t if_num; /**< Interface number. */ +-}; +- +-/** + * nss_gre_tunnel_msg + * Data for sending and receiving GRE tunnel messages. + */ +@@ -394,34 +348,6 @@ extern nss_tx_status_t nss_gre_tunnel_in + nss_gre_tunnel_msg_callback_t cb, void *app_data); + + /** +- * nss_gre_tunnel_stats_unregister_notifier +- * Deregisters a statistics notifier. +- * +- * @datatypes +- * notifier_block +- * +- * @param[in] nb Notifier block. +- * +- * @return +- * 0 on success or non-zero on failure. +- */ +-extern int nss_gre_tunnel_stats_unregister_notifier(struct notifier_block *nb); +- +-/** +- * nss_gre_tunnel_stats_register_notifier +- * Registers a statistics notifier. +- * +- * @datatypes +- * notifier_block +- * +- * @param[in] nb Notifier block. +- * +- * @return +- * 0 on success or non-zero on failure. +- */ +-extern int nss_gre_tunnel_stats_register_notifier(struct notifier_block *nb); +- +-/** + * @} + */ + +--- a/exports/nss_if.h ++++ b/exports/nss_if.h +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2014-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2014-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -53,8 +53,6 @@ enum nss_if_message_types { + NSS_IF_SET_IGS_NODE, + NSS_IF_CLEAR_IGS_NODE, + NSS_IF_RESET_NEXTHOP, +- NSS_IF_PPE_PORT_CREATE, +- NSS_IF_PPE_PORT_DESTROY, + NSS_IF_MAX_MSG_TYPES = 9999, + }; + +@@ -200,14 +198,6 @@ struct nss_if_igs_config { + }; + + /** +- * nss_if_ppe_port_create +- * Message to create PPE port. +- */ +-struct nss_if_ppe_port_create { +- int32_t ppe_port_num; /**< PPE port number returned by NSS. */ +-}; +- +-/** + * nss_if_msgs + * Information for physical NSS interface command messages. + */ +@@ -240,8 +230,6 @@ union nss_if_msgs { + /**< Set nexthop of interface. */ + struct nss_if_igs_config config_igs; + /**< Configure an ingress shaper interface. */ +- struct nss_if_ppe_port_create ppe_port_create; +- /**< Create a PPE port. */ + }; + + /** +@@ -321,23 +309,6 @@ extern struct nss_ctx_instance *nss_if_r + extern nss_tx_status_t nss_if_tx_buf(struct nss_ctx_instance *nss_ctx, struct sk_buff *os_buf, uint32_t if_num); + + /** +- * nss_if_tx_msg_with_size +- * Sends a message to the NSS interface. +- * +- * @datatypes +- * nss_ctx_instance \n +- * nss_if_msg +- * +- * @param[in,out] nss_ctx Pointer to the NSS context. +- * @param[in] nim Pointer to the NSS interface message. +- * @param[in] size Total message buffer size. +- * +- * @return +- * Status of the Tx operation. +- */ +-nss_tx_status_t nss_if_tx_msg_with_size(struct nss_ctx_instance *nss_ctx, struct nss_if_msg *nim, uint32_t size); +- +-/** + * nss_if_tx_msg + * Sends a message to the NSS interface. + * +@@ -355,7 +326,7 @@ nss_tx_status_t nss_if_tx_msg(struct nss + + /** + * nss_if_msg_sync +- * Sends a message to the NSS interface and waits for the response. ++ * Sends a message to the NSS interface and wait for the response. + * + * @datatypes + * nss_ctx_instance \n +@@ -401,70 +372,6 @@ nss_tx_status_t nss_if_set_nexthop(struc + nss_tx_status_t nss_if_reset_nexthop(struct nss_ctx_instance *nss_ctx, uint32_t if_num); + + /** +- * nss_if_change_mtu +- * Changes the MTU of the interface. +- * +- * @datatypes +- * nss_ctx_instance +- * +- * @param[in] nss_ctx Pointer to the NSS context. +- * @param[in] if_num NSS interface number. +- * @param[in] mtu New MTU. +- * +- * @return +- * Status of the transmit operation. +- */ +-nss_tx_status_t nss_if_change_mtu(struct nss_ctx_instance *nss_ctx, nss_if_num_t if_num, uint16_t mtu); +- +-/** +- * nss_if_change_mac_addr +- * Changes the MAC address of the interface. +- * +- * @datatypes +- * nss_ctx_instance +- * +- * @param[in] nss_ctx Pointer to the NSS context. +- * @param[in] if_num NSS interface number. +- * @param[in] mac_addr New MAC address. +- * +- * @return +- * Status of the transmit operation. +- */ +-nss_tx_status_t nss_if_change_mac_addr(struct nss_ctx_instance *nss_ctx, nss_if_num_t if_num, uint8_t *mac_addr); +- +-/** +- * nss_if_vsi_unassign +- * Detaches the VSI ID from the given interface. +- * +- * @datatypes +- * nss_ctx_instance +- * +- * @param[in] nss_ctx Pointer to the NSS context. +- * @param[in] if_num NSS interface number. +- * @param[in] vsi VSI ID. +- * +- * @return +- * Status of the transmit operation. +- */ +-nss_tx_status_t nss_if_vsi_unassign(struct nss_ctx_instance *nss_ctx, nss_if_num_t if_num, uint32_t vsi); +- +-/** +- * nss_if_vsi_assign +- * Attaches the VSI ID to the given interface. +- * +- * @datatypes +- * nss_ctx_instance +- * +- * @param[in] nss_ctx Pointer to the NSS context. +- * @param[in] if_num NSS interface number. +- * @param[in] vsi VSI ID. +- * +- * @return +- * Status of the transmit operation. +- */ +-nss_tx_status_t nss_if_vsi_assign(struct nss_ctx_instance *nss_ctx, nss_if_num_t if_num, uint32_t vsi); +- +-/** + * @} + */ + +--- a/exports/nss_ipsec_cmn.h ++++ b/exports/nss_ipsec_cmn.h +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -107,37 +107,6 @@ enum nss_ipsec_cmn_ctx_type { + }; + + /** +- * nss_ipsec_cmn_stats_types +- * IPsec common statistics types. +- */ +-enum nss_ipsec_cmn_stats_types { +- NSS_IPSEC_CMN_STATS_FAIL_HEADROOM = NSS_STATS_NODE_MAX, +- /**< Failure in headroom check. */ +- NSS_IPSEC_CMN_STATS_FAIL_TAILROOM, /**< Failure in tailroom check. */ +- NSS_IPSEC_CMN_STATS_FAIL_REPLAY, /**< Failure in anti-replay check. */ +- NSS_IPSEC_CMN_STATS_FAIL_REPLAY_DUP, /**< Failure in anti-replay; duplicate records. */ +- NSS_IPSEC_CMN_STATS_FAIL_REPLAY_WIN, /**< Failure in anti-replay; packet outside the window. */ +- NSS_IPSEC_CMN_STATS_FAIL_PBUF_CRYPTO, /**< Failure in crypto pbuf allocation. */ +- NSS_IPSEC_CMN_STATS_FAIL_QUEUE, /**< Failure due to queue full in IPsec. */ +- NSS_IPSEC_CMN_STATS_FAIL_QUEUE_CRYPTO, /**< Failure due to queue full in crypto. */ +- NSS_IPSEC_CMN_STATS_FAIL_QUEUE_NEXTHOP, /**< Failure due to queue full in next hop. */ +- NSS_IPSEC_CMN_STATS_FAIL_PBUF_ALLOC, /**< Failure in pbuf allocation. */ +- NSS_IPSEC_CMN_STATS_FAIL_PBUF_LINEAR, /**< Failure in pbuf linearization. */ +- NSS_IPSEC_CMN_STATS_FAIL_PBUF_STATS, /**< Failure in pbuf allocation for statistics. */ +- NSS_IPSEC_CMN_STATS_FAIL_PBUF_ALIGN, /**< Failure in pbuf access due to non-word alignmnt */ +- NSS_IPSEC_CMN_STATS_FAIL_CIPHER, /**< Failure in decrypting the data. */ +- NSS_IPSEC_CMN_STATS_FAIL_AUTH, /**< Failure in authenticating the data. */ +- NSS_IPSEC_CMN_STATS_FAIL_SEQ_OVF, /**< Failure due to sequence number rollover. */ +- NSS_IPSEC_CMN_STATS_FAIL_BLK_LEN, /**< Failure in decapsulation due to bad cipher block length. */ +- NSS_IPSEC_CMN_STATS_FAIL_HASH_LEN, /**< Failure in decapsulation due to bad hash block length. */ +- NSS_IPSEC_CMN_STATS_FAIL_TRANSFORM, /**< Failure in transformation; general error. */ +- NSS_IPSEC_CMN_STATS_FAIL_CRYPTO, /**< Failure in crypto transformation. */ +- NSS_IPSEC_CMN_STATS_FAIL_CLE, /**< Failure in classification; general failure. */ +- NSS_IPSEC_CMN_STATS_IS_STOPPED, /**< Indicates if SA is stopped; for example: sequence overflow. */ +- NSS_IPSEC_CMN_STATS_MAX, /**< Maximum statistics type. */ +-}; +- +-/** + * nss_ipsec_cmn_flow_tuple + * IPsec tuple for creating flow entries. + * +@@ -227,7 +196,6 @@ struct nss_ipsec_cmn_sa { + struct nss_ipsec_cmn_ctx { + enum nss_ipsec_cmn_ctx_type type; /**< Node type. */ + uint32_t except_ifnum; /**< Exception interface for egress. */ +- uint32_t sibling_ifnum; /**< Sibling interface. */ + }; + + /** +@@ -269,7 +237,7 @@ struct nss_ipsec_cmn_sa_stats { + uint32_t fail_pbuf_alloc; /**< Failure in pbuf allocation. */ + uint32_t fail_pbuf_linear; /**< Failure in pbuf linearization. */ + uint32_t fail_pbuf_stats; /**< Failure in pbuf allocation for statistics. */ +- uint32_t fail_pbuf_align; /**< Failure in pbuf access due to non-word alignment. */ ++ uint32_t fail_pbuf_align; /**< Failure in pbuf access due non-word alignment. */ + uint32_t fail_cipher; /**< Failure in decrypting the data. */ + uint32_t fail_auth; /**< Failure in authenticating the data. */ + uint32_t fail_seq_ovf; /**< Failure due to sequence number rollover. */ +@@ -278,7 +246,6 @@ struct nss_ipsec_cmn_sa_stats { + uint32_t fail_transform; /**< Failure in transformation; general error. */ + uint32_t fail_crypto; /**< Failure in crypto transformation. */ + uint32_t fail_cle; /**< Failure in classification; general failure. */ +- uint32_t is_stopped; /**< Indicates if SA is stopped; for example, sequence overflow. */ + }; + + /** +@@ -301,7 +268,6 @@ struct nss_ipsec_cmn_ctx_stats { + uint32_t exceptioned; /**< Exceptioned to host. */ + uint32_t linearized; /**< Linearized packets. */ + uint32_t redirected; /**< Redirected from inline. */ +- uint32_t dropped; /**< Total dropped packets. */ + uint32_t fail_sa; /**< Failed to find SA. */ + uint32_t fail_flow; /**< Failed to find flow. */ + uint32_t fail_stats; /**< Failed to send statistics. */ +@@ -309,9 +275,6 @@ struct nss_ipsec_cmn_ctx_stats { + uint32_t fail_transform; /**< Failed to produce output. */ + uint32_t fail_linearized; /**< Failed to linearize. */ + uint32_t fail_mdata_ver; /**< Invalid metadata version. */ +- uint32_t fail_ctx_active; /**< Failed to queue as context is not active. */ +- uint32_t fail_pbuf_crypto; /**< Failed to allocate pbuf for crypto operation. */ +- uint32_t fail_queue_crypto; /**< Failed to queue pbuf to crypto pnode. */ + }; + + /** +@@ -368,16 +331,6 @@ struct nss_ipsec_cmn_mdata { + }; + + /** +- * nss_ipsec_cmn_stats_notification +- * IPsec common transmission statistics structure. +- */ +-struct nss_ipsec_cmn_stats_notification { +- uint64_t stats_ctx[NSS_IPSEC_CMN_STATS_MAX]; /**< Context transmission statistics. */ +- uint32_t core_id; /**< Core ID. */ +- uint32_t if_num; /**< Interface number. */ +-}; +- +-/** + * nss_ipsec_cmn_msg + * Message structure for NSS IPsec messages. + */ +@@ -466,23 +419,6 @@ extern struct nss_ctx_instance *nss_ipse + extern uint32_t nss_ipsec_cmn_get_ifnum_with_coreid(int32_t ifnum); + + /** +- * nss_ipsec_cmn_unregister_if +- * Deregisters an IPSEC tunnel interface from the NSS. +- * +- * @param[in] if_num NSS interface number. +- * +- * @return +- * None. +- * +- * @dependencies +- * The tunnel interface must have been previously registered. +- * +- * @return +- * True if successful, else false. +- */ +-extern bool nss_ipsec_cmn_unregister_if(uint32_t if_num); +- +-/** + * nss_ipsec_cmn_register_if + * Registers the IPsec interface with the NSS for sending and + * receiving messages. +@@ -510,26 +446,25 @@ extern struct nss_ctx_instance *nss_ipse + uint32_t features, enum nss_dynamic_interface_type type, void *app_data); + + /** +- * nss_ipsec_cmn_notify_unregister +- * Deregisters the message notifier from the HLOS driver. +- * +- * @datatypes +- * nss_ctx_instance +- * +- * @param[in,out] ctx Pointer to the context of the HLOS driver. +- * @param[in] if_num NSS interface number. ++ * nss_ipsec_cmn_unregister_if ++ * Deregisters a IPSEC tunnel interface from the NSS. + * ++ * @param[in] if_num NSS interface number. ++. * + * @return + * None. + * + * @dependencies +- * The message notifier must have been previously registered. ++ * The tunnel interface must have been previously registered. ++ * ++ * @return ++ * True if successful, else false. + */ +-extern void nss_ipsec_cmn_notify_unregister(struct nss_ctx_instance *ctx, uint32_t if_num); ++extern bool nss_ipsec_cmn_unregister_if(uint32_t if_num); + + /** + * nss_ipsec_cmn_notify_register +- * Registers an event callback to handle notifications from the IPsec firmware package. ++ * Register an event callback to handle notification from IPsec firmware package. + * + * @datatypes + * nss_ipsec_cmn_msg_callback_t \n +@@ -539,11 +474,29 @@ extern void nss_ipsec_cmn_notify_unregis + * @param[in] app_data Pointer to the application context. + * + * @return +- * Pointer to the NSS core context. ++ * Pointer to NSS core context. + */ + extern struct nss_ctx_instance *nss_ipsec_cmn_notify_register(uint32_t ifnum, nss_ipsec_cmn_msg_callback_t cb, void *app_data); + + /** ++ * nss_ipsec_cmn_notify_unregister ++ * Deregisters the message notifier from the HLOS driver. ++ * ++ * @datatypes ++ * nss_ctx_instance ++ * ++ * @param[in,out] ctx Pointer to the context of the HLOS driver. ++ * @param[in] if_num NSS interface number. ++ * ++ * @return ++ * None. ++ * ++ * @dependencies ++ * The message notifier must have been previously registered. ++ */ ++extern void nss_ipsec_cmn_notify_unregister(struct nss_ctx_instance *ctx, uint32_t if_num); ++ ++/** + * nss_ipsec_cmn_msg_init + * Initializes an IPsec message. + * +@@ -657,34 +610,6 @@ extern bool nss_ipsec_cmn_ppe_port_confi + bool nss_ipsec_cmn_ppe_mtu_update(struct nss_ctx_instance *ctx, uint32_t if_num, uint16_t mtu, uint16_t mru); + + /** +- * nss_ipsec_cmn_stats_unregister_notifier +- * Deregisters a statistics notifier. +- * +- * @datatypes +- * notifier_block +- * +- * @param[in] nb Notifier block. +- * +- * @return +- * 0 on success or non-zero on failure. +- */ +-extern int nss_ipsec_cmn_stats_unregister_notifier(struct notifier_block *nb); +- +-/** +- * nss_ipsec_cmn_stats_register_notifier +- * Registers a statistics notifier. +- * +- * @datatypes +- * notifier_block +- * +- * @param[in] nb Notifier block. +- * +- * @return +- * 0 on success or non-zero on failure. +- */ +-extern int nss_ipsec_cmn_stats_register_notifier(struct notifier_block *nb); +- +-/** + * @} + */ + +--- a/exports/nss_ipv4.h ++++ b/exports/nss_ipv4.h +@@ -1,12 +1,9 @@ + /* + ************************************************************************** +- * Copyright (c) 2014-2021, The Linux Foundation. All rights reserved. +- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. +- * ++ * Copyright (c) 2014-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +- * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +@@ -29,116 +26,13 @@ + #include "nss_stats_public.h" + #endif + ++#include "nss_fw_version.h" ++ + /** + * @addtogroup nss_ipv4_subsystem + * @{ + */ + +-/* +- * IPv4 connection flags (to be used with nss_ipv4_create::flags). +- */ +-#define NSS_IPV4_CREATE_FLAG_NO_SEQ_CHECK 0x01 +- /**< Rule for not checking sequence numbers. */ +-#define NSS_IPV4_CREATE_FLAG_BRIDGE_FLOW 0x02 +- /**< Rule that indicates pure bridge flow (no routing is involved). */ +-#define NSS_IPV4_CREATE_FLAG_ROUTED 0x04 /**< Rule for a routed connection. */ +- +-#define NSS_IPV4_CREATE_FLAG_DSCP_MARKING 0x08 /**< Rule for DSCP marking. */ +-#define NSS_IPV4_CREATE_FLAG_VLAN_MARKING 0x10 /**< Rule for VLAN marking. */ +-#define NSS_IPV4_CREATE_FLAG_QOS_VALID 0x20 /**< Rule for QoS is valid. */ +- +-/** +- * nss_ipv4_create +- * Information for an IPv4 flow or connection create rule. +- * +- * All fields must be passed in host-endian order. +- */ +-struct nss_ipv4_create { +- int32_t src_interface_num; +- /**< Source interface number (virtual or physical). */ +- int32_t dest_interface_num; +- /**< Destination interface number (virtual or physical). */ +- int32_t protocol; /**< L4 protocol, e.g., TCP or UDP. */ +- uint32_t flags; /**< Flags associated with this rule. */ +- uint32_t from_mtu; /**< MTU of the incoming interface. */ +- uint32_t to_mtu; /**< MTU of the outgoing interface. */ +- uint32_t src_ip; /**< Source IP address. */ +- int32_t src_port; /**< Source L4 port, e.g., TCP or UDP port. */ +- uint32_t src_ip_xlate; /**< Translated source IP address (used with SNAT). */ +- int32_t src_port_xlate; /**< Translated source L4 port (used with SNAT). */ +- uint32_t dest_ip; /**< Destination IP address. */ +- int32_t dest_port; /**< Destination L4 port, e.g., TCP or UDP port. */ +- uint32_t dest_ip_xlate; +- /**< Translated destination IP address (used with DNAT). */ +- int32_t dest_port_xlate; +- /**< Translated destination L4 port (used with DNAT). */ +- uint8_t src_mac[ETH_ALEN]; +- /**< Source MAC address. */ +- uint8_t dest_mac[ETH_ALEN]; +- /**< Destination MAC address. */ +- uint8_t src_mac_xlate[ETH_ALEN]; +- /**< Translated source MAC address (post-routing). */ +- uint8_t dest_mac_xlate[ETH_ALEN]; +- /**< Translated destination MAC address (post-routing). */ +- uint8_t flow_window_scale; /**< Window scaling factor (TCP). */ +- uint32_t flow_max_window; /**< Maximum window size (TCP). */ +- uint32_t flow_end; /**< TCP window end. */ +- uint32_t flow_max_end; /**< TCP window maximum end. */ +- uint32_t flow_pppoe_if_exist; +- /**< Flow direction: PPPoE interface existence flag. */ +- int32_t flow_pppoe_if_num; +- /**< Flow direction: PPPoE interface number. */ +- uint16_t ingress_vlan_tag; /**< Ingress VLAN tag expected for this flow. */ +- uint8_t return_window_scale; +- /**< Window scaling factor of the return direction (TCP). */ +- uint32_t return_max_window; +- /**< Maximum window size of the return direction. */ +- uint32_t return_end; +- /**< Flow end for the return direction. */ +- uint32_t return_max_end; +- /**< Flow maximum end for the return direction. */ +- uint32_t return_pppoe_if_exist; +- /**< Return direction: PPPoE interface existence flag. */ +- int32_t return_pppoe_if_num; +- /**< Return direction: PPPoE interface number. */ +- uint16_t egress_vlan_tag; /**< Egress VLAN tag expected for this flow. */ +- uint8_t spo_needed; /**< Indicates whether SPO is required. */ +- struct net_device *top_ndev; /**< Netdevice associated with the top interface. */ +- uint32_t param_a1; /**< Custom parameter 1. */ +- uint32_t param_a2; /**< Custom parameter 2. */ +- uint32_t param_a3; /**< Custom parameter 3. */ +- uint32_t param_a4; /**< Custom parameter 4. */ +- uint32_t qos_tag; /**< Deprecated, will be removed soon. */ +- uint32_t flow_qos_tag; /**< QoS tag value for the flow direction. */ +- uint32_t return_qos_tag; /**< QoS tag value for the return direction. */ +- uint8_t dscp_itag; /**< DSCP marking tag. */ +- uint8_t dscp_imask; /**< DSCP marking input mask. */ +- uint8_t dscp_omask; /**< DSCP marking output mask. */ +- uint8_t dscp_oval; /**< DSCP marking output value. */ +- uint16_t vlan_itag; /**< VLAN marking tag. */ +- uint16_t vlan_imask; /**< VLAN marking input mask. */ +- uint16_t vlan_omask; /**< VLAN marking output mask. */ +- uint16_t vlan_oval; /**< VLAN marking output value. */ +- uint32_t in_vlan_tag[MAX_VLAN_DEPTH]; +- /**< Ingress VLAN tag expected for this flow. */ +- uint32_t out_vlan_tag[MAX_VLAN_DEPTH]; +- /**< Egress VLAN tag expected for this flow. */ +- uint8_t flow_dscp; /**< IP DSCP value for the flow direction. */ +- uint8_t return_dscp; /**< IP DSCP value for the return direction. */ +-}; +- +-/** +- * nss_ipv4_destroy +- * Information for an IPv4 flow or connection destroy rule. +- */ +-struct nss_ipv4_destroy { +- int32_t protocol; /**< L4 protocol ID. */ +- uint32_t src_ip; /**< Source IP address. */ +- int32_t src_port; /**< Source L4 port, e.g., TCP or UDP port. */ +- uint32_t dest_ip; /**< Destination IP address. */ +- int32_t dest_port; /**< Destination L4 port, e.g., TCP or UDP port. */ +-}; +- + /** + * nss_ipv4_message_types + * IPv4 bridge and routing rule message types. +@@ -219,12 +113,6 @@ enum nss_ipv4_stats_types { + /**< Number of IPv4 multicast connection destroy requests that missed the cache. */ + NSS_IPV4_STATS_MC_CONNECTION_FLUSHES, + /**< Number of IPv4 multicast connection flushes. */ +- NSS_IPV4_STATS_CONNECTION_CREATE_INVALID_MIRROR_IFNUM, +- /**< Number of IPv4 mirror connection requests with an invalid interface number. */ +- NSS_IPV4_STATS_CONNECTION_CREATE_INVALID_MIRROR_IFTYPE, +- /**< Number of IPv4 mirror connection requests with an invalid interface type. */ +- NSS_IPV4_STATS_MIRROR_FAILURES, +- /**< Number of IPv4 mirror failures. */ + NSS_IPV4_STATS_MAX, + /**< Maximum message type. */ + }; +@@ -252,18 +140,17 @@ enum nss_ipv4_stats_types { + * carries an IPv4 payload within it. + */ + #define NSS_IPV4_RULE_CREATE_FLAG_L2_ENCAP 0x80 ++ + #define NSS_IPV4_RULE_CREATE_FLAG_DROP 0x100 + /**< Rule to drop packets. */ + #define NSS_IPV4_RULE_CREATE_FLAG_EXCEPTION 0x200 + /**< Rule to except packets. */ ++ + #define NSS_IPV4_RULE_CREATE_FLAG_SRC_INTERFACE_CHECK 0x400 + /**< Check the source interface for the rule. */ ++ + #define NSS_IPV4_RULE_CREATE_FLAG_NO_SRC_IDENT 0x800 + /**< Zero out the source identifier for the rule. */ +-#define NSS_IPV4_RULE_CREATE_FLAG_NO_MAC 0x1000 +- /**< Flag to bypass writing MAC addresses. */ +-#define NSS_IPV4_RULE_CREATE_FLAG_EMESH_SP 0x2000 +- /**< Mark rule as E-MESH Service Prioritization valid. */ + + /* + * Validity flags for rule creation. +@@ -287,16 +174,11 @@ enum nss_ipv4_stats_types { + /**< Destination MAC address fields are valid. */ + #define NSS_IPV4_RULE_CREATE_IGS_VALID 0x800 + /**< Ingress shaping fields are valid. */ +-#define NSS_IPV4_RULE_CREATE_IDENTIFIER_VALID 0x1000 +- /**< Identifier is valid. */ +-#define NSS_IPV4_RULE_CREATE_MIRROR_VALID 0x2000 /**< Mirror fields are valid. */ + + /* + * Multicast command rule flags + */ + #define NSS_IPV4_MC_RULE_CREATE_FLAG_MC_UPDATE 0x01 /**< Multicast rule update. */ +-#define NSS_IPV4_MC_RULE_CREATE_FLAG_MC_EMESH_SP 0x02 +- /**< Mark multicast rule as E-MESH Service Prioritization valid. */ + + /* + * Multicast command validity flags +@@ -344,23 +226,6 @@ enum nss_ipv4_stats_types { + #define NSS_IPV4_SRC_MAC_RETURN_VALID 0x02 + /**< MAC address for the return interface is valid. */ + +-/* +- * Identifier valid flags (to be used with identifier_valid_flags field of nss_ipv4_identifier_rule structure) +- */ +-#define NSS_IPV4_FLOW_IDENTIFIER_VALID 0x01 +- /**< Identifier for flow direction is valid. */ +-#define NSS_IPV4_RETURN_IDENTIFIER_VALID 0x02 +- /**< Identifier for return direction is valid. */ +- +-/* +- * Mirror valid flags (to be used with the valid field of nss_ipv4_mirror_rule structure) +- */ +-#define NSS_IPV4_MIRROR_FLOW_VALID 0x01 +- /**< Mirror interface number for the flow direction is valid. */ +-#define NSS_IPV4_MIRROR_RETURN_VALID 0x02 +- /**< Mirror interface number for the return direction is valid. */ +- +- + /** + * nss_ipv4_5tuple + * Common 5-tuple information. +@@ -522,29 +387,6 @@ struct nss_ipv4_rps_rule { + }; + + /** +- * nss_ipv4_identifier_rule +- * Identifier rule structure. +- */ +-struct nss_ipv4_identifier_rule { +- uint32_t identifier_valid_flags; +- /**< Identifier validity flags. */ +- uint32_t flow_identifier; +- /**< Identifier for flow direction. */ +- uint32_t return_identifier; +- /**< Identifier for return direction. */ +-}; +- +-/** +- * nss_ipv4_mirror_rule +- * Mirror rule structure. +- */ +-struct nss_ipv4_mirror_rule { +- uint32_t valid; /**< Mirror validity flags. */ +- nss_if_num_t flow_ifnum; /**< Flow mirror interface number. */ +- nss_if_num_t return_ifnum; /**< Return mirror interface number. */ +-}; +- +-/** + * nss_ipv4_error_response_types + * Error types for IPv4 messages. + */ +@@ -569,8 +411,6 @@ enum nss_ipv4_error_response_types { + NSS_IPV4_CR_HASH_BITMAP_INVALID, + NSS_IPV4_DR_HW_DECEL_FAIL_ERROR, + NSS_IPV4_CR_RETURN_EXIST_ERROR, +- NSS_IPV4_CR_INVALID_IDENTIFIER, +- NSS_IPV4_CR_EMESH_SP_CONFIG_INVALID, + NSS_IPV4_LAST + }; + +@@ -610,10 +450,6 @@ struct nss_ipv4_rule_create_msg { + /**< RPS parameter. */ + struct nss_ipv4_igs_rule igs_rule; + /**< Ingress shaping related accleration parameters. */ +- struct nss_ipv4_identifier_rule identifier; +- /**< Rule for adding identifier. */ +- struct nss_ipv4_mirror_rule mirror_rule; +- /**< Mirror rule parameter. */ + }; + + /** +@@ -900,10 +736,10 @@ enum nss_ipv4_exception_events { + NSS_IPV4_EXCEPTION_EVENT_MC_PBUF_ALLOC_FAILURE, + NSS_IPV4_EXCEPTION_EVENT_PPPOE_BRIDGE_NO_ICME, + NSS_IPV4_EXCEPTION_EVENT_PPPOE_NO_SESSION, ++#if (NSS_FW_VERSION_CODE > NSS_FW_VERSION(11,0)) + NSS_IPV4_EXCEPTION_EVENT_ICMP_IPV4_GRE_HEADER_INCOMPLETE, + NSS_IPV4_EXCEPTION_EVENT_ICMP_IPV4_ESP_HEADER_INCOMPLETE, +- NSS_IPV4_EXCEPTION_EVENT_EMESH_PRIO_MISMATCH, +- NSS_IPV4_EXCEPTION_EVENT_MC_UCAST_DMAC, ++#endif + NSS_IPV4_EXCEPTION_EVENT_MAX + }; + +@@ -958,16 +794,6 @@ struct nss_ipv4_node_sync { + + uint32_t ipv4_mc_connection_flushes; + /**< Number of multicast connection flushes. */ +- +- uint32_t ipv4_connection_create_invalid_mirror_ifnum; +- /**< Number of failed create requests with an invalid mirror interface number. */ +- +- uint32_t ipv4_connection_create_invalid_mirror_iftype; +- /**< Number of failed create requests with an invalid mirror interface type. */ +- +- uint32_t ipv4_mirror_failures; +- /**< Mirror packet failed. */ +- + uint32_t exception_events[NSS_IPV4_EXCEPTION_EVENT_MAX]; + /**< Number of exception events. */ + }; +--- a/exports/nss_ipv6.h ++++ b/exports/nss_ipv6.h +@@ -1,12 +1,9 @@ + /* + ************************************************************************** +- * Copyright (c) 2014-2021, The Linux Foundation. All rights reserved. +- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. +- * ++ * Copyright (c) 2014-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +- * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +@@ -31,126 +28,6 @@ + */ + + /** +- * Converts the format of an IPv6 address from Linux to NSS. @hideinitializer +- */ +-#define IN6_ADDR_TO_IPV6_ADDR(ipv6, in6) \ +- { \ +- ((uint32_t *)ipv6)[0] = in6.in6_u.u6_addr32[0]; \ +- ((uint32_t *)ipv6)[1] = in6.in6_u.u6_addr32[1]; \ +- ((uint32_t *)ipv6)[2] = in6.in6_u.u6_addr32[2]; \ +- ((uint32_t *)ipv6)[3] = in6.in6_u.u6_addr32[3]; \ +- } +- +-/** +- * Converts the format of an IPv6 address from NSS to Linux. @hideinitializer +- */ +-#define IPV6_ADDR_TO_IN6_ADDR(in6, ipv6) \ +- { \ +- in6.in6_u.u6_addr32[0] = ((uint32_t *)ipv6)[0]; \ +- in6.in6_u.u6_addr32[1] = ((uint32_t *)ipv6)[1]; \ +- in6.in6_u.u6_addr32[2] = ((uint32_t *)ipv6)[2]; \ +- in6.in6_u.u6_addr32[3] = ((uint32_t *)ipv6)[3]; \ +- } +- +-/** +- * Format of an IPv6 address (16 * 8 bits). +- */ +-#define IPV6_ADDR_OCTAL_FMT "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x" +- +-/** +- * Prints an IPv6 address (16 * 8 bits). +- */ +-#define IPV6_ADDR_TO_OCTAL(ipv6) ((uint16_t *)ipv6)[0], ((uint16_t *)ipv6)[1], ((uint16_t *)ipv6)[2], ((uint16_t *)ipv6)[3], ((uint16_t *)ipv6)[4], ((uint16_t *)ipv6)[5], ((uint16_t *)ipv6)[6], ((uint16_t *)ipv6)[7] +- +-/* +- * IPv6 connection flags (to be used with nss_ipv6_create::flags. +- */ +-#define NSS_IPV6_CREATE_FLAG_NO_SEQ_CHECK 0x1 +- /**< Indicates that sequence numbers are not to be checked. */ +-#define NSS_IPV6_CREATE_FLAG_BRIDGE_FLOW 0x02 +- /**< Indicates that this is a pure bridge flow (no routing is involved). */ +-#define NSS_IPV6_CREATE_FLAG_ROUTED 0x04 /**< Rule is for a routed connection. */ +-#define NSS_IPV6_CREATE_FLAG_DSCP_MARKING 0x08 /**< Rule for DSCP marking. */ +-#define NSS_IPV6_CREATE_FLAG_VLAN_MARKING 0x10 /**< Rule for VLAN marking. */ +-#define NSS_IPV6_CREATE_FLAG_QOS_VALID 0x20 /**< Rule for Valid QoS. */ +- +-/** +- * nss_ipv6_create +- * Information for an IPv6 flow or connection create rule. +- * +- * All fields must be passed in host-endian order. +- */ +-struct nss_ipv6_create { +- int32_t src_interface_num; +- /**< Source interface number (virtual or physical). */ +- int32_t dest_interface_num; +- /**< Destination interface number (virtual or physical). */ +- int32_t protocol; /**< L4 protocol, e.g., TCP or UDP,. */ +- uint32_t flags; /**< Flags associated with this rule. */ +- uint32_t from_mtu; /**< MTU of the incoming interface. */ +- uint32_t to_mtu; /**< MTU of the outgoing interface. */ +- uint32_t src_ip[4]; /**< Source IP address. */ +- int32_t src_port; /**< Source L4 port, e.g., TCP or UDP port. */ +- uint32_t dest_ip[4]; /**< Destination IP address. */ +- int32_t dest_port; /**< Destination L4 port, e.g., TCP or UDP port. */ +- uint8_t src_mac[ETH_ALEN]; /**< Source MAC address. */ +- uint8_t dest_mac[ETH_ALEN]; /**< Destination MAC address. */ +- uint8_t flow_window_scale; /**< Window scaling factor (TCP). */ +- uint32_t flow_max_window; /**< Maximum window size (TCP). */ +- uint32_t flow_end; /**< TCP window end. */ +- uint32_t flow_max_end; /**< TCP window maximum end. */ +- uint32_t flow_pppoe_if_exist; +- /**< Flow direction: PPPoE interface existence flag. */ +- int32_t flow_pppoe_if_num; +- /**< Flow direction: PPPoE interface number. */ +- uint16_t ingress_vlan_tag; +- /**< Ingress VLAN tag expected for this flow. */ +- uint8_t return_window_scale; +- /**< Window scaling factor (TCP) for the return direction. */ +- uint32_t return_max_window; +- /**< Maximum window size (TCP) for the return direction. */ +- uint32_t return_end; +- /**< End for the return direction. */ +- uint32_t return_max_end; +- /**< Maximum end for the return direction. */ +- uint32_t return_pppoe_if_exist; +- /**< Return direction: PPPoE interface existence flag. */ +- int32_t return_pppoe_if_num; +- /**< Return direction: PPPoE interface number. */ +- uint16_t egress_vlan_tag; /**< Egress VLAN tag expected for this flow. */ +- uint32_t qos_tag; /**< Deprecated; will be removed soon. */ +- uint32_t flow_qos_tag; /**< QoS tag value for flow direction. */ +- uint32_t return_qos_tag; /**< QoS tag value for the return direction. */ +- uint8_t dscp_itag; /**< DSCP marking tag. */ +- uint8_t dscp_imask; /**< DSCP marking input mask. */ +- uint8_t dscp_omask; /**< DSCP marking output mask. */ +- uint8_t dscp_oval; /**< DSCP marking output value. */ +- uint16_t vlan_itag; /**< VLAN marking tag. */ +- uint16_t vlan_imask; /**< VLAN marking input mask. */ +- uint16_t vlan_omask; /**< VLAN marking output mask. */ +- uint16_t vlan_oval; /**< VLAN marking output value. */ +- uint32_t in_vlan_tag[MAX_VLAN_DEPTH]; +- /**< Ingress VLAN tag expected for this flow. */ +- uint32_t out_vlan_tag[MAX_VLAN_DEPTH]; +- /**< Egress VLAN tag expected for this flow. */ +- uint8_t flow_dscp; /**< IP DSCP value for flow direction. */ +- uint8_t return_dscp; /**< IP DSCP value for the return direction. */ +- struct net_device *top_ndev; /**< Netdevice associated with the top interface. */ +-}; +- +-/** +- * nss_ipv6_destroy +- * Information for an IPv6 flow or connection destroy rule. +- */ +-struct nss_ipv6_destroy { +- int32_t protocol; /**< L4 protocol, e.g., TCP or UDP. */ +- uint32_t src_ip[4]; /**< Source IP address. */ +- int32_t src_port; /**< Source L4 port, e.g., TCP or UDP port. */ +- uint32_t dest_ip[4]; /**< Destination IP address. */ +- int32_t dest_port; /**< Destination L4 port, e.g., TCP or UDP port. */ +-}; +- +-/** + * nss_ipv6_stats_types + * IPv6 node statistics. + */ +@@ -199,14 +76,6 @@ enum nss_ipv6_stats_types { + /**< Number of IPv6 multicast connection destroy requests that missed the cache. */ + NSS_IPV6_STATS_MC_CONNECTION_FLUSHES, + /**< Number of IPv6 multicast connection flushes. */ +- NSS_IPV6_STATS_CONNECTION_CREATE_INVALID_MIRROR_IFNUM, +- /**< Number of IPv6 mirror connection requests with an invalid interface number. */ +- NSS_IPV6_STATS_CONNECTION_CREATE_INVALID_MIRROR_IFTYPE, +- /**< Number of IPv6 mirror connection requests with an invalid interface type. */ +- +- NSS_IPV6_STATS_MIRROR_FAILURES, +- /**< Number of IPv6 mirror failures. */ +- + NSS_IPV6_STATS_MAX, + /**< Maximum message type. */ + }; +@@ -270,14 +139,11 @@ enum nss_ipv6_dscp_map_actions { + /**< Drop packets. */ + #define NSS_IPV6_RULE_CREATE_FLAG_EXCEPTION 0x200 + /**< Rule to except packets. */ ++ + #define NSS_IPV6_RULE_CREATE_FLAG_SRC_INTERFACE_CHECK 0x400 + /**< Check the source interface for the rule. */ + #define NSS_IPV6_RULE_CREATE_FLAG_NO_SRC_IDENT 0x800 + /**< Flag to indicate NSS to ignore src_ident and use value 0 for it during rule addition. */ +-#define NSS_IPV6_RULE_CREATE_FLAG_NO_MAC 0x1000 +- /**< Flag to bypass writing MAC addresses. */ +-#define NSS_IPV6_RULE_CREATE_FLAG_EMESH_SP 0x2000 +- /**< Mark rule as E-MESH Service Prioritization valid. */ + + /* + * IPv6 rule creation validity flags. +@@ -299,15 +165,12 @@ enum nss_ipv6_dscp_map_actions { + #define NSS_IPV6_RULE_CREATE_DEST_MAC_VALID 0x400 + /**< Destination MAC address fields are valid. */ + #define NSS_IPV6_RULE_CREATE_IGS_VALID 0x800 /**< Ingress shaping fields are valid. */ +-#define NSS_IPV6_RULE_CREATE_IDENTIFIER_VALID 0x1000 /**< Identifier is valid. */ +-#define NSS_IPV6_RULE_CREATE_MIRROR_VALID 0x2000 /**< Mirror fields are valid. */ ++ + + /* + * Multicast command rule flags + */ + #define NSS_IPV6_MC_RULE_CREATE_FLAG_MC_UPDATE 0x01 /**< Multicast rule update. */ +-#define NSS_IPV6_MC_RULE_CREATE_FLAG_MC_EMESH_SP 0x02 +- /**< Mark multicast rule as E-MESH Service Prioritization valid. */ + + /* + * Multicast command validity flags +@@ -353,22 +216,6 @@ enum nss_ipv6_dscp_map_actions { + #define NSS_IPV6_SRC_MAC_RETURN_VALID 0x02 + /**< MAC address for the return interface is valid. */ + +-/* +- * Identifier valid flags (to be used with identifier_valid_flags field of nss_ipv6_identifier_rule structure) +- */ +-#define NSS_IPV6_FLOW_IDENTIFIER_VALID 0x01 +- /**< Identifier for flow direction is valid. */ +-#define NSS_IPV6_RETURN_IDENTIFIER_VALID 0x02 +- /**< Identifier for return direction is valid. */ +- +-/* +- * Mirror valid flags (to be used with the valid field of nss_ipv6_mirror_rule structure) +- */ +-#define NSS_IPV6_MIRROR_FLOW_VALID 0x01 +- /**< Mirror interface number for the flow direction is valid. */ +-#define NSS_IPV6_MIRROR_RETURN_VALID 0x02 +- /**< Mirror interface number for the return direction is valid. */ +- + /** + * nss_ipv6_exception_events + * Exception events from an IPv6 bridge or route handler. +@@ -429,12 +276,14 @@ enum nss_ipv6_exception_events { + NSS_IPV6_EXCEPTION_EVENT_TUNIPIP6_NEEDS_FRAGMENTATION, + NSS_IPV6_EXCEPTION_EVENT_PPPOE_BRIDGE_NO_ICME, + NSS_IPV6_EXCEPTION_EVENT_DONT_FRAG_SET, ++#if (NSS_FW_VERSION_CODE > NSS_FW_VERSION(11,0)) + NSS_IPV6_EXCEPTION_EVENT_REASSEMBLY_NOT_SUPPORTED, ++#endif + NSS_IPV6_EXCEPTION_EVENT_PPPOE_NO_SESSION, ++#if (NSS_FW_VERSION_CODE > NSS_FW_VERSION(11,0)) + NSS_IPV6_EXCEPTION_EVENT_ICMP_IPV6_GRE_HEADER_INCOMPLETE, + NSS_IPV6_EXCEPTION_EVENT_ICMP_IPV6_ESP_HEADER_INCOMPLETE, +- NSS_IPV6_EXCEPTION_EVENT_EMESH_PRIO_MISMATCH, +- NSS_IPV6_EXCEPTION_EVENT_MC_UCAST_DMAC, ++#endif + NSS_IPV6_EXCEPTION_EVENT_MAX + }; + +@@ -589,29 +438,6 @@ struct nss_ipv6_rps_rule { + }; + + /** +- * nss_ipv6_identifier_rule +- * Identifier rule structure. +- */ +-struct nss_ipv6_identifier_rule { +- uint32_t identifier_valid_flags; +- /**< Identifier validity flags. */ +- uint32_t flow_identifier; +- /**< Identifier for flow direction. */ +- uint32_t return_identifier; +- /**< Identifier for return direction. */ +-}; +- +-/** +- * nss_ipv6_mirror_rule +- * Mirror rule structure. +- */ +-struct nss_ipv6_mirror_rule { +- uint32_t valid; /**< Mirror validity flags. */ +- nss_if_num_t flow_ifnum; /**< Flow mirror interface number. */ +- nss_if_num_t return_ifnum; /**< Return mirror interface number. */ +-}; +- +-/** + * nss_ipv6_error_response_types + * Error types for IPv6 messages. + */ +@@ -647,24 +473,24 @@ enum nss_ipv6_error_response_types { + /**< Invalid interface for updating multicast. */ + NSS_IPV6_CR_ACCEL_MODE_CONFIG_INVALID, + /**< Invalid config value for acceleration mode. */ ++#if (NSS_FW_VERSION_CODE > NSS_FW_VERSION(11,0)) + NSS_IPV6_CR_INVALID_MSG_ERROR, + /**< Invalid message size error. */ + NSS_IPV6_CR_DSCP2PRI_PRI_INVALID, + /**< Priority value out of range error. */ + NSS_IPV6_CR_DSCP2PRI_CONFIG_INVALID, + /**< Invalid DSCP value. */ ++#endif + NSS_IPV6_CR_INVALID_RPS, + /**< Invalid RPS Value. */ + NSS_IPV6_HASH_BITMAP_INVALID, + /**< Invalid hash bitmap. */ ++#if (NSS_FW_VERSION_CODE > NSS_FW_VERSION(11,0)) + NSS_IPV6_DR_HW_DECEL_FAIL_ERROR, + /**< Hardware deceleration fail error. */ + NSS_IPV6_CR_RETURN_EXIST_ERROR, + /**< Rule creation failed because a 5-tuple return already exists. */ +- NSS_IPV6_CR_INVALID_IDENTIFIER, +- /**< Invalid identifier value. */ +- NSS_IPV6_CR_EMESH_SP_CONFIG_INVALID, +- /**< Rule creation failed because Qos tag was not set for a Emesh SP rule. */ ++#endif + NSS_IPV6_LAST + /**< Maximum number of error responses. */ + }; +@@ -705,10 +531,6 @@ struct nss_ipv6_rule_create_msg { + /**< RPS parameter. */ + struct nss_ipv6_igs_rule igs_rule; + /**< Ingress shaping related accleration parameters. */ +- struct nss_ipv6_identifier_rule identifier; +- /**< Rule for adding identifier. */ +- struct nss_ipv6_mirror_rule mirror_rule; +- /**< Mirror rule parameter. */ + }; + + /** +@@ -954,16 +776,6 @@ struct nss_ipv6_node_sync { + + uint32_t ipv6_mc_connection_flushes; + /**< Number of multicast connection flushes. */ +- +- uint32_t ipv6_connection_create_invalid_mirror_ifnum; +- /**< Number of failed create requests with an invalid mirror interface number. */ +- +- uint32_t ipv6_connection_create_invalid_mirror_iftype; +- /**< Number of failed create requests with an invalid mirror interface type. */ +- +- uint32_t ipv6_mirror_failures; +- /**< Mirror packet failed. */ +- + uint32_t exception_events[NSS_IPV6_EXCEPTION_EVENT_MAX]; + /**< Number of exception events. */ + }; +--- a/exports/nss_lso_rx.h ++++ b/exports/nss_lso_rx.h +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the +@@ -17,7 +17,7 @@ + */ + + /* +- * @file nss_lso_rx.h ++ * nss_lso_rx.h + * NSS driver LSO (Large Send Offload) Rx header file. + */ + +--- a/exports/nss_map_t.h ++++ b/exports/nss_map_t.h +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -37,20 +37,6 @@ + #define NSS_MAX_MAP_T_DYNAMIC_INTERFACES 4 + + /** +- * MAP-T metadata flag. +- */ +-#define NSS_MAPT_MDATA_FLAG_DF_BIT (1 << 0) +- +-/** +- * nss_map_t_mdata +- * MAP-T metadata +- */ +-struct nss_map_t_mdata { +- uint16_t flags; /**< Metadata flags. */ +- uint16_t res[6]; /**< Reserved for future use. */ +-}; +- +-/** + * nss_map_t_msg_types + * Message types for MAP-T requests and responses. + */ +--- a/exports/nss_mirror.h ++++ b/exports/nss_mirror.h +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the +@@ -79,20 +79,6 @@ enum nss_mirror_error_type { + }; + + /** +- * nss_mirror_stats +- * Mirror interface debug statistics. +- */ +-enum nss_mirror_stats { +- NSS_MIRROR_STATS_PKTS, /**< Number of packets exceptioned to host. */ +- NSS_MIRROR_STATS_BYTES, /**< Number of bytes exceptioned to host. */ +- NSS_MIRROR_STATS_TX_SEND_FAIL, /**< Transmit send failures. */ +- NSS_MIRROR_STATS_DEST_LOOKUP_FAIL, /**< Destination lookup failures. */ +- NSS_MIRROR_STATS_MEM_ALLOC_FAIL, /**< Memory allocation failures. */ +- NSS_MIRROR_STATS_COPY_FAIL, /**< Copy failures. */ +- NSS_MIRROR_STATS_MAX /**< Maximum statistics count. */ +-}; +- +-/** + * nss_mirror_configure_msg + * Mirror interface configuration information. + */ +@@ -134,16 +120,6 @@ struct nss_mirror_stats_sync_msg { + }; + + /** +- * nss_mirror_stats_notification +- * Mirror transmission statistics structure. +- */ +-struct nss_mirror_stats_notification { +- uint64_t stats_ctx[NSS_MIRROR_STATS_MAX]; /**< Context transmission statistics. */ +- uint32_t core_id; /**< Core ID. */ +- uint32_t if_num; /**< Interface number. */ +-}; +- +-/** + * nss_mirror_msg + * Data for sending and receiving mirror interface messages. + */ +@@ -230,17 +206,6 @@ extern nss_tx_status_t nss_mirror_tx_msg + extern nss_tx_status_t nss_mirror_tx_msg_sync(struct nss_ctx_instance *nss_ctx, struct nss_mirror_msg *msg); + + /** +- * nss_mirror_unregister_if +- * Deregisters a mirror interface from the NSS. +- * +- * @param[in] if_num NSS interface number. +- * +- * @return +- * None. +- */ +-extern void nss_mirror_unregister_if(uint32_t if_num); +- +-/** + * nss_mirror_register_if + * Registers a mirror interface with the NSS for sending and receiving messages. + * +@@ -264,6 +229,17 @@ extern struct nss_ctx_instance *nss_mirr + struct net_device *netdev, uint32_t features); + + /** ++ * nss_mirror_unregister_if ++ * Deregisters a mirror interface from the NSS. ++ * ++ * @param[in] if_num NSS interface number. ++ * ++ * @return ++ * None. ++ */ ++extern void nss_mirror_unregister_if(uint32_t if_num); ++ ++/** + * nss_mirror_verify_if_num + * Verify whether the interface is an mirror interface or not. + * +@@ -284,34 +260,6 @@ extern bool nss_mirror_verify_if_num(uin + extern void nss_mirror_register_handler(void); + + /** +- * nss_mirror_stats_unregister_notifier +- * Deregisters a statistics notifier. +- * +- * @datatypes +- * notifier_block +- * +- * @param[in] nb Notifier block. +- * +- * @return +- * 0 on success or non-zero on failure. +- */ +-extern int nss_mirror_stats_unregister_notifier(struct notifier_block *nb); +- +-/** +- * nss_mirror_stats_register_notifier +- * Registers a statistics notifier. +- * +- * @datatypes +- * notifier_block +- * +- * @param[in] nb Notifier block. +- * +- * @return +- * 0 on success or non-zero on failure. +- */ +-extern int nss_mirror_stats_register_notifier(struct notifier_block *nb); +- +-/** + * @} + */ + #endif +--- a/exports/nss_n2h.h ++++ b/exports/nss_n2h.h +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2014-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2014-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -62,7 +62,6 @@ struct nss_n2h_cfg_pvt { + struct nss_n2h_payload_info empty_buf_pool_info; /**< Empty buffer pool information. */ + struct nss_n2h_payload_info empty_paged_buf_pool_info; /**< Paged buffer pool information. */ + int wifi_pool; /**< Size of the empty Wi-Fi buffer pool. */ +- int shaper_pool; /**< Size of the empty shaper pool. */ + int response; /**< Response from the firmware. */ + }; + +@@ -74,40 +73,43 @@ struct nss_n2h_cfg_pvt { + */ + enum nss_n2h_stats_types { + NSS_N2H_STATS_QUEUE_DROPPED = NSS_STATS_NODE_MAX, +- /**< Number of packets dropped because the exception queue is too full. */ +- NSS_N2H_STATS_TOTAL_TICKS, /**< Total clock ticks spend inside the N2H. */ +- NSS_N2H_STATS_WORST_CASE_TICKS, /**< Worst case iteration of the exception path in ticks. */ +- NSS_N2H_STATS_ITERATIONS, /**< Number of iterations around the N2H. */ +- NSS_N2H_STATS_PBUF_OCM_TOTAL_COUNT, /**< Number of pbuf OCM total count. */ +- NSS_N2H_STATS_PBUF_OCM_FREE_COUNT, /**< Number of pbuf OCM free count. */ ++ /* Number of packets dropped because the exception queue is too full */ ++ NSS_N2H_STATS_TOTAL_TICKS, /* Total clock ticks spend inside the N2H */ ++ NSS_N2H_STATS_WORST_CASE_TICKS, /* Worst case iteration of the exception path in ticks */ ++ NSS_N2H_STATS_ITERATIONS, /* Number of iterations around the N2H */ ++ + NSS_N2H_STATS_PBUF_OCM_ALLOC_FAILS_WITH_PAYLOAD, +- /**< Number of pbuf OCM allocations that have failed with payload. */ ++ /* Number of pbuf ocm allocations that have failed with payload */ ++ NSS_N2H_STATS_PBUF_OCM_FREE_COUNT, /* Number of pbuf ocm free count */ ++ NSS_N2H_STATS_PBUF_OCM_TOTAL_COUNT, /* Number of pbuf ocm total count */ + NSS_N2H_STATS_PBUF_OCM_ALLOC_FAILS_NO_PAYLOAD, +- /**< Number of pbuf OCM allocations that have failed without payload. */ +- NSS_N2H_STATS_PBUF_DEFAULT_TOTAL_COUNT, /**< Number of pbuf default total count. */ +- NSS_N2H_STATS_PBUF_DEFAULT_FREE_COUNT, /**< Number of pbuf default free count. */ ++ /* Number of pbuf ocm allocations that have failed without payload */ ++ + NSS_N2H_STATS_PBUF_DEFAULT_ALLOC_FAILS_WITH_PAYLOAD, +- /**< Number of pbuf default allocations that have failed with payload. */ ++ /* Number of pbuf default allocations that have failed with payload */ ++ ++ NSS_N2H_STATS_PBUF_DEFAULT_FREE_COUNT, /* Number of pbuf default free count */ ++ NSS_N2H_STATS_PBUF_DEFAULT_TOTAL_COUNT, /* Number of pbuf default total count */ + NSS_N2H_STATS_PBUF_DEFAULT_ALLOC_FAILS_NO_PAYLOAD, +- /**< Number of pbuf default allocations that have failed without payload. */ ++ /* Number of pbuf default allocations that have failed without payload */ + +- NSS_N2H_STATS_PAYLOAD_ALLOC_FAILS, /**< Number of pbuf allocations that have failed because there were no free payloads. */ +- NSS_N2H_STATS_PAYLOAD_FREE_COUNT, /**< Number of free payloads that exist. */ ++ NSS_N2H_STATS_PAYLOAD_ALLOC_FAILS, /* Number of pbuf allocations that have failed because there were no free payloads */ ++ NSS_N2H_STATS_PAYLOAD_FREE_COUNT, /* Number of free payloads that exist */ + +- NSS_N2H_STATS_H2N_CONTROL_PACKETS, /**< Control packets received from HLOS. */ +- NSS_N2H_STATS_H2N_CONTROL_BYTES, /**< Control bytes received from HLOS. */ +- NSS_N2H_STATS_N2H_CONTROL_PACKETS, /**< Control packets sent to HLOS. */ +- NSS_N2H_STATS_N2H_CONTROL_BYTES, /**< Control bytes sent to HLOS. */ +- +- NSS_N2H_STATS_H2N_DATA_PACKETS, /**< Data packets received from HLOS. */ +- NSS_N2H_STATS_H2N_DATA_BYTES, /**< Data bytes received from HLOS. */ +- NSS_N2H_STATS_N2H_DATA_PACKETS, /**< Data packets sent to HLOS. */ +- NSS_N2H_STATS_N2H_DATA_BYTES, /**< Data bytes sent to HLOS. */ +- NSS_N2H_STATS_N2H_TOT_PAYLOADS, /**< Number of payloads in NSS. */ +- NSS_N2H_STATS_N2H_INTERFACE_INVALID, /**< Number of bad interface access. */ +- NSS_N2H_STATS_ENQUEUE_RETRIES, /**< Number of enqueue retries by N2H. */ ++ NSS_N2H_STATS_H2N_CONTROL_PACKETS, /* Control packets received from HLOS */ ++ NSS_N2H_STATS_H2N_CONTROL_BYTES, /* Control bytes received from HLOS */ ++ NSS_N2H_STATS_N2H_CONTROL_PACKETS, /* Control packets sent to HLOS */ ++ NSS_N2H_STATS_N2H_CONTROL_BYTES, /* Control bytes sent to HLOS */ ++ ++ NSS_N2H_STATS_H2N_DATA_PACKETS, /* Data packets received from HLOS */ ++ NSS_N2H_STATS_H2N_DATA_BYTES, /* Data bytes received from HLOS */ ++ NSS_N2H_STATS_N2H_DATA_PACKETS, /* Data packets sent to HLOS */ ++ NSS_N2H_STATS_N2H_DATA_BYTES, /* Data bytes sent to HLOS */ ++ NSS_N2H_STATS_N2H_TOT_PAYLOADS, /* No. of payloads in NSS */ ++ NSS_N2H_STATS_N2H_INTERFACE_INVALID, /* No. of bad interface access */ ++ NSS_N2H_STATS_ENQUEUE_RETRIES, /* No. of enqueue retries by N2H */ + +- NSS_N2H_STATS_MAX, /**< Maximum message type. */ ++ NSS_N2H_STATS_MAX, + }; + + /** +@@ -133,7 +135,6 @@ enum nss_n2h_metadata_types { + NSS_TX_METADATA_TYPE_N2H_QUEUE_LIMIT_CFG, + NSS_TX_METADATA_TYPE_N2H_PAGED_BUFFER_POOL_INIT, + NSS_TX_METADATA_TYPE_N2H_HOST_BACK_PRESSURE_CFG, +- NSS_TX_METADATA_TYPE_N2H_SHAPER_POOL_CFG, + NSS_METADATA_TYPE_N2H_MAX, + }; + +@@ -362,24 +363,6 @@ struct nss_n2h_host_back_pressure { + }; + + /** +- * nss_n2h_shaper_mem_cfg_msg +- * Shaper memory configuration message. +- */ +-struct nss_n2h_shaper_mem_cfg_msg { +- uint32_t mem_blk_size; /**< Size of the memory block. */ +- uint32_t num_blks; /**< Number of memory blocks. */ +- +- uint32_t pool_addr[MAX_PAGES_PER_MSG]; +- /**< Buffer addresses. */ +- nss_ptr_t pool_vaddr[MAX_PAGES_PER_MSG]; +- /**< Virtual addresses of the buffers. */ +-#ifndef __LP64__ +- uint32_t padding[MAX_PAGES_PER_MSG]; +- /**< Padding that fits up to 64 bits. Do not reuse. */ +-#endif +-}; +- +-/** + * nss_n2h_msg + * Data for sending and receiving N2H messages. + */ +@@ -426,8 +409,6 @@ struct nss_n2h_msg { + /**< Paged buffer pool initialization. */ + struct nss_n2h_host_back_pressure host_bp_cfg; + /**< Host back pressure configuration. */ +- struct nss_n2h_shaper_mem_cfg_msg shaper_mem_cfg; +- /**< Shaper memory configuration. */ + } msg; /**< Message payload. */ + }; + +--- a/exports/nss_phy_if.h ++++ b/exports/nss_phy_if.h +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2020, 2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the +@@ -17,7 +17,7 @@ + */ + + /** +- * @file nss_phy_if.h ++ * @file nss_phy_if.h.h + * NSS physical interface definitions. + */ + +--- a/exports/nss_ppe.h ++++ b/exports/nss_ppe.h +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2016-2018, 2020-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2016-2018, 2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -22,8 +22,6 @@ + #ifndef _NSS_PPE_H_ + #define _NSS_PPE_H_ + +-typedef int32_t nss_ppe_port_t; +- + /** + * @addtogroup nss_ppe_subsystem + * @{ +@@ -54,38 +52,9 @@ enum nss_ppe_sc_type { + NSS_PPE_SC_PTP, /**< Service code for PTP packets. */ + NSS_PPE_SC_VLAN_FILTER_BYPASS, /**< VLAN filter bypass for bridge flows between 2 different VSIs. */ + NSS_PPE_SC_L3_EXCEPT, /**< Indicate exception post tunnel/TAP operation. */ +- NSS_PPE_SC_SPF_BYPASS, /**< Source port filtering bypass in PPE. */ + NSS_PPE_SC_MAX, /**< Maximum service code. */ + }; + +-/** +- * nss_ppe_stats_unregister_notifier +- * Deregisters a statistics notifier. +- * +- * @datatypes +- * notifier_block +- * +- * @param[in] nb Notifier block. +- * +- * @return +- * 0 on success or non-zero on failure. +- */ +-extern int nss_ppe_stats_unregister_notifier(struct notifier_block *nb); +- +-/** +- * nss_ppe_stats_register_notifier +- * Registers a statistics notifier. +- * +- * @datatypes +- * notifier_block +- * +- * @param[in] nb Notifier block. +- * +- * @return +- * 0 on success or non-zero on failure. +- */ +-extern int nss_ppe_stats_register_notifier(struct notifier_block *nb); +- + /** @} */ /* end_addtogroup nss_ppe_subsystem */ + + #endif /* _NSS_PPE_H_ */ +--- a/exports/nss_project.h ++++ b/exports/nss_project.h +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2017-2018, 2021 The Linux Foundation. All rights reserved. ++ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -38,12 +38,6 @@ + #define NSS_PROJECT_IRQS_PER_MESSAGE 32 + + /** +- * Maximum possible value of priority after classification +- * at an ingress interface. +- */ +-#define NSS_PROJECT_PRI_MQ_MAP_MAX_SIZE 16 +- +-/** + * nss_project_message_types + * Project message types. + */ +@@ -52,8 +46,6 @@ enum nss_project_message_types { + /**< Message to enable or disable worker thread statistics. */ + NSS_PROJECT_MSG_WT_STATS_NOTIFY, + /**< NSS to HLOS message containing worker thread statistics. */ +- NSS_PROJECT_MSG_SET_QUEUE_PRI_MAP_CFG, +- /**< Message to configure priority to multi-queue mapping. */ + NSS_PROJECT_MSG_MAX, + }; + +@@ -68,8 +60,6 @@ enum nss_project_error_types { + /**< The firmware does not support worker thread statistics. */ + NSS_PROJECT_ERROR_WT_STATS_REDUNDANT_ENABLE, + /**< The firmware received a redundant request to enable worker thread statistics. */ +- NSS_PROJECT_ERROR_MQ_NUMBER_INVALID, +- /**< The firmware received an invalid multi-queue number. */ + NSS_PROJECT_ERROR_MAX, + }; + +@@ -121,15 +111,6 @@ struct nss_project_msg_wt_stats_notify { + }; + + /** +- * nss_project_msg_pri_mq_map_cfg +- * NSS priority to multi-queue mapping configuration. +- */ +-struct nss_project_msg_pri_mq_map_cfg { +- uint8_t pri_mq_map[NSS_PROJECT_PRI_MQ_MAP_MAX_SIZE]; +- /**< Priority to multi-queue mapping array. */ +-}; +- +-/** + * nss_project_msg + * General message structure for project messages. + */ +@@ -144,8 +125,6 @@ struct nss_project_msg { + /**< Enable or disable worker thread statistics. */ + struct nss_project_msg_wt_stats_notify wt_stats_notify; + /**< One-way worker thread statistics message. */ +- struct nss_project_msg_pri_mq_map_cfg pri_mq_map_cfg; +- /**< Configure priority to multi-queue message. */ + } msg; /**< Message payload. */ + }; + +@@ -191,17 +170,6 @@ void nss_project_unregister_sysctl(void) + void nss_project_register_handler(struct nss_ctx_instance *nss_ctx); + + /** +- * nss_project_pri_mq_map_configure +- * Configures priority to multi-queue mapping. +- * +- * @param[in] nss_ctx Pointer to the NSS context. +- * +- * @return +- * Status of the configuration update operation. +- */ +-extern nss_tx_status_t nss_project_pri_mq_map_configure(struct nss_ctx_instance *nss_ctx); +- +-/** + * @} + */ + +--- a/exports/nss_qrfs.h ++++ b/exports/nss_qrfs.h +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2017-2018, 2021 The Linux Foundation. All rights reserved. ++ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -110,7 +110,6 @@ struct nss_qrfs_msg { + } msg; /**< Message payload. */ + }; + +-#ifdef __KERNEL__ + /** + * Callback function for receiving QRFS messages. + * +@@ -177,23 +176,6 @@ void nss_qrfs_notify_unregister(int core + * Status of the Tx operation. + */ + nss_tx_status_t nss_qrfs_set_flow_rule(struct sk_buff *skb, uint32_t cpu, uint32_t action); +-/** +- * nss_qrfs_configure_flow_rule +- * Configures and sends a QRFS message to the NSS core to configure(add/remove) the flow rule. +- * +- * @param[in] dst_addr Destination IP address. +- * @param[in] src_addr Source IP address. +- * @param[in] dst_port Destination port. +- * @param[in] src_port Source port. +- * @param[in] version IP version. +- * @param[in] proto Protocol. +- * @param[in] cpu CPU number to be offloaded to. +- * @param[in] type Type of action to perform on the flow table, can be add or delete. +- * +- * @return +- * Status of the Tx operation. +- */ +-nss_tx_status_t nss_qrfs_configure_flow_rule(uint32_t *dst_addr, uint32_t *src_addr, uint16_t dst_port, uint16_t src_port, uint32_t version, uint16_t proto, uint16_t cpu, enum nss_qrfs_msg_types type); + + /** + * nss_qrfs_init +@@ -208,5 +190,4 @@ void nss_qrfs_init(void); + * @} + */ + +-#endif + #endif /* __NSS_QRFS_H */ +--- a/exports/nss_qvpn.h ++++ b/exports/nss_qvpn.h +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2019, 2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -27,6 +27,10 @@ + * @{ + */ + ++#define NSS_QVPN_INTERFACE_MAX_LONG BITS_TO_LONGS(NSS_MAX_NET_INTERFACES) /**< QVPN interface mapping bits. */ ++#define NSS_QVPN_STATS_MAX_LINES (NSS_STATS_NODE_MAX + 32) /**< Maxminum number of lines for QVPN statistics dump. */ ++#define NSS_QVPN_STATS_SIZE_PER_IF (NSS_STATS_MAX_STR_LENGTH * NSS_QVPN_STATS_MAX_LINES) /**< Total number of statistics per QVPN interface. */ ++ + #define NSS_QVPN_CMDS_MAX 10 /**< Maximum number of QVPN commands supported. */ + #define NSS_QVPN_VPN_HDR_HEAD_SIZE_MAX 64 /**< Maximum size of QVPN header. */ + #define NSS_QVPN_VPN_HDR_TAIL_SIZE_MAX 32 /**< Maximum size of QVPN tail. */ +@@ -290,16 +294,6 @@ struct nss_qvpn_stats_sync_msg { + }; + + /** +- * nss_qvpn_stats_notification +- * QVPN transmission statistics structure. +- */ +-struct nss_qvpn_stats_notification { +- uint64_t stats_ctx[NSS_STATS_NODE_MAX]; /**< Context transmission statistics. */ +- uint32_t core_id; /**< Core ID. */ +- uint32_t if_num; /**< Interface number. */ +-}; +- +-/** + * nss_qvpn_msg + * QVPN message structure for configuration and statistics. + */ +@@ -426,17 +420,6 @@ typedef void (*nss_qvpn_callback_t)(stru + typedef void (*nss_qvpn_msg_callback_t)(void *app_data, struct nss_cmn_msg *msg); + + /** +- * nss_qvpn_unregister_if +- * Deregisters the QVPN interface from the NSS. +- * +- * @param[in] if_num NSS interface number. +- * +- * @return +- * None. +- */ +-void nss_qvpn_unregister_if(uint32_t if_num); +- +-/** + * nss_qvpn_register_if + * Register to send/receive QVPN messages to NSS. + * +@@ -459,6 +442,17 @@ struct nss_ctx_instance *nss_qvpn_regist + uint32_t features, void *app_ctx); + + /** ++ * nss_qvpn_unregister_if ++ * Deregisters the QVPN interface from the NSS. ++ * ++ * @param[in] if_num NSS interface number. ++ * ++ * @return ++ * None. ++ */ ++void nss_qvpn_unregister_if(uint32_t if_num); ++ ++/** + * nss_qvpn_ifnum_with_core_id + * Gets the QVPN interface number with the core ID. + * +@@ -488,34 +482,6 @@ void nss_qvpn_register_handler(void); + unsigned long *nss_qvpn_ifmap_get(void); + + /** +- * nss_qvpn_stats_unregister_notifier +- * Deregisters a statistics notifier. +- * +- * @datatypes +- * notifier_block +- * +- * @param[in] nb Notifier block. +- * +- * @return +- * 0 on success or non-zero on failure. +- */ +-extern int nss_qvpn_stats_unregister_notifier(struct notifier_block *nb); +- +-/** +- * nss_qvpn_stats_register_notifier +- * Registers a statistics notifier. +- * +- * @datatypes +- * notifier_block +- * +- * @param[in] nb Notifier block. +- * +- * @return +- * 0 on success or non-zero on failure. +- */ +-extern int nss_qvpn_stats_register_notifier(struct notifier_block *nb); +- +-/** + * @} + */ + +--- a/exports/nss_rmnet_rx.h ++++ b/exports/nss_rmnet_rx.h +@@ -18,7 +18,7 @@ + + /* + * @file nss_rmnet_rx.h +- * NSS RMNET interface message Structure and APIs ++ * NSS Virtual interface message Structure and APIs + */ + + #ifndef __NSS_RMNET_RX_H +@@ -58,7 +58,7 @@ enum nss_rmnet_rx_msg_types { + + /** + * nss_rmnet_rx_error_types +- * Error types for the RMNET interface. ++ * Error types for the virtual interface. + */ + enum nss_rmnet_rx_error_types { + NSS_RMNET_RX_SUCCESS, /**< No error. */ +@@ -125,19 +125,19 @@ struct nss_rmnet_rx_msg { + struct nss_cmn_msg cm; /**< Common message header. */ + + /** +- * Payload of an RMNET interface message. ++ * Payload of a virtual interface message. + */ + union { + struct nss_rmnet_rx_config_msg if_config; +- /**< Rule for creating an RMNET interface. */ ++ /**< Rule for creating a virtual interface. */ + struct nss_rmnet_rx_stats stats; +- /**< RMNET interface statistics. */ ++ /**< Virtual interface statistics. */ + } msg; /**< Message payload. */ + }; + + /** + * Callback to transmit interface data received from NSS +- * to the transmit path of the RMNET interface. ++ * to the transmit path of the virtual interface. + * + * @datatypes + * net_device \n +@@ -183,8 +183,8 @@ struct nss_rmnet_rx_handle { + int32_t if_num_h2n; /**< Redirect interface number on host-to-NSS path. */ + struct net_device *ndev; /**< Associated network device. */ + struct nss_rmnet_rx_pvt *pvt; /**< Private data structure. */ +- uint64_t *stats_n2h; /**< RMNET interface statistics from NSS-to-host. */ +- uint64_t *stats_h2n; /**< RMNET interface statistics from host-to-NSS. */ ++ uint64_t *stats_n2h; /**< Virtual interface statistics from NSS-to-host. */ ++ uint64_t *stats_h2n; /**< Virtual interface statistics from host-to-NSS. */ + atomic_t refcnt; /**< Reference count. */ + nss_rmnet_rx_msg_callback_t cb; /**< Message callback. */ + void *app_data; /**< Application data to be passed to the callback. */ +@@ -192,12 +192,12 @@ struct nss_rmnet_rx_handle { + + /** + * nss_rmnet_rx_destroy_sync +- * Destroys the RMNET interface synchronously. ++ * Destroys the virtual interface synchronously. + * + * @datatypes + * nss_rmnet_rx_handle + * +- * @param[in,out] handle Pointer to the RMNET interface handle (provided during ++ * @param[in,out] handle Pointer to the virtual interface handle (provided during + * dynamic interface allocation). + * + * @return +@@ -210,7 +210,7 @@ extern nss_tx_status_t nss_rmnet_rx_dest + + /** + * nss_rmnet_rx_create_sync_nexthop +- * Creates an RMNET interface synchronously with specified nexthops. ++ * Creates a virtual interface synchronously with specified nexthops. + * + * @datatypes + * net_device +@@ -220,33 +220,19 @@ extern nss_tx_status_t nss_rmnet_rx_dest + * @param[in] nexthop_h2n Nexthop interface number of host-to-NSS dynamic interface. + * + * @return +- * Pointer to the NSS RMNET interface handle. ++ * Pointer to NSS virtual interface handle. + */ + extern struct nss_rmnet_rx_handle *nss_rmnet_rx_create_sync_nexthop(struct net_device *netdev, uint32_t nexthop_n2h, uint32_t nexthop_h2n); + + /** +- * nss_rmnet_rx_create +- * Creates an RMNET interface synchronously with generic nexthops. +- * +- * @datatypes +- * net_device +- * +- * @param[in] netdev Pointer to the associated network device. +- * +- * @return +- * Pointer to the NSS RMNET interface handle. +- */ +-extern struct nss_rmnet_rx_handle *nss_rmnet_rx_create(struct net_device *netdev); +- +-/** + * nss_rmnet_rx_tx_buf +- * Forwards RMNET interface packets to the NSS. ++ * Forwards virtual interface packets to the NSS. + * + * @datatypes + * nss_rmnet_rx_handle \n + * sk_buff + * +- * @param[in,out] handle Pointer to the RMNET interface handle (provided during ++ * @param[in,out] handle Pointer to the virtual interface handle (provided during + * registration). + * @param[in] skb Pointer to the data socket buffer. + * +@@ -258,14 +244,14 @@ extern nss_tx_status_t nss_rmnet_rx_tx_b + + /** + * nss_rmnet_rx_tx_msg +- * Sends a message to the RMNET interface. ++ * Sends a message to the virtual interface. + * + * @datatypes + * nss_ctx_instance \n + * nss_rmnet_rx_msg + * + * @param[in] nss_ctx Pointer to the NSS context (provided during registration). +- * @param[in] nvim Pointer to the RMNET interface message. ++ * @param[in] nvim Pointer to the virtual interface message. + * + * @return + * Command Tx status. +@@ -274,12 +260,12 @@ extern nss_tx_status_t nss_rmnet_rx_tx_m + + /** + * nss_rmnet_rx_xmit_callback_unregister +- * Deregisters the transmit callback from the RMNET interface. ++ * Deregisters the transmit callback from the virtual interface. + * + * @datatypes + * nss_rmnet_rx_handle + * +- * @param[in,out] handle Pointer to the RMNET interface handle. ++ * @param[in,out] handle Pointer to the virtual interface handle. + * + * @return + * None. +@@ -288,15 +274,15 @@ extern void nss_rmnet_rx_xmit_callback_u + + /** + * nss_rmnet_rx_xmit_callback_register +- * Registers a transmit callback to an RMNET interface. ++ * Registers a transmit callback to a virtual interface. + * + * @datatypes + * nss_rmnet_rx_handle \n + * nss_rmnet_rx_xmit_callback_t + * +- * @param[in,out] handle Pointer to the RMNET interface handle (provided during ++ * @param[in,out] handle Pointer to the virtual interface handle (provided during + * dynamic interface allocation). +- * @param[in] cb Callback handler for RMNET data packets. ++ * @param[in] cb Callback handler for virtual data packets. + * + * @return + * None. +@@ -306,12 +292,12 @@ extern void nss_rmnet_rx_xmit_callback_r + + /** + * nss_rmnet_rx_unregister +- * Deregisters an RMNET interface from the NSS driver. ++ * Deregisters a virtual interface from the NSS driver. + * + * @datatypes + * nss_rmnet_rx_handle + * +- * @param[in,out] handle Pointer to the RMNET interface handle. ++ * @param[in,out] handle Pointer to the virtual interface handle. + * + * @return + * None. +@@ -320,16 +306,16 @@ extern void nss_rmnet_rx_unregister(stru + + /** + * nss_rmnet_rx_register +- * Registers an RMNET Interface with NSS driver. ++ * Registers a virtual Interface with NSS driver. + * + * @datatypes + * nss_rmnet_rx_handle \n + * nss_rmnet_rx_data_callback_t \n + * net_device + * +- * @param[in,out] handle Pointer to the RMNET interface handle (provided during ++ * @param[in,out] handle Pointer to the virtual interface handle (provided during + * dynamic interface allocation). +- * @param[in] data_callback Callback handler for RMNET data packets. ++ * @param[in] data_callback Callback handler for virtual data packets. + * @param[in] netdev Pointer to the associated network device. + * + * @return +@@ -363,22 +349,22 @@ extern int32_t nss_rmnet_rx_get_ifnum(st + + /** + * nss_rmnet_rx_get_interface_num +- * Returns the RMNET interface number associated with the handle. ++ * Returns the virtual interface number associated with the handle. + * + * @datatypes + * nss_rmnet_rx_handle + * +- * @param[in] handle Pointer to the RMNET interface handle (provided during ++ * @param[in] handle Pointer to the virtual interface handle (provided during + dynamic interface allocation). + * + * @return +- * RMNET interface number. ++ * Virtual interface number. + */ + extern int32_t nss_rmnet_rx_get_interface_num(struct nss_rmnet_rx_handle *handle); + + /** + * nss_rmnet_rx_get_context +- * Gets the RMNET interface context. ++ * Gets the virtual interface context. + * + * @return + * Pointer to the NSS core context. +--- a/exports/nss_shaper.h ++++ b/exports/nss_shaper.h +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2014, 2017-2018, 2021 The Linux Foundation. All rights reserved. ++ * Copyright (c) 2014, 2017-2018 The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -59,7 +59,7 @@ enum nss_shaper_config_types { + NSS_SHAPER_CONFIG_TYPE_FREE_SHAPER_NODE, + NSS_SHAPER_CONFIG_TYPE_SET_DEFAULT, + NSS_SHAPER_CONFIG_TYPE_SET_ROOT, +- NSS_SHAPER_CONFIG_TYPE_SHAPER_NODE_STATS_SYNC_MANY, ++ NSS_SHAPER_CONFIG_TYPE_SHAPER_NODE_BASIC_STATS_GET, + NSS_SHAPER_CONFIG_TYPE_SHAPER_NODE_ATTACH, + NSS_SHAPER_CONFIG_TYPE_SHAPER_NODE_DETACH, + NSS_SHAPER_CONFIG_TYPE_SHAPER_NODE_CHANGE_PARAM, +@@ -672,7 +672,6 @@ struct nss_shaper_node_stats { + * Statistics response for shaper nodes. + */ + struct nss_shaper_node_stats_response { +- uint32_t qos_tag; /**< QoS tag of the shaper node. */ + struct nss_shaper_node_stats sn_stats; /**< Common shaper node statistics. */ + + /** +@@ -686,27 +685,21 @@ struct nss_shaper_node_stats_response { + }; + + /** +- * nss_shaper_node_stats_sync_many +- * Message structure to request shaper node statistics. ++ * nss_shaper_node_stats_get ++ * Statistics of a shaper node. + */ +-struct nss_shaper_node_stats_sync_many { ++struct nss_shaper_node_stats_get { + +- /* +- * Request/Response +- */ +- uint32_t last_qos_tag; /**< Last QoS tag. Zero indicates a fresh iteration. */ +- +- /* +- * Request +- */ +- uint16_t size; /**< Total buffer size indicated by host. */ +- +- /* +- * Response +- */ +- uint16_t count; /**< Number of shaper nodes for which statistics are copied. */ +- struct nss_shaper_node_stats_response stats_sync[]; +- /**< Response to host. */ ++ /* ++ * Request ++ */ ++ uint32_t qos_tag; /**< QoS tag of the shaper node. */ ++ ++ /* ++ * Response ++ */ ++ struct nss_shaper_node_stats_response response; ++ /**< Shaper node statistics response */ + }; + + /** +@@ -733,8 +726,8 @@ struct nss_shaper_configure { + /**< Set a shaper to operate in Hybrid mode. */ + struct nss_shaper_node_config shaper_node_config; + /**< Configuration message for any type of shaper node. */ +- struct nss_shaper_node_stats_sync_many stats_get; +- /**< Statistics of multiple shaper nodes. */ ++ struct nss_shaper_node_stats_get shaper_node_stats_get; ++ /**< Statistics for a shaper node. */ + } msg; /**< Types of configuration messages. */ + }; + +--- a/exports/nss_tls.h ++++ b/exports/nss_tls.h +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above +@@ -69,43 +69,6 @@ enum nss_tls_error { + }; + + /** +- * nss_tls_stats_types +- * TLS statistics types. +- */ +-enum nss_tls_stats_types { +- NSS_TLS_STATS_SINGLE_REC = NSS_STATS_NODE_MAX, +- /**< Number of transmit single record datagrams. */ +- NSS_TLS_STATS_MULTI_REC, /**< Number of multiple transmit record datagrams. */ +- NSS_TLS_STATS_TX_INVAL_REQS, /**< Number of transmit invalidations successfully requested. */ +- NSS_TLS_STATS_RX_CCS_REC, /**< Number of change cipher specification records received. */ +- NSS_TLS_STATS_FAIL_CCS, /**< Failure to switch to new crypto. */ +- NSS_TLS_STATS_ETH_NODE_DEACTIVE, /**< Ethernet node deactivated because no crypto was available. */ +- NSS_TLS_STATS_CRYPTO_ALLOC_SUCCESS, /**< Number of successful crypto allocations. */ +- NSS_TLS_STATS_CRYPTO_FREE_REQ, /**< Number of crypto-free requests. */ +- NSS_TLS_STATS_CRYPTO_FREE_SUCCESS, /**< Number of crypto-free successes. */ +- NSS_TLS_STATS_FAIL_CRYPTO_ALLOC, /**< Number of failed crypto allocations. */ +- NSS_TLS_STATS_FAIL_CRYPTO_LOOKUP, /**< Failure to find an active crypto session. */ +- NSS_TLS_STATS_FAIL_REQ_ALLOC, /**< Failure to allocate request memory pool. */ +- NSS_TLS_STATS_FAIL_PBUF_STATS, /**< Failure in pbuf allocation for statistics. */ +- NSS_TLS_STATS_FAIL_CTX_ACTIVE, /**< Failure in enqueue due to inactive context. */ +- NSS_TLS_STATS_HW_LEN_ERROR, /**< Length error. */ +- NSS_TLS_STATS_HW_TOKEN_ERROR, /**< Token error; unknown token command or instruction. */ +- NSS_TLS_STATS_HW_BYPASS_ERROR, /**< Token contains too much bypass data. */ +- NSS_TLS_STATS_HW_CRYPTO_ERROR, /**< Cryptographic block size error. */ +- NSS_TLS_STATS_HW_HASH_ERROR, /**< Hash block size error. */ +- NSS_TLS_STATS_HW_CONFIG_ERROR, /**< Invalid command, algorithm, or mode combination. */ +- NSS_TLS_STATS_HW_ALGO_ERROR, /**< Unsupported algorithm. */ +- NSS_TLS_STATS_HW_HASH_OVF_ERROR, /**< Hash input overflow. */ +- NSS_TLS_STATS_HW_AUTH_ERROR, /**< Hash input overflow. */ +- NSS_TLS_STATS_HW_PAD_VERIFY_ERROR, /**< Pad verification error. */ +- NSS_TLS_STATS_HW_TIMEOUT_ERROR, /**< Data timed out. */ +- NSS_TLS_STATS_NO_DESC_IN, /**< Ingress DMA descriptor not available. */ +- NSS_TLS_STATS_NO_DESC_OUT, /**< Egress DMA descriptor not available. */ +- NSS_TLS_STATS_NO_REQS, /**< Not enough requests available for records. */ +- NSS_TLS_STATS_MAX, /**< Maximum statistics type. */ +-}; +- +-/** + * nss_tls_hw_stats + * TLS HW statistics. + */ +@@ -194,16 +157,6 @@ struct nss_tls_cipher_update { + }; + + /** +- * nss_tls_stats_notification +- * TLS transmission statistics structure. +- */ +-struct nss_tls_stats_notification { +- uint64_t stats_ctx[NSS_TLS_STATS_MAX]; /**< Context transmission statistics. */ +- uint32_t core_id; /**< Core ID. */ +- uint32_t if_num; /**< Interface number. */ +-}; +- +-/** + * nss_tls_msg + * Data for sending and receiving TLS messages. + */ +@@ -292,7 +245,7 @@ extern nss_tx_status_t nss_tls_tx_msg(st + * @param[in] if_num NSS interface number. + * @param[in] type Type of message. + * @param[in] len Size of the payload. +- * @param[in] ntcm Pointer to the NSS IPsec message. ++ * @param[in] nicm Pointer to the NSS IPsec message. + * + * @return + * Status of the Tx operation. +@@ -302,20 +255,6 @@ extern nss_tx_status_t nss_tls_tx_msg_sy + struct nss_tls_msg *ntcm); + + /** +- * nss_tls_unregister_if +- * Deregisters a TLS session interface from the NSS. +- * +- * @param[in] if_num NSS interface number. +- * +- * @return +- * None. +- * +- * @dependencies +- * The TLS session interface must have been previously registered. +- */ +-extern void nss_tls_unregister_if(uint32_t if_num); +- +-/** + * nss_tls_register_if + * Registers a TLS session interface with the NSS for sending and receiving + * messages. +@@ -345,19 +284,22 @@ extern struct nss_ctx_instance *nss_tls_ + void *app_ctx); + + /** +- * nss_tls_notify_unregister +- * Deregisters an event callback. ++ * nss_tls_unregister_if ++ * Deregisters a TLS session interface from the NSS. + * +- * @param[in] ifnum NSS interface number. ++ * @param[in] if_num NSS interface number. + * + * @return + * None. ++ * ++ * @dependencies ++ * The TLS session interface must have been previously registered. + */ +-extern void nss_tls_notify_unregister(uint32_t ifnum); ++extern void nss_tls_unregister_if(uint32_t if_num); + + /** + * nss_tls_notify_register +- * Registers an event callback to handle notification from TLS firmware package. ++ * Register an event callback to handle notification from TLS firmware package. + * + * @datatypes + * nss_tls_msg_callback_t +@@ -372,6 +314,17 @@ extern void nss_tls_notify_unregister(ui + extern struct nss_ctx_instance *nss_tls_notify_register(uint32_t ifnum, nss_tls_msg_callback_t ev_cb, void *app_data); + + /** ++ * nss_tls_notify_unregister ++ * Unregister an event callback. ++ * ++ * @param[in] ifnum NSS interface number. ++ * ++ * @return ++ * None. ++ */ ++extern void nss_tls_notify_unregister(uint32_t ifnum); ++ ++/** + * nss_tls_msg_init + * Initializes a TLS message sent asynchronously. + * +@@ -424,44 +377,6 @@ extern struct nss_ctx_instance *nss_tls_ + * Pointer to the device. + */ + extern struct device *nss_tls_get_dev(struct nss_ctx_instance *nss_ctx); +- +-/** +- * nss_tls_ifmap_get +- * Returns active TLS interfaces. +- * +- * @return +- * Pointer to the interface map. +- */ +-unsigned long *nss_tls_ifmap_get(void); +- +-/** +- * nss_tls_stats_unregister_notifier +- * Deregisters a statistics notifier. +- * +- * @datatypes +- * notifier_block +- * +- * @param[in] nb Notifier block. +- * +- * @return +- * 0 on success or non-zero on failure. +- */ +-extern int nss_tls_stats_unregister_notifier(struct notifier_block *nb); +- +-/** +- * nss_tls_stats_register_notifier +- * Registers a statistics notifier. +- * +- * @datatypes +- * notifier_block +- * +- * @param[in] nb Notifier block. +- * +- * @return +- * 0 on success or non-zero on failure. +- */ +-extern int nss_tls_stats_register_notifier(struct notifier_block *nb); +- + /** + * @} + */ +--- a/exports/nss_trustsec_tx.h ++++ b/exports/nss_trustsec_tx.h +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2016-2017, 2020, 2021 The Linux Foundation. All rights reserved. ++ * Copyright (c) 2016-2017, 2020 The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -44,7 +44,7 @@ enum nss_trustsec_tx_msg_types { + * Error types for the TrustSec Tx interface. + */ + enum nss_trustsec_tx_error_types { +- NSS_TRUSTSEC_TX_ERR_NONE, /** No error. */ ++ NSS_TRUSTSEC_TX_ERR_NONE, /** No error */ + NSS_TRUSTSEC_TX_ERR_INVAL_SRC_IF, /** Source interface is invalid. */ + NSS_TRUSTSEC_TX_ERR_RECONFIGURE_SRC_IF, /** Source interface is already configured. */ + NSS_TRUSTSEC_TX_ERR_DEST_IF_NOT_FOUND, /** Destination interface is not found. */ +--- a/exports/nss_tunipip6.h ++++ b/exports/nss_tunipip6.h +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2014, 2017-2018, 2020, 2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2014, 2017-2018, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -23,154 +23,81 @@ + #define __NSS_TUNIPIP6_H + + /** +- * Maximum number of supported TUNIPIP6 tunnels. +- */ +-#define NSS_TUNIPIP6_TUNNEL_MAX 32 +- +-/** + * @addtogroup nss_tunipip6_subsystem + * @{ + */ + ++#define NSS_TUNIPIP6_MAX_FMR_NUMBER 4 /**< Maximum number of forward mapping rule (FMR). */ ++ + /** +- * nss_tunipip6_map_rule +- * Mapping rule (FMR/BMR) for forwarding traffic to the node in the same domain. ++ * nss_tunipip6_fmr ++ * Forward mapping rule (FMR) for direct forwarding traffic to the node in the same domain. + */ +-struct nss_tunipip6_map_rule { ++struct nss_tunipip6_fmr { + uint32_t ip6_prefix[4]; /**< An IPv6 prefix assigned by a mapping rule. */ + uint32_t ip4_prefix; /**< An IPv4 prefix assigned by a mapping rule. */ + uint32_t ip6_prefix_len; /**< IPv6 prefix length. */ + uint32_t ip4_prefix_len; /**< IPv4 prefix length. */ +- uint32_t ip6_suffix[4]; /**< IPv6 suffix. */ +- uint32_t ip6_suffix_len; /**< IPv6 suffix length. */ + uint32_t ea_len; /**< Embedded Address (EA) bits. */ +- uint32_t psid_offset; /**< PSID offset default 6. */ +-}; +- +-/** +- * nss_tunipip6_err_types +- * Error types for response to messages from the host. +- */ +-enum nss_tunipip6_err_types { +- NSS_TUNIPIP6_ERR_TYPE_MAX_TUNNELS, /**< Maximum number of tunnel reached. */ +- NSS_TUNIPIP6_ERR_TYPE_TUNNEL_EXIST, /**< Tunnel already exists. */ +- NSS_TUNIPIP6_ERR_TYPE_ENCAP_BAD_PARAM, /**< Bad configuration. */ +- NSS_TUNIPIP6_ERR_TYPE_ENCAP_FMR_EXIST, /**< FMR already exists. */ +- NSS_TUNIPIP6_ERR_TYPE_ENCAP_NO_FMR, /**< No FMR configured.*/ +- NSS_TUNIPIP6_ERR_TYPE_ENCAP_FMR_FULL, /**< FMR table is full. */ +- NSS_TUNIPIP6_ERR_TYPE_ENCAP_INVALID_FMR, /**< Invalid FMR configured.*/ +- NSS_TUNIPIP6_ERR_TYPE_ENCAP_BMR_EXIST, /**< BMR already exists. */ +- NSS_TUNIPIP6_ERR_TYPE_ENCAP_NO_BMR, /**< No BMR configured. */ +- NSS_TUNIPIP6_ERR_TYPE_ENCAP_FMR_MEM_ALLOC_FAILED, /**< Pool allocation for FMR failed. */ +- NSS_TUNIPIP6_ERR_TYPE_UNKNOWN, /**< Unknown message type. */ +- NSS_TUNIPIP6_ERROR_MAX, /**< Maximum number of errors. */ ++ uint32_t offset; /**< PSID offset default 6. */ + }; + + /** + * nss_tunipip6_metadata_types +- * Message types for TUNIPIP6 (IPv4 in IPv6) tunnel requests and responses. ++ * Message types for DS-Lite (IPv4 in IPv6) tunnel requests and responses. + */ + enum nss_tunipip6_metadata_types { + NSS_TUNIPIP6_TX_ENCAP_IF_CREATE, + NSS_TUNIPIP6_TX_DECAP_IF_CREATE, +- NSS_TUNIPIP6_STATS_SYNC, +- NSS_TUNIPIP6_FMR_RULE_ADD, +- NSS_TUNIPIP6_FMR_RULE_DEL, +- NSS_TUNIPIP6_FMR_RULE_FLUSH, +- NSS_TUNIPIP6_BMR_RULE_ADD, +- NSS_TUNIPIP6_BMR_RULE_DEL, ++ NSS_TUNIPIP6_RX_STATS_SYNC, + NSS_TUNIPIP6_MAX, + }; + + /** + * nss_tunipip6_create_msg +- * Payload for configuring the TUNIPIP6 interface. ++ * Payload for configuring the DS-Lite interface. + */ + struct nss_tunipip6_create_msg { ++ struct nss_tunipip6_fmr fmr[NSS_TUNIPIP6_MAX_FMR_NUMBER]; /**< Tunnel FMR array. */ + uint32_t saddr[4]; /**< Tunnel source address. */ + uint32_t daddr[4]; /**< Tunnel destination address. */ + uint32_t flowlabel; /**< Tunnel IPv6 flow label. */ + uint32_t flags; /**< Tunnel additional flags. */ ++ uint32_t fmr_number; /**< Tunnel FMR number. */ + uint32_t sibling_if_num; /**< Sibling interface number. */ ++ uint16_t reserved1; /**< Reserved for alignment. */ + uint8_t hop_limit; /**< Tunnel IPv6 hop limit. */ + uint8_t draft03; /**< Use MAP-E draft03 specification. */ +- uint8_t ttl_inherit; /**< Inherit IPv4 TTL to hoplimit. */ +- uint8_t tos_inherit; /**< Inherit IPv4 ToS. */ +- uint8_t frag_id_update; /**< Enable update of fragment identifier of IPv4. */ +- uint8_t reserved[3]; /**< Reserved bytes. */ +- uint32_t fmr_max; /**< Maximum number of FMRs that can be configured. */ +-}; +- +-/** +- * nss_tunipip6_debug_stats +- * TUNIPIP6 debug statistics. +- */ +-struct nss_tunipip6_debug_stats { +- struct { +- struct { +- uint32_t low_headroom; /**< Low headroom for encapsulation. */ +- uint32_t unhandled_proto; /**< Unhandled protocol for encapsulation. */ +- } exp; +- +- struct { +- uint32_t enqueue_fail; /**< Encapsulation enqueue fail. */ +- } drop; +- +- struct { +- uint32_t err_tunnel_cfg; /**< Tunnel configuration error. */ +- uint32_t total_fmr; /**< Total number of existing FMRs. */ +- uint32_t fmr_add_req; /**< FMR add requests. */ +- uint32_t fmr_del_req; /**< FMR delete requests. */ +- uint32_t fmr_flush_req; /**< FMR flush requests. */ +- uint32_t fmr_update_req; /**< FMR update requests. */ +- uint32_t fmr_add_fail; /**< FMR addition failed. */ +- uint32_t fmr_del_fail; /**< FMR deletion failed. */ +- uint32_t err_no_fmr; /**< No FMR configured. */ +- uint32_t bmr_add_req; /**< BMR add requests. */ +- uint32_t bmr_del_req; /**< BMR delete requests. */ +- uint32_t err_bmr_exist; /**< BMR already configured. */ +- uint32_t err_no_bmr; /**< No BMR configured. */ +- } cfg; +- } encap; +- +- struct { +- struct { +- uint32_t enqueue_fail; /**< Decapsulation enqueue fail. */ +- } drop; +- } decap; + }; + + /** + * nss_tunipip6_stats_sync_msg +- * Message information for TUNIPIP6 synchronization statistics. ++ * Message information for DS-Lite synchronization statistics. + */ + struct nss_tunipip6_stats_sync_msg { +- struct nss_cmn_node_stats node_stats; /**< Common node statistics. */ +- struct nss_tunipip6_debug_stats tun_stats; /**< TUNIPIP6 debug statistics. */ ++ struct nss_cmn_node_stats node_stats; /**< Common node statistics. */ + }; + + /** + * nss_tunipip6_msg +- * Data for sending and receiving TUNIPIP6 messages. ++ * Data for sending and receiving DS-Lite messages. + */ + struct nss_tunipip6_msg { + struct nss_cmn_msg cm; /**< Common message header. */ + + /** +- * Payload of a TUNIPIP6 message. ++ * Payload of a DS-Lite message. + */ + union { + struct nss_tunipip6_create_msg tunipip6_create; +- /**< Create a TUNIPIP6 tunnel. */ +- struct nss_tunipip6_stats_sync_msg stats; +- /**< Synchronized statistics for the TUNIPIP6 interface. */ +- struct nss_tunipip6_map_rule map_rule; +- /**< BMR/FMR rule to add/delete, new or existing rules. */ +- } msg; /**< Message payload for TUNIPIP6 messages exchanged with NSS core. */ ++ /**< Create a DS-Lite tunnel. */ ++ struct nss_tunipip6_stats_sync_msg stats_sync; ++ /**< Synchronized statistics for the DS-Lite interface. */ ++ } msg; /**< Message payload for IPIP6 Tunnel messages exchanged with NSS core. */ + }; + + /** +- * Callback function for receiving TUNIPIP6 messages. ++ * Callback function for receiving DS-Lite messages. + * + * @datatypes + * nss_tunipip6_msg +@@ -182,7 +109,7 @@ typedef void (*nss_tunipip6_msg_callback + + /** + * nss_tunipip6_tx +- * Sends a TUNIPIP6 message to NSS core. ++ * Sends a DS-Lite message to NSS core. + * + * @datatypes + * nss_ctx_instance \n +@@ -197,23 +124,7 @@ typedef void (*nss_tunipip6_msg_callback + extern nss_tx_status_t nss_tunipip6_tx(struct nss_ctx_instance *nss_ctx, struct nss_tunipip6_msg *msg); + + /** +- * nss_tunipip6_tx_sync +- * Sends a TUNIPIP6 message to NSS core synchronously. +- * +- * @datatypes +- * nss_ctx_instance \n +- * nss_tunipip6_msg +- * +- * @param[in] nss_ctx Pointer to the NSS context. +- * @param[in] msg Pointer to the message data. +- * +- * @return +- * Status of the Tx operation. +- */ +-extern nss_tx_status_t nss_tunipip6_tx_sync(struct nss_ctx_instance *nss_ctx, struct nss_tunipip6_msg *msg); +- +-/** +- * Callback function for receiving TUNIPIP6 data. ++ * Callback function for receiving DS-Lite data. + * + * @datatypes + * net_device \n +@@ -226,10 +137,10 @@ extern nss_tx_status_t nss_tunipip6_tx_s + */ + typedef void (*nss_tunipip6_callback_t)(struct net_device *netdev, struct sk_buff *skb, struct napi_struct *napi); + +-/** ++/* + * nss_register_tunipip6_if + * Registers the TUNIPIP6 interface with the NSS for sending and receiving +- * TUNIPIP6 messages. ++ * DS-Lite messages. + * + * @datatypes + * nss_tunipip6_callback_t \n +@@ -279,9 +190,9 @@ extern void nss_unregister_tunipip6_if(u + */ + extern void nss_tunipip6_msg_init(struct nss_tunipip6_msg *ntm, uint16_t if_num, uint32_t type, uint32_t len, void *cb, void *app_data); + +-/** ++/* + * nss_tunipip6_get_context() +- * Get TUNIPIP6 context. ++ * Get tunipip6 context. + * + * @return + * Pointer to the NSS core context. +--- a/exports/nss_virt_if.h ++++ b/exports/nss_virt_if.h +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2014-2017, 2019, 2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2014-2017, 2019, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -93,8 +93,8 @@ struct nss_virt_if_interface_stats { + * Virtual interface statistics received from the NSS. + */ + struct nss_virt_if_stats { +- struct nss_virt_if_base_node_stats base_stats; /**< Virtual interface statistics of NSS base node. */ +- struct nss_virt_if_interface_stats if_stats; /**< Virtual interface statistics of each pair of interfaces. */ ++ struct nss_virt_if_base_node_stats base_stats; ++ struct nss_virt_if_interface_stats if_stats; + }; + + /** +--- a/exports/nss_vxlan.h ++++ b/exports/nss_vxlan.h +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2019, 2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -53,11 +53,6 @@ + #define NSS_VXLAN_RULE_FLAG_UDP 0x0100 /**< UDP tunnel. */ + + /** +- * Flag used to set the IPSec interface number in the MAC add message for binding with VxLAN. +- */ +-#define NSS_VXLAN_MAC_ENABLE_IPSEC_BIND 0x01 +- +-/** + * nss_vxlan_msg_type + * Message types for VxLAN tunnel. + */ +@@ -116,8 +111,6 @@ struct nss_vxlan_stats_msg { + uint32_t except_vni_lookup_failed; /**< Virtual network ID look up failed. */ + uint32_t dropped_malformed; /**< Packet is malformed. */ + uint32_t dropped_next_node_queue_full; /**< Next node dropped the packet. */ +- uint32_t except_inner_hash; /**< Inner hash calculation failed. */ +- uint32_t decap_ipsec_src_err; /* Drops due to incorrect packet buffer source for VxLAN over IPSec flow. */ + }; + + /** +@@ -140,7 +133,7 @@ struct nss_vxlan_rule_msg { + */ + uint16_t flow_label; /**< Flow label. */ + uint8_t tos; /**< Type of service/traffic class. */ +- uint8_t ttl; /**< TTL/hop limit. */ ++ uint8_t ttl; /**< TTL/Hop Limit. */ + + /* + * L4 rules +@@ -168,9 +161,6 @@ struct nss_vxlan_mac_msg { + /**< Tunnel encapsulation header. */ + uint32_t vni; /**< VxLAN network identifier. */ + uint16_t mac_addr[3]; /**< MAC address. */ +- uint8_t reserved; /**< Reserved. */ +- uint8_t flags; /**< First bit set in the LSB indicates if IPSec is enabled. */ +- uint32_t ipsec_if_num; /**< IPSec source interface number. */ + }; + + /** +--- a/exports/nss_wifi.h ++++ b/exports/nss_wifi.h +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2015-2018, 2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -35,8 +35,6 @@ + #define NSS_WIFI_IPV6_ADDR_LEN 16 /**< Size of the IPv6 address. */ + #define NSS_WIFI_MAX_RSSI_CHAINS 4 /**< Maximum number of RSSI chains. */ + #define NSS_WIFI_WME_NUM_AC 4 /**< Number of ACs. */ +-#define NSS_WIFI_MIC_KEY_LEN 8 +- + + /** + * Maximum number of Wi-Fi peers per radio as a sum of +@@ -94,8 +92,6 @@ enum nss_wifi_metadata_types { + NSS_WIFI_OL_PEER_TIME_MSG, + NSS_WIFI_PEER_SET_VLAN_ID_MSG, + NSS_WIFI_PEER_ISOLATION_MSG, +- NSS_WIFI_PEER_AUTH_MSG, +- NSS_WIFI_PEER_SECURITY_CFG, + NSS_WIFI_MAX_MSG + }; + +@@ -638,11 +634,6 @@ struct nss_wifi_stats_sync_msg { + * Number of times a deny list was hit during multicast enhancement. + */ + uint32_t mc_enhance_denylist_hit; +- +- /** +- * Total number of data packets dropped for an unauthorized peer. +- */ +- uint32_t peer_unauth_rx_pkt_drop; + }; + + /** +@@ -650,8 +641,8 @@ struct nss_wifi_stats_sync_msg { + * Information for creating a Wi-Fi peer freelist. + */ + struct nss_wifi_peer_freelist_append_msg { +- uint32_t addr; /**< Starting address of the peer freelist pool. */ +- uint32_t length; /**< Size of the peer freelist pool. */ ++ uint32_t addr; /**< Starting address of peer freelist pool. */ ++ uint32_t length; /**< Size of peer freelist pool. */ + uint32_t num_peers; /**< Maximum peer entries supported in the pool. */ + }; + +@@ -718,7 +709,7 @@ struct nss_wifi_peer_ol_stats { + uint32_t tx_mcast; /**< Number of multicast packets sent. */ + uint32_t tx_ucast; /**< Number of unicast packets sent. */ + uint32_t tx_data; /**< Number data packets sent. */ +- uint32_t tx_bytes; /**< Number of bytes transmitted. */ ++ uint32_t tx_bytes; /**< Number of bytes sent. */ + uint32_t tx_fail; /**< Number of failed Tx packets. */ + uint32_t thrup_bytes; /**< Number of throughput bytes. */ + uint32_t tx_bcast_pkts; /**< Number of broadcast packets sent. */ +@@ -731,10 +722,6 @@ struct nss_wifi_peer_ol_stats { + uint32_t ppdu_retries; /**< Number of PPDU retries. */ + uint32_t rssi_chains[NSS_WIFI_MAX_RSSI_CHAINS]; + /**< Acknowledgment RSSI per chain. */ +- uint32_t rx_msdus; /**< Number of MSDUs received. */ +- uint32_t rx_bytes; /**< Number of bytes received. */ +- uint32_t rx_mpdus; /**< Number of MPDUs received. */ +- uint32_t rx_retries; /**< Number of MPDU retries. */ + }; + + /** +@@ -751,7 +738,7 @@ struct nss_wifi_ol_stats_msg { + + /** + * nss_wifi_sta_kickout_msg +- * Station kickout message from NSS firmware. ++ * Station kickout message from NSS Firmware + */ + struct nss_wifi_sta_kickout_msg { + uint32_t peer_id; /**< Peer ID. */ +@@ -766,18 +753,9 @@ struct nss_wifi_peer_isolation_msg { + uint16_t isolation; /**< Isolation enabled/disabled. */ + }; + +-/* +- * nss_wifi_peer_auth_msg +- * Peer authentication flag status. +- */ +-struct nss_wifi_peer_auth_msg { +- uint16_t peer_id; /**< Peer ID. */ +- uint16_t auth_flag; /**< Peer authentication flag. */ +-}; +- + /** + * nss_wifi_wnm_peer_rx_activity_msg +- * Receive active state information for the peer. ++ * Rx active state information for the peer. + */ + struct nss_wifi_wnm_peer_rx_activity_msg { + uint16_t nentries; /**< Number of entries. */ +@@ -789,17 +767,6 @@ struct nss_wifi_wnm_peer_rx_activity_msg + }; + + /** +- * nss_wifi_peer_security_type_msg +- * Wi-fi security type message. +- */ +-struct nss_wifi_peer_security_type_msg { +- uint16_t peer_id; /**< Peer ID. */ +- uint8_t pkt_type; /**< Unicast or broadcast packet type. */ +- uint8_t security_type; /**< Security type. */ +- uint8_t mic_key[NSS_WIFI_MIC_KEY_LEN]; /**< MIC key. */ +-}; +- +-/** + * nss_wifi_append_metaheader + * Append metaheader after pbuf->data for stats_v2. + */ +@@ -946,21 +913,17 @@ struct nss_wifi_msg { + struct nss_wifi_cmd_msg wcmdm; + /**< Pdev command information. */ + struct nss_wifi_enable_ol_statsv2 wesh_msg; +- /**< Enable version 2 transmit/receive statistics. */ ++ /**< Enable version 2 tx/rx stats. */ + struct nss_wifi_ol_peer_time_msg wopt_msg; + /**< Send per peer/TID timestamp statistics to host. */ + struct nss_wifi_peer_isolation_msg isolation_msg; + /**< Enable or disable peer isolation. */ +- struct nss_wifi_peer_auth_msg auth_msg; +- /**< Enable or disable peer authorization. */ +- struct nss_wifi_peer_security_type_msg securitymsg; +- /**< Wifili peer security message. */ + } msg; /**< Message Payload. */ + }; + + /** + * nss_wifi_get_context +- * Gets the Wi-Fi context used in NSS GRE transmit. ++ * Gets the Wi-Fi context used in nss_gre_tx. + * + * @return + * Pointer to the NSS core context. +--- /dev/null ++++ b/exports/nss_wifi_if.h +@@ -0,0 +1,292 @@ ++/* ++ ************************************************************************** ++ * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. ++ * Permission to use, copy, modify, and/or distribute this software for ++ * any purpose with or without fee is hereby granted, provided that the ++ * above copyright notice and this permission notice appear in all copies. ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT ++ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ************************************************************************** ++ */ ++ ++/** ++ * @file nss_wifi_if.h ++ * NSS Wi-Fi interface message Structure and APIs. ++ */ ++ ++#ifndef __NSS_WIFI_IF_H ++#define __NSS_WIFI_IF_H ++ ++/** ++ * @addtogroup nss_wifi_subsystem ++ * @{ ++ */ ++ ++/** ++ * nss_wifi_if_msg_types ++ * Message types for Wi-Fi interface requests and responses. ++ */ ++enum nss_wifi_if_msg_types { ++ NSS_WIFI_IF_OPEN = NSS_IF_OPEN, ++ NSS_WIFI_IF_CLOSE = NSS_IF_CLOSE, ++ NSS_WIFI_IF_LINK_STATE_NOTIFY = NSS_IF_LINK_STATE_NOTIFY, ++ NSS_WIFI_IF_MTU_CHANGE = NSS_IF_MTU_CHANGE, ++ NSS_WIFI_IF_MAC_ADDR_SET = NSS_IF_MAC_ADDR_SET, ++ NSS_WIFI_IF_STATS_SYNC = NSS_IF_STATS, ++ NSS_WIFI_IF_ISHAPER_ASSIGN = NSS_IF_ISHAPER_ASSIGN, ++ NSS_WIFI_IF_BSHAPER_ASSIGN = NSS_IF_BSHAPER_ASSIGN, ++ NSS_WIFI_IF_ISHAPER_UNASSIGN = NSS_IF_ISHAPER_UNASSIGN, ++ NSS_WIFI_IF_BSHAPER_UNASSIGN = NSS_IF_BSHAPER_UNASSIGN, ++ NSS_WIFI_IF_ISHAPER_CONFIG = NSS_IF_ISHAPER_CONFIG, ++ NSS_WIFI_IF_BSHAPER_CONFIG = NSS_IF_BSHAPER_CONFIG, ++ NSS_WIFI_IF_VSI_ASSIGN = NSS_IF_VSI_ASSIGN, ++ NSS_WIFI_IF_VSI_UNASSIGN = NSS_IF_VSI_UNASSIGN, ++ NSS_WIFI_IF_TX_CREATE_MSG = NSS_IF_MAX_MSG_TYPES + 1, ++ NSS_WIFI_IF_TX_DESTROY_MSG, ++ NSS_WIFI_IF_STATS_SYNC_MSG, ++ NSS_WIFI_IF_MAX_MSG_TYPES ++}; ++ ++/** ++ * nss_wifi_if_error_types ++ * Error types for the Wi-Fi interface. ++ */ ++enum nss_wifi_if_error_types { ++ NSS_WIFI_IF_SUCCESS, ++ NSS_WIFI_IF_CORE_FAILURE, ++ NSS_WIFI_IF_ALLOC_FAILURE, ++ NSS_WIFI_IF_DYNAMIC_IF_FAILURE, ++ NSS_WIFI_IF_MSG_TX_FAILURE, ++ NSS_WIFI_IF_REG_FAILURE, ++ NSS_WIFI_IF_CORE_NOT_INITIALIZED ++}; ++ ++/** ++ * nss_wifi_if_create_msg ++ * Payload for configuring the Wi-Fi interface. ++ */ ++struct nss_wifi_if_create_msg { ++ uint32_t flags; /**< Interface flags. */ ++ uint8_t mac_addr[ETH_ALEN]; /**< MAC address. */ ++}; ++ ++/** ++ * nss_wifi_if_destroy_msg ++ * Payload for destroying the Wi-Fi interface. ++ */ ++struct nss_wifi_if_destroy_msg { ++ int32_t reserved; /**< Placeholder. */ ++}; ++ ++/** ++ * nss_wifi_if_stats ++ * Wi-Fi interface statistics received from the NSS. ++ */ ++struct nss_wifi_if_stats { ++ struct nss_cmn_node_stats node_stats; ++ /**< Common statistics. */ ++ uint32_t tx_enqueue_failed; ++ /**< Number of packets dropped when queuing to the next node in a network graph. */ ++ uint32_t shaper_enqueue_failed; ++ /**< Number of packets dropped when queuing to the shaper node. */ ++}; ++ ++/** ++ * nss_wifi_if_msg ++ * Data for sending and receiving Wi-Fi interface messages. ++ */ ++struct nss_wifi_if_msg { ++ struct nss_cmn_msg cm; /**< Common message header. */ ++ ++ /** ++ * Payload of a Wi-Fi interface message. ++ */ ++ union { ++ union nss_if_msgs if_msgs; ++ /**< NSS interface messages. */ ++ struct nss_wifi_if_create_msg create; ++ /**< Creates a Wi-Fi interface rule. */ ++ struct nss_wifi_if_destroy_msg destroy; ++ /**< Destroys a Wi-Fi interface rule. */ ++ struct nss_wifi_if_stats stats; ++ /**< Interface statistics. */ ++ } msg; /**< Message payload. */ ++}; ++ ++/** ++ * nss_wifi_if_pvt ++ * Private data information for the Wi-Fi interface. ++ */ ++struct nss_wifi_if_pvt { ++ struct semaphore sem; ++ /**< Semaphore for a specified Wi-Fi interface number. */ ++ struct completion complete; ++ /**< Waits for the NSS to process a message on the specified Wi-Fi interface. */ ++ int response; /**< Response received on a Wi-Fi interface number. */ ++ int sem_init_done; ++ /**< Indicates whether the semaphore is initialized. */ ++}; ++ ++/** ++ * Callback function for receiving Wi-Fi data. ++ * ++ * @datatypes ++ * net_device \n ++ * sk_buff \n ++ * napi_struct ++ * ++ * @param[in] netdev Pointer to the associated network device. ++ * @param[in] skb Pointer to the data socket buffer. ++ * @param[in] napi Pointer to the NAPI structure. ++ */ ++typedef void (*nss_wifi_if_data_callback_t)(struct net_device *netdev, ++ struct sk_buff *skb, struct napi_struct *napi); ++ ++/** ++ * Callback function for receiving Wi-Fi messages. ++ * ++ * @datatypes ++ * nss_cmn_msg ++ * ++ * @param[in] app_data Pointer to the application context of the message. ++ * @param[in] msg Pointer to the message data. ++ */ ++typedef void (*nss_wifi_if_msg_callback_t)(void *app_data, ++ struct nss_cmn_msg *msg); ++ ++/** ++ * nss_wifi_if_handle ++ * Context for WLAN-to-NSS communication. ++ */ ++struct nss_wifi_if_handle { ++ struct nss_ctx_instance *nss_ctx; /**< NSS context. */ ++ int32_t if_num; /**< Interface number. */ ++ struct nss_wifi_if_pvt *pvt; /**< Private data structure. */ ++ struct nss_wifi_if_stats stats; ++ /**< Statistics corresponding to this handle. */ ++ nss_wifi_if_msg_callback_t cb; ++ /**< Callback registered by other modules. */ ++ void *app_data; ++ /**< Application context to be passed to that callback. */ ++}; ++ ++/** ++ * nss_wifi_if_tx_msg ++ * Sends a message to the Wi-Fi interface. ++ * ++ * @datatypes ++ * nss_ctx_instance \n ++ * nss_wifi_if_msg ++ * ++ * @param[in] nss_ctx Pointer to the NSS context (provided during registration). ++ * @param[in] nwim Pointer to the Wi-Fi interface message. ++ * ++ * @return ++ * Status of the Tx operation. ++ */ ++extern nss_tx_status_t nss_wifi_if_tx_msg(struct nss_ctx_instance *nss_ctx, ++ struct nss_wifi_if_msg *nwim); ++ ++/** ++ * nss_wifi_if_register ++ * Registers a Wi-Fi interface with the NSS driver. ++ * ++ * @datatypes ++ * nss_wifi_if_handle \n ++ * nss_wifi_if_data_callback_t \n ++ * net_device ++ * ++ * @param[in] handle Pointer to the Wi-Fi context (provided during Wi-Fi ++ * interface allocation). ++ * @param[in] rx_callback Callback handler for Wi-Fi data packets. ++ * @param[in] netdev Pointer to the associated network device. ++ * ++ * @return ++ * None. ++ */ ++extern void nss_wifi_if_register(struct nss_wifi_if_handle *handle, ++ nss_wifi_if_data_callback_t rx_callback, ++ struct net_device *netdev); ++ ++/** ++ * nss_wifi_if_unregister ++ * Deregisters a Wi-Fi interface from the NSS driver. ++ * ++ * @datatypes ++ * nss_wifi_if_handle ++ * ++ * @param[in] handle Pointer to the Wi-Fi context. ++ * ++ * @return ++ * None. ++ */ ++extern void nss_wifi_if_unregister(struct nss_wifi_if_handle *handle); ++ ++/** ++ * nss_wifi_if_create_sync ++ * Creates a Wi-Fi interface. ++ * ++ * @datatypes ++ * net_device ++ * ++ * @param[in] netdev Pointer to the associated network device. ++ * ++ * @return ++ * Pointer to the Wi-Fi handle. ++ */ ++extern struct nss_wifi_if_handle *nss_wifi_if_create_sync(struct net_device *netdev); ++ ++/** ++ * nss_wifi_if_destroy_sync ++ * Destroys the Wi-Fi interface associated with the interface number. ++ * ++ * @datatypes ++ * nss_wifi_if_handle ++ * ++ * @param[in] handle Pointer to the Wi-Fi handle. ++ * ++ * @return ++ * Status of the Tx operation. ++ */ ++extern nss_tx_status_t nss_wifi_if_destroy_sync(struct nss_wifi_if_handle *handle); ++ ++/** ++ * nss_wifi_if_tx_buf ++ * Sends a data packet or buffer to the NSS. ++ * ++ * @datatypes ++ * nss_wifi_if_handle \n ++ * sk_buff ++ * ++ * @param[in] handle Context associated with the interface. ++ * @param[in] skb Pointer to the data socket buffer. ++ * ++ * @return ++ * Status of the Tx operation. ++ */ ++extern nss_tx_status_t nss_wifi_if_tx_buf(struct nss_wifi_if_handle *handle, ++ struct sk_buff *skb); ++ ++/** ++ * nss_wifi_if_copy_stats ++ * Copies Wi-Fi interface statistics for display. ++ * ++ * @param[in] if_num NSS interface number. ++ * @param[in] index Index in the statistics array. ++ * @param[out] line Pointer to the buffer into which the statistics are copied. ++ * ++ * @return ++ * Number of bytes copied. ++ */ ++int32_t nss_wifi_if_copy_stats(int32_t if_num, int index, char *line); ++ ++/** ++ * @} ++ */ ++ ++#endif /* __NSS_WIFI_IF_H */ +--- a/exports/nss_wifi_mac_db_if.h ++++ b/exports/nss_wifi_mac_db_if.h +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2020, 2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above +@@ -25,18 +25,6 @@ + + #define NSS_WIFI_MAC_DB_ENTRY_IF_LOCAL 0x1 + +- /** +- * @addtogroup nss_wifi_mac_db_if_subsystem +- * @{ +- */ +- +-/* +- * MAX Wi-Fi MAC database entries sent in group +- * is chosen considering the entry size and +- * maximum entries a smallest buffer could accomodate. +- */ +-#define NSS_WIFI_MAC_DB_GROUP_ENTRIES_MAX 48 +- + /** + * nss_wifi_mac_db_msg_types + * Wi-Fi MAC database messages. +@@ -47,9 +35,6 @@ enum nss_wifi_mac_db_msg_types { + NSS_WIFI_MAC_DB_DEL_ENTRY_MSG, /**< Wi-Fi MAC database delete entry message. */ + NSS_WIFI_MAC_DB_UPDATE_ENTRY_MSG, /**< Wi-Fi MAC database update entry message. */ + NSS_WIFI_MAC_DB_DEINIT_MSG, /**< Wi-Fi MAC database deinitialization message. */ +- NSS_WIFI_MAC_DB_GROUP_ENTRIES_ADD_MSG, /**< Wi-Fi MAC database group entries add message. */ +- NSS_WIFI_MAC_DB_ENTRY_ACTIVITY_MSG, /**< Wi-Fi MAC database entry activity message. */ +- NSS_WIFI_MAC_DB_CREATE_ENTRY_MSG, /**< Wi-Fi MAC database entry create message. */ + NSS_WIFI_MAC_DB_MAX_MSG + }; + +@@ -77,84 +62,11 @@ enum nss_wifi_mac_db_if_opmode { + }; + + /** +- * nss_wifi_mac_db_err_types +- * Wi-Fi MAC database errors. +- */ +-enum nss_wifi_mac_db_err_types { +- NSS_WIFI_MAC_DB_ERROR_NONE, +- /**< Wi-Fi MAC database error none. */ +- NSS_WIFI_MAC_DB_ERROR_ENTRY_ALLOC_FAIL, +- /**< Error used to report a Wi-Fi MAC database entry pool allocation failure. */ +- NSS_WIFI_MAC_DB_ERROR_MAC_EXISTS, +- /**< Error used to report that a Wi-Fi MAC database entry already exists. */ +- NSS_WIFI_MAC_DB_ERROR_MAC_TABLE_FULL, +- /**< Error used to report that a Wi-Fi MAC table is full. */ +- NSS_WIFI_MAC_DB_ERROR_MAC_ENTRY_ALLOC_FAILED, +- /**< Error used to report a Wi-Fi MAC database entry allocation failure. */ +- NSS_WIFI_MAC_DB_ERROR_ENTRY_NOT_FOUND, +- /**< Error used to report that a Wi-Fi MAC database entry is not present. */ +- NSS_WIFI_MAC_DB_ERROR_MAC_ENTRY_UNHASHED, +- /**< Error used to report that a Wi-Fi MAC database entry is unhashed. */ +- NSS_WIFI_MAC_DB_ERROR_MAC_ENTRY_DELETE_FAILED, +- /**< Error used to report a Wi-Fi MAC database entry delete failure. */ +- NSS_WIFI_MAC_DB_ERROR_INVALID_NUM_ENTRIES_FAIL, +- /**< Error used to report the number of invalid Wi-Fi MAC database entries. */ +- NSS_WIFI_MAC_DB_ERROR_NOT_ALLOCATED_FAIL, +- /**< Error used to report that a Wi-Fi MAC database is not allocated. */ +- NSS_WIFI_MAC_DB_ERROR_INV_IF_RECVD_FAIL, +- /**< Error used to report that a Wi-Fi MAC database entry interface is invalid. */ +- NSS_WIFI_MAC_DB_ERROR_INVALID_EVENT, +- /**< Error used to report that a Wi-Fi MAC database event is invalid. */ +- NSS_WIFI_MAC_DB_ERROR_PN_INVALID, +- /**< Error used to report that a Wi-Fi MAC database entry pnode is invalid. */ +- NSS_WIFI_MAC_DB_ERROR_PHY_PN_INVALID, +- /**< Error used to report that a Wi-Fi MAC database entry radio pnode is invalid. */ +- NSS_WIFI_MAC_DB_ERROR_ENTRY_POOL_INVALID, +- /**< Error used to report that a Wi-Fi MAC database entry pool is invalid. */ +- NSS_WIFI_MAC_DB_ERROR_ENTRY_POOL_ALREADY_ALLOCATED, +- /**< Error used to report that a Wi-Fi MAC database entry pool exists. */ +- NSS_WIFI_MAC_DB_ERROR_GROUP_ENTRY_ADD_FAIL, +- /**< Error used to report that a Wi-Fi MAC database group entry add failure. */ +- NSS_WIFI_MAC_DB_ERROR_MAX, +- /**< Wi-Fi MAC database error maximum. */ +-}; +- +-/** +- * nss_wifi_mac_db_entry_create_msg +- * Wi-Fi MAC database entry create message. +- */ +-struct nss_wifi_mac_db_entry_create_msg { +- uint8_t mac_addr[ETH_ALEN]; /**< MAC address. */ +- uint16_t reserved; /**< Reserved bytes. */ +- int32_t nss_if; /**< NSS interface number. */ +-}; +- +-/** +- * nss_wifi_mac_db_entry_activity_info +- * Wi-Fi MAC database entry activity information. +- */ +-struct nss_wifi_mac_db_entry_activity_info { +- uint8_t mac_addr[ETH_ALEN]; /**< MAC address. */ +- uint16_t reserved; /**< Reserved bytes. */ +- int32_t nss_if; /**< NSS interface number. */ +-}; +- +-/** +- * nss_wifi_mac_db_entry_activity_info_msg +- * Wi-Fi MAC database entry activity information message. +- */ +-struct nss_wifi_mac_db_entry_activity_info_msg { +- uint32_t nentries; /**< Number of entries. */ +- struct nss_wifi_mac_db_entry_activity_info info[1]; +- /**< Wi-Fi MAC database entry activity information. */ +-}; +- +-/** + * nss_wifi_mac_db_entry_info_msg + * Wi-Fi MAC database entry information. + */ + struct nss_wifi_mac_db_entry_info_msg { +- uint8_t mac_addr[ETH_ALEN]; /**< MAC address. */ ++ uint8_t mac_addr[6]; /**< MAC address. */ + uint16_t flag; /**< Flag information about NSS interface. */ + int32_t nss_if; /**< NSS interface number. */ + uint32_t iftype; /**< NSS interface type. */ +@@ -163,17 +75,6 @@ struct nss_wifi_mac_db_entry_info_msg { + }; + + /** +- * nss_wifi_mac_db_entry_group_info_msg +- * Wi-Fi MAC database group of entries information. +- */ +-struct nss_wifi_mac_db_entry_group_info_msg { +- uint32_t num_entries; +- /**< Number of entries in group information message. */ +- struct nss_wifi_mac_db_entry_info_msg entry[NSS_WIFI_MAC_DB_GROUP_ENTRIES_MAX]; +- /**< Wi-Fi MAC database information specific message. */ +-}; +- +-/** + * nss_wifi_mac_db_msg + * Structure that describes Wi-Fi MAC database messages. + */ +@@ -186,12 +87,6 @@ struct nss_wifi_mac_db_msg { + union { + struct nss_wifi_mac_db_entry_info_msg nmfdbeimsg; + /**< Wi-Fi MAC database information specific message. */ +- struct nss_wifi_mac_db_entry_group_info_msg nmfdbegimsg; +- /**< Wi-Fi MAC database information specific message. */ +- struct nss_wifi_mac_db_entry_activity_info_msg nmfdbeact_imsg; +- /**< Wi-Fi MAC database entry activity information message. */ +- struct nss_wifi_mac_db_entry_create_msg nmfdbecmsg; +- /**< Wi-Fi MAC database entry create message. */ + } msg; /**< Message payload. */ + }; + +@@ -280,9 +175,4 @@ struct nss_ctx_instance *nss_register_wi + */ + void nss_unregister_wifi_mac_db_if(uint32_t if_num); + struct nss_ctx_instance *nss_wifi_mac_db_get_context(void); +- +-/** +- * @} +- */ +- + #endif /* __NSS_WIFI_MAC_DB_H */ +--- a/exports/nss_wifi_vdev.h ++++ b/exports/nss_wifi_vdev.h +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -16,7 +16,7 @@ + + /** + * @file nss_wifi_vdev.h +- * NSS-to-HLOS Wi-Fi virtual device interface definitions. ++ * NSS TO HLOS Wi-Fi virtual device interface definitions. + */ + + #ifndef __NSS_WIFI_VDEV_H +@@ -31,7 +31,6 @@ + /**< Offset of the metadata in a virtual device message. */ + #define NSS_WIFI_VDEV_DSCP_MAP_LEN 64 /**< Length of the DSCP MAP field. */ + #define NSS_WIFI_VDEV_IPV6_ADDR_LENGTH 16 /**< Size of the IPv6 address field. */ +-#define NSS_WIFI_VDEV_IPV6_ADDR_WORDS 4 /**< Size of the IPv6 address field in words. */ + #define NSS_WIFI_MAX_SRCS 4 /**< Maximum number of multicast sources. */ + #define NSS_WIFI_VDEV_MAX_ME_ENTRIES 32 /**< Maximum number of multicast enhancement entries. */ + +@@ -75,8 +74,6 @@ enum nss_wifi_vdev_msg_types { + NSS_WIFI_VDEV_INTERFACE_RECOVERY_RESET_MSG, + NSS_WIFI_VDEV_INTERFACE_RECOVERY_RECONF_MSG, + NSS_WIFI_VDEV_SET_GROUP_KEY, +- NSS_WIFI_VDEV_HMMC_MEMBER_ADD_MSG, +- NSS_WIFI_VDEV_HMMC_MEMBER_DEL_MSG, + NSS_WIFI_VDEV_MAX_MSG + }; + +@@ -131,15 +128,6 @@ enum nss_wifi_vdev_err_types { + NSS_WIFI_VDEV_VLAN_MODE_CONFIG_FAIL, + NSS_WIFI_VDEV_RECOVERY_RESET_FAIL, + NSS_WIFI_VDEV_RECOVERY_RECONF_FAIL, +- NSS_WIFI_VDEV_CONFIG_GROUP_KEY_FAIL, +- NSS_WIFI_VDEV_MULTIPASS_NOT_ENABLED, +- NSS_WIFI_VDEV_ALLOC_VLAN_MAP_FAILED, +- NSS_WIFI_VDEV_MTU_CHANGE_FAIL, +- NSS_WIFI_VDEV_MAC_ADDR_CHANGE_FAIL, +- NSS_WIFI_VDEV_PPE_PORT_CREATE_FAIL, +- NSS_WIFI_VDEV_PPE_PORT_DESTROY_FAIL, +- NSS_WIFI_VDEV_PPE_VSI_ASSIGN_FAIL, +- NSS_WIFI_VDEV_PPE_VSI_UNASSIGN_FAIL, + NSS_WIFI_VDEV_EINV_MAX_CFG + }; + +@@ -162,14 +150,6 @@ enum nss_wifi_vdev_ext_data_pkt_type { + NSS_WIFI_VDEV_EXT_TX_COMPL_PKT_TYPE = 11, /**< Tx completion. */ + NSS_WIFI_VDEV_EXT_DATA_PKT_TYPE_WDS_LEARN = 12, /**< WDS source port learning command. */ + NSS_WIFI_VDEV_EXT_DATA_PPDU_INFO = 13, /**< PPDU metadata information. */ +- NSS_WIFI_VDEV_EXT_DATA_PKT_TYPE_MCBC_RX = 14, /**< Multicast/broadcast packet received. */ +- NSS_WIFI_VDEV_MESH_EXT_DATA_PKT_TYPE_RX_SPL_PACKET = 15, +- /**< Mesh link VAP special packet. */ +- NSS_WIFI_VDEV_MESH_EXT_DATA_PKT_TYPE_RX_MCAST_EXC = 16, +- /**< Mesh link VAP multicast packet. */ +- NSS_WIFI_VDEV_EXT_DATA_PKT_TYPE_4ADDR = 17, /**< 4 address exception to host. */ +- NSS_WIFI_VDEV_EXT_DATA_MPDU_INFO = 18, /**< MPDU metadata information. */ +- NSS_WIFI_VDEV_EXT_DATA_PKT_TYPE_EAPOL = 19, /**< EAPOL packets. */ + NSS_WIFI_VDEV_EXT_DATA_PKT_TYPE_MAX + }; + +@@ -200,13 +180,6 @@ enum nss_wifi_vdev_cmd { + NSS_WIFI_VDEV_CFG_AST_OVERRIDE_CMD, /**< Configuration to set AST (Address Search Table) override on VAP. */ + NSS_WIFI_VDEV_CFG_SON_CAP_CMD, /**< Configuration to set software defined network capability on VAP. */ + NSS_WIFI_VDEV_CFG_MULTIPASS_CMD, /**< Configuration to enable multipass phrase capability on VAP. */ +- NSS_WIFI_VDEV_CFG_HLOS_TID_OVERRIDE_CMD, +- /**< Configuration to enable HLOS TID override on VAP. */ +- NSS_WIFI_VDEV_ENABLE_IGMP_ME_CMD, /**< Configuration to set IGMP multicast enhancement on VAP. */ +- NSS_WIFI_VDEV_CFG_WDS_BACKHAUL_CMD, +- /**< Configuration to set WDS backhaul extension on VAP. */ +- NSS_WIFI_VDEV_CFG_MCBC_EXC_TO_HOST_CMD, /**< Configuration to set multicast/broadcast exception to host on VAP. */ +- NSS_WIFI_VDEV_DROP_3ADDR_MCAST_CMD, /**< Configuration to drop multicast three address frames. */ + NSS_WIFI_VDEV_MAX_CMD + }; + +@@ -242,11 +215,6 @@ enum nss_wifi_vdev_vlan_tagging_mode { + NSS_WIFI_VDEV_VLAN_MAX /**< Wi-Fi maximum VLAN support type. */ + }; + +-enum vap_ext_mode { +- WIFI_VDEV_EXT_MODE_MESH_LINK = 1, /* Wi-Fi mesh VAP mode */ +- WIFI_VDEV_EXT_MODE_MAX, /* Wi-Fi maximum VAP mode */ +-}; +- + /** + * nss_wifi_vdev_config_msg + * Virtual device configuration. +@@ -272,9 +240,7 @@ struct nss_wifi_vdev_config_msg { + /**< VAP is configured as a smart monitor VAP. */ + uint8_t is_wrap; /**< Specifies whether the VAP is a WRAP-AP. */ + uint8_t is_nss_qwrap_en; /**< VAP is configured for NSS firmware QWRAP logic. */ +- uint8_t tx_per_pkt_vdev_id_check; /**< Transmit per-packet virtual device ID check. */ +- uint8_t align_pad; /**< Reserved field. */ +- uint32_t vap_ext_mode; /**< Different VAP extended modes. */ ++ uint8_t reserved[2]; /**< Reserved for 4-byte alignment padding. */ + }; + + /** +@@ -345,7 +311,7 @@ struct nss_wifi_vdev_me_snptbl_grp_creat + union { + uint32_t grpaddr_ip4; + /**< IPv4 address. */ +- uint32_t grpaddr_ip6[NSS_WIFI_VDEV_IPV6_ADDR_WORDS]; ++ uint8_t grpaddr_ip6[NSS_WIFI_VDEV_IPV6_ADDR_LENGTH]; + /**< IPv6 address. */ + } u; /**< IP address of the multicast group. */ + +@@ -366,7 +332,7 @@ struct nss_wifi_vdev_me_snptbl_grp_delet + union { + uint32_t grpaddr_ip4; + /**< IPv4 address. */ +- uint32_t grpaddr_ip6[NSS_WIFI_VDEV_IPV6_ADDR_WORDS]; ++ uint8_t grpaddr_ip6[NSS_WIFI_VDEV_IPV6_ADDR_LENGTH]; + /**< IPv6 address. */ + } u; /**< IP address of the multicast group. */ + +@@ -397,7 +363,7 @@ struct nss_wifi_vdev_me_snptbl_grp_mbr_a + union { + uint32_t grpaddr_ip4; + /**< IPv4 address. */ +- uint32_t grpaddr_ip6[NSS_WIFI_VDEV_IPV6_ADDR_WORDS]; ++ uint8_t grpaddr_ip6[NSS_WIFI_VDEV_IPV6_ADDR_LENGTH]; + /**< IPv6 address. */ + } u; /**< IP address of the multicast group. */ + +@@ -427,7 +393,7 @@ struct nss_wifi_vdev_me_snptbl_grp_mbr_d + union { + uint32_t grpaddr_ip4; + /**< IPv4 address. */ +- uint32_t grpaddr_ip6[NSS_WIFI_VDEV_IPV6_ADDR_WORDS]; ++ uint8_t grpaddr_ip6[NSS_WIFI_VDEV_IPV6_ADDR_LENGTH]; + /**< IPv6 address. */ + }u; /**< IP address of the multicast group. */ + uint8_t grp_addr[ETH_ALEN]; +@@ -449,7 +415,7 @@ struct nss_wifi_vdev_me_snptbl_grp_mbr_u + union { + uint32_t grpaddr_ip4; + /**< IPv4 address. */ +- uint32_t grpaddr_ip6[NSS_WIFI_VDEV_IPV6_ADDR_WORDS]; ++ uint8_t grpaddr_ip6[NSS_WIFI_VDEV_IPV6_ADDR_LENGTH]; + /**< IPv6 address. */ + }u; /**< IP address of the multicast group. */ + +@@ -464,66 +430,6 @@ struct nss_wifi_vdev_me_snptbl_grp_mbr_u + }; + + /** +- * nss_wifi_vdev_me_hmmc_add_msg +- * Information for adding an entry into the host-managed multicast list. +- */ +-struct nss_wifi_vdev_me_hmmc_add_msg { +- uint32_t ether_type; /**< IPv4 or IPv6. */ +- union { +- uint32_t ipv4_addr; +- /**< IPv4 multicast group address. */ +- uint32_t ipv6_addr[NSS_WIFI_VDEV_IPV6_ADDR_WORDS]; +- /**< IPv6 multicast group address. */ +- } u; /**< Type of group addresses. */ +- uint32_t netmask; /**< IP subnet netmask. */ +-}; +- +-/** +- * nss_wifi_vdev_me_hmmc_del_msg +- * Information for deleting an entry from the host-managed multicast list. +- */ +-struct nss_wifi_vdev_me_hmmc_del_msg { +- uint32_t ether_type; /**< IPv4 or IPv6. */ +- union { +- uint32_t ipv4_addr; +- /**< IPv4 multicast group address. */ +- uint32_t ipv6_addr[NSS_WIFI_VDEV_IPV6_ADDR_WORDS]; +- /**< IPv6 multicast group address. */ +- } u; /**< Type of group addresses. */ +- uint32_t netmask; /**< IP subnet netmask. */ +-}; +- +-/** +- * nss_wifi_vdev_me_deny_ip_add_msg +- * Information for adding an entry into the denylist. +- */ +-struct nss_wifi_vdev_me_deny_ip_add_msg { +- uint32_t ether_type; /**< IPv4 or IPv6. */ +- union { +- uint32_t ipv4_addr; +- /**< IPv4 multicast group address. */ +- uint32_t ipv6_addr[NSS_WIFI_VDEV_IPV6_ADDR_WORDS]; +- /**< IPv6 multicast group address. */ +- } u; /**< Type of group addresses. */ +- uint32_t netmask; /**< IP subnet netmask. */ +-}; +- +-/** +- * nss_wifi_vdev_me_deny_ip_del_msg +- * Information for deleting an entry from the denylist. +- */ +-struct nss_wifi_vdev_me_deny_ip_del_msg { +- uint32_t ether_type; /**< IPv4 or IPv6. */ +- union { +- uint32_t ipv4_addr; +- /**< IPv4 multicast group address. */ +- uint32_t ipv6_addr[NSS_WIFI_VDEV_IPV6_ADDR_WORDS]; +- /**< IPv6 multicast group address. */ +- } u; /**< Type of group addresses. */ +- uint32_t netmask; /**< IP subnet netmask. */ +-}; +- +-/** + * nss_wifi_vdev_me_snptbl_deny_grp_add_msg + * Information for adding a snooplist member to a deny list. + */ +@@ -818,49 +724,6 @@ struct nss_wifi_vdev_ppdu_metadata { + }; + + /** +- * nss_wifi_vdev_peer_mpdu_metadata +- * MPDU metadata. +- */ +-struct nss_wifi_vdev_peer_mpdu_metadata { +- uint16_t peer_id; /**< Corresponding peer ID. */ +- uint8_t tid; /**< TID of the flow or MPDU queue. */ +- uint8_t msdu_info; /**< First or last MSDU information. */ +- uint32_t ppdu_id; /**< PPDU ID. */ +- uint32_t tsf; /**< Timing synchronization function. */ +- uint8_t transmit_cnt; /**< Transmission count. */ +- uint8_t status; /**< Frame acknowledged/failed. */ +- uint16_t reserved; /**< Reserved. */ +-}; +- +-/** +- * nss_wifi_vdev_eapol_mdata_dir +- * EAPOL metadata direction. +- */ +-enum nss_wifi_vdev_eapol_mdata_dir { +- WIFI_VDEV_EAPOL_MDATA_TX, /**< EAPOL metadata for transmit direction. */ +- WIFI_VDEV_EAPOL_MDATA_RX /**< EAPOL metadata for receive direction. */ +-}; +- +-/** +- * nss_wifi_vdev_eapol_metadata +- * Metadata per EAPOL packet. +- */ +-struct nss_wifi_vdev_eapol_per_packet_metadata { +- enum nss_wifi_vdev_eapol_mdata_dir dir; /**< EAPOL metadata direction. */ +- uint16_t peer_id; /**< Peer ID. */ +-}; +- +-/** +- * nss_wifi_vdev_addr4_data_metadata +- * Address 4 metadata +- */ +-struct nss_wifi_vdev_addr4_data_metadata { +- uint16_t peer_id; /**< Peer ID. */ +- uint8_t sa_valid; /**< Source address is valid. */ +- uint8_t addr4_valid; /**< Address 4 is valid. */ +-}; +- +-/** + * nss_wifi_vdev_per_packet_metadata + * Wi-Fi per packet metadata content. + */ +@@ -889,12 +752,6 @@ struct nss_wifi_vdev_per_packet_metadata + /**< Per packet Tx metadata structure for wireless distribution system mode. */ + struct nss_wifi_vdev_ppdu_metadata ppdu_metadata; + /**< Per packet PPDU metadata needed for per PPDU copy mode. */ +- struct nss_wifi_vdev_addr4_data_metadata addr4_metadata; +- /**< Create metadata for the WDS extension interface. */ +- struct nss_wifi_vdev_peer_mpdu_metadata mpdu_metadata; +- /**< Per packet Tx metadata structure for Tx capture info per MPDU. */ +- struct nss_wifi_vdev_eapol_per_packet_metadata eapol_metadata; +- /**< Per packet metadata structure for EAPOL. */ + } metadata; + /**< Metadata payload for special data receive message. */ + }; +@@ -904,8 +761,9 @@ struct nss_wifi_vdev_per_packet_metadata + * Metadata payload for Mesh mode receive. + */ + struct nss_wifi_vdev_meshmode_rx_metadata { +- uint16_t rs_ratephy_lo; /**< PHY rate lower order bytes. */ +- uint16_t rs_ratephy_hi; /**< PHY rate higher order bytes. */ ++ uint16_t rs_ratephy; /**< PHY rate. */ ++ uint16_t rs_ratephy_lo; /**< PHY rate lower bytes. */ ++ uint16_t rs_ratephy_hi; /**< PHY rate higher bytes. */ + uint16_t cntr_chan_freq; /** Center channel frequency. */ + uint16_t vdev_id; /**< Virtual device ID. */ + uint16_t peer_id; /**< Peer ID. */ +@@ -1031,22 +889,6 @@ struct nss_wifi_vdev_mcast_enhance_stats + * Number of multicast bytes received for multicast enhancement. + */ + uint32_t mcast_rcvd_bytes; +- +- /** +- * Number of IGMP packets received for conversion to unicast. +- */ +- uint32_t igmp_rcvd; +- +- /** +- * Number of IGMP packets converted to unicast as a part of +- * VoW IGMP improvements. +- */ +- uint32_t igmp_ucast_converted; +- +- /** +- * Number of group members that could not be added due to failed allocation. +- */ +- uint32_t mcast_mbr_alloc_failed; + }; + + /** +@@ -1055,8 +897,8 @@ struct nss_wifi_vdev_mcast_enhance_stats + */ + struct nss_wifi_vdev_stats_sync_msg { + uint32_t dropped; /**< Number of dropped packets. */ +- uint32_t tx_enqueue_cnt; /**< Transmit pnode enqueue count. */ +- uint32_t tx_enqueue_fail_cnt; /**< Transmit pnode enqueue count. */ ++ uint32_t tx_enqueue_cnt; /**< Tx pnode enqueue count. */ ++ uint32_t tx_enqueue_fail_cnt; /**< Tx pnode enqueue count. */ + uint32_t tx_intra_bss_enqueue_cnt; /**< Intra BSS enqueue count. */ + uint32_t tx_intra_bss_enqueue_fail_cnt; + /**< Intra BSS enqueue fail count. */ +@@ -1064,12 +906,12 @@ struct nss_wifi_vdev_stats_sync_msg { + /**< Virual device multicast/broadcast packet count in AP mode. */ + uint32_t tx_intra_bss_mcast_send_fail_cnt; + /**< Virtual device multicast/broadcast packet count in AP mode. */ +- uint32_t tx_enqueue_bytes; /**< Transmit enqueue bytes count. */ ++ uint32_t tx_enqueue_bytes; /**< Tx enqueue bytes count. */ + uint32_t rx_enqueue_cnt; /**< Ethernet node enqueue count. */ + uint32_t rx_enqueue_fail_cnt; /**< Ethernet node enqueue fail count. */ + uint32_t rx_except_enqueue_cnt; /**< N2H (NSS to Host) node enqueue count. */ + uint32_t rx_except_enqueue_fail_cnt; /**< N2H (NSS to Host) node enqueue fail count. */ +- uint32_t rx_enqueue_bytes; /**< Receive enqueue bytes count. */ ++ uint32_t rx_enqueue_bytes; /**< Rx enqueue bytes count. */ + uint32_t rx_wds_learn_send_cnt; /**< Virtual device WDS source port learn count. */ + uint32_t rx_wds_learn_send_fail_cnt; /**< Virtual device WDS source count fail. */ + struct nss_wifi_vdev_mcast_enhance_stats wvmes; +@@ -1089,17 +931,6 @@ struct nss_wifi_vdev_stats_sync_msg { + uint32_t tx_eapol_cnt; /**< Number of EAPoL frames in transmit direction. */ + uint32_t nawds_tx_mcast_cnt; /**< Number of NAWDS packets sent. */ + uint32_t nawds_tx_mcast_bytes; /**< Number of NAWDS bytes sent. */ +- uint32_t per_pkt_vdev_check_fail; /**< Number of packets that failed vdev id check in Tx. */ +- uint32_t rx_mcast_cnt; /**< Receive multicast packet count. */ +- uint32_t rx_mcast_bytes; /**< Receive multicast bytes count. */ +- uint32_t rx_decrypt_err; /**< Receive decryption error */ +- uint32_t rx_mic_err; /**< Receive MIC error */ +- uint32_t mcbc_exc_host_fail_cnt; +- /**< Number of multicast/broadcast packets failed to send to host through exception path. */ +- uint32_t addr4_exc_fail; /**< Number of failed 4 address exceptions. */ +- uint32_t addr4_exc_pass; /**< Number of successful 4 address exceptions. */ +- uint32_t eapol_over_nl_exc_fail_cnt; /**< Number of EAPOL over NL exception packet failures. */ +- uint32_t eapol_over_nl_exc_pass_cnt; /**< Number of EAPOL over NL exception packet successes. */ + }; + + /** +@@ -1130,15 +961,7 @@ struct nss_wifi_vdev_msg { + struct nss_wifi_vdev_me_snptbl_grp_mbr_update_msg vdev_grp_member_update; + /**< Updates a snooplist group member. */ + struct nss_wifi_vdev_me_snptbl_deny_grp_add_msg vdev_deny_member_add; +- /**< Add a snooplist member to the deny list. */ +- struct nss_wifi_vdev_me_hmmc_add_msg vdev_hmmc_member_add; +- /**< Adds a member to the HMMC list. */ +- struct nss_wifi_vdev_me_hmmc_del_msg vdev_hmmc_member_del; +- /**< Deletes a member from the HMMC list. */ +- struct nss_wifi_vdev_me_deny_ip_add_msg vdev_deny_list_member_add; +- /**< Adds a member to the denylist. */ +- struct nss_wifi_vdev_me_deny_ip_del_msg vdev_deny_list_member_del; +- /**< Deletes a member from the denylist. */ ++ /**< Adds a snooplist member to a deny list. */ + struct nss_wifi_vdev_txmsg vdev_txmsgext; + /**< Transmits special data. */ + struct nss_wifi_vdev_vow_dbg_cfg_msg vdev_vow_dbg_cfg; +--- a/exports/nss_wifili_if.h ++++ b/exports/nss_wifili_if.h +@@ -1,19 +1,16 @@ + /* + ************************************************************************** +- * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. +- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for any +- * purpose with or without fee is hereby granted, provided that the above +- * copyright notice and this permission notice appear in all copies. +- * ++ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. ++ * Permission to use, copy, modify, and/or distribute this software for ++ * any purpose with or without fee is hereby granted, provided that the ++ * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT ++ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + +@@ -65,7 +62,7 @@ + /**< Maximum number of bandwidth supported. */ + #define NSS_WIFILI_REPT_MU_MIMO 1 + #define NSS_WIFILI_REPT_MU_OFDMA_MIMO 3 +-#define NSS_WIFILI_MAX_RESERVED_TYPE 2 ++#define NSS_WIFILI_MAX_RESERVED_TYPE 3 + /**< Maximum reserved type. */ + #define NSS_WIFILI_SOC_PER_PACKET_METADATA_SIZE 60 + /**< Metadata area total size. */ +@@ -87,7 +84,7 @@ + /**< Maximum DMA error codes. */ + #define NSS_WIFILI_MAX_TID 8 + /**< Maximum TID values. */ +-#define NSS_WIFILI_DELAY_INDEX_MAX 13 ++#define NSS_WIFILI_DELAY_INDEX_MAX 10 + /**< Maximum software enqueue delay buckets. */ + #define NSS_WIFILI_MAX_NUMBER_OF_ADDTNL_SEG 64 + /**< Maximum number of additional pages allocated from host. */ +@@ -97,69 +94,12 @@ + /**< Maximum number of flow queues. */ + #define NSS_WIFILI_WBM_INTERNAL_ERR_MAX 5 + /**< WBM internal maximum errors. */ +-#define NSS_WIFILI_MAX_VOW_TID_NUM 4 +- /**< Maximum version 3 TID values. */ +- +-/* +- * Peer Size in Bytes +- */ +-#define NSS_WIFILI_PEER_SIZE 1600 +- +-/* +- * Maximum size of target SoC type string +- */ +-#define NSS_WIFILI_SOC_STRING_SIZE_MAX 24 + + /* + * Radio specific flags + */ + #define NSS_WIFILI_PDEV_FLAG_V3_STATS_ENABLED 0x00000008 + /**< Flag to enable version 3 statistics. */ +-/** +- * Peer message flags. +- */ +-#define NSS_WIFILI_PEER_MSG_DISABLE_4ADDR 0x01 +- +-#ifdef __KERNEL__ /* only kernel will use. */ +- +-/** +- * Wireless Multimedia Extention Access Category to TID. @hideinitializer +- */ +-#define NSS_WIFILI_WME_AC_TO_TID(_ac) ( \ +- ((_ac) == NSS_WIFILI_WME_AC_VO) ? 6 : \ +- (((_ac) == NSS_WIFILI_WME_AC_VI) ? 5 : \ +- (((_ac) == NSS_WIFILI_WME_AC_BK) ? 1 : \ +- 0))) +- +-/** +- * Wireless TID to Wireless Extension Multimedia Access Category. @hideinitializer +- */ +-#define NSS_WIFILI_TID_TO_WME_AC(_tid) ( \ +- (((_tid) == 0) || ((_tid) == 3)) ? NSS_WIFILI_WME_AC_BE : \ +- ((((_tid) == 1) || ((_tid) == 2)) ? NSS_WIFILI_WME_AC_BK : \ +- ((((_tid) == 4) || ((_tid) == 5)) ? NSS_WIFILI_WME_AC_VI : \ +- NSS_WIFILI_WME_AC_VO))) +-#endif /* __KERNEL */ +- +-/** +- * nss_wifili_thread_scheme_id +- * List of thread scheme IDs. +- */ +-enum nss_wifili_thread_scheme_id { +- NSS_WIFILI_THREAD_SCHEME_ID_0, /**< High priority scheme index. */ +- NSS_WIFILI_THREAD_SCHEME_ID_1, /**< Low priority scheme index. */ +- NSS_WIFILI_THREAD_SCHEME_ID_2, /**< High priority scheme index. */ +- NSS_WIFILI_THREAD_SCHEME_ID_MAX /**< Maximum value of scheme index. */ +-}; +- +-/* +- * nss_wifili_thread_scheme_priority +- * List of wifili thread scheme priority. +- */ +-enum nss_wifili_thread_scheme_priority { +- NSS_WIFILI_LOW_PRIORITY_SCHEME, /**< Low priority scheme. */ +- NSS_WIFILI_HIGH_PRIORITY_SCHEME, /**< High priority scheme. */ +-}; + + /** + * nss_wifili_wme_stream_classes +@@ -244,20 +184,6 @@ enum nss_wifili_msg_types { + NSS_WIFILI_ISOLATION_MSG, + NSS_WIFILI_PEER_EXT_STATS_MSG, + NSS_WIFILI_CLR_STATS, +- NSS_WIFILI_PEER_4ADDR_EVENT_MSG, +- NSS_WIFILI_DBDC_REPEATER_LOOP_DETECTION_MSG, +- NSS_WIFILI_PEER_UPDATE_AUTH_FLAG, +- NSS_WIFILI_SEND_MESH_CAPABILITY_INFO, +- NSS_WIFILI_PDEV_TX_CAPTURE_MSG, +- NSS_WIFILI_PEER_TX_CAPTURE_MSG, +- NSS_WIFILI_PDEV_V3_RX_ERROR_STATS_SYNC_MSG, +- NSS_WIFILI_SEND_DBG_LATENCY_EVENT_MSG, +- NSS_WIFILI_SET_TX_LATENCY_THRESHOLD, +- NSS_WIFILI_SET_TX_LATENCY_PKTLOG_THRESHOLD, +- NSS_WIFILI_SET_V3_STATS_TX_DROP_TID, +- NSS_WIFILI_SET_V3_STATS_TX_DROP_THRESHOLD, +- NSS_WIFILI_ASTENTRY_SYNC_MSG, +- NSS_WIFILI_MECENTRY_SYNC_MSG, + NSS_WIFILI_MAX_MSG + }; + +@@ -404,8 +330,6 @@ enum nss_wifili_error_types { + /**< Invalid TLV length. */ + NSS_WIFILI_EMESG_RX_BUF_LEN_INVALID, + /**< Invalid Rx buffer length. */ +- NSS_WIFILI_EMSG_TX_CAPTURE_MODE_UPDATE_FAIL, +- /**< Tx capture mode update failure. */ + NSS_WIFILI_EMSG_UNKNOWN + /**< Unknown error message. */ + }; +@@ -435,7 +359,6 @@ enum nss_wifili_radio_cmd { + NSS_WIFILI_SET_FORCE_CLIENT_MCAST_TRAFFIC, /**< Flag to force multicast traffic for a radio. */ + NSS_WIFILI_SET_DROP_SECONDARY_MCAST, /**< Flag to drop multicast traffic on secondary radio. */ + NSS_WIFILI_SET_DBDC_FASTLANE, /**< Flag to set DBDC fast-lane mode. */ +- NSS_WIFILI_SET_DBDC_NOBACKHAUL_RADIO, /**< Flag to set DBDC to no backhaul radio. */ + NSS_WIFILI_RADIO_MAX_CMD /**< Maximum radio command index. */ + }; + +@@ -541,8 +464,6 @@ enum nss_wifili_stats_tx_comp { + NSS_WIFILI_STATS_TX_DESC_FREE_INV_COOKIE, /**< Number of invalid cookie packets. */ + NSS_WIFILI_STATS_TX_DESC_FREE_HW_RING_EMPTY, /**< Number of times hardware ring empty found. */ + NSS_WIFILI_STATS_TX_DESC_FREE_REAPED, /**< Number of Tx packets that are reaped out of the Tx completion ring. */ +- NSS_WIFILI_STATS_TX_CAPTURE_ENQUEUE, /**< Number of Tx packets enqueued to host. */ +- NSS_WIFILI_STATS_TX_CAPTURE_ENQUEUE_FAIL, /**< Number of Tx packets failed to enqueue to host. */ + NSS_WIFILI_STATS_TX_DESC_FREE_MAX, /**< Number of Tx completion statistics. */ + }; + +@@ -642,14 +563,14 @@ enum nss_wifili_stats_rxdma_ring { + * Wifili WBM(Wireless Buffer Manager) ring statistics. + */ + enum nss_wifili_stats_wbm { +- NSS_WIFILI_STATS_WBM_IE_LOCAL_ALLOC_FAIL, /**< Number of Wireless Buffer Manager internal local allocation failures. */ +- NSS_WIFILI_STATS_WBM_SRC_DMA, /**< Number of receive invalid source DMA. */ +- NSS_WIFILI_STATS_WBM_SRC_DMA_CODE_INV, /**< Number of receive invalid source DMA. */ +- NSS_WIFILI_STATS_WBM_SRC_REO, /**< Number of receive invalid source reorder. */ +- NSS_WIFILI_STATS_WBM_SRC_REO_CODE_NULLQ, /**< Number of receive invalid reorder error with NULL queue. */ +- NSS_WIFILI_STATS_WBM_SRC_REO_CODE_INV, /**< Number of receive invalid reorder code invalid. */ +- NSS_WIFILI_STATS_WBM_SRC_INV, /**< Number of receive invalid source invalid. */ +- NSS_WIFILI_STATS_WBM_MAX, /**< Number of receive Wireless Buffer Manager statistics. */ ++ NSS_WIFILI_STATS_WBM_IE_LOCAL_ALLOC_FAIL, /**< Number of Wireless Buffer Manger internal local allocation failures. */ ++ NSS_WIFILI_STATS_WBM_SRC_DMA, /**< Number of Rx invalid source DMA. */ ++ NSS_WIFILI_STATS_WBM_SRC_DMA_CODE_INV, /**< Number of Rx invalid source DMA. */ ++ NSS_WIFILI_STATS_WBM_SRC_REO, /**< Number of Rx invalid source reorder. */ ++ NSS_WIFILI_STATS_WBM_SRC_REO_CODE_NULLQ, /**< Number of Rx invalid reorder error with NULL queue. */ ++ NSS_WIFILI_STATS_WBM_SRC_REO_CODE_INV, /**< Number of Rx invalid reorder code invalid. */ ++ NSS_WIFILI_STATS_WBM_SRC_INV, /**< Number of Rx invalid source invalid. */ ++ NSS_WIFILI_STATS_WBM_MAX, /**< Number of Rx Wireless Buffer Manager statistics. */ + }; + + /** +@@ -681,12 +602,9 @@ struct nss_wifili_stats { + * NSS wifili soc stats + */ + struct nss_wifili_soc_stats { +- uint32_t soc_maxpdev; +- /**< Maximum number of radios per SoC. */ ++ uint32_t soc_maxpdev; /**< Maximum number of radios per SoC. */ + struct nss_wifili_stats stats_wifili; +- /**< Per-SoC statistics. */ +- char soc_type[NSS_WIFILI_SOC_STRING_SIZE_MAX]; +- /**< Target SoC type string. */ ++ /**< Per-SoC statistics. */ + }; + + /** +@@ -732,13 +650,11 @@ struct nss_wifili_hal_srng_info{ + */ + struct nss_wifili_hal_srng_soc_msg { + uint32_t dev_base_addr; +- /**< Base address of WLAN device. */ ++ /**< Base address of wlan dev. */ + uint32_t shadow_rdptr_mem_addr; + /**< Shadow read pointer address. */ + uint32_t shadow_wrptr_mem_addr; + /**< Shadow write pointer address. */ +- uint32_t lmac_rings_start_id; +- /**< Start ID of LMAC rings. */ + }; + + /** +@@ -857,10 +773,6 @@ struct nss_wifili_pdev_init_msg { + /**< Number of descriptors per Rx pool. */ + uint32_t target_pdev_id; + /**< Target physical device ID. */ +- uint8_t scheme_id; +- /**< Radio scheme ID. */ +- uint8_t reserved[3]; +- /**< Padding for alignment. */ + }; + + /** +@@ -911,10 +823,6 @@ struct nss_wifili_peer_msg { + /**< AST hash to be used during packet transmission. */ + uint32_t pext_stats_mem; + /**< Peer extended statistics memory. */ +- uint32_t flags; +- /**< Peer flags. */ +- uint32_t peer_memory_size; +- /**< Peer memory allocated from host to NSS. */ + }; + + /** +@@ -1030,12 +938,10 @@ struct nss_wifili_tx_tcl_ring_stats { + * Tx completion ring statistics. + */ + struct nss_wifili_tx_comp_ring_stats { +- uint32_t invalid_bufsrc; /**< Tx completion ring descriptor invalid buffer source. */ +- uint32_t invalid_cookie; /**< Tx completion ring descriptor has invalid cookies. */ +- uint32_t hw_ring_empty; /**< Tx completion hardware ring empty. */ +- uint32_t ring_reaped; /**< Tx completion successfull ring reaped. */ +- uint32_t tx_cap_enqueue_count; /**< Number of Tx packets enqueued to host. */ +- uint32_t tx_cap_enqueue_fail_count; /**< Number of Tx packets failed to enqueue to host. */ ++ uint32_t invalid_bufsrc; /**< Tx comp (Completion) ring descriptor invalid buffer source. */ ++ uint32_t invalid_cookie; /**< Tx comletion ring descriptor has invalid cookies. */ ++ uint32_t hw_ring_empty; /**< Tx completion hardware ring empty. */ ++ uint32_t ring_reaped; /**< Tx completion successfull ring reaped. */ + }; + + /** +@@ -1074,16 +980,16 @@ struct nss_wifili_rx_wbm_ring_stats { + uint32_t invalid_buf_mgr; /**< Invalid buffer manager. */ + uint32_t err_src_rxdma; /**< Wireless Buffer Manager source is Rx DMA ring. */ + uint32_t err_src_rxdma_code_inv; /**< Wireless Buffer Manager source DMA reason unknown. */ +- uint32_t err_src_reo; /**< Wireless Buffer Manager source is receive reorder ring. */ +- uint32_t err_src_reo_code_nullq; /**< Wireless Buffer Manager source receive reorder ring because of NULL TLV. */ +- uint32_t err_src_reo_code_inv; /**< Wireless Buffer Manager source receive reorder ring reason unknown. */ ++ uint32_t err_src_reo; /**< Wireless Buffer Manager source is Rx reorder ring. */ ++ uint32_t err_src_reo_code_nullq; /**< Wireless Buffer Manager source Rx reorder ring because of NULL TLV. */ ++ uint32_t err_src_reo_code_inv; /**< Wireless Buffer Manager source Rx reorder ring reason unknown. */ + uint32_t err_src_invalid; /**< Wireless Buffer Manager source is unknown. */ + uint32_t err_reo_codes[NSS_WIFILI_REO_CODE_MAX]; +- /**< Receive reoder error codes. */ ++ /**< Rx reoder error codes. */ + uint32_t err_dma_codes[NSS_WIFILI_DMA_CODE_MAX]; + /**< DMA error codes. */ + uint32_t err_internal_codes[NSS_WIFILI_WBM_INTERNAL_ERR_MAX]; +- /**< Wireless Buffer Manager error codes. */ ++ /**< Wireless Buffer Manger error codes. */ + }; + + /** +@@ -1260,50 +1166,6 @@ struct nss_wifili_pdev_v3_delay_stats_sy + }; + + /** +- * nss_wifili_v3_reo_stats +- * Wifili REO error statistics for version 3. +- */ +-struct nss_wifili_v3_reo_stats { +- uint32_t err_src_reo_code_inv; +- /**< Reason for the Wireless Buffer Manager Rx REO ring is unknown.. */ +- uint32_t err_reo_codes[NSS_WIFILI_REO_CODE_MAX]; +- /**< Rx REO error codes. */ +-}; +- +-/** +- * nss_wifili_v3_rxdma_stats +- * Wifili Rx DMA error statistics for version 3. +- */ +-struct nss_wifili_v3_rxdma_stats { +- uint32_t err_src_rxdma_code_inv; +- /**< DMA reason unknown. */ +- uint32_t err_dma_codes[NSS_WIFILI_DMA_CODE_MAX]; +- /**< DMA Rx error codes. */ +-}; +- +-/** +- * nss_wifili_radio_error_stats_v3 +- * Wifili radio error statistics for version 3. +- */ +-struct nss_wifili_radio_error_stats_v3 { +- struct nss_wifili_v3_reo_stats reo_stats[NSS_WIFILI_MAX_VOW_TID_NUM]; +- /**< REO statistics per maximum version 3 TID values. */ +- struct nss_wifili_v3_rxdma_stats rxdma_stats[NSS_WIFILI_MAX_VOW_TID_NUM]; +- /**< Rx DMA statistics per maximum version 3 TID values. */ +-}; +- +-/** +- * nss_wifili_pdev_v3_error_stats_sync_msg +- * Wifili message to synchronize version 3 error statistics to HLOS. +- */ +-struct nss_wifili_pdev_v3_error_stats_sync_msg { +- uint32_t radio_id; +- /**< Radio ID of Wifili message. */ +- struct nss_wifili_radio_error_stats_v3 wlpv3_error_stats; +- /**< Wifli version 3 error statistics. */ +-}; +- +-/** + * nss_wifili_device_stats + * Wifili specific statistics. + */ +@@ -1339,8 +1201,6 @@ struct nss_wifili_device_stats { + struct nss_wifili_stats_sync_msg { + struct nss_wifili_device_stats stats; + /**< Device statistics. */ +- uint32_t target_type; +- /**< Target SoC type. */ + }; + + /** +@@ -1417,7 +1277,6 @@ struct nss_wifili_rx_err { + struct nss_wifili_rx_ctrl_stats { + struct nss_wifili_rx_err err; /**< Rx peer errors. */ + uint32_t multipass_rx_pkt_drop; /**< Total number of multipass packets without a VLAN header. */ +- uint32_t peer_unauth_rx_pkt_drop; /**< Number of receive packets dropped due to an authorized peer. */ + uint32_t reserved_type[NSS_WIFILI_MAX_RESERVED_TYPE]; /**< Reserved type for future use. */ + uint32_t non_amsdu_cnt; /**< Number of MSDUs with no MSDU level aggregation. */ + uint32_t amsdu_cnt; /**< Number of MSDUs part of AMSDU. */ +@@ -1433,19 +1292,6 @@ struct nss_wifili_rx_ctrl_stats { + uint32_t rx_intra_bss_fail_bytes; /**< Total Intra-BSS bytes received. */ + uint32_t bcast_rcv_cnt; /**< Total number of broadcast packets received. */ + uint32_t bcast_rcv_bytes; /**< Total number of broadcast bytes received. */ +- uint32_t defrag_mcast_drop; /**< Total number of defrag multicast dropped packets. */ +- uint32_t mcast_3addr_drop; /**< Total number of 3 address multicast dropped packets. */ +-}; +- +-/** +- * nss_wifili_retry_ctrl_stats +- * Peer retry statistics. +- */ +-struct nss_wifili_retry_ctrl_stats { +- uint32_t tx_failed_retry_count; /**< Transmit failed retry count. */ +- uint32_t tx_retry_count; /**< Transmit retry count. */ +- uint32_t tx_multiple_retry_count; /**< Transmit multiple retry count. */ +- uint32_t rx_retry_count; /**< Receive retry count. */ + }; + + /** +@@ -1458,8 +1304,6 @@ struct nss_wifili_peer_ctrl_stats { + /**< Peer Tx control statistics. */ + struct nss_wifili_rx_ctrl_stats rx; + /**< Peer Rx control statistics. */ +- struct nss_wifili_retry_ctrl_stats retry; +- /**< Peer retry Statistics. */ + }; + + /** +@@ -1686,14 +1530,6 @@ struct nss_wifili_peer_isolation_msg { + }; + + /** +- * nss_wifili_dbdc_repeater_loop_detection_msg +- * Wifili DBDC repeater loop detection message. +- */ +-struct nss_wifili_dbdc_repeater_loop_detection_msg { +- bool dbdc_loop_detected; /**< DBDC repeater loop detection flag. */ +-}; +- +-/** + * nss_wifili_dbdc_repeater_set_msg + * Wifili DBDC repeater set message. + */ +@@ -1746,16 +1582,6 @@ struct nss_wifili_clr_stats_msg { + }; + + /** +- * nss_wifili_update_auth_flag +- * Peer authentication flag message. +- */ +-struct nss_wifili_peer_update_auth_flag { +- uint16_t peer_id; /**< Peer ID. */ +- uint8_t auth_flag; /**< Peer authentication flag. */ +- uint8_t reserved; /**< Alignment padding. */ +-}; +- +-/** + * nss_wifili_update_pdev_lmac_id_msg + * Physical device ID and lower MAC ID update message. + */ +@@ -1775,25 +1601,6 @@ struct nss_wifili_radio_cmd_msg { + uint32_t value; /**< Value of the command. */ + }; + +-/* +- * nss_wifili_pdev_tx_capture_msg +- * Tx capture enable per pdev message. +- */ +-struct nss_wifili_pdev_tx_capture_msg { +- uint8_t pdev_id; /**< Physical device ID. */ +- uint8_t tx_cap_config; /**< Flag to enable or disable Tx capture for physical device. */ +-}; +- +-/* +- * nss_wifili_peer_tx_capture_msg +- * Tx capture enable per peer message. +- */ +-struct nss_wifili_peer_tx_capture_msg { +- uint16_t peer_id; /**< Peer ID. */ +- uint8_t tx_cap_config; /**< Flag to enable or disable Tx capture for peer. */ +- uint8_t reserved; /**< Reserved. */ +-}; +- + /** + * nss_wifili_radio_buf_cfg_msg + * Wi-Fi Radio buffer requirement configuration. +@@ -1831,108 +1638,6 @@ struct nss_wifili_radio_cfg_msg { + }; + + /** +- * struct wifili_peer_wds_4addr_allow_msg +- * Per-peer four address configuration message. +- */ +-struct nss_wifili_peer_wds_4addr_allow_msg { +- uint32_t peer_id; /**< Peer ID. */ +- uint32_t if_num; /**< Associate virtual interface number. */ +- bool enable; /**< Boolean flag to enable/disable four address frames. */ +-}; +- +-/** +- * struct nss_wifili_mesh_capability_info +- * Wi-Fi mesh capability flag. +- */ +-struct nss_wifili_mesh_capability_info { +- bool mesh_enable; /**< Wi-Fi mesh capability flag. */ +-}; +- +-/** +- * struct nss_wifili_dbg_latency_event_msg +- * Wifili debug latency event sent to host. +- */ +-struct nss_wifili_dbg_latency_event_msg { +- uint32_t tid; /**< Traffic Identifier (TID) value. */ +- uint32_t pktlog_en; /**< Packet log enable value. */ +- uint32_t value; /**< Packet log enumeration value. */ +- uint32_t tx_latency; /**< Transmit latency value of event. */ +- uint32_t tx_drop; /**< Tx drop value */ +- uint16_t peer_id; /**< Peer ID of event. */ +- uint8_t reserved[2]; /**< Reserved field. */ +-}; +- +-/* +- * nss_wifili_set_tx_latency_threshold +- * Sets transmit latency threshold value. +- */ +-struct nss_wifili_set_tx_latency_threshold { +- uint32_t radio_id; /**< Radio ID of event. */ +- uint32_t latency_threshold; /**< Latency threshold value.. */ +-}; +- +-/* +- * nss_wifli_v3_stats_set_vow_tid_msg +- * Sets TID value for version 3 debugging. +- */ +-struct nss_wifli_v3_stats_set_vow_tid_msg { +- uint32_t radio_id; /**< Radio ID. */ +- uint32_t tid; /**< Traffic Identifier (TID) value. */ +-}; +- +-/* +- * nss_wifili_set_tx_drop_threshold +- * Set Tx drop threshold value. +- */ +-struct nss_wifili_set_tx_drop_threshold { +- uint32_t radio_id; /**< Radio ID. */ +- uint32_t tx_drop_threshold; /**< Tx drop threshold value. */ +-}; +- +-/* +- * nss_wifi_peer_map_astentry_info +- * NSS wifi peer map AST entry information. +- */ +-struct nss_wifi_peer_map_astentry_info { +- uint16_t entry_no; /**< Entry number. */ +- uint16_t dest_mac_addr[ETH_ALEN/2]; /**< MAC address. */ +- uint16_t peer_id; /**< Peer ID. */ +- uint16_t hw_ast_idx; /**< Peer associated hardware IDX. */ +- uint16_t astinfoseq; /**< AST entry information sequence. */ +- uint8_t radio_id; /**< AST entry radio ID. */ +- uint8_t ast_type; /**< AST entry type. */ +-}; +- +-/* +- * nss_wifili_astentry_info_msg +- * NSS wifili AST entry information message. +- */ +-struct nss_wifili_astentry_info_msg { +- uint16_t nentries; /**< Number of entries in the information message. */ +- struct nss_wifi_peer_map_astentry_info info[0]; /**< AST entry information specific message. */ +-}; +- +-/* +- * nss_wifi_peer_map_mecentry_info +- * NSS wifi peer map MEC entry information. +- */ +-struct nss_wifi_peer_map_mecentry_info { +- uint16_t entry_no; /**< Entry number. */ +- uint16_t mac_addr[ETH_ALEN/2]; /**< MAC address. */ +- uint8_t radio_id; /**< MEC entry radio ID. */ +- uint8_t reserved[3]; /**< Reserved fields. */ +-}; +- +-/* +- * nss_wifili_mecentry_info_msg +- * NSS wifili MEC entry information message. +- */ +-struct nss_wifili_mecentry_info_msg { +- uint16_t nentries; /**< Number of entries in the information message. */ +- struct nss_wifi_peer_map_mecentry_info info[0]; /**< MEC entry information specific message. */ +-}; +- +-/* + * nss_wifili_msg + * Structure that describes wifili messages. + */ +@@ -2008,32 +1713,6 @@ struct nss_wifili_msg { + /**< Peer extended statistics message. */ + struct nss_wifili_clr_stats_msg clrstats; + /**< Clear NSS firmware statistics. */ +- struct nss_wifili_peer_wds_4addr_allow_msg wpswm; +- /**< Peer four-address event message. */ +- struct nss_wifili_dbdc_repeater_loop_detection_msg wdrldm; +- /**< Wifili DBDC repeater loop detection message. */ +- struct nss_wifili_peer_update_auth_flag peer_auth; +- /**< Peer authentication flag message. */ +- struct nss_wifili_mesh_capability_info cap_info; +- /**< Mesh capability flag. */ +- struct nss_wifili_pdev_tx_capture_msg pdevtxcapmsg; +- /**< Wifili physical device Tx capture message. */ +- struct nss_wifili_peer_tx_capture_msg peertxcapmsg; +- /**< Wifili peer Tx capture message. */ +- struct nss_wifili_pdev_v3_error_stats_sync_msg v3_rx_error_stats_msg; +- /**< Wifili version 3 Rx error statistics message. */ +- struct nss_wifili_dbg_latency_event_msg dbg_info; +- /**< Debug latency event for host. */ +- struct nss_wifili_set_tx_latency_threshold tx_latency_threshold; +- /**< Tx latency threshold value. */ +- struct nss_wifli_v3_stats_set_vow_tid_msg v3_tid; +- /**< TID value for version 3. */ +- struct nss_wifili_set_tx_drop_threshold tx_drop_threshold; +- /**< Tx drop threshold value. */ +- struct nss_wifili_astentry_info_msg astinfo; +- /**< Wifili AST database entry information message. */ +- struct nss_wifili_mecentry_info_msg mecinfo; +- /**< Wifili MEC database entry information message. */ + } msg; /**< Message payload. */ + }; + +@@ -2178,60 +1857,7 @@ void nss_unregister_wifili_radio_if(uint + * @return + * External interface number. + */ +-nss_if_num_t nss_get_available_wifili_external_if(void); +- +-/** +- * nss_wifili_release_external_if +- * Release the used interface number +- * +- * @datatypes +- * nss_if_num +- * +- * @param[in] if_num NSS interface number. +- * +- * @return +- * void +- */ +-void nss_wifili_release_external_if(nss_if_num_t ifnum); +- +-/** +- * nss_wifili_thread_scheme_alloc +- * Allocate thread scheme entry and return scheme index. +- * +- * @param[in] nss_ctx NSS context pointer. +- * @param[in] radio_ifnum Radio interface number. +- * @param[in] radio_priority Radio Priority requested. +- * +- * @return +- * uint8_t. +- */ +-uint8_t nss_wifili_thread_scheme_alloc(struct nss_ctx_instance *nss_ctx, +- int32_t radio_ifnum, +- uint32_t radio_priority); +- +-/** +- * nss_wifili_thread_scheme_dealloc +- * Release thread scheme database entry. +- * +- * @param[in] nss_ctx NSS context pointer. +- * @param[in] radio_ifnum Radio interface number. +- * +- * @return +- * void. +- */ +-void nss_wifili_thread_scheme_dealloc(struct nss_ctx_instance *nss_ctx, +- int32_t radio_ifnum); +- +-/** +- * nss_wifili_get_radio_num +- * Get radio number. +- * +- * @param[in] nss_ctx NSS context pointer. +- * +- * @return +- * uint32_t. +- */ +-uint32_t nss_wifili_get_radio_num(struct nss_ctx_instance *nss_ctx); ++uint32_t nss_get_available_wifili_external_if(void); + + /** + * nss_wifili_stats_register_notifier +--- a/nss_capwap.c ++++ b/nss_capwap.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2014-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2014-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -49,32 +49,16 @@ struct nss_capwap_handle { + static struct nss_capwap_handle *nss_capwap_hdl[NSS_MAX_DYNAMIC_INTERFACES]; + + /* +- * nss_capwap_get_interface_type() +- * Function to get the type of dynamic interface. +- */ +-static enum nss_dynamic_interface_type nss_capwap_get_interface_type(uint32_t if_num) +-{ +- struct nss_ctx_instance *nss_ctx; +- nss_ctx = &nss_top_main.nss[nss_top_main.capwap_handler_id]; +- NSS_VERIFY_CTX_MAGIC(nss_ctx); +- +- return nss_dynamic_interface_get_type(nss_ctx, if_num); +-} +- +-/* + * nss_capwap_verify_if_num() + * Verify if_num passed to us. + */ + static bool nss_capwap_verify_if_num(uint32_t if_num) + { +- enum nss_dynamic_interface_type type; +- + if (nss_is_dynamic_interface(if_num) == false) { + return false; + } + +- type = nss_capwap_get_interface_type(if_num); +- if ((type != NSS_DYNAMIC_INTERFACE_TYPE_CAPWAP_HOST_INNER) && (type != NSS_DYNAMIC_INTERFACE_TYPE_CAPWAP_OUTER) ) { ++ if (nss_dynamic_interface_get_type(nss_capwap_get_ctx(), if_num) != NSS_DYNAMIC_INTERFACE_TYPE_CAPWAP) { + return false; + } + +@@ -104,10 +88,10 @@ static void nss_capwap_refcnt_dec(int32_ + } + + /* +- * nss_capwap_refcnt_get() ++ * nss_capwap_refcnt() + * Get refcnt on the tunnel. + */ +-static uint32_t nss_capwap_refcnt_get(int32_t if_num) ++static uint32_t nss_capwap_refcnt(int32_t if_num) + { + if_num = if_num - NSS_DYNAMIC_IF_START; + return atomic_read(&nss_capwap_hdl[if_num]->refcnt); +@@ -149,62 +133,45 @@ static nss_capwap_msg_callback_t nss_cap + } + + /* +- * nss_capwap_update_stats() ++ * nss_capwapmgr_update_stats() + * Update per-tunnel stats for each CAPWAP interface. + */ +-static void nss_capwap_update_stats(struct nss_capwap_handle *handle, struct nss_capwap_stats_msg *fstats) ++static void nss_capwapmgr_update_stats(struct nss_capwap_handle *handle, struct nss_capwap_stats_msg *fstats) + { + struct nss_capwap_tunnel_stats *stats; +- enum nss_dynamic_interface_type type; + + stats = &handle->stats; +- type = nss_capwap_get_interface_type(handle->if_num); + +- switch(type) { +- case NSS_DYNAMIC_INTERFACE_TYPE_CAPWAP_OUTER: +- stats->rx_segments += fstats->rx_segments; +- stats->dtls_pkts += fstats->dtls_pkts; +- stats->rx_dup_frag += fstats->rx_dup_frag; +- stats->rx_oversize_drops += fstats->rx_oversize_drops; +- stats->rx_frag_timeout_drops += fstats->rx_frag_timeout_drops; +- stats->rx_n2h_drops += fstats->rx_n2h_drops; +- stats->rx_n2h_queue_full_drops += fstats->rx_n2h_queue_full_drops; +- stats->rx_mem_failure_drops += fstats->rx_mem_failure_drops; +- stats->rx_csum_drops += fstats->rx_csum_drops; +- stats->rx_malformed += fstats->rx_malformed; +- stats->rx_frag_gap_drops += fstats->rx_frag_gap_drops; +- +- /* +- * Update pnode rx stats for OUTER node. +- */ +- stats->pnode_stats.rx_packets += fstats->pnode_stats.rx_packets; +- stats->pnode_stats.rx_bytes += fstats->pnode_stats.rx_bytes; +- stats->pnode_stats.rx_dropped += nss_cmn_rx_dropped_sum(&fstats->pnode_stats); +- break; +- +- case NSS_DYNAMIC_INTERFACE_TYPE_CAPWAP_HOST_INNER: +- stats->tx_segments += fstats->tx_segments; +- stats->tx_queue_full_drops += fstats->tx_queue_full_drops; +- stats->tx_mem_failure_drops += fstats->tx_mem_failure_drops; +- stats->tx_dropped_sg_ref += fstats->tx_dropped_sg_ref; +- stats->tx_dropped_ver_mis += fstats->tx_dropped_ver_mis; +- stats->tx_dropped_hroom += fstats->tx_dropped_hroom; +- stats->tx_dropped_dtls += fstats->tx_dropped_dtls; +- stats->tx_dropped_nwireless += fstats->tx_dropped_nwireless; +- +- /* +- * Update pnode tx stats for INNER node. +- */ +- stats->pnode_stats.tx_packets += fstats->pnode_stats.tx_packets; +- stats->pnode_stats.tx_bytes += fstats->pnode_stats.tx_bytes; +- stats->tx_dropped_inner += nss_cmn_rx_dropped_sum(&fstats->pnode_stats); +- break; +- +- default: +- nss_warning("%px: Received invalid dynamic interface type: %d", handle, type); +- nss_assert(0); +- return; +- } ++ stats->rx_segments += fstats->rx_segments; ++ stats->dtls_pkts += fstats->dtls_pkts; ++ ++ stats->rx_dup_frag += fstats->rx_dup_frag; ++ stats->rx_oversize_drops += fstats->rx_oversize_drops; ++ stats->rx_frag_timeout_drops += fstats->rx_frag_timeout_drops; ++ stats->rx_queue_full_drops += fstats->rx_queue_full_drops; ++ stats->rx_n2h_queue_full_drops += fstats->rx_n2h_queue_full_drops; ++ stats->rx_mem_failure_drops += fstats->rx_mem_failure_drops; ++ stats->rx_csum_drops += fstats->rx_csum_drops; ++ stats->rx_malformed += fstats->rx_malformed; ++ stats->rx_frag_gap_drops += fstats->rx_frag_gap_drops; ++ ++ stats->tx_segments += fstats->tx_segments; ++ stats->tx_queue_full_drops += fstats->tx_queue_full_drops; ++ stats->tx_mem_failure_drops += fstats->tx_mem_failure_drops; ++ stats->tx_dropped_sg_ref += fstats->tx_dropped_sg_ref; ++ stats->tx_dropped_ver_mis += fstats->tx_dropped_ver_mis; ++ stats->tx_dropped_hroom += fstats->tx_dropped_hroom; ++ stats->tx_dropped_dtls += fstats->tx_dropped_dtls; ++ stats->tx_dropped_nwireless += fstats->tx_dropped_nwireless; ++ ++ /* ++ * add pnode stats now. ++ */ ++ stats->pnode_stats.rx_packets += fstats->pnode_stats.rx_packets; ++ stats->pnode_stats.rx_bytes += fstats->pnode_stats.rx_bytes; ++ stats->pnode_stats.rx_dropped += nss_cmn_rx_dropped_sum(&fstats->pnode_stats); ++ stats->pnode_stats.tx_packets += fstats->pnode_stats.tx_packets; ++ stats->pnode_stats.tx_bytes += fstats->pnode_stats.tx_bytes; + + /* + * Set to 1 when the tunnel is operating in fast memory. +@@ -250,7 +217,7 @@ static void nss_capwap_msg_handler(struc + /* + * Update driver statistics and send statistics notifications to the registered modules. + */ +- nss_capwap_update_stats(nss_capwap_hdl[if_num], &ntm->msg.stats); ++ nss_capwapmgr_update_stats(nss_capwap_hdl[if_num], &ntm->msg.stats); + nss_capwap_stats_notify(ncm->interface, nss_ctx->id); + } + } +@@ -295,23 +262,23 @@ static bool nss_capwap_instance_alloc(st + memset(h, 0, sizeof(struct nss_capwap_handle)); + h->if_num = if_num; + +- spin_lock_bh(&nss_capwap_spinlock); ++ spin_lock(&nss_capwap_spinlock); + if (nss_capwap_hdl[if_num - NSS_DYNAMIC_IF_START] != NULL) { +- spin_unlock_bh(&nss_capwap_spinlock); ++ spin_unlock(&nss_capwap_spinlock); + kfree(h); + nss_warning("%px: Another thread is already allocated instance for :%d", nss_ctx, if_num); + return false; + } + + nss_capwap_hdl[if_num - NSS_DYNAMIC_IF_START] = h; +- spin_unlock_bh(&nss_capwap_spinlock); ++ spin_unlock(&nss_capwap_spinlock); + + return true; + } + + /* + * nss_capwap_tx_msg() +- * Transmit a CAPWAP message to NSS FW. Don't call this from softirq/interrupts. ++ * Transmit a CAPWAP message to NSS FW. Don't call this from softirq/interrupts. + */ + nss_tx_status_t nss_capwap_tx_msg(struct nss_ctx_instance *nss_ctx, struct nss_capwap_msg *msg) + { +@@ -332,14 +299,14 @@ nss_tx_status_t nss_capwap_tx_msg(struct + } + + if_num = msg->cm.interface - NSS_DYNAMIC_IF_START; +- spin_lock_bh(&nss_capwap_spinlock); ++ spin_lock(&nss_capwap_spinlock); + if (!nss_capwap_hdl[if_num]) { +- spin_unlock_bh(&nss_capwap_spinlock); ++ spin_unlock(&nss_capwap_spinlock); + nss_warning("%px: capwap tunnel if_num is not there: %d", nss_ctx, msg->cm.interface); + return NSS_TX_FAILURE_BAD_PARAM; + } + nss_capwap_refcnt_inc(msg->cm.interface); +- spin_unlock_bh(&nss_capwap_spinlock); ++ spin_unlock(&nss_capwap_spinlock); + + /* + * Trace messages. +@@ -381,14 +348,14 @@ bool nss_capwap_get_stats(uint32_t if_nu + } + + if_num = if_num - NSS_DYNAMIC_IF_START; +- spin_lock_bh(&nss_capwap_spinlock); ++ spin_lock(&nss_capwap_spinlock); + if (nss_capwap_hdl[if_num] == NULL) { +- spin_unlock_bh(&nss_capwap_spinlock); ++ spin_unlock(&nss_capwap_spinlock); + return false; + } + + memcpy(stats, &nss_capwap_hdl[if_num]->stats, sizeof(struct nss_capwap_tunnel_stats)); +- spin_unlock_bh(&nss_capwap_spinlock); ++ spin_unlock(&nss_capwap_spinlock); + return true; + } + EXPORT_SYMBOL(nss_capwap_get_stats); +@@ -409,13 +376,13 @@ struct nss_ctx_instance *nss_capwap_noti + return NULL; + } + +- spin_lock_bh(&nss_capwap_spinlock); ++ spin_lock(&nss_capwap_spinlock); + if (nss_capwap_hdl[if_num - NSS_DYNAMIC_IF_START] != NULL) { +- spin_unlock_bh(&nss_capwap_spinlock); ++ spin_unlock(&nss_capwap_spinlock); + nss_warning("%px: notfiy register tunnel already exists for interface %d", nss_ctx, if_num); + return NULL; + } +- spin_unlock_bh(&nss_capwap_spinlock); ++ spin_unlock(&nss_capwap_spinlock); + + return nss_ctx; + } +@@ -443,9 +410,9 @@ nss_tx_status_t nss_capwap_notify_unregi + } + + index = if_num - NSS_DYNAMIC_IF_START; +- spin_lock_bh(&nss_capwap_spinlock); ++ spin_lock(&nss_capwap_spinlock); + if (nss_capwap_hdl[index] == NULL) { +- spin_unlock_bh(&nss_capwap_spinlock); ++ spin_unlock(&nss_capwap_spinlock); + nss_warning("%px: notify unregister received for unallocated if_num: %d", nss_ctx, if_num); + return NSS_TX_FAILURE_BAD_PARAM; + } +@@ -454,14 +421,14 @@ nss_tx_status_t nss_capwap_notify_unregi + * It's the responsibility of caller to wait and call us again. We return failure saying + * that we can't remove msg handler now. + */ +- if (nss_capwap_refcnt_get(if_num) != 0) { +- spin_unlock_bh(&nss_capwap_spinlock); ++ if (nss_capwap_refcnt(if_num) != 0) { ++ spin_unlock(&nss_capwap_spinlock); + nss_warning("%px: notify unregister tunnel %d: has reference", nss_ctx, if_num); + return NSS_TX_FAILURE_QUEUE; + } + + nss_capwap_set_msg_callback(if_num, NULL, NULL); +- spin_unlock_bh(&nss_capwap_spinlock); ++ spin_unlock(&nss_capwap_spinlock); + + return NSS_TX_SUCCESS; + } +@@ -482,12 +449,12 @@ struct nss_ctx_instance *nss_capwap_data + return NULL; + } + +- spin_lock_bh(&nss_capwap_spinlock); ++ spin_lock(&nss_capwap_spinlock); + if (nss_ctx->subsys_dp_register[if_num].ndev != NULL) { +- spin_unlock_bh(&nss_capwap_spinlock); ++ spin_unlock(&nss_capwap_spinlock); + return NULL; + } +- spin_unlock_bh(&nss_capwap_spinlock); ++ spin_unlock(&nss_capwap_spinlock); + + core_status = nss_core_register_handler(nss_ctx, if_num, nss_capwap_msg_handler, NULL); + if (core_status != NSS_CORE_STATUS_SUCCESS) { +@@ -521,18 +488,18 @@ bool nss_capwap_data_unregister(uint32_t + return false; + } + +- spin_lock_bh(&nss_capwap_spinlock); ++ spin_lock(&nss_capwap_spinlock); + /* + * It's the responsibility of caller to wait and call us again. + */ +- if (nss_capwap_refcnt_get(if_num) != 0) { +- spin_unlock_bh(&nss_capwap_spinlock); ++ if (nss_capwap_refcnt(if_num) != 0) { ++ spin_unlock(&nss_capwap_spinlock); + nss_warning("%px: notify unregister tunnel %d: has reference", nss_ctx, if_num); + return false; + } + h = nss_capwap_hdl[if_num - NSS_DYNAMIC_IF_START]; + nss_capwap_hdl[if_num - NSS_DYNAMIC_IF_START] = NULL; +- spin_unlock_bh(&nss_capwap_spinlock); ++ spin_unlock(&nss_capwap_spinlock); + + (void) nss_core_unregister_handler(nss_ctx, if_num); + +--- a/nss_capwap_stats.c ++++ b/nss_capwap_stats.c +@@ -50,7 +50,7 @@ static ssize_t nss_capwap_stats_encap(ch + tcnt = s->tx_dropped_ver_mis; + break; + case 5: +- tcnt = s->tx_dropped_inner; ++ tcnt = 0; + break; + case 6: + tcnt = s->tx_dropped_hroom; +@@ -114,7 +114,7 @@ static ssize_t nss_capwap_stats_decap(ch + tcnt = s->rx_frag_gap_drops; + break; + case 9: +- tcnt = s->rx_n2h_drops; ++ tcnt = s->rx_queue_full_drops; + return snprintf(line, len, "%s = %llu (n2h = %llu)\n", nss_capwap_strings_decap_stats[i].stats_name, tcnt, s->rx_n2h_queue_full_drops); + case 10: + tcnt = s->rx_n2h_queue_full_drops; +@@ -166,22 +166,12 @@ static ssize_t nss_capwap_stats_read(str + + for (; if_num <= max_if_num; if_num++) { + bool isthere; +- enum nss_dynamic_interface_type dtype; + + if (nss_is_dynamic_interface(if_num) == false) { + continue; + } + +- dtype = nss_dynamic_interface_get_type(nss_capwap_get_ctx(), if_num); +- +- /* +- * Read encap stats from inner node and decap stats from outer node. +- */ +- if ((type == 1) && (dtype != NSS_DYNAMIC_INTERFACE_TYPE_CAPWAP_HOST_INNER)) { +- continue; +- } +- +- if ((type == 0) && (dtype != NSS_DYNAMIC_INTERFACE_TYPE_CAPWAP_OUTER)) { ++ if (nss_dynamic_interface_get_type(nss_capwap_get_ctx(), if_num) != NSS_DYNAMIC_INTERFACE_TYPE_CAPWAP) { + continue; + } + +--- a/nss_capwap_strings.c ++++ b/nss_capwap_strings.c +@@ -32,7 +32,7 @@ struct nss_stats_info nss_capwap_strings + {"tx_segments", NSS_STATS_TYPE_SPECIAL}, + {"tx_drop_seg_ref", NSS_STATS_TYPE_DROP}, + {"tx_drop_ver_mismatch",NSS_STATS_TYPE_DROP}, +- {"tx_dropped_inner", NSS_STATS_TYPE_DROP}, ++ {"tx_drop_unalign", NSS_STATS_TYPE_DROP}, + {"tx_drop_hroom", NSS_STATS_TYPE_DROP}, + {"tx_drop_DTLS", NSS_STATS_TYPE_DROP}, + {"tx_drop_nwireless", NSS_STATS_TYPE_DROP}, +@@ -69,7 +69,7 @@ struct nss_stats_info nss_capwap_strings + {"rx_drop_frag_timeout",NSS_STATS_TYPE_DROP}, + {"rx_drop_frag_dup", NSS_STATS_TYPE_DROP}, + {"rx_drop_frag_gap", NSS_STATS_TYPE_DROP}, +- {"rx_drop_n2h", NSS_STATS_TYPE_DROP}, ++ {"rx_drop_qfull", NSS_STATS_TYPE_DROP}, + {"rx_drop_n2h_qfull", NSS_STATS_TYPE_DROP}, + {"rx_drop_mem_fail", NSS_STATS_TYPE_DROP}, + {"rx_drop_csum", NSS_STATS_TYPE_DROP}, +--- a/nss_clmap.c ++++ b/nss_clmap.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -23,7 +23,6 @@ + #include "nss_cmn.h" + #include "nss_tx_rx_common.h" + #include "nss_clmap_stats.h" +-#include "nss_clmap_strings.h" + #include "nss_clmap_log.h" + + #define NSS_CLMAP_TX_TIMEOUT 3000 +@@ -107,7 +106,6 @@ static void nss_clmap_msg_handler(struct + switch (nclm->cm.type) { + case NSS_CLMAP_MSG_TYPE_SYNC_STATS: + nss_clmap_stats_sync(nss_ctx, &nclm->msg.stats, ncm->interface); +- nss_clmap_stats_notify(nss_ctx, ncm->interface); + break; + } + +@@ -116,7 +114,7 @@ static void nss_clmap_msg_handler(struct + */ + if (ncm->response == NSS_CMN_RESPONSE_NOTIFY) { + ncm->cb = (nss_ptr_t)nss_core_get_msg_handler(nss_ctx, ncm->interface); +- ncm->app_data = (nss_ptr_t)nss_ctx->nss_rx_interface_handlers[ncm->interface].app_data; ++ ncm->app_data = (nss_ptr_t)nss_ctx->nss_rx_interface_handlers[nss_ctx->id][ncm->interface].app_data; + } + + /* +@@ -338,9 +336,7 @@ EXPORT_SYMBOL(nss_clmap_get_ctx); + */ + void nss_clmap_init() + { ++ nss_clmap_stats_dentry_create(); + sema_init(&clmap_pvt.sem, 1); + init_completion(&clmap_pvt.complete); +- +- nss_clmap_stats_dentry_create(); +- nss_clmap_strings_dentry_create(); + } +--- a/nss_clmap_stats.c ++++ b/nss_clmap_stats.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -15,25 +15,15 @@ + */ + + #include "nss_tx_rx_common.h" +-#include "nss_clmap.h" + #include "nss_clmap_stats.h" +-#include "nss_clmap_strings.h" + +-/* +- * Declare atomic notifier data structure for statistics. +- */ +-ATOMIC_NOTIFIER_HEAD(nss_clmap_stats_notifier); +- +-/* +- * Spinlock to protect clmap statistics update/read +- */ + DEFINE_SPINLOCK(nss_clmap_stats_lock); + + struct nss_clmap_stats *stats_db[NSS_CLMAP_MAX_DEBUG_INTERFACES] = {NULL}; + + /* + * nss_clmap_interface_type_str +- * Clmap interface type string. ++ * Clmap interface type string. + */ + static char *nss_clmap_interface_type_str[NSS_CLMAP_INTERFACE_TYPE_MAX] = { + "Upstream", +@@ -41,23 +31,34 @@ static char *nss_clmap_interface_type_st + }; + + /* +- * nss_clmap_stats_session_unregister +- * Unregister debug statistic for clmap session. ++ * nss_clmap_stats_str ++ * Clmap statistics strings for nss tunnel stats + */ +-void nss_clmap_stats_session_unregister(uint32_t if_num) +-{ +- uint32_t i; +- +- spin_lock_bh(&nss_clmap_stats_lock); +- for (i = 0; i < NSS_CLMAP_MAX_DEBUG_INTERFACES; i++) { +- if (stats_db[i] && (stats_db[i]->nss_if_num == if_num)) { +- kfree(stats_db[i]); +- stats_db[i] = NULL; +- break; +- } +- } +- spin_unlock_bh(&nss_clmap_stats_lock); +-} ++static char *nss_clmap_stats_str[NSS_CLMAP_INTERFACE_STATS_MAX] = { ++ "rx_pkts", ++ "rx_bytes", ++ "tx_pkts", ++ "tx_bytes", ++ "rx_queue_0_dropped", ++ "rx_queue_1_dropped", ++ "rx_queue_2_dropped", ++ "rx_queue_3_dropped", ++ "MAC DB look up failed", ++ "Invalid packet count", ++ "Headroom drop", ++ "Next node queue full drop", ++ "Pbuf alloc failed drop", ++ "Linear failed drop", ++ "Shared packet count", ++ "Ethernet frame error", ++ "Macdb create requests count", ++ "Macdb create failures MAC exists count", ++ "Macdb create failures MAC table full count", ++ "Macdb destroy requests count", ++ "Macdb destroy failures MAC not found count", ++ "Macdb destroy failures MAC unhashed count", ++ "Macdb flush requests count" ++}; + + /* + * nss_clmap_stats_session_register +@@ -94,6 +95,25 @@ bool nss_clmap_stats_session_register(ui + } + + /* ++ * nss_clmap_stats_session_unregister ++ * Unregister debug statistic for clmap session. ++ */ ++void nss_clmap_stats_session_unregister(uint32_t if_num) ++{ ++ uint32_t i; ++ ++ spin_lock_bh(&nss_clmap_stats_lock); ++ for (i = 0; i < NSS_CLMAP_MAX_DEBUG_INTERFACES; i++) { ++ if (stats_db[i] && (stats_db[i]->nss_if_num == if_num)) { ++ kfree(stats_db[i]); ++ stats_db[i] = NULL; ++ break; ++ } ++ } ++ spin_unlock_bh(&nss_clmap_stats_lock); ++} ++ ++/* + * nss_clmap_get_debug_stats() + * Get clmap debug statistics. + */ +@@ -122,12 +142,12 @@ static int nss_clmap_get_debug_stats(str + static ssize_t nss_clmap_stats_read(struct file *fp, char __user *ubuf, + size_t sz, loff_t *ppos) + { +- uint32_t max_output_lines = (NSS_CLMAP_INTERFACE_STATS_MAX * NSS_CLMAP_MAX_DEBUG_INTERFACES) + NSS_STATS_EXTRA_OUTPUT_LINES; ++ uint32_t max_output_lines = 2 + (NSS_CLMAP_INTERFACE_STATS_MAX * NSS_CLMAP_MAX_DEBUG_INTERFACES + 2) + 2; + size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines; + size_t size_wr = 0; + ssize_t bytes_read = 0; + struct net_device *dev; +- uint32_t id; ++ uint32_t id, i; + struct nss_clmap_stats *clmap_stats = NULL; + int interface_cnt; + +@@ -151,7 +171,8 @@ static ssize_t nss_clmap_stats_read(stru + * Get clmap statistics. + */ + interface_cnt = nss_clmap_get_debug_stats(clmap_stats); +- size_wr += nss_stats_banner(lbuf, size_wr, size_al, "clmap stats", NSS_STATS_SINGLE_CORE); ++ size_wr = scnprintf(lbuf + size_wr, size_al - size_wr, ++ "\n clmap Interface statistics start:\n\n"); + for (id = 0; id < interface_cnt; id++) { + struct nss_clmap_stats *clmsp = clmap_stats + id; + +@@ -169,10 +190,16 @@ static ssize_t nss_clmap_stats_read(stru + clmsp->nss_if_num, nss_clmap_interface_type_str[clmsp->nss_if_type], dev->name); + dev_put(dev); + +- size_wr += nss_stats_print("clmap", NULL, NSS_STATS_SINGLE_INSTANCE, nss_clmap_strings_stats, +- clmsp->stats, NSS_CLMAP_INTERFACE_STATS_MAX, lbuf, size_wr, size_al); ++ for (i = 0; i < NSS_CLMAP_INTERFACE_STATS_MAX; i++) { ++ size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, ++ "\t%s = %llu\n", nss_clmap_stats_str[i], ++ clmsp->stats[i]); ++ } ++ size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\n"); + } + ++ size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, ++ "\n clmap Interface statistics end\n"); + bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, size_wr); + + kfree(clmap_stats); +@@ -245,52 +272,3 @@ void nss_clmap_stats_dentry_create(void) + { + nss_stats_create_dentry("clmap", &nss_clmap_stats_ops); + } +- +-/* +- * nss_clmap_stats_notify() +- * Sends notifications to all the registered modules. +- * +- * Leverage NSS-FW statistics timing to update Netlink. +- */ +-void nss_clmap_stats_notify(struct nss_ctx_instance *nss_ctx, uint32_t if_num) +-{ +- struct nss_clmap_stats_notification clmap_stats; +- struct nss_clmap_stats *s = NULL; +- int i; +- +- spin_lock_bh(&nss_clmap_stats_lock); +- for (i = 0; i < NSS_CLMAP_MAX_DEBUG_INTERFACES; i++) { +- if (!stats_db[i] || (stats_db[i]->nss_if_num != if_num)) { +- continue; +- } +- +- s = stats_db[i]; +- clmap_stats.core_id = nss_ctx->id; +- clmap_stats.if_num = if_num; +- memcpy(clmap_stats.stats_ctx, s->stats, sizeof(clmap_stats.stats_ctx)); +- spin_unlock_bh(&nss_clmap_stats_lock); +- atomic_notifier_call_chain(&nss_clmap_stats_notifier, NSS_STATS_EVENT_NOTIFY, &clmap_stats); +- return; +- } +- spin_unlock_bh(&nss_clmap_stats_lock); +-} +- +-/* +- * nss_clmap_stats_unregister_notifier() +- * Deregisters statistics notifier. +- */ +-int nss_clmap_stats_unregister_notifier(struct notifier_block *nb) +-{ +- return atomic_notifier_chain_unregister(&nss_clmap_stats_notifier, nb); +-} +-EXPORT_SYMBOL(nss_clmap_stats_unregister_notifier); +- +-/* +- * nss_clmap_stats_register_notifier() +- * Registers statistics notifier. +- */ +-int nss_clmap_stats_register_notifier(struct notifier_block *nb) +-{ +- return atomic_notifier_chain_register(&nss_clmap_stats_notifier, nb); +-} +-EXPORT_SYMBOL(nss_clmap_stats_register_notifier); +--- a/nss_clmap_stats.h ++++ b/nss_clmap_stats.h +@@ -1,6 +1,6 @@ + /* + ****************************************************************************** +- * Copyright (c) 2019, 2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -20,11 +20,50 @@ + #define NSS_CLMAP_MAX_DEBUG_INTERFACES 2 * NSS_CLMAP_MAX_INTERFACES + + /* ++ * Clmap NSS interface type. ++ */ ++enum nss_clmap_interface_type { ++ NSS_CLMAP_INTERFACE_TYPE_US, ++ NSS_CLMAP_INTERFACE_TYPE_DS, ++ NSS_CLMAP_INTERFACE_TYPE_MAX ++}; ++ ++/* ++ * Clmap statistic counters. ++ */ ++enum nss_clmap_stats_type { ++ NSS_CLMAP_INTERFACE_STATS_RX_PKTS, ++ NSS_CLMAP_INTERFACE_STATS_RX_BYTES, ++ NSS_CLMAP_INTERFACE_STATS_TX_PKTS, ++ NSS_CLMAP_INTERFACE_STATS_TX_BYTES, ++ NSS_CLMAP_INTERFACE_STATS_RX_QUEUE_0_DROPPED, ++ NSS_CLMAP_INTERFACE_STATS_RX_QUEUE_1_DROPPED, ++ NSS_CLMAP_INTERFACE_STATS_RX_QUEUE_2_DROPPED, ++ NSS_CLMAP_INTERFACE_STATS_RX_QUEUE_3_DROPPED, ++ NSS_CLMAP_INTERFACE_STATS_DROPPED_MACDB_LOOKUP_FAILED, ++ NSS_CLMAP_INTERFACE_STATS_DROPPED_INVALID_PACKET_SIZE, ++ NSS_CLMAP_INTERFACE_STATS_DROPPED_LOW_HEADROOM, ++ NSS_CLMAP_INTERFACE_STATS_DROPPED_NEXT_NODE_QUEUE_FULL, ++ NSS_CLMAP_INTERFACE_STATS_DROPPED_PBUF_ALLOC_FAILED, ++ NSS_CLMAP_INTERFACE_STATS_DROPPED_LINEAR_FAILED, ++ NSS_CLMAP_INTERFACE_STATS_SHARED_PACKET_CNT, ++ NSS_CLMAP_INTERFACE_STATS_ETHERNET_FRAME_ERROR, ++ NSS_CLMAP_INTERFACE_STATS_MACDB_CREATE_REQUESTS_CNT, ++ NSS_CLMAP_INTERFACE_STATS_MACDB_CREATE_MAC_EXISTS_CNT, ++ NSS_CLMAP_INTERFACE_STATS_MACDB_CREATE_MAC_TABLE_FULL_CNT, ++ NSS_CLMAP_INTERFACE_STATS_MACDB_DESTROY_REQUESTS_CNT, ++ NSS_CLMAP_INTERFACE_STATS_MACDB_DESTROY_MAC_NOT_FOUND_CNT, ++ NSS_CLMAP_INTERFACE_STATS_MACDB_DESTROY_MAC_UNHASHED_CNT, ++ NSS_CLMAP_INTERFACE_STATS_MACDB_FLUSH_REQUESTS_CNT, ++ NSS_CLMAP_INTERFACE_STATS_MAX, ++}; ++ ++/* + * Clmap session debug statistics. + */ + struct nss_clmap_stats { +- uint64_t stats[NSS_CLMAP_INTERFACE_STATS_MAX]; /* Clmap statistics. */ +- int32_t if_index; /* Interface index. */ ++ uint64_t stats[NSS_CLMAP_INTERFACE_STATS_MAX]; ++ int32_t if_index; + uint32_t nss_if_num; /* NSS interface number. */ + enum nss_clmap_interface_type nss_if_type; /* NSS interface type. */ + bool valid; +@@ -33,7 +72,6 @@ struct nss_clmap_stats { + /* + * Clmap statistics APIs. + */ +-extern void nss_clmap_stats_notify(struct nss_ctx_instance *nss_ctx, uint32_t if_num); + extern bool nss_clmap_stats_session_register(uint32_t if_num, enum nss_clmap_interface_type if_type, struct net_device *netdev); + extern void nss_clmap_stats_session_unregister(uint32_t if_num); + extern void nss_clmap_stats_sync(struct nss_ctx_instance *nss_ctx, struct nss_clmap_stats_msg *stats_msg, uint32_t if_num); +--- a/nss_clmap_strings.c ++++ /dev/null +@@ -1,73 +0,0 @@ +-/* +- ************************************************************************** +- * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- ************************************************************************** +- */ +- +-#include "nss_stats.h" +-#include "nss_core.h" +-#include "nss_strings.h" +-#include "nss_clmap_strings.h" +- +-/* +- * nss_clmap_strings_stats +- * Clmap statistics strings for nss tunnel stats +- */ +-struct nss_stats_info nss_clmap_strings_stats[NSS_CLMAP_INTERFACE_STATS_MAX] = { +- {"rx_pkts", NSS_STATS_TYPE_COMMON}, +- {"rx_bytes", NSS_STATS_TYPE_COMMON}, +- {"tx_pkts", NSS_STATS_TYPE_COMMON}, +- {"tx_bytes", NSS_STATS_TYPE_COMMON}, +- {"rx_queue_0_dropped", NSS_STATS_TYPE_DROP}, +- {"rx_queue_1_dropped", NSS_STATS_TYPE_DROP}, +- {"rx_queue_2_dropped", NSS_STATS_TYPE_DROP}, +- {"rx_queue_3_dropped", NSS_STATS_TYPE_DROP}, +- {"MAC DB look up failed", NSS_STATS_TYPE_SPECIAL}, +- {"Invalid packet count", NSS_STATS_TYPE_SPECIAL}, +- {"Headroom drop", NSS_STATS_TYPE_SPECIAL}, +- {"Next node queue full drop", NSS_STATS_TYPE_SPECIAL}, +- {"Pbuf alloc failed drop", NSS_STATS_TYPE_SPECIAL}, +- {"Linear failed drop", NSS_STATS_TYPE_SPECIAL}, +- {"Shared packet count", NSS_STATS_TYPE_SPECIAL}, +- {"Ethernet frame error", NSS_STATS_TYPE_SPECIAL}, +- {"Macdb create requests count", NSS_STATS_TYPE_SPECIAL}, +- {"Macdb create failures MAC exists count", NSS_STATS_TYPE_SPECIAL}, +- {"Macdb create failures MAC table full count", NSS_STATS_TYPE_SPECIAL}, +- {"Macdb destroy requests count", NSS_STATS_TYPE_SPECIAL}, +- {"Macdb destroy failures MAC not found count", NSS_STATS_TYPE_SPECIAL}, +- {"Macdb destroy failures MAC unhashed count", NSS_STATS_TYPE_SPECIAL}, +- {"Macdb flush requests count", NSS_STATS_TYPE_SPECIAL} +-}; +- +-/* +- * nss_clmap_strings_read() +- * Read clmap statistics names +- */ +-static ssize_t nss_clmap_strings_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- return nss_strings_print(ubuf, sz, ppos, nss_clmap_strings_stats, NSS_CLMAP_INTERFACE_STATS_MAX); +-} +- +-/* +- * nss_clmap_strings_ops +- */ +-NSS_STRINGS_DECLARE_FILE_OPERATIONS(clmap); +- +-/* +- * nss_clmap_strings_dentry_create() +- * Create clmap statistics strings debug entry. +- */ +-void nss_clmap_strings_dentry_create(void) +-{ +- nss_strings_create_dentry("clmap", &nss_clmap_strings_ops); +-} +--- a/nss_clmap_strings.h ++++ /dev/null +@@ -1,25 +0,0 @@ +-/* +- *************************************************************************** +- * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- *************************************************************************** +- */ +- +-#ifndef __NSS_CLMAP_STRINGS_H +-#define __NSS_CLMAP_STRINGS_H +- +-#include "nss_clmap_stats.h" +- +-extern struct nss_stats_info nss_clmap_strings_stats[NSS_CLMAP_INTERFACE_STATS_MAX]; +-extern void nss_clmap_strings_dentry_create(void); +- +-#endif /* __NSS_CLMAP_STRINGS_H */ +--- a/nss_cmn.c ++++ b/nss_cmn.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2014-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2014-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -197,7 +197,8 @@ bool nss_cmn_interface_is_redirect(struc + { + enum nss_dynamic_interface_type type = nss_dynamic_interface_get_type(nss_ctx, interface_num); + +- return type == NSS_DYNAMIC_INTERFACE_TYPE_GENERIC_REDIR_N2H ++ return type == NSS_DYNAMIC_INTERFACE_TYPE_WIFI ++ || type == NSS_DYNAMIC_INTERFACE_TYPE_GENERIC_REDIR_N2H + || type == NSS_DYNAMIC_INTERFACE_TYPE_GENERIC_REDIR_H2N + || type == NSS_DYNAMIC_INTERFACE_TYPE_VIRTIF_DEPRECATED; + } +--- a/nss_core.c ++++ b/nss_core.c +@@ -1,12 +1,9 @@ + /* + ************************************************************************** +- * Copyright (c) 2013-2021, The Linux Foundation. All rights reserved. +- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. +- * ++ * Copyright (c) 2013-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +- * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +@@ -37,13 +34,7 @@ + #endif + #include + #include "nss_tx_rx_common.h" +- +-#ifdef NSS_DATA_PLANE_GENERIC_SUPPORT + #include "nss_data_plane.h" +-#endif +-#ifdef NSS_DATA_PLANE_LITE_SUPPORT +-#include "nss_data_plane_lite.h" +-#endif + + #define NSS_CORE_JUMBO_LINEAR_BUF_SIZE 128 + +@@ -61,7 +52,9 @@ + (((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0)))) || \ + (((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0)))) || \ + (((LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0)))) || \ +-(((LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(5, 5, 0)))))) ++(((LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(5, 5, 0)))) || \ ++(((LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(5, 11, 0)))) || \ ++(((LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(5, 16, 0)))))) + #error "Check skb recycle code in this file to match Linux version" + #endif + +@@ -85,10 +78,6 @@ uint16_t pn_qlimits[NSS_MAX_NUM_PRI] = { + module_param_array(pn_qlimits, short, NULL, 0); + MODULE_PARM_DESC(pn_qlimits, "Queue limit per queue"); + +-static int qos_mem_size = 0; +-module_param(qos_mem_size, int, S_IRUGO); +-MODULE_PARM_DESC(qos_mem_size, "QoS memory size"); +- + /* + * Atomic variables to control jumbo_mru & paged_mode + */ +@@ -96,24 +85,6 @@ static atomic_t jumbo_mru; + static atomic_t paged_mode; + + /* +- * nss_core_update_qos_mem_size() +- * Update the memory size for QoS +- */ +-void nss_core_update_qos_mem_size(int size) +-{ +- qos_mem_size = size; +-} +- +-/* +- * nss_core_get_qos_mem_size() +- * Get the memeory size for QoS +- */ +-int nss_core_get_qos_mem_size(void) +-{ +- return qos_mem_size; +-} +- +-/* + * nss_core_update_max_ipv4_conn() + * Update the maximum number of configured IPv4 connections + */ +@@ -221,12 +192,12 @@ uint32_t nss_core_register_msg_handler(s + /* + * Check if already registered + */ +- if (nss_ctx->nss_rx_interface_handlers[interface].msg_cb) { ++ if (nss_ctx->nss_rx_interface_handlers[nss_ctx->id][interface].msg_cb) { + nss_warning("Error - Duplicate Interface CB Registered for interface %d\n", interface); + return NSS_CORE_STATUS_FAILURE; + } + +- nss_ctx->nss_rx_interface_handlers[interface].msg_cb = msg_cb; ++ nss_ctx->nss_rx_interface_handlers[nss_ctx->id][interface].msg_cb = msg_cb; + + return NSS_CORE_STATUS_SUCCESS; + } +@@ -245,7 +216,7 @@ uint32_t nss_core_unregister_msg_handler + return NSS_CORE_STATUS_FAILURE; + } + +- nss_ctx->nss_rx_interface_handlers[interface].msg_cb = NULL; ++ nss_ctx->nss_rx_interface_handlers[nss_ctx->id][interface].msg_cb = NULL; + + return NSS_CORE_STATUS_SUCCESS; + } +@@ -270,13 +241,13 @@ uint32_t nss_core_register_handler(struc + /* + * Check if already registered + */ +- if (nss_ctx->nss_rx_interface_handlers[interface].cb != NULL) { ++ if (nss_ctx->nss_rx_interface_handlers[nss_ctx->id][interface].cb != NULL) { + nss_warning("Error - Duplicate Interface CB Registered for interface %d\n", interface); + return NSS_CORE_STATUS_FAILURE; + } + +- nss_ctx->nss_rx_interface_handlers[interface].cb = cb; +- nss_ctx->nss_rx_interface_handlers[interface].app_data = app_data; ++ nss_ctx->nss_rx_interface_handlers[nss_ctx->id][interface].cb = cb; ++ nss_ctx->nss_rx_interface_handlers[nss_ctx->id][interface].app_data = app_data; + + return NSS_CORE_STATUS_SUCCESS; + } +@@ -295,8 +266,8 @@ uint32_t nss_core_unregister_handler(str + return NSS_CORE_STATUS_FAILURE; + } + +- nss_ctx->nss_rx_interface_handlers[interface].cb = NULL; +- nss_ctx->nss_rx_interface_handlers[interface].app_data = NULL; ++ nss_ctx->nss_rx_interface_handlers[nss_ctx->id][interface].cb = NULL; ++ nss_ctx->nss_rx_interface_handlers[nss_ctx->id][interface].app_data = NULL; + + return NSS_CORE_STATUS_SUCCESS; + } +@@ -325,17 +296,6 @@ void nss_core_set_subsys_dp_type(struct + } + + /* +- * nss_core_is_mq_enabled() +- * Get multi-queue status. +- * +- * Returns 'true' if multi-queue is enabled otherwise returns 'false'. +- */ +-bool nss_core_is_mq_enabled(void) +-{ +- return pn_mq_en; +-} +- +-/* + * nss_core_register_subsys_dp() + * Registers a netdevice and associated information at a given interface. + * +@@ -445,8 +405,8 @@ void nss_core_handle_nss_status_pkt(stru + return; + } + +- cb = nss_ctx->nss_rx_interface_handlers[nss_if].cb; +- app_data = nss_ctx->nss_rx_interface_handlers[nss_if].app_data; ++ cb = nss_ctx->nss_rx_interface_handlers[nss_ctx->id][nss_if].cb; ++ app_data = nss_ctx->nss_rx_interface_handlers[nss_ctx->id][nss_if].app_data; + + if (!cb) { + nss_warning("%px: Callback not registered for interface %d", nss_ctx, nss_if); +@@ -964,6 +924,7 @@ static inline void nss_core_handle_buffe + dev_put(ndev); + } + ++#if (NSS_FW_VERSION_CODE > NSS_FW_VERSION(11,0)) + /* + * nss_core_handle_ext_buffer_pkt() + * Handle Extended data plane packet received on physical or virtual interface. +@@ -1008,6 +969,7 @@ static inline void nss_core_handle_ext_b + dev_kfree_skb_any(nbuf); + } + } ++#endif + + /* + * nss_core_rx_pbuf() +@@ -1024,7 +986,9 @@ static inline void nss_core_rx_pbuf(stru + NSS_PKT_STATS_DEC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_NSS_SKB_COUNT]); + + if (interface_num >= NSS_MAX_NET_INTERFACES) { ++#if (NSS_FW_VERSION_CODE > NSS_FW_VERSION(11,0)) + NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_RX_INVALID_INTERFACE]); ++#endif + nss_warning("%px: Invalid interface_num: %d", nss_ctx, interface_num); + dev_kfree_skb_any(nbuf); + return; +@@ -1034,7 +998,9 @@ static inline void nss_core_rx_pbuf(stru + * Check if core_id value is valid. + */ + if (core_id > nss_top_main.num_nss) { ++#if (NSS_FW_VERSION_CODE > NSS_FW_VERSION(11,0)) + NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_RX_INVALID_CORE_ID]); ++#endif + nss_warning("%px: Invalid core id: %d", nss_ctx, core_id); + dev_kfree_skb_any(nbuf); + return; +@@ -1066,9 +1032,11 @@ static inline void nss_core_rx_pbuf(stru + nss_core_handle_bounced_pkt(nss_ctx, reg, nbuf); + break; + ++#if (NSS_FW_VERSION_CODE > NSS_FW_VERSION(11,0)) + case N2H_BUFFER_PACKET_EXT: + nss_core_handle_ext_buffer_pkt(nss_ctx, interface_num, nbuf, napi, desc->bit_flags); + break; ++#endif + + case N2H_BUFFER_STATUS: + NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_RX_STATUS]); +@@ -1100,7 +1068,9 @@ static inline void nss_core_rx_pbuf(stru + break; + + default: ++#if (NSS_FW_VERSION_CODE > NSS_FW_VERSION(11,0)) + NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_RX_INVALID_BUFFER_TYPE]); ++#endif + nss_warning("%px: Invalid buffer type %d received from NSS", nss_ctx, buffer_type); + dev_kfree_skb_any(nbuf); + } +@@ -1116,7 +1086,7 @@ static inline void nss_core_set_skb_clas + #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 4, 0)) + nbuf->tc_verd = SET_TC_NCLS_NSS(nbuf->tc_verd); + #else +- skb_set_tc_classify_offload(nbuf); ++ skb_skip_tc_classify(nbuf); + #endif + #endif + } +@@ -1658,7 +1628,7 @@ static int32_t nss_core_handle_cause_que + * + */ + if (unlikely((buffer_type == N2H_BUFFER_CRYPTO_RESP))) { +- dma_unmap_single(NULL, (desc->buffer + desc->payload_offs), desc->payload_len, DMA_FROM_DEVICE); ++ dma_unmap_single(nss_ctx->dev, (desc->buffer + desc->payload_offs), desc->payload_len, DMA_FROM_DEVICE); + goto consume; + } + +@@ -1734,7 +1704,6 @@ static void nss_core_init_nss(struct nss + { + struct nss_top_instance *nss_top; + int ret; +- int i; + + NSS_CORE_DMA_CACHE_MAINT((void *)if_map, sizeof(*if_map), DMA_FROM_DEVICE); + NSS_CORE_DSB(); +@@ -1750,9 +1719,6 @@ static void nss_core_init_nss(struct nss + #ifdef NSS_DRV_C2C_ENABLE + nss_ctx->c2c_start = nss_ctx->meminfo_ctx.c2c_start_dma; + #endif +- for (i = 0; i < NSS_H2N_DESC_RING_NUM; i++) { +- nss_ctx->h2n_desc_rings[i].nss_index_local = 0; +- } + + nss_top = nss_ctx->nss_top; + spin_lock_bh(&nss_top->lock); +@@ -1763,12 +1729,6 @@ static void nss_core_init_nss(struct nss + ret = nss_n2h_update_queue_config_async(nss_ctx, pn_mq_en, pn_qlimits); + if (ret != NSS_TX_SUCCESS) { + nss_warning("%px: Failed to send pnode queue config to core 1\n", nss_ctx); +- return; +- } +- +- ret = nss_project_pri_mq_map_configure(nss_ctx); +- if (ret != NSS_TX_SUCCESS) { +- nss_warning("%px: Failed to send pnode priority to multi-queue config to core 1\n", nss_ctx); + } + return; + } +@@ -1776,21 +1736,20 @@ static void nss_core_init_nss(struct nss + /* + * If nss core0 is up, then we are ready to hook to nss-gmac + */ +-#if defined(NSS_DATA_PLANE_GENERIC_SUPPORT) || defined(NSS_DATA_PLANE_LITE_SUPPORT) +-#ifdef NSS_DATA_PLANE_GENERIC_SUPPORT + if (nss_data_plane_schedule_registration()) { ++ + /* + * Configure the maximum number of IPv4/IPv6 + * connections supported by the accelerator. + */ +-#ifdef NSS_DRV_IPV4_ENABLE + nss_ipv4_conn_cfg = max_ipv4_conn; +- nss_ipv4_update_conn_count(max_ipv4_conn); +-#endif + + #ifdef NSS_DRV_IPV6_ENABLE + nss_ipv6_conn_cfg = max_ipv6_conn; ++ nss_ipv4_update_conn_count(max_ipv4_conn); + nss_ipv6_update_conn_count(max_ipv6_conn); ++#else ++ nss_ipv4_update_conn_count(max_ipv4_conn); + #endif + + #ifdef NSS_MEM_PROFILE_LOW +@@ -1804,25 +1763,11 @@ static void nss_core_init_nss(struct nss + nss_warning("%px: Failed to update empty buffer pool config\n", nss_ctx); + } + #endif +- +-#ifdef NSS_DRV_SHAPER_ENABLE +- ret = nss_n2h_cfg_qos_mem_size(nss_ctx, qos_mem_size); +- if (ret != NSS_TX_SUCCESS) { +- nss_warning("%px: Failed to update QoS memory pool config\n", nss_ctx); +- } +-#endif +-#endif /* NSS_DATA_PLANE_GENERIC_SUPPORT */ +- +-#ifdef NSS_DATA_PLANE_LITE_SUPPORT +- if (nss_data_plane_lite_schedule_registration()) { +- nss_data_plane_lite_register(nss_ctx); +-#endif + } else { + spin_lock_bh(&nss_top->lock); + nss_ctx->state = NSS_CORE_STATE_UNINITIALIZED; + spin_unlock_bh(&nss_top->lock); + } +-#endif /* NSS_DATA_PLANE_GENERIC_SUPPORT || NSS_DATA_PLANE_LITE_SUPPORT */ + } + + /* +@@ -2281,15 +2226,6 @@ static void nss_core_handle_cause_nonque + #endif + } + +-#if defined(NSS_DRV_EDMA_LITE_ENABLE) +- /* +- * check if point offload it enabled; if yes then send message +- */ +- if (nss_edma_lite_enabled(nss_ctx) && !nss_edma_lite_is_configured()) { +- nss_edma_lite_msg_cfg_map(nss_ctx); +- } +-#endif +- + /* + * TODO: find better mechanism to handle empty buffers + */ +@@ -2658,7 +2594,11 @@ static inline bool nss_core_skb_can_reus + if (unlikely(irqs_disabled())) + return false; + ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) ++ if (unlikely(skb_shinfo(nbuf)->flags & SKBFL_ZEROCOPY_ENABLE)) ++#else + if (unlikely(skb_shinfo(nbuf)->tx_flags & SKBTX_DEV_ZEROCOPY)) ++#endif + return false; + + if (unlikely(skb_is_nonlinear(nbuf))) +@@ -3046,7 +2986,7 @@ static inline int32_t nss_core_send_buff + */ + void nss_core_init_handlers(struct nss_ctx_instance *nss_ctx) + { +- struct nss_rx_cb_list *cb_list = nss_ctx->nss_rx_interface_handlers; ++ struct nss_rx_cb_list *cb_list = nss_ctx->nss_rx_interface_handlers[nss_ctx->id]; + memset(cb_list, 0, sizeof(*cb_list) * NSS_MAX_NET_INTERFACES); + } + +@@ -3100,52 +3040,48 @@ int32_t nss_core_send_buffer(struct nss_ + * Take a lock for queue + */ + spin_lock_bh(&h2n_desc_ring->lock); +- nss_index = h2n_desc_ring->nss_index_local; +- hlos_index = h2n_desc_ring->hlos_index; +- count = ((nss_index - hlos_index - 1) + size) & (mask); + + /* +- * If local index shows that there is not enough space in the ring, +- * Read the actual index from the consumer's generation (NSS-FW). ++ * We need to work out if there's sufficent space in our transmit descriptor ++ * ring to place all the segments of a nbuf. + */ ++ NSS_CORE_DMA_CACHE_MAINT((void *)&if_map->h2n_nss_index[qid], sizeof(uint32_t), DMA_FROM_DEVICE); ++ NSS_CORE_DSB(); ++ nss_index = if_map->h2n_nss_index[qid]; ++ ++ hlos_index = h2n_desc_ring->hlos_index; ++ ++ count = ((nss_index - hlos_index - 1) + size) & (mask); ++ + if (unlikely(count < (segments + 1))) { + /* +- * We need to work out if there's sufficent space in our transmit descriptor +- * ring to place all the segments of a nbuf. +- */ +- NSS_CORE_DMA_CACHE_MAINT((void *)&if_map->h2n_nss_index[qid], sizeof(uint32_t), DMA_FROM_DEVICE); +- NSS_CORE_DSB(); +- nss_index = if_map->h2n_nss_index[qid]; +- h2n_desc_ring->nss_index_local = nss_index; +- count = ((nss_index - hlos_index - 1) + size) & (mask); +- if (unlikely(count < (segments + 1))) { +- /* +- * NOTE: tx_q_full_cnt and TX_STOPPED flags will be used +- * when we will add support for DESC Q congestion management +- * in future +- */ +- h2n_desc_ring->tx_q_full_cnt++; +- h2n_desc_ring->flags |= NSS_H2N_DESC_RING_FLAGS_TX_STOPPED; +- spin_unlock_bh(&h2n_desc_ring->lock); +- nss_warning("%px: Data/Command Queue full reached", nss_ctx); ++ * NOTE: tx_q_full_cnt and TX_STOPPED flags will be used ++ * when we will add support for DESC Q congestion management ++ * in future ++ */ ++ h2n_desc_ring->tx_q_full_cnt++; ++ h2n_desc_ring->flags |= NSS_H2N_DESC_RING_FLAGS_TX_STOPPED; ++ spin_unlock_bh(&h2n_desc_ring->lock); ++ nss_warning("%px: Data/Command Queue full reached", nss_ctx); + + #if (NSS_PKT_STATS_ENABLED == 1) +- if (nss_ctx->id == NSS_CORE_0) { +- NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_TX_QUEUE_FULL_0]); +- } else if (nss_ctx->id == NSS_CORE_1) { +- NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_TX_QUEUE_FULL_1]); +- } else { +- nss_warning("%px: Invalid nss core: %d\n", nss_ctx, nss_ctx->id); +- } ++ if (nss_ctx->id == NSS_CORE_0) { ++ NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_TX_QUEUE_FULL_0]); ++ } else if (nss_ctx->id == NSS_CORE_1) { ++ NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_TX_QUEUE_FULL_1]); ++ } else { ++ nss_warning("%px: Invalid nss core: %d\n", nss_ctx, nss_ctx->id); ++ } + #endif +- /* +- * Enable de-congestion interrupt from NSS +- */ +- nss_hal_enable_interrupt(nss_ctx, nss_ctx->int_ctx[0].shift_factor, NSS_N2H_INTR_TX_UNBLOCKED); + +- return NSS_CORE_STATUS_FAILURE_QUEUE; +- } ++ /* ++ * Enable de-congestion interrupt from NSS ++ */ ++ nss_hal_enable_interrupt(nss_ctx, nss_ctx->int_ctx[0].shift_factor, NSS_N2H_INTR_TX_UNBLOCKED); ++ ++ return NSS_CORE_STATUS_FAILURE_QUEUE; + } ++ + desc = &desc_ring[hlos_index]; + + /* +--- a/nss_core.h ++++ b/nss_core.h +@@ -1,12 +1,9 @@ + /* + ************************************************************************** +- * Copyright (c) 2013-2021, The Linux Foundation. All rights reserved. +- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. +- * ++ * Copyright (c) 2013-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +- * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +@@ -41,10 +38,8 @@ + #include "nss_phys_if.h" + #include "nss_hlos_if.h" + #include "nss_oam.h" +-#ifdef NSS_DATA_PLANE_GENERIC_SUPPORT + #include "nss_data_plane.h" + #include "nss_gmac_stats.h" +-#endif + #include "nss_meminfo.h" + #include "nss_stats.h" + +@@ -191,7 +186,7 @@ static inline void nss_core_dma_cache_ma + /* + * NSS maximum IRQ per interrupt instance/core + */ +-#if defined(NSS_HAL_IPQ807x_SUPPORT) || defined(NSS_HAL_IPQ60XX_SUPPORT) || defined(NSS_HAL_IPQ95XX_SUPPORT) ++#if defined(NSS_HAL_IPQ807x_SUPPORT) || defined(NSS_HAL_IPQ60XX_SUPPORT) + #define NSS_MAX_IRQ_PER_INSTANCE 6 + #define NSS_MAX_IRQ_PER_CORE 10 /* must match with NSS_HAL_N2H_INTR_PURPOSE_MAX */ + #elif defined(NSS_HAL_IPQ50XX_SUPPORT) +@@ -238,7 +233,6 @@ static inline void nss_core_dma_cache_ma + * + */ + #define NSS_FREQ_SCALE_NA 0xFAADFAAD /* Frequency scale not supported */ +-#define NSS_FREQ_NA 0x0 /* Instructions Per ms Min */ + + #define NSS_FREQ_110 110000000 /* Frequency in hz */ + #define NSS_FREQ_110_MIN 0x03000 /* Instructions Per ms Min */ +@@ -282,14 +276,6 @@ static inline void nss_core_dma_cache_ma + #define NSS_FREQ_800_MIN 0x07000 /* Instructions Per ms Min */ + #define NSS_FREQ_800_MAX 0x25000 /* Instructions Per ms Max */ + +-#define NSS_FREQ_850 850000000 /* Frequency in hz */ +-#define NSS_FREQ_850_MIN 0x07000 /* Instructions Per ms Min */ +-#define NSS_FREQ_850_MAX 0x0c000 /* Instructions Per ms Max */ +- +-#define NSS_FREQ_1000 1000000000 /* Frequency in hz */ +-#define NSS_FREQ_1000_MIN 0x0c000 /* Instructions Per ms Min */ +-#define NSS_FREQ_1000_MAX 0x25000 /* Instructions Per ms Max */ +- + #define NSS_FREQ_1497 1497600000 /* Frequency in hz */ + #if defined(NSS_HAL_IPQ60XX_SUPPORT) + #define NSS_FREQ_1497_MIN 0x18000 /* Instructions Per ms Min */ +@@ -394,7 +380,6 @@ struct hlos_n2h_desc_ring { + struct hlos_h2n_desc_rings { + struct h2n_desc_if_instance desc_ring; /* Descriptor ring */ + uint32_t hlos_index; +- uint32_t nss_index_local; /* Index number for the next descriptor (NSS owned) */ + spinlock_t lock; /* Lock to save from simultaneous access */ + uint32_t flags; /* Flags */ + uint64_t tx_q_full_cnt; /* Descriptor queue full count */ +@@ -492,9 +477,6 @@ struct nss_ctx_instance { + /* Service code callbacks */ + void *service_code_ctx[NSS_MAX_SERVICE_CODE]; + /* Service code callback contexts */ +- nss_edma_lite_msg_callback_t edma_lite_callback; +- /* EDMA lite callback */ +- void *edma_lite_ctx; /* EDMA lite context */ + spinlock_t decongest_cb_lock; /* Lock to protect queue decongestion cb table */ + uint16_t phys_if_mtu[NSS_MAX_PHYSICAL_INTERFACES]; + /* Current MTU value of physical interface */ +@@ -504,7 +486,7 @@ struct nss_ctx_instance { + /* Worker thread statistics */ + struct nss_unaligned_stats unaligned_stats; + /* Unaligned emulation performance statistics */ +- struct nss_rx_cb_list nss_rx_interface_handlers[NSS_MAX_NET_INTERFACES]; ++ struct nss_rx_cb_list nss_rx_interface_handlers[NSS_MAX_CORES][NSS_MAX_NET_INTERFACES]; + /* NSS interface callback handlers */ + struct nss_subsystem_dataplane_register subsys_dp_register[NSS_MAX_NET_INTERFACES]; + /* Subsystem registration data */ +@@ -577,9 +559,6 @@ struct nss_top_instance { + uint8_t mirror_handler_id; + uint8_t wmdb_handler_id; + uint8_t dma_handler_id; +- uint8_t udp_st_handler_id; +- uint8_t edma_lite_handler_id[NSS_MAX_CORES]; +- uint8_t trustsec_rx_handler_id; + + /* + * Data/Message callbacks for various interfaces +@@ -674,10 +653,8 @@ struct nss_top_instance { + */ + atomic64_t stats_drv[NSS_DRV_STATS_MAX]; + /* Hlos driver statistics */ +-#ifdef NSS_DATA_PLANE_GENERIC_SUPPORT + uint64_t stats_gmac[NSS_MAX_PHYSICAL_INTERFACES][NSS_GMAC_STATS_MAX]; + /* GMAC statistics */ +-#endif + uint64_t stats_node[NSS_MAX_NET_INTERFACES][NSS_STATS_NODE_MAX]; + /* IPv4 statistics per interface */ + bool nss_hal_common_init_done; +@@ -690,10 +667,8 @@ struct nss_top_instance { + */ + uint64_t last_rx_jiffies; /* Time of the last RX message from the NA in jiffies */ + struct nss_hal_ops *hal_ops; /* nss_hal ops for this target platform */ +-#ifdef NSS_DATA_PLANE_GENERIC_SUPPORT + struct nss_data_plane_ops *data_plane_ops; + /* nss_data_plane ops for this target platform */ +-#endif + }; + + #if (NSS_PKT_STATS_ENABLED == 1) +@@ -919,12 +894,6 @@ struct nss_platform_data { + /* Does this core handle TLS Tunnel ? */ + enum nss_feature_enabled mirror_enabled; + /* Does this core handle mirror? */ +- enum nss_feature_enabled udp_st_enabled; +- /* Does this core handle udp st? */ +- enum nss_feature_enabled edma_lite_enabled; +- /* Does this core handle EDMA lite? */ +- enum nss_feature_enabled trustsec_enabled; +- /* Does this core handle TrustSec? */ + }; + #endif + +@@ -975,8 +944,6 @@ extern uint32_t nss_core_unregister_hand + extern void nss_core_init_handlers(struct nss_ctx_instance *nss_ctx); + void nss_core_update_max_ipv4_conn(int conn); + void nss_core_update_max_ipv6_conn(int conn); +-void nss_core_update_qos_mem_size(int size); +-int nss_core_get_qos_mem_size(void); + extern void nss_core_register_subsys_dp(struct nss_ctx_instance *nss_ctx, uint32_t if_num, + nss_phys_if_rx_callback_t cb, + nss_phys_if_rx_ext_data_callback_t ext_cb, +@@ -984,11 +951,10 @@ extern void nss_core_register_subsys_dp( + uint32_t features); + extern void nss_core_unregister_subsys_dp(struct nss_ctx_instance *nss_ctx, uint32_t if_num); + void nss_core_set_subsys_dp_type(struct nss_ctx_instance *nss_ctx, struct net_device *ndev, uint32_t if_num, uint32_t type); +-extern bool nss_core_is_mq_enabled(void); + + static inline nss_if_rx_msg_callback_t nss_core_get_msg_handler(struct nss_ctx_instance *nss_ctx, uint32_t interface) + { +- return nss_ctx->nss_rx_interface_handlers[interface].msg_cb; ++ return nss_ctx->nss_rx_interface_handlers[nss_ctx->id][interface].msg_cb; + } + + static inline uint32_t nss_core_get_max_buf_size(struct nss_ctx_instance *nss_ctx) +@@ -1056,6 +1022,5 @@ extern void nss_ppe_free(void); + */ + extern nss_tx_status_t nss_n2h_cfg_empty_pool_size(struct nss_ctx_instance *nss_ctx, uint32_t pool_sz); + extern nss_tx_status_t nss_n2h_paged_buf_pool_init(struct nss_ctx_instance *nss_ctx); +-extern nss_tx_status_t nss_n2h_cfg_qos_mem_size(struct nss_ctx_instance *nss_ctx, uint32_t pool_sz); + + #endif /* __NSS_CORE_H */ +--- a/nss_coredump.c ++++ b/nss_coredump.c +@@ -25,7 +25,11 @@ + #include "nss_hal.h" + #include "nss_log.h" + #include ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 14, 0)) + #include /* for panic_notifier_list */ ++#else ++#include ++#endif + #include /* for time */ + #include "nss_tx_rx_common.h" + +--- a/nss_crypto_cmn.c ++++ b/nss_crypto_cmn.c +@@ -21,8 +21,6 @@ + + #include "nss_tx_rx_common.h" + #include "nss_crypto_cmn.h" +-#include "nss_crypto_cmn_strings.h" +-#include "nss_crypto_cmn_stats.h" + #include "nss_crypto_cmn_log.h" + + /* +@@ -96,18 +94,6 @@ static void nss_crypto_cmn_msg_handler(s + */ + nss_crypto_cmn_log_rx_msg(nim); + +- switch (nim->cm.type) { +- case NSS_CRYPTO_CMN_MSG_TYPE_SYNC_NODE_STATS: +- case NSS_CRYPTO_CMN_MSG_TYPE_SYNC_ENG_STATS: +- case NSS_CRYPTO_CMN_MSG_TYPE_SYNC_CTX_STATS: +- /* +- * Update driver statistics and send statistics +- * notification to the registered modules. +- */ +- nss_crypto_cmn_stats_sync(nss_ctx, &nim->msg.stats); +- nss_crypto_cmn_stats_notify(nss_ctx); +- break; +- } + /* + * Load, Test & call + */ +@@ -226,12 +212,6 @@ nss_tx_status_t nss_crypto_cmn_tx_msg_sy + * further details read Linux/Documentation/memory-barrier.txt + */ + smp_rmb(); +- +- if (msg->cm.response != NSS_CMN_RESPONSE_ACK) { +- up(&pvt->sem); +- return NSS_TX_FAILURE; +- } +- + up(&pvt->sem); + + return NSS_TX_SUCCESS; +@@ -377,9 +357,6 @@ void nss_crypto_cmn_register_handler(voi + sema_init(&g_nss_crypto_cmn.sem, 1); + init_completion(&g_nss_crypto_cmn.complete); + nss_core_register_handler(nss_ctx, NSS_CRYPTO_CMN_INTERFACE, nss_crypto_cmn_msg_handler, NULL); +- +- nss_crypto_cmn_stats_dentry_create(); +- nss_crypto_cmn_strings_dentry_create(); + } + + /* +--- a/nss_crypto_cmn_stats.c ++++ /dev/null +@@ -1,166 +0,0 @@ +-/* +- ************************************************************************** +- * Copyright (c) 2020, The Linux Foundation. All rights reserved. +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- ************************************************************************** +- */ +- +-#include "nss_core.h" +-#include "nss_crypto_cmn_stats.h" +-#include "nss_crypto_cmn_strings.h" +- +-/* +- * Declare atomic notifier data structure for statistics. +- */ +-ATOMIC_NOTIFIER_HEAD(nss_crypto_cmn_stats_notifier); +- +-/* +- * Spinlock to protect CRYPTO_CMN statistics update/read +- */ +-DEFINE_SPINLOCK(nss_crypto_cmn_stats_lock); +- +-/* +- * nss_crypto_cmn_stats +- * crypto common statistics +- */ +-uint64_t nss_crypto_cmn_stats[NSS_CRYPTO_CMN_STATS_MAX]; +- +-/* +- * nss_crypto_cmn_stats_read() +- * Read crypto common statistics +- */ +-static ssize_t nss_crypto_cmn_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- int32_t i; +- +- /* +- * Max output lines = #stats + +- * few blank lines for banner printing + Number of Extra outputlines +- * for future reference to add new stats +- */ +- uint32_t max_output_lines = NSS_CRYPTO_CMN_STATS_MAX + NSS_STATS_EXTRA_OUTPUT_LINES; +- size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines; +- size_t size_wr = 0; +- ssize_t bytes_read = 0; +- uint64_t *stats_shadow; +- +- char *lbuf = vzalloc(size_al); +- if (unlikely(!lbuf)) { +- nss_warning("Could not allocate memory for local statistics buffer"); +- return -ENOMEM; +- } +- +- stats_shadow = vzalloc(NSS_CRYPTO_CMN_STATS_MAX * 8); +- if (unlikely(!stats_shadow)) { +- nss_warning("Could not allocate memory for local shadow buffer"); +- vfree(lbuf); +- return -ENOMEM; +- } +- +- /* +- * crypto common statistics +- */ +- spin_lock_bh(&nss_crypto_cmn_stats_lock); +- for (i = 0; i < NSS_CRYPTO_CMN_STATS_MAX; i++) +- stats_shadow[i] = nss_crypto_cmn_stats[i]; +- +- spin_unlock_bh(&nss_crypto_cmn_stats_lock); +- size_wr += nss_stats_banner(lbuf, size_wr, size_al, "crypto_cmn", NSS_STATS_SINGLE_CORE); +- size_wr += nss_stats_print("crypto_cmn", NULL, NSS_STATS_SINGLE_INSTANCE, nss_crypto_cmn_strings_stats, +- stats_shadow, NSS_CRYPTO_CMN_STATS_MAX, lbuf, size_wr, size_al); +- +- bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf)); +- vfree(lbuf); +- vfree(stats_shadow); +- +- return bytes_read; +-} +- +-/* +- * nss_crypto_cmn_stats_ops +- */ +-NSS_STATS_DECLARE_FILE_OPERATIONS(crypto_cmn); +- +-/* +- * nss_crypto_cmn_stats_dentry_create() +- * Create crypto common statistics debug entry. +- */ +-void nss_crypto_cmn_stats_dentry_create(void) +-{ +- nss_stats_create_dentry("crypto_cmn", &nss_crypto_cmn_stats_ops); +-} +- +-/* +- * nss_crypto_cmn_stats_sync() +- * Handle the syncing of NSS crypto common statistics. +- */ +-void nss_crypto_cmn_stats_sync(struct nss_ctx_instance *nss_ctx, struct nss_crypto_cmn_stats *nct) +-{ +- int j; +- +- spin_lock_bh(&nss_crypto_cmn_stats_lock); +- +- /* +- * Common node stats +- */ +- nss_crypto_cmn_stats[NSS_STATS_NODE_RX_PKTS] += nct->nstats.rx_packets; +- nss_crypto_cmn_stats[NSS_STATS_NODE_RX_BYTES] += nct->nstats.rx_bytes; +- nss_crypto_cmn_stats[NSS_STATS_NODE_TX_PKTS] += nct->nstats.tx_packets; +- nss_crypto_cmn_stats[NSS_STATS_NODE_TX_BYTES] += nct->nstats.tx_bytes; +- +- for (j = 0; j < NSS_MAX_NUM_PRI; j++) +- nss_crypto_cmn_stats[NSS_STATS_NODE_RX_QUEUE_0_DROPPED + j] += nct->nstats.rx_dropped[j]; +- +- /* +- * crypto common statistics +- */ +- nss_crypto_cmn_stats[NSS_CRYPTO_CMN_STATS_FAIL_VERSION] += nct->fail_version; +- nss_crypto_cmn_stats[NSS_CRYPTO_CMN_STATS_FAIL_CTX] += nct->fail_ctx; +- nss_crypto_cmn_stats[NSS_CRYPTO_CMN_STATS_FAIL_DMA] += nct->fail_dma; +- +- spin_unlock_bh(&nss_crypto_cmn_stats_lock); +-} +- +-/* +- * nss_crypto_cmn_stats_notify() +- * Sends notifications to all the registered modules. +- * +- * Leverage NSS-FW statistics timing to update Netlink. +- */ +-void nss_crypto_cmn_stats_notify(struct nss_ctx_instance *nss_ctx) +-{ +- struct nss_crypto_cmn_stats_notification crypto_cmn_stats; +- +- crypto_cmn_stats.core_id = nss_ctx->id; +- memcpy(crypto_cmn_stats.stats, nss_crypto_cmn_stats, sizeof(crypto_cmn_stats.stats)); +- atomic_notifier_call_chain(&nss_crypto_cmn_stats_notifier, NSS_STATS_EVENT_NOTIFY, &crypto_cmn_stats); +-} +- +-/* +- * nss_crypto_cmn_stats_register_notifier() +- * Registers statistics notifier. +- */ +-int nss_crypto_cmn_stats_register_notifier(struct notifier_block *nb) +-{ +- return atomic_notifier_chain_register(&nss_crypto_cmn_stats_notifier, nb); +-} +-EXPORT_SYMBOL(nss_crypto_cmn_stats_register_notifier); +- +-/* +- * nss_crypto_cmn_stats_unregister_notifier() +- * Deregisters statistics notifier. +- */ +-int nss_crypto_cmn_stats_unregister_notifier(struct notifier_block *nb) +-{ +- return atomic_notifier_chain_unregister(&nss_crypto_cmn_stats_notifier, nb); +-} +-EXPORT_SYMBOL(nss_crypto_cmn_stats_unregister_notifier); +--- a/nss_crypto_cmn_stats.h ++++ /dev/null +@@ -1,77 +0,0 @@ +-/* +- ****************************************************************************** +- * Copyright (c) 2020, The Linux Foundation. All rights reserved. +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- * **************************************************************************** +- */ +- +-#ifndef __NSS_CRYPTO_CMN_STATS_H +-#define __NSS_CRYPTO_CMN_STATS_H +- +-#include +- +-/** +- * nss_crypto_cmn_stats_types +- * crypto common transmission node statistics +- */ +-enum nss_crypto_cmn_stats_types { +- NSS_CRYPTO_CMN_STATS_FAIL_VERSION = NSS_STATS_NODE_MAX, /* version mismatch failures */ +- NSS_CRYPTO_CMN_STATS_FAIL_CTX, /* context related failures */ +- NSS_CRYPTO_CMN_STATS_FAIL_DMA, /* dma descriptor full */ +- NSS_CRYPTO_CMN_STATS_MAX, /* Maximum message type */ +-}; +- +-/** +- * nss_crypto_cmn_stats_notification +- * crypto common transmission statistics structure +- */ +-struct nss_crypto_cmn_stats_notification { +- uint32_t core_id; /* core ID */ +- uint64_t stats[NSS_CRYPTO_CMN_STATS_MAX]; /* transmission statistics */ +-}; +- +-/* +- * crypto common statistics APIs +- */ +-extern void nss_crypto_cmn_stats_notify(struct nss_ctx_instance *nss_ctx); +-extern void nss_crypto_cmn_stats_sync(struct nss_ctx_instance *nss_ctx, struct nss_crypto_cmn_stats *nct); +-extern void nss_crypto_cmn_stats_dentry_create(void); +- +-/** +- * nss_crypto_cmn_stats_register_notifier +- * Registers a statistics notifier. +- * +- * @datatypes +- * notifier_block +- * +- * @param[in] nb Notifier block. +- * +- * @return +- * 0 on success or -2 on failure. +- */ +-extern int nss_crypto_cmn_stats_register_notifier(struct notifier_block *nb); +- +-/** +- * nss_crypto_cmn_stats_unregister_notifier +- * Deregisters a statistics notifier. +- * +- * @datatypes +- * notifier_block +- * +- * @param[in] nb Notifier block. +- * +- * @return +- * 0 on success or -2 on failure. +- */ +-extern int nss_crypto_cmn_stats_unregister_notifier(struct notifier_block *nb); +- +-#endif /* __NSS_CRYPTO_CMN_STATS_H */ +--- a/nss_crypto_cmn_strings.c ++++ /dev/null +@@ -1,61 +0,0 @@ +-/* +- ************************************************************************** +- * Copyright (c) 2020, The Linux Foundation. All rights reserved. +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- ************************************************************************** +- */ +- +-#include "nss_stats.h" +-#include "nss_core.h" +-#include "nss_strings.h" +-#include "nss_crypto_cmn_strings.h" +- +-/* +- * nss_crypto_cmn_strings_stats +- * crypto common statistics strings. +- */ +-struct nss_stats_info nss_crypto_cmn_strings_stats[NSS_CRYPTO_CMN_STATS_MAX] = { +- {"rx_pkts", NSS_STATS_TYPE_COMMON}, +- {"rx_byts", NSS_STATS_TYPE_COMMON}, +- {"tx_pkts", NSS_STATS_TYPE_COMMON}, +- {"tx_byts", NSS_STATS_TYPE_COMMON}, +- {"rx_queue[0]_drops", NSS_STATS_TYPE_DROP}, +- {"rx_queue[1]_drops", NSS_STATS_TYPE_DROP}, +- {"rx_queue[2]_drops", NSS_STATS_TYPE_DROP}, +- {"rx_queue[3]_drops", NSS_STATS_TYPE_DROP}, +- {"fail_version", NSS_STATS_TYPE_SPECIAL}, +- {"fail_ctx", NSS_STATS_TYPE_SPECIAL}, +- {"fail_dma", NSS_STATS_TYPE_SPECIAL} +-}; +- +-/* +- * nss_crypto_cmn_strings_read() +- * Read crypto common node statistics names +- */ +-static ssize_t nss_crypto_cmn_strings_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- return nss_strings_print(ubuf, sz, ppos, nss_crypto_cmn_strings_stats, NSS_CRYPTO_CMN_STATS_MAX); +-} +- +-/* +- * nss_crypto_cmn_strings_ops +- */ +-NSS_STRINGS_DECLARE_FILE_OPERATIONS(crypto_cmn); +- +-/* +- * nss_crypto_cmn_strings_dentry_create() +- * Create crypto common statistics strings debug entry. +- */ +-void nss_crypto_cmn_strings_dentry_create(void) +-{ +- nss_strings_create_dentry("crypto_cmn", &nss_crypto_cmn_strings_ops); +-} +--- a/nss_crypto_cmn_strings.h ++++ /dev/null +@@ -1,25 +0,0 @@ +-/* +- ************************************************************************** +- * Copyright (c) 2020, The Linux Foundation. All rights reserved. +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- ************************************************************************** +- */ +- +-#ifndef __NSS_CRYPTO_CMN_STRINGS_H +-#define __NSS_CRYPTO_CMN_STRINGS_H +- +-#include "nss_crypto_cmn_stats.h" +- +-extern struct nss_stats_info nss_crypto_cmn_strings_stats[NSS_CRYPTO_CMN_STATS_MAX]; +-extern void nss_crypto_cmn_strings_dentry_create(void); +- +-#endif /* __NSS_CRYPTO_CMN_STRINGS_H */ +--- a/nss_data_plane/hal/include/nss_data_plane_hal.h ++++ b/nss_data_plane/hal/include/nss_data_plane_hal.h +@@ -17,22 +17,6 @@ + #include "nss_phys_if.h" + #include + +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0)) +-#define NSS_DATA_PLANE_SUPPORTED_FEATURES (NETIF_F_HIGHDMA \ +- | NETIF_F_HW_CSUM \ +- | NETIF_F_RXCSUM \ +- | NETIF_F_SG \ +- | NETIF_F_FRAGLIST \ +- | (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_UFO)) +-#else +-#define NSS_DATA_PLANE_SUPPORTED_FEATURES (NETIF_F_HIGHDMA \ +- | NETIF_F_HW_CSUM \ +- | NETIF_F_RXCSUM \ +- | NETIF_F_SG \ +- | NETIF_F_FRAGLIST \ +- | (NETIF_F_TSO | NETIF_F_TSO6)) +-#endif +- + /* + * nss_data_plane_param + */ +@@ -49,6 +33,5 @@ struct nss_data_plane_param { + void nss_data_plane_hal_add_dp_ops(struct nss_dp_data_plane_ops *dp_ops); + void nss_data_plane_hal_register(struct nss_ctx_instance *nss_ctx); + void nss_data_plane_hal_unregister(struct nss_ctx_instance *nss_ctx); +-void nss_data_plane_hal_set_features(struct nss_dp_data_plane_ctx *dpc); + uint16_t nss_data_plane_hal_get_mtu_sz(uint16_t mtu); + void nss_data_plane_hal_stats_sync(struct nss_data_plane_param *ndpp, struct nss_phys_if_stats *stats); +--- a/nss_data_plane/hal/nss_ipq60xx.c ++++ b/nss_data_plane/hal/nss_ipq60xx.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above +@@ -40,12 +40,25 @@ static int nss_data_plane_hal_vsi_unassi + } + + /* ++ * nss_data_plane_hal_get_stats() ++ * Called by nss-dp to get GMAC stats ++ */ ++static void nss_data_plane_hal_get_stats(struct nss_dp_data_plane_ctx *dpc, ++ struct nss_dp_gmac_stats *stats) ++{ ++ /* ++ * EDMA doesn't send extended statistics. ++ */ ++} ++ ++/* + * nss_data_plane_hal_add_dp_ops() + */ + void nss_data_plane_hal_add_dp_ops(struct nss_dp_data_plane_ops *dp_ops) + { + dp_ops->vsi_assign = nss_data_plane_hal_vsi_assign; + dp_ops->vsi_unassign = nss_data_plane_hal_vsi_unassign; ++ dp_ops->get_stats = nss_data_plane_hal_get_stats; + } + + /* +@@ -71,17 +84,6 @@ void nss_data_plane_hal_unregister(struc + } + + /* +- * nss_data_plane_hal_set_features +- */ +-void nss_data_plane_hal_set_features(struct nss_dp_data_plane_ctx *dpc) +-{ +- dpc->dev->features |= NSS_DATA_PLANE_SUPPORTED_FEATURES; +- dpc->dev->hw_features |= NSS_DATA_PLANE_SUPPORTED_FEATURES; +- dpc->dev->vlan_features |= NSS_DATA_PLANE_SUPPORTED_FEATURES; +- dpc->dev->wanted_features |= NSS_DATA_PLANE_SUPPORTED_FEATURES; +-} +- +-/* + * nss_data_plane_hal_stats_sync() + */ + void nss_data_plane_hal_stats_sync(struct nss_data_plane_param *ndpp, +--- a/nss_data_plane/hal/nss_ipq807x.c ++++ b/nss_data_plane/hal/nss_ipq807x.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above +@@ -40,12 +40,25 @@ static int nss_data_plane_hal_vsi_unassi + } + + /* ++ * nss_data_plane_hal_get_stats() ++ * Called by nss-dp to get GMAC stats ++ */ ++static void nss_data_plane_hal_get_stats(struct nss_dp_data_plane_ctx *dpc, ++ struct nss_dp_gmac_stats *stats) ++{ ++ /* ++ * EDMA doesn't send extended statistics. ++ */ ++} ++ ++/* + * nss_data_plane_hal_add_dp_ops() + */ + void nss_data_plane_hal_add_dp_ops(struct nss_dp_data_plane_ops *dp_ops) + { + dp_ops->vsi_assign = nss_data_plane_hal_vsi_assign; + dp_ops->vsi_unassign = nss_data_plane_hal_vsi_unassign; ++ dp_ops->get_stats = nss_data_plane_hal_get_stats; + } + + /* +@@ -71,17 +84,6 @@ void nss_data_plane_hal_unregister(struc + } + + /* +- * nss_data_plane_hal_set_features +- */ +-void nss_data_plane_hal_set_features(struct nss_dp_data_plane_ctx *dpc) +-{ +- dpc->dev->features |= NSS_DATA_PLANE_SUPPORTED_FEATURES; +- dpc->dev->hw_features |= NSS_DATA_PLANE_SUPPORTED_FEATURES; +- dpc->dev->vlan_features |= NSS_DATA_PLANE_SUPPORTED_FEATURES; +- dpc->dev->wanted_features |= NSS_DATA_PLANE_SUPPORTED_FEATURES; +-} +- +-/* + * nss_data_plane_hal_stats_sync() + */ + void nss_data_plane_hal_stats_sync(struct nss_data_plane_param *ndpp, +--- a/nss_data_plane/include/nss_data_plane.h ++++ b/nss_data_plane/include/nss_data_plane.h +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2014-2017,2020-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2014-2017,2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -25,8 +25,6 @@ + #include + #include "nss_phys_if.h" + +-#define NSS_DATA_PLANE_MAX_PACKET_LEN 65535 +- + /* + * nss_data_plane_schedule_registration() + * Called from nss_init to schedule a work to do data_plane register to data plane host driver +--- a/nss_data_plane/nss_data_plane.c ++++ b/nss_data_plane/nss_data_plane.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -19,6 +19,22 @@ + #include "nss_tx_rx_common.h" + #include "nss_data_plane_hal.h" + ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0)) ++#define NSS_DATA_PLANE_SUPPORTED_FEATURES (NETIF_F_HIGHDMA \ ++ | NETIF_F_HW_CSUM \ ++ | NETIF_F_RXCSUM \ ++ | NETIF_F_SG \ ++ | NETIF_F_FRAGLIST \ ++ | (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_UFO)) ++#else ++#define NSS_DATA_PLANE_SUPPORTED_FEATURES (NETIF_F_HIGHDMA \ ++ | NETIF_F_HW_CSUM \ ++ | NETIF_F_RXCSUM \ ++ | NETIF_F_SG \ ++ | NETIF_F_FRAGLIST \ ++ | (NETIF_F_TSO | NETIF_F_TSO6)) ++#endif ++ + /* + * nss_data_plane_param + */ +@@ -101,6 +117,12 @@ static int __nss_data_plane_mac_addr(str + static int __nss_data_plane_change_mtu(struct nss_dp_data_plane_ctx *dpc, uint32_t mtu) + { + struct nss_data_plane_param *dp = (struct nss_data_plane_param *)dpc; ++ ++ if (mtu > NSS_DP_MAX_MTU_SIZE) { ++ nss_warning("%px: MTU exceeds MAX size %d\n", dp, mtu); ++ return NSS_DP_FAILURE; ++ } ++ + return nss_phys_if_change_mtu(dp->nss_ctx, mtu, dp->if_num); + } + +@@ -160,9 +182,8 @@ static netdev_tx_t __nss_data_plane_buf( + goto drop; + } + +- if (skb->len > NSS_DATA_PLANE_MAX_PACKET_LEN) { +- nss_warning("skb->len ( %u ) > Maximum packet length ( %u ) \n", +- skb->len, NSS_DATA_PLANE_MAX_PACKET_LEN); ++ if (skb->len > NSS_DP_MAX_PACKET_LEN) { ++ nss_warning("skb->len ( %u ) > Maximum packet length ( %u ) \n", skb->len, NSS_DP_MAX_PACKET_LEN); + goto drop; + } + +@@ -207,7 +228,10 @@ drop: + */ + static void __nss_data_plane_set_features(struct nss_dp_data_plane_ctx *dpc) + { +- nss_data_plane_hal_set_features(dpc); ++ dpc->dev->features |= NSS_DATA_PLANE_SUPPORTED_FEATURES; ++ dpc->dev->hw_features |= NSS_DATA_PLANE_SUPPORTED_FEATURES; ++ dpc->dev->vlan_features |= NSS_DATA_PLANE_SUPPORTED_FEATURES; ++ dpc->dev->wanted_features |= NSS_DATA_PLANE_SUPPORTED_FEATURES; + } + + /* +--- a/nss_data_plane/nss_data_plane_common.c ++++ b/nss_data_plane/nss_data_plane_common.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2014-2016,2020-2021 The Linux Foundation. All rights reserved. ++ * Copyright (c) 2014-2016,2020 The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -39,16 +39,9 @@ static void nss_data_plane_work_function + */ + ret = nss_n2h_update_queue_config_sync(nss_ctx, pn_mq_en, pn_qlimits); + if (ret != NSS_TX_SUCCESS) { +- nss_warning("%px: Failed to send pnode queue config to core 0\n", nss_ctx); +- goto data_plane_reg; ++ nss_warning("Failed to send pnode queue config to core 0\n"); + } + +- ret = nss_project_pri_mq_map_configure(nss_ctx); +- if (ret != NSS_TX_SUCCESS) { +- nss_warning("%px: Failed to send pnode priority to multi-queue config to core 0\n", nss_ctx); +- } +- +-data_plane_reg: + nss_top->data_plane_ops->data_plane_register(nss_ctx); + } + +--- a/nss_data_plane/nss_data_plane_gmac.c ++++ b/nss_data_plane/nss_data_plane_gmac.c +@@ -20,7 +20,7 @@ + #include "nss_tx_rx_common.h" + #include + +-#define NSS_DP_GMAC_SUPPORTED_FEATURES (NETIF_F_HIGHDMA | NETIF_F_HW_CSUM | NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_FRAGLIST | (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_UFO)) ++#define NSS_DP_GMAC_SUPPORTED_FEATURES (NETIF_F_HIGHDMA | NETIF_F_HW_CSUM | NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_FRAGLIST | (NETIF_F_TSO | NETIF_F_TSO6)) + #define NSS_DATA_PLANE_GMAC_MAX_INTERFACES 4 + + static DEFINE_SPINLOCK(nss_data_plane_gmac_stats_lock); +--- a/nss_dma.c ++++ b/nss_dma.c +@@ -128,7 +128,7 @@ static void nss_dma_msg_handler(struct n + */ + if (ncm->response == NSS_CMN_RESPONSE_NOTIFY) { + ncm->cb = (nss_ptr_t)nss_core_get_msg_handler(nss_ctx, ncm->interface); +- ncm->app_data = (nss_ptr_t)nss_ctx->nss_rx_interface_handlers[ncm->interface].app_data; ++ ncm->app_data = (nss_ptr_t)nss_ctx->nss_rx_interface_handlers[nss_ctx->id][ncm->interface].app_data; + } + + /* +--- a/nss_dma_stats.h ++++ b/nss_dma_stats.h +@@ -1,6 +1,6 @@ + /* + ****************************************************************************** +- * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the +@@ -21,10 +21,44 @@ + + #include + ++/** ++ * nss_dma_stats_types ++ * DMA node statistics. ++ */ ++enum nss_dma_stats_types { ++ NSS_DMA_STATS_NO_REQ = NSS_STATS_NODE_MAX, /**< Request descriptor not available. */ ++ NSS_DMA_STATS_NO_DESC, /**< DMA descriptors not available. */ ++ NSS_DMA_STATS_NEXTHOP, /**< Failed to retrive next hop. */ ++ NSS_DMA_STATS_FAIL_NEXTHOP_QUEUE, /**< Failed to queue next hop. */ ++ NSS_DMA_STATS_FAIL_LINEAR_SZ, /**< Failed to get memory for linearization. */ ++ NSS_DMA_STATS_FAIL_LINEAR_ALLOC, /**< Failed to allocate buffer for linearization. */ ++ NSS_DMA_STATS_FAIL_LINEAR_NO_SG, /**< Skip linearization due to non-SG packet. */ ++ NSS_DMA_STATS_FAIL_SPLIT_SZ, /**< Failed to spliting buffer into multiple buffers. */ ++ NSS_DMA_STATS_FAIL_SPLIT_ALLOC, /**< Failed to allocate buffer for split. */ ++ NSS_DMA_STATS_FAIL_SYNC_ALLOC, /**< Failed to allocate buffer for sending statistics. */ ++ NSS_DMA_STATS_FAIL_CTX_ACTIVE, /**< Failed to queue as the node is not active. */ ++ NSS_DMA_STATS_FAIL_HW_E0, /**< Failed to process in HW, error code E0. */ ++ NSS_DMA_STATS_FAIL_HW_E1, /**< Failed to process in HW, error code E1. */ ++ NSS_DMA_STATS_FAIL_HW_E2, /**< Failed to process in HW, error code E2. */ ++ NSS_DMA_STATS_FAIL_HW_E3, /**< Failed to process in HW, error code E3. */ ++ NSS_DMA_STATS_FAIL_HW_E4, /**< Failed to process in HW, error code E4. */ ++ NSS_DMA_STATS_FAIL_HW_E5, /**< Failed to process in HW, error code E5. */ ++ NSS_DMA_STATS_FAIL_HW_E6, /**< Failed to process in HW, error code E6. */ ++ NSS_DMA_STATS_FAIL_HW_E7, /**< Failed to process in HW, error code E7. */ ++ NSS_DMA_STATS_FAIL_HW_E8, /**< Failed to process in HW, error code E8. */ ++ NSS_DMA_STATS_FAIL_HW_E9, /**< Failed to process in HW, error code E9. */ ++ NSS_DMA_STATS_FAIL_HW_E10, /**< Failed to process in HW, error code E10. */ ++ NSS_DMA_STATS_FAIL_HW_E11, /**< Failed to process in HW, error code E11. */ ++ NSS_DMA_STATS_FAIL_HW_E12, /**< Failed to process in HW, error code E12. */ ++ NSS_DMA_STATS_FAIL_HW_E13, /**< Failed to process in HW, error code E13. */ ++ NSS_DMA_STATS_FAIL_HW_E14, /**< Failed to process in HW, error code E14. */ ++ NSS_DMA_STATS_FAIL_HW_E15, /**< Failed to process in HW, error code E15. */ ++ NSS_DMA_STATS_MAX, /**< Maximum message type. */ ++}; ++ + /* + * DMA statistics APIs + */ +-extern void nss_dma_stats_notify(struct nss_ctx_instance *nss_ctx); + extern void nss_dma_stats_sync(struct nss_ctx_instance *nss_ctx, struct nss_dma_stats *nds); + extern void nss_dma_stats_dentry_create(void); + +--- a/nss_dtls_cmn.c ++++ b/nss_dtls_cmn.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -16,16 +16,15 @@ + + #include "nss_tx_rx_common.h" + #include "nss_dtls_cmn_log.h" +-#include "nss_dtls_cmn_stats.h" +-#include "nss_dtls_cmn_strings.h" + + #define NSS_DTLS_CMN_TX_TIMEOUT 3000 /* 3 Seconds */ + #define NSS_DTLS_CMN_INTERFACE_MAX_LONG BITS_TO_LONGS(NSS_MAX_NET_INTERFACES) +- ++#define NSS_DTLS_CMN_STATS_MAX_LINES (NSS_STATS_NODE_MAX + 32) ++#define NSS_DTLS_CMN_STATS_SIZE_PER_IF (NSS_STATS_MAX_STR_LENGTH * NSS_DTLS_CMN_STATS_MAX_LINES) + /* + * Private data structure. + */ +-static struct nss_dtls_cmn_pvt { ++static struct nss_dtls_cmn_cmn_pvt { + struct semaphore sem; + struct completion complete; + enum nss_dtls_cmn_error resp; +@@ -33,6 +32,91 @@ static struct nss_dtls_cmn_pvt { + } dtls_cmn_pvt; + + /* ++ * nss_dtls_cmn_stats_sync() ++ * Update dtls_cmn node statistics. ++ */ ++static void nss_dtls_cmn_stats_sync(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm) ++{ ++ struct nss_dtls_cmn_msg *ndcm = (struct nss_dtls_cmn_msg *)ncm; ++ struct nss_top_instance *nss_top = nss_ctx->nss_top; ++ struct nss_dtls_cmn_ctx_stats *msg_stats = &ndcm->msg.stats; ++ uint64_t *if_stats; ++ ++ spin_lock_bh(&nss_top->stats_lock); ++ ++ /* ++ * Update common node stats, ++ * Note: DTLS only supports a single queue for RX. ++ */ ++ if_stats = nss_top->stats_node[ncm->interface]; ++ if_stats[NSS_STATS_NODE_RX_PKTS] += msg_stats->pkt.rx_packets; ++ if_stats[NSS_STATS_NODE_RX_BYTES] += msg_stats->pkt.rx_bytes; ++ if_stats[NSS_STATS_NODE_RX_QUEUE_0_DROPPED] += msg_stats->pkt.rx_dropped[0]; ++ ++ if_stats[NSS_STATS_NODE_TX_PKTS] += msg_stats->pkt.tx_packets; ++ if_stats[NSS_STATS_NODE_TX_BYTES] += msg_stats->pkt.tx_bytes; ++ ++ spin_unlock_bh(&nss_top->stats_lock); ++} ++ ++/* ++ * nss_dtls_cmn_stats_read() ++ * Read dtls_cmn node statiistics. ++ */ ++static ssize_t nss_dtls_cmn_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) ++{ ++ struct nss_ctx_instance *nss_ctx = nss_dtls_cmn_get_context(); ++ enum nss_dynamic_interface_type type; ++ ssize_t bytes_read = 0; ++ size_t len = 0, size; ++ uint32_t if_num; ++ char *buf; ++ ++ size = NSS_DTLS_CMN_STATS_SIZE_PER_IF * bitmap_weight(dtls_cmn_pvt.if_map, NSS_MAX_NET_INTERFACES); ++ ++ buf = kzalloc(size, GFP_KERNEL); ++ if (!buf) { ++ nss_warning("Could not allocate memory for local statistics buffer"); ++ return 0; ++ } ++ ++ /* ++ * Common node stats for each DTLS dynamic interface. ++ */ ++ for_each_set_bit(if_num, dtls_cmn_pvt.if_map, NSS_MAX_NET_INTERFACES) { ++ ++ type = nss_dynamic_interface_get_type(nss_ctx, if_num); ++ ++ switch (type) { ++ case NSS_DYNAMIC_INTERFACE_TYPE_DTLS_CMN_INNER: ++ len += scnprintf(buf + len, size - len, "\nInner if_num:%03u", if_num); ++ break; ++ ++ case NSS_DYNAMIC_INTERFACE_TYPE_DTLS_CMN_OUTER: ++ len += scnprintf(buf + len, size - len, "\nOuter if_num:%03u", if_num); ++ break; ++ ++ default: ++ len += scnprintf(buf + len, size - len, "\nUnknown(%d) if_num:%03u", type, if_num); ++ break; ++ } ++ ++ len += scnprintf(buf + len, size - len, "\n-------------------\n"); ++ len += nss_stats_fill_common_stats(if_num, NSS_STATS_SINGLE_INSTANCE, buf, len, size - len, "dtls_cmn"); ++ } ++ ++ bytes_read = simple_read_from_buffer(ubuf, sz, ppos, buf, len); ++ kfree(buf); ++ ++ return bytes_read; ++} ++ ++/* ++ * nss_dtls_cmn_stats_ops. ++ */ ++NSS_STATS_DECLARE_FILE_OPERATIONS(dtls_cmn) ++ ++/* + * nss_dtls_cmn_verify_ifnum() + * Verify if the interface number is a DTLS interface. + */ +@@ -78,17 +162,15 @@ static void nss_dtls_cmn_handler(struct + return; + } + +- if (ncm->type == NSS_DTLS_CMN_MSG_TYPE_SYNC_STATS) { ++ if (ncm->type == NSS_DTLS_CMN_MSG_TYPE_SYNC_STATS) + nss_dtls_cmn_stats_sync(nss_ctx, ncm); +- nss_dtls_cmn_stats_notify(nss_ctx, ncm->interface); +- } + + /* + * Update the callback and app_data for NOTIFY messages. + */ + if (ncm->response == NSS_CMN_RESPONSE_NOTIFY) { + ncm->cb = (nss_ptr_t)nss_core_get_msg_handler(nss_ctx, ncm->interface); +- ncm->app_data = (nss_ptr_t)nss_ctx->nss_rx_interface_handlers[ncm->interface].app_data; ++ ncm->app_data = (nss_ptr_t)nss_ctx->nss_rx_interface_handlers[nss_ctx->id][ncm->interface].app_data; + } + + /* +@@ -139,15 +221,6 @@ static void nss_dtls_cmn_callback(void * + } + + /* +- * nss_dtls_cmn_ifmap_get() +- * Return DTLS common active interfaces map. +- */ +-unsigned long *nss_dtls_cmn_ifmap_get(void) +-{ +- return dtls_cmn_pvt.if_map; +-} +- +-/* + * nss_dtls_cmn_tx_buf() + * Transmit buffer over DTLS interface. + */ +@@ -446,6 +519,5 @@ void nss_dtls_cmn_register_handler(void) + { + sema_init(&dtls_cmn_pvt.sem, 1); + init_completion(&dtls_cmn_pvt.complete); +- nss_dtls_cmn_stats_dentry_create(); +- nss_dtls_cmn_strings_dentry_create(); ++ nss_stats_create_dentry("dtls_cmn", &nss_dtls_cmn_stats_ops); + } +--- a/nss_dtls_cmn_log.c ++++ b/nss_dtls_cmn_log.c +@@ -1,12 +1,9 @@ + /* + ************************************************************************** + * Copyright (c) 2018, 2020, The Linux Foundation. All rights reserved. +- * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. +- * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +- * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +@@ -35,8 +32,7 @@ static int8_t *nss_dtls_cmn_log_message_ + "DTLS_CMN Switch DTLS Transform", + "DTLS_CMN Deconfigure Context", + "DTLS_CMN Synchronize Stats", +- "DTLS_CMN Node Statistics", +- "DTLS_CMN Update VP" ++ "DTLS_CMN Node Statistics" + }; + + /* +@@ -57,9 +53,7 @@ static int8_t *nss_dtls_cmn_log_error_re + "DTLS_CMN Switch Hardware Context Fail", + "DTLS_CMN Already Configured", + "DTLS_CMN No Memory", +- "DTLS_CMN Copy Nonce Failure", +- "DTLS_CMN Update VP Failure", +- "DTLS_CMN Destroy VP Failure" ++ "DTLS_CMN Copy Nonce Failure" + }; + + /* +--- a/nss_dtls_cmn_stats.c ++++ /dev/null +@@ -1,215 +0,0 @@ +-/* +- *************************************************************************** +- * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- *************************************************************************** +- */ +- +-#include "nss_core.h" +-#include "nss_dtls_cmn.h" +-#include "nss_dtls_cmn_stats.h" +-#include "nss_dtls_cmn_strings.h" +- +-/* +- * Declare atomic notifier data structure for statistics. +- */ +-ATOMIC_NOTIFIER_HEAD(nss_dtls_cmn_stats_notifier); +- +-/* +- * Spinlock to protect dtls common statistics update/read +- */ +-DEFINE_SPINLOCK(nss_dtls_cmn_stats_lock); +- +-unsigned long *nss_dtls_cmn_ifmap_get(void); +- +-/* +- * nss_dtls_cmn_ctx_stats +- * dtls common ctx statistics +- */ +-uint64_t nss_dtls_cmn_ctx_stats[NSS_MAX_NET_INTERFACES][NSS_DTLS_CMN_CTX_STATS_MAX]; +- +-/* +- * nss_dtls_cmn_stats_iface_type() +- * Return a string for each interface type. +- */ +-static const char *nss_dtls_cmn_stats_iface_type(enum nss_dynamic_interface_type type) +-{ +- switch (type) { +- case NSS_DYNAMIC_INTERFACE_TYPE_DTLS_CMN_INNER: +- return "dtls_cmn_inner"; +- +- case NSS_DYNAMIC_INTERFACE_TYPE_DTLS_CMN_OUTER: +- return "dtls_cmn_outer"; +- +- default: +- return "invalid_interface"; +- +- } +-} +- +-/* +- * nss_dtls_cmn_stats_read() +- * Read dtls common node statistics. +- */ +-static ssize_t nss_dtls_cmn_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- /* +- * Max output lines = #stats + +- * few blank lines for banner printing + Number of Extra outputlines +- * for future reference to add new stats +- */ +- uint32_t max_output_lines = NSS_DTLS_CMN_CTX_STATS_MAX + NSS_STATS_EXTRA_OUTPUT_LINES; +- size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines; +- struct nss_ctx_instance *nss_ctx = nss_dtls_cmn_get_context(); +- enum nss_dynamic_interface_type type; +- unsigned long *ifmap; +- uint64_t *stats_shadow; +- ssize_t bytes_read = 0; +- size_t size_wr = 0; +- uint32_t if_num; +- int32_t i; +- int count; +- char *lbuf; +- +- ifmap = nss_dtls_cmn_ifmap_get(); +- count = bitmap_weight(ifmap, NSS_MAX_NET_INTERFACES); +- if (count) { +- size_al = size_al * count; +- } +- +- lbuf = vzalloc(size_al); +- if (unlikely(!lbuf)) { +- nss_warning("Could not allocate memory for local statistics buffer"); +- return -ENOMEM; +- } +- +- stats_shadow = vzalloc(NSS_DTLS_CMN_CTX_STATS_MAX * 8); +- if (unlikely(!stats_shadow)) { +- nss_warning("Could not allocate memory for local shadow buffer"); +- vfree(lbuf); +- return -ENOMEM; +- } +- +- /* +- * Common node stats for each DTLS dynamic interface. +- */ +- size_wr += nss_stats_banner(lbuf, size_wr, size_al, "dtls_cmn stats", NSS_STATS_SINGLE_CORE); +- for_each_set_bit(if_num, ifmap, NSS_MAX_NET_INTERFACES) { +- +- type = nss_dynamic_interface_get_type(nss_ctx, if_num); +- if ((type != NSS_DYNAMIC_INTERFACE_TYPE_DTLS_CMN_INNER) && +- (type != NSS_DYNAMIC_INTERFACE_TYPE_DTLS_CMN_OUTER)) { +- continue; +- } +- +- spin_lock_bh(&nss_dtls_cmn_stats_lock); +- for (i = 0; i < NSS_DTLS_CMN_CTX_STATS_MAX; i++) { +- stats_shadow[i] = nss_dtls_cmn_ctx_stats[if_num][i]; +- } +- spin_unlock_bh(&nss_dtls_cmn_stats_lock); +- +- size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\n%s if_num:%03u\n", +- nss_dtls_cmn_stats_iface_type(type), if_num); +- size_wr += nss_stats_print("dtls_cmn", NULL, NSS_STATS_SINGLE_INSTANCE, nss_dtls_cmn_ctx_stats_str, +- stats_shadow, NSS_DTLS_CMN_CTX_STATS_MAX, lbuf, size_wr, size_al); +- } +- +- bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf)); +- vfree(lbuf); +- vfree(stats_shadow); +- +- return bytes_read; +-} +- +-/* +- * nss_dtls_cmn_stats_ops. +- */ +-NSS_STATS_DECLARE_FILE_OPERATIONS(dtls_cmn); +- +-/* +- * nss_dtls_cmn_stats_dentry_create() +- * Create dtls common statistics debug entry. +- */ +-void nss_dtls_cmn_stats_dentry_create(void) +-{ +- nss_stats_create_dentry("dtls_cmn", &nss_dtls_cmn_stats_ops); +-} +- +-/* +- * nss_dtls_cmn_stats_sync() +- * Update dtls common node statistics. +- */ +-void nss_dtls_cmn_stats_sync(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm) +-{ +- struct nss_dtls_cmn_msg *ndcm = (struct nss_dtls_cmn_msg *)ncm; +- struct nss_dtls_cmn_ctx_stats *ndccs = &ndcm->msg.stats; +- uint64_t *ctx_stats; +- uint32_t *msg_stats; +- uint16_t i = 0; +- +- spin_lock_bh(&nss_dtls_cmn_stats_lock); +- +- msg_stats = (uint32_t *)ndccs; +- ctx_stats = nss_dtls_cmn_ctx_stats[ncm->interface]; +- +- for (i = 0; i < NSS_DTLS_CMN_CTX_STATS_MAX; i++, ctx_stats++, msg_stats++) { +- *ctx_stats += *msg_stats; +- } +- +- spin_unlock_bh(&nss_dtls_cmn_stats_lock); +-} +- +-/* +- * nss_dtls_cmn_stats_notify() +- * Sends notifications to all the registered modules. +- * +- * Leverage NSS-FW statistics timing to update Netlink. +- */ +-void nss_dtls_cmn_stats_notify(struct nss_ctx_instance *nss_ctx, uint32_t if_num) +-{ +- struct nss_dtls_cmn_stats_notification *dtls_cmn_stats; +- +- dtls_cmn_stats = kmalloc(sizeof(struct nss_dtls_cmn_stats_notification), GFP_ATOMIC); +- if (!dtls_cmn_stats) { +- nss_warning("Unable to allocate memory for stats notification\n"); +- return; +- } +- +- spin_lock_bh(&nss_dtls_cmn_stats_lock); +- dtls_cmn_stats->core_id = nss_ctx->id; +- dtls_cmn_stats->if_num = if_num; +- memcpy(dtls_cmn_stats->stats_ctx, nss_dtls_cmn_ctx_stats[if_num], sizeof(dtls_cmn_stats->stats_ctx)); +- spin_unlock_bh(&nss_dtls_cmn_stats_lock); +- +- atomic_notifier_call_chain(&nss_dtls_cmn_stats_notifier, NSS_STATS_EVENT_NOTIFY, dtls_cmn_stats); +- kfree(dtls_cmn_stats); +-} +- +-/* +- * nss_dtls_cmn_stats_unregister_notifier() +- * Deregisters statistics notifier. +- */ +-int nss_dtls_cmn_stats_unregister_notifier(struct notifier_block *nb) +-{ +- return atomic_notifier_chain_unregister(&nss_dtls_cmn_stats_notifier, nb); +-} +-EXPORT_SYMBOL(nss_dtls_cmn_stats_unregister_notifier); +- +-/* +- * nss_dtls_cmn_stats_register_notifier() +- * Registers statistics notifier. +- */ +-int nss_dtls_cmn_stats_register_notifier(struct notifier_block *nb) +-{ +- return atomic_notifier_chain_register(&nss_dtls_cmn_stats_notifier, nb); +-} +-EXPORT_SYMBOL(nss_dtls_cmn_stats_register_notifier); +--- a/nss_dtls_cmn_stats.h ++++ /dev/null +@@ -1,26 +0,0 @@ +-/* +- **************************************************************************** +- * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- **************************************************************************** +- */ +- +-#ifndef __NSS_DTLS_CMN_STATS_H +-#define __NSS_DTLS_CMN_STATS_H +- +-#include +- +-extern void nss_dtls_cmn_stats_notify(struct nss_ctx_instance *nss_ctx, uint32_t if_num); +-extern void nss_dtls_cmn_stats_sync(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm); +-extern void nss_dtls_cmn_stats_dentry_create(void); +- +-#endif /* __NSS_DTLS_CMN_STATS_H */ +--- a/nss_dtls_cmn_strings.c ++++ /dev/null +@@ -1,128 +0,0 @@ +-/* +- **************************************************************************** +- * Copyright (c) 2020, The Linux Foundation. All rights reserved. +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- **************************************************************************** +- */ +- +-#include "nss_stats.h" +-#include "nss_core.h" +-#include "nss_strings.h" +-#include "nss_dtls_cmn_strings.h" +- +-/* +- * nss_dtls_cmn_ctx_stats_str +- * dtls common ctx statistics strings. +- */ +-struct nss_stats_info nss_dtls_cmn_ctx_stats_str[NSS_DTLS_CMN_CTX_STATS_MAX] = { +- {"rx_pkts", NSS_STATS_TYPE_COMMON}, +- {"rx_byts", NSS_STATS_TYPE_COMMON}, +- {"tx_pkts", NSS_STATS_TYPE_COMMON}, +- {"tx_byts", NSS_STATS_TYPE_COMMON}, +- {"rx_queue[0]_drops", NSS_STATS_TYPE_DROP}, +- {"rx_queue[1]_drops", NSS_STATS_TYPE_DROP}, +- {"rx_queue[2]_drops", NSS_STATS_TYPE_DROP}, +- {"rx_queue[3]_drops", NSS_STATS_TYPE_DROP}, +- {"rx_single_rec", NSS_STATS_TYPE_SPECIAL}, +- {"rx_multi_rec", NSS_STATS_TYPE_SPECIAL}, +- {"fail_crypto_resource", NSS_STATS_TYPE_DROP}, +- {"fail_crypto_enqueue", NSS_STATS_TYPE_DROP}, +- {"fail_headroom", NSS_STATS_TYPE_DROP}, +- {"fail_tailroom", NSS_STATS_TYPE_DROP}, +- {"fail_ver", NSS_STATS_TYPE_DROP}, +- {"fail_epoch", NSS_STATS_TYPE_DROP}, +- {"fail_dtls_record", NSS_STATS_TYPE_DROP}, +- {"fail_capwap", NSS_STATS_TYPE_DROP}, +- {"fail_replay", NSS_STATS_TYPE_DROP}, +- {"fail_replay_dup", NSS_STATS_TYPE_DROP}, +- {"fail_replay_win", NSS_STATS_TYPE_DROP}, +- {"fail_queue", NSS_STATS_TYPE_DROP}, +- {"fail_queue_nexthop", NSS_STATS_TYPE_DROP}, +- {"fail_pbuf_alloc", NSS_STATS_TYPE_DROP}, +- {"fail_pbuf_linear", NSS_STATS_TYPE_DROP}, +- {"fail_pbuf_stats", NSS_STATS_TYPE_DROP}, +- {"fail_pbuf_align", NSS_STATS_TYPE_DROP}, +- {"fail_ctx_active", NSS_STATS_TYPE_DROP}, +- {"fail_hwctx_active", NSS_STATS_TYPE_DROP}, +- {"fail_cipher", NSS_STATS_TYPE_EXCEPTION}, +- {"fail_auth", NSS_STATS_TYPE_EXCEPTION}, +- {"fail_seq_ovf", NSS_STATS_TYPE_DROP}, +- {"fail_blk_len", NSS_STATS_TYPE_DROP}, +- {"fail_hash_len", NSS_STATS_TYPE_DROP}, +- {"len_error", NSS_STATS_TYPE_DROP}, +- {"token_error", NSS_STATS_TYPE_DROP}, +- {"bypass_error", NSS_STATS_TYPE_DROP}, +- {"config_error", NSS_STATS_TYPE_DROP}, +- {"algo_error", NSS_STATS_TYPE_DROP}, +- {"hash_ovf_error", NSS_STATS_TYPE_DROP}, +- {"ttl_error", NSS_STATS_TYPE_DROP}, +- {"csum_error", NSS_STATS_TYPE_DROP}, +- {"timeout_error", NSS_STATS_TYPE_DROP}, +- {"fail_cle_[0]", NSS_STATS_TYPE_DROP}, +- {"fail_cle_[1]", NSS_STATS_TYPE_DROP}, +- {"fail_cle_[2]", NSS_STATS_TYPE_DROP}, +- {"fail_cle_[3]", NSS_STATS_TYPE_DROP}, +- {"fail_cle_[4]", NSS_STATS_TYPE_DROP}, +- {"fail_cle_[5]", NSS_STATS_TYPE_DROP}, +- {"fail_cle_[6]", NSS_STATS_TYPE_DROP}, +- {"fail_cle_[7]", NSS_STATS_TYPE_DROP}, +- {"fail_cle_[8]", NSS_STATS_TYPE_DROP}, +- {"fail_cle_[9]", NSS_STATS_TYPE_DROP}, +- {"fail_cle_[10]", NSS_STATS_TYPE_DROP}, +- {"fail_cle_[11]", NSS_STATS_TYPE_DROP}, +- {"fail_cle_[12]", NSS_STATS_TYPE_DROP}, +- {"fail_cle_[13]", NSS_STATS_TYPE_DROP}, +- {"fail_cle_[14]", NSS_STATS_TYPE_DROP}, +- {"fail_cle_[15]", NSS_STATS_TYPE_DROP}, +- {"fail_cle_[16]", NSS_STATS_TYPE_DROP}, +- {"fail_cle_[17]", NSS_STATS_TYPE_DROP}, +- {"fail_cle_[18]", NSS_STATS_TYPE_DROP}, +- {"fail_cle_[19]", NSS_STATS_TYPE_DROP}, +- {"fail_cle_[20]", NSS_STATS_TYPE_DROP}, +- {"fail_cle_[21]", NSS_STATS_TYPE_DROP}, +- {"fail_cle_[22]", NSS_STATS_TYPE_DROP}, +- {"fail_cle_[23]", NSS_STATS_TYPE_DROP}, +- {"fail_cle_[24]", NSS_STATS_TYPE_DROP}, +- {"fail_cle_[25]", NSS_STATS_TYPE_DROP}, +- {"fail_cle_[26]", NSS_STATS_TYPE_DROP}, +- {"fail_cle_[27]", NSS_STATS_TYPE_DROP}, +- {"fail_cle_[28]", NSS_STATS_TYPE_DROP}, +- {"fail_cle_[29]", NSS_STATS_TYPE_DROP}, +- {"fail_cle_[30]", NSS_STATS_TYPE_DROP}, +- {"fail_cle_[31]", NSS_STATS_TYPE_DROP}, +- {"seq_low", NSS_STATS_TYPE_SPECIAL}, +- {"seq_high", NSS_STATS_TYPE_SPECIAL}, +- {"epoch", NSS_STATS_TYPE_SPECIAL} +-}; +- +-/* +- * nss_dtls_cmn_ctx_stats_str_strings_read() +- * Read dtls common ctx statistics names +- */ +-static ssize_t nss_dtls_cmn_ctx_stats_str_strings_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- return nss_strings_print(ubuf, sz, ppos, nss_dtls_cmn_ctx_stats_str, NSS_DTLS_CMN_CTX_STATS_MAX); +-} +- +-/* +- * nss_dtls_cmn_ctx_stats_str_strings_ops +- */ +-NSS_STRINGS_DECLARE_FILE_OPERATIONS(dtls_cmn_ctx_stats_str); +- +-/* +- * nss_dtls_cmn_strings_dentry_create() +- * Create dtls common statistics strings debug entry. +- */ +-void nss_dtls_cmn_strings_dentry_create(void) +-{ +- nss_strings_create_dentry("dtls_cmn_ctx_stats_str", &nss_dtls_cmn_ctx_stats_str_strings_ops); +-} +--- a/nss_dtls_cmn_strings.h ++++ /dev/null +@@ -1,25 +0,0 @@ +-/* +- **************************************************************************** +- * Copyright (c) 2020, The Linux Foundation. All rights reserved. +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- **************************************************************************** +- */ +- +-#ifndef __NSS_DTLS_CMN_STRINGS_H +-#define __NSS_DTLS_CMN_STRINGS_H +- +-#include "nss_dtls_cmn_stats.h" +- +-extern struct nss_stats_info nss_dtls_cmn_ctx_stats_str[NSS_DTLS_CMN_CTX_STATS_MAX]; +-extern void nss_dtls_cmn_strings_dentry_create(void); +- +-#endif /* __NSS_DTLS_CMN_STRINGS_H */ +--- a/nss_dynamic_interface_stats.c ++++ b/nss_dynamic_interface_stats.c +@@ -26,10 +26,10 @@ + const char *nss_dynamic_interface_type_names[NSS_DYNAMIC_INTERFACE_TYPE_MAX] = { + "NSS_DYNAMIC_INTERFACE_TYPE_NONE", + "NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR", +- "NSS_DYNAMIC_INTERFACE_TYPE_RESERVED_5", ++ "NSS_DYNAMIC_INTERFACE_TYPE_CAPWAP", + "NSS_DYNAMIC_INTERFACE_TYPE_TUNIPIP6_INNER", + "NSS_DYNAMIC_INTERFACE_TYPE_TUNIPIP6_OUTER", +- "NSS_DYNAMIC_INTERFACE_TYPE_RESERVED", ++ "NSS_DYNAMIC_INTERFACE_TYPE_WIFI", + "NSS_DYNAMIC_INTERFACE_TYPE_VAP", + "NSS_DYNAMIC_INTERFACE_TYPE_RESERVED_0", + "NSS_DYNAMIC_INTERFACE_TYPE_PPPOE", +@@ -43,7 +43,11 @@ const char *nss_dynamic_interface_type_n + "NSS_DYNAMIC_INTERFACE_TYPE_BRIDGE", + "NSS_DYNAMIC_INTERFACE_TYPE_VLAN", + "NSS_DYNAMIC_INTERFACE_TYPE_RESERVED_3", ++#if (NSS_FW_VERSION_CODE <= NSS_FW_VERSION(11,0)) ++ "NSS_DYNAMIC_INTERFACE_TYPE_WIFILI", ++#else + "NSS_DYNAMIC_INTERFACE_TYPE_WIFILI_INTERNAL", ++#endif + "NSS_DYNAMIC_INTERFACE_TYPE_MAP_T_INNER", + "NSS_DYNAMIC_INTERFACE_TYPE_MAP_T_OUTER", + "NSS_DYNAMIC_INTERFACE_TYPE_GRE_TUNNEL_INNER", +@@ -80,15 +84,22 @@ const char *nss_dynamic_interface_type_n + "NSS_DYNAMIC_INTERFACE_TYPE_IGS", + "NSS_DYNAMIC_INTERFACE_TYPE_CLMAP_US", + "NSS_DYNAMIC_INTERFACE_TYPE_CLMAP_DS", ++#if (NSS_FW_VERSION_CODE > NSS_FW_VERSION(11,0)) + "NSS_DYNAMIC_INTERFACE_TYPE_VXLAN_INNER", + "NSS_DYNAMIC_INTERFACE_TYPE_VXLAN_OUTER", + "NSS_DYNAMIC_INTERFACE_TYPE_MATCH", ++#endif + "NSS_DYNAMIC_INTERFACE_TYPE_RMNET_RX_N2H", + "NSS_DYNAMIC_INTERFACE_TYPE_RMNET_RX_H2N", ++#if (NSS_FW_VERSION_CODE > NSS_FW_VERSION(11,0)) + "NSS_DYNAMIC_INTERFACE_TYPE_WIFILI_EXTERNAL0", + "NSS_DYNAMIC_INTERFACE_TYPE_WIFILI_EXTERNAL1", +- "NSS_DYNAMIC_INTERFACE_TYPE_CAPWAP_HOST_INNER", +- "NSS_DYNAMIC_INTERFACE_TYPE_CAPWAP_OUTER", ++#endif ++#if (NSS_FW_VERSION_CODE > NSS_FW_VERSION(11,1)) ++ "NSS_DYNAMIC_INTERFACE_TYPE_TLS_INNER", ++ "NSS_DYNAMIC_INTERFACE_TYPE_TLS_OUTER", ++ "NSS_DYNAMIC_INTERFACE_TYPE_MIRROR", ++#endif + }; + + /* +--- a/nss_edma_lite.c ++++ /dev/null +@@ -1,243 +0,0 @@ +-/* +- * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for any +- * purpose with or without fee is hereby granted, provided that the above +- * copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- */ +- +-/* +- * nss_edma_lite.c +- * NSS EDMA APIs +- */ +-#include "nss_edma_lite_stats.h" +-#include "nss_edma_lite_strings.h" +-#include +- +-/* +- ********************************** +- Rx APIs +- ********************************** +- */ +-static bool is_map_configured = false; +- +-/* +- * nss_edma_lite_interface_handler() +- * Handle NSS -> HLOS messages for EDMA node +- */ +-static void nss_edma_lite_interface_handler(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm, __attribute__((unused))void *app_data) +-{ +- struct nss_edma_lite_msg *nelm = (struct nss_edma_lite_msg *)ncm; +- nss_edma_lite_msg_callback_t cb; +- +- /* +- * Is this a valid request/response packet? +- */ +- if (nelm->cm.type >= NSS_EDMA_LITE_MSG_TYPE_MAX) { +- nss_warning("%px: received invalid message %d for edma_lite interface", nss_ctx, nelm->cm.type); +- return; +- } +- +- /* +- * Handle different types of messages +- */ +- switch (nelm->cm.type) { +- case NSS_EDMA_LITE_MSG_NODE_STATS_SYNC: +- nss_edma_lite_node_stats_sync(nss_ctx, &nelm->msg.node_stats); +- break; +- case NSS_EDMA_LITE_MSG_RING_STATS_SYNC: +- nss_edma_lite_ring_stats_sync(nss_ctx, &nelm->msg.ring_stats); +- break; +- case NSS_EDMA_LITE_MSG_ERR_STATS_SYNC: +- nss_edma_lite_err_stats_sync(nss_ctx, &nelm->msg.err_stats); +- break; +- default: +- if (ncm->response != NSS_CMN_RESPONSE_ACK) { +- /* +- * Check response +- */ +- nss_info("%px: Received response %d for type %d, interface %d", +- nss_ctx, ncm->response, ncm->type, ncm->interface); +- } +- } +- +- /* +- * Update the callback and app_data for NOTIFY messages, edma_lite sends all notify messages +- * to the same callback/app_data. +- */ +- if (nelm->cm.response == NSS_CMN_RESPONSE_NOTIFY) { +- ncm->cb = (nss_ptr_t)nss_ctx->edma_lite_callback; +- ncm->app_data = (nss_ptr_t)nss_ctx->edma_lite_ctx; +- } +- +- /* +- * Do we have a callback? +- */ +- if (!ncm->cb) { +- return; +- } +- +- /* +- * Callback +- */ +- cb = (nss_edma_lite_msg_callback_t)ncm->cb; +- cb((void *)ncm->app_data, nelm); +-} +- +-/* +- * nss_edma_lite_msg_cfg_map_callback() +- */ +-static void nss_edma_lite_msg_cfg_map_callback(void *app_data, struct nss_edma_lite_msg *nelm) +-{ +- struct nss_ctx_instance *nss_ctx __attribute__((unused)) = (struct nss_ctx_instance *)app_data; +- if (nelm->cm.response != NSS_CMN_RESPONSE_ACK) { +- nss_warning("%px: nss edma_lite_map configuration failed: %d for NSS core %d\n", +- nss_ctx, nelm->cm.error, nss_ctx->id); +- return; +- } +- +- /* TODO: SHould we protect this with some lock */ +- if (nelm->cm.type == NSS_EDMA_LITE_MSG_TYPE_RING_MAP) { +- is_map_configured = true; +- } +- +- nss_info("%px: nss edma_lite_map configuration succeeded for NSS core %d\n", nss_ctx, nss_ctx->id); +-} +- +-/* +- * nss_edma_lite_tx_msg() +- * Transmit an EDMA lite config message to the FW with a specified size. +- */ +-nss_tx_status_t nss_edma_lite_tx_msg(struct nss_ctx_instance *nss_ctx, struct nss_edma_lite_msg *nelm) +-{ +- struct nss_cmn_msg *ncm = &nelm->cm; +- +- if (ncm->type >= NSS_EDMA_LITE_MSG_TYPE_MAX) { +- nss_warning("%px: message type out of range: %d", nss_ctx, ncm->type); +- return NSS_TX_FAILURE; +- } +- +- return nss_core_send_cmd(nss_ctx, nelm, sizeof(*nelm), NSS_NBUF_PAYLOAD_SIZE); +-} +-EXPORT_SYMBOL(nss_edma_lite_tx_msg); +- +-bool nss_edma_lite_is_configured(void) +-{ +- return is_map_configured; +-} +-EXPORT_SYMBOL(nss_edma_lite_is_configured); +- +-/* +- * nss_edma_lite_msg_cfg_map() +- * Send ring number to EDMA lite. +- */ +-nss_tx_status_t nss_edma_lite_msg_cfg_map(struct nss_ctx_instance *nss_ctx) +-{ +- int32_t status; +- struct nss_edma_lite_msg nelm; +- struct nss_edma_lite_ring_map *cfg_map; +- uint32_t txdesc_num, txcmpl_num, rxfill_num, rxdesc_num; +- +- nss_edma_lite_msg_init(&nelm, NSS_EDMA_LITE_INTERFACE, NSS_EDMA_LITE_MSG_TYPE_RING_MAP, +- sizeof(struct nss_edma_lite_ring_map), nss_edma_lite_msg_cfg_map_callback, (void *)nss_ctx); +- +- /* +- * Invoke DP API to get point offload information +- */ +- nss_dp_point_offload_info_get(&txdesc_num, &txcmpl_num, &rxfill_num, &rxdesc_num); +- +- cfg_map = &nelm.msg.map; +- cfg_map->txdesc_num = txdesc_num; +- cfg_map->txcmpl_num = txcmpl_num; +- cfg_map->rxfill_num = rxfill_num; +- cfg_map->rxdesc_num = rxdesc_num; +- +- status = nss_edma_lite_tx_msg(nss_ctx, &nelm); +- if (unlikely(status != NSS_TX_SUCCESS)) { +- return status; +- } +- +- return NSS_TX_SUCCESS; +-} +- +-/* +- * nss_edma_lite_msg_init() +- * Initialize EDMA LITE message. +- */ +-void nss_edma_lite_msg_init(struct nss_edma_lite_msg *nelm, uint16_t if_num, uint32_t type, uint32_t len, +- nss_edma_lite_msg_callback_t cb, void *app_data) +-{ +- nss_cmn_msg_init(&nelm->cm, if_num, type, len, (void *)cb, app_data); +-} +-EXPORT_SYMBOL(nss_edma_lite_msg_init); +- +-/* +- * nss_edma_lite_notify_register() +- * Register to received EDMA events. +- */ +-void nss_edma_lite_notify_register(nss_edma_lite_msg_callback_t cb, void *app_data) +-{ +- struct nss_ctx_instance *nss_ctx; +- int i = 0; +- +- for (i = 0; i < NSS_MAX_CORES; i++) { +- int id = nss_top_main.edma_lite_handler_id[i]; +- if (id >= 0) { +- nss_ctx = &nss_top_main.nss[id]; +- nss_ctx->edma_lite_callback = cb; +- nss_ctx->edma_lite_ctx = app_data; +- } +- } +-} +-EXPORT_SYMBOL(nss_edma_lite_notify_register); +- +-/* +- * nss_edma_lite_notify_unregister() +- * Unregister to received EDMA events. +- */ +-void nss_edma_lite_notify_unregister(void) +-{ +- struct nss_ctx_instance *nss_ctx; +- int i = 0; +- +- for (i = 0; i < NSS_MAX_CORES; i++) { +- int id = nss_top_main.edma_lite_handler_id[i]; +- if (id >= 0) { +- nss_ctx = &nss_top_main.nss[id]; +- nss_ctx->edma_lite_callback = NULL; +- } +- } +-} +-EXPORT_SYMBOL(nss_edma_lite_notify_unregister); +- +-/* +- * nss_edma_lite_enabled() +- */ +-bool nss_edma_lite_enabled(struct nss_ctx_instance *nss_ctx) +-{ +- int id = nss_top_main.edma_lite_handler_id[nss_ctx->id]; +- if (id == nss_ctx->id) +- return true; +- +- return false; +-} +-EXPORT_SYMBOL(nss_edma_lite_enabled); +- +-/* +- * nss_edma_lite_register_handler() +- */ +-void nss_edma_lite_register_handler(struct nss_ctx_instance *nss_ctx) +-{ +- nss_core_register_handler(nss_ctx, NSS_EDMA_LITE_INTERFACE, nss_edma_lite_interface_handler, NULL); +- +- nss_edma_lite_stats_dentry_create(); +- nss_edma_lite_strings_dentry_create(); +-} +--- a/nss_edma_lite_stats.c ++++ /dev/null +@@ -1,579 +0,0 @@ +-/* +- * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for any +- * purpose with or without fee is hereby granted, provided that the above +- * copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- */ +- +-/* +- * nss_edma_lite_stats.c +- * NSS EDMA statistics APIs +- */ +- +-#include "nss_edma_lite_stats.h" +-#include "nss_edma_lite_strings.h" +- +-/* +- * Declare atomic notifier data structure for statistics. +- */ +-ATOMIC_NOTIFIER_HEAD(nss_edma_lite_stats_notifier); +- +-struct nss_edma_lite_stats edma_stats; +- +-/* +- ********************************** +- EDMA statistics APIs +- ********************************** +- */ +- +-/* +- * nss_edma_lite_node_stats_read() +- * Read EDMA node stats +- */ +-static ssize_t nss_edma_lite_node_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- int32_t i; +- +- /* +- * max output lines = #stats + start tag line + end tag line + three blank lines +- */ +- uint32_t max_output_lines = (NSS_STATS_NODE_MAX + 2) + 3; +- size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines; +- size_t size_wr = 0; +- ssize_t bytes_read = 0; +- uint64_t *stats_shadow; +- +- char *lbuf = kzalloc(size_al, GFP_KERNEL); +- if (unlikely(lbuf == NULL)) { +- nss_warning("Could not allocate memory for local statistics buffer"); +- return 0; +- } +- +- stats_shadow = kzalloc(NSS_STATS_NODE_MAX * sizeof(uint64_t), GFP_KERNEL); +- if (unlikely(stats_shadow == NULL)) { +- nss_warning("Could not allocate memory for local shadow buffer"); +- kfree(lbuf); +- return 0; +- } +- +- size_wr += nss_stats_banner(lbuf, size_wr, size_al, "edma", NSS_STATS_SINGLE_CORE); +- +- /* +- * Common node stats +- */ +- size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "Node stats:\n\n"); +- spin_lock_bh(&nss_top_main.stats_lock); +- +- for (i = 0; (i < NSS_STATS_NODE_MAX); i++) +- stats_shadow[i] = edma_stats.node_stats[i]; +- +- spin_unlock_bh(&nss_top_main.stats_lock); +- size_wr += nss_stats_print("edma_node", NULL, NSS_STATS_SINGLE_INSTANCE +- , nss_edma_lite_strings_stats_node +- , stats_shadow +- , NSS_STATS_NODE_MAX +- , lbuf, size_wr, size_al); +- bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf)); +- kfree(lbuf); +- kfree(stats_shadow); +- +- return bytes_read; +-} +- +-/* +- * nss_edma_lite_txring_stats_read() +- * Read EDMA Tx ring stats +- */ +-static ssize_t nss_edma_lite_txring_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- int32_t i = 0; +- +- /* +- * max output lines = #stats + start tag line + end tag line + three blank lines +- */ +- uint32_t max_output_lines = (NSS_EDMA_LITE_STATS_TX_MAX + 2) + 3; +- size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines; +- size_t size_wr = 0; +- ssize_t bytes_read = 0; +- uint64_t *stats_shadow; +- +- char *lbuf = kzalloc(size_al, GFP_KERNEL); +- if (unlikely(lbuf == NULL)) { +- nss_warning("Could not allocate memory for local statistics buffer"); +- return 0; +- } +- +- stats_shadow = kzalloc(NSS_EDMA_LITE_STATS_TX_MAX * sizeof(uint64_t), GFP_KERNEL); +- if (unlikely(stats_shadow == NULL)) { +- nss_warning("Could not allocate memory for local shadow buffer"); +- kfree(lbuf); +- return 0; +- } +- +- size_wr = scnprintf(lbuf, size_al, "edma Tx ring stats start:\n\n"); +- +- /* +- * Tx ring stats +- */ +- size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "Tx ring stats:\n\n"); +- spin_lock_bh(&nss_top_main.stats_lock); +- for (i = 0; (i < NSS_EDMA_LITE_STATS_TX_MAX); i++) +- stats_shadow[i] = edma_stats.tx_stats[i]; +- +- spin_unlock_bh(&nss_top_main.stats_lock); +- +- size_wr += nss_stats_print("edma_tx_ring", NULL, NSS_STATS_SINGLE_INSTANCE +- , nss_edma_lite_strings_stats_tx +- , stats_shadow +- , NSS_EDMA_LITE_STATS_TX_MAX +- , lbuf, size_wr, size_al); +- bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf)); +- kfree(lbuf); +- kfree(stats_shadow); +- +- return bytes_read; +-} +- +-/* +- * nss_edma_lite_rxring_stats_read() +- * Read EDMA rxring stats +- */ +-static ssize_t nss_edma_lite_rxring_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- int32_t i= 0; +- +- /* +- * max output lines = #stats + start tag line + end tag line + three blank lines +- */ +- uint32_t max_output_lines = (NSS_EDMA_LITE_STATS_RX_MAX + 2) + 3; +- size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines; +- size_t size_wr = 0; +- ssize_t bytes_read = 0; +- uint64_t *stats_shadow; +- +- char *lbuf = kzalloc(size_al, GFP_KERNEL); +- if (unlikely(lbuf == NULL)) { +- nss_warning("Could not allocate memory for local statistics buffer"); +- return 0; +- } +- +- stats_shadow = kzalloc(NSS_EDMA_LITE_STATS_RX_MAX * sizeof(uint64_t), GFP_KERNEL); +- if (unlikely(stats_shadow == NULL)) { +- nss_warning("Could not allocate memory for local shadow buffer"); +- kfree(lbuf); +- return 0; +- } +- +- /* +- * RX ring stats +- */ +- spin_lock_bh(&nss_top_main.stats_lock); +- for (i = 0; (i < NSS_EDMA_LITE_STATS_RX_MAX); i++) +- stats_shadow[i] = edma_stats.rx_stats[i]; +- +- spin_unlock_bh(&nss_top_main.stats_lock); +- size_wr += nss_stats_print("edma_rx_ring", NULL, NSS_STATS_SINGLE_INSTANCE +- , nss_edma_lite_strings_stats_rx +- , stats_shadow +- , NSS_EDMA_LITE_STATS_RX_MAX +- , lbuf, size_wr, size_al); +- bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf)); +- kfree(lbuf); +- kfree(stats_shadow); +- +- return bytes_read; +-} +- +-/* +- * nss_edma_lite_txcmplring_stats_read() +- * Read EDMA txcmplring stats +- */ +-static ssize_t nss_edma_lite_txcmplring_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- int32_t i = 0; +- +- /* +- * max output lines = #stats + start tag line + end tag line + three blank lines +- */ +- uint32_t max_output_lines = (NSS_EDMA_LITE_STATS_TXCMPL_MAX + 2) + 3; +- size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines; +- size_t size_wr = 0; +- ssize_t bytes_read = 0; +- uint64_t *stats_shadow; +- +- char *lbuf = kzalloc(size_al, GFP_KERNEL); +- if (unlikely(lbuf == NULL)) { +- nss_warning("Could not allocate memory for local statistics buffer"); +- return 0; +- } +- +- stats_shadow = kzalloc(NSS_EDMA_LITE_STATS_TXCMPL_MAX * sizeof(uint64_t), GFP_KERNEL); +- if (unlikely(stats_shadow == NULL)) { +- nss_warning("Could not allocate memory for local shadow buffer"); +- kfree(lbuf); +- return 0; +- } +- +- size_wr = scnprintf(lbuf, size_al, "edma Tx cmpl ring stats start:\n\n"); +- +- /* +- * Tx cmpl ring stats +- */ +- size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "Tx cmpl ring stats:\n\n"); +- spin_lock_bh(&nss_top_main.stats_lock); +- for (i = 0; (i < NSS_EDMA_LITE_STATS_TXCMPL_MAX); i++) +- stats_shadow[i] = edma_stats.txcmpl_stats[i]; +- +- spin_unlock_bh(&nss_top_main.stats_lock); +- size_wr += nss_stats_print("edma_tx_cmpl_ring", NULL, NSS_STATS_SINGLE_INSTANCE +- , nss_edma_lite_strings_stats_txcmpl +- , stats_shadow +- , NSS_EDMA_LITE_STATS_TXCMPL_MAX +- , lbuf, size_wr, size_al); +- size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\nedma Tx cmpl ring stats end\n\n"); +- bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf)); +- kfree(lbuf); +- kfree(stats_shadow); +- +- return bytes_read; +-} +- +-/* +- * nss_edma_lite_rxfillring_stats_read() +- * Read EDMA rxfillring stats +- */ +-static ssize_t nss_edma_lite_rxfillring_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- int32_t i = 0; +- +- /* +- * max output lines = #stats + start tag line + end tag line + three blank lines +- */ +- uint32_t max_output_lines = (NSS_EDMA_LITE_STATS_RXFILL_MAX + 2) + 3; +- size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines; +- size_t size_wr = 0; +- ssize_t bytes_read = 0; +- uint64_t *stats_shadow; +- +- char *lbuf = kzalloc(size_al, GFP_KERNEL); +- if (unlikely(lbuf == NULL)) { +- nss_warning("Could not allocate memory for local statistics buffer"); +- return 0; +- } +- +- stats_shadow = kzalloc(NSS_EDMA_LITE_STATS_RXFILL_MAX * sizeof(uint64_t), GFP_KERNEL); +- if (unlikely(stats_shadow == NULL)) { +- nss_warning("Could not allocate memory for local shadow buffer"); +- kfree(lbuf); +- return 0; +- } +- +- size_wr = scnprintf(lbuf, size_al, "edma Rx fill ring stats start:\n\n"); +- +- /* +- * Rx fill ring stats +- */ +- size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "Rx fill ring stats:\n\n"); +- spin_lock_bh(&nss_top_main.stats_lock); +- for (i = 0; i < NSS_EDMA_LITE_STATS_RXFILL_MAX; i++) { +- stats_shadow[i] = edma_stats.rxfill_stats[i]; +- } +- +- spin_unlock_bh(&nss_top_main.stats_lock); +- size_wr += nss_stats_print("edma_rx_fill_ring", NULL +- , NSS_STATS_SINGLE_INSTANCE +- , nss_edma_lite_strings_stats_rxfill +- , stats_shadow +- , NSS_EDMA_LITE_STATS_RXFILL_MAX +- , lbuf, size_wr, size_al); +- bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf)); +- kfree(lbuf); +- kfree(stats_shadow); +- +- return bytes_read; +-} +- +-/* +- * nss_edma_lite_err_stats_read() +- * Read EDMA err stats +- */ +-static ssize_t nss_edma_lite_err_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- int32_t i; +- +- /* +- * max output lines = #stats + start tag line + end tag line + three blank lines +- */ +- uint32_t max_output_lines = (NSS_EDMA_LITE_ERR_STATS_MAX + 2) + 3; +- size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines; +- size_t size_wr = 0; +- ssize_t bytes_read = 0; +- uint64_t *stats_shadow; +- +- char *lbuf = kzalloc(size_al, GFP_KERNEL); +- if (unlikely(lbuf == NULL)) { +- nss_warning("Could not allocate memory for local statistics buffer"); +- return 0; +- } +- +- stats_shadow = kzalloc(NSS_EDMA_LITE_ERR_STATS_MAX * sizeof(uint64_t), GFP_KERNEL); +- if (unlikely(stats_shadow == NULL)) { +- nss_warning("Could not allocate memory for local shadow buffer"); +- kfree(lbuf); +- return 0; +- } +- +- size_wr = scnprintf(lbuf, size_al, "edma error stats start:\n\n"); +- +- /* +- * Common node stats +- */ +- spin_lock_bh(&nss_top_main.stats_lock); +- +- for (i = 0; (i < NSS_EDMA_LITE_ERR_STATS_MAX); i++) +- stats_shadow[i] = edma_stats.err[i]; +- +- spin_unlock_bh(&nss_top_main.stats_lock); +- size_wr += nss_stats_print("edma_err", NULL, NSS_STATS_SINGLE_INSTANCE +- , nss_edma_lite_strings_stats_err_map +- , stats_shadow +- , NSS_EDMA_LITE_ERR_STATS_MAX +- , lbuf, size_wr, size_al); +- bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf)); +- kfree(lbuf); +- kfree(stats_shadow); +- +- return bytes_read; +-} +- +-/* +- * edma_node_stats_ops +- */ +-NSS_STATS_DECLARE_FILE_OPERATIONS(edma_lite_node); +- +-/* +- * edma_txring_stats_ops +- */ +-NSS_STATS_DECLARE_FILE_OPERATIONS(edma_lite_txring); +- +-/* +- * edma_rxring_stats_ops +- */ +-NSS_STATS_DECLARE_FILE_OPERATIONS(edma_lite_rxring); +- +-/* +- * edma_txcmplring_stats_ops +- */ +-NSS_STATS_DECLARE_FILE_OPERATIONS(edma_lite_txcmplring); +- +-/* +- * edma_rxfillring_stats_ops +- */ +-NSS_STATS_DECLARE_FILE_OPERATIONS(edma_lite_rxfillring); +- +-/* +- * edma_err_stats_ops +- */ +-NSS_STATS_DECLARE_FILE_OPERATIONS(edma_lite_err); +- +-/* +- * nss_edma_lite_stats_dentry_create() +- * Create edma statistics debug entry. +- */ +-void nss_edma_lite_stats_dentry_create(void) +-{ +- struct dentry *edma_d = NULL; +- struct dentry *edma_rings_dir_d = NULL; +- struct dentry *edma_tx_d = NULL; +- struct dentry *edma_rx_d = NULL; +- struct dentry *edma_txcmpl_d = NULL; +- struct dentry *edma_rxfill_d = NULL; +- struct dentry *edma_err_stats_d = NULL; +- struct dentry *edma_node_stats_d = NULL; +- +- edma_d = debugfs_create_dir("edma_lite", nss_top_main.stats_dentry); +- if (unlikely(edma_d == NULL)) { +- nss_warning("Failed to create qca-nss-drv/stats/edma directory"); +- return; +- } +- +- /* +- * edma node stats +- */ +- edma_node_stats_d = debugfs_create_file("node_stats", 0400, edma_d, &nss_top_main, &nss_edma_lite_node_stats_ops); +- if (unlikely(edma_node_stats_d == NULL)) { +- nss_warning("Failed to create qca-nss-drv/stats/edma/node_stats file"); +- return; +- } +- +- /* +- * edma error stats +- */ +- edma_err_stats_d = debugfs_create_file("err_stats", 0400, edma_d, &nss_top_main, &nss_edma_lite_err_stats_ops); +- if (unlikely(edma_err_stats_d == NULL)) { +- nss_warning("Failed to create qca-nss-drv/stats/edma/err_stats file"); +- return; +- } +- +- /* +- * edma ring stats +- */ +- edma_rings_dir_d = debugfs_create_dir("rings", edma_d); +- if (unlikely(edma_rings_dir_d == NULL)) { +- nss_warning("Failed to create qca-nss-drv/stats/edma/rings directory"); +- return; +- } +- +- /* +- * edma tx ring stats +- */ +- edma_tx_d = debugfs_create_file("tx", 0400, edma_rings_dir_d, &nss_top_main, &nss_edma_lite_txring_stats_ops); +- if (unlikely(edma_tx_d == NULL)) { +- nss_warning("Failed to create qca-nss-drv/stats/edma/rings/tx file"); +- return; +- } +- +- /* +- * edma rx ring stats +- */ +- edma_rx_d = debugfs_create_file("rx", 0400, edma_rings_dir_d, &nss_top_main, &nss_edma_lite_rxring_stats_ops); +- if (unlikely(edma_rx_d == NULL)) { +- nss_warning("Failed to create qca-nss-drv/stats/edma/rings/rx file"); +- return; +- } +- +- /* +- * edma tx cmpl ring stats +- */ +- edma_txcmpl_d = debugfs_create_file("txcmpl", 0400, edma_rings_dir_d, &nss_top_main, &nss_edma_lite_txcmplring_stats_ops); +- if (unlikely(edma_txcmpl_d == NULL)) { +- nss_warning("Failed to create qca-nss-drv/stats/edma/rings/txcmpl file"); +- return; +- } +- +- /* +- * edma rx fill ring stats +- */ +- edma_rxfill_d = debugfs_create_file("rxfill", 0400, edma_rings_dir_d, &nss_top_main, &nss_edma_lite_rxfillring_stats_ops); +- if (unlikely(edma_rxfill_d == NULL)) { +- nss_warning("Failed to create qca-nss-drv/stats/edma/rings/rxfill file"); +- return; +- } +-} +- +-/* +- * nss_edma_lite_node_stats_sync() +- * Handle the syncing of EDMA node statistics. +- */ +-void nss_edma_lite_node_stats_sync(struct nss_ctx_instance *nss_ctx, struct nss_edma_lite_node_stats_sync *nerss) +-{ +- int32_t i; +- struct nss_top_instance *nss_top = nss_ctx->nss_top; +- +- spin_lock_bh(&nss_top->stats_lock); +- +- /* +- * edma node stats +- */ +- edma_stats.node_stats[NSS_STATS_NODE_RX_PKTS] += nerss->node_stats.rx_packets; +- edma_stats.node_stats[NSS_STATS_NODE_RX_BYTES] += nerss->node_stats.rx_bytes; +- edma_stats.node_stats[NSS_STATS_NODE_TX_PKTS] += nerss->node_stats.tx_packets; +- edma_stats.node_stats[NSS_STATS_NODE_TX_BYTES] += nerss->node_stats.tx_bytes; +- +- for (i = 0; i < NSS_MAX_NUM_PRI; i++) { +- edma_stats.node_stats[NSS_STATS_NODE_RX_QUEUE_0_DROPPED + i] += nerss->node_stats.rx_dropped[i]; +- } +- +- spin_unlock_bh(&nss_top->stats_lock); +-} +- +-/* +- * nss_edma_lite_ring_stats_sync() +- * Handle the syncing of EDMA ring statistics. +- */ +-void nss_edma_lite_ring_stats_sync(struct nss_ctx_instance *nss_ctx, struct nss_edma_lite_ring_stats_sync *nerss) +-{ +- struct nss_top_instance *nss_top = nss_ctx->nss_top; +- +- spin_lock_bh(&nss_top->stats_lock); +- +- /* +- * edma tx ring stats +- */ +- edma_stats.tx_stats[NSS_EDMA_LITE_STATS_TX_ERR] += nerss->tx_ring.tx_err; +- edma_stats.tx_stats[NSS_EDMA_LITE_STATS_TX_DROPPED] += nerss->tx_ring.tx_dropped; +- edma_stats.tx_stats[NSS_EDMA_LITE_STATS_TX_DESC] += nerss->tx_ring.desc_cnt; +- +- /* +- * edma rx ring stats +- */ +- edma_stats.rx_stats[NSS_EDMA_LITE_STATS_RX_DESC] += nerss->rx_ring.desc_cnt; +- +- /* +- * edma tx cmpl ring stats +- */ +- edma_stats.txcmpl_stats[NSS_EDMA_LITE_STATS_TXCMPL_DESC] += nerss->txcmpl_ring.desc_cnt; +- +- /* +- * edma rx fill ring stats +- */ +- edma_stats.rxfill_stats[NSS_EDMA_LITE_STATS_RXFILL_DESC] += nerss->rxfill_ring.desc_cnt; +- +- spin_unlock_bh(&nss_top->stats_lock); +-} +- +-/* +- * nss_edma_lite_err_stats_sync() +- * Handle the syncing of EDMA error statistics. +- */ +-void nss_edma_lite_err_stats_sync(struct nss_ctx_instance *nss_ctx, struct nss_edma_lite_err_stats_sync *nerss) +-{ +- +- struct nss_top_instance *nss_top = nss_ctx->nss_top; +- +- spin_lock_bh(&nss_top->stats_lock); +- edma_stats.err[NSS_EDMA_LITE_ALLOC_FAIL_CNT] += nerss->alloc_fail_cnt; +- spin_unlock_bh(&nss_top->stats_lock); +-} +- +-/* +- * nss_edma_lite_stats_notify() +- * Calls statistics notifier. +- * +- * Leverage NSS-FW statistics timing to update Netlink. +- */ +-void nss_edma_lite_stats_notify(struct nss_ctx_instance *nss_ctx) +-{ +- uint32_t core_id = nss_ctx->id; +- +- atomic_notifier_call_chain(&nss_edma_lite_stats_notifier, NSS_STATS_EVENT_NOTIFY, (void *)&core_id); +-} +- +-/* +- * nss_edma_lite_stats_register_notifier() +- * Registers statistics notifier. +- */ +-int nss_edma_lite_stats_register_notifier(struct notifier_block *nb) +-{ +- return atomic_notifier_chain_register(&nss_edma_lite_stats_notifier, nb); +-} +-EXPORT_SYMBOL(nss_edma_lite_stats_register_notifier); +- +-/* +- * nss_edma_lite_stats_unregister_notifier() +- * Deregisters stats notifier. +- */ +-int nss_edma_lite_stats_unregister_notifier(struct notifier_block *nb) +-{ +- return atomic_notifier_chain_unregister(&nss_edma_lite_stats_notifier, nb); +-} +-EXPORT_SYMBOL(nss_edma_lite_stats_unregister_notifier); +--- a/nss_edma_lite_stats.h ++++ /dev/null +@@ -1,36 +0,0 @@ +-/* +- * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for any +- * purpose with or without fee is hereby granted, provided that the above +- * copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- */ +- +-/* +- * nss_edma_lite_stats.h +- * NSS EDMA statistics header file. +- */ +- +-#ifndef __NSS_EDMA_LITE_STATS_H +-#define __NSS_EDMA_LITE_STATS_H +- +-#include "nss_core.h" +- +-/* +- * NSS EDMA statistics APIs +- */ +-extern void nss_edma_lite_stats_notify(struct nss_ctx_instance *nss_ctx); +-extern void nss_edma_lite_node_stats_sync(struct nss_ctx_instance *nss_ctx, struct nss_edma_lite_node_stats_sync *nerss); +-extern void nss_edma_lite_ring_stats_sync(struct nss_ctx_instance *nss_ctx, struct nss_edma_lite_ring_stats_sync *nerss); +-extern void nss_edma_lite_err_stats_sync(struct nss_ctx_instance *nss_ctx, struct nss_edma_lite_err_stats_sync *nerss); +-extern void nss_edma_lite_stats_dentry_create(void); +- +-#endif /* __NSS_EDMA_LITE_STATS_H */ +--- a/nss_edma_lite_strings.c ++++ /dev/null +@@ -1,246 +0,0 @@ +-/* +- * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for any +- * purpose with or without fee is hereby granted, provided that the above +- * copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- */ +- +-#include "nss_stats.h" +-#include "nss_core.h" +-#include +-#include "nss_strings.h" +- +-/* +- * nss_edma_lite_strings_stats_node +- * EDMA statistics strings. +- */ +-struct nss_stats_info nss_edma_lite_strings_stats_node[NSS_STATS_NODE_MAX] = { +- {"rx_pkts" , NSS_STATS_TYPE_COMMON}, +- {"rx_byts" , NSS_STATS_TYPE_COMMON}, +- {"tx_pkts" , NSS_STATS_TYPE_COMMON}, +- {"tx_byts" , NSS_STATS_TYPE_COMMON}, +- {"rx_queue[0]_drops" , NSS_STATS_TYPE_DROP}, +- {"rx_queue[1]_drops" , NSS_STATS_TYPE_DROP}, +- {"rx_queue[2]_drops" , NSS_STATS_TYPE_DROP}, +- {"rx_queue[3]_drops" , NSS_STATS_TYPE_DROP} +-}; +- +-/* +- * nss_edma_lite_node_stats_strings_read() +- * Read EDMA node statistics names. +- */ +-static ssize_t nss_edma_lite_node_stats_strings_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- return nss_strings_print(ubuf, sz, ppos, nss_edma_lite_strings_stats_node, NSS_STATS_NODE_MAX); +-} +- +-/* +- * nss_edma_lite_node_stats_strings_ops +- */ +-NSS_STRINGS_DECLARE_FILE_OPERATIONS(edma_lite_node_stats); +- +-/* +- * nss_edma_lite_strings_stats_tx +- */ +-struct nss_stats_info nss_edma_lite_strings_stats_tx[NSS_EDMA_LITE_STATS_TX_MAX] = { +- {"tx_err" , NSS_STATS_TYPE_ERROR}, +- {"tx_drops" , NSS_STATS_TYPE_DROP}, +- {"desc_cnt" , NSS_STATS_TYPE_SPECIAL} +-}; +- +-/* +- * nss_edma_lite_txring_strings_read() +- * Read EDMA txring names. +- */ +-static ssize_t nss_edma_lite_txring_strings_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- return nss_strings_print(ubuf, sz, ppos, nss_edma_lite_strings_stats_tx, NSS_EDMA_LITE_STATS_TX_MAX); +-} +- +-/* +- * edma_txring_strings_ops +- */ +-NSS_STRINGS_DECLARE_FILE_OPERATIONS(edma_lite_txring); +- +-/* +- * nss_edma_lite_strings_stats_rx +- */ +-struct nss_stats_info nss_edma_lite_strings_stats_rx[NSS_EDMA_LITE_STATS_RX_MAX] = { +- {"desc_cnt" , NSS_STATS_TYPE_SPECIAL} +-}; +- +-/* +- * nss_edma_lite_rxring_strings_read() +- * Read EDMA rxring names. +- */ +-static ssize_t nss_edma_lite_rxring_strings_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- return nss_strings_print(ubuf, sz, ppos, nss_edma_lite_strings_stats_rx, NSS_EDMA_LITE_STATS_RX_MAX); +-} +- +-/* +- * edma_rxring_strings_ops +- */ +-NSS_STRINGS_DECLARE_FILE_OPERATIONS(edma_lite_rxring); +- +-/* +- * nss_edma_lite_strings_stats_txcmpl +- */ +-struct nss_stats_info nss_edma_lite_strings_stats_txcmpl[NSS_EDMA_LITE_STATS_TXCMPL_MAX] = { +- {"desc_cnt" , NSS_STATS_TYPE_SPECIAL} +-}; +- +-/* +- * nss_edma_lite_txcmplring_strings_read() +- * Read EDMA txcmplring names. +- */ +-static ssize_t nss_edma_lite_txcmplring_strings_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- return nss_strings_print(ubuf, sz, ppos, nss_edma_lite_strings_stats_txcmpl, NSS_EDMA_LITE_STATS_TXCMPL_MAX); +-} +- +-/* +- * edma_txcmplring_strings_ops +- */ +-NSS_STRINGS_DECLARE_FILE_OPERATIONS(edma_lite_txcmplring); +- +-/* +- * nss_edma_lite_strings_stats_rxfill +- */ +-struct nss_stats_info nss_edma_lite_strings_stats_rxfill[NSS_EDMA_LITE_STATS_RXFILL_MAX] = { +- {"desc_cnt" , NSS_STATS_TYPE_SPECIAL} +-}; +- +-/* +- * nss_edma_lite_rxfillring_strings_read() +- * Read EDMA rxfillring names. +- */ +-static ssize_t nss_edma_lite_rxfillring_strings_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- return nss_strings_print(ubuf, sz, ppos, nss_edma_lite_strings_stats_rxfill, NSS_EDMA_LITE_STATS_RXFILL_MAX); +-} +- +-/* +- * edma_rxfillring_strings_ops +- */ +-NSS_STRINGS_DECLARE_FILE_OPERATIONS(edma_lite_rxfillring); +- +-/* +- * nss_edma_lite_strings_stats_err_map +- */ +-struct nss_stats_info nss_edma_lite_strings_stats_err_map[NSS_EDMA_LITE_ERR_STATS_MAX] = { +- {"alloc_fail_cnt" , NSS_STATS_TYPE_ERROR}, +- {"unknown_pkt_cnt" , NSS_STATS_TYPE_ERROR}, +-}; +- +-/* +- * nss_edma_lite_err_strings_read() +- * Read EDMA error names. +- */ +-static ssize_t nss_edma_lite_err_strings_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- return nss_strings_print(ubuf, sz, ppos, nss_edma_lite_strings_stats_err_map, NSS_EDMA_LITE_ERR_STATS_MAX); +-} +- +-/* +- * edma_err_strings_ops +- */ +-NSS_STRINGS_DECLARE_FILE_OPERATIONS(edma_lite_err); +- +-/* +- * nss_edma_lite_strings_dentry_create() +- * Create EDMA statistics strings debug entry. +- */ +-void nss_edma_lite_strings_dentry_create(void) +-{ +- struct dentry *edma_d; +- struct dentry *edma_rings_dir_d; +- struct dentry *file_d; +- +- if (!nss_top_main.strings_dentry) { +- nss_warning("qca-nss-drv/strings is not present"); +- return; +- } +- +- edma_d = debugfs_create_dir("edma", nss_top_main.strings_dentry); +- if (!edma_d) { +- nss_warning("Failed to create qca-nss-drv/strings/edma directory"); +- return; +- } +- +- /* +- * edma node stats +- */ +- file_d = debugfs_create_file("node_stats", 0400, edma_d, &nss_top_main, &nss_edma_lite_node_stats_strings_ops); +- if (!file_d) { +- nss_warning("Failed to create qca-nss-drv/strings/edma/node_stats file"); +- goto fail; +- } +- +- /* +- * edma error stats +- */ +- file_d = debugfs_create_file("err_stats", 0400, edma_d, &nss_top_main, &nss_edma_lite_err_strings_ops); +- if (!file_d) { +- nss_warning("Failed to create qca-nss-drv/strings/edma/err_stats file"); +- goto fail; +- } +- +- /* +- * edma ring stats +- */ +- edma_rings_dir_d = debugfs_create_dir("rings", edma_d); +- if (!edma_rings_dir_d) { +- nss_warning("Failed to create qca-nss-drv/strings/edma/rings directory"); +- goto fail; +- } +- +- /* +- * edma tx ring stats +- */ +- file_d = debugfs_create_file("tx", 0400, edma_rings_dir_d, &nss_top_main, &nss_edma_lite_txring_strings_ops); +- if (!file_d) { +- nss_warning("Failed to create qca-nss-drv/strings/edma/rings/tx file"); +- goto fail; +- } +- +- /* +- * edma rx ring stats +- */ +- file_d = debugfs_create_file("rx", 0400, edma_rings_dir_d, &nss_top_main, &nss_edma_lite_rxring_strings_ops); +- if (!file_d) { +- nss_warning("Failed to create qca-nss-drv/strings/edma/rings/rx file"); +- goto fail; +- } +- +- /* +- * edma tx cmpl ring stats +- */ +- file_d = debugfs_create_file("txcmpl", 0400, edma_rings_dir_d, &nss_top_main, &nss_edma_lite_txcmplring_strings_ops); +- if (!file_d) { +- nss_warning("Failed to create qca-nss-drv/strings/edma/rings/txcmpl file"); +- goto fail; +- } +- +- /* +- * edma rx fill ring stats +- */ +- file_d = debugfs_create_file("rxfill", 0400, edma_rings_dir_d, &nss_top_main, &nss_edma_lite_rxfillring_strings_ops); +- if (!file_d) { +- nss_warning("Failed to create qca-nss-drv/strings/edma/rings/rxfill file"); +- goto fail; +- } +- +- return; +-fail: +- debugfs_remove_recursive(edma_d); +-} +--- a/nss_edma_lite_strings.h ++++ /dev/null +@@ -1,28 +0,0 @@ +-/* +- * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for any +- * purpose with or without fee is hereby granted, provided that the above +- * copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- */ +- +-#ifndef __NSS_EDMA_LITE_LITE_STRINGS_H +-#define __NSS_EDMA_LITE_LITE_STRINGS_H +- +-extern struct nss_stats_info nss_edma_lite_strings_stats_node[NSS_STATS_NODE_MAX]; +-extern struct nss_stats_info nss_edma_lite_strings_stats_tx[NSS_EDMA_LITE_STATS_TX_MAX]; +-extern struct nss_stats_info nss_edma_lite_strings_stats_rx[NSS_EDMA_LITE_STATS_RX_MAX]; +-extern struct nss_stats_info nss_edma_lite_strings_stats_txcmpl[NSS_EDMA_LITE_STATS_TXCMPL_MAX]; +-extern struct nss_stats_info nss_edma_lite_strings_stats_rxfill[NSS_EDMA_LITE_STATS_RXFILL_MAX]; +-extern struct nss_stats_info nss_edma_lite_strings_stats_err_map[NSS_EDMA_LITE_ERR_STATS_MAX]; +-extern void nss_edma_lite_strings_dentry_create(void); +- +-#endif /* __NSS_EDMA_LITE_STRINGS_H */ +--- a/nss_edma_stats.c ++++ b/nss_edma_stats.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -732,7 +732,6 @@ void nss_edma_metadata_ring_stats_sync(s + edma_stats.rx_stats[i][NSS_EDMA_STATS_RX_DESC] += nerss->rx_ring[i].desc_cnt; + edma_stats.rx_stats[i][NSS_EDMA_STATS_RX_QOS_ERR] += nerss->rx_ring[i].qos_err; + edma_stats.rx_stats[i][NSS_EDMA_STATS_RX_SRC_PORT_INVALID] += nerss->rx_ring[i].rx_src_port_invalid; +- edma_stats.rx_stats[i][NSS_EDMA_STATS_RX_SRC_IF_INVALID] += nerss->rx_ring[i].rx_src_if_invalid; + } + + /* +--- a/nss_edma_strings.c ++++ b/nss_edma_strings.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -78,8 +78,7 @@ struct nss_stats_info nss_edma_strings_s + {"rx_csum_err" , NSS_STATS_TYPE_ERROR}, + {"desc_cnt" , NSS_STATS_TYPE_SPECIAL}, + {"qos_err" , NSS_STATS_TYPE_DROP}, +- {"rx_src_port_invalid" , NSS_STATS_TYPE_DROP}, +- {"rx_src_interface_invalid" , NSS_STATS_TYPE_DROP} ++ {"rx_src_port_invalid" , NSS_STATS_TYPE_DROP} + }; + + /* +--- a/nss_freq.c ++++ b/nss_freq.c +@@ -299,12 +299,7 @@ void nss_freq_scale_frequency(struct nss + + if (nss_runtime_samples.freq_scale_rate_limit_down++ >= NSS_FREQUENCY_SCALE_RATE_LIMIT_DOWN) { + minimum = nss_runtime_samples.freq_scale[index].minimum; +- +- /* +- * Check if we need to lower the frequency. For some SoC like IPQ50xx, low frequency +- * is not supported. So check if the next lower frequency is configured before shifting down +- */ +- if ((nss_runtime_samples.average < minimum) && (index > 0) && nss_runtime_samples.freq_scale[index - 1].maximum) { ++ if ((nss_runtime_samples.average < minimum) && (index > 0)) { + nss_runtime_samples.freq_scale_index--; + nss_runtime_samples.freq_scale_ready = 0; + +--- a/nss_gre.c ++++ b/nss_gre.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -17,7 +17,6 @@ + #include "nss_tx_rx_common.h" + #include "nss_gre_stats.h" + #include "nss_gre_log.h" +-#include "nss_gre_strings.h" + + #define NSS_GRE_TX_TIMEOUT 3000 /* 3 Seconds */ + +@@ -116,13 +115,11 @@ static void nss_gre_msg_handler(struct n + /* + * debug stats embedded in stats msg + */ +- nss_gre_stats_session_sync(nss_ctx, &ntm->msg.sstats, ncm->interface); +- nss_gre_stats_session_notify(nss_ctx, ncm->interface); ++ nss_gre_stats_session_debug_sync(nss_ctx, &ntm->msg.sstats, ncm->interface); + break; + + case NSS_GRE_MSG_BASE_STATS: +- nss_gre_stats_base_sync(nss_ctx, &ntm->msg.bstats); +- nss_gre_stats_base_notify(nss_ctx); ++ nss_gre_stats_base_debug_sync(nss_ctx, &ntm->msg.bstats); + break; + + default: +@@ -407,5 +404,4 @@ void nss_gre_register_handler(void) + init_completion(&nss_gre_pvt.complete); + nss_core_register_handler(nss_ctx, NSS_GRE_INTERFACE, nss_gre_msg_handler, NULL); + nss_gre_stats_dentry_create(); +- nss_gre_strings_dentry_create(); + } +--- a/nss_gre_redir.c ++++ b/nss_gre_redir.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2014-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2014-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -16,7 +16,6 @@ + + #include "nss_tx_rx_common.h" + #include "nss_gre_redir_stats.h" +-#include "nss_gre_redir_strings.h" + #include "nss_gre_redir_log.h" + #define NSS_GRE_REDIR_TX_TIMEOUT 3000 /* 3 Seconds */ + +@@ -32,9 +31,14 @@ static struct { + } nss_gre_redir_pvt; + + /* ++ * Spinlock to update tunnel stats. ++ */ ++static DEFINE_SPINLOCK(nss_gre_redir_stats_lock); ++ ++/* + * Array to hold tunnel stats along with if_num + */ +-struct nss_gre_redir_tunnel_stats tun_stats[NSS_GRE_REDIR_MAX_INTERFACES]; ++static struct nss_gre_redir_tunnel_stats tun_stats[NSS_GRE_REDIR_MAX_INTERFACES]; + + /* + * nss_gre_callback() +@@ -55,7 +59,7 @@ static void nss_gre_redir_msg_sync_callb + * nss_gre_redir_verify_ifnum() + * Verify interface type. + */ +-bool nss_gre_redir_verify_ifnum(uint32_t if_num) ++static bool nss_gre_redir_verify_ifnum(uint32_t if_num) + { + uint32_t type; + +@@ -69,6 +73,92 @@ bool nss_gre_redir_verify_ifnum(uint32_t + } + + /* ++ * nss_gre_redir_tunnel_update_stats() ++ * Update gre_redir tunnel stats. ++ */ ++static void nss_gre_redir_tunnel_update_stats(struct nss_ctx_instance *nss_ctx, int if_num, struct nss_gre_redir_stats_sync_msg *ngss) ++{ ++ int i, j; ++ uint32_t type; ++ struct net_device *dev; ++ ++ type = nss_dynamic_interface_get_type(nss_ctx, if_num); ++ dev = nss_cmn_get_interface_dev(nss_ctx, if_num); ++ if (!dev) { ++ nss_warning("%px: Unable to find net device for the interface %d\n", nss_ctx, if_num); ++ return; ++ } ++ ++ if (!nss_gre_redir_verify_ifnum(if_num)) { ++ nss_warning("%px: Unknown type for interface %d\n", nss_ctx, if_num); ++ return; ++ } ++ ++ spin_lock_bh(&nss_gre_redir_stats_lock); ++ for (i = 0; i < NSS_GRE_REDIR_MAX_INTERFACES; i++) { ++ if (tun_stats[i].dev == dev) { ++ break; ++ } ++ } ++ ++ if (i == NSS_GRE_REDIR_MAX_INTERFACES) { ++ nss_warning("%px: Unable to find tunnel stats instance for interface %d\n", nss_ctx, if_num); ++ return; ++ } ++ ++ nss_assert(tun_stats[i].ref_count); ++ switch (type) { ++ case NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_WIFI_HOST_INNER: ++ case NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_WIFI_OFFL_INNER: ++ case NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_SJACK_INNER: ++ tun_stats[i].node_stats.tx_packets += ngss->node_stats.tx_packets; ++ tun_stats[i].node_stats.tx_bytes += ngss->node_stats.tx_bytes; ++ tun_stats[i].sjack_tx_packets += ngss->sjack_rx_packets; ++ tun_stats[i].encap_sg_alloc_drop += ngss->encap_sg_alloc_drop; ++ tun_stats[i].tx_dropped += nss_cmn_rx_dropped_sum(&(ngss->node_stats)); ++ for (j = 0; j < NSS_GRE_REDIR_MAX_RADIO; j++) { ++ tun_stats[i].offl_tx_pkts[j] += ngss->offl_rx_pkts[j]; ++ } ++ ++ break; ++ ++ case NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_OUTER: ++ tun_stats[i].node_stats.rx_packets += ngss->node_stats.rx_packets; ++ tun_stats[i].node_stats.rx_bytes += ngss->node_stats.rx_bytes; ++ tun_stats[i].sjack_rx_packets += ngss->sjack_rx_packets; ++ tun_stats[i].decap_fail_drop += ngss->decap_fail_drop; ++ tun_stats[i].decap_split_drop += ngss->decap_split_drop; ++ tun_stats[i].split_sg_alloc_fail += ngss->split_sg_alloc_fail; ++ tun_stats[i].split_linear_copy_fail += ngss->split_linear_copy_fail; ++ tun_stats[i].split_not_enough_tailroom += ngss->split_not_enough_tailroom; ++ tun_stats[i].decap_eapol_frames += ngss->decap_eapol_frames; ++ tun_stats[i].node_stats.rx_dropped[0] += nss_cmn_rx_dropped_sum(&(ngss->node_stats)); ++ for (j = 0; j < NSS_GRE_REDIR_MAX_RADIO; j++) { ++ tun_stats[i].offl_rx_pkts[j] += ngss->offl_rx_pkts[j]; ++ } ++ ++ break; ++ ++ case NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_EXCEPTION_US: ++ tun_stats[i].exception_us_rx += ngss->node_stats.rx_packets; ++ tun_stats[i].exception_us_tx += ngss->node_stats.tx_packets; ++ break; ++ ++ case NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_EXCEPTION_DS: ++ tun_stats[i].exception_ds_rx += ngss->node_stats.rx_packets; ++ tun_stats[i].exception_ds_tx += ngss->node_stats.tx_packets; ++ tun_stats[i].exception_ds_invalid_dst_drop += ngss->exception_ds_invalid_dst_drop; ++ tun_stats[i].exception_ds_inv_appid += ngss->exception_ds_inv_appid; ++ tun_stats[i].headroom_unavail += ngss->headroom_unavail; ++ tun_stats[i].tx_completion_success += ngss->tx_completion_success; ++ tun_stats[i].tx_completion_drop += ngss->tx_completion_drop; ++ break; ++ } ++ ++ spin_unlock_bh(&nss_gre_redir_stats_lock); ++} ++ ++/* + * nss_gre_redir_handler() + * Handle NSS -> HLOS messages for GRE tunnel. + */ +@@ -109,7 +199,7 @@ static void nss_gre_redir_msg_handler(st + */ + if (ncm->response == NSS_CMN_RESPONSE_NOTIFY) { + ncm->cb = (nss_ptr_t)nss_core_get_msg_handler(nss_ctx, ncm->interface); +- ncm->app_data = (nss_ptr_t)nss_ctx->nss_rx_interface_handlers[ncm->interface].app_data; ++ ncm->app_data = (nss_ptr_t)nss_ctx->nss_rx_interface_handlers[nss_ctx->id][ncm->interface].app_data; + } + + /* +@@ -119,8 +209,7 @@ static void nss_gre_redir_msg_handler(st + + switch (ncm->type) { + case NSS_GRE_REDIR_RX_STATS_SYNC_MSG: +- nss_gre_redir_stats_sync(nss_ctx, ncm->interface, &ngrm->msg.stats_sync); +- nss_gre_redir_stats_notify(nss_ctx, ncm->interface); ++ nss_gre_redir_tunnel_update_stats(nss_ctx, ncm->interface, &ngrm->msg.stats_sync); + break; + } + +@@ -452,6 +541,24 @@ nss_tx_status_t nss_gre_redir_configure_ + EXPORT_SYMBOL(nss_gre_redir_configure_outer_node); + + /* ++ * nss_gre_redir_get_stats() ++ * Get gre_redir tunnel stats. ++ */ ++bool nss_gre_redir_get_stats(int index, struct nss_gre_redir_tunnel_stats *stats) ++{ ++ spin_lock_bh(&nss_gre_redir_stats_lock); ++ if (tun_stats[index].ref_count == 0) { ++ spin_unlock_bh(&nss_gre_redir_stats_lock); ++ return false; ++ } ++ ++ memcpy(stats, &tun_stats[index], sizeof(struct nss_gre_redir_tunnel_stats)); ++ spin_unlock_bh(&nss_gre_redir_stats_lock); ++ return true; ++} ++EXPORT_SYMBOL(nss_gre_redir_get_stats); ++ ++/* + * nss_gre_redir_tx_msg() + * Transmit a GRE message to NSS FW. + */ +@@ -668,6 +775,4 @@ void nss_gre_redir_register_handler(void + nss_warning("%px: Not able to register handler for gre_redir base interface with NSS core\n", nss_ctx); + return; + } +- +- nss_gre_redir_strings_dentry_create(); + } +--- a/nss_gre_redir_lag_ds.c ++++ b/nss_gre_redir_lag_ds.c +@@ -1,6 +1,6 @@ + /* +- **************************************************************************** +- * Copyright (c) 2018, 2020-2021, The Linux Foundation. All rights reserved. ++ ************************************************************************** ++ * Copyright (c) 2018, 2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -11,18 +11,17 @@ + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- **************************************************************************** ++ ************************************************************************** + */ + + #include "nss_tx_rx_common.h" +-#include "nss_gre_redir_lag.h" + #include "nss_gre_redir_lag_ds_stats.h" + #include "nss_gre_redir_lag_ds_log.h" +-#include "nss_gre_redir_lag_ds_strings.h" + + #define NSS_GRE_REDIR_LAG_DS_TX_TIMEOUT 3000 /* 3 Seconds */ + +-struct nss_gre_redir_lag_ds_tun_stats tun_ds_stats[NSS_GRE_REDIR_LAG_MAX_NODE]; ++static struct nss_gre_redir_lag_ds_tun_stats tun_stats[NSS_GRE_REDIR_LAG_MAX_NODE]; ++static DEFINE_SPINLOCK(nss_gre_redir_lag_ds_stats_lock); + + /* + * Private data structure +@@ -65,11 +64,11 @@ static void nss_gre_redir_lag_ds_callbac + * nss_gre_redir_lag_ds_get_node_idx() + * Returns index of statistics context. + */ +-bool nss_gre_redir_lag_ds_get_node_idx(uint32_t ifnum, uint32_t *idx) ++static inline bool nss_gre_redir_lag_ds_get_node_idx(uint32_t ifnum, uint32_t *idx) + { + uint32_t node_idx; + for (node_idx = 0; node_idx < NSS_GRE_REDIR_LAG_MAX_NODE; node_idx++) { +- if ((tun_ds_stats[node_idx].valid) && (tun_ds_stats[node_idx].ifnum == ifnum)) { ++ if ((tun_stats[node_idx].valid) && (tun_stats[node_idx].ifnum == ifnum)) { + *idx = node_idx; + return true; + } +@@ -79,10 +78,37 @@ bool nss_gre_redir_lag_ds_get_node_idx(u + } + + /* ++ * nss_gre_redir_lag_ds_update_sync_stats() ++ * Update synchonized statistics. ++ */ ++static void nss_gre_redir_lag_ds_update_sync_stats(struct nss_ctx_instance *nss_ctx, struct nss_gre_redir_lag_ds_sync_stats_msg *ngss, uint32_t ifnum) ++{ ++ int idx, j; ++ ++ spin_lock_bh(&nss_gre_redir_lag_ds_stats_lock); ++ if (!nss_gre_redir_lag_ds_get_node_idx(ifnum, &idx)) { ++ spin_unlock_bh(&nss_gre_redir_lag_ds_stats_lock); ++ nss_warning("%px: Unable to update hash stats msg. Stats context not found.\n", nss_ctx); ++ return; ++ } ++ ++ tun_stats[idx].tx_packets += ngss->node_stats.tx_packets; ++ tun_stats[idx].tx_bytes += ngss->node_stats.tx_bytes; ++ tun_stats[idx].rx_packets += ngss->node_stats.rx_packets; ++ tun_stats[idx].rx_bytes += ngss->node_stats.rx_bytes; ++ for (j = 0; j < NSS_MAX_NUM_PRI; j++) { ++ tun_stats[idx].rx_dropped[j] += ngss->node_stats.rx_dropped[j]; ++ } ++ tun_stats[idx].dst_invalid += ngss->ds_stats.dst_invalid; ++ tun_stats[idx].exception_cnt += ngss->ds_stats.exception_cnt; ++ spin_unlock_bh(&nss_gre_redir_lag_ds_stats_lock); ++} ++ ++/* + * nss_gre_redir_lag_ds_verify_ifnum() + * Verify interface type. + */ +-bool nss_gre_redir_lag_ds_verify_ifnum(uint32_t if_num) ++static bool nss_gre_redir_lag_ds_verify_ifnum(uint32_t if_num) + { + return nss_dynamic_interface_get_type(nss_gre_redir_lag_ds_get_context(), if_num) == NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_LAG_DS; + } +@@ -121,7 +147,7 @@ static void nss_gre_redir_lag_ds_msg_han + */ + if (ncm->response == NSS_CMN_RESPONSE_NOTIFY) { + ncm->cb = (nss_ptr_t)nss_core_get_msg_handler(nss_ctx, ncm->interface); +- ncm->app_data = (nss_ptr_t)nss_ctx->nss_rx_interface_handlers[ncm->interface].app_data; ++ ncm->app_data = (nss_ptr_t)nss_ctx->nss_rx_interface_handlers[nss_ctx->id][ncm->interface].app_data; + } + + /* +@@ -136,8 +162,7 @@ static void nss_gre_redir_lag_ds_msg_han + + switch (ncm->type) { + case NSS_GRE_REDIR_LAG_DS_STATS_SYNC_MSG: +- nss_gre_redir_lag_ds_stats_sync(nss_ctx, &ngrm->msg.ds_sync_stats, ncm->interface); +- nss_gre_redir_lag_ds_stats_notify(nss_ctx, ncm->interface); ++ nss_gre_redir_lag_ds_update_sync_stats(nss_ctx, &ngrm->msg.ds_sync_stats, ncm->interface); + break; + } + +@@ -192,7 +217,7 @@ static enum nss_gre_redir_lag_err_types + return NSS_GRE_REDIR_LAG_ERR_STATS_INDEX_NOT_FOUND; + } + +- tun_ds_stats[idx].valid = false; ++ tun_stats[idx].valid = false; + spin_unlock_bh(&nss_gre_redir_lag_ds_stats_lock); + return NSS_GRE_REDIR_LAG_SUCCESS; + } +@@ -233,9 +258,9 @@ static struct nss_ctx_instance *nss_gre_ + nss_core_set_subsys_dp_type(nss_ctx, netdev, if_num, type); + spin_lock_bh(&nss_gre_redir_lag_ds_stats_lock); + for (i = 0; i < NSS_GRE_REDIR_LAG_MAX_NODE; i++) { +- if (!tun_ds_stats[i].valid) { +- tun_ds_stats[i].ifnum = if_num; +- tun_ds_stats[i].valid = true; ++ if (!tun_stats[i].valid) { ++ tun_stats[i].ifnum = if_num; ++ tun_stats[i].valid = true; + break; + } + } +@@ -256,6 +281,26 @@ struct nss_ctx_instance *nss_gre_redir_l + EXPORT_SYMBOL(nss_gre_redir_lag_ds_get_context); + + /* ++ * nss_gre_redir_lag_ds_get_cmn_stats() ++ * Get statistics for downstream LAG node. ++ */ ++bool nss_gre_redir_lag_ds_get_cmn_stats(struct nss_gre_redir_lag_ds_tun_stats *cmn_stats, uint32_t index) ++{ ++ if (index >= NSS_GRE_REDIR_LAG_MAX_NODE) { ++ return false; ++ } ++ ++ spin_lock_bh(&nss_gre_redir_lag_ds_stats_lock); ++ if (!tun_stats[index].valid) { ++ spin_unlock_bh(&nss_gre_redir_lag_ds_stats_lock); ++ return false; ++ } ++ memcpy((void *)cmn_stats, (void *)&tun_stats[index], sizeof(*cmn_stats)); ++ spin_unlock_bh(&nss_gre_redir_lag_ds_stats_lock); ++ return true; ++} ++ ++/* + * nss_gre_redir_lag_ds_tx_msg() + * Transmit a gre message to NSS. + */ +@@ -396,7 +441,6 @@ void nss_gre_redir_lag_ds_register_handl + return; + } + +- nss_gre_redir_lag_ds_strings_dentry_create(); + nss_gre_redir_lag_ds_pvt.cb = NULL; + nss_gre_redir_lag_ds_pvt.app_data = NULL; + sema_init(&nss_gre_redir_lag_ds_pvt.sem, 1); +--- a/nss_gre_redir_lag_ds_stats.c ++++ b/nss_gre_redir_lag_ds_stats.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2019, 2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -17,38 +17,69 @@ + #include "nss_core.h" + #include "nss_gre_redir_lag.h" + #include "nss_gre_redir_lag_ds_stats.h" +-#include "nss_gre_redir_lag_ds_strings.h" + + /* +- * Declare atomic notifier data structure for statistics. ++ * nss_gre_redir_lag_ds_stats_str ++ * GRE REDIR LAG DS common statistics strings. + */ +-ATOMIC_NOTIFIER_HEAD(nss_gre_redir_lag_ds_stats_notifier); ++static uint8_t *nss_gre_redir_lag_ds_stats_str[NSS_GRE_REDIR_LAG_DS_STATS_MAX] = { ++ "rx_packets", ++ "rx_bytes", ++ "tx_packets", ++ "tx_bytes", ++ "rx_queue_0_dropped", ++ "rx_queue_1_dropped", ++ "rx_queue_2_dropped", ++ "rx_queue_3_dropped", ++ "dst_invalid", ++ "exception_packets" ++}; ++ ++/* ++ * nss_gre_redir_lag_ds_tunnel_stats() ++ * Make a row for GRE_REDIR LAG DS stats. ++ */ ++static ssize_t nss_gre_redir_lag_ds_cmn_stats_read_entry(char *line, int len, int type, struct nss_gre_redir_lag_ds_tun_stats *s) ++{ ++ uint64_t tcnt = 0; ++ ++ switch (type) { ++ case NSS_STATS_NODE_RX_PKTS: ++ tcnt = s->rx_packets; ++ return snprintf(line, len, "Common node stats start:\n\n%s = %llu\n", nss_gre_redir_lag_ds_stats_str[type], tcnt); ++ case NSS_STATS_NODE_RX_BYTES: ++ tcnt = s->rx_bytes; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_lag_ds_stats_str[type], tcnt); ++ case NSS_STATS_NODE_TX_PKTS: ++ tcnt = s->tx_packets; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_lag_ds_stats_str[type], tcnt); ++ case NSS_STATS_NODE_TX_BYTES: ++ tcnt = s->tx_bytes; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_lag_ds_stats_str[type], tcnt); ++ case NSS_STATS_NODE_RX_QUEUE_0_DROPPED: ++ tcnt = s->rx_dropped[0]; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_lag_ds_stats_str[type], tcnt); ++#if (NSS_MAX_NUM_PRI > 1) ++ case NSS_STATS_NODE_RX_QUEUE_1_DROPPED: ++ tcnt = s->rx_dropped[1]; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_lag_ds_stats_str[type], tcnt); ++ case NSS_STATS_NODE_RX_QUEUE_2_DROPPED: ++ tcnt = s->rx_dropped[2]; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_lag_ds_stats_str[type], tcnt); ++ case NSS_STATS_NODE_RX_QUEUE_3_DROPPED: ++ tcnt = s->rx_dropped[3]; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_lag_ds_stats_str[type], tcnt); ++#endif ++ case NSS_GRE_REDIR_LAG_DS_STATS_DST_INVALID: ++ tcnt = s->dst_invalid; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_lag_ds_stats_str[type], tcnt); ++ case NSS_GRE_REDIR_LAG_DS_STATS_EXCEPTION_PKT: ++ tcnt = s->exception_cnt; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_lag_ds_stats_str[type], tcnt); + +-/* +- * Spinlock to protect GRE redirect lag ds statistics update/read +- */ +-DEFINE_SPINLOCK(nss_gre_redir_lag_ds_stats_lock); +- +-extern struct nss_gre_redir_lag_ds_tun_stats tun_ds_stats[NSS_GRE_REDIR_LAG_MAX_NODE]; +- +-/* +- * nss_gre_redir_lag_ds_stats_get() +- * Get statistics for downstream LAG node. +- */ +-bool nss_gre_redir_lag_ds_stats_get(struct nss_gre_redir_lag_ds_tun_stats *cmn_stats, uint32_t index) +-{ +- if (index >= NSS_GRE_REDIR_LAG_MAX_NODE) +- return false; +- +- spin_lock_bh(&nss_gre_redir_lag_ds_stats_lock); +- if (!tun_ds_stats[index].valid) { +- spin_unlock_bh(&nss_gre_redir_lag_ds_stats_lock); +- return false; ++ default: ++ return 0; + } +- +- memcpy((void *)cmn_stats, (void *)&tun_ds_stats[index], sizeof(*cmn_stats)); +- spin_unlock_bh(&nss_gre_redir_lag_ds_stats_lock); +- return true; + } + + /* +@@ -57,45 +88,47 @@ bool nss_gre_redir_lag_ds_stats_get(stru + */ + static ssize_t nss_gre_redir_lag_ds_cmn_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) + { +- /* +- * Max output lines = #stats + +- * few blank lines for banner printing + Number of Extra outputlines +- * for future reference to add new stats +- */ +- uint32_t max_output_lines = NSS_GRE_REDIR_LAG_DS_STATS_MAX + NSS_STATS_EXTRA_OUTPUT_LINES; +- size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines; ++ ssize_t bytes_read = 0; + struct nss_stats_data *data = fp->private_data; + struct nss_gre_redir_lag_ds_tun_stats stats; +- ssize_t bytes_read = 0; +- size_t size_wr = 0; +- +- char *lbuf = kzalloc(size_al, GFP_KERNEL); +- if (unlikely(!lbuf)) { +- nss_warning("Could not allocate memory for local statistics buffer"); +- return 0; +- } ++ size_t bytes; ++ char line[80]; ++ int start; + + while (data->index < NSS_GRE_REDIR_LAG_MAX_NODE) { +- if (nss_gre_redir_lag_ds_stats_get(&stats, data->index)) { ++ if (nss_gre_redir_lag_ds_get_cmn_stats(&stats, data->index)) { + break; + } + + data->index++; + } + +- if (data->index >= NSS_GRE_REDIR_LAG_MAX_NODE) { +- kfree(lbuf); ++ if (data->index == NSS_GRE_REDIR_LAG_MAX_NODE) { + return 0; + } + +- size_wr += nss_stats_banner(lbuf, size_wr, size_al, "gre_redir_lag_ds stats", NSS_STATS_SINGLE_CORE); +- size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\nTunnel stats for %03u\n", stats.ifnum); +- size_wr += nss_stats_print("gre_redir_lag_ds", NULL, NSS_STATS_SINGLE_INSTANCE, nss_gre_redir_lag_ds_strings_stats, +- &stats.rx_packets, NSS_GRE_REDIR_LAG_DS_STATS_MAX, lbuf, size_wr, size_al); ++ bytes = snprintf(line, sizeof(line), "\nTunnel stats for \n"); ++ if (copy_to_user(ubuf, line, bytes) != 0) { ++ return -EFAULT; ++ } ++ ++ bytes_read += bytes; ++ start = NSS_STATS_NODE_RX_PKTS; ++ while (bytes_read < sz && start < NSS_GRE_REDIR_LAG_DS_STATS_MAX) { ++ bytes = nss_gre_redir_lag_ds_cmn_stats_read_entry(line, sizeof(line), start, &stats); ++ ++ if ((bytes_read + bytes) > sz) ++ break; ++ ++ if (copy_to_user(ubuf + bytes_read, line, bytes) != 0) { ++ return -EFAULT; ++ } ++ ++ bytes_read += bytes; ++ start++; ++ } + +- bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf)); + data->index++; +- kfree(lbuf); + return bytes_read; + } + +@@ -128,84 +161,3 @@ struct dentry *nss_gre_redir_lag_ds_stat + + return cmn_stats; + } +- +-/* +- * nss_gre_redir_lag_ds_stats_sync() +- * Update synchonized statistics. +- */ +-void nss_gre_redir_lag_ds_stats_sync(struct nss_ctx_instance *nss_ctx, struct nss_gre_redir_lag_ds_sync_stats_msg *ngss, uint32_t ifnum) +-{ +- int idx, j; +- +- spin_lock_bh(&nss_gre_redir_lag_ds_stats_lock); +- if (!nss_gre_redir_lag_ds_get_node_idx(ifnum, &idx)) { +- spin_unlock_bh(&nss_gre_redir_lag_ds_stats_lock); +- nss_warning("%px: Unable to update hash stats msg. Stats context not found.\n", nss_ctx); +- return; +- } +- +- tun_ds_stats[idx].tx_packets += ngss->node_stats.tx_packets; +- tun_ds_stats[idx].tx_bytes += ngss->node_stats.tx_bytes; +- tun_ds_stats[idx].rx_packets += ngss->node_stats.rx_packets; +- tun_ds_stats[idx].rx_bytes += ngss->node_stats.rx_bytes; +- for (j = 0; j < NSS_MAX_NUM_PRI; j++) { +- tun_ds_stats[idx].rx_dropped[j] += ngss->node_stats.rx_dropped[j]; +- } +- +- tun_ds_stats[idx].dst_invalid += ngss->ds_stats.dst_invalid; +- tun_ds_stats[idx].exception_cnt += ngss->ds_stats.exception_cnt; +- spin_unlock_bh(&nss_gre_redir_lag_ds_stats_lock); +-} +- +-/* +- * nss_gre_redir_lag_ds_stats_notify() +- * Sends notifications to all the registered modules. +- * +- * Leverage NSS-FW statistics timing to update Netlink. +- */ +-void nss_gre_redir_lag_ds_stats_notify(struct nss_ctx_instance *nss_ctx, uint32_t if_num) +-{ +- struct nss_gre_redir_lag_ds_stats_notification *stats_notify; +- int idx; +- +- stats_notify = kzalloc(sizeof(struct nss_gre_redir_lag_ds_stats_notification), GFP_ATOMIC); +- if (!stats_notify) { +- nss_warning("Unable to allocate memory for stats notification\n"); +- return; +- } +- +- spin_lock_bh(&nss_gre_redir_lag_ds_stats_lock); +- if (!nss_gre_redir_lag_ds_get_node_idx(if_num, &idx)) { +- spin_unlock_bh(&nss_gre_redir_lag_ds_stats_lock); +- nss_warning("%px: Unable to update hash stats msg. Stats context not found.\n", nss_ctx); +- kfree(stats_notify); +- return; +- } +- +- stats_notify->core_id = nss_ctx->id; +- stats_notify->if_num = if_num; +- memcpy(&(stats_notify->stats_ctx), &(tun_ds_stats[idx]), sizeof(stats_notify->stats_ctx)); +- spin_unlock_bh(&nss_gre_redir_lag_ds_stats_lock); +- atomic_notifier_call_chain(&nss_gre_redir_lag_ds_stats_notifier, NSS_STATS_EVENT_NOTIFY, stats_notify); +- kfree(stats_notify); +-} +- +-/* +- * nss_gre_redir_lag_ds_stats_unregister_notifier() +- * Deregisters statistics notifier. +- */ +-int nss_gre_redir_lag_ds_stats_unregister_notifier(struct notifier_block *nb) +-{ +- return atomic_notifier_chain_unregister(&nss_gre_redir_lag_ds_stats_notifier, nb); +-} +-EXPORT_SYMBOL(nss_gre_redir_lag_ds_stats_unregister_notifier); +- +-/* +- * nss_gre_redir_lag_ds_stats_register_notifier() +- * Registers statistics notifier. +- */ +-int nss_gre_redir_lag_ds_stats_register_notifier(struct notifier_block *nb) +-{ +- return atomic_notifier_chain_register(&nss_gre_redir_lag_ds_stats_notifier, nb); +-} +-EXPORT_SYMBOL(nss_gre_redir_lag_ds_stats_register_notifier); +--- a/nss_gre_redir_lag_ds_stats.h ++++ b/nss_gre_redir_lag_ds_stats.h +@@ -1,6 +1,6 @@ + /* +- ************************************************************************** +- * Copyright (c) 2018, 2021, The Linux Foundation. All rights reserved. ++ ****************************************************************************** ++ * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -11,18 +11,20 @@ + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- * ************************************************************************ ++ * **************************************************************************** + */ + + #ifndef __NSS_GRE_REDIR_LAG_DS_STATS_H__ + #define __NSS_GRE_REDIR_LAG_DS_STATS_H__ + +-extern spinlock_t nss_gre_redir_lag_ds_stats_lock; +-extern void nss_gre_redir_lag_ds_stats_notify(struct nss_ctx_instance *nss_ctx, uint32_t if_num); +-extern bool nss_gre_redir_lag_ds_verify_ifnum(uint32_t if_num); +-extern bool nss_gre_redir_lag_ds_get_node_idx(uint32_t ifnum, uint32_t *idx); +-extern void nss_gre_redir_lag_ds_stats_sync(struct nss_ctx_instance *nss_ctx, +- struct nss_gre_redir_lag_ds_sync_stats_msg *ngss, uint32_t ifnum); +-extern struct dentry *nss_gre_redir_lag_ds_stats_dentry_create(void); ++/* ++ * GRE redirect LAG downstream statistics ++ */ ++enum nss_gre_redir_lag_ds_stats_types { ++ NSS_GRE_REDIR_LAG_DS_STATS_DST_INVALID = NSS_STATS_NODE_MAX, ++ NSS_GRE_REDIR_LAG_DS_STATS_EXCEPTION_PKT, ++ NSS_GRE_REDIR_LAG_DS_STATS_MAX, ++}; + ++extern struct dentry *nss_gre_redir_lag_ds_stats_dentry_create(void); + #endif +--- a/nss_gre_redir_lag_ds_strings.c ++++ /dev/null +@@ -1,60 +0,0 @@ +-/* +- *************************************************************************** +- * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- *************************************************************************** +- */ +- +-#include "nss_stats.h" +-#include "nss_core.h" +-#include "nss_strings.h" +-#include "nss_gre_redir_lag_ds_strings.h" +- +-/* +- * nss_gre_redir_lag_ds_strings_stats +- * GRE REDIR LAG DS common statistics strings. +- */ +-struct nss_stats_info nss_gre_redir_lag_ds_strings_stats[NSS_GRE_REDIR_LAG_DS_STATS_MAX] = { +- {"rx_packets", NSS_STATS_TYPE_COMMON}, +- {"rx_bytes", NSS_STATS_TYPE_COMMON}, +- {"tx_packets", NSS_STATS_TYPE_COMMON}, +- {"tx_bytes", NSS_STATS_TYPE_COMMON}, +- {"rx_dropped_0", NSS_STATS_TYPE_DROP}, +- {"rx_dropped_1", NSS_STATS_TYPE_DROP}, +- {"rx_dropped_2", NSS_STATS_TYPE_DROP}, +- {"rx_dropped_3", NSS_STATS_TYPE_DROP}, +- {"dst_invalid", NSS_STATS_TYPE_EXCEPTION}, +- {"exception_packets", NSS_STATS_TYPE_SPECIAL} +-}; +- +-/* +- * nss_gre_redir_lag_ds_strings_read() +- * Read gre_redir_lag_ds statistics names +- */ +-static ssize_t nss_gre_redir_lag_ds_strings_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- return nss_strings_print(ubuf, sz, ppos, nss_gre_redir_lag_ds_strings_stats, NSS_GRE_REDIR_LAG_DS_STATS_MAX); +-} +- +-/* +- * nss_gre_redir_lag_ds_strings_ops +- */ +-NSS_STRINGS_DECLARE_FILE_OPERATIONS(gre_redir_lag_ds); +- +-/* +- * nss_gre_redir_lag_ds_strings_dentry_create() +- * Create gre_redir_lag_ds statistics strings debug entry. +- */ +-void nss_gre_redir_lag_ds_strings_dentry_create(void) +-{ +- nss_strings_create_dentry("gre_redir_lag_ds", &nss_gre_redir_lag_ds_strings_ops); +-} +--- a/nss_gre_redir_lag_ds_strings.h ++++ /dev/null +@@ -1,25 +0,0 @@ +-/* +- *************************************************************************** +- * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- *************************************************************************** +- */ +- +-#ifndef __NSS_GRE_REDIR_LAG_DS_STRINGS_H +-#define __NSS_GRE_REDIR_LAG_DS_STRINGS_H +- +-#include "nss_gre_redir_lag_ds_stats.h" +- +-extern struct nss_stats_info nss_gre_redir_lag_ds_strings_stats[NSS_GRE_REDIR_LAG_DS_STATS_MAX]; +-extern void nss_gre_redir_lag_ds_strings_dentry_create(void); +- +-#endif /* __NSS_GRE_REDIR_LAG_DS_STRINGS_H */ +--- a/nss_gre_redir_lag_us.c ++++ b/nss_gre_redir_lag_us.c +@@ -1,6 +1,6 @@ + /* +- **************************************************************************** +- * Copyright (c) 2018, 2020-2021, The Linux Foundation. All rights reserved. ++ ************************************************************************** ++ * Copyright (c) 2018, 2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -11,19 +11,39 @@ + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- **************************************************************************** ++ ************************************************************************** + */ + + #include "nss_tx_rx_common.h" + #include "nss_gre_redir_lag_us_stats.h" + #include "nss_gre_redir_lag_us_log.h" +-#include "nss_gre_redir_lag_us_strings.h" + + #define NSS_GRE_REDIR_LAG_US_TX_TIMEOUT 3000 /* 3 Seconds */ + #define NSS_GRE_REDIR_LAG_US_STATS_SYNC_PERIOD msecs_to_jiffies(4000) + #define NSS_GRE_REDIR_LAG_US_STATS_SYNC_UDELAY 4000 + +-struct nss_gre_redir_lag_us_cmn_ctx cmn_ctx; ++/* ++ * nss_gre_redir_lag_us_pvt_sync_stats ++ * Hash statistics synchronization context. ++ */ ++struct nss_gre_redir_lag_us_pvt_sync_stats { ++ struct delayed_work nss_gre_redir_lag_us_work; /**< Delayed work per LAG US node. */ ++ struct nss_gre_redir_lag_us_msg db_sync_msg; /**< Hash statistics message. */ ++ struct nss_gre_redir_lag_us_tunnel_stats tun_stats; /**< GRE redirect LAG common statistics. */ ++ nss_gre_redir_lag_us_msg_callback_t cb; /**< Callback for hash query message. */ ++ void *app_data; /**< app_data for hash query message. */ ++ uint32_t ifnum; /**< NSS interface number. */ ++ bool valid; /**< Valid flag. */ ++}; ++ ++/* ++ * Common context for stats update. ++ */ ++static struct nss_gre_redir_lag_us_cmn_ctx { ++ spinlock_t nss_gre_redir_lag_us_stats_lock; /**< Spin lock. */ ++ struct workqueue_struct *nss_gre_redir_lag_us_wq; /**< Work queue. */ ++ struct nss_gre_redir_lag_us_pvt_sync_stats stats_ctx[NSS_GRE_REDIR_LAG_MAX_NODE]; ++} cmn_ctx; + + /* + * Sync response context. +@@ -63,6 +83,61 @@ static void nss_gre_redir_lag_us_callbac + } + + /* ++ * nss_gre_redir_lag_us_get_node_idx() ++ * Returns index of statistics context. ++ */ ++static bool nss_gre_redir_lag_us_get_node_idx(uint32_t ifnum, uint32_t *idx) ++{ ++ uint32_t node_idx; ++ for (node_idx = 0; node_idx < NSS_GRE_REDIR_LAG_MAX_NODE; node_idx++) { ++ if ((cmn_ctx.stats_ctx[node_idx].valid) && (cmn_ctx.stats_ctx[node_idx].ifnum == ifnum)) { ++ *idx = node_idx; ++ return true; ++ } ++ } ++ ++ return false; ++} ++ ++/* ++ * nss_gre_redir_lag_us_update_sync_stats() ++ * Update synchonized statistics. ++ */ ++static void nss_gre_redir_lag_us_update_sync_stats(struct nss_ctx_instance *nss_ctx, struct nss_gre_redir_lag_us_cmn_sync_stats_msg *ngss, ++ uint32_t ifnum) ++{ ++ int idx, j; ++ ++ spin_lock_bh(&cmn_ctx.nss_gre_redir_lag_us_stats_lock); ++ if (!nss_gre_redir_lag_us_get_node_idx(ifnum, &idx)) { ++ spin_unlock_bh(&cmn_ctx.nss_gre_redir_lag_us_stats_lock); ++ nss_warning("%px: Unable to update hash stats msg. Stats context not found.\n", nss_ctx); ++ return; ++ } ++ ++ cmn_ctx.stats_ctx[idx].tun_stats.tx_packets += ngss->node_stats.tx_packets; ++ cmn_ctx.stats_ctx[idx].tun_stats.tx_bytes += ngss->node_stats.tx_bytes; ++ cmn_ctx.stats_ctx[idx].tun_stats.rx_packets += ngss->node_stats.rx_packets; ++ cmn_ctx.stats_ctx[idx].tun_stats.rx_bytes += ngss->node_stats.rx_bytes; ++ for (j = 0; j < NSS_MAX_NUM_PRI; j++) { ++ cmn_ctx.stats_ctx[idx].tun_stats.rx_dropped[j] += ngss->node_stats.rx_dropped[j]; ++ } ++ cmn_ctx.stats_ctx[idx].tun_stats.us_stats.amsdu_pkts += ngss->us_stats.amsdu_pkts; ++ cmn_ctx.stats_ctx[idx].tun_stats.us_stats.amsdu_pkts_enqueued += ngss->us_stats.amsdu_pkts_enqueued; ++ cmn_ctx.stats_ctx[idx].tun_stats.us_stats.amsdu_pkts_exceptioned += ngss->us_stats.amsdu_pkts_exceptioned; ++ cmn_ctx.stats_ctx[idx].tun_stats.us_stats.exceptioned += ngss->us_stats.exceptioned; ++ cmn_ctx.stats_ctx[idx].tun_stats.us_stats.freed += ngss->us_stats.freed; ++ cmn_ctx.stats_ctx[idx].tun_stats.db_stats.add_attempt += ngss->db_stats.add_attempt; ++ cmn_ctx.stats_ctx[idx].tun_stats.db_stats.add_success += ngss->db_stats.add_success; ++ cmn_ctx.stats_ctx[idx].tun_stats.db_stats.add_fail_table_full += ngss->db_stats.add_fail_table_full; ++ cmn_ctx.stats_ctx[idx].tun_stats.db_stats.add_fail_exists += ngss->db_stats.add_fail_exists; ++ cmn_ctx.stats_ctx[idx].tun_stats.db_stats.del_attempt += ngss->db_stats.del_attempt; ++ cmn_ctx.stats_ctx[idx].tun_stats.db_stats.del_success += ngss->db_stats.del_success; ++ cmn_ctx.stats_ctx[idx].tun_stats.db_stats.del_fail_not_found += ngss->db_stats.del_fail_not_found; ++ spin_unlock_bh(&cmn_ctx.nss_gre_redir_lag_us_stats_lock); ++} ++ ++/* + * nss_gre_redir_lag_us_hash_update_stats_req() + * Update query hash message's index for next request. + */ +@@ -92,14 +167,25 @@ static void nss_gre_redir_lag_us_hash_up + * If more hash entries are to be fetched from FW, queue work with delay of one eighth of + * the polling period. Else, schedule work with a delay of polling period. + */ +- if (cmn_ctx.stats_ctx[idx].db_sync_msg.msg.hash_stats.db_entry_idx) ++ if (cmn_ctx.stats_ctx[idx].db_sync_msg.msg.hash_stats.db_entry_idx) { + sync_delay = NSS_GRE_REDIR_LAG_US_STATS_SYNC_PERIOD / 8; ++ } + +- queue_delayed_work(cmn_ctx.nss_gre_redir_lag_us_wq, &(cmn_ctx.stats_ctx[idx].nss_gre_redir_lag_us_work), sync_delay); ++ queue_delayed_work(cmn_ctx.nss_gre_redir_lag_us_wq, &(cmn_ctx.stats_ctx[idx].nss_gre_redir_lag_us_work), ++ sync_delay); + spin_unlock_bh(&cmn_ctx.nss_gre_redir_lag_us_stats_lock); + } + + /* ++ * nss_gre_redir_lag_us_verify_ifnum() ++ * Verify interface type. ++ */ ++static bool nss_gre_redir_lag_us_verify_ifnum(uint32_t if_num) ++{ ++ return nss_dynamic_interface_get_type(nss_gre_redir_lag_us_get_context(), if_num) == NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_LAG_US; ++} ++ ++/* + * nss_gre_redir_lag_us_handler() + * Handle NSS -> HLOS messages for gre tunnel + */ +@@ -138,7 +224,7 @@ static void nss_gre_redir_lag_us_msg_han + */ + if (ncm->response == NSS_CMN_RESPONSE_NOTIFY) { + ncm->cb = (nss_ptr_t)nss_core_get_msg_handler(nss_ctx, ncm->interface); +- ncm->app_data = (nss_ptr_t)nss_ctx->nss_rx_interface_handlers[ncm->interface].app_data; ++ ncm->app_data = (nss_ptr_t)nss_ctx->nss_rx_interface_handlers[nss_ctx->id][ncm->interface].app_data; + } + + /* +@@ -148,8 +234,7 @@ static void nss_gre_redir_lag_us_msg_han + + switch (ncm->type) { + case NSS_GRE_REDIR_LAG_US_CMN_STATS_SYNC_MSG: +- nss_gre_redir_lag_us_stats_sync(nss_ctx, &ngrm->msg.us_sync_stats, ncm->interface); +- nss_gre_redir_lag_us_stats_notify(nss_ctx, ncm->interface); ++ nss_gre_redir_lag_us_update_sync_stats(nss_ctx, &ngrm->msg.us_sync_stats, ncm->interface); + break; + + case NSS_GRE_REDIR_LAG_US_DB_HASH_NODE_MSG: +@@ -429,32 +514,6 @@ static struct nss_ctx_instance *nss_gre_ + } + + /* +- * nss_gre_redir_lag_us_get_node_idx() +- * Returns index of statistics context. +- */ +-bool nss_gre_redir_lag_us_get_node_idx(uint32_t ifnum, uint32_t *idx) +-{ +- uint32_t node_idx; +- for (node_idx = 0; node_idx < NSS_GRE_REDIR_LAG_MAX_NODE; node_idx++) { +- if ((cmn_ctx.stats_ctx[node_idx].valid) && (cmn_ctx.stats_ctx[node_idx].ifnum == ifnum)) { +- *idx = node_idx; +- return true; +- } +- } +- +- return false; +-} +- +-/* +- * nss_gre_redir_lag_us_verify_ifnum() +- * Verify interface type. +- */ +-bool nss_gre_redir_lag_us_verify_ifnum(uint32_t if_num) +-{ +- return nss_dynamic_interface_get_type(nss_gre_redir_lag_us_get_context(), if_num) == NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_LAG_US; +-} +- +-/* + * nss_gre_redir_lag_us_get_context() + * Retrieve context for GRE redirect LAG upstream node. + */ +@@ -547,6 +606,29 @@ bool nss_gre_redir_lag_us_configure_node + EXPORT_SYMBOL(nss_gre_redir_lag_us_configure_node); + + /* ++ * nss_gre_redir_lag_us_get_cmn_stats() ++ * Common upstream statistics. ++ */ ++bool nss_gre_redir_lag_us_get_cmn_stats(struct nss_gre_redir_lag_us_tunnel_stats *cmn_stats, uint32_t index) ++{ ++ if (index >= NSS_GRE_REDIR_LAG_MAX_NODE) { ++ nss_warning("Index is out of valid range %u\n", index); ++ return false; ++ } ++ ++ spin_lock_bh(&cmn_ctx.nss_gre_redir_lag_us_stats_lock); ++ if (!cmn_ctx.stats_ctx[index].valid) { ++ spin_unlock_bh(&cmn_ctx.nss_gre_redir_lag_us_stats_lock); ++ nss_warning("Common context not found for the index %u\n", index); ++ return false; ++ } ++ ++ memcpy((void *)cmn_stats, (void *)&(cmn_ctx.stats_ctx[index].tun_stats), sizeof(*cmn_stats)); ++ spin_unlock_bh(&cmn_ctx.nss_gre_redir_lag_us_stats_lock); ++ return true; ++} ++ ++/* + * nss_gre_redir_lag_us_tx_msg() + * Transmit a GRE LAG message to NSS firmware asynchronously. + */ +@@ -656,7 +738,6 @@ void nss_gre_redir_lag_us_register_handl + return; + } + +- nss_gre_redir_lag_us_strings_dentry_create(); + nss_gre_redir_lag_us_sync_ctx.cb = NULL; + nss_gre_redir_lag_us_sync_ctx.app_data = NULL; + sema_init(&nss_gre_redir_lag_us_sync_ctx.sem, 1); +--- a/nss_gre_redir_lag_us_stats.c ++++ b/nss_gre_redir_lag_us_stats.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2019, 2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -17,39 +17,109 @@ + #include "nss_core.h" + #include "nss_gre_redir_lag.h" + #include "nss_gre_redir_lag_us_stats.h" +-#include "nss_gre_redir_lag_us_strings.h" +- +-#define NSS_GRE_REDIR_LAG_US_STATS_SYNC_PERIOD msecs_to_jiffies(4000) +-#define NSS_GRE_REDIR_LAG_US_STATS_SYNC_UDELAY 4000 +- +-/* +- * Declare atomic notifier data structure for statistics. +- */ +-ATOMIC_NOTIFIER_HEAD(nss_gre_redir_lag_us_stats_notifier); +- +-extern struct nss_gre_redir_lag_us_cmn_ctx cmn_ctx; + + /* +- * nss_gre_redir_lag_us_stats_get +- * Get the common upstream statistics. ++ * nss_gre_redir_lag_us_stats_str ++ * GRE REDIR LAG US common statistics strings. + */ +-bool nss_gre_redir_lag_us_stats_get(struct nss_gre_redir_lag_us_tunnel_stats *cmn_stats, uint32_t index) +-{ +- if (index >= NSS_GRE_REDIR_LAG_MAX_NODE) { +- nss_warning("Index is out of valid range %u\n", index); +- return false; +- } +- +- spin_lock_bh(&cmn_ctx.nss_gre_redir_lag_us_stats_lock); +- if (!cmn_ctx.stats_ctx[index].valid) { +- spin_unlock_bh(&cmn_ctx.nss_gre_redir_lag_us_stats_lock); +- nss_warning("Common context not found for the index %u\n", index); +- return false; ++static uint8_t *nss_gre_redir_lag_us_stats_str[NSS_GRE_REDIR_LAG_US_STATS_MAX] = { ++ "rx_packets", ++ "rx_bytes", ++ "tx_packets", ++ "tx_bytes", ++ "rx_queue_0_dropped", ++ "rx_queue_1_dropped", ++ "rx_queue_2_dropped", ++ "rx_queue_3_dropped", ++ "Amsdu pkts", ++ "Amsdu pkts enqueued", ++ "Amsdu pkts exceptioned", ++ "Exceptioned", ++ "Freed", ++ "add attempt", ++ "add success", ++ "add fail table full", ++ "add fail exists", ++ "del attempt", ++ "del success", ++ "del fail not found", ++}; ++ ++/* ++ * nss_gre_redir_lag_us_tunnel_stats() ++ * Make a row for GRE_REDIR LAG US stats. ++ */ ++static ssize_t nss_gre_redir_lag_us_cmn_stats_read_entry(char *line, int len, int type, struct nss_gre_redir_lag_us_tunnel_stats *s) ++{ ++ uint64_t tcnt = 0; ++ ++ switch (type) { ++ case NSS_STATS_NODE_RX_PKTS: ++ tcnt = s->rx_packets; ++ return snprintf(line, len, "Common node stats start:\n\n%s = %llu\n", nss_gre_redir_lag_us_stats_str[type], tcnt); ++ case NSS_STATS_NODE_RX_BYTES: ++ tcnt = s->rx_bytes; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_lag_us_stats_str[type], tcnt); ++ case NSS_STATS_NODE_TX_PKTS: ++ tcnt = s->tx_packets; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_lag_us_stats_str[type], tcnt); ++ case NSS_STATS_NODE_TX_BYTES: ++ tcnt = s->tx_bytes; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_lag_us_stats_str[type], tcnt); ++ case NSS_STATS_NODE_RX_QUEUE_0_DROPPED: ++ tcnt = s->rx_dropped[0]; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_lag_us_stats_str[type], tcnt); ++#if (NSS_MAX_NUM_PRI > 1) ++ case NSS_STATS_NODE_RX_QUEUE_1_DROPPED: ++ tcnt = s->rx_dropped[1]; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_lag_us_stats_str[type], tcnt); ++ case NSS_STATS_NODE_RX_QUEUE_2_DROPPED: ++ tcnt = s->rx_dropped[2]; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_lag_us_stats_str[type], tcnt); ++ case NSS_STATS_NODE_RX_QUEUE_3_DROPPED: ++ tcnt = s->rx_dropped[3]; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_lag_us_stats_str[type], tcnt); ++#endif ++ case NSS_GRE_REDIR_LAG_US_STATS_AMSDU_PKTS: ++ tcnt = s->us_stats.amsdu_pkts; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_lag_us_stats_str[type], tcnt); ++ case NSS_GRE_REDIR_LAG_US_STATS_AMSDU_PKTS_ENQUEUED: ++ tcnt = s->us_stats.amsdu_pkts_enqueued; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_lag_us_stats_str[type], tcnt); ++ case NSS_GRE_REDIR_LAG_US_STATS_AMSDU_PKTS_EXCEPTIONED: ++ tcnt = s->us_stats.amsdu_pkts_exceptioned; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_lag_us_stats_str[type], tcnt); ++ case NSS_GRE_REDIR_LAG_US_STATS_EXCEPTIONED: ++ tcnt = s->us_stats.exceptioned; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_lag_us_stats_str[type], tcnt); ++ case NSS_GRE_REDIR_LAG_US_STATS_FREED: ++ tcnt = s->us_stats.freed; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_lag_us_stats_str[type], tcnt); ++ case NSS_GRE_REDIR_LAG_US_STATS_ADD_ATTEMPT: ++ tcnt = s->db_stats.add_attempt; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_lag_us_stats_str[type], tcnt); ++ case NSS_GRE_REDIR_LAG_US_STATS_ADD_SUCCESS: ++ tcnt = s->db_stats.add_success; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_lag_us_stats_str[type], tcnt); ++ case NSS_GRE_REDIR_LAG_US_STATS_ADD_FAIL_TABLE_FULL: ++ tcnt = s->db_stats.add_fail_table_full; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_lag_us_stats_str[type], tcnt); ++ case NSS_GRE_REDIR_LAG_US_STATS_ADD_FAIL_EXISTS: ++ tcnt = s->db_stats.add_fail_exists; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_lag_us_stats_str[type], tcnt); ++ case NSS_GRE_REDIR_LAG_US_STATS_DEL_ATTEMPT: ++ tcnt = s->db_stats.del_attempt; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_lag_us_stats_str[type], tcnt); ++ case NSS_GRE_REDIR_LAG_US_STATS_DEL_SUCCESS: ++ tcnt = s->db_stats.del_success; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_lag_us_stats_str[type], tcnt); ++ case NSS_GRE_REDIR_LAG_US_STATS_DEL_FAIL_NOT_FOUND: ++ tcnt = s->db_stats.del_fail_not_found; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_lag_us_stats_str[type], tcnt); ++ default: ++ nss_warning("Unknown tunnel stats type.\n"); ++ return 0; + } +- +- memcpy((void *)cmn_stats, (void *)&(cmn_ctx.stats_ctx[index].tun_stats), sizeof(*cmn_stats)); +- spin_unlock_bh(&cmn_ctx.nss_gre_redir_lag_us_stats_lock); +- return true; + } + + /* +@@ -58,26 +128,15 @@ bool nss_gre_redir_lag_us_stats_get(stru + */ + static ssize_t nss_gre_redir_lag_us_cmn_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) + { +- /* +- * Max output lines = #stats + +- * few blank lines for banner printing + Number of Extra outputlines +- * for future reference to add new stats +- */ +- uint32_t max_output_lines = NSS_GRE_REDIR_LAG_US_STATS_MAX + NSS_STATS_EXTRA_OUTPUT_LINES; +- size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines; ++ ssize_t bytes_read = 0; + struct nss_stats_data *data = fp->private_data; + struct nss_gre_redir_lag_us_tunnel_stats stats; +- ssize_t bytes_read = 0; +- size_t size_wr = 0; +- +- char *lbuf = kzalloc(size_al, GFP_KERNEL); +- if (unlikely(!lbuf)) { +- nss_warning("Could not allocate memory for local statistics buffer"); +- return 0; +- } ++ size_t bytes; ++ char line[80]; ++ int start; + + while (data->index < NSS_GRE_REDIR_LAG_MAX_NODE) { +- if (nss_gre_redir_lag_us_stats_get(&stats, data->index)) { ++ if (nss_gre_redir_lag_us_get_cmn_stats(&stats, data->index)) { + break; + } + +@@ -85,17 +144,31 @@ static ssize_t nss_gre_redir_lag_us_cmn_ + } + + if (data->index == NSS_GRE_REDIR_LAG_MAX_NODE) { +- kfree(lbuf); + return 0; + } + +- size_wr += nss_stats_banner(lbuf, size_wr, size_al, "gre_redir_lag_us stats", NSS_STATS_SINGLE_CORE); +- size_wr += nss_stats_print("gre_redir_lag_us", NULL, NSS_STATS_SINGLE_INSTANCE, nss_gre_redir_lag_us_strings_stats, +- &stats.rx_packets, NSS_GRE_REDIR_LAG_US_STATS_MAX, lbuf, size_wr, size_al); ++ bytes = snprintf(line, sizeof(line), "\nTunnel stats"); ++ if (copy_to_user(ubuf, line, bytes) != 0) { ++ return -EFAULT; ++ } ++ ++ bytes_read += bytes; ++ start = NSS_STATS_NODE_RX_PKTS; ++ while (bytes_read < sz && start <= NSS_GRE_REDIR_LAG_US_STATS_DEL_FAIL_NOT_FOUND) { ++ bytes = nss_gre_redir_lag_us_cmn_stats_read_entry(line, sizeof(line), start, &stats); ++ if ((bytes_read + bytes) > sz) { ++ break; ++ } ++ ++ if (copy_to_user(ubuf + bytes_read, line, bytes) != 0) { ++ return -EFAULT; ++ } ++ ++ bytes_read += bytes; ++ start++; ++ } + +- bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf)); + data->index++; +- kfree(lbuf); + return bytes_read; + } + +@@ -128,99 +201,3 @@ struct dentry *nss_gre_redir_lag_us_stat + + return cmn_stats; + } +- +-/* +- * nss_gre_redir_lag_us_stats_sync() +- * Update synchonized statistics. +- */ +-void nss_gre_redir_lag_us_stats_sync(struct nss_ctx_instance *nss_ctx, +- struct nss_gre_redir_lag_us_cmn_sync_stats_msg *ngss, uint32_t ifnum) +-{ +- int idx, j; +- struct nss_gre_redir_lag_us_tunnel_stats *node_stats; +- +- spin_lock_bh(&cmn_ctx.nss_gre_redir_lag_us_stats_lock); +- if (!nss_gre_redir_lag_us_get_node_idx(ifnum, &idx)) { +- spin_unlock_bh(&cmn_ctx.nss_gre_redir_lag_us_stats_lock); +- nss_warning("%px: Unable to update hash stats msg. Stats context not found.\n", nss_ctx); +- return; +- } +- +- node_stats = &cmn_ctx.stats_ctx[idx].tun_stats; +- +- node_stats->tx_packets += ngss->node_stats.tx_packets; +- node_stats->tx_bytes += ngss->node_stats.tx_bytes; +- node_stats->rx_packets += ngss->node_stats.rx_packets; +- node_stats->rx_bytes += ngss->node_stats.rx_bytes; +- for (j = 0; j < NSS_MAX_NUM_PRI; j++) { +- node_stats->rx_dropped[j] += ngss->node_stats.rx_dropped[j]; +- } +- +- node_stats->us_stats.amsdu_pkts += ngss->us_stats.amsdu_pkts; +- node_stats->us_stats.amsdu_pkts_enqueued += ngss->us_stats.amsdu_pkts_enqueued; +- node_stats->us_stats.amsdu_pkts_exceptioned += ngss->us_stats.amsdu_pkts_exceptioned; +- node_stats->us_stats.exceptioned += ngss->us_stats.exceptioned; +- node_stats->us_stats.freed += ngss->us_stats.freed; +- node_stats->db_stats.add_attempt += ngss->db_stats.add_attempt; +- node_stats->db_stats.add_success += ngss->db_stats.add_success; +- node_stats->db_stats.add_fail_table_full += ngss->db_stats.add_fail_table_full; +- node_stats->db_stats.add_fail_exists += ngss->db_stats.add_fail_exists; +- node_stats->db_stats.del_attempt += ngss->db_stats.del_attempt; +- node_stats->db_stats.del_success += ngss->db_stats.del_success; +- node_stats->db_stats.del_fail_not_found += ngss->db_stats.del_fail_not_found; +- spin_unlock_bh(&cmn_ctx.nss_gre_redir_lag_us_stats_lock); +-} +- +-/* +- * nss_gre_redir_lag_us_stats_notify() +- * Sends notifications to all the registered modules. +- * +- * Leverage NSS-FW statistics timing to update Netlink. +- */ +-void nss_gre_redir_lag_us_stats_notify(struct nss_ctx_instance *nss_ctx, uint32_t if_num) +-{ +- struct nss_gre_redir_lag_us_stats_notification *stats_notify; +- int idx; +- +- stats_notify = kzalloc(sizeof(struct nss_gre_redir_lag_us_stats_notification), GFP_ATOMIC); +- if (!stats_notify) { +- nss_warning("Unable to allocate memory for stats notification\n"); +- return; +- } +- +- spin_lock_bh(&cmn_ctx.nss_gre_redir_lag_us_stats_lock); +- if (!nss_gre_redir_lag_us_get_node_idx(if_num, &idx)) { +- spin_unlock_bh(&cmn_ctx.nss_gre_redir_lag_us_stats_lock); +- nss_warning("%px: Unable to update hash stats msg. Stats context not found.\n", nss_ctx); +- kfree(stats_notify); +- return; +- } +- +- stats_notify->core_id = nss_ctx->id; +- stats_notify->if_num = if_num; +- memcpy(&(stats_notify->stats_ctx), &(cmn_ctx.stats_ctx[idx].tun_stats), sizeof(stats_notify->stats_ctx)); +- spin_unlock_bh(&cmn_ctx.nss_gre_redir_lag_us_stats_lock); +- atomic_notifier_call_chain(&nss_gre_redir_lag_us_stats_notifier, NSS_STATS_EVENT_NOTIFY, stats_notify); +- kfree(stats_notify); +-} +- +-/* +- * nss_gre_redir_lag_us_stats_unregister_notifier() +- * Deregisters statistics notifier. +- */ +-int nss_gre_redir_lag_us_stats_unregister_notifier(struct notifier_block *nb) +-{ +- return atomic_notifier_chain_unregister(&nss_gre_redir_lag_us_stats_notifier, nb); +-} +-EXPORT_SYMBOL(nss_gre_redir_lag_us_stats_unregister_notifier); +- +-/* +- * nss_gre_redir_lag_us_stats_register_notifier() +- * Registers statistics notifier. +- */ +-int nss_gre_redir_lag_us_stats_register_notifier(struct notifier_block *nb) +-{ +- return atomic_notifier_chain_register(&nss_gre_redir_lag_us_stats_notifier, nb); +-} +-EXPORT_SYMBOL(nss_gre_redir_lag_us_stats_register_notifier); +- +--- a/nss_gre_redir_lag_us_stats.h ++++ b/nss_gre_redir_lag_us_stats.h +@@ -1,6 +1,6 @@ + /* + ****************************************************************************** +- * Copyright (c) 2018, 2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -18,33 +18,23 @@ + #define __NSS_GRE_REDIR_LAG_US_STATS_H__ + + /* +- * nss_gre_redir_lag_us_pvt_sync_stats +- * Hash statistics synchronization context. ++ * GRE redirect LAG upstream statistics + */ +-struct nss_gre_redir_lag_us_pvt_sync_stats { +- struct delayed_work nss_gre_redir_lag_us_work; /**< Delayed work per LAG US node. */ +- struct nss_gre_redir_lag_us_msg db_sync_msg; /**< Hash statistics message. */ +- struct nss_gre_redir_lag_us_tunnel_stats tun_stats; /**< GRE redirect LAG common statistics. */ +- nss_gre_redir_lag_us_msg_callback_t cb; /**< Callback for hash query message. */ +- void *app_data; /**< app_data for hash query message. */ +- uint32_t ifnum; /**< NSS interface number. */ +- bool valid; /**< Valid flag. */ ++enum nss_gre_redir_lag_us_stats_types { ++ NSS_GRE_REDIR_LAG_US_STATS_AMSDU_PKTS = NSS_STATS_NODE_MAX, ++ NSS_GRE_REDIR_LAG_US_STATS_AMSDU_PKTS_ENQUEUED, ++ NSS_GRE_REDIR_LAG_US_STATS_AMSDU_PKTS_EXCEPTIONED, ++ NSS_GRE_REDIR_LAG_US_STATS_EXCEPTIONED, ++ NSS_GRE_REDIR_LAG_US_STATS_FREED, ++ NSS_GRE_REDIR_LAG_US_STATS_ADD_ATTEMPT, ++ NSS_GRE_REDIR_LAG_US_STATS_ADD_SUCCESS, ++ NSS_GRE_REDIR_LAG_US_STATS_ADD_FAIL_TABLE_FULL, ++ NSS_GRE_REDIR_LAG_US_STATS_ADD_FAIL_EXISTS, ++ NSS_GRE_REDIR_LAG_US_STATS_DEL_ATTEMPT, ++ NSS_GRE_REDIR_LAG_US_STATS_DEL_SUCCESS, ++ NSS_GRE_REDIR_LAG_US_STATS_DEL_FAIL_NOT_FOUND, ++ NSS_GRE_REDIR_LAG_US_STATS_MAX, + }; + +-/* +- * Common context for stats update. +- */ +-struct nss_gre_redir_lag_us_cmn_ctx { +- struct workqueue_struct *nss_gre_redir_lag_us_wq; /**< Work queue. */ +- spinlock_t nss_gre_redir_lag_us_stats_lock; /**< Spin lock. */ +- struct nss_gre_redir_lag_us_pvt_sync_stats stats_ctx[NSS_GRE_REDIR_LAG_MAX_NODE]; +-}; +- +-extern void nss_gre_redir_lag_us_stats_notify(struct nss_ctx_instance *nss_ctx, uint32_t if_num); +-extern bool nss_gre_redir_lag_us_get_node_idx(uint32_t ifnum, uint32_t *idx); +-extern bool nss_gre_redir_lag_us_verify_ifnum(uint32_t if_num); +-extern void nss_gre_redir_lag_us_stats_sync(struct nss_ctx_instance *nss_ctx, +- struct nss_gre_redir_lag_us_cmn_sync_stats_msg *ngss, uint32_t ifnum); + extern struct dentry *nss_gre_redir_lag_us_stats_dentry_create(void); +- + #endif +--- a/nss_gre_redir_lag_us_strings.c ++++ /dev/null +@@ -1,71 +0,0 @@ +-/* +- *************************************************************************** +- * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- *************************************************************************** +- */ +- +-#include "nss_stats.h" +-#include "nss_core.h" +-#include "nss_strings.h" +-#include "nss_gre_redir_lag_us_strings.h" +- +-/* +- * nss_gre_redir_lag_us_strings_stats +- * GRE REDIR LAG US common statistics strings. +- */ +-struct nss_stats_info nss_gre_redir_lag_us_strings_stats[NSS_GRE_REDIR_LAG_US_STATS_MAX] = { +- {"rx_packets", NSS_STATS_TYPE_COMMON}, +- {"rx_bytes", NSS_STATS_TYPE_COMMON}, +- {"tx_packets", NSS_STATS_TYPE_COMMON}, +- {"tx_bytes", NSS_STATS_TYPE_COMMON}, +- {"rx_dropped_0", NSS_STATS_TYPE_DROP}, +- {"rx_dropped_1", NSS_STATS_TYPE_DROP}, +- {"rx_dropped_2", NSS_STATS_TYPE_DROP}, +- {"rx_dropped_3", NSS_STATS_TYPE_DROP}, +- {"Amsdu pkts", NSS_STATS_TYPE_SPECIAL}, +- {"Amsdu pkts enqueued", NSS_STATS_TYPE_SPECIAL}, +- {"Amsdu pkts exceptioned", NSS_STATS_TYPE_EXCEPTION}, +- {"Exceptioned", NSS_STATS_TYPE_EXCEPTION}, +- {"Freed", NSS_STATS_TYPE_SPECIAL}, +- {"add attempt", NSS_STATS_TYPE_SPECIAL}, +- {"add success", NSS_STATS_TYPE_SPECIAL}, +- {"add fail table full", NSS_STATS_TYPE_SPECIAL}, +- {"add fail exists", NSS_STATS_TYPE_SPECIAL}, +- {"del attempt", NSS_STATS_TYPE_SPECIAL}, +- {"del success", NSS_STATS_TYPE_SPECIAL}, +- {"del fail not found", NSS_STATS_TYPE_SPECIAL} +-}; +- +-/* +- * nss_gre_redir_lag_us_strings_read() +- * Read gre_redir_lag_us statistics names +- */ +-static ssize_t nss_gre_redir_lag_us_strings_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- return nss_strings_print(ubuf, sz, ppos, nss_gre_redir_lag_us_strings_stats, NSS_GRE_REDIR_LAG_US_STATS_MAX); +-} +- +-/* +- * nss_gre_redir_lag_us_strings_ops +- */ +-NSS_STRINGS_DECLARE_FILE_OPERATIONS(gre_redir_lag_us); +- +-/* +- * nss_gre_redir_lag_us_strings_dentry_create() +- * Create gre_redir_lag_us statistics strings debug entry. +- */ +-void nss_gre_redir_lag_us_strings_dentry_create(void) +-{ +- nss_strings_create_dentry("gre_redir_lag_us", &nss_gre_redir_lag_us_strings_ops); +-} +- +--- a/nss_gre_redir_lag_us_strings.h ++++ /dev/null +@@ -1,25 +0,0 @@ +-/* +- *************************************************************************** +- * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- *************************************************************************** +- */ +- +-#ifndef __NSS_GRE_REDIR_LAG_US_STRINGS_H +-#define __NSS_GRE_REDIR_LAG_US_STRINGS_H +- +-#include "nss_gre_redir_lag_us_stats.h" +- +-extern struct nss_stats_info nss_gre_redir_lag_us_strings_stats[NSS_GRE_REDIR_LAG_US_STATS_MAX]; +-extern void nss_gre_redir_lag_us_strings_dentry_create(void); +- +-#endif /* __NSS_GRE_REDIR_LAG_US_STRINGS_H */ +--- a/nss_gre_redir_mark.c ++++ b/nss_gre_redir_mark.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -15,7 +15,6 @@ + */ + + #include "nss_tx_rx_common.h" +-#include "nss_gre_redir_mark_strings.h" + #include "nss_gre_redir_mark_stats.h" + #include "nss_gre_redir_mark_log.h" + #define NSS_GRE_REDIR_MARK_TX_TIMEOUT 3000 /* 3 Seconds */ +@@ -30,6 +29,16 @@ static struct { + } nss_gre_redir_mark_pvt; + + /* ++ * Spinlock to update GRE redir mark stats. ++ */ ++static DEFINE_SPINLOCK(nss_gre_redir_mark_stats_lock); ++ ++/* ++ * Global GRE redir mark stats structure. ++ */ ++static struct nss_gre_redir_mark_stats gre_mark_stats; ++ ++/* + * nss_gre_redir_mark_msg_sync_callback() + * Callback to handle the completion of HLOS-->NSS messages. + */ +@@ -45,6 +54,54 @@ static void nss_gre_redir_mark_msg_sync_ + } + + /* ++ * nss_gre_redir_mark_stats_sync() ++ * Update GRE redir mark stats. ++ */ ++static void nss_gre_redir_mark_stats_sync(struct nss_ctx_instance *nss_ctx, int if_num, struct nss_gre_redir_mark_stats_sync_msg *ngss) ++{ ++ struct net_device *dev; ++ dev = nss_cmn_get_interface_dev(nss_ctx, if_num); ++ if (!dev) { ++ nss_warning("%px: Unable to find net device for the interface %d\n", nss_ctx, if_num); ++ return; ++ } ++ ++ if (if_num != NSS_GRE_REDIR_MARK_INTERFACE) { ++ nss_warning("%px: Unknown type for interface %d\n", nss_ctx, if_num); ++ return; ++ } ++ ++ /* ++ * Update the stats in exclusive mode to prevent the read from the process ++ * context through debug fs. ++ */ ++ spin_lock_bh(&nss_gre_redir_mark_stats_lock); ++ ++ /* ++ * Update the common node stats ++ */ ++ gre_mark_stats.stats[NSS_GRE_REDIR_MARK_STATS_TX_PKTS] += ngss->node_stats.tx_packets; ++ gre_mark_stats.stats[NSS_GRE_REDIR_MARK_STATS_TX_BYTES] += ngss->node_stats.tx_bytes; ++ gre_mark_stats.stats[NSS_GRE_REDIR_MARK_STATS_RX_PKTS] += ngss->node_stats.rx_packets; ++ gre_mark_stats.stats[NSS_GRE_REDIR_MARK_STATS_RX_BYTES] += ngss->node_stats.rx_bytes; ++ gre_mark_stats.stats[NSS_GRE_REDIR_MARK_STATS_RX_DROPS] += nss_cmn_rx_dropped_sum(&(ngss->node_stats)); ++ ++ /* ++ * Update the GRE redir mark specific stats ++ */ ++ gre_mark_stats.stats[NSS_GRE_REDIR_MARK_STATS_HLOS_MAGIC_FAILED] += ngss->hlos_magic_fail; ++ gre_mark_stats.stats[NSS_GRE_REDIR_MARK_STATS_INV_DST_IF_DROPS] += ngss->invalid_dst_drop; ++ gre_mark_stats.stats[NSS_GRE_REDIR_MARK_STATS_DST_IF_ENQUEUE] += ngss->dst_enqueue_success; ++ gre_mark_stats.stats[NSS_GRE_REDIR_MARK_STATS_DST_IF_ENQUEUE_DROPS] += ngss->dst_enqueue_drop; ++ gre_mark_stats.stats[NSS_GRE_REDIR_MARK_STATS_INV_APPID] += ngss->inv_appid; ++ gre_mark_stats.stats[NSS_GRE_REDIR_MARK_STATS_HEADROOM_UNAVAILABLE] += ngss->headroom_unavail; ++ gre_mark_stats.stats[NSS_GRE_REDIR_MARK_STATS_TX_COMPLETION_SUCCESS] += ngss->tx_completion_success; ++ gre_mark_stats.stats[NSS_GRE_REDIR_MARK_STATS_TX_COMPLETION_DROPS] += ngss->tx_completion_drop; ++ ++ spin_unlock_bh(&nss_gre_redir_mark_stats_lock); ++} ++ ++/* + * nss_gre_redir_mark_handler() + * Handle NSS to HLOS messages for GRE redir mark + */ +@@ -80,7 +137,6 @@ static void nss_gre_redir_mark_handler(s + + if (ncm->type == NSS_GRE_REDIR_MARK_STATS_SYNC_MSG) { + nss_gre_redir_mark_stats_sync(nss_ctx, ncm->interface, &ngrm->msg.stats_sync); +- nss_gre_redir_mark_stats_notify(nss_ctx, ncm->interface); + } + + /* +@@ -105,6 +161,28 @@ static void nss_gre_redir_mark_handler(s + } + + /* ++ * nss_gre_redir_mark_get_stats() ++ * Get gre_redir tunnel stats. ++ */ ++bool nss_gre_redir_mark_get_stats(void *stats_mem) ++{ ++ struct nss_gre_redir_mark_stats *stats = (struct nss_gre_redir_mark_stats *)stats_mem; ++ if (!stats) { ++ nss_warning("No memory to copy GRE redir mark stats"); ++ return false; ++ } ++ ++ /* ++ * Copy the GRE redir mark stats in the memory. ++ */ ++ spin_lock_bh(&nss_gre_redir_mark_stats_lock); ++ memcpy(stats, &gre_mark_stats, sizeof(struct nss_gre_redir_mark_stats)); ++ spin_unlock_bh(&nss_gre_redir_mark_stats_lock); ++ return true; ++} ++EXPORT_SYMBOL(nss_gre_redir_mark_get_stats); ++ ++/* + * nss_gre_redir_mark_reg_cb() + * Configure a callback on VAP. + */ +@@ -262,7 +340,7 @@ bool nss_gre_redir_mark_unregister_if(ui + return false; + } + +- nss_ctx->nss_rx_interface_handlers[if_num].msg_cb = NULL; ++ nss_ctx->nss_rx_interface_handlers[nss_ctx->id][if_num].msg_cb = NULL; + return true; + } + EXPORT_SYMBOL(nss_gre_redir_mark_unregister_if); +@@ -326,7 +404,6 @@ void nss_gre_redir_mark_register_handler + return; + } + +- nss_gre_redir_mark_strings_dentry_create(); + sema_init(&nss_gre_redir_mark_pvt.sem, 1); + init_completion(&nss_gre_redir_mark_pvt.complete); + +--- a/nss_gre_redir_mark_stats.c ++++ b/nss_gre_redir_mark_stats.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2019, 2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -18,64 +18,95 @@ + #include "nss_stats.h" + #include "nss_gre_redir_mark.h" + #include "nss_gre_redir_mark_stats.h" +-#include "nss_gre_redir_mark_strings.h" + + #define NSS_GRE_REDIR_MARK_STATS_STR_LEN 50 + #define NSS_GRE_REDIR_MARK_STATS_LEN ((NSS_GRE_REDIR_MARK_STATS_MAX + 7 ) * NSS_GRE_REDIR_MARK_STATS_STR_LEN) +- +-/* +- * Declare atomic notifier data structure for statistics. +- */ +-ATOMIC_NOTIFIER_HEAD(nss_gre_redir_mark_stats_notifier); +- + /* +- * Spinlock to protect GRE redirect mark statistics update/read ++ * nss_gre_redir_mark_stats_str ++ * GRE redir mark statistics string + */ +-DEFINE_SPINLOCK(nss_gre_redir_mark_stats_lock); +- +-/* +- * Global GRE redirect mark stats structure. +- */ +-struct nss_gre_redir_mark_stats gre_mark_stats; +- +-/* +- * nss_gre_redir_mark_stats_get() +- * Get gre_redir tunnel stats. +- */ +-bool nss_gre_redir_mark_stats_get(struct nss_gre_redir_mark_stats *stats_mem) +-{ +- if (!stats_mem) { +- nss_warning("No memory to copy GRE redir mark stats"); +- return false; ++static int8_t *nss_gre_redir_mark_stats_str[NSS_GRE_REDIR_MARK_STATS_MAX] = { ++ "TX Packets", ++ "TX Bytes", ++ "RX Packets", ++ "RX Bytes", ++ "RX Drops", ++ "HLOS Magic Failed", ++ "Tx Inv_dst_if Drops", ++ "Tx Dst_if Enqueue", ++ "Tx Dst_if Enqueue Drops", ++ "Invalid Appid", ++ "Headroom Unavailable", ++ "Tx Completion Host Enqueue Success", ++ "Tx Completion Host Enqueue Drops", ++}; ++ ++/* ++ * nss_gre_redir_mark_stats_cpy() ++ * Fill the stats. ++ */ ++static ssize_t nss_gre_redir_mark_stats_cpy(char *lbuf, int len, int i, struct nss_gre_redir_mark_stats *s) ++{ ++ uint64_t tcnt = 0; ++ ++ switch (i) { ++ case NSS_GRE_REDIR_MARK_STATS_TX_PKTS: ++ tcnt = s->stats[NSS_GRE_REDIR_MARK_STATS_TX_PKTS]; ++ return scnprintf(lbuf, len, "Common node stats start:\n\n%s = %llu\n", nss_gre_redir_mark_stats_str[i], tcnt); ++ case NSS_GRE_REDIR_MARK_STATS_TX_BYTES: ++ tcnt = s->stats[NSS_GRE_REDIR_MARK_STATS_TX_BYTES]; ++ return scnprintf(lbuf, len, "%s = %llu\n", nss_gre_redir_mark_stats_str[i], tcnt); ++ case NSS_GRE_REDIR_MARK_STATS_RX_PKTS: ++ tcnt = s->stats[NSS_GRE_REDIR_MARK_STATS_RX_PKTS]; ++ return scnprintf(lbuf, len, "%s = %llu\n", nss_gre_redir_mark_stats_str[i], tcnt); ++ case NSS_GRE_REDIR_MARK_STATS_RX_BYTES: ++ tcnt = s->stats[NSS_GRE_REDIR_MARK_STATS_RX_BYTES]; ++ return scnprintf(lbuf, len, "%s = %llu\n", nss_gre_redir_mark_stats_str[i], tcnt); ++ case NSS_GRE_REDIR_MARK_STATS_RX_DROPS: ++ tcnt = s->stats[NSS_GRE_REDIR_MARK_STATS_RX_DROPS]; ++ return scnprintf(lbuf, len, "%s = %llu\nCommon node stats end.\n", nss_gre_redir_mark_stats_str[i], tcnt); ++ case NSS_GRE_REDIR_MARK_STATS_HLOS_MAGIC_FAILED: ++ tcnt = s->stats[NSS_GRE_REDIR_MARK_STATS_HLOS_MAGIC_FAILED]; ++ return scnprintf(lbuf, len, "Offload stats start:\n\n%s = %llu\n", nss_gre_redir_mark_stats_str[i], tcnt); ++ case NSS_GRE_REDIR_MARK_STATS_INV_DST_IF_DROPS: ++ tcnt = s->stats[NSS_GRE_REDIR_MARK_STATS_INV_DST_IF_DROPS]; ++ return scnprintf(lbuf, len, "%s = %llu\n", nss_gre_redir_mark_stats_str[i], tcnt); ++ case NSS_GRE_REDIR_MARK_STATS_DST_IF_ENQUEUE: ++ tcnt = s->stats[NSS_GRE_REDIR_MARK_STATS_DST_IF_ENQUEUE]; ++ return scnprintf(lbuf, len, "%s = %llu\n", nss_gre_redir_mark_stats_str[i], tcnt); ++ case NSS_GRE_REDIR_MARK_STATS_DST_IF_ENQUEUE_DROPS: ++ tcnt = s->stats[NSS_GRE_REDIR_MARK_STATS_DST_IF_ENQUEUE_DROPS]; ++ return scnprintf(lbuf, len, "%s = %llu\n", nss_gre_redir_mark_stats_str[i], tcnt); ++ case NSS_GRE_REDIR_MARK_STATS_INV_APPID: ++ tcnt = s->stats[NSS_GRE_REDIR_MARK_STATS_INV_APPID]; ++ return scnprintf(lbuf, len, "%s = %llu\n", nss_gre_redir_mark_stats_str[i], tcnt); ++ case NSS_GRE_REDIR_MARK_STATS_HEADROOM_UNAVAILABLE: ++ tcnt = s->stats[NSS_GRE_REDIR_MARK_STATS_HEADROOM_UNAVAILABLE]; ++ return scnprintf(lbuf, len, "%s = %llu\n", nss_gre_redir_mark_stats_str[i], tcnt); ++ case NSS_GRE_REDIR_MARK_STATS_TX_COMPLETION_SUCCESS: ++ tcnt = s->stats[NSS_GRE_REDIR_MARK_STATS_TX_COMPLETION_SUCCESS]; ++ return scnprintf(lbuf, len, "%s = %llu\n", nss_gre_redir_mark_stats_str[i], tcnt); ++ case NSS_GRE_REDIR_MARK_STATS_TX_COMPLETION_DROPS: ++ tcnt = s->stats[NSS_GRE_REDIR_MARK_STATS_TX_COMPLETION_DROPS]; ++ return scnprintf(lbuf, len, "%s = %llu\nOffload stats end.\n", nss_gre_redir_mark_stats_str[i], tcnt); ++ default: ++ nss_warning("Unknown stats type %d.\n", i); ++ return 0; + } +- +- /* +- * Copy the GRE redir mark stats in the memory. +- */ +- spin_lock_bh(&nss_gre_redir_mark_stats_lock); +- memcpy(stats_mem, &gre_mark_stats, sizeof(struct nss_gre_redir_mark_stats)); +- spin_unlock_bh(&nss_gre_redir_mark_stats_lock); +- return true; + } +-EXPORT_SYMBOL(nss_gre_redir_mark_stats_get); + +-/** ++/* + * nss_gre_redir_mark_stats_read() + * READ GRE redir mark stats. + */ + static ssize_t nss_gre_redir_mark_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) + { +- /* +- * Max output lines = #stats + +- * few blank lines for banner printing + Number of Extra outputlines +- * for future reference to add new stats +- */ +- uint32_t max_output_lines = NSS_GRE_REDIR_MARK_STATS_MAX + NSS_STATS_EXTRA_OUTPUT_LINES; +- size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines; + struct nss_gre_redir_mark_stats stats; + size_t size_wr = 0; ++ int start, end; + ssize_t bytes_read = 0; + bool isthere; ++ size_t size_al = ((NSS_GRE_REDIR_MARK_STATS_MAX + 7 ) * NSS_GRE_REDIR_MARK_STATS_STR_LEN); + + char *lbuf = kzalloc(size_al, GFP_KERNEL); + if (unlikely(!lbuf)) { +@@ -86,16 +117,21 @@ static ssize_t nss_gre_redir_mark_stats_ + /* + * If GRE redir mark does not exists, then (isthere) will be false. + */ +- isthere = nss_gre_redir_mark_stats_get(&stats); ++ isthere = nss_gre_redir_mark_get_stats((void*)&stats); + if (!isthere) { + nss_warning("Could not get GRE redirect stats"); + kfree(lbuf); + return 0; + } + +- size_wr += nss_stats_banner(lbuf, size_wr, size_al, "gre_redir_mark stats", NSS_STATS_SINGLE_CORE); +- size_wr += nss_stats_print("gre_redir_mark", NULL, NSS_STATS_SINGLE_INSTANCE, nss_gre_redir_mark_strings_stats, +- stats.stats, NSS_GRE_REDIR_MARK_STATS_MAX, lbuf, size_wr, size_al); ++ size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\nGRE redir mark stats\n"); ++ ++ start = NSS_GRE_REDIR_MARK_STATS_TX_PKTS; ++ end = NSS_GRE_REDIR_MARK_STATS_MAX; ++ while (start < end) { ++ size_wr += nss_gre_redir_mark_stats_cpy(lbuf + size_wr, size_al - size_wr, start, &stats); ++ start++; ++ } + + bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, size_wr); + +@@ -125,106 +161,3 @@ struct dentry *nss_gre_redir_mark_stats_ + + return gre_redir_mark; + } +- +-/* +- * nss_gre_redir_mark_stats_sync() +- * Update GRE redir mark stats. +- */ +-void nss_gre_redir_mark_stats_sync(struct nss_ctx_instance *nss_ctx, int if_num, struct nss_gre_redir_mark_stats_sync_msg *ngss) +-{ +- int i; +- struct net_device *dev; +- dev = nss_cmn_get_interface_dev(nss_ctx, if_num); +- if (!dev) { +- nss_warning("%px: Unable to find net device for the interface %d\n", nss_ctx, if_num); +- return; +- } +- +- if (if_num != NSS_GRE_REDIR_MARK_INTERFACE) { +- nss_warning("%px: Unknown type for interface %d\n", nss_ctx, if_num); +- return; +- } +- +- /* +- * Update the stats in exclusive mode to prevent the read from the process +- * context through debug fs. +- */ +- spin_lock_bh(&nss_gre_redir_mark_stats_lock); +- +- /* +- * Update the common node stats +- */ +- gre_mark_stats.stats[NSS_STATS_NODE_TX_PKTS] += ngss->node_stats.tx_packets; +- gre_mark_stats.stats[NSS_STATS_NODE_TX_BYTES] += ngss->node_stats.tx_bytes; +- gre_mark_stats.stats[NSS_STATS_NODE_RX_PKTS] += ngss->node_stats.rx_packets; +- gre_mark_stats.stats[NSS_STATS_NODE_RX_BYTES] += ngss->node_stats.rx_bytes; +- for (i = 0; i < NSS_MAX_NUM_PRI; i++) { +- gre_mark_stats.stats[NSS_STATS_NODE_RX_QUEUE_0_DROPPED + i] += ngss->node_stats.rx_dropped[i]; +- } +- +- /* +- * Update the GRE redir mark specific stats +- */ +- gre_mark_stats.stats[NSS_GRE_REDIR_MARK_STATS_HLOS_MAGIC_FAILED] += ngss->hlos_magic_fail; +- gre_mark_stats.stats[NSS_GRE_REDIR_MARK_STATS_INV_DST_IF_DROPS] += ngss->invalid_dst_drop; +- gre_mark_stats.stats[NSS_GRE_REDIR_MARK_STATS_DST_IF_ENQUEUE] += ngss->dst_enqueue_success; +- gre_mark_stats.stats[NSS_GRE_REDIR_MARK_STATS_DST_IF_ENQUEUE_DROPS] += ngss->dst_enqueue_drop; +- gre_mark_stats.stats[NSS_GRE_REDIR_MARK_STATS_INV_APPID] += ngss->inv_appid; +- gre_mark_stats.stats[NSS_GRE_REDIR_MARK_STATS_HEADROOM_UNAVAILABLE] += ngss->headroom_unavail; +- gre_mark_stats.stats[NSS_GRE_REDIR_MARK_STATS_TX_COMPLETION_SUCCESS] += ngss->tx_completion_success; +- gre_mark_stats.stats[NSS_GRE_REDIR_MARK_STATS_TX_COMPLETION_DROPS] += ngss->tx_completion_drop; +- +- spin_unlock_bh(&nss_gre_redir_mark_stats_lock); +-} +- +-/* +- * nss_gre_redir_mark_stats_notify() +- * Sends notifications to all the registered modules. +- * +- * Leverage NSS-FW statistics timing to update Netlink. +- */ +-void nss_gre_redir_mark_stats_notify(struct nss_ctx_instance *nss_ctx, uint32_t if_num) +-{ +- struct nss_gre_redir_mark_stats_notification *stats_notify; +- +- stats_notify = kzalloc(sizeof(struct nss_gre_redir_mark_stats_notification), GFP_ATOMIC); +- if (!stats_notify) { +- nss_warning("Unable to allocate memory for stats notification\n"); +- return; +- } +- +- if (if_num != NSS_GRE_REDIR_MARK_INTERFACE) { +- nss_warning("%px: Unknown type for interface %d\n", nss_ctx, if_num); +- kfree(stats_notify); +- return; +- } +- +- spin_lock_bh(&nss_gre_redir_mark_stats_lock); +- stats_notify->core_id = nss_ctx->id; +- stats_notify->if_num = if_num; +- memcpy(stats_notify->stats_ctx, gre_mark_stats.stats, sizeof(stats_notify->stats_ctx)); +- spin_unlock_bh(&nss_gre_redir_mark_stats_lock); +- +- atomic_notifier_call_chain(&nss_gre_redir_mark_stats_notifier, NSS_STATS_EVENT_NOTIFY, stats_notify); +- kfree(stats_notify); +-} +- +-/* +- * nss_gre_redir_mark_stats_unregister_notifier() +- * Deregisters statistics notifier. +- */ +-int nss_gre_redir_mark_stats_unregister_notifier(struct notifier_block *nb) +-{ +- return atomic_notifier_chain_unregister(&nss_gre_redir_mark_stats_notifier, nb); +-} +-EXPORT_SYMBOL(nss_gre_redir_mark_stats_unregister_notifier); +- +-/* +- * nss_gre_redir_mark_stats_register_notifier() +- * Registers statistics notifier. +- */ +-int nss_gre_redir_mark_stats_register_notifier(struct notifier_block *nb) +-{ +- return atomic_notifier_chain_register(&nss_gre_redir_mark_stats_notifier, nb); +-} +-EXPORT_SYMBOL(nss_gre_redir_mark_stats_register_notifier); +--- a/nss_gre_redir_mark_stats.h ++++ b/nss_gre_redir_mark_stats.h +@@ -1,6 +1,6 @@ + /* + ****************************************************************************** +- * Copyright (c) 2019, 2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -18,6 +18,26 @@ + #define __NSS_GRE_REDIR_MARK_STATS_H__ + + /* ++ * GRE REDIR statistics types ++ */ ++enum nss_gre_redir_mark_stats_types { ++ NSS_GRE_REDIR_MARK_STATS_TX_PKTS, ++ NSS_GRE_REDIR_MARK_STATS_TX_BYTES, ++ NSS_GRE_REDIR_MARK_STATS_RX_PKTS, ++ NSS_GRE_REDIR_MARK_STATS_RX_BYTES, ++ NSS_GRE_REDIR_MARK_STATS_RX_DROPS, ++ NSS_GRE_REDIR_MARK_STATS_HLOS_MAGIC_FAILED, ++ NSS_GRE_REDIR_MARK_STATS_INV_DST_IF_DROPS, ++ NSS_GRE_REDIR_MARK_STATS_DST_IF_ENQUEUE, ++ NSS_GRE_REDIR_MARK_STATS_DST_IF_ENQUEUE_DROPS, ++ NSS_GRE_REDIR_MARK_STATS_INV_APPID, ++ NSS_GRE_REDIR_MARK_STATS_HEADROOM_UNAVAILABLE, ++ NSS_GRE_REDIR_MARK_STATS_TX_COMPLETION_SUCCESS, ++ NSS_GRE_REDIR_MARK_STATS_TX_COMPLETION_DROPS, ++ NSS_GRE_REDIR_MARK_STATS_MAX ++}; ++ ++/* + * NSS core stats -- for H2N/N2H gre_redir_mark debug stats + */ + struct nss_gre_redir_mark_stats { +@@ -27,9 +47,6 @@ struct nss_gre_redir_mark_stats { + /* + * NSS GRE REDIR Mark statistics APIs + */ +-extern void nss_gre_redir_mark_stats_notify(struct nss_ctx_instance *nss_ctx, uint32_t if_num); +-extern void nss_gre_redir_mark_stats_sync(struct nss_ctx_instance *nss_ctx, int if_num, +- struct nss_gre_redir_mark_stats_sync_msg *ngss); + extern struct dentry *nss_gre_redir_mark_stats_dentry_create(void); + + #endif /* __NSS_GRE_REDIR_MARK_STATS_H__ */ +--- a/nss_gre_redir_mark_strings.c ++++ /dev/null +@@ -1,66 +0,0 @@ +-/* +- *************************************************************************** +- * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- *************************************************************************** +- */ +- +-#include "nss_stats.h" +-#include "nss_core.h" +-#include "nss_strings.h" +-#include "nss_gre_redir_mark_strings.h" +- +-/* +- * nss_gre_redir_mark_strings_stats +- * GRE redir mark statistics string +- */ +-struct nss_stats_info nss_gre_redir_mark_strings_stats[NSS_GRE_REDIR_MARK_STATS_MAX] = { +- {"rx Packets", NSS_STATS_TYPE_COMMON}, +- {"rx Bytes", NSS_STATS_TYPE_COMMON}, +- {"tx Packets", NSS_STATS_TYPE_COMMON}, +- {"tx Bytes", NSS_STATS_TYPE_COMMON}, +- {"rx_dropped_0", NSS_STATS_TYPE_DROP}, +- {"rx_dropped_1", NSS_STATS_TYPE_DROP}, +- {"rx_dropped_2", NSS_STATS_TYPE_DROP}, +- {"rx_dropped_3", NSS_STATS_TYPE_DROP}, +- {"HLOS Magic Failed", NSS_STATS_TYPE_SPECIAL}, +- {"tx Inv_dst_if Drops", NSS_STATS_TYPE_DROP}, +- {"tx Dst_if Enqueue", NSS_STATS_TYPE_SPECIAL}, +- {"tx Dst_if Enqueue Drops", NSS_STATS_TYPE_DROP}, +- {"Invalid Appid", NSS_STATS_TYPE_SPECIAL}, +- {"Headroom Unavailable", NSS_STATS_TYPE_EXCEPTION}, +- {"tx Completion Host Enqueue Success", NSS_STATS_TYPE_SPECIAL}, +- {"tx Completion Host Enqueue Drops", NSS_STATS_TYPE_DROP} +-}; +- +-/* +- * nss_gre_redir_mark_strings_read() +- * Read gre_redir_mark statistics names +- */ +-static ssize_t nss_gre_redir_mark_strings_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- return nss_strings_print(ubuf, sz, ppos, nss_gre_redir_mark_strings_stats, NSS_GRE_REDIR_MARK_STATS_MAX); +-} +- +-/* +- * nss_gre_redir_mark_strings_ops +- */ +-NSS_STRINGS_DECLARE_FILE_OPERATIONS(gre_redir_mark); +- +-/* +- * nss_gre_redir_mark_strings_dentry_create() +- * Create gre_redir_mark statistics strings debug entry. +- */ +-void nss_gre_redir_mark_strings_dentry_create(void) +-{ +- nss_strings_create_dentry("gre_redir_mark", &nss_gre_redir_mark_strings_ops); +-} +--- a/nss_gre_redir_mark_strings.h ++++ /dev/null +@@ -1,25 +0,0 @@ +-/* +- **************************************************************************** +- * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- **************************************************************************** +- */ +- +-#ifndef __NSS_GRE_REDIR_MARK_STRINGS_H +-#define __NSS_GRE_REDIR_MARK_STRINGS_H +- +-#include "nss_gre_redir_mark_stats.h" +- +-extern struct nss_stats_info nss_gre_redir_mark_strings_stats[NSS_GRE_REDIR_MARK_STATS_MAX]; +-extern void nss_gre_redir_mark_strings_dentry_create(void); +- +-#endif /* __NSS_GRE_REDIR_MARK_STRINGS_H */ +--- a/nss_gre_redir_stats.c ++++ b/nss_gre_redir_stats.c +@@ -1,6 +1,6 @@ + /* +- **************************************************************************** +- * Copyright (c) 2017-2019, 2021, The Linux Foundation. All rights reserved. ++ ************************************************************************** ++ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -11,46 +11,146 @@ + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- **************************************************************************** ++ ************************************************************************** + */ + + #include "nss_core.h" + #include "nss_gre_redir.h" + #include "nss_gre_redir_stats.h" +-#include "nss_gre_redir_strings.h" + + /* +- * Declare atomic notifier data structure for statistics. ++ * nss_gre_redir_stats_str ++ * GRE REDIR statistics string + */ +-ATOMIC_NOTIFIER_HEAD(nss_gre_redir_stats_notifier); ++static int8_t *nss_gre_redir_stats_str[NSS_GRE_REDIR_STATS_MAX] = { ++ "TX Packets", ++ "TX Bytes", ++ "TX Drops", ++ "RX Packets", ++ "RX Bytes", ++ "RX Drops", ++ "TX Sjack Packets", ++ "RX Sjack packets", ++ "TX Offload Packets", ++ "RX Offload Packets", ++ "US exception RX Packets", ++ "US exception TX Packets", ++ "DS exception RX Packets", ++ "DS exception TX Packets", ++ "Encap SG alloc drop", ++ "Decap fail drop", ++ "Decap split drop", ++ "Split SG alloc fail", ++ "Split linear copy fail", ++ "Split not enough tailroom", ++ "Exception ds invalid dst", ++ "Decap eapol frames", ++ "Exception ds invalid appid", ++ "Headroom Unavailable", ++ "Exception ds Tx completion Success", ++ "Exception ds Tx completion drop" ++}; + + /* +- * Spinlock to protect GRE redirect statistics update/read ++ * nss_gre_redir_stats() ++ * Make a row for GRE_REDIR stats. + */ +-DEFINE_SPINLOCK(nss_gre_redir_stats_lock); +- +-/* +- * Array to hold tunnel stats along with if_num +- */ +-extern struct nss_gre_redir_tunnel_stats tun_stats[NSS_GRE_REDIR_MAX_INTERFACES]; +- +-/* +- * nss_gre_redir_stats_get() +- * Get GRE redirect tunnel stats. +- */ +-bool nss_gre_redir_stats_get(int index, struct nss_gre_redir_tunnel_stats *stats) ++static ssize_t nss_gre_redir_stats(char *line, int len, int i, struct nss_gre_redir_tunnel_stats *s) + { +- spin_lock_bh(&nss_gre_redir_stats_lock); +- if (tun_stats[index].ref_count == 0) { +- spin_unlock_bh(&nss_gre_redir_stats_lock); +- return false; ++ char name[40]; ++ uint64_t tcnt = 0; ++ int j = 0; ++ ++ switch (i) { ++ case NSS_GRE_REDIR_STATS_TX_PKTS: ++ tcnt = s->node_stats.tx_packets; ++ return snprintf(line, len, "Common node stats start:\n\n%s = %llu\n", nss_gre_redir_stats_str[i], tcnt); ++ case NSS_GRE_REDIR_STATS_TX_BYTES: ++ tcnt = s->node_stats.tx_bytes; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_stats_str[i], tcnt); ++ case NSS_GRE_REDIR_STATS_TX_DROPS: ++ tcnt = s->tx_dropped; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_stats_str[i], tcnt); ++ case NSS_GRE_REDIR_STATS_RX_PKTS: ++ tcnt = s->node_stats.rx_packets; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_stats_str[i], tcnt); ++ case NSS_GRE_REDIR_STATS_RX_BYTES: ++ tcnt = s->node_stats.rx_bytes; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_stats_str[i], tcnt); ++ case NSS_GRE_REDIR_STATS_RX_DROPS: ++ tcnt = s->node_stats.rx_dropped[0]; ++ return snprintf(line, len, "%s = %llu\nCommon node stats end.\n", nss_gre_redir_stats_str[i], tcnt); ++ case NSS_GRE_REDIR_STATS_SJACK_TX_PKTS: ++ tcnt = s->sjack_tx_packets; ++ return snprintf(line, len, "Offload stats start:\n\n%s = %llu\n", nss_gre_redir_stats_str[i], tcnt); ++ case NSS_GRE_REDIR_STATS_OFFLOAD_TX_PKTS: ++ for (j = 0; j < NSS_GRE_REDIR_MAX_RADIO; j++) { ++ scnprintf(name, sizeof(name), "TX offload pkts for radio %d", j); ++ tcnt += snprintf(line + tcnt, len - tcnt, "%s = %llu\n", name, s->offl_tx_pkts[j]); ++ } ++ return tcnt; ++ case NSS_GRE_REDIR_STATS_SJACK_RX_PKTS: ++ tcnt = s->sjack_rx_packets; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_stats_str[i], tcnt); ++ case NSS_GRE_REDIR_STATS_OFFLOAD_RX_PKTS: ++ for (j = 0; j < NSS_GRE_REDIR_MAX_RADIO; j++) { ++ scnprintf(name, sizeof(name), "RX offload pkts for radio %d", j); ++ tcnt += snprintf(line + tcnt, len - tcnt, "%s = %llu\n", name, s->offl_rx_pkts[j]); ++ } ++ return tcnt; ++ case NSS_GRE_REDIR_STATS_EXCEPTION_US_RX_PKTS: ++ tcnt = s->exception_us_rx; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_stats_str[i], tcnt); ++ case NSS_GRE_REDIR_STATS_EXCEPTION_US_TX_PKTS: ++ tcnt = s->exception_us_tx; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_stats_str[i], tcnt); ++ case NSS_GRE_REDIR_STATS_EXCEPTION_DS_RX_PKTS: ++ tcnt = s->exception_ds_rx; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_stats_str[i], tcnt); ++ case NSS_GRE_REDIR_STATS_EXCEPTION_DS_TX_PKTS: ++ tcnt = s->exception_ds_tx; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_stats_str[i], tcnt); ++ case NSS_GRE_REDIR_STATS_ENCAP_SG_ALLOC_DROP: ++ tcnt = s->encap_sg_alloc_drop; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_stats_str[i], tcnt); ++ case NSS_GRE_REDIR_STATS_DECAP_FAIL_DROP: ++ tcnt = s->decap_fail_drop; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_stats_str[i], tcnt); ++ case NSS_GRE_REDIR_STATS_DECAP_SPLIT_DROP: ++ tcnt = s->decap_split_drop; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_stats_str[i], tcnt); ++ case NSS_GRE_REDIR_STATS_SPLIT_SG_ALLOC_FAIL: ++ tcnt = s->split_sg_alloc_fail; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_stats_str[i], tcnt); ++ case NSS_GRE_REDIR_STATS_SPLIT_LINEAR_COPY_FAIL: ++ tcnt = s->split_linear_copy_fail; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_stats_str[i], tcnt); ++ case NSS_GRE_REDIR_STATS_SPLIT_NOT_ENOUGH_TAILROOM: ++ tcnt = s->split_not_enough_tailroom; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_stats_str[i], tcnt); ++ case NSS_GRE_REDIR_STATS_EXCEPTION_DS_INVALID_DST_DROP: ++ tcnt = s->exception_ds_invalid_dst_drop; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_stats_str[i], tcnt); ++ case NSS_GRE_REDIR_STATS_DECAP_EAPOL_FRAMES: ++ tcnt = s->decap_eapol_frames; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_stats_str[i], tcnt); ++ case NSS_GRE_REDIR_STATS_EXCEPTION_DS_INV_APPID: ++ tcnt = s->exception_ds_inv_appid; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_stats_str[i], tcnt); ++ case NSS_GRE_REDIR_STATS_HEADROOM_UNAVAILABLE: ++ tcnt = s->headroom_unavail; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_stats_str[i], tcnt); ++ case NSS_GRE_REDIR_STATS_TX_COMPLETION_SUCCESS: ++ tcnt = s->tx_completion_success; ++ return snprintf(line, len, "%s = %llu\n", nss_gre_redir_stats_str[i], tcnt); ++ case NSS_GRE_REDIR_STATS_TX_COMPLETION_DROP: ++ tcnt = s->tx_completion_drop; ++ return snprintf(line, len, "%s = %llu\nOffload stats end.\n", nss_gre_redir_stats_str[i], tcnt); ++ default: ++ nss_warning("Unknown stats type %d.\n", i); ++ return 0; + } +- +- memcpy(stats, &tun_stats[index], sizeof(struct nss_gre_redir_tunnel_stats)); +- spin_unlock_bh(&nss_gre_redir_stats_lock); +- return true; + } +-EXPORT_SYMBOL(nss_gre_redir_stats_get); + + /* + * nss_gre_redir_stats_read() +@@ -58,25 +158,14 @@ EXPORT_SYMBOL(nss_gre_redir_stats_get); + */ + static ssize_t nss_gre_redir_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) + { +- /* +- * Max output lines = #stats + +- * few blank lines for banner printing + Number of Extra outputlines +- * for future reference to add new stats +- */ +- uint32_t max_output_lines = NSS_GRE_REDIR_STATS_MAX + NSS_STATS_EXTRA_OUTPUT_LINES; +- size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines * NSS_GRE_REDIR_MAX_INTERFACES; + struct nss_stats_data *data = fp->private_data; +- struct nss_gre_redir_tunnel_stats stats; + ssize_t bytes_read = 0; +- size_t size_wr = 0; ++ struct nss_gre_redir_tunnel_stats stats; ++ size_t bytes; ++ char line[80 * NSS_GRE_REDIR_MAX_RADIO]; ++ int start, end; + int index = 0; + +- char *lbuf = kzalloc(size_al, GFP_KERNEL); +- if (unlikely(!lbuf)) { +- nss_warning("Could not allocate memory for local statistics buffer"); +- return 0; +- } +- + if (data) { + index = data->index; + } +@@ -85,7 +174,6 @@ static ssize_t nss_gre_redir_stats_read( + * If we are done accomodating all the GRE_REDIR tunnels. + */ + if (index >= NSS_GRE_REDIR_MAX_INTERFACES) { +- kfree(lbuf); + return 0; + } + +@@ -95,23 +183,48 @@ static ssize_t nss_gre_redir_stats_read( + /* + * If gre_redir tunnel does not exists, then isthere will be false. + */ +- isthere = nss_gre_redir_stats_get(index, &stats); ++ isthere = nss_gre_redir_get_stats(index, &stats); + if (!isthere) { + continue; + } + +- size_wr += nss_stats_banner(lbuf, size_wr, size_al, "gre_redir stats", NSS_STATS_SINGLE_CORE); +- size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\nTunnel stats for %s\n", stats.dev->name); +- size_wr += nss_stats_print("gre_redir", NULL, NSS_STATS_SINGLE_INSTANCE, nss_gre_redir_strings_stats, +- &stats.tstats.rx_packets, NSS_GRE_REDIR_STATS_MAX, lbuf, size_wr, size_al); ++ bytes = snprintf(line, sizeof(line), "\nTunnel stats for %s\n", stats.dev->name); ++ if ((bytes_read + bytes) > sz) { ++ break; ++ } ++ ++ if (copy_to_user(ubuf + bytes_read, line, bytes) != 0) { ++ bytes_read = -EFAULT; ++ goto fail; ++ } ++ bytes_read += bytes; ++ start = NSS_GRE_REDIR_STATS_TX_PKTS; ++ end = NSS_GRE_REDIR_STATS_MAX; ++ while (bytes_read < sz && start < end) { ++ bytes = nss_gre_redir_stats(line, sizeof(line), start, &stats); ++ ++ if ((bytes_read + bytes) > sz) ++ break; ++ ++ if (copy_to_user(ubuf + bytes_read, line, bytes) != 0) { ++ bytes_read = -EFAULT; ++ goto fail; ++ } ++ ++ bytes_read += bytes; ++ start++; ++ } ++ } ++ ++ if (bytes_read > 0) { ++ *ppos = bytes_read; + } + +- bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf)); + if (data) { + data->index = index; + } + +- kfree(lbuf); ++fail: + return bytes_read; + } + +@@ -145,168 +258,3 @@ struct dentry *nss_gre_redir_stats_dentr + + return gre_redir; + } +- +-/* +- * nss_gre_redir_stats_sync() +- * Update gre_redir tunnel stats. +- */ +-void nss_gre_redir_stats_sync(struct nss_ctx_instance *nss_ctx, int if_num, struct nss_gre_redir_stats_sync_msg *ngss) +-{ +- int i, j; +- uint32_t type; +- struct net_device *dev; +- struct nss_gre_redir_tun_stats *node_stats; +- +- type = nss_dynamic_interface_get_type(nss_ctx, if_num); +- dev = nss_cmn_get_interface_dev(nss_ctx, if_num); +- if (!dev) { +- nss_warning("%px: Unable to find net device for the interface %d\n", nss_ctx, if_num); +- return; +- } +- +- if (!nss_gre_redir_verify_ifnum(if_num)) { +- nss_warning("%px: Unknown type for interface %d\n", nss_ctx, if_num); +- return; +- } +- +- spin_lock_bh(&nss_gre_redir_stats_lock); +- for (i = 0; i < NSS_GRE_REDIR_MAX_INTERFACES; i++) { +- if (tun_stats[i].dev == dev) { +- break; +- } +- } +- +- if (i == NSS_GRE_REDIR_MAX_INTERFACES) { +- nss_warning("%px: Unable to find tunnel stats instance for interface %d\n", nss_ctx, if_num); +- spin_unlock_bh(&nss_gre_redir_stats_lock); +- return; +- } +- +- nss_assert(tun_stats[i].ref_count); +- node_stats = &tun_stats[i].tstats; +- switch (type) { +- case NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_WIFI_HOST_INNER: +- case NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_WIFI_OFFL_INNER: +- case NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_SJACK_INNER: +- node_stats->tx_packets += ngss->node_stats.tx_packets; +- node_stats->tx_bytes += ngss->node_stats.tx_bytes; +- node_stats->sjack_tx_packets += ngss->sjack_rx_packets; +- node_stats->encap_sg_alloc_drop += ngss->encap_sg_alloc_drop; +- node_stats->tx_dropped += nss_cmn_rx_dropped_sum(&(ngss->node_stats)); +- for (j = 0; j < NSS_GRE_REDIR_MAX_RADIO; j++) { +- node_stats->offl_tx_pkts[j] += ngss->offl_rx_pkts[j]; +- } +- +- break; +- +- case NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_OUTER: +- node_stats->rx_packets += ngss->node_stats.rx_packets; +- node_stats->rx_bytes += ngss->node_stats.rx_bytes; +- node_stats->sjack_rx_packets += ngss->sjack_rx_packets; +- node_stats->decap_fail_drop += ngss->decap_fail_drop; +- node_stats->decap_split_drop += ngss->decap_split_drop; +- node_stats->split_sg_alloc_fail += ngss->split_sg_alloc_fail; +- node_stats->split_linear_copy_fail += ngss->split_linear_copy_fail; +- node_stats->split_not_enough_tailroom += ngss->split_not_enough_tailroom; +- node_stats->decap_eapol_frames += ngss->decap_eapol_frames; +- for (j = 0; j < NSS_MAX_NUM_PRI; j++) { +- node_stats->rx_dropped[j] += ngss->node_stats.rx_dropped[j]; +- } +- +- for (j = 0; j < NSS_GRE_REDIR_MAX_RADIO; j++) { +- node_stats->offl_rx_pkts[j] += ngss->offl_rx_pkts[j]; +- } +- +- break; +- +- case NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_EXCEPTION_US: +- node_stats->exception_us_rx += ngss->node_stats.rx_packets; +- node_stats->exception_us_tx += ngss->node_stats.tx_packets; +- break; +- +- case NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_EXCEPTION_DS: +- node_stats->exception_ds_rx += ngss->node_stats.rx_packets; +- node_stats->exception_ds_tx += ngss->node_stats.tx_packets; +- node_stats->exception_ds_invalid_dst_drop += ngss->exception_ds_invalid_dst_drop; +- node_stats->exception_ds_inv_appid += ngss->exception_ds_inv_appid; +- node_stats->headroom_unavail += ngss->headroom_unavail; +- node_stats->tx_completion_success += ngss->tx_completion_success; +- node_stats->tx_completion_drop += ngss->tx_completion_drop; +- break; +- } +- +- spin_unlock_bh(&nss_gre_redir_stats_lock); +-} +- +-/* +- * nss_gre_redir_stats_notify() +- * Sends notifications to all the registered modules. +- * +- * Leverage NSS-FW statistics timing to update Netlink. +- */ +-void nss_gre_redir_stats_notify(struct nss_ctx_instance *nss_ctx, uint32_t if_num) +-{ +- struct nss_gre_redir_stats_notification *stats_notify; +- struct net_device *dev; +- int i; +- +- stats_notify = kzalloc(sizeof(struct nss_gre_redir_stats_notification), GFP_ATOMIC); +- if (!stats_notify) { +- nss_warning("Unable to allocate memory for stats notification\n"); +- return; +- } +- +- dev = nss_cmn_get_interface_dev(nss_ctx, if_num); +- if (!dev) { +- nss_warning("%px: Unable to find net device for the interface %d\n", nss_ctx, if_num); +- kfree(stats_notify); +- return; +- } +- +- if (!nss_gre_redir_verify_ifnum(if_num)) { +- nss_warning("%px: Unknown type for interface %d\n", nss_ctx, if_num); +- kfree(stats_notify); +- return; +- } +- +- spin_lock_bh(&nss_gre_redir_stats_lock); +- for (i = 0; i < NSS_GRE_REDIR_MAX_INTERFACES; i++) { +- if (tun_stats[i].dev == dev) { +- break; +- } +- } +- +- if (i == NSS_GRE_REDIR_MAX_INTERFACES) { +- nss_warning("%px: Unable to find tunnel stats instance for interface %d\n", nss_ctx, if_num); +- spin_unlock_bh(&nss_gre_redir_stats_lock); +- kfree(stats_notify); +- return; +- } +- +- stats_notify->core_id = nss_ctx->id; +- stats_notify->if_num = if_num; +- memcpy(&(stats_notify->stats_ctx), &(tun_stats[i]), sizeof(stats_notify->stats_ctx)); +- spin_unlock_bh(&nss_gre_redir_stats_lock); +- atomic_notifier_call_chain(&nss_gre_redir_stats_notifier, NSS_STATS_EVENT_NOTIFY, stats_notify); +- kfree(stats_notify); +-} +- +-/* +- * nss_gre_redir_stats_unregister_notifier() +- * Degisters statistics notifier. +- */ +-int nss_gre_redir_stats_unregister_notifier(struct notifier_block *nb) +-{ +- return atomic_notifier_chain_unregister(&nss_gre_redir_stats_notifier, nb); +-} +-EXPORT_SYMBOL(nss_gre_redir_stats_unregister_notifier); +- +-/* +- * nss_gre_redir_stats_register_notifier() +- * Registers statistics notifier. +- */ +-int nss_gre_redir_stats_register_notifier(struct notifier_block *nb) +-{ +- return atomic_notifier_chain_register(&nss_gre_redir_stats_notifier, nb); +-} +-EXPORT_SYMBOL(nss_gre_redir_stats_register_notifier); +--- a/nss_gre_redir_stats.h ++++ b/nss_gre_redir_stats.h +@@ -1,6 +1,6 @@ + /* + ****************************************************************************** +- * Copyright (c) 2017-2019, 2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -18,13 +18,41 @@ + #define __NSS_GRE_REDIR_STATS_H__ + + /* ++ * GRE REDIR statistics ++ */ ++enum nss_gre_redir_stats_types { ++ NSS_GRE_REDIR_STATS_TX_PKTS, ++ NSS_GRE_REDIR_STATS_TX_BYTES, ++ NSS_GRE_REDIR_STATS_TX_DROPS, ++ NSS_GRE_REDIR_STATS_RX_PKTS, ++ NSS_GRE_REDIR_STATS_RX_BYTES, ++ NSS_GRE_REDIR_STATS_RX_DROPS, ++ NSS_GRE_REDIR_STATS_SJACK_TX_PKTS, ++ NSS_GRE_REDIR_STATS_SJACK_RX_PKTS, ++ NSS_GRE_REDIR_STATS_OFFLOAD_TX_PKTS, ++ NSS_GRE_REDIR_STATS_OFFLOAD_RX_PKTS, ++ NSS_GRE_REDIR_STATS_EXCEPTION_US_RX_PKTS, ++ NSS_GRE_REDIR_STATS_EXCEPTION_US_TX_PKTS, ++ NSS_GRE_REDIR_STATS_EXCEPTION_DS_RX_PKTS, ++ NSS_GRE_REDIR_STATS_EXCEPTION_DS_TX_PKTS, ++ NSS_GRE_REDIR_STATS_ENCAP_SG_ALLOC_DROP, ++ NSS_GRE_REDIR_STATS_DECAP_FAIL_DROP, ++ NSS_GRE_REDIR_STATS_DECAP_SPLIT_DROP, ++ NSS_GRE_REDIR_STATS_SPLIT_SG_ALLOC_FAIL, ++ NSS_GRE_REDIR_STATS_SPLIT_LINEAR_COPY_FAIL, ++ NSS_GRE_REDIR_STATS_SPLIT_NOT_ENOUGH_TAILROOM, ++ NSS_GRE_REDIR_STATS_EXCEPTION_DS_INVALID_DST_DROP, ++ NSS_GRE_REDIR_STATS_DECAP_EAPOL_FRAMES, ++ NSS_GRE_REDIR_STATS_EXCEPTION_DS_INV_APPID, ++ NSS_GRE_REDIR_STATS_HEADROOM_UNAVAILABLE, ++ NSS_GRE_REDIR_STATS_TX_COMPLETION_SUCCESS, ++ NSS_GRE_REDIR_STATS_TX_COMPLETION_DROP, ++ NSS_GRE_REDIR_STATS_MAX ++}; ++ ++/* + * NSS GRE REDIR statistics APIs + */ +-extern spinlock_t nss_gre_redir_stats_lock; +-extern bool nss_gre_redir_verify_ifnum(uint32_t if_num); +-extern void nss_gre_redir_stats_notify(struct nss_ctx_instance *nss_ctx, uint32_t if_num); +-extern void nss_gre_redir_stats_sync(struct nss_ctx_instance *nss_ctx, int if_num, +- struct nss_gre_redir_stats_sync_msg *ngss); + extern struct dentry *nss_gre_redir_stats_dentry_create(void); + + #endif /* __NSS_GRE_REDIR_STATS_H__ */ +--- a/nss_gre_redir_strings.c ++++ /dev/null +@@ -1,87 +0,0 @@ +-/* +- *************************************************************************** +- * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- *************************************************************************** +- */ +- +-#include "nss_stats.h" +-#include "nss_core.h" +-#include "nss_strings.h" +-#include "nss_gre_redir_strings.h" +- +-/* +- * nss_gre_redir_strings_stats +- * GRE redirect statistics string. +- */ +-struct nss_stats_info nss_gre_redir_strings_stats[NSS_GRE_REDIR_STATS_MAX] = { +- {"RX Packets", NSS_STATS_TYPE_COMMON}, +- {"RX Bytes", NSS_STATS_TYPE_COMMON}, +- {"TX Packets", NSS_STATS_TYPE_COMMON}, +- {"TX Bytes", NSS_STATS_TYPE_COMMON}, +- {"RX Drops_[0]", NSS_STATS_TYPE_DROP}, +- {"RX Drops_[1]", NSS_STATS_TYPE_DROP}, +- {"RX Drops_[2]", NSS_STATS_TYPE_DROP}, +- {"RX Drops_[3]", NSS_STATS_TYPE_DROP}, +- {"TX Drops", NSS_STATS_TYPE_DROP}, +- {"RX Sjack Packets", NSS_STATS_TYPE_SPECIAL}, +- {"TX Sjack packets", NSS_STATS_TYPE_SPECIAL}, +- {"RX Offload Packets_[0]", NSS_STATS_TYPE_SPECIAL}, +- {"RX Offload Packets_[1]", NSS_STATS_TYPE_SPECIAL}, +- {"RX Offload Packets_[2]", NSS_STATS_TYPE_SPECIAL}, +- {"RX Offload Packets_[3]", NSS_STATS_TYPE_SPECIAL}, +- {"RX Offload Packets_[4]", NSS_STATS_TYPE_SPECIAL}, +- {"TX Offload Packets_[0]", NSS_STATS_TYPE_SPECIAL}, +- {"TX Offload Packets_[1]", NSS_STATS_TYPE_SPECIAL}, +- {"TX Offload Packets_[2]", NSS_STATS_TYPE_SPECIAL}, +- {"TX Offload Packets_[3]", NSS_STATS_TYPE_SPECIAL}, +- {"TX Offload Packets_[4]", NSS_STATS_TYPE_SPECIAL}, +- {"US exception RX Packets", NSS_STATS_TYPE_EXCEPTION}, +- {"US exception TX Packets", NSS_STATS_TYPE_EXCEPTION}, +- {"DS exception RX Packets", NSS_STATS_TYPE_EXCEPTION}, +- {"DS exception TX Packets", NSS_STATS_TYPE_EXCEPTION}, +- {"Encap SG alloc drop", NSS_STATS_TYPE_DROP}, +- {"Decap fail drop", NSS_STATS_TYPE_DROP}, +- {"Decap split drop", NSS_STATS_TYPE_SPECIAL}, +- {"Split SG alloc fail", NSS_STATS_TYPE_SPECIAL}, +- {"Split linear copy fail", NSS_STATS_TYPE_SPECIAL}, +- {"Split not enough tailroom", NSS_STATS_TYPE_EXCEPTION}, +- {"Exception ds invalid dst", NSS_STATS_TYPE_SPECIAL}, +- {"Decap eapol frames", NSS_STATS_TYPE_SPECIAL}, +- {"Exception ds invalid appid", NSS_STATS_TYPE_EXCEPTION}, +- {"Headroom Unavailable", NSS_STATS_TYPE_EXCEPTION}, +- {"Exception ds Tx completion Success", NSS_STATS_TYPE_SPECIAL}, +- {"Exception ds Tx completion drop", NSS_STATS_TYPE_DROP} +-}; +- +-/* +- * nss_gre_redir_strings_read() +- * Read GRE redirect statistics names. +- */ +-static ssize_t nss_gre_redir_strings_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- return nss_strings_print(ubuf, sz, ppos, nss_gre_redir_strings_stats, NSS_GRE_REDIR_STATS_MAX); +-} +- +-/* +- * nss_gre_redir_strings_ops +- */ +-NSS_STRINGS_DECLARE_FILE_OPERATIONS(gre_redir); +- +-/* +- * nss_gre_redir_strings_dentry_create() +- * Create GRE redirect statistics strings debug entry. +- */ +-void nss_gre_redir_strings_dentry_create(void) +-{ +- nss_strings_create_dentry("gre_redir", &nss_gre_redir_strings_ops); +-} +--- a/nss_gre_redir_strings.h ++++ /dev/null +@@ -1,25 +0,0 @@ +-/* +- *************************************************************************** +- * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- *************************************************************************** +- */ +- +-#ifndef __NSS_GRE_REDIR_STRINGS_H +-#define __NSS_GRE_REDIR_STRINGS_H +- +-#include "nss_gre_redir_stats.h" +- +-extern struct nss_stats_info nss_gre_redir_strings_stats[NSS_GRE_REDIR_STATS_MAX]; +-extern void nss_gre_redir_strings_dentry_create(void); +- +-#endif /* __NSS_GRE_REDIR_STRINGS_H */ +--- a/nss_gre_stats.c ++++ b/nss_gre_stats.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -21,38 +21,77 @@ + */ + + #include "nss_tx_rx_common.h" +-#include "nss_gre.h" + #include "nss_gre_stats.h" +-#include "nss_gre_strings.h" + + /* +- * Declare atomic notifier data structure for statistics. ++ * Data structures to store GRE nss debug stats + */ +-ATOMIC_NOTIFIER_HEAD(nss_gre_stats_notifier); ++static DEFINE_SPINLOCK(nss_gre_stats_lock); ++static struct nss_gre_stats_session_debug session_debug_stats[NSS_GRE_MAX_DEBUG_SESSION_STATS]; ++static struct nss_gre_stats_base_debug base_debug_stats; + + /* +- * Data structures to store GRE nss debug stats ++ * nss_gre_stats_base_debug_str ++ * GRE debug statistics strings for base types + */ +-static DEFINE_SPINLOCK(nss_gre_stats_lock); +-static struct nss_gre_stats_session session_stats[NSS_GRE_MAX_DEBUG_SESSION_STATS]; +-static struct nss_gre_stats_base base_stats; ++struct nss_stats_info nss_gre_stats_base_debug_str[NSS_GRE_STATS_BASE_DEBUG_MAX] = { ++ {"base_rx_pkts" ,NSS_STATS_TYPE_COMMON}, ++ {"base_rx_drops" ,NSS_STATS_TYPE_DROP}, ++ {"base_exp_eth_hdr_missing" ,NSS_STATS_TYPE_EXCEPTION}, ++ {"base_exp_eth_type_non_ip" ,NSS_STATS_TYPE_EXCEPTION}, ++ {"base_exp_ip_unknown_protocol" ,NSS_STATS_TYPE_EXCEPTION}, ++ {"base_exp_ip_header_incomplete" ,NSS_STATS_TYPE_EXCEPTION}, ++ {"base_exp_ip_bad_total_length" ,NSS_STATS_TYPE_EXCEPTION}, ++ {"base_exp_ip_bad_checksum" ,NSS_STATS_TYPE_EXCEPTION}, ++ {"base_exp_ip_datagram_incomplete" ,NSS_STATS_TYPE_EXCEPTION}, ++ {"base_exp_ip_fragment" ,NSS_STATS_TYPE_EXCEPTION}, ++ {"base_exp_ip_options_incomplete" ,NSS_STATS_TYPE_EXCEPTION}, ++ {"base_exp_ip_with_options" ,NSS_STATS_TYPE_EXCEPTION}, ++ {"base_exp_ipv6_unknown_protocol" ,NSS_STATS_TYPE_EXCEPTION}, ++ {"base_exp_ipv6_header_incomplete" ,NSS_STATS_TYPE_EXCEPTION}, ++ {"base_exp_unknown_session" ,NSS_STATS_TYPE_EXCEPTION}, ++ {"base_exp_node_inactive" ,NSS_STATS_TYPE_EXCEPTION} ++}; ++ ++/* ++ * nss_gre_stats_session_debug_str ++ * GRE debug statistics strings for sessions ++ */ ++struct nss_stats_info nss_gre_stats_session_debug_str[NSS_GRE_STATS_SESSION_DEBUG_MAX] = { ++ {"session_pbuf_alloc_fail" , NSS_STATS_TYPE_ERROR}, ++ {"session_decap_forward_enqueue_fail" , NSS_STATS_TYPE_DROP}, ++ {"session_encap_forward_enqueue_fail" , NSS_STATS_TYPE_DROP}, ++ {"session_decap_tx_forwarded" , NSS_STATS_TYPE_SPECIAL}, ++ {"session_encap_rx_received" , NSS_STATS_TYPE_SPECIAL}, ++ {"session_encap_rx_drops" , NSS_STATS_TYPE_DROP}, ++ {"session_encap_rx_linear_fail" , NSS_STATS_TYPE_DROP}, ++ {"session_exp_rx_key_error" , NSS_STATS_TYPE_EXCEPTION}, ++ {"session_exp_rx_seq_error" , NSS_STATS_TYPE_EXCEPTION}, ++ {"session_exp_rx_cs_error" , NSS_STATS_TYPE_EXCEPTION}, ++ {"session_exp_rx_flag_mismatch" , NSS_STATS_TYPE_EXCEPTION}, ++ {"session_exp_rx_malformed" , NSS_STATS_TYPE_EXCEPTION}, ++ {"session_exp_rx_invalid_protocol" , NSS_STATS_TYPE_EXCEPTION}, ++ {"session_exp_rx_no_headroom" , NSS_STATS_TYPE_EXCEPTION} ++}; + + /* + * GRE statistics APIs + */ + + /* +- * nss_gre_stats_session_unregister() +- * Unregister debug statistic for GRE session. ++ * nss_gre_stats_session_register() ++ * Register debug statistic for GRE session. + */ +-void nss_gre_stats_session_unregister(uint32_t if_num) ++void nss_gre_stats_session_register(uint32_t if_num, struct net_device *netdev) + { + int i; + + spin_lock_bh(&nss_gre_stats_lock); + for (i = 0; i < NSS_GRE_MAX_DEBUG_SESSION_STATS; i++) { +- if (session_stats[i].if_num == if_num) { +- memset(&session_stats[i], 0, sizeof(struct nss_gre_stats_session)); ++ if (!session_debug_stats[i].valid) { ++ session_debug_stats[i].valid = true; ++ session_debug_stats[i].if_num = if_num; ++ session_debug_stats[i].if_index = netdev->ifindex; + break; + } + } +@@ -60,19 +99,17 @@ void nss_gre_stats_session_unregister(ui + } + + /* +- * nss_gre_stats_session_register() +- * Register debug statistic for GRE session. ++ * nss_gre_stats_session_unregister() ++ * Unregister debug statistic for GRE session. + */ +-void nss_gre_stats_session_register(uint32_t if_num, struct net_device *netdev) ++void nss_gre_stats_session_unregister(uint32_t if_num) + { + int i; + + spin_lock_bh(&nss_gre_stats_lock); + for (i = 0; i < NSS_GRE_MAX_DEBUG_SESSION_STATS; i++) { +- if (!session_stats[i].valid) { +- session_stats[i].valid = true; +- session_stats[i].if_num = if_num; +- session_stats[i].if_index = netdev->ifindex; ++ if (session_debug_stats[i].if_num == if_num) { ++ memset(&session_debug_stats[i], 0, sizeof(struct nss_gre_stats_session_debug)); + break; + } + } +@@ -80,25 +117,25 @@ void nss_gre_stats_session_register(uint + } + + /* +- * nss_gre_stats_session_sync() ++ * nss_gre_stats_session_debug_sync() + * debug statistics sync for GRE session. + */ +-void nss_gre_stats_session_sync(struct nss_ctx_instance *nss_ctx, struct nss_gre_session_stats_msg *sstats, uint16_t if_num) ++void nss_gre_stats_session_debug_sync(struct nss_ctx_instance *nss_ctx, struct nss_gre_session_stats_msg *sstats, uint16_t if_num) + { + int i, j; + enum nss_dynamic_interface_type interface_type = nss_dynamic_interface_get_type(nss_ctx, if_num); + + spin_lock_bh(&nss_gre_stats_lock); + for (i = 0; i < NSS_GRE_MAX_DEBUG_SESSION_STATS; i++) { +- if (session_stats[i].if_num == if_num) { +- for (j = 0; j < NSS_GRE_SESSION_DEBUG_MAX; j++) { +- session_stats[i].stats[j] += sstats->stats[j]; ++ if (session_debug_stats[i].if_num == if_num) { ++ for (j = 0; j < NSS_GRE_STATS_SESSION_DEBUG_MAX; j++) { ++ session_debug_stats[i].stats[j] += sstats->stats[j]; + } + + if (interface_type == NSS_DYNAMIC_INTERFACE_TYPE_GRE_INNER) { +- session_stats[i].stats[NSS_GRE_SESSION_ENCAP_RX_RECEIVED] += sstats->node_stats.rx_packets; ++ session_debug_stats[i].stats[NSS_GRE_STATS_SESSION_ENCAP_RX_RECEIVED] += sstats->node_stats.rx_packets; + } else if (interface_type == NSS_DYNAMIC_INTERFACE_TYPE_GRE_OUTER) { +- session_stats[i].stats[NSS_GRE_SESSION_DECAP_TX_FORWARDED] += sstats->node_stats.tx_packets; ++ session_debug_stats[i].stats[NSS_GRE_STATS_SESSION_DECAP_TX_FORWARDED] += sstats->node_stats.tx_packets; + } + break; + } +@@ -107,38 +144,38 @@ void nss_gre_stats_session_sync(struct n + } + + /* +- * nss_gre_stats_base_sync() ++ * nss_gre_stats_base_debug_sync() + * Debug statistics sync for GRE base node. + */ +-void nss_gre_stats_base_sync(struct nss_ctx_instance *nss_ctx, struct nss_gre_base_stats_msg *bstats) ++void nss_gre_stats_base_debug_sync(struct nss_ctx_instance *nss_ctx, struct nss_gre_base_stats_msg *bstats) + { + int i; + + spin_lock_bh(&nss_gre_stats_lock); +- for (i = 0; i < NSS_GRE_BASE_DEBUG_MAX; i++) { +- base_stats.stats[i] += bstats->stats[i]; ++ for (i = 0; i < NSS_GRE_STATS_BASE_DEBUG_MAX; i++) { ++ base_debug_stats.stats[i] += bstats->stats[i]; + } + spin_unlock_bh(&nss_gre_stats_lock); + } + + /* +- * nss_gre_stats_session_get() ++ * nss_gre_stats_session_debug_get() + * Get GRE session debug statistics. + */ +-static void nss_gre_stats_session_get(void *stats_mem, int size) ++static void nss_gre_stats_session_debug_get(void *stats_mem, int size) + { +- struct nss_gre_stats_session *stats = (struct nss_gre_stats_session *)stats_mem; ++ struct nss_gre_stats_session_debug *stats = (struct nss_gre_stats_session_debug *)stats_mem; + int i; + +- if (!stats || (size < (sizeof(struct nss_gre_stats_session) * NSS_GRE_MAX_DEBUG_SESSION_STATS))) { ++ if (!stats || (size < (sizeof(struct nss_gre_stats_session_debug) * NSS_GRE_MAX_DEBUG_SESSION_STATS))) { + nss_warning("No memory to copy gre stats"); + return; + } + + spin_lock_bh(&nss_gre_stats_lock); + for (i = 0; i < NSS_GRE_MAX_DEBUG_SESSION_STATS; i++) { +- if (session_stats[i].valid) { +- memcpy(stats, &session_stats[i], sizeof(struct nss_gre_stats_session)); ++ if (session_debug_stats[i].valid) { ++ memcpy(stats, &session_debug_stats[i], sizeof(struct nss_gre_stats_session_debug)); + stats++; + } + } +@@ -146,25 +183,25 @@ static void nss_gre_stats_session_get(vo + } + + /* +- * nss_gre_stats_base_get() ++ * nss_gre_stats_base_debug_get() + * Get GRE debug base statistics. + */ +-static void nss_gre_stats_base_get(void *stats_mem, int size) ++static void nss_gre_stats_base_debug_get(void *stats_mem, int size) + { +- struct nss_gre_stats_base *stats = (struct nss_gre_stats_base *)stats_mem; ++ struct nss_gre_stats_base_debug *stats = (struct nss_gre_stats_base_debug *)stats_mem; + + if (!stats) { + nss_warning("No memory to copy GRE base stats\n"); + return; + } + +- if (size < sizeof(struct nss_gre_stats_base)) { ++ if (size < sizeof(struct nss_gre_stats_base_debug)) { + nss_warning("Not enough memory to copy GRE base stats\n"); + return; + } + + spin_lock_bh(&nss_gre_stats_lock); +- memcpy(stats, &base_stats, sizeof(struct nss_gre_stats_base)); ++ memcpy(stats, &base_debug_stats, sizeof(struct nss_gre_stats_base_debug)); + spin_unlock_bh(&nss_gre_stats_lock); + } + +@@ -176,15 +213,15 @@ static ssize_t nss_gre_stats_read(struct + { + uint32_t max_output_lines = 2 /* header & footer for base debug stats */ + + 2 /* header & footer for session debug stats */ +- + NSS_GRE_BASE_DEBUG_MAX /* Base debug */ +- + NSS_GRE_MAX_DEBUG_SESSION_STATS * (NSS_GRE_SESSION_DEBUG_MAX + 2) /*session stats */ ++ + NSS_GRE_STATS_BASE_DEBUG_MAX /* Base debug */ ++ + NSS_GRE_MAX_DEBUG_SESSION_STATS * (NSS_GRE_STATS_SESSION_DEBUG_MAX + 2) /*session stats */ + + 2; + size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines; + size_t size_wr = 0; + ssize_t bytes_read = 0; + struct net_device *dev; +- struct nss_gre_stats_session *sstats; +- struct nss_gre_stats_base *bstats; ++ struct nss_gre_stats_session_debug *sstats; ++ struct nss_gre_stats_base_debug *bstats; + int id; + + char *lbuf = kzalloc(size_al, GFP_KERNEL); +@@ -193,14 +230,14 @@ static ssize_t nss_gre_stats_read(struct + return 0; + } + +- bstats = kzalloc(sizeof(struct nss_gre_stats_base), GFP_KERNEL); ++ bstats = kzalloc(sizeof(struct nss_gre_stats_base_debug), GFP_KERNEL); + if (unlikely(!bstats)) { + nss_warning("Could not allocate memory for base debug statistics buffer"); + kfree(lbuf); + return 0; + } + +- sstats = kzalloc(sizeof(struct nss_gre_stats_session) * NSS_GRE_MAX_DEBUG_SESSION_STATS, GFP_KERNEL); ++ sstats = kzalloc(sizeof(struct nss_gre_stats_session_debug) * NSS_GRE_MAX_DEBUG_SESSION_STATS, GFP_KERNEL); + if (unlikely(!sstats)) { + nss_warning("Could not allocate memory for base debug statistics buffer"); + kfree(lbuf); +@@ -213,18 +250,18 @@ static ssize_t nss_gre_stats_read(struct + /* + * Get all base stats + */ +- nss_gre_stats_base_get((void *)bstats, sizeof(struct nss_gre_stats_base)); ++ nss_gre_stats_base_debug_get((void *)bstats, sizeof(struct nss_gre_stats_base_debug)); + + size_wr += nss_stats_print("gre", NULL, NSS_STATS_SINGLE_INSTANCE +- , nss_gre_strings_base_stats ++ , nss_gre_stats_base_debug_str + , bstats->stats +- , NSS_GRE_BASE_DEBUG_MAX ++ , NSS_GRE_STATS_BASE_DEBUG_MAX + , lbuf, size_wr, size_al); + + /* + * Get all session stats + */ +- nss_gre_stats_session_get(sstats, sizeof(struct nss_gre_stats_session) * NSS_GRE_MAX_DEBUG_SESSION_STATS); ++ nss_gre_stats_session_debug_get(sstats, sizeof(struct nss_gre_stats_session_debug) * NSS_GRE_MAX_DEBUG_SESSION_STATS); + + for (id = 0; id < NSS_GRE_MAX_DEBUG_SESSION_STATS; id++) { + +@@ -243,9 +280,9 @@ static ssize_t nss_gre_stats_read(struct + (sstats + id)->if_num); + } + size_wr += nss_stats_print("gre_session", NULL, id +- , nss_gre_strings_session_stats ++ , nss_gre_stats_session_debug_str + , (sstats + id)->stats +- , NSS_GRE_SESSION_DEBUG_MAX ++ , NSS_GRE_STATS_SESSION_DEBUG_MAX + , lbuf, size_wr, size_al); + size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\n"); + } +@@ -272,67 +309,3 @@ void nss_gre_stats_dentry_create(void) + nss_stats_create_dentry("gre", &nss_gre_stats_ops); + } + +-/* +- * nss_gre_stats_base_notify() +- * Sends notifications to all the registered modules. +- * +- * Leverage NSS-FW statistics timing to update Netlink. +- */ +-void nss_gre_stats_base_notify(struct nss_ctx_instance *nss_ctx) +-{ +- struct nss_gre_base_stats_notification gre_stats; +- +- spin_lock_bh(&nss_gre_stats_lock); +- gre_stats.core_id = nss_ctx->id; +- memcpy(gre_stats.stats_base_ctx, base_stats.stats, sizeof(gre_stats.stats_base_ctx)); +- spin_unlock_bh(&nss_gre_stats_lock); +- +- atomic_notifier_call_chain(&nss_gre_stats_notifier, NSS_STATS_EVENT_NOTIFY, &gre_stats); +-} +- +-/* +- * nss_gre_stats_session_notify() +- * Sends notifications to all the registered modules. +- * +- * Leverage NSS-FW statistics timing to update Netlink. +- */ +-void nss_gre_stats_session_notify(struct nss_ctx_instance *nss_ctx, uint32_t if_num) +-{ +- struct nss_gre_session_stats_notification gre_stats; +- int i; +- +- spin_lock_bh(&nss_gre_stats_lock); +- for (i = 0; i < NSS_GRE_MAX_DEBUG_SESSION_STATS; i++) { +- if (session_stats[i].if_num != if_num) { +- continue; +- } +- +- memcpy(gre_stats.stats_session_ctx, session_stats[i].stats, sizeof(gre_stats.stats_session_ctx)); +- gre_stats.core_id = nss_ctx->id; +- gre_stats.if_num = if_num; +- spin_unlock_bh(&nss_gre_stats_lock); +- atomic_notifier_call_chain(&nss_gre_stats_notifier, NSS_STATS_EVENT_NOTIFY, &gre_stats); +- return; +- } +- spin_unlock_bh(&nss_gre_stats_lock); +-} +- +-/* +- * nss_gre_stats_unregister_notifier() +- * Deregisters statistics notifier. +- */ +-int nss_gre_stats_unregister_notifier(struct notifier_block *nb) +-{ +- return atomic_notifier_chain_unregister(&nss_gre_stats_notifier, nb); +-} +-EXPORT_SYMBOL(nss_gre_stats_unregister_notifier); +- +-/* +- * nss_gre_stats_register_notifier() +- * Registers statistics notifier. +- */ +-int nss_gre_stats_register_notifier(struct notifier_block *nb) +-{ +- return atomic_notifier_chain_register(&nss_gre_stats_notifier, nb); +-} +-EXPORT_SYMBOL(nss_gre_stats_register_notifier); +--- a/nss_gre_stats.h ++++ b/nss_gre_stats.h +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2017, 2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -22,32 +22,72 @@ + #ifndef __NSS_GRE_STATS_H + #define __NSS_GRE_STATS_H + +-#include ++/* ++ * GRE base debug statistics types ++ */ ++enum nss_gre_stats_base_debug_types { ++ NSS_GRE_STATS_BASE_RX_PACKETS, /**< Rx packet count. */ ++ NSS_GRE_STATS_BASE_RX_DROPPED, /**< Rx dropped count. */ ++ NSS_GRE_STATS_BASE_EXP_ETH_HDR_MISSING, /**< Ethernet header missing. */ ++ NSS_GRE_STATS_BASE_EXP_ETH_TYPE_NON_IP, /**< Not IPV4 or IPV6 packet. */ ++ NSS_GRE_STATS_BASE_EXP_IP_UNKNOWN_PROTOCOL, /**< Unknown protocol. */ ++ NSS_GRE_STATS_BASE_EXP_IP_HEADER_INCOMPLETE, /**< Bad IP header. */ ++ NSS_GRE_STATS_BASE_EXP_IP_BAD_TOTAL_LENGTH, /**< Invalid IP packet length. */ ++ NSS_GRE_STATS_BASE_EXP_IP_BAD_CHECKSUM, /**< Bad packet checksum. */ ++ NSS_GRE_STATS_BASE_EXP_IP_DATAGRAM_INCOMPLETE, /**< Bad packet. */ ++ NSS_GRE_STATS_BASE_EXP_IP_FRAGMENT, /**< IP fragment. */ ++ NSS_GRE_STATS_BASE_EXP_IP_OPTIONS_INCOMPLETE, /**< Invalid IP options. */ ++ NSS_GRE_STATS_BASE_EXP_IP_WITH_OPTIONS, /**< IP packet with options. */ ++ NSS_GRE_STATS_BASE_EXP_IPV6_UNKNOWN_PROTOCOL, /**< Unknown protocol. */ ++ NSS_GRE_STATS_BASE_EXP_IPV6_HEADER_INCOMPLETE, /**< Incomplete IPV6 header. */ ++ NSS_GRE_STATS_BASE_EXP_GRE_UNKNOWN_SESSION, /**< Unknown GRE session. */ ++ NSS_GRE_STATS_BASE_EXP_GRE_NODE_INACTIVE, /**< GRE node inactive. */ ++ NSS_GRE_STATS_BASE_DEBUG_MAX, /**< GRE base error max. */ ++}; + + /* + * GRE base debug statistics + */ +-struct nss_gre_stats_base { +- uint64_t stats[NSS_GRE_BASE_DEBUG_MAX]; /**< GRE debug statistics. */ ++struct nss_gre_stats_base_debug { ++ uint64_t stats[NSS_GRE_STATS_BASE_DEBUG_MAX]; /**< GRE debug statistics. */ ++}; ++ ++/* ++ * GRE session debug statistics types ++ */ ++enum nss_gre_stats_session_debug_types { ++ NSS_GRE_STATS_SESSION_PBUF_ALLOC_FAIL, /**< Pbuf alloc failure. */ ++ NSS_GRE_STATS_SESSION_DECAP_FORWARD_ENQUEUE_FAIL, /**< Rx forward enqueue failure. */ ++ NSS_GRE_STATS_SESSION_ENCAP_FORWARD_ENQUEUE_FAIL, /**< Tx forward enqueue failure. */ ++ NSS_GRE_STATS_SESSION_DECAP_TX_FORWARDED, /**< Packets forwarded after decap. */ ++ NSS_GRE_STATS_SESSION_ENCAP_RX_RECEIVED, /**< Packets received for encap. */ ++ NSS_GRE_STATS_SESSION_ENCAP_RX_DROPPED, /**< Packets dropped while enqueue for encap. */ ++ NSS_GRE_STATS_SESSION_ENCAP_RX_LINEAR_FAIL, /**< Packets dropped during encap linearization. */ ++ NSS_GRE_STATS_SESSION_EXP_RX_KEY_ERROR, /**< Rx KEY error. */ ++ NSS_GRE_STATS_SESSION_EXP_RX_SEQ_ERROR, /**< Rx sequence number error. */ ++ NSS_GRE_STATS_SESSION_EXP_RX_CS_ERROR, /**< Rx checksum error. */ ++ NSS_GRE_STATS_SESSION_EXP_RX_FLAG_MISMATCH, /**< Rx flag mismatch. */ ++ NSS_GRE_STATS_SESSION_EXP_RX_MALFORMED, /**< Rx malformed packet. */ ++ NSS_GRE_STATS_SESSION_EXP_RX_INVALID_PROTOCOL, /**< Rx invalid protocol. */ ++ NSS_GRE_STATS_SESSION_EXP_RX_NO_HEADROOM, /**< Rx no headroom. */ ++ NSS_GRE_STATS_SESSION_DEBUG_MAX, /**< Session debug max. */ + }; + + /* + * GRE session debug statistics + */ +-struct nss_gre_stats_session { +- uint64_t stats[NSS_GRE_SESSION_DEBUG_MAX]; /**< Session debug statistics. */ +- int32_t if_index; /**< Netdevice's ifindex. */ +- uint32_t if_num; /**< NSS interface number. */ +- bool valid; /**< Is node valid ? */ ++struct nss_gre_stats_session_debug { ++ uint64_t stats[NSS_GRE_STATS_SESSION_DEBUG_MAX]; /**< Session debug statistics. */ ++ int32_t if_index; /**< Netdevice's ifindex. */ ++ uint32_t if_num; /**< NSS interface number. */ ++ bool valid; /**< Is node valid ? */ + }; + + /* + * GRE statistics APIs + */ +-extern void nss_gre_stats_base_notify(struct nss_ctx_instance *nss_ctx); +-extern void nss_gre_stats_session_notify(struct nss_ctx_instance *nss_ctx, uint32_t if_num); +-extern void nss_gre_stats_session_sync(struct nss_ctx_instance *nss_ctx, struct nss_gre_session_stats_msg *sstats, uint16_t if_num); +-extern void nss_gre_stats_base_sync(struct nss_ctx_instance *nss_ctx, struct nss_gre_base_stats_msg *bstats); ++extern void nss_gre_stats_session_debug_sync(struct nss_ctx_instance *nss_ctx, struct nss_gre_session_stats_msg *sstats, uint16_t if_num); ++extern void nss_gre_stats_base_debug_sync(struct nss_ctx_instance *nss_ctx, struct nss_gre_base_stats_msg *bstats); + extern void nss_gre_stats_session_register(uint32_t if_num, struct net_device *netdev); + extern void nss_gre_stats_session_unregister(uint32_t if_num); + extern void nss_gre_stats_dentry_create(void); +--- a/nss_gre_strings.c ++++ /dev/null +@@ -1,124 +0,0 @@ +-/* +- *************************************************************************** +- * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- *************************************************************************** +- */ +- +-#include "nss_stats.h" +-#include "nss_core.h" +-#include "nss_strings.h" +-#include "nss_gre_strings.h" +- +-/* +- * nss_gre_strings_base_stats +- * GRE debug statistics strings for base types +- */ +-struct nss_stats_info nss_gre_strings_base_stats[NSS_GRE_BASE_DEBUG_MAX] = { +- {"base_rx_pkts", NSS_STATS_TYPE_COMMON}, +- {"base_rx_drops", NSS_STATS_TYPE_DROP}, +- {"base_exp_eth_hdr_missing", NSS_STATS_TYPE_EXCEPTION}, +- {"base_exp_eth_type_non_ip", NSS_STATS_TYPE_EXCEPTION}, +- {"base_exp_ip_unknown_protocol", NSS_STATS_TYPE_EXCEPTION}, +- {"base_exp_ip_header_incomplete", NSS_STATS_TYPE_EXCEPTION}, +- {"base_exp_ip_bad_total_length", NSS_STATS_TYPE_EXCEPTION}, +- {"base_exp_ip_bad_checksum", NSS_STATS_TYPE_EXCEPTION}, +- {"base_exp_ip_datagram_incomplete", NSS_STATS_TYPE_EXCEPTION}, +- {"base_exp_ip_fragment", NSS_STATS_TYPE_EXCEPTION}, +- {"base_exp_ip_options_incomplete", NSS_STATS_TYPE_EXCEPTION}, +- {"base_exp_ip_with_options", NSS_STATS_TYPE_EXCEPTION}, +- {"base_exp_ipv6_unknown_protocol", NSS_STATS_TYPE_EXCEPTION}, +- {"base_exp_ipv6_header_incomplete", NSS_STATS_TYPE_EXCEPTION}, +- {"base_exp_unknown_session", NSS_STATS_TYPE_EXCEPTION}, +- {"base_exp_node_inactive", NSS_STATS_TYPE_EXCEPTION} +-}; +- +-/* +- * nss_gre_base_strings_read() +- * Read GRE base debug statistics names +- */ +-static ssize_t nss_gre_base_strings_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- return nss_strings_print(ubuf, sz, ppos, nss_gre_strings_base_stats, NSS_GRE_BASE_DEBUG_MAX); +-} +- +-/* +- * nss_gre_base_strings_ops +- */ +-NSS_STRINGS_DECLARE_FILE_OPERATIONS(gre_base); +- +-/* +- * nss_gre_strings_session_stats +- * GRE debug statistics strings for sessions +- */ +-struct nss_stats_info nss_gre_strings_session_stats[NSS_GRE_SESSION_DEBUG_MAX] = { +- {"session_pbuf_alloc_fail", NSS_STATS_TYPE_ERROR}, +- {"session_decap_forward_enqueue_fail", NSS_STATS_TYPE_DROP}, +- {"session_encap_forward_enqueue_fail", NSS_STATS_TYPE_DROP}, +- {"session_decap_tx_forwarded", NSS_STATS_TYPE_SPECIAL}, +- {"session_encap_rx_received", NSS_STATS_TYPE_SPECIAL}, +- {"session_encap_rx_drops", NSS_STATS_TYPE_DROP}, +- {"session_encap_rx_linear_fail", NSS_STATS_TYPE_DROP}, +- {"session_exp_rx_key_error", NSS_STATS_TYPE_EXCEPTION}, +- {"session_exp_rx_seq_error", NSS_STATS_TYPE_EXCEPTION}, +- {"session_exp_rx_cs_error", NSS_STATS_TYPE_EXCEPTION}, +- {"session_exp_rx_flag_mismatch", NSS_STATS_TYPE_EXCEPTION}, +- {"session_exp_rx_malformed", NSS_STATS_TYPE_EXCEPTION}, +- {"session_exp_rx_invalid_protocol", NSS_STATS_TYPE_EXCEPTION}, +- {"session_exp_rx_no_headroom", NSS_STATS_TYPE_EXCEPTION} +-}; +- +-/* +- * nss_gre_session_strings_read() +- * Read GRE session debug statistics names +- */ +-static ssize_t nss_gre_session_strings_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- return nss_strings_print(ubuf, sz, ppos, nss_gre_strings_session_stats, NSS_GRE_SESSION_DEBUG_MAX); +-} +- +-/* +- * nss_gre_session_strings_ops +- */ +-NSS_STRINGS_DECLARE_FILE_OPERATIONS(gre_session); +- +-/* +- * nss_gre_strings_dentry_create() +- * Create gre statistics strings debug entry. +- */ +-void nss_gre_strings_dentry_create(void) +-{ +- struct dentry *gre_d = NULL; +- +- if (!nss_top_main.strings_dentry) { +- nss_warning("qca-nss-drv/strings is not present"); +- return; +- } +- +- gre_d = debugfs_create_dir("gre", nss_top_main.strings_dentry); +- if (!gre_d) { +- nss_warning("Failed to create qca-nss-drv/strings/gre directory"); +- return; +- } +- +- if (!debugfs_create_file("gre_base", 0400, gre_d, &nss_top_main, &nss_gre_base_strings_ops)) { +- nss_warning("Failed to create qca-nss-drv/strings/gre/gre_base file"); +- debugfs_remove_recursive(gre_d); +- return; +- } +- +- if (!debugfs_create_file("gre_session", 0400, gre_d, &nss_top_main, &nss_gre_session_strings_ops)) { +- nss_warning("Failed to create qca-nss-drv/strings/gre/gre_session file"); +- debugfs_remove_recursive(gre_d); +- return; +- } +-} +--- a/nss_gre_strings.h ++++ /dev/null +@@ -1,26 +0,0 @@ +-/* +- **************************************************************************** +- * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- **************************************************************************** +- */ +- +-#ifndef __NSS_GRE_STRINGS_H +-#define __NSS_GRE_STRINGS_H +- +-#include "nss_gre_stats.h" +- +-extern struct nss_stats_info nss_gre_strings_base_stats[NSS_GRE_BASE_DEBUG_MAX]; +-extern struct nss_stats_info nss_gre_strings_session_stats[NSS_GRE_SESSION_DEBUG_MAX]; +-extern void nss_gre_strings_dentry_create(void); +- +-#endif /* __NSS_GRE_STRINGS_H */ +--- a/nss_gre_tunnel.c ++++ b/nss_gre_tunnel.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -17,7 +17,6 @@ + #include "nss_tx_rx_common.h" + #include "nss_gre_tunnel_stats.h" + #include "nss_gre_tunnel_log.h" +-#include "nss_gre_tunnel_strings.h" + + #define NSS_GRE_TUNNEL_TX_TIMEOUT 3000 /* 3 Seconds */ + +@@ -90,7 +89,6 @@ static void nss_gre_tunnel_handler(struc + switch (ngtm->cm.type) { + case NSS_GRE_TUNNEL_MSG_STATS: + nss_gre_tunnel_stats_session_sync(nss_ctx, &ngtm->msg.stats, ncm->interface); +- nss_gre_tunnel_stats_notify(nss_ctx, ncm->interface); + break; + } + +@@ -320,16 +318,16 @@ struct nss_ctx_instance *nss_gre_tunnel_ + + BUG_ON(!nss_gre_tunnel_verify_if_num(if_num)); + +- spin_lock_bh(&nss_gre_tunnel_stats_lock); ++ spin_lock_bh(&nss_gre_tunnel_stats_session_debug_lock); + for (i = 0; i < NSS_MAX_GRE_TUNNEL_SESSIONS; i++) { +- if (!session_stats[i].valid) { +- session_stats[i].valid = true; +- session_stats[i].if_num = if_num; +- session_stats[i].if_index = netdev->ifindex; ++ if (!nss_gre_tunnel_session_debug_stats[i].valid) { ++ nss_gre_tunnel_session_debug_stats[i].valid = true; ++ nss_gre_tunnel_session_debug_stats[i].if_num = if_num; ++ nss_gre_tunnel_session_debug_stats[i].if_index = netdev->ifindex; + break; + } + } +- spin_unlock_bh(&nss_gre_tunnel_stats_lock); ++ spin_unlock_bh(&nss_gre_tunnel_stats_session_debug_lock); + + if (i == NSS_MAX_GRE_TUNNEL_SESSIONS) { + nss_warning("%px: Cannot find free slot for GRE Tunnel session stats, I/F:%u\n", nss_ctx, if_num); +@@ -338,9 +336,9 @@ struct nss_ctx_instance *nss_gre_tunnel_ + + if (nss_ctx->subsys_dp_register[if_num].ndev) { + nss_warning("%px: Cannot find free slot for GRE Tunnel NSS I/F:%u\n", nss_ctx, if_num); +- session_stats[i].valid = false; +- session_stats[i].if_num = 0; +- session_stats[i].if_index = 0; ++ nss_gre_tunnel_session_debug_stats[i].valid = false; ++ nss_gre_tunnel_session_debug_stats[i].if_num = 0; ++ nss_gre_tunnel_session_debug_stats[i].if_index = 0; + return NULL; + } + +@@ -349,7 +347,6 @@ struct nss_ctx_instance *nss_gre_tunnel_ + nss_top_main.gre_tunnel_msg_callback = ev_cb; + nss_core_register_handler(nss_ctx, if_num, nss_gre_tunnel_handler, app_ctx); + nss_gre_tunnel_stats_dentry_create(); +- nss_gre_tunnel_strings_dentry_create(); + + return nss_ctx; + } +@@ -366,15 +363,15 @@ void nss_gre_tunnel_unregister_if(uint32 + + BUG_ON(!nss_gre_tunnel_verify_if_num(if_num)); + +- spin_lock_bh(&nss_gre_tunnel_stats_lock); ++ spin_lock_bh(&nss_gre_tunnel_stats_session_debug_lock); + for (i = 0; i < NSS_MAX_GRE_TUNNEL_SESSIONS; i++) { +- if (session_stats[i].if_num == if_num) { +- memset(&session_stats[i], 0, +- sizeof(struct nss_gre_tunnel_stats_session)); ++ if (nss_gre_tunnel_session_debug_stats[i].if_num == if_num) { ++ memset(&nss_gre_tunnel_session_debug_stats[i], 0, ++ sizeof(struct nss_gre_tunnel_stats_session_debug)); + break; + } + } +- spin_unlock_bh(&nss_gre_tunnel_stats_lock); ++ spin_unlock_bh(&nss_gre_tunnel_stats_session_debug_lock); + + if (i == NSS_MAX_GRE_TUNNEL_SESSIONS) { + nss_warning("%px: Cannot find debug stats for GRE Tunnel session: %d\n", nss_ctx, if_num); +--- a/nss_gre_tunnel_stats.c ++++ b/nss_gre_tunnel_stats.c +@@ -1,6 +1,6 @@ + /* +- **************************************************************************** +- * Copyright (c) 2017, 2020-2021, The Linux Foundation. All rights reserved. ++ ************************************************************************** ++ * Copyright (c) 2017, 2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -11,25 +11,48 @@ + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- **************************************************************************** ++ ************************************************************************** + */ + + #include "nss_tx_rx_common.h" +-#include "nss_gre_tunnel.h" + #include "nss_gre_tunnel_stats.h" +-#include "nss_gre_tunnel_strings.h" + +-/* +- * Declare atomic notifier data structure for statistics. +- */ +-ATOMIC_NOTIFIER_HEAD(nss_gre_tunnel_stats_notifier); ++DEFINE_SPINLOCK(nss_gre_tunnel_stats_session_debug_lock); ++struct nss_gre_tunnel_stats_session_debug nss_gre_tunnel_session_debug_stats[NSS_MAX_GRE_TUNNEL_SESSIONS]; + + /* +- * Spinlock to protect gre tunnel statistics update/read ++ * nss_gre_tunnel_stats_session_debug_str ++ * GRE Tunnel statistics strings for nss session stats + */ +-DEFINE_SPINLOCK(nss_gre_tunnel_stats_lock); +- +-struct nss_gre_tunnel_stats_session session_stats[NSS_MAX_GRE_TUNNEL_SESSIONS]; ++static int8_t *nss_gre_tunnel_stats_session_debug_str[NSS_GRE_TUNNEL_STATS_SESSION_MAX] = { ++ "RX_PKTS", ++ "TX_PKTS", ++ "RX_QUEUE_0_DROPPED", ++ "RX_QUEUE_1_DROPPED", ++ "RX_QUEUE_2_DROPPED", ++ "RX_QUEUE_3_DROPPED", ++ "RX_MALFORMED", ++ "RX_INVALID_PROT", ++ "DECAP_QUEUE_FULL", ++ "RX_SINGLE_REC_DGRAM", ++ "RX_INVALID_REC_DGRAM", ++ "BUFFER_ALLOC_FAIL", ++ "BUFFER_COPY_FAIL", ++ "OUTFLOW_QUEUE_FULL", ++ "TX_DROPPED_HROOM", ++ "RX_CBUFFER_ALLOC_FAIL", ++ "RX_CENQUEUE_FAIL", ++ "RX_DECRYPT_DONE", ++ "RX_FORWARD_ENQUEUE_FAIL", ++ "TX_CBUFFER_ALLOC_FAIL", ++ "TX_CENQUEUE_FAIL", ++ "TX_DROPPED_TROOM", ++ "TX_FORWARD_ENQUEUE_FAIL", ++ "TX_CIPHER_DONE", ++ "CRYPTO_NOSUPP", ++ "RX_DROPPED_MH_VERSION", ++ "RX_UNALIGNED_PKT", ++}; + + /* + * nss_gre_tunnel_stats_session_sync() +@@ -39,20 +62,20 @@ void nss_gre_tunnel_stats_session_sync(s + uint16_t if_num) + { + int i; +- struct nss_gre_tunnel_stats_session *s = NULL; ++ struct nss_gre_tunnel_stats_session_debug *s = NULL; + + NSS_VERIFY_CTX_MAGIC(nss_ctx); + +- spin_lock_bh(&nss_gre_tunnel_stats_lock); ++ spin_lock_bh(&nss_gre_tunnel_stats_session_debug_lock); + for (i = 0; i < NSS_MAX_GRE_TUNNEL_SESSIONS; i++) { +- if (session_stats[i].if_num == if_num) { +- s = &session_stats[i]; ++ if (nss_gre_tunnel_session_debug_stats[i].if_num == if_num) { ++ s = &nss_gre_tunnel_session_debug_stats[i]; + break; + } + } + + if (!s) { +- spin_unlock_bh(&nss_gre_tunnel_stats_lock); ++ spin_unlock_bh(&nss_gre_tunnel_stats_session_debug_lock); + nss_warning("%px: Session not found: %u", nss_ctx, if_num); + return; + } +@@ -95,14 +118,14 @@ void nss_gre_tunnel_stats_session_sync(s + #endif + } + +- spin_unlock_bh(&nss_gre_tunnel_stats_lock); ++ spin_unlock_bh(&nss_gre_tunnel_stats_session_debug_lock); + } + + /* +- * nss_gre_tunnel_stats_session_get() ++ * nss_gre_tunnel_stats_session_debug_get() + * Get session GRE Tunnel statitics. + */ +-static void nss_gre_tunnel_stats_session_get(struct nss_gre_tunnel_stats_session *stats) ++static void nss_gre_tunnel_stats_session_debug_get(struct nss_gre_tunnel_stats_session_debug *stats) + { + int i; + +@@ -111,15 +134,15 @@ static void nss_gre_tunnel_stats_session + return; + } + +- spin_lock_bh(&nss_gre_tunnel_stats_lock); ++ spin_lock_bh(&nss_gre_tunnel_stats_session_debug_lock); + for (i = 0; i < NSS_MAX_GRE_TUNNEL_SESSIONS; i++) { +- if (session_stats[i].valid) { +- memcpy(stats, &session_stats[i], +- sizeof(struct nss_gre_tunnel_stats_session)); ++ if (nss_gre_tunnel_session_debug_stats[i].valid) { ++ memcpy(stats, &nss_gre_tunnel_session_debug_stats[i], ++ sizeof(struct nss_gre_tunnel_stats_session_debug)); + stats++; + } + } +- spin_unlock_bh(&nss_gre_tunnel_stats_lock); ++ spin_unlock_bh(&nss_gre_tunnel_stats_session_debug_lock); + } + + /* +@@ -134,10 +157,9 @@ static ssize_t nss_gre_tunnel_stats_read + size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines; + size_t size_wr = 0; + ssize_t bytes_read = 0; +- uint64_t *stats_shadow; + struct net_device *dev; + int id, i; +- struct nss_gre_tunnel_stats_session *gre_tunnel_session_stats = NULL; ++ struct nss_gre_tunnel_stats_session_debug *gre_tunnel_session_stats = NULL; + + char *lbuf = kzalloc(size_al, GFP_KERNEL); + if (unlikely(lbuf == NULL)) { +@@ -145,31 +167,24 @@ static ssize_t nss_gre_tunnel_stats_read + return 0; + } + +- stats_shadow = kzalloc(NSS_CRYPTO_CMN_RESP_ERROR_MAX * 8, GFP_KERNEL); +- if (unlikely(!stats_shadow)) { +- nss_warning("Could not allocate memory for local shadow buffer"); +- kfree(lbuf); +- return 0; +- } +- +- gre_tunnel_session_stats = kzalloc((sizeof(struct nss_gre_tunnel_stats_session) ++ gre_tunnel_session_stats = kzalloc((sizeof(struct nss_gre_tunnel_stats_session_debug) + * NSS_MAX_GRE_TUNNEL_SESSIONS), GFP_KERNEL); + if (unlikely(gre_tunnel_session_stats == NULL)) { + nss_warning("Could not allocate memory for populating GRE Tunnel stats"); + kfree(lbuf); +- kfree(stats_shadow); + return 0; + } + + /* + * Get all stats + */ +- nss_gre_tunnel_stats_session_get(gre_tunnel_session_stats); ++ nss_gre_tunnel_stats_session_debug_get(gre_tunnel_session_stats); + + /* + * Session stats + */ +- size_wr += nss_stats_banner(lbuf, size_wr, size_al, "GRE tunnel stats", NSS_STATS_SINGLE_CORE); ++ size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, ++ "\nGRE Tunnel session stats start:\n\n"); + + for (id = 0; id < NSS_MAX_GRE_TUNNEL_SESSIONS; id++) { + if (!gre_tunnel_session_stats[id].valid) +@@ -188,33 +203,34 @@ static ssize_t nss_gre_tunnel_stats_read + gre_tunnel_session_stats[id].if_num); + } + +- size_wr += nss_stats_print("gre_tunnel", NULL, NSS_STATS_SINGLE_INSTANCE, +- nss_gre_tunnel_strings_stats, gre_tunnel_session_stats[id].stats, +- NSS_GRE_TUNNEL_STATS_SESSION_MAX, lbuf, size_wr, size_al); ++ for (i = 0; i < NSS_GRE_TUNNEL_STATS_SESSION_MAX; i++) { ++ size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, ++ "\t%s = %llu\n", ++ nss_gre_tunnel_stats_session_debug_str[i], ++ gre_tunnel_session_stats[id].stats[i]); ++ } + + /* + * Print crypto resp err stats. + * TODO: We are not printing with the right enum string for crypto. This + * is intentional since we atleast want to see some stats for now. + */ +- spin_lock_bh(&nss_gre_tunnel_stats_lock); + for (i = 0; i < NSS_CRYPTO_CMN_RESP_ERROR_MAX; i++) { +- stats_shadow[i] = gre_tunnel_session_stats[id].stats[NSS_GRE_TUNNEL_STATS_SESSION_MAX + i]; ++ size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, ++ "\t%s = %llu\n", ++ nss_gre_tunnel_stats_session_debug_str[i], ++ gre_tunnel_session_stats[id].stats[NSS_GRE_TUNNEL_STATS_SESSION_MAX + i]); + } + +- spin_unlock_bh(&nss_gre_tunnel_stats_lock); +- size_wr += nss_stats_print("gre_tunnel", NULL, NSS_STATS_SINGLE_INSTANCE, +- nss_gre_tunnel_strings_stats, stats_shadow, +- NSS_CRYPTO_CMN_RESP_ERROR_MAX, lbuf, size_wr, size_al); +- + size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\n"); + } + ++ size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, ++ "\nGRE Tunnel session stats end\n"); + bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, size_wr); + + kfree(gre_tunnel_session_stats); + kfree(lbuf); +- kfree(stats_shadow); + return bytes_read; + } + +@@ -231,52 +247,3 @@ void nss_gre_tunnel_stats_dentry_create( + { + nss_stats_create_dentry("gre_tunnel", &nss_gre_tunnel_stats_ops); + } +- +-/* +- * nss_gre_tunnel_stats_notify() +- * Sends notifications to all the registered modules. +- * +- * Leverage NSS-FW statistics timing to update Netlink. +- */ +-void nss_gre_tunnel_stats_notify(struct nss_ctx_instance *nss_ctx, uint32_t if_num) +-{ +- struct nss_gre_tunnel_stats_notification gre_tunnel_stats; +- struct nss_gre_tunnel_stats_session *s = NULL; +- int i; +- +- spin_lock_bh(&nss_gre_tunnel_stats_lock); +- for (i = 0; i < NSS_MAX_GRE_TUNNEL_SESSIONS; i++) { +- if (session_stats[i].if_num != if_num) { +- continue; +- } +- +- s = &session_stats[i]; +- gre_tunnel_stats.core_id = nss_ctx->id; +- gre_tunnel_stats.if_num = if_num; +- memcpy(gre_tunnel_stats.stats_ctx, s->stats, sizeof(gre_tunnel_stats.stats_ctx)); +- spin_unlock_bh(&nss_gre_tunnel_stats_lock); +- atomic_notifier_call_chain(&nss_gre_tunnel_stats_notifier, NSS_STATS_EVENT_NOTIFY, &gre_tunnel_stats); +- return; +- } +- spin_unlock_bh(&nss_gre_tunnel_stats_lock); +-} +- +-/* +- * nss_gre_tunnel_stats_unregister_notifier() +- * Deregisters statistics notifier. +- */ +-int nss_gre_tunnel_stats_unregister_notifier(struct notifier_block *nb) +-{ +- return atomic_notifier_chain_unregister(&nss_gre_tunnel_stats_notifier, nb); +-} +-EXPORT_SYMBOL(nss_gre_tunnel_stats_unregister_notifier); +- +-/* +- * nss_gre_tunnel_stats_register_notifier() +- * Registers statistics notifier. +- */ +-int nss_gre_tunnel_stats_register_notifier(struct notifier_block *nb) +-{ +- return atomic_notifier_chain_register(&nss_gre_tunnel_stats_notifier, nb); +-} +-EXPORT_SYMBOL(nss_gre_tunnel_stats_register_notifier); +--- a/nss_gre_tunnel_stats.h ++++ b/nss_gre_tunnel_stats.h +@@ -1,6 +1,6 @@ + /* + ****************************************************************************** +- * Copyright (c) 2016-2017, 2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -18,26 +18,58 @@ + #define __NSS_GRE_TUNNEL_STATS_H + + /* ++ * GRE Tunnel session debug statistic counters ++ */ ++enum nss_gre_tunnel_stats_session { ++ NSS_GRE_TUNNEL_STATS_SESSION_RX_PKTS, ++ NSS_GRE_TUNNEL_STATS_SESSION_TX_PKTS, ++ NSS_GRE_TUNNEL_STATS_SESSION_RX_QUEUE_0_DROPPED, ++ NSS_GRE_TUNNEL_STATS_SESSION_RX_QUEUE_1_DROPPED, ++ NSS_GRE_TUNNEL_STATS_SESSION_RX_QUEUE_2_DROPPED, ++ NSS_GRE_TUNNEL_STATS_SESSION_RX_QUEUE_3_DROPPED, ++ NSS_GRE_TUNNEL_STATS_SESSION_RX_MALFORMED, ++ NSS_GRE_TUNNEL_STATS_SESSION_RX_INVALID_PROT, ++ NSS_GRE_TUNNEL_STATS_SESSION_DECAP_QUEUE_FULL, ++ NSS_GRE_TUNNEL_STATS_SESSION_RX_SINGLE_REC_DGRAM, ++ NSS_GRE_TUNNEL_STATS_SESSION_RX_INVALID_REC_DGRAM, ++ NSS_GRE_TUNNEL_STATS_SESSION_BUFFER_ALLOC_FAIL, ++ NSS_GRE_TUNNEL_STATS_SESSION_BUFFER_COPY_FAIL, ++ NSS_GRE_TUNNEL_STATS_SESSION_OUTFLOW_QUEUE_FULL, ++ NSS_GRE_TUNNEL_STATS_SESSION_RX_DROPPED_HROOM, ++ NSS_GRE_TUNNEL_STATS_SESSION_RX_CBUFFER_ALLOC_FAIL, ++ NSS_GRE_TUNNEL_STATS_SESSION_RX_CENQUEUE_FAIL, ++ NSS_GRE_TUNNEL_STATS_SESSION_RX_DECRYPT_DONE, ++ NSS_GRE_TUNNEL_STATS_SESSION_RX_FORWARD_ENQUEUE_FAIL, ++ NSS_GRE_TUNNEL_STATS_SESSION_TX_CBUFFER_ALLOC_FAIL, ++ NSS_GRE_TUNNEL_STATS_SESSION_TX_CENQUEUE_FAIL, ++ NSS_GRE_TUNNEL_STATS_SESSION_RX_DROPPED_TROOM, ++ NSS_GRE_TUNNEL_STATS_SESSION_TX_FORWARD_ENQUEUE_FAIL, ++ NSS_GRE_TUNNEL_STATS_SESSION_TX_CIPHER_DONE, ++ NSS_GRE_TUNNEL_STATS_SESSION_CRYPTO_NOSUPP, ++ NSS_GRE_TUNNEL_STATS_SESSION_RX_DROPPED_MH_VERSION, ++ NSS_GRE_TUNNEL_STATS_SESSION_RX_UNALIGNED_PKT, ++ NSS_GRE_TUNNEL_STATS_SESSION_MAX, ++}; ++ ++/* + * GRE Tunnel session debug statistics + */ +-struct nss_gre_tunnel_stats_session { ++struct nss_gre_tunnel_stats_session_debug { + uint64_t stats[NSS_GRE_TUNNEL_STATS_SESSION_MAX + NSS_CRYPTO_CMN_RESP_ERROR_MAX]; +- /* GRE tunnel statistics */ +- int32_t if_index; /* Interface index */ +- uint32_t if_num; /* NSS interface number */ ++ int32_t if_index; ++ uint32_t if_num; /* nss interface number */ + bool valid; + }; + + /* + * Data structures to store GRE Tunnel nss debug stats + */ +-extern spinlock_t nss_gre_tunnel_stats_lock; +-extern struct nss_gre_tunnel_stats_session session_stats[NSS_MAX_GRE_TUNNEL_SESSIONS]; ++extern spinlock_t nss_gre_tunnel_stats_session_debug_lock; ++extern struct nss_gre_tunnel_stats_session_debug nss_gre_tunnel_session_debug_stats[NSS_MAX_GRE_TUNNEL_SESSIONS]; + + /* + * GRE Tunnel statistics APIs + */ +-extern void nss_gre_tunnel_stats_notify(struct nss_ctx_instance *nss_ctx, uint32_t if_num); + extern void nss_gre_tunnel_stats_session_sync(struct nss_ctx_instance *nss_ctx, struct nss_gre_tunnel_stats *stats_msg, uint16_t if_num); + extern void nss_gre_tunnel_stats_dentry_create(void); + +--- a/nss_gre_tunnel_strings.c ++++ /dev/null +@@ -1,77 +0,0 @@ +-/* +- **************************************************************************** +- * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- **************************************************************************** +- */ +- +-#include "nss_stats.h" +-#include "nss_core.h" +-#include "nss_strings.h" +-#include "nss_gre_tunnel_strings.h" +- +-/* +- * nss_gre_tunnel_strings_stats +- * GRE Tunnel statistics strings for nss session stats +- */ +-struct nss_stats_info nss_gre_tunnel_strings_stats[NSS_GRE_TUNNEL_STATS_SESSION_MAX] = { +- {"rx_pkts", NSS_STATS_TYPE_COMMON}, +- {"tx_pkts", NSS_STATS_TYPE_COMMON}, +- {"rx_queue_0_dropped", NSS_STATS_TYPE_DROP}, +- {"rx_queue_1_dropped", NSS_STATS_TYPE_DROP}, +- {"rx_queue_2_dropped", NSS_STATS_TYPE_DROP}, +- {"rx_queue_3_dropped", NSS_STATS_TYPE_DROP}, +- {"rx_malformed", NSS_STATS_TYPE_SPECIAL}, +- {"rx_invalid_prot", NSS_STATS_TYPE_SPECIAL}, +- {"decap_queue_full", NSS_STATS_TYPE_SPECIAL}, +- {"rx_single_rec_dgram", NSS_STATS_TYPE_SPECIAL}, +- {"rx_invalid_rec_dgram", NSS_STATS_TYPE_SPECIAL}, +- {"buffer_alloc_fail", NSS_STATS_TYPE_SPECIAL}, +- {"buffer_copy_fail", NSS_STATS_TYPE_SPECIAL}, +- {"outflow_queue_full", NSS_STATS_TYPE_SPECIAL}, +- {"tx_dropped_hroom", NSS_STATS_TYPE_DROP}, +- {"rx_cbuffer_alloc_fail", NSS_STATS_TYPE_SPECIAL}, +- {"rx_cenqueue_fail", NSS_STATS_TYPE_SPECIAL}, +- {"rx_decrypt_done", NSS_STATS_TYPE_SPECIAL}, +- {"rx_forward_enqueue_fail", NSS_STATS_TYPE_SPECIAL}, +- {"tx_cbuffer_alloc_fail", NSS_STATS_TYPE_SPECIAL}, +- {"tx_cenqueue_fail", NSS_STATS_TYPE_SPECIAL}, +- {"rx_dropped_troom", NSS_STATS_TYPE_DROP}, +- {"tx_forward_enqueue_fail", NSS_STATS_TYPE_SPECIAL}, +- {"tx_cipher_done", NSS_STATS_TYPE_SPECIAL}, +- {"crypto_nosupp", NSS_STATS_TYPE_SPECIAL}, +- {"rx_dropped_mh_version", NSS_STATS_TYPE_SPECIAL}, +- {"rx_unaligned_pkt", NSS_STATS_TYPE_SPECIAL} +-}; +- +-/* +- * nss_gre_tunnel_strings_read() +- * Read gre_tunnel session debug statistics names +- */ +-static ssize_t nss_gre_tunnel_strings_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- return nss_strings_print(ubuf, sz, ppos, nss_gre_tunnel_strings_stats, NSS_GRE_TUNNEL_STATS_SESSION_MAX); +-} +- +-/* +- * nss_gre_tunnel_strings_ops +- */ +-NSS_STRINGS_DECLARE_FILE_OPERATIONS(gre_tunnel); +- +-/* +- * nss_gre_tunnel_strings_dentry_create() +- * Create gre_tunnel statistics strings debug entry. +- */ +-void nss_gre_tunnel_strings_dentry_create(void) +-{ +- nss_strings_create_dentry("gre_tunnel", &nss_gre_tunnel_strings_ops); +-} +--- a/nss_gre_tunnel_strings.h ++++ /dev/null +@@ -1,25 +0,0 @@ +-/* +- **************************************************************************** +- * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- **************************************************************************** +- */ +- +-#ifndef __NSS_GRE_TUNNEL_STRINGS_H +-#define __NSS_GRE_TUNNEL_STRINGS_H +- +-#include "nss_gre_tunnel_stats.h" +- +-extern struct nss_stats_info nss_gre_tunnel_strings_stats[NSS_GRE_TUNNEL_STATS_SESSION_MAX]; +-extern void nss_gre_tunnel_strings_dentry_create(void); +- +-#endif /* __NSS_GRE_TUNNEL_STRINGS_H */ +--- a/nss_hal/fsm9010/nss_hal_pvt.c ++++ b/nss_hal/fsm9010/nss_hal_pvt.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -145,13 +145,12 @@ static struct nss_platform_data *__nss_h + npd->nphys = res_nphys.start; + npd->vphys = res_vphys.start; + +- npd->nmap = ioremap_nocache(npd->nphys, resource_size(&res_nphys)); ++ npd->nmap = ioremap(npd->nphys, resource_size(&res_nphys)); + if (!npd->nmap) { + nss_info_always("%px: nss%d: ioremap() fail for nphys\n", nss_ctx, nss_ctx->id); + goto out; + } + +- nss_assert(npd->vphys); + npd->vmap = ioremap_cache(npd->vphys, resource_size(&res_vphys)); + if (!npd->vmap) { + nss_info_always("%px: nss%d: ioremap() fail for vphys\n", nss_ctx, nss_ctx->id); +--- a/nss_hal/include/nss_hal.h ++++ b/nss_hal/include/nss_hal.h +@@ -1,12 +1,9 @@ + /* + ************************************************************************** + * Copyright (c) 2013, 2016-2020 The Linux Foundation. All rights reserved. +- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. +- * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +- * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +@@ -52,9 +49,6 @@ extern struct nss_hal_ops nss_hal_ipq50x + #if defined(NSS_HAL_FSM9010_SUPPORT) + extern struct nss_hal_ops nss_hal_fsm9010_ops; + #endif +-#if defined(NSS_HAL_IPQ95XX_SUPPORT) +-extern struct nss_hal_ops nss_hal_ipq95xx_ops; +-#endif + + #define NSS_HAL_SUPPORTED_INTERRUPTS (NSS_N2H_INTR_EMPTY_BUFFER_QUEUE | \ + NSS_N2H_INTR_DATA_QUEUE_0 | \ +--- a/nss_hal/include/nss_regs.h ++++ b/nss_hal/include/nss_regs.h +@@ -1,12 +1,9 @@ + /* + ************************************************************************** + * Copyright (c) 2013, 2015-2017, 2019-2020, The Linux Foundation. All rights reserved. +- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. +- * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +- * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +@@ -41,26 +38,16 @@ + #define NSS_REGS_C2C_INTR_CLR_OFFSET 0x001c + #define NSS_REGS_N2H_INTR_STATUS_OFFSET 0x0020 + #define NSS_REGS_N2H_INTR_SET_OFFSET 0x0024 +- +-#if defined(NSS_HAL_IPQ95XX_SUPPORT) +-#define NSS_REGS_CORE_INT_STAT0_ENABLE_OFFSET 0x0028 +-#define NSS_REGS_CORE_INT_STAT1_ENABLE_OFFSET 0x002c +-#define NSS_REGS_CORE_INT_STAT2_ENABLE_OFFSET 0x0030 +-#define NSS_REGS_CORE_INT_STAT3_ENABLE_OFFSET 0x0034 +-#elif defined(NSS_HAL_FSM9010_SUPPORT) || defined(NSS_HAL_IPQ806X_SUPPORT) + #define NSS_REGS_N2H_INTR_CLR_OFFSET 0x0028 + #define NSS_REGS_N2H_INTR_MASK_OFFSET 0x002c + #define NSS_REGS_N2H_INTR_MASK_SET_OFFSET 0x0030 + #define NSS_REGS_N2H_INTR_MASK_CLR_OFFSET 0x0034 +-#endif +- + #define NSS_REGS_CORE_INT_STAT0_TYPE_OFFSET 0x0038 + #define NSS_REGS_CORE_INT_STAT1_TYPE_OFFSET 0x003c + #define NSS_REGS_CORE_INT_STAT2_TYPE_OFFSET 0x0040 + #define NSS_REGS_CORE_INT_STAT3_TYPE_OFFSET 0x0044 + #define NSS_REGS_CORE_IFETCH_RANGE_OFFSET 0x0048 + +- + /* + * FPB register offsets + */ +--- a/nss_hal/ipq60xx/nss_hal_pvt.c ++++ b/nss_hal/ipq60xx/nss_hal_pvt.c +@@ -207,13 +207,13 @@ static struct nss_platform_data *__nss_h + npd->nphys = res_nphys.start; + npd->qgic_phys = res_qgic_phys.start; + +- npd->nmap = ioremap_nocache(npd->nphys, resource_size(&res_nphys)); ++ npd->nmap = ioremap(npd->nphys, resource_size(&res_nphys)); + if (!npd->nmap) { + nss_info_always("%px: nss%d: ioremap() fail for nphys\n", nss_ctx, nss_ctx->id); + goto out; + } + +- npd->qgic_map = ioremap_nocache(npd->qgic_phys, resource_size(&res_qgic_phys)); ++ npd->qgic_map = ioremap(npd->qgic_phys, resource_size(&res_qgic_phys)); + if (!npd->qgic_map) { + nss_info_always("%px: nss%d: ioremap() fail for qgic map\n", nss_ctx, nss_ctx->id); + goto out; +@@ -433,13 +433,13 @@ static int __nss_hal_common_reset(struct + + of_node_put(cmn); + +- nss_misc_reset = ioremap_nocache(res_nss_misc_reset.start, resource_size(&res_nss_misc_reset)); ++ nss_misc_reset = ioremap(res_nss_misc_reset.start, resource_size(&res_nss_misc_reset)); + if (!nss_misc_reset) { + pr_err("%px: ioremap fail for nss_misc_reset\n", nss_dev); + return -EFAULT; + } + +- nss_misc_reset_flag = ioremap_nocache(res_nss_misc_reset_flag.start, resource_size(&res_nss_misc_reset_flag)); ++ nss_misc_reset_flag = ioremap(res_nss_misc_reset_flag.start, resource_size(&res_nss_misc_reset_flag)); + if (!nss_misc_reset_flag) { + pr_err("%px: ioremap fail for nss_misc_reset_flag\n", nss_dev); + return -EFAULT; +--- a/nss_hal/ipq806x/nss_hal_pvt.c ++++ b/nss_hal/ipq806x/nss_hal_pvt.c +@@ -458,7 +458,7 @@ static struct nss_platform_data *__nss_h + npd->nphys = res_nphys.start; + npd->vphys = res_vphys.start; + +- npd->nmap = ioremap_nocache(npd->nphys, resource_size(&res_nphys)); ++ npd->nmap = ioremap(npd->nphys, resource_size(&res_nphys)); + if (!npd->nmap) { + nss_info_always("%px: nss%d: ioremap() fail for nphys\n", nss_ctx, nss_ctx->id); + goto out; +@@ -711,7 +711,7 @@ static int __nss_hal_common_reset(struct + } + of_node_put(cmn); + +- fpb_base = ioremap_nocache(res_nss_fpb_base.start, resource_size(&res_nss_fpb_base)); ++ fpb_base = ioremap(res_nss_fpb_base.start, resource_size(&res_nss_fpb_base)); + if (!fpb_base) { + pr_err("%px: ioremap fail for nss_fpb_base\n", nss_dev); + return -EFAULT; +--- a/nss_hal/ipq807x/nss_hal_pvt.c ++++ b/nss_hal/ipq807x/nss_hal_pvt.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -234,20 +234,19 @@ static struct nss_platform_data *__nss_h + npd->vphys = res_vphys.start; + npd->qgic_phys = res_qgic_phys.start; + +- npd->nmap = ioremap_nocache(npd->nphys, resource_size(&res_nphys)); ++ npd->nmap = ioremap(npd->nphys, resource_size(&res_nphys)); + if (!npd->nmap) { + nss_info_always("%px: nss%d: ioremap() fail for nphys\n", nss_ctx, nss_ctx->id); + goto out; + } + +- nss_assert(npd->vphys); + npd->vmap = ioremap_cache(npd->vphys, resource_size(&res_vphys)); + if (!npd->vmap) { + nss_info_always("%px: nss%d: ioremap() fail for vphys\n", nss_ctx, nss_ctx->id); + goto out; + } + +- npd->qgic_map = ioremap_nocache(npd->qgic_phys, resource_size(&res_qgic_phys)); ++ npd->qgic_map = ioremap(npd->qgic_phys, resource_size(&res_qgic_phys)); + if (!npd->qgic_map) { + nss_info_always("%px: nss%d: ioremap() fail for qgic map\n", nss_ctx, nss_ctx->id); + goto out; +@@ -467,7 +466,7 @@ static int __nss_hal_common_reset(struct + } + of_node_put(cmn); + +- nss_misc_reset = ioremap_nocache(res_nss_misc_reset.start, resource_size(&res_nss_misc_reset)); ++ nss_misc_reset = ioremap(res_nss_misc_reset.start, resource_size(&res_nss_misc_reset)); + if (!nss_misc_reset) { + pr_err("%px: ioremap fail for nss_misc_reset\n", nss_dev); + return -EFAULT; +--- a/nss_hal/nss_hal.c ++++ b/nss_hal/nss_hal.c +@@ -1,12 +1,9 @@ + /* + ************************************************************************** + * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. +- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. +- * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +- * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +@@ -27,17 +24,13 @@ + #include + #include + #include ++#include + + #include "nss_hal.h" + #include "nss_arch.h" + #include "nss_core.h" + #include "nss_tx_rx_common.h" +-#ifdef NSS_DATA_PLANE_GENERIC_SUPPORT + #include "nss_data_plane.h" +-#endif +-#ifdef NSS_DATA_PLANE_LITE_SUPPORT +-#include "nss_data_plane_lite.h" +-#endif + #if (NSS_PM_SUPPORT == 1) + #include "nss_pm.h" + #endif +@@ -81,9 +74,9 @@ int nss_hal_firmware_load(struct nss_ctx + } + + +- load_mem = ioremap_nocache(npd->load_addr, nss_fw->size); ++ load_mem = ioremap(npd->load_addr, nss_fw->size); + if (!load_mem) { +- nss_info_always("%px: ioremap_nocache failed: %x", nss_ctx, npd->load_addr); ++ nss_info_always("%px: ioremap failed: %x", nss_ctx, npd->load_addr); + release_firmware(nss_fw); + return rc; + } +@@ -95,6 +88,7 @@ int nss_hal_firmware_load(struct nss_ctx + return 0; + } + ++ + /* + * nss_hal_dt_parse_features() + */ +@@ -105,14 +99,12 @@ void nss_hal_dt_parse_features(struct de + */ + npd->bridge_enabled = of_property_read_bool(np, "qcom,bridge-enabled"); + npd->capwap_enabled = of_property_read_bool(np, "qcom,capwap-enabled"); +- npd->clmap_enabled = of_property_read_bool(np, "qcom,clmap-enabled"); + npd->crypto_enabled = of_property_read_bool(np, "qcom,crypto-enabled"); + npd->dtls_enabled = of_property_read_bool(np, "qcom,dtls-enabled"); + npd->gre_enabled = of_property_read_bool(np, "qcom,gre-enabled"); + npd->gre_redir_enabled = of_property_read_bool(np, "qcom,gre-redir-enabled"); + npd->gre_tunnel_enabled = of_property_read_bool(np, "qcom,gre_tunnel_enabled"); + npd->gre_redir_mark_enabled = of_property_read_bool(np, "qcom,gre-redir-mark-enabled"); +- npd->igs_enabled = of_property_read_bool(np, "qcom,igs-enabled"); + npd->ipsec_enabled = of_property_read_bool(np, "qcom,ipsec-enabled"); + npd->ipv4_enabled = of_property_read_bool(np, "qcom,ipv4-enabled"); + npd->ipv4_reasm_enabled = of_property_read_bool(np, "qcom,ipv4-reasm-enabled"); +@@ -126,25 +118,19 @@ void nss_hal_dt_parse_features(struct de + npd->pptp_enabled = of_property_read_bool(np, "qcom,pptp-enabled"); + npd->portid_enabled = of_property_read_bool(np, "qcom,portid-enabled"); + npd->pvxlan_enabled = of_property_read_bool(np, "qcom,pvxlan-enabled"); ++ npd->clmap_enabled = of_property_read_bool(np, "qcom,clmap-enabled"); + npd->qvpn_enabled = of_property_read_bool(np, "qcom,qvpn-enabled"); + npd->rmnet_rx_enabled = of_property_read_bool(np, "qcom,rmnet_rx-enabled"); + npd->shaping_enabled = of_property_read_bool(np, "qcom,shaping-enabled"); +- npd->tls_enabled = of_property_read_bool(np, "qcom,tls-enabled"); + npd->tstamp_enabled = of_property_read_bool(np, "qcom,tstamp-enabled"); + npd->turbo_frequency = of_property_read_bool(np, "qcom,turbo-frequency"); + npd->tun6rd_enabled = of_property_read_bool(np, "qcom,tun6rd-enabled"); + npd->tunipip6_enabled = of_property_read_bool(np, "qcom,tunipip6-enabled"); + npd->vlan_enabled = of_property_read_bool(np, "qcom,vlan-enabled"); +- npd->vxlan_enabled = of_property_read_bool(np, "qcom,vxlan-enabled"); + npd->wlanredirect_enabled = of_property_read_bool(np, "qcom,wlanredirect-enabled"); + npd->wifioffload_enabled = of_property_read_bool(np, "qcom,wlan-dataplane-offload-enabled"); +- npd->match_enabled = of_property_read_bool(np, "qcom,match-enabled"); +- npd->mirror_enabled = of_property_read_bool(np, "qcom,mirror-enabled"); +- npd->udp_st_enabled = of_property_read_bool(np, "qcom,udp-st-enabled"); +- npd->edma_lite_enabled = of_property_read_bool(np, "qcom,edma-lite-enabled"); +- npd->trustsec_enabled = of_property_read_bool(np, "qcom,trustsec-enabled"); ++ npd->igs_enabled = of_property_read_bool(np, "qcom,igs-enabled"); + } +- + /* + * nss_hal_clean_up_irq() + */ +@@ -365,7 +351,6 @@ int nss_hal_probe(struct platform_device + } + #endif + +-#ifdef NSS_DRV_IPV4_ENABLE + if (npd->ipv4_enabled == NSS_FEATURE_ENABLED) { + nss_top->ipv4_handler_id = nss_dev->id; + nss_ipv4_register_handler(); +@@ -374,15 +359,10 @@ int nss_hal_probe(struct platform_device + nss_top->edma_handler_id = nss_dev->id; + nss_edma_register_handler(); + #endif +- +-#ifdef NSS_DRV_ETH_RX_ENABLE + nss_eth_rx_register_handler(nss_ctx); +-#endif +- + #ifdef NSS_DRV_LAG_ENABLE + nss_lag_register_handler(); + #endif +- + #ifdef NSS_DRV_TRUSTSEC_ENABLE + nss_top->trustsec_tx_handler_id = nss_dev->id; + nss_trustsec_tx_register_handler(); +@@ -393,25 +373,15 @@ int nss_hal_probe(struct platform_device + nss_top->dynamic_interface_table[NSS_DYNAMIC_INTERFACE_TYPE_GENERIC_REDIR_N2H] = nss_dev->id; + nss_top->dynamic_interface_table[NSS_DYNAMIC_INTERFACE_TYPE_GENERIC_REDIR_H2N] = nss_dev->id; + } +-#endif +- +-#ifdef NSS_DRV_TRUSTSEC_RX_ENABLE +- if (npd->trustsec_enabled == NSS_FEATURE_ENABLED) { +- nss_top->trustsec_rx_handler_id = nss_dev->id; +- nss_trustsec_rx_register_handler(); +- +- nss_top->trustsec_tx_handler_id = nss_dev->id; +- nss_trustsec_tx_register_handler(); +- } +-#endif + ++#if (NSS_FW_VERSION_CODE > NSS_FW_VERSION(11,3)) + #ifdef NSS_DRV_CAPWAP_ENABLE + if (npd->capwap_enabled == NSS_FEATURE_ENABLED) { + nss_top->capwap_handler_id = nss_dev->id; +- nss_top->dynamic_interface_table[NSS_DYNAMIC_INTERFACE_TYPE_CAPWAP_OUTER] = nss_dev->id; +- nss_top->dynamic_interface_table[NSS_DYNAMIC_INTERFACE_TYPE_CAPWAP_HOST_INNER] = nss_dev->id; ++ nss_top->dynamic_interface_table[NSS_DYNAMIC_INTERFACE_TYPE_CAPWAP] = nss_dev->id; + } + #endif ++#endif + + #ifdef NSS_DRV_IPV4_REASM_ENABLE + if (npd->ipv4_reasm_enabled == NSS_FEATURE_ENABLED) { +@@ -441,7 +411,7 @@ int nss_hal_probe(struct platform_device + */ + if (npd->crypto_enabled == NSS_FEATURE_ENABLED) { + nss_top->crypto_handler_id = nss_dev->id; +-#if defined(NSS_HAL_IPQ807x_SUPPORT) || defined(NSS_HAL_IPQ60XX_SUPPORT) || defined(NSS_HAL_IPQ50XX_SUPPORT) || defined(NSS_HAL_IPQ95XX_SUPPORT) ++#if defined(NSS_HAL_IPQ807x_SUPPORT) || defined(NSS_HAL_IPQ60XX_SUPPORT) || defined(NSS_HAL_IPQ50XX_SUPPORT) + nss_crypto_cmn_register_handler(); + #else + nss_top->crypto_enabled = 1; +@@ -513,7 +483,7 @@ int nss_hal_probe(struct platform_device + #ifdef NSS_DRV_DTLS_ENABLE + if (npd->dtls_enabled == NSS_FEATURE_ENABLED) { + nss_top->dtls_handler_id = nss_dev->id; +-#if defined(NSS_HAL_IPQ807x_SUPPORT) || defined(NSS_HAL_IPQ60XX_SUPPORT) || defined(NSS_HAL_IPQ50XX_SUPPORT) || defined(NSS_HAL_IPQ95XX_SUPPORT) ++#if defined(NSS_HAL_IPQ807x_SUPPORT) || defined(NSS_HAL_IPQ60XX_SUPPORT) || defined(NSS_HAL_IPQ50XX_SUPPORT) + nss_top->dynamic_interface_table[NSS_DYNAMIC_INTERFACE_TYPE_DTLS_CMN_INNER] = nss_dev->id; + nss_top->dynamic_interface_table[NSS_DYNAMIC_INTERFACE_TYPE_DTLS_CMN_OUTER] = nss_dev->id; + nss_dtls_cmn_register_handler(); +@@ -588,33 +558,24 @@ int nss_hal_probe(struct platform_device + } + #endif + +-#ifdef NSS_DRV_WIFIOFFLOAD_ENABLE ++#ifdef NSS_DRV_WIFI_ENABLE + if (npd->wifioffload_enabled == NSS_FEATURE_ENABLED) { + nss_top->wifi_handler_id = nss_dev->id; + nss_top->dynamic_interface_table[NSS_DYNAMIC_INTERFACE_TYPE_VAP] = nss_dev->id; + nss_wifi_register_handler(); + nss_wifili_register_handler(); +-#ifdef NSS_DRV_WIFI_EXT_VDEV_ENABLE +- nss_wifi_ext_vdev_register_handler(); +-#endif ++#if (NSS_FW_VERSION_CODE <= NSS_FW_VERSION(11,0)) ++ nss_top->dynamic_interface_table[NSS_DYNAMIC_INTERFACE_TYPE_WIFILI] = nss_dev->id; ++#else + nss_top->dynamic_interface_table[NSS_DYNAMIC_INTERFACE_TYPE_WIFILI_INTERNAL] = nss_dev->id; + nss_top->dynamic_interface_table[NSS_DYNAMIC_INTERFACE_TYPE_WIFILI_EXTERNAL0] = nss_dev->id; + nss_top->dynamic_interface_table[NSS_DYNAMIC_INTERFACE_TYPE_WIFILI_EXTERNAL1] = nss_dev->id; +- nss_top->dynamic_interface_table[NSS_DYNAMIC_INTERFACE_TYPE_WIFI_EXT_VDEV_WDS] = nss_dev->id; +- nss_top->dynamic_interface_table[NSS_DYNAMIC_INTERFACE_TYPE_WIFI_EXT_VDEV_VLAN] = nss_dev->id; +- nss_top->dynamic_interface_table[NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER] = nss_dev->id; +- nss_top->dynamic_interface_table[NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_OUTER] = nss_dev->id; +- + /* + * Register wifi mac database when offload enabled + */ + nss_top->wmdb_handler_id = nss_dev->id; + nss_wifi_mac_db_register_handler(); +- +- /* +- * Initialize wifili thread scheme database +- */ +- nss_wifili_thread_scheme_db_init(nss_dev->id); ++#endif + } + #endif + +@@ -701,6 +662,7 @@ int nss_hal_probe(struct platform_device + } + #endif + ++#if (NSS_FW_VERSION_CODE > NSS_FW_VERSION(11,1)) + #ifdef NSS_DRV_TLS_ENABLE + #if defined(NSS_HAL_IPQ807x_SUPPORT) || defined(NSS_HAL_IPQ60XX_SUPPORT) + if (npd->tls_enabled == NSS_FEATURE_ENABLED) { +@@ -711,7 +673,6 @@ int nss_hal_probe(struct platform_device + } + #endif + #endif +- + #ifdef NSS_DRV_MIRROR_ENABLE + if (npd->mirror_enabled == NSS_FEATURE_ENABLED) { + nss_top->mirror_handler_id = nss_dev->id; +@@ -719,14 +680,7 @@ int nss_hal_probe(struct platform_device + nss_mirror_register_handler(); + nss_info("%d: NSS mirror is enabled", nss_dev->id); + } +- + #endif +- +-#ifdef NSS_DRV_UDP_ST_ENABLE +- if (npd->udp_st_enabled == NSS_FEATURE_ENABLED) { +- nss_top->udp_st_handler_id = nss_dev->id; +- nss_udp_st_register_handler(nss_ctx); +- } + #endif + + if (nss_ctx->id == 0) { +@@ -740,19 +694,8 @@ int nss_hal_probe(struct platform_device + nss_freq_init_cpu_usage(); + #endif + +-#ifdef NSS_DRV_LSO_RX_ENABLE + nss_lso_rx_register_handler(nss_ctx); +-#endif +- } +- +-#ifdef NSS_DRV_EDMA_LITE_ENABLE +- if (npd->edma_lite_enabled == NSS_FEATURE_ENABLED) { +- nss_top->edma_lite_handler_id[nss_ctx->id] = nss_ctx->id; +- nss_edma_lite_register_handler(nss_ctx); +- } else { +- nss_top->edma_lite_handler_id[nss_ctx->id] = -1; + } +-#endif + + nss_top->frequency_handler_id = nss_dev->id; + +@@ -798,7 +741,7 @@ int nss_hal_probe(struct platform_device + nss_hal_enable_interrupt(nss_ctx, nss_ctx->int_ctx[i].shift_factor, NSS_HAL_SUPPORTED_INTERRUPTS); + } + +- nss_info_always("%px: All resources initialized and nss core%d has been brought out of reset", nss_ctx, nss_dev->id); ++ nss_info("%px: All resources initialized and nss core%d has been brought out of reset", nss_ctx, nss_dev->id); + goto out; + + err_register_irq: +@@ -851,13 +794,7 @@ int nss_hal_remove(struct platform_devic + /* + * nss-drv is exiting, unregister and restore host data plane + */ +-#ifdef NSS_DATA_PLANE_GENERIC_SUPPORT + nss_top->data_plane_ops->data_plane_unregister(); +-#endif +- +-#ifdef NSS_DATA_PLANE_LITE_SUPPORT +- nss_data_plane_lite_unregister(); +-#endif + + #if (NSS_FABRIC_SCALING_SUPPORT == 1) + fab_scaling_unregister(nss_core0_clk); +--- a/nss_if.c ++++ b/nss_if.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2014-2016, 2018-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2014-2016, 2018-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -160,10 +160,10 @@ nss_tx_status_t nss_if_tx_buf(struct nss + } + + /* +- * nss_if_tx_msg_with_size() +- * Transmit a message to the specific interface on this core with a specified size. ++ * nss_if_tx_msg() ++ * Transmit a message to the specific interface on this core. + */ +-nss_tx_status_t nss_if_tx_msg_with_size(struct nss_ctx_instance *nss_ctx, struct nss_if_msg *nim, uint32_t size) ++nss_tx_status_t nss_if_tx_msg(struct nss_ctx_instance *nss_ctx, struct nss_if_msg *nim) + { + struct nss_cmn_msg *ncm = &nim->cm; + struct net_device *dev; +@@ -198,19 +198,7 @@ nss_tx_status_t nss_if_tx_msg_with_size( + return NSS_TX_FAILURE_BAD_PARAM; + } + +- return nss_core_send_cmd(nss_ctx, nim, sizeof(*nim), size); +-} +-EXPORT_SYMBOL(nss_if_tx_msg_with_size); +- +-/* +- * nss_if_tx_msg() +- * Transmit a message to the specific interface on this core. +- */ +-nss_tx_status_t nss_if_tx_msg(struct nss_ctx_instance *nss_ctx, struct nss_if_msg *nim) +-{ +- NSS_VERIFY_CTX_MAGIC(nss_ctx); +- +- return nss_if_tx_msg_with_size(nss_ctx, nim, NSS_NBUF_PAYLOAD_SIZE); ++ return nss_core_send_cmd(nss_ctx, nim, sizeof(*nim), NSS_NBUF_PAYLOAD_SIZE); + } + + /* +@@ -277,90 +265,6 @@ nss_tx_status_t nss_if_set_nexthop(struc + } + EXPORT_SYMBOL(nss_if_set_nexthop); + +-/* +- * nss_if_change_mtu() +- * Change the MTU of the interface. +- */ +-nss_tx_status_t nss_if_change_mtu(struct nss_ctx_instance *nss_ctx, nss_if_num_t if_num, uint16_t mtu) +-{ +- struct nss_if_msg nim; +- +- NSS_VERIFY_CTX_MAGIC(nss_ctx); +- +- nss_trace("%px: NSS If MTU will be changed to %u, of NSS if num: %u\n", nss_ctx, mtu, if_num); +- +- nss_cmn_msg_init(&nim.cm, if_num, NSS_IF_MTU_CHANGE, +- sizeof(struct nss_if_mtu_change), nss_if_callback, NULL); +- +- nim.msg.mtu_change.min_buf_size = mtu; +- +- return nss_if_msg_sync(nss_ctx, &nim); +-} +-EXPORT_SYMBOL(nss_if_change_mtu); +- +-/* +- * nss_if_change_mac_addr() +- * Change the MAC address of the interface. +- */ +-nss_tx_status_t nss_if_change_mac_addr(struct nss_ctx_instance *nss_ctx, nss_if_num_t if_num, uint8_t *mac_addr) +-{ +- struct nss_if_msg nim; +- +- NSS_VERIFY_CTX_MAGIC(nss_ctx); +- +- nss_trace("%px: NSS If MAC address will be changed to %s, of NSS if num: %u\n", nss_ctx, mac_addr, if_num); +- +- nss_cmn_msg_init(&nim.cm, if_num, NSS_IF_MAC_ADDR_SET, +- sizeof(struct nss_if_mac_address_set), nss_if_callback, NULL); +- +- memcpy(nim.msg.mac_address_set.mac_addr, mac_addr, ETH_ALEN); +- +- return nss_if_msg_sync(nss_ctx, &nim); +-} +-EXPORT_SYMBOL(nss_if_change_mac_addr); +- +-/* +- * nss_if_vsi_unassign() +- * API to send VSI detach message to NSS FW. +- */ +-nss_tx_status_t nss_if_vsi_unassign(struct nss_ctx_instance *nss_ctx, nss_if_num_t if_num, uint32_t vsi) +-{ +- struct nss_if_msg nim; +- +- NSS_VERIFY_CTX_MAGIC(nss_ctx); +- +- nss_trace("%px: VSI to be unassigned is %u\n", nss_ctx, vsi); +- +- nss_cmn_msg_init(&nim.cm, if_num, NSS_IF_VSI_UNASSIGN, +- sizeof(struct nss_if_vsi_unassign), nss_if_callback, NULL); +- +- nim.msg.vsi_unassign.vsi = vsi; +- +- return nss_if_msg_sync(nss_ctx, &nim); +-} +-EXPORT_SYMBOL(nss_if_vsi_unassign); +- +-/* +- * nss_if_vsi_assign() +- * API to send VSI attach message to NSS FW. +- */ +-nss_tx_status_t nss_if_vsi_assign(struct nss_ctx_instance *nss_ctx, nss_if_num_t if_num, uint32_t vsi) +-{ +- struct nss_if_msg nim; +- +- NSS_VERIFY_CTX_MAGIC(nss_ctx); +- +- nss_trace("%px: VSI to be assigned is %u\n", nss_ctx, vsi); +- +- nss_cmn_msg_init(&nim.cm, if_num, NSS_IF_VSI_ASSIGN, +- sizeof(struct nss_if_vsi_assign), nss_if_callback, NULL); +- +- nim.msg.vsi_assign.vsi = vsi; +- +- return nss_if_msg_sync(nss_ctx, &nim); +-} +-EXPORT_SYMBOL(nss_if_vsi_assign); +- + EXPORT_SYMBOL(nss_if_tx_msg); + EXPORT_SYMBOL(nss_if_register); + EXPORT_SYMBOL(nss_if_unregister); +--- a/nss_igs.c ++++ b/nss_igs.c +@@ -14,14 +14,12 @@ + ************************************************************************** + */ + +-#include "nss_tx_rx_common.h" +-#include "nss_igs_stats.h" +- +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 4, 0)) + #ifdef CONFIG_NET_CLS_ACT + #include + #endif +-#endif ++ ++#include "nss_tx_rx_common.h" ++#include "nss_igs_stats.h" + + static struct module *nss_igs_module; + +--- a/nss_init.c ++++ b/nss_init.c +@@ -1,12 +1,9 @@ + /* + ************************************************************************** + * Copyright (c) 2013-2021, The Linux Foundation. All rights reserved. +- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. +- * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +- * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +@@ -27,12 +24,7 @@ + #include "nss_pm.h" + #endif + #include "nss_tx_rx_common.h" +-#ifdef NSS_DATA_PLANE_GENERIC_SUPPORT + #include "nss_data_plane.h" +-#endif +-#ifdef NSS_DATA_PLANE_LITE_SUPPORT +-#include "nss_data_plane_lite.h" +-#endif + #include "nss_capwap.h" + #include "nss_strings.h" + +@@ -641,24 +633,10 @@ static struct ctl_table_header *nss_dev_ + */ + static int __init nss_init(void) + { +-#if defined(NSS_DRV_POINT_OFFLOAD) +- struct device_node *pof = NULL; +-#endif +- +- + #if (NSS_DT_SUPPORT == 1) + struct device_node *cmn = NULL; + #endif +- +-#if defined(NSS_DRV_POINT_OFFLOAD) +- pof = of_find_node_by_name(NULL, "reg_update"); +- if ((!pof) || (!of_property_read_bool(pof, "ubi_core_enable"))) { +- nss_info_always("UBI is not enabled. Disable qca-nss-drv\n"); +- return 0; +- } +-#endif +- +-nss_info("Init NSS driver"); ++ nss_info("Init NSS driver"); + + #if (NSS_DT_SUPPORT == 1) + /* +@@ -677,18 +655,14 @@ nss_info("Init NSS driver"); + #if defined(NSS_HAL_IPQ806X_SUPPORT) + if (of_machine_is_compatible("qcom,ipq8064") || of_machine_is_compatible("qcom,ipq8062")) { + nss_top_main.hal_ops = &nss_hal_ipq806x_ops; +-#ifdef NSS_DATA_PLANE_GENERIC_SUPPORT + nss_top_main.data_plane_ops = &nss_data_plane_gmac_ops; +-#endif + nss_top_main.num_nss = 2; + } + #endif + #if defined(NSS_HAL_IPQ807x_SUPPORT) + if (of_machine_is_compatible("qcom,ipq807x") || of_machine_is_compatible("qcom,ipq8074")) { + nss_top_main.hal_ops = &nss_hal_ipq807x_ops; +-#ifdef NSS_DATA_PLANE_GENERIC_SUPPORT + nss_top_main.data_plane_ops = &nss_data_plane_ops; +-#endif + #if defined(NSS_MEM_PROFILE_LOW) + nss_top_main.num_nss = 1; + #else +@@ -699,35 +673,21 @@ nss_info("Init NSS driver"); + #if defined(NSS_HAL_IPQ60XX_SUPPORT) + if (of_machine_is_compatible("qcom,ipq6018")) { + nss_top_main.hal_ops = &nss_hal_ipq60xx_ops; +-#ifdef NSS_DATA_PLANE_GENERIC_SUPPORT + nss_top_main.data_plane_ops = &nss_data_plane_ops; +-#endif + nss_top_main.num_nss = 1; + } + #endif + #if defined(NSS_HAL_IPQ50XX_SUPPORT) + if (of_machine_is_compatible("qcom,ipq5018")) { + nss_top_main.hal_ops = &nss_hal_ipq50xx_ops; +-#ifdef NSS_DATA_PLANE_GENERIC_SUPPORT + nss_top_main.data_plane_ops = &nss_data_plane_ops; +-#endif + nss_top_main.num_nss = 1; + } + #endif +- +-#if defined(NSS_HAL_IPQ95XX_SUPPORT) +- if (of_machine_is_compatible("qcom,ipq9574-emulation") || of_machine_is_compatible("qcom,ipq9574")) { +- nss_top_main.hal_ops = &nss_hal_ipq95xx_ops; +- nss_top_main.num_nss = 1; +- } +-#endif +- + #if defined(NSS_HAL_FSM9010_SUPPORT) + if (of_machine_is_compatible("qcom,fsm9010")) { + nss_top_main.hal_ops = &nss_hal_fsm9010_ops; +-#ifdef NSS_DATA_PLANE_GENERIC_SUPPORT + nss_top_main.data_plane_ops = &nss_data_plane_gmac_ops; +-#endif + nss_top_main.num_nss = 1; + } + #endif +@@ -740,9 +700,7 @@ nss_info("Init NSS driver"); + * For banana, only ipq806x is supported + */ + nss_top_main.hal_ops = &nss_hal_ipq806x_ops; +-#ifdef NSS_DATA_PLANE_GENERIC_SUPPORT + nss_top_main.data_plane_ops = &nss_data_plane_gmac_ops; +-#endif + nss_top_main.num_nss = 2; + + #endif /* NSS_DT_SUPPORT */ +@@ -751,20 +709,11 @@ nss_info("Init NSS driver"); + /* + * Initialize data_plane workqueue + */ +- +-#ifdef NSS_DATA_PLANE_GENERIC_SUPPORT + if (nss_data_plane_init_delay_work()) { + nss_warning("Error initializing nss_data_plane_workqueue\n"); + return -EFAULT; + } +-#endif + +-#ifdef NSS_DATA_PLANE_LITE_SUPPORT +- if (nss_data_plane_lite_init_delay_work()){ +- nss_warning("Error initializing nss_data_plane_lite_workqueue\n"); +- return -EFAULT; +- } +-#endif + /* + * Enable spin locks + */ +@@ -790,9 +739,7 @@ nss_info("Init NSS driver"); + /* + * Registering sysctl for ipv4/6 specific config. + */ +-#ifdef NSS_DRV_IPV4_ENABLE + nss_ipv4_register_sysctl(); +-#endif + #ifdef NSS_DRV_IPV6_ENABLE + nss_ipv6_register_sysctl(); + #endif +@@ -828,13 +775,12 @@ nss_info("Init NSS driver"); + */ + nss_project_register_sysctl(); + ++#ifdef NSS_DRV_PPPOE_ENABLE + /* + * Registering sysctl for pppoe specific config. + */ +-#ifdef NSS_DRV_PPPOE_ENABLE + nss_pppoe_register_sysctl(); + #endif +- + /* + * Setup Runtime Sample values + */ +@@ -928,13 +874,6 @@ nss_info("Init NSS driver"); + #endif + + /* +- * Init Wi-Fi mesh +- */ +-#ifdef NSS_DRV_WIFI_MESH_ENABLE +- nss_wifi_mesh_init(); +-#endif +- +- /* + * Register platform_driver + */ + return platform_driver_register(&nss_driver); +@@ -968,20 +907,18 @@ static void __exit nss_cleanup(void) + nss_c2c_tx_unregister_sysctl(); + #endif + ++#ifdef NSS_DRV_PPPOE_ENABLE + /* + * Unregister pppoe specific sysctl + */ +-#ifdef NSS_DRV_PPPOE_ENABLE + nss_pppoe_unregister_sysctl(); + #endif + + /* + * Unregister ipv4/6 specific sysctl and free allocated to connection tables + */ +-#ifdef NSS_DRV_IPV4_ENABLE + nss_ipv4_unregister_sysctl(); + nss_ipv4_free_conn_tables(); +-#endif + + #ifdef NSS_DRV_IPV6_ENABLE + nss_ipv6_unregister_sysctl(); +@@ -989,14 +926,7 @@ static void __exit nss_cleanup(void) + #endif + + nss_project_unregister_sysctl(); +- +-#ifdef NSS_DATA_PLANE_GENERIC_SUPPORT + nss_data_plane_destroy_delay_work(); +-#endif +- +-#ifdef NSS_DATA_PLANE_LITE_SUPPORT +- nss_data_plane_lite_destroy_delay_work(); +-#endif + + /* + * cleanup ppe on supported platform +--- a/nss_ipsec_cmn.c ++++ b/nss_ipsec_cmn.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -19,11 +19,11 @@ + #include "nss_ipsec_cmn.h" + #include "nss_ppe.h" + #include "nss_ipsec_cmn_log.h" +-#include "nss_ipsec_cmn_stats.h" +-#include "nss_ipsec_cmn_strings.h" + + #define NSS_IPSEC_CMN_TX_TIMEOUT 3000 /* 3 Seconds */ + #define NSS_IPSEC_CMN_INTERFACE_MAX_LONG BITS_TO_LONGS(NSS_MAX_NET_INTERFACES) ++#define NSS_IPSEC_CMN_STATS_MAX_LINES (NSS_STATS_NODE_MAX + 32) ++#define NSS_IPSEC_CMN_STATS_SIZE_PER_IF (NSS_STATS_MAX_STR_LENGTH * NSS_IPSEC_CMN_STATS_MAX_LINES) + + /* + * Private data structure for handling synchronous messaging. +@@ -36,6 +36,104 @@ static struct nss_ipsec_cmn_pvt { + } ipsec_cmn_pvt; + + /* ++ * nss_ipsec_cmn_stats_sync() ++ * Update ipsec_cmn node statistics. ++ */ ++static void nss_ipsec_cmn_stats_sync(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm) ++{ ++ struct nss_ipsec_cmn_msg *nicm = (struct nss_ipsec_cmn_msg *)ncm; ++ struct nss_top_instance *nss_top = nss_ctx->nss_top; ++ struct nss_cmn_node_stats *msg_stats = &nicm->msg.ctx_sync.stats.cmn_stats; ++ uint64_t *if_stats; ++ int8_t i; ++ ++ spin_lock_bh(&nss_top->stats_lock); ++ ++ /* ++ * Update common node stats, ++ * Note: DTLS only supports a single queue for RX ++ */ ++ if_stats = nss_top->stats_node[ncm->interface]; ++ if_stats[NSS_STATS_NODE_RX_PKTS] += msg_stats->rx_packets; ++ if_stats[NSS_STATS_NODE_RX_BYTES] += msg_stats->rx_bytes; ++ ++ for (i = 0; i < NSS_MAX_NUM_PRI; i++) { ++ if_stats[NSS_STATS_NODE_RX_QUEUE_0_DROPPED + i] += msg_stats->rx_dropped[i]; ++ } ++ ++ if_stats[NSS_STATS_NODE_TX_PKTS] += msg_stats->tx_packets; ++ if_stats[NSS_STATS_NODE_TX_BYTES] += msg_stats->tx_bytes; ++ ++ spin_unlock_bh(&nss_top->stats_lock); ++} ++ ++/* ++ * nss_ipsec_cmn_stats_read() ++ * Read ipsec_cmn node statistics. ++ */ ++static ssize_t nss_ipsec_cmn_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) ++{ ++ struct nss_ctx_instance *nss_ctx = nss_ipsec_cmn_get_context(); ++ enum nss_dynamic_interface_type type; ++ ssize_t bytes_read = 0; ++ size_t len = 0, size; ++ uint32_t if_num; ++ char *buf; ++ ++ size = NSS_IPSEC_CMN_STATS_SIZE_PER_IF * bitmap_weight(ipsec_cmn_pvt.if_map, NSS_MAX_NET_INTERFACES); ++ ++ buf = kzalloc(size, GFP_KERNEL); ++ if (!buf) { ++ nss_warning("Could not allocate memory for local statistics buffer\n"); ++ return 0; ++ } ++ ++ len += nss_stats_banner(buf, len, size, "ipsec_cmn", NSS_STATS_SINGLE_CORE); ++ ++ /* ++ * Common node stats for each IPSEC dynamic interface. ++ */ ++ for_each_set_bit(if_num, ipsec_cmn_pvt.if_map, NSS_MAX_NET_INTERFACES) { ++ ++ type = nss_dynamic_interface_get_type(nss_ctx, if_num); ++ switch (type) { ++ case NSS_DYNAMIC_INTERFACE_TYPE_IPSEC_CMN_INNER: ++ len += scnprintf(buf + len, size - len, "\nInner if_num:%03u", if_num); ++ break; ++ ++ case NSS_DYNAMIC_INTERFACE_TYPE_IPSEC_CMN_MDATA_INNER: ++ len += scnprintf(buf + len, size - len, "\nMetadata inner if_num:%03u", if_num); ++ break; ++ ++ case NSS_DYNAMIC_INTERFACE_TYPE_IPSEC_CMN_OUTER: ++ len += scnprintf(buf + len, size - len, "\nOuter if_num:%03u", if_num); ++ break; ++ ++ case NSS_DYNAMIC_INTERFACE_TYPE_IPSEC_CMN_MDATA_OUTER: ++ len += scnprintf(buf + len, size - len, "\nMetadata outer if_num:%03u", if_num); ++ break; ++ ++ default: ++ len += scnprintf(buf + len, size - len, "\nUnknown(%d) if_num:%03u", type, if_num); ++ break; ++ } ++ ++ len += scnprintf(buf + len, size - len, "\n-------------------\n"); ++ len += nss_stats_fill_common_stats(if_num, NSS_STATS_SINGLE_INSTANCE, buf, len, size - len, "ipsec_cmn"); ++ } ++ ++ bytes_read = simple_read_from_buffer(ubuf, sz, ppos, buf, len); ++ kfree(buf); ++ ++ return bytes_read; ++} ++ ++/* ++ * nss_ipsec_cmn_stats_ops ++ */ ++NSS_STATS_DECLARE_FILE_OPERATIONS(ipsec_cmn) ++ ++/* + * nss_ipsec_cmn_verify_ifnum() + * Verify if the interface number is a IPsec interface. + */ +@@ -91,10 +189,8 @@ static void nss_ipsec_cmn_msg_handler(st + return; + } + +- if (ncm->type == NSS_IPSEC_CMN_MSG_TYPE_CTX_SYNC) { ++ if (ncm->type == NSS_IPSEC_CMN_MSG_TYPE_CTX_SYNC) + nss_ipsec_cmn_stats_sync(nss_ctx, ncm); +- nss_ipsec_cmn_stats_notify(nss_ctx, ncm->interface); +- } + + /* + * Update the callback and app_data for NOTIFY messages, ipsec_cmn sends all notify messages +@@ -102,7 +198,7 @@ static void nss_ipsec_cmn_msg_handler(st + */ + if (ncm->response == NSS_CMN_RESPONSE_NOTIFY) { + ncm->cb = (nss_ptr_t)nss_core_get_msg_handler(nss_ctx, ncm->interface); +- ncm->app_data = (nss_ptr_t)nss_ctx->nss_rx_interface_handlers[ncm->interface].app_data; ++ ncm->app_data = (nss_ptr_t)nss_ctx->nss_rx_interface_handlers[nss_ctx->id][ncm->interface].app_data; + } + + /* +@@ -151,15 +247,6 @@ static void nss_ipsec_cmn_sync_resp(void + } + + /* +- * nss_ipsec_cmn_ifmap_get() +- * Return IPsec common active interfaces map. +- */ +-unsigned long *nss_ipsec_cmn_ifmap_get(void) +-{ +- return ipsec_cmn_pvt.if_map; +-} +- +-/* + * nss_ipsec_cmn_get_context() + * Retrieve context for IPSEC redir. + */ +@@ -335,10 +422,8 @@ struct nss_ctx_instance *nss_ipsec_cmn_r + return NULL; + } + +-#ifdef NSS_DRV_PPE_ENABLE + if (features & NSS_IPSEC_CMN_FEATURE_INLINE_ACCEL) + nss_ppe_tx_ipsec_add_intf_msg(nss_ipsec_cmn_get_ifnum_with_coreid(if_num)); +-#endif + + /* + * Registering handler for sending tunnel interface msgs to NSS. +@@ -520,6 +605,5 @@ void nss_ipsec_cmn_register_handler(void + { + sema_init(&ipsec_cmn_pvt.sem, 1); + init_completion(&ipsec_cmn_pvt.complete); +- nss_ipsec_cmn_stats_dentry_create(); +- nss_ipsec_cmn_strings_dentry_create(); ++ nss_stats_create_dentry("ipsec_cmn", &nss_ipsec_cmn_stats_ops); + } +--- a/nss_ipsec_cmn_stats.c ++++ /dev/null +@@ -1,219 +0,0 @@ +-/* +- *************************************************************************** +- * Copyright (c) 2021, The Linux Foundation. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- *************************************************************************** +- */ +- +-#include "nss_core.h" +-#include "nss_ipsec_cmn.h" +-#include "nss_ipsec_cmn_stats.h" +-#include "nss_ipsec_cmn_strings.h" +- +-/* +- * Declare atomic notifier data structure for statistics. +- */ +-ATOMIC_NOTIFIER_HEAD(nss_ipsec_cmn_stats_notifier); +- +-/* +- * Spinlock to protect IPsec common statistics update/read +- */ +-DEFINE_SPINLOCK(nss_ipsec_cmn_stats_lock); +- +-unsigned long *nss_ipsec_cmn_ifmap_get(void); +-const char *nss_ipsec_cmn_stats_iface_type(enum nss_dynamic_interface_type type); +- +-/* +- * nss_ipsec_cmn_stats +- * ipsec common statistics +- */ +-uint64_t nss_ipsec_cmn_stats[NSS_MAX_NET_INTERFACES][NSS_IPSEC_CMN_STATS_MAX]; +- +-/* +- * nss_ipsec_cmn_stats_read() +- * Read ipsec_cmn node statistics. +- */ +-static ssize_t nss_ipsec_cmn_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- /* +- * Max output lines = #stats + +- * few blank lines for banner printing + Number of Extra outputlines +- * for future reference to add new stats +- */ +- uint32_t max_output_lines = NSS_IPSEC_CMN_STATS_MAX + NSS_STATS_EXTRA_OUTPUT_LINES; +- size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines; +- struct nss_ctx_instance *nss_ctx = nss_ipsec_cmn_get_context(); +- enum nss_dynamic_interface_type type; +- unsigned long *ifmap; +- uint64_t *stats_shadow; +- ssize_t bytes_read = 0; +- size_t size_wr = 0; +- uint32_t if_num; +- int32_t i; +- int count; +- char *lbuf; +- +- ifmap = nss_ipsec_cmn_ifmap_get(); +- count = bitmap_weight(ifmap, NSS_MAX_NET_INTERFACES); +- if (count) { +- size_al = size_al * count; +- } +- +- lbuf = vzalloc(size_al); +- if (unlikely(!lbuf)) { +- nss_warning("Could not allocate memory for local statistics buffer"); +- return -ENOMEM; +- } +- +- stats_shadow = vzalloc(NSS_IPSEC_CMN_STATS_MAX * 8); +- if (unlikely(!stats_shadow)) { +- nss_warning("Could not allocate memory for local shadow buffer"); +- vfree(lbuf); +- return -ENOMEM; +- } +- +- /* +- * Common node stats for each IPSEC dynamic interface. +- */ +- size_wr += nss_stats_banner(lbuf, size_wr, size_al, "ipsec_cmn stats", NSS_STATS_SINGLE_CORE); +- for_each_set_bit(if_num, ifmap, NSS_MAX_NET_INTERFACES) { +- +- type = nss_dynamic_interface_get_type(nss_ctx, if_num); +- if ((type < NSS_DYNAMIC_INTERFACE_TYPE_IPSEC_CMN_INNER) || +- (type > NSS_DYNAMIC_INTERFACE_TYPE_IPSEC_CMN_REDIRECT)) { +- continue; +- } +- +- spin_lock_bh(&nss_ipsec_cmn_stats_lock); +- for (i = 0; i < NSS_IPSEC_CMN_STATS_MAX; i++) { +- stats_shadow[i] = nss_ipsec_cmn_stats[if_num][i]; +- } +- spin_unlock_bh(&nss_ipsec_cmn_stats_lock); +- +- size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\n%s if_num:%03u\n", +- nss_ipsec_cmn_stats_iface_type(type), if_num); +- size_wr += nss_stats_print("ipsec_cmn", NULL, NSS_STATS_SINGLE_INSTANCE, nss_ipsec_cmn_strings_stats, +- stats_shadow, NSS_IPSEC_CMN_STATS_MAX, lbuf, size_wr, size_al); +- } +- +- bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf)); +- vfree(lbuf); +- vfree(stats_shadow); +- +- return bytes_read; +-} +- +-/* +- * nss_ipsec_cmn_stats_ops. +- */ +-NSS_STATS_DECLARE_FILE_OPERATIONS(ipsec_cmn); +- +-/* +- * nss_ipsec_cmn_stats_sync() +- * Update ipsec_cmn node statistics. +- */ +-void nss_ipsec_cmn_stats_sync(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm) +-{ +- struct nss_ipsec_cmn_msg *nicm = (struct nss_ipsec_cmn_msg *)ncm; +- struct nss_ipsec_cmn_ctx_stats *ndccs = &nicm->msg.ctx_sync.stats; +- uint64_t *ctx_stats; +- uint32_t *msg_stats; +- uint16_t i = 0; +- +- spin_lock_bh(&nss_ipsec_cmn_stats_lock); +- +- msg_stats = (uint32_t *)ndccs; +- ctx_stats = nss_ipsec_cmn_stats[ncm->interface]; +- +- for (i = 0; i < NSS_IPSEC_CMN_STATS_MAX; i++, ctx_stats++, msg_stats++) { +- *ctx_stats += *msg_stats; +- } +- +- spin_unlock_bh(&nss_ipsec_cmn_stats_lock); +-} +- +-/* +- * nss_ipsec_cmn_stats_iface_type() +- * Return a string for each interface type. +- */ +-const char *nss_ipsec_cmn_stats_iface_type(enum nss_dynamic_interface_type type) +-{ +- switch (type) { +- case NSS_DYNAMIC_INTERFACE_TYPE_IPSEC_CMN_INNER: +- return "ipsec_cmn_inner"; +- +- case NSS_DYNAMIC_INTERFACE_TYPE_IPSEC_CMN_MDATA_INNER: +- return "ipsec_cmn_mdata_inner"; +- +- case NSS_DYNAMIC_INTERFACE_TYPE_IPSEC_CMN_OUTER: +- return "ipsec_cmn_outer"; +- +- case NSS_DYNAMIC_INTERFACE_TYPE_IPSEC_CMN_MDATA_OUTER: +- return "ipsec_cmn_mdata_outer"; +- +- case NSS_DYNAMIC_INTERFACE_TYPE_IPSEC_CMN_REDIRECT: +- return "ipsec_cmn_redirect"; +- +- default: +- return "invalid_interface"; +- } +-} +- +-/* +- * nss_ipsec_cmn_stats_notify() +- * Sends notifications to all the registered modules. +- * +- * Leverage NSS-FW statistics timing to update Netlink. +- */ +-void nss_ipsec_cmn_stats_notify(struct nss_ctx_instance *nss_ctx, uint32_t if_num) +-{ +- struct nss_ipsec_cmn_stats_notification ipsec_cmn_stats; +- +- spin_lock_bh(&nss_ipsec_cmn_stats_lock); +- ipsec_cmn_stats.core_id = nss_ctx->id; +- ipsec_cmn_stats.if_num = if_num; +- memcpy(ipsec_cmn_stats.stats_ctx, nss_ipsec_cmn_stats[if_num], sizeof(ipsec_cmn_stats.stats_ctx)); +- spin_unlock_bh(&nss_ipsec_cmn_stats_lock); +- +- atomic_notifier_call_chain(&nss_ipsec_cmn_stats_notifier, NSS_STATS_EVENT_NOTIFY, &ipsec_cmn_stats); +-} +- +-/* +- * nss_ipsec_cmn_stats_unregister_notifier() +- * Deregisters statistics notifier. +- */ +-int nss_ipsec_cmn_stats_unregister_notifier(struct notifier_block *nb) +-{ +- return atomic_notifier_chain_unregister(&nss_ipsec_cmn_stats_notifier, nb); +-} +-EXPORT_SYMBOL(nss_ipsec_cmn_stats_unregister_notifier); +- +-/* +- * nss_ipsec_cmn_stats_register_notifier() +- * Registers statistics notifier. +- */ +-int nss_ipsec_cmn_stats_register_notifier(struct notifier_block *nb) +-{ +- return atomic_notifier_chain_register(&nss_ipsec_cmn_stats_notifier, nb); +-} +-EXPORT_SYMBOL(nss_ipsec_cmn_stats_register_notifier); +- +-/* +- * nss_ipsec_cmn_stats_dentry_create() +- * Create ipsec common statistics debug entry. +- */ +-void nss_ipsec_cmn_stats_dentry_create(void) +-{ +- nss_stats_create_dentry("ipsec_cmn", &nss_ipsec_cmn_stats_ops); +-} +--- a/nss_ipsec_cmn_stats.h ++++ /dev/null +@@ -1,28 +0,0 @@ +-/* +- *************************************************************************** +- * Copyright (c) 2021, The Linux Foundation. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- *************************************************************************** +- */ +- +-#ifndef __NSS_IPSEC_CMN_STATS_H +-#define __NSS_IPSEC_CMN_STATS_H +- +-#include +- +-extern void nss_ipsec_cmn_stats_notify(struct nss_ctx_instance *nss_ctx, uint32_t if_num); +-extern void nss_ipsec_cmn_stats_sync(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm); +-extern void nss_ipsec_cmn_stats_dentry_create(void); +- +-#endif /* __NSS_IPSEC_CMN_STATS_H */ +--- a/nss_ipsec_cmn_strings.c ++++ /dev/null +@@ -1,82 +0,0 @@ +-/* +- *************************************************************************** +- * Copyright (c) 2021, The Linux Foundation. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- *************************************************************************** +- */ +- +-#include "nss_stats.h" +-#include "nss_core.h" +-#include "nss_strings.h" +-#include "nss_ipsec_cmn_strings.h" +- +-/* +- * nss_ipsec_cmn_strings_stats +- * ipsec common statistics strings. +- */ +-struct nss_stats_info nss_ipsec_cmn_strings_stats[NSS_IPSEC_CMN_STATS_MAX] = { +- {"rx_pkts", NSS_STATS_TYPE_COMMON}, +- {"rx_byts", NSS_STATS_TYPE_COMMON}, +- {"tx_pkts", NSS_STATS_TYPE_COMMON}, +- {"tx_byts", NSS_STATS_TYPE_COMMON}, +- {"rx_queue[0]_drops", NSS_STATS_TYPE_DROP}, +- {"rx_queue[1]_drops", NSS_STATS_TYPE_DROP}, +- {"rx_queue[2]_drops", NSS_STATS_TYPE_DROP}, +- {"rx_queue[3]_drops", NSS_STATS_TYPE_DROP}, +- {"fail_headroom", NSS_STATS_TYPE_DROP}, +- {"fail_tailroom", NSS_STATS_TYPE_DROP}, +- {"fail_replay", NSS_STATS_TYPE_DROP}, +- {"fail_replay_dup", NSS_STATS_TYPE_DROP}, +- {"fail_replay_win", NSS_STATS_TYPE_DROP}, +- {"fail_pbuf_crypto", NSS_STATS_TYPE_DROP}, +- {"fail_queue", NSS_STATS_TYPE_DROP}, +- {"fail_queue_crypto", NSS_STATS_TYPE_DROP}, +- {"fail_queue_nexthop", NSS_STATS_TYPE_DROP}, +- {"fail_pbuf_alloc", NSS_STATS_TYPE_DROP}, +- {"fail_pbuf_linear", NSS_STATS_TYPE_DROP}, +- {"fail_pbuf_stats", NSS_STATS_TYPE_DROP}, +- {"fail_pbuf_align", NSS_STATS_TYPE_DROP}, +- {"fail_cipher", NSS_STATS_TYPE_EXCEPTION}, +- {"fail_auth", NSS_STATS_TYPE_EXCEPTION}, +- {"fail_seq_ovf", NSS_STATS_TYPE_DROP}, +- {"fail_blk_len", NSS_STATS_TYPE_DROP}, +- {"fail_hash_len", NSS_STATS_TYPE_DROP}, +- {"fail_transform", NSS_STATS_TYPE_DROP}, +- {"fail_crypto", NSS_STATS_TYPE_DROP}, +- {"fail_cle", NSS_STATS_TYPE_DROP}, +- {"is_stopped", NSS_STATS_TYPE_SPECIAL} +-}; +- +-/* +- * nss_ipsec_cmn_strings_read() +- * Read ipsec common statistics names +- */ +-static ssize_t nss_ipsec_cmn_strings_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- return nss_strings_print(ubuf, sz, ppos, nss_ipsec_cmn_strings_stats, NSS_IPSEC_CMN_STATS_MAX); +-} +- +-/* +- * nss_ipsec_cmn_strings_ops +- */ +-NSS_STRINGS_DECLARE_FILE_OPERATIONS(ipsec_cmn); +- +-/* +- * nss_ipsec_cmn_strings_dentry_create() +- * Create ipsec common statistics strings debug entry. +- */ +-void nss_ipsec_cmn_strings_dentry_create(void) +-{ +- nss_strings_create_dentry("ipsec_cmn", &nss_ipsec_cmn_strings_ops); +-} +--- a/nss_ipsec_cmn_strings.h ++++ /dev/null +@@ -1,27 +0,0 @@ +-/* +- *************************************************************************** +- * Copyright (c) 2021, The Linux Foundation. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- *************************************************************************** +- */ +- +-#ifndef __NSS_IPSEC_CMN_STRINGS_H +-#define __NSS_IPSEC_CMN_STRINGS_H +- +-#include "nss_ipsec_cmn_stats.h" +- +-extern struct nss_stats_info nss_ipsec_cmn_strings_stats[NSS_IPSEC_CMN_STATS_MAX]; +-extern void nss_ipsec_cmn_strings_dentry_create(void); +- +-#endif /* __NSS_IPSEC_CMN_STRINGS_H */ +--- a/nss_ipv4.c ++++ b/nss_ipv4.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2013-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2013-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -70,20 +70,6 @@ static inline void nss_ipv4_dscp_map_usa + } + + /* +- * nss_ipv4_get_total_conn_count() +- * Returns the sum of IPv4 and IPv6 connections. +- */ +-static uint32_t nss_ipv4_get_total_conn_count(int ipv4_num_conn) +-{ +- +-#ifdef NSS_DRV_IPV6_ENABLE +- return ipv4_num_conn + nss_ipv6_conn_cfg; +-#else +- return ipv4_num_conn; +-#endif +-} +- +-/* + * nss_ipv4_rx_msg_handler() + * Handle NSS -> HLOS messages for IPv4 bridge/route + */ +@@ -438,7 +424,7 @@ static int nss_ipv4_conn_cfg_process(str + + nss_info("%px: IPv4 supported connections: %d\n", nss_ctx, conn); + +- nss_ipv4_ct_info.ce_mem = __get_free_pages(GFP_ATOMIC | __GFP_NOWARN | __GFP_ZERO, ++ nss_ipv4_ct_info.ce_mem = __get_free_pages(GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO, + get_order(nss_ipv4_ct_info.ce_table_size)); + if (!nss_ipv4_ct_info.ce_mem) { + nss_warning("%px: Memory allocation failed for IPv4 Connections: %d\n", +@@ -447,7 +433,7 @@ static int nss_ipv4_conn_cfg_process(str + goto fail; + } + +- nss_ipv4_ct_info.cme_mem = __get_free_pages(GFP_ATOMIC | __GFP_NOWARN | __GFP_ZERO, ++ nss_ipv4_ct_info.cme_mem = __get_free_pages(GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO, + get_order(nss_ipv4_ct_info.cme_table_size)); + if (!nss_ipv4_ct_info.ce_mem) { + nss_warning("%px: Memory allocation failed for IPv4 Connections: %d\n", +@@ -546,8 +532,7 @@ int nss_ipv4_update_conn_count(int ipv4_ + * Min. value should be at least 256 connections. This is the + * minimum connections we will support for each of them. + */ +- sum_of_conn = nss_ipv4_get_total_conn_count(ipv4_num_conn); +- ++ sum_of_conn = ipv4_num_conn + nss_ipv6_conn_cfg; + if ((ipv4_num_conn & NSS_NUM_CONN_QUANTA_MASK) || + (sum_of_conn > NSS_MAX_TOTAL_NUM_CONN_IPV4_IPV6) || + (ipv4_num_conn < NSS_MIN_NUM_CONN)) { +--- a/nss_ipv4_log.c ++++ b/nss_ipv4_log.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2016, 2018, 2020-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2016, 2018, 2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -88,9 +88,7 @@ static void nss_ipv4_log_rule_create_msg + "flow_qos_tag: %x (%u)\n" + "return_qos_tag: %x (%u)\n" + "flow_dscp: %x\n" +- "return_dscp: %x\n" +- "flow_mirror_ifnum: %u\n" +- "return_mirror_ifnum: %u\n", ++ "return_dscp: %x\n", + nim, + nircm->tuple.protocol, + nircm->conn_rule.flow_mtu, +@@ -116,9 +114,7 @@ static void nss_ipv4_log_rule_create_msg + nircm->qos_rule.flow_qos_tag, nircm->qos_rule.flow_qos_tag, + nircm->qos_rule.return_qos_tag, nircm->qos_rule.return_qos_tag, + nircm->dscp_rule.flow_dscp, +- nircm->dscp_rule.return_dscp, +- nircm->mirror_rule.flow_ifnum, +- nircm->mirror_rule.return_ifnum); ++ nircm->dscp_rule.return_dscp); + } + + /* +--- a/nss_ipv4_stats.c ++++ b/nss_ipv4_stats.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2016-2017, 2019-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2016-2017, 2019-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -177,9 +177,6 @@ void nss_ipv4_stats_node_sync(struct nss + nss_ipv4_stats[NSS_IPV4_STATS_MC_CONNECTION_DESTROY_REQUESTS] += nins->ipv4_mc_connection_destroy_requests; + nss_ipv4_stats[NSS_IPV4_STATS_MC_CONNECTION_DESTROY_MISSES] += nins->ipv4_mc_connection_destroy_misses; + nss_ipv4_stats[NSS_IPV4_STATS_MC_CONNECTION_FLUSHES] += nins->ipv4_mc_connection_flushes; +- nss_ipv4_stats[NSS_IPV4_STATS_CONNECTION_CREATE_INVALID_MIRROR_IFNUM] += nins->ipv4_connection_create_invalid_mirror_ifnum; +- nss_ipv4_stats[NSS_IPV4_STATS_CONNECTION_CREATE_INVALID_MIRROR_IFTYPE] += nins->ipv4_connection_create_invalid_mirror_iftype; +- nss_ipv4_stats[NSS_IPV4_STATS_MIRROR_FAILURES] += nins->ipv4_mirror_failures; + + for (i = 0; i < NSS_IPV4_EXCEPTION_EVENT_MAX; i++) { + nss_ipv4_exception_stats[i] += nins->exception_events[i]; +--- a/nss_ipv4_strings.c ++++ b/nss_ipv4_strings.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the +@@ -106,10 +106,10 @@ struct nss_stats_info nss_ipv4_strings_e + {"mc_pbuf_alloc_failure" , NSS_STATS_TYPE_EXCEPTION}, + {"pppoe_bridge_no_icme" , NSS_STATS_TYPE_EXCEPTION}, + {"pppoe_no_session" , NSS_STATS_TYPE_DROP}, ++#if (NSS_FW_VERSION_CODE > NSS_FW_VERSION(11,0)) + {"icmp_ipv4_gre_hdr_incomplete" , NSS_STATS_TYPE_EXCEPTION}, + {"icmp_ipv4_esp_hdr_incomplete" , NSS_STATS_TYPE_EXCEPTION}, +- {"emesh_prio_mismatch" , NSS_STATS_TYPE_EXCEPTION}, +- {"mc_ucast_dmac_failure" , NSS_STATS_TYPE_EXCEPTION}, ++#endif + }; + + /* +@@ -137,10 +137,7 @@ struct nss_stats_info nss_ipv4_strings_s + {"mc_create_invalid_interface" , NSS_STATS_TYPE_SPECIAL}, + {"mc_destroy_requests" , NSS_STATS_TYPE_SPECIAL}, + {"mc_destroy_misses" , NSS_STATS_TYPE_SPECIAL}, +- {"mc_flushes" , NSS_STATS_TYPE_SPECIAL}, +- {"mirror_invalid_ifnum_conn_create_req" , NSS_STATS_TYPE_SPECIAL}, +- {"mirror_invalid_iftype_conn_create_req" , NSS_STATS_TYPE_SPECIAL}, +- {"mirror_failures" , NSS_STATS_TYPE_SPECIAL}, ++ {"mc_flushes" , NSS_STATS_TYPE_SPECIAL} + }; + + /* +--- a/nss_ipv6.c ++++ b/nss_ipv6.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2014-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2014-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -428,7 +428,7 @@ static int nss_ipv6_conn_cfg_process(str + + nss_info("%px: IPv6 supported connections: %d\n", nss_ctx, conn); + +- nss_ipv6_ct_info.ce_mem = __get_free_pages(GFP_ATOMIC | __GFP_NOWARN | __GFP_ZERO, ++ nss_ipv6_ct_info.ce_mem = __get_free_pages(GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO, + get_order(nss_ipv6_ct_info.ce_table_size)); + if (!nss_ipv6_ct_info.ce_mem) { + nss_warning("%px: Memory allocation failed for IPv6 Connections: %d\n", +@@ -440,7 +440,7 @@ static int nss_ipv6_conn_cfg_process(str + nss_ctx, + conn); + +- nss_ipv6_ct_info.cme_mem = __get_free_pages(GFP_ATOMIC | __GFP_NOWARN | __GFP_ZERO, ++ nss_ipv6_ct_info.cme_mem = __get_free_pages(GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO, + get_order(nss_ipv6_ct_info.cme_table_size)); + if (!nss_ipv6_ct_info.cme_mem) { + nss_warning("%px: Memory allocation failed for IPv6 Connections: %d\n", +--- a/nss_ipv6_log.c ++++ b/nss_ipv6_log.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2016, 2018, 2020-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2016, 2018, 2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -103,9 +103,7 @@ static void nss_ipv6_log_rule_create_msg + "flow_qos_tag: %x (%u)\n" + "return_qos_tag: %x (%u)\n" + "flow_dscp: %x\n" +- "return_dscp: %x\n" +- "flow_mirror_ifnum: %u\n" +- "return_mirror_ifnum: %u\n", ++ "return_dscp: %x\n", + nim, + nircm->tuple.protocol, + nircm->conn_rule.flow_mtu, +@@ -129,9 +127,7 @@ static void nss_ipv6_log_rule_create_msg + nircm->qos_rule.flow_qos_tag, nircm->qos_rule.flow_qos_tag, + nircm->qos_rule.return_qos_tag, nircm->qos_rule.return_qos_tag, + nircm->dscp_rule.flow_dscp, +- nircm->dscp_rule.return_dscp, +- nircm->mirror_rule.flow_ifnum, +- nircm->mirror_rule.return_ifnum); ++ nircm->dscp_rule.return_dscp); + } + + /* +--- a/nss_ipv6_stats.c ++++ b/nss_ipv6_stats.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2016-2017, 2019-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2016-2017, 2019-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -180,9 +180,6 @@ void nss_ipv6_stats_node_sync(struct nss + nss_ipv6_stats[NSS_IPV6_STATS_MC_CONNECTION_DESTROY_REQUESTS] += nins->ipv6_mc_connection_destroy_requests; + nss_ipv6_stats[NSS_IPV6_STATS_MC_CONNECTION_DESTROY_MISSES] += nins->ipv6_mc_connection_destroy_misses; + nss_ipv6_stats[NSS_IPV6_STATS_MC_CONNECTION_FLUSHES] += nins->ipv6_mc_connection_flushes; +- nss_ipv6_stats[NSS_IPV6_STATS_CONNECTION_CREATE_INVALID_MIRROR_IFNUM] += nins->ipv6_connection_create_invalid_mirror_ifnum; +- nss_ipv6_stats[NSS_IPV6_STATS_CONNECTION_CREATE_INVALID_MIRROR_IFTYPE] += nins->ipv6_connection_create_invalid_mirror_iftype; +- nss_ipv6_stats[NSS_IPV6_STATS_MIRROR_FAILURES] += nins->ipv6_mirror_failures; + + for (i = 0; i < NSS_IPV6_EXCEPTION_EVENT_MAX; i++) { + nss_ipv6_exception_stats[i] += nins->exception_events[i]; +--- a/nss_ipv6_strings.c ++++ b/nss_ipv6_strings.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the +@@ -81,12 +81,14 @@ struct nss_stats_info nss_ipv6_strings_e + {"tunipip6_needs_fragmentation" , NSS_STATS_TYPE_EXCEPTION}, + {"pppoe_bridge_no_icme" , NSS_STATS_TYPE_EXCEPTION}, + {"dont_frag_set" , NSS_STATS_TYPE_EXCEPTION}, ++#if (NSS_FW_VERSION_CODE > NSS_FW_VERSION(11,0)) + {"reassembly_not_supported" , NSS_STATS_TYPE_EXCEPTION}, + {"pppoe_no_session" , NSS_STATS_TYPE_DROP}, + {"icmp_gre_header_incomplete" , NSS_STATS_TYPE_EXCEPTION}, + {"icmp_esp_header_incomplete" , NSS_STATS_TYPE_EXCEPTION}, +- {"emesh_prio_mismatch" , NSS_STATS_TYPE_EXCEPTION}, +- {"mc_ucast_dmac_failure" , NSS_STATS_TYPE_EXCEPTION}, ++#else ++ {"pppoe_no_session" , NSS_STATS_TYPE_DROP}, ++#endif + }; + + /* +@@ -115,10 +117,7 @@ struct nss_stats_info nss_ipv6_strings_s + {"mc_create_invalid_interface" ,NSS_STATS_TYPE_SPECIAL}, + {"mc_destroy_requests" ,NSS_STATS_TYPE_SPECIAL}, + {"mc_destroy_misses" ,NSS_STATS_TYPE_SPECIAL}, +- {"mc_flushes" ,NSS_STATS_TYPE_SPECIAL}, +- {"mirror_invalid_ifnum_conn_create_req" ,NSS_STATS_TYPE_SPECIAL}, +- {"mirror_invalid_iftype_conn_create_req" ,NSS_STATS_TYPE_SPECIAL}, +- {"mirror_failures" ,NSS_STATS_TYPE_SPECIAL}, ++ {"mc_flushes" ,NSS_STATS_TYPE_SPECIAL} + }; + + /* +--- a/nss_map_t_stats.c ++++ b/nss_map_t_stats.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2017,2019-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2017,2019-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -60,7 +60,7 @@ static ssize_t nss_map_t_stats_read(stru + for (id = 0; id < NSS_MAX_MAP_T_DYNAMIC_INTERFACES; id++) { + + if (!map_t_instance_stats[id].valid) { +- continue; ++ break; + } + + dev = dev_get_by_index(&init_net, map_t_instance_stats[id].if_index); +--- a/nss_match.c ++++ b/nss_match.c +@@ -1,6 +1,6 @@ + /* + *************************************************************************** +- * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above +@@ -23,7 +23,6 @@ + #include "nss_tx_rx_common.h" + #include "nss_match_log.h" + #include "nss_match_stats.h" +-#include "nss_match_strings.h" + + #define NSS_MATCH_TX_TIMEOUT 1000 /* 1 Seconds */ + +@@ -149,7 +148,6 @@ static void nss_match_handler(struct nss + * Update common node statistics + */ + nss_match_stats_sync(nss_ctx, nem); +- nss_match_stats_notify(nss_ctx, nem->cm.interface); + } + + if (ncm->response == NSS_CMN_RESPONSE_NOTIFY) { +@@ -211,10 +209,10 @@ nss_tx_status_t nss_match_msg_tx_sync(st + EXPORT_SYMBOL(nss_match_msg_tx_sync); + + /* +- * nss_match_unregister_instance() +- * Unregisters match instance. ++ * nss_match_register_instance() ++ * Registers match instance. + */ +-bool nss_match_unregister_instance(int if_num) ++struct nss_ctx_instance *nss_match_register_instance(int if_num, nss_match_msg_sync_callback_t notify_cb) + { + struct nss_ctx_instance *nss_ctx; + uint32_t status; +@@ -224,27 +222,32 @@ bool nss_match_unregister_instance(int i + + if (!nss_match_verify_if_num(if_num)) { + nss_warning("%px: Incorrect interface number: %d", nss_ctx, if_num); +- return false; ++ return NULL; + } + +- nss_core_unregister_handler(nss_ctx, if_num); +- status = nss_core_unregister_msg_handler(nss_ctx, if_num); ++ nss_core_register_handler(nss_ctx, if_num, nss_match_handler, NULL); ++ status = nss_core_register_msg_handler(nss_ctx, if_num, (nss_if_rx_msg_callback_t)notify_cb); + if (status != NSS_CORE_STATUS_SUCCESS) { +- nss_warning("%px: Not able to unregister handler for interface %d with NSS core\n", nss_ctx, if_num); +- return false; ++ nss_warning("%px: Not able to register handler for interface %d with NSS core\n", nss_ctx, if_num); ++ return NULL; + } + +- nss_match_ifnum_delete(if_num); ++ if (!nss_match_ifnum_add(if_num)) { ++ nss_warning("%px: Unable to add match inteface : %u\n", nss_ctx, if_num); ++ nss_core_unregister_handler(nss_ctx, if_num); ++ nss_core_unregister_msg_handler(nss_ctx, if_num); ++ return NULL; ++ } + +- return true; ++ return nss_ctx; + } +-EXPORT_SYMBOL(nss_match_unregister_instance); ++EXPORT_SYMBOL(nss_match_register_instance); + + /* +- * nss_match_register_instance() +- * Registers match instance. ++ * nss_match_unregister_instance() ++ * Unregisters match instance. + */ +-struct nss_ctx_instance *nss_match_register_instance(int if_num, nss_match_msg_sync_callback_t notify_cb) ++bool nss_match_unregister_instance(int if_num) + { + struct nss_ctx_instance *nss_ctx; + uint32_t status; +@@ -254,26 +257,21 @@ struct nss_ctx_instance *nss_match_regis + + if (!nss_match_verify_if_num(if_num)) { + nss_warning("%px: Incorrect interface number: %d", nss_ctx, if_num); +- return NULL; ++ return false; + } + +- nss_core_register_handler(nss_ctx, if_num, nss_match_handler, NULL); +- status = nss_core_register_msg_handler(nss_ctx, if_num, (nss_if_rx_msg_callback_t)notify_cb); ++ nss_core_unregister_handler(nss_ctx, if_num); ++ status = nss_core_unregister_msg_handler(nss_ctx, if_num); + if (status != NSS_CORE_STATUS_SUCCESS) { +- nss_warning("%px: Not able to register handler for interface %d with NSS core\n", nss_ctx, if_num); +- return NULL; ++ nss_warning("%px: Not able to unregister handler for interface %d with NSS core\n", nss_ctx, if_num); ++ return false; + } + +- if (!nss_match_ifnum_add(if_num)) { +- nss_warning("%px: Unable to add match inteface : %u\n", nss_ctx, if_num); +- nss_core_unregister_handler(nss_ctx, if_num); +- nss_core_unregister_msg_handler(nss_ctx, if_num); +- return NULL; +- } ++ nss_match_ifnum_delete(if_num); + +- return nss_ctx; ++ return true; + } +-EXPORT_SYMBOL(nss_match_register_instance); ++EXPORT_SYMBOL(nss_match_unregister_instance); + + /* + * nss_match_msg_init() +@@ -293,7 +291,6 @@ EXPORT_SYMBOL(nss_match_msg_init); + void nss_match_init() + { + nss_match_stats_dentry_create(); +- nss_match_strings_dentry_create(); + sema_init(&match_pvt.sem, 1); + init_completion(&match_pvt.complete); + } +--- a/nss_match_stats.c ++++ b/nss_match_stats.c +@@ -1,6 +1,6 @@ + /* + *************************************************************************** +- * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above +@@ -23,123 +23,21 @@ + #include "nss_stats.h" + #include + #include "nss_match_stats.h" +-#include "nss_match_strings.h" + + #define NSS_MATCH_STATS_SIZE_PER_IF (NSS_STATS_MAX_STR_LENGTH * NSS_STATS_NODE_MAX) + /* Total number of statistics per match interface. */ + + int match_ifnum[NSS_MATCH_INSTANCE_MAX] = {0}; +-uint64_t nss_match_stats[NSS_MATCH_INSTANCE_MAX][NSS_MATCH_STATS_MAX]; + static DEFINE_SPINLOCK(nss_match_stats_lock); + + /* +- * Declare atomic notifier data structure for statistics. +- */ +-ATOMIC_NOTIFIER_HEAD(nss_match_stats_notifier); +- +-/* +- * nss_match_stats_read() +- * Read match node statiistics. +- */ +-static ssize_t nss_match_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- /* +- * Max output lines = #stats + +- * few blank lines for banner printing + Number of Extra outputlines +- * for future reference to add new stats +- */ +- uint32_t max_output_lines = NSS_MATCH_STATS_MAX + NSS_STATS_EXTRA_OUTPUT_LINES; +- size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines * NSS_MATCH_INSTANCE_MAX; +- ssize_t bytes_read = 0; +- size_t size_wr = 0; +- uint32_t if_num; +- int index; +- +- char *lbuf = kzalloc(size_al, GFP_KERNEL); +- if (unlikely(!lbuf)) { +- nss_warning("Could not allocate memory for local statistics buffer"); +- return 0; +- } +- +- size_wr += nss_stats_banner(lbuf, size_wr, size_al, "match stats", NSS_STATS_SINGLE_CORE); +- +- /* +- * Common node stats for each match dynamic interface. +- */ +- for (index = 0; index < NSS_MATCH_INSTANCE_MAX; index++) { +- +- spin_lock_bh(&nss_match_stats_lock); +- if_num = match_ifnum[index]; +- spin_unlock_bh(&nss_match_stats_lock); +- +- if (if_num) { +- size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\nMatch node if_num:%03u", if_num); +- size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\n ---------------------- \n"); +- size_wr += nss_stats_print("match", NULL, NSS_STATS_SINGLE_INSTANCE, nss_match_strings_stats, +- nss_match_stats[index], NSS_MATCH_STATS_MAX, lbuf, size_wr, size_al); +- continue; +- } +- } +- +- bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf)); +- kfree(lbuf); +- return bytes_read; +-} +- +- +-/* +- * nss_match_stats_sync() +- * Update match common node statistics. +- */ +-void nss_match_stats_sync(struct nss_ctx_instance *nss_ctx, struct nss_match_msg *nmm) +-{ +- struct nss_match_stats_sync *ndccs = &nmm->msg.stats; +- uint64_t *ctx_stats; +- uint32_t *msg_stats; +- uint32_t if_num; +- uint16_t i = 0; +- int index; +- +- for (index = 0; index < NSS_MATCH_INSTANCE_MAX; index++) { +- spin_lock_bh(&nss_match_stats_lock); +- if_num = match_ifnum[index]; +- spin_unlock_bh(&nss_match_stats_lock); +- +- if (if_num == nmm->cm.interface) { +- break; +- } +- } +- +- if (index == NSS_MATCH_INSTANCE_MAX) { +- nss_warning("Invalid Match index\n"); +- return; +- } +- +- spin_lock_bh(&nss_match_stats_lock); +- msg_stats = (uint32_t *)ndccs; +- ctx_stats = nss_match_stats[index]; +- +- for (i = 0; i < NSS_MATCH_STATS_MAX; i++, ctx_stats++, msg_stats++) { +- *ctx_stats += *msg_stats; +- } +- +- spin_unlock_bh(&nss_match_stats_lock); +-} +- +-/* +- * nss_match_stats_ops +- */ +-NSS_STATS_DECLARE_FILE_OPERATIONS(match) +- +-/* + * nss_match_ifnum_add() +- * Add match node interface ID. + */ + bool nss_match_ifnum_add(int if_num) + { + int index = 0; + +- spin_lock_bh(&nss_match_stats_lock); ++ spin_lock(&nss_match_stats_lock); + + for (index = 0; index < NSS_MATCH_INSTANCE_MAX; index++) { + if (match_ifnum[index]) { +@@ -148,23 +46,22 @@ bool nss_match_ifnum_add(int if_num) + + match_ifnum[index] = if_num; + +- spin_unlock_bh(&nss_match_stats_lock); ++ spin_unlock(&nss_match_stats_lock); + return true; + } + +- spin_unlock_bh(&nss_match_stats_lock); ++ spin_unlock(&nss_match_stats_lock); + return false; + } + + /* + * nss_match_ifnum_delete() +- * Delete match node interface ID. + */ + bool nss_match_ifnum_delete(int if_num) + { + int index = 0; + +- spin_lock_bh(&nss_match_stats_lock); ++ spin_lock(&nss_match_stats_lock); + + for (index = 0; index < NSS_MATCH_INSTANCE_MAX; index++) { + if (match_ifnum[index] != if_num) { +@@ -173,67 +70,91 @@ bool nss_match_ifnum_delete(int if_num) + + match_ifnum[index] = 0; + +- spin_unlock_bh(&nss_match_stats_lock); ++ spin_unlock(&nss_match_stats_lock); + return true; + } + +- spin_unlock_bh(&nss_match_stats_lock); ++ spin_unlock(&nss_match_stats_lock); + return false; + } + ++ + /* +- * nss_match_stats_notify() +- * Sends notifications to all the registered modules. +- * +- * Leverage NSS-FW statistics timing to update Netlink. ++ * nss_match_stats_read() ++ * Read match node statiistics. + */ +-void nss_match_stats_notify(struct nss_ctx_instance *nss_ctx, uint32_t if_num) ++static ssize_t nss_match_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) + { +- struct nss_match_stats_notification match_stats; +- uint32_t interface; +- int index; ++ ssize_t bytes_read = 0; ++ uint32_t index, if_num; ++ char *lbuf; ++ size_t size_al = NSS_MATCH_STATS_SIZE_PER_IF * NSS_MATCH_INSTANCE_MAX; ++ size_t size_wr = 0; + +- match_stats.core_id = nss_ctx->id; +- match_stats.if_num = if_num; ++ lbuf = kzalloc(size_al, GFP_KERNEL); ++ if (!lbuf) { ++ nss_warning("Could not allocate memory for local statistics buffer\n"); ++ return 0; ++ } + ++ size_wr += nss_stats_banner(lbuf, size_wr, size_al, "match", NSS_STATS_SINGLE_CORE); ++ ++ /* ++ * Common node stats for each match dynamic interface. ++ */ + for (index = 0; index < NSS_MATCH_INSTANCE_MAX; index++) { ++ + spin_lock_bh(&nss_match_stats_lock); +- interface = match_ifnum[index]; ++ if_num = match_ifnum[index]; + spin_unlock_bh(&nss_match_stats_lock); + +- if (interface == if_num) { +- break; ++ if (if_num) { ++ size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\nMatch node if_num:%03u", if_num); ++ size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\n ---------------------- \n"); ++ size_wr += nss_stats_fill_common_stats(if_num, NSS_STATS_SINGLE_INSTANCE, lbuf, size_wr, size_al, "match"); ++ continue; + } + } + +- if (index == NSS_MATCH_INSTANCE_MAX) { +- nss_warning("Invalid Match index\n"); +- return; +- } +- +- spin_lock_bh(&nss_match_stats_lock); +- memcpy(match_stats.stats_ctx, nss_match_stats[index], sizeof(match_stats.stats_ctx)); +- spin_unlock_bh(&nss_match_stats_lock); +- atomic_notifier_call_chain(&nss_match_stats_notifier, NSS_STATS_EVENT_NOTIFY, &match_stats); ++ bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf)); ++ kfree(lbuf); ++ return bytes_read; + } + ++ + /* +- * nss_match_stats_unregister_notifier() +- * Deregisters statistics notifier. ++ * nss_match_stats_sync() ++ * Update match common node statistics. + */ +-int nss_match_stats_unregister_notifier(struct notifier_block *nb) ++void nss_match_stats_sync(struct nss_ctx_instance *nss_ctx, struct nss_match_msg *nmm) + { +- return atomic_notifier_chain_unregister(&nss_match_stats_notifier, nb); ++ struct nss_top_instance *nss_top = nss_ctx->nss_top; ++ struct nss_match_stats_sync *msg_stats = &nmm->msg.stats; ++ uint64_t *if_stats; ++ int index; ++ ++ spin_lock_bh(&nss_top->stats_lock); ++ ++ /* ++ * Update common node stats ++ */ ++ if_stats = nss_top->stats_node[nmm->cm.interface]; ++ if_stats[NSS_STATS_NODE_RX_PKTS] += msg_stats->p_stats.rx_packets; ++ if_stats[NSS_STATS_NODE_RX_BYTES] += msg_stats->p_stats.rx_bytes; ++ if_stats[NSS_STATS_NODE_TX_PKTS] += msg_stats->p_stats.tx_packets; ++ if_stats[NSS_STATS_NODE_TX_BYTES] += msg_stats->p_stats.tx_bytes; ++ ++ for (index = 0; index < NSS_MAX_NUM_PRI; index++) { ++ if_stats[NSS_STATS_NODE_RX_QUEUE_0_DROPPED + index] += msg_stats->p_stats.rx_dropped[index]; ++ } ++ ++ spin_unlock_bh(&nss_top->stats_lock); + } + + /* +- * nss_match_stats_register_notifier() +- * Registers statistics notifier. ++ * nss_match_stats_ops + */ +-int nss_match_stats_register_notifier(struct notifier_block *nb) +-{ +- return atomic_notifier_chain_register(&nss_match_stats_notifier, nb); +-} ++NSS_STATS_DECLARE_FILE_OPERATIONS(match) + + /* + * nss_match_stats_dentry_create() +--- a/nss_match_stats.h ++++ b/nss_match_stats.h +@@ -1,6 +1,6 @@ + /* + *************************************************************************** +- * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above +@@ -19,63 +19,9 @@ + #ifndef __NSS_MATCH_STATS_H__ + #define __NSS_MATCH_STATS_H__ + +-/** +- * nss_match_stats_types +- * Match statistics types. +- */ +-enum nss_match_stats_types { +- NSS_MATCH_STATS_HIT_COUNT_0 = NSS_STATS_NODE_MAX, +- /**< Hit count of rule ID 1. */ +- NSS_MATCH_STATS_HIT_COUNT_1, /**< Hit count of rule ID 2. */ +- NSS_MATCH_STATS_HIT_COUNT_2, /**< Hit count of rule ID 3. */ +- NSS_MATCH_STATS_HIT_COUNT_3, /**< Hit count of rule ID 4. */ +- NSS_MATCH_STATS_HIT_COUNT_4, /**< Hit count of rule ID 5. */ +- NSS_MATCH_STATS_HIT_COUNT_5, /**< Hit count of rule ID 6. */ +- NSS_MATCH_STATS_HIT_COUNT_6, /**< Hit count of rule ID 7. */ +- NSS_MATCH_STATS_HIT_COUNT_7, /**< Hit count of rule ID 8. */ +- NSS_MATCH_STATS_HIT_COUNT_8, /**< Hit count of rule ID 9. */ +- NSS_MATCH_STATS_HIT_COUNT_9, /**< Hit count of rule ID 10. */ +- NSS_MATCH_STATS_HIT_COUNT_10, /**< Hit count of rule ID 11. */ +- NSS_MATCH_STATS_HIT_COUNT_11, /**< Hit count of rule ID 12. */ +- NSS_MATCH_STATS_HIT_COUNT_12, /**< Hit count of rule ID 13. */ +- NSS_MATCH_STATS_HIT_COUNT_13, /**< Hit count of rule ID 14. */ +- NSS_MATCH_STATS_HIT_COUNT_14, /**< Hit count of rule ID 15. */ +- NSS_MATCH_STATS_HIT_COUNT_15, /**< Hit count of rule ID 16. */ +- NSS_MATCH_STATS_HIT_COUNT_16, /**< Hit count of rule ID 17. */ +- NSS_MATCH_STATS_HIT_COUNT_17, /**< Hit count of rule ID 18. */ +- NSS_MATCH_STATS_HIT_COUNT_18, /**< Hit count of rule ID 19. */ +- NSS_MATCH_STATS_HIT_COUNT_19, /**< Hit count of rule ID 20. */ +- NSS_MATCH_STATS_HIT_COUNT_20, /**< Hit count of rule ID 21. */ +- NSS_MATCH_STATS_HIT_COUNT_21, /**< Hit count of rule ID 22. */ +- NSS_MATCH_STATS_HIT_COUNT_22, /**< Hit count of rule ID 23. */ +- NSS_MATCH_STATS_HIT_COUNT_23, /**< Hit count of rule ID 24. */ +- NSS_MATCH_STATS_HIT_COUNT_24, /**< Hit count of rule ID 25. */ +- NSS_MATCH_STATS_HIT_COUNT_25, /**< Hit count of rule ID 26. */ +- NSS_MATCH_STATS_HIT_COUNT_26, /**< Hit count of rule ID 27. */ +- NSS_MATCH_STATS_HIT_COUNT_27, /**< Hit count of rule ID 28. */ +- NSS_MATCH_STATS_HIT_COUNT_28, /**< Hit count of rule ID 29. */ +- NSS_MATCH_STATS_HIT_COUNT_29, /**< Hit count of rule ID 30. */ +- NSS_MATCH_STATS_HIT_COUNT_30, /**< Hit count of rule ID 31. */ +- NSS_MATCH_STATS_HIT_COUNT_31, /**< Hit count of rule ID 32. */ +- NSS_MATCH_STATS_MAX, /**< Maximum statistics type. */ +-}; +- +-/** +- * nss_match_stats_notification +- * Match transmission statistics structure. +- */ +-struct nss_match_stats_notification { +- uint64_t stats_ctx[NSS_MATCH_STATS_MAX]; /**< Context transmission statistics. */ +- uint32_t core_id; /**< Core ID. */ +- uint32_t if_num; /**< Interface number. */ +-}; +- + extern bool nss_match_ifnum_add(int if_num); + extern bool nss_match_ifnum_delete(int if_num); +-extern void nss_match_stats_notify(struct nss_ctx_instance *nss_ctx, uint32_t if_num); + extern void nss_match_stats_sync(struct nss_ctx_instance *nss_ctx, struct nss_match_msg *nmm); + extern void nss_match_stats_dentry_create(void); +-extern int nss_match_stats_unregister_notifier(struct notifier_block *nb); +-extern int nss_match_stats_register_notifier(struct notifier_block *nb); + + #endif /* __NSS_MATCH_STATS_H__ */ +--- a/nss_match_strings.c ++++ /dev/null +@@ -1,92 +0,0 @@ +-/* +- *************************************************************************** +- * Copyright (c) 2021, The Linux Foundation. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- *************************************************************************** +- */ +- +-#include "nss_stats.h" +-#include "nss_core.h" +-#include "nss_strings.h" +-#include "nss_match_strings.h" +- +-/* +- * nss_match_strings_stats +- * match statistics strings. +- */ +-struct nss_stats_info nss_match_strings_stats[NSS_MATCH_STATS_MAX] = { +- {"rx_pkts", NSS_STATS_TYPE_COMMON}, +- {"rx_byts", NSS_STATS_TYPE_COMMON}, +- {"tx_pkts", NSS_STATS_TYPE_COMMON}, +- {"tx_byts", NSS_STATS_TYPE_COMMON}, +- {"rx_queue[0]_drops", NSS_STATS_TYPE_DROP}, +- {"rx_queue[1]_drops", NSS_STATS_TYPE_DROP}, +- {"rx_queue[2]_drops", NSS_STATS_TYPE_DROP}, +- {"rx_queue[3]_drops", NSS_STATS_TYPE_DROP}, +- {"hit_count[0]", NSS_STATS_TYPE_SPECIAL}, +- {"hit_count[1]", NSS_STATS_TYPE_SPECIAL}, +- {"hit_count[2]", NSS_STATS_TYPE_SPECIAL}, +- {"hit_count[3]", NSS_STATS_TYPE_SPECIAL}, +- {"hit_count[4]", NSS_STATS_TYPE_SPECIAL}, +- {"hit_count[5]", NSS_STATS_TYPE_SPECIAL}, +- {"hit_count[6]", NSS_STATS_TYPE_SPECIAL}, +- {"hit_count[7]", NSS_STATS_TYPE_SPECIAL}, +- {"hit_count[8]", NSS_STATS_TYPE_SPECIAL}, +- {"hit_count[9]", NSS_STATS_TYPE_SPECIAL}, +- {"hit_count[10]", NSS_STATS_TYPE_SPECIAL}, +- {"hit_count[11]", NSS_STATS_TYPE_SPECIAL}, +- {"hit_count[12]", NSS_STATS_TYPE_SPECIAL}, +- {"hit_count[13]", NSS_STATS_TYPE_SPECIAL}, +- {"hit_count[14]", NSS_STATS_TYPE_SPECIAL}, +- {"hit_count[15]", NSS_STATS_TYPE_SPECIAL}, +- {"hit_count[16]", NSS_STATS_TYPE_SPECIAL}, +- {"hit_count[17]", NSS_STATS_TYPE_SPECIAL}, +- {"hit_count[18]", NSS_STATS_TYPE_SPECIAL}, +- {"hit_count[19]", NSS_STATS_TYPE_SPECIAL}, +- {"hit_count[20]", NSS_STATS_TYPE_SPECIAL}, +- {"hit_count[21]", NSS_STATS_TYPE_SPECIAL}, +- {"hit_count[22]", NSS_STATS_TYPE_SPECIAL}, +- {"hit_count[23]", NSS_STATS_TYPE_SPECIAL}, +- {"hit_count[24]", NSS_STATS_TYPE_SPECIAL}, +- {"hit_count[25]", NSS_STATS_TYPE_SPECIAL}, +- {"hit_count[26]", NSS_STATS_TYPE_SPECIAL}, +- {"hit_count[27]", NSS_STATS_TYPE_SPECIAL}, +- {"hit_count[28]", NSS_STATS_TYPE_SPECIAL}, +- {"hit_count[29]", NSS_STATS_TYPE_SPECIAL}, +- {"hit_count[30]", NSS_STATS_TYPE_SPECIAL}, +- {"hit_count[31]", NSS_STATS_TYPE_SPECIAL} +-}; +- +-/* +- * nss_match_stats_strings_read() +- * Read match statistics names +- */ +-static ssize_t nss_match_strings_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- return nss_strings_print(ubuf, sz, ppos, nss_match_strings_stats, NSS_MATCH_STATS_MAX); +-} +- +-/* +- * nss_match_strings_ops +- */ +-NSS_STRINGS_DECLARE_FILE_OPERATIONS(match); +- +-/* +- * nss_match_strings_dentry_create() +- * Create match statistics strings debug entry. +- */ +-void nss_match_strings_dentry_create(void) +-{ +- nss_strings_create_dentry("match", &nss_match_strings_ops); +-} +--- a/nss_match_strings.h ++++ /dev/null +@@ -1,27 +0,0 @@ +-/* +- *************************************************************************** +- * Copyright (c) 2021, The Linux Foundation. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- *************************************************************************** +- */ +- +-#ifndef __NSS_MATCH_STRINGS_H +-#define __NSS_MATCH_STRINGS_H +- +-#include "nss_match_stats.h" +- +-extern struct nss_stats_info nss_match_strings_stats[NSS_MATCH_STATS_MAX]; +-extern void nss_match_strings_dentry_create(void); +- +-#endif /* __NSS_MATCH_STRINGS_H */ +--- a/nss_meminfo.c ++++ b/nss_meminfo.c +@@ -735,7 +735,7 @@ bool nss_meminfo_init(struct nss_ctx_ins + /* + * meminfo_start is the label where the start address of meminfo map is stored. + */ +- meminfo_start = (uint32_t *)ioremap_nocache(nss_ctx->load + NSS_MEMINFO_MAP_START_OFFSET, ++ meminfo_start = (uint32_t *)ioremap(nss_ctx->load + NSS_MEMINFO_MAP_START_OFFSET, + NSS_MEMINFO_RESERVE_AREA_SIZE); + if (!meminfo_start) { + nss_info_always("%px: cannot remap meminfo start\n", nss_ctx); +--- a/nss_mirror.c ++++ b/nss_mirror.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the +@@ -18,7 +18,6 @@ + + #include "nss_tx_rx_common.h" + #include "nss_mirror_stats.h" +-#include "nss_mirror_strings.h" + #include "nss_mirror_log.h" + + #define NSS_MIRROR_TX_TIMEOUT 3000 /* 3 Seconds */ +@@ -90,7 +89,6 @@ static void nss_mirror_handler(struct ns + * Debug stats embedded in stats msg. + */ + nss_mirror_stats_sync(nss_ctx, nmm, ncm->interface); +- nss_mirror_stats_notify(nss_ctx, ncm->interface); + break; + } + +@@ -292,5 +290,4 @@ void nss_mirror_register_handler(void) + init_completion(&nss_mirror_pvt.complete); + + nss_mirror_stats_dentry_create(); +- nss_mirror_strings_dentry_create(); + } +--- a/nss_mirror_stats.c ++++ b/nss_mirror_stats.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the +@@ -18,19 +18,28 @@ + + #include "nss_stats.h" + #include "nss_core.h" +-#include "nss_mirror.h" + #include "nss_mirror_stats.h" +-#include "nss_mirror_strings.h" + + static struct nss_mirror_stats_debug_instance *stats_db[NSS_MAX_MIRROR_DYNAMIC_INTERFACES]; + /* Mirror stats data structure. */ + + /* +- * Atomic notifier data structure for statistics ++ * Data structures to store mirror interface stats. + */ +-ATOMIC_NOTIFIER_HEAD(nss_mirror_stats_notifier); ++static DEFINE_SPINLOCK(nss_mirror_stats_debug_lock); + +-static DEFINE_SPINLOCK(nss_mirror_stats_lock); ++/* ++ * nss_mirror_stats_str ++ * Mirror statistics strings for nss session stats. ++ */ ++struct nss_stats_info nss_mirror_stats_str[NSS_MIRROR_STATS_MAX] = { ++ {"MIRROR_STATS_PKTS" , NSS_STATS_TYPE_SPECIAL}, ++ {"MIRROR_STATS_BYTES" , NSS_STATS_TYPE_SPECIAL}, ++ {"MIRROR_STATS_TX_FAIL" , NSS_STATS_TYPE_DROP}, ++ {"MIRROR_STATS_DEST_LOOKUP_FAIL" , NSS_STATS_TYPE_DROP}, ++ {"MIRROR_STATS_MEM_ALLOC_FAIL" , NSS_STATS_TYPE_ERROR}, ++ {"MIRROR_STATS_COPY_FAIL" , NSS_STATS_TYPE_ERROR}, ++}; + + /* + * nss_mirror_stats_get() +@@ -46,7 +55,7 @@ static void nss_mirror_stats_get(void *s + return; + } + +- spin_lock_bh(&nss_mirror_stats_lock); ++ spin_lock_bh(&nss_mirror_stats_debug_lock); + for (i = 0; i < NSS_MAX_MIRROR_DYNAMIC_INTERFACES; i++) { + + /* +@@ -62,7 +71,7 @@ static void nss_mirror_stats_get(void *s + } + } + } +- spin_unlock_bh(&nss_mirror_stats_lock); ++ spin_unlock_bh(&nss_mirror_stats_debug_lock); + } + + /* +@@ -106,7 +115,7 @@ static ssize_t nss_mirror_stats_read(str + * Get all stats + */ + nss_mirror_stats_get((void *)mirror_shadow_stats, mirror_active_instances); +- size_wr += nss_stats_banner(lbuf, size_wr, size_al, "mirror stats", NSS_STATS_SINGLE_CORE); ++ size_wr += nss_stats_banner(lbuf, size_wr, size_al, "mirror", NSS_STATS_SINGLE_CORE); + + /* + * Session stats +@@ -128,12 +137,13 @@ static ssize_t nss_mirror_stats_read(str + /* + * Mirror interface exception stats. + */ +- size_wr += nss_stats_print("mirror", "mirror exception stats", ++ size_wr += nss_stats_print("mirror", "mirror exception stats start", + id, +- nss_mirror_strings_stats, ++ nss_mirror_stats_str, + mirror_shadow_stats[id].stats, + NSS_MIRROR_STATS_MAX, + lbuf, size_wr, size_al); ++ size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\n"); + } + + bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, size_wr); +@@ -156,7 +166,7 @@ void nss_mirror_stats_sync(struct nss_ct + struct nss_cmn_node_stats *node_stats_ptr = &stats_msg->node_stats; + uint32_t *mirror_stats_ptr = (uint32_t *)&stats_msg->mirror_stats; + +- spin_lock_bh(&nss_mirror_stats_lock); ++ spin_lock_bh(&nss_mirror_stats_debug_lock); + for (i = 0; i < NSS_MAX_MIRROR_DYNAMIC_INTERFACES; i++) { + if (!stats_db[i] || (stats_db[i]->if_num != if_num)) { + continue; +@@ -168,16 +178,16 @@ void nss_mirror_stats_sync(struct nss_ct + */ + stats_db[i]->stats[j] += mirror_stats_ptr[j]; + } +- spin_unlock_bh(&nss_mirror_stats_lock); ++ spin_unlock_bh(&nss_mirror_stats_debug_lock); + goto sync_cmn_stats; + } + +- spin_unlock_bh(&nss_mirror_stats_lock); + nss_warning("Invalid mirror stats sync message received for %d interface\n", if_num); ++ spin_unlock_bh(&nss_mirror_stats_debug_lock); + return; + + sync_cmn_stats: +- spin_lock_bh(&nss_mirror_stats_lock); ++ spin_lock_bh(&nss_top->stats_lock); + + /* + * Sync common stats. +@@ -192,7 +202,7 @@ sync_cmn_stats: + node_stats_ptr->rx_dropped[i]; + } + +- spin_unlock_bh(&nss_mirror_stats_lock); ++ spin_unlock_bh(&nss_top->stats_lock); + } + + /* +@@ -212,7 +222,7 @@ void nss_mirror_stats_reset(uint32_t if_ + /* + * Reset mirror stats. + */ +- spin_lock_bh(&nss_mirror_stats_lock); ++ spin_lock_bh(&nss_mirror_stats_debug_lock); + for (i = 0; i < NSS_MAX_MIRROR_DYNAMIC_INTERFACES; i++) { + if (!stats_db[i] || (stats_db[i]->if_num != if_num)) { + continue; +@@ -222,7 +232,7 @@ void nss_mirror_stats_reset(uint32_t if_ + stats_db[i] = NULL; + break; + } +- spin_unlock_bh(&nss_mirror_stats_lock); ++ spin_unlock_bh(&nss_mirror_stats_debug_lock); + + if (mirror_debug_instance) { + vfree(mirror_debug_instance); +@@ -245,7 +255,7 @@ int nss_mirror_stats_init(uint32_t if_nu + return -1; + } + +- spin_lock_bh(&nss_mirror_stats_lock); ++ spin_lock_bh(&nss_mirror_stats_debug_lock); + for (i = 0; i < NSS_MAX_MIRROR_DYNAMIC_INTERFACES; i++) { + if (stats_db[i] != NULL) { + continue; +@@ -254,10 +264,10 @@ int nss_mirror_stats_init(uint32_t if_nu + stats_db[i] = mirror_debug_instance; + stats_db[i]->if_num = if_num; + stats_db[i]->if_index = netdev->ifindex; +- spin_unlock_bh(&nss_mirror_stats_lock); ++ spin_unlock_bh(&nss_mirror_stats_debug_lock); + return 0; + } +- spin_unlock_bh(&nss_mirror_stats_lock); ++ spin_unlock_bh(&nss_mirror_stats_debug_lock); + vfree(mirror_debug_instance); + return -1; + } +@@ -275,50 +285,3 @@ void nss_mirror_stats_dentry_create(void + { + nss_stats_create_dentry("mirror", &nss_mirror_stats_ops); + } +- +-/* +- * nss_mirror_stats_notify() +- * Sends notifications to all the registered modules. +- * +- * Leverage NSS-FW statistics timing to update Netlink. +- */ +-void nss_mirror_stats_notify(struct nss_ctx_instance *nss_ctx, uint32_t if_num) +-{ +- struct nss_mirror_stats_notification mirror_stats; +- int i; +- +- spin_lock_bh(&nss_mirror_stats_lock); +- for (i = 0; i < NSS_MAX_MIRROR_DYNAMIC_INTERFACES; i++) { +- if (!stats_db[i] || (stats_db[i]->if_num != if_num)) { +- continue; +- } +- +- memcpy(mirror_stats.stats_ctx, stats_db[i]->stats, sizeof(mirror_stats.stats_ctx)); +- mirror_stats.core_id = nss_ctx->id; +- mirror_stats.if_num = if_num; +- spin_unlock_bh(&nss_mirror_stats_lock); +- atomic_notifier_call_chain(&nss_mirror_stats_notifier, NSS_STATS_EVENT_NOTIFY, &mirror_stats); +- return; +- } +- spin_unlock_bh(&nss_mirror_stats_lock); +-} +- +-/* +- * nss_mirror_stats_unregister_notifier() +- * Deregisters statistics notifier. +- */ +-int nss_mirror_stats_unregister_notifier(struct notifier_block *nb) +-{ +- return atomic_notifier_chain_unregister(&nss_mirror_stats_notifier, nb); +-} +-EXPORT_SYMBOL(nss_mirror_stats_unregister_notifier); +- +-/* +- * nss_mirror_stats_register_notifier() +- * Registers statistics notifier. +- */ +-int nss_mirror_stats_register_notifier(struct notifier_block *nb) +-{ +- return atomic_notifier_chain_register(&nss_mirror_stats_notifier, nb); +-} +-EXPORT_SYMBOL(nss_mirror_stats_register_notifier); +--- a/nss_mirror_stats.h ++++ b/nss_mirror_stats.h +@@ -1,6 +1,6 @@ + /* + ****************************************************************************** +- * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the +@@ -25,6 +25,20 @@ + extern atomic_t nss_mirror_num_instances; + + /* ++ * nss_mirror_stats ++ * Mirror interface debug statistics. ++ */ ++enum nss_mirror_stats { ++ NSS_MIRROR_STATS_PKTS, /* Number of packets exceptioned to host. */ ++ NSS_MIRROR_STATS_BYTES, /* Number of bytes exceptioned to host. */ ++ NSS_MIRROR_STATS_TX_SEND_FAIL, /* Transmit send failures. */ ++ NSS_MIRROR_STATS_DEST_LOOKUP_FAIL, /* Destination lookup failures. */ ++ NSS_MIRROR_STATS_MEM_ALLOC_FAIL, /* Memory allocation failures. */ ++ NSS_MIRROR_STATS_COPY_FAIL, /* Copy failures. */ ++ NSS_MIRROR_STATS_MAX /* Maximum statistics count. */ ++}; ++ ++/* + * nss_mirror_stats_debug_instance + * Stucture for H2N/N2H mirror interface debug stats. + */ +@@ -34,11 +48,29 @@ struct nss_mirror_stats_debug_instance { + uint32_t if_num; /* Mirror instance NSS interface number */ + }; + ++/* ++ * nss_mirror_stats_sync() ++ * API to sync statistics for mirror interface. ++ */ + extern void nss_mirror_stats_sync(struct nss_ctx_instance *nss_ctx, + struct nss_mirror_msg *nmm, uint16_t if_num); ++ ++/* ++ * nss_mirror_stats_reset() ++ * API to reset the mirror interface stats. ++ */ + extern void nss_mirror_stats_reset(uint32_t if_num); ++ ++/* ++ * nss_mirror_stats_init() ++ * API to initialize mirror debug instance statistics. ++ */ + extern int nss_mirror_stats_init(uint32_t if_num, struct net_device *netdev); ++ ++/* ++ * nss_mirror_stats_dentry_create() ++ * Create mirror interface statistics debug entry. ++ */ + extern void nss_mirror_stats_dentry_create(void); +-extern void nss_mirror_stats_notify(struct nss_ctx_instance *nss_ctx, uint32_t if_num); + + #endif /* __NSS_MIRROR_STATS_H */ +--- a/nss_mirror_strings.c ++++ /dev/null +@@ -1,58 +0,0 @@ +-/* +- *************************************************************************** +- * Copyright (c) 2021, The Linux Foundation. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- *************************************************************************** +- */ +- +-#include "nss_stats.h" +-#include "nss_core.h" +-#include "nss_strings.h" +-#include "nss_mirror_strings.h" +- +-/* +- * nss_mirror_strings_stats +- * Mirror statistics strings for nss session stats. +- */ +-struct nss_stats_info nss_mirror_strings_stats[NSS_MIRROR_STATS_MAX] = { +- {"pkts", NSS_STATS_TYPE_SPECIAL}, +- {"bytes", NSS_STATS_TYPE_SPECIAL}, +- {"tx_fail", NSS_STATS_TYPE_DROP}, +- {"dest_lookup_fail", NSS_STATS_TYPE_DROP}, +- {"mem_alloc_fail", NSS_STATS_TYPE_ERROR}, +- {"copy_fail", NSS_STATS_TYPE_ERROR}, +-}; +- +-/* +- * nss_mirror_strings_read() +- * Read mirror statistics names +- */ +-static ssize_t nss_mirror_strings_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- return nss_strings_print(ubuf, sz, ppos, nss_mirror_strings_stats, NSS_MIRROR_STATS_MAX); +-} +- +-/* +- * nss_mirror_strings_ops +- */ +-NSS_STRINGS_DECLARE_FILE_OPERATIONS(mirror); +- +-/* +- * nss_mirror_strings_dentry_create() +- * Create mirror statistics strings debug entry. +- */ +-void nss_mirror_strings_dentry_create(void) +-{ +- nss_strings_create_dentry("mirror", &nss_mirror_strings_ops); +-} +--- a/nss_mirror_strings.h ++++ /dev/null +@@ -1,27 +0,0 @@ +-/* +- *************************************************************************** +- * Copyright (c) 2021, The Linux Foundation. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- *************************************************************************** +- */ +- +-#ifndef __NSS_MIRROR_STRINGS_H +-#define __NSS_MIRROR_STRINGS_H +- +-#include "nss_mirror_stats.h" +- +-extern struct nss_stats_info nss_mirror_strings_stats[NSS_MIRROR_STATS_MAX]; +-extern void nss_mirror_strings_dentry_create(void); +- +-#endif /* __NSS_MIRROR_STRINGS_H */ +--- a/nss_n2h.c ++++ b/nss_n2h.c +@@ -33,12 +33,6 @@ + #define NSS_N2H_DEFAULT_EMPTY_POOL_BUF_SZ 8192 + #define NSS_N2H_TX_TIMEOUT 3000 /* 3 Seconds */ + +-/* +- * Allocate shaper pool memory in multiple chunk of PAGE_SIZE +- */ +-#define NSS_N2H_MIN_QOS_MEM_POOL_SZ 1 +-#define NSS_N2H_QOS_MEM_POOL_SZ_MB(size) (size * 1024 * 1024) +- + int nss_n2h_empty_pool_buf_cfg[NSS_MAX_CORES] __read_mostly = {-1, -1}; + int nss_n2h_empty_paged_pool_buf_cfg[NSS_MAX_CORES] __read_mostly = {-1, -1}; + int nss_n2h_water_mark[NSS_MAX_CORES][2] __read_mostly = {{-1, -1}, {-1, -1} }; +@@ -50,7 +44,6 @@ int nss_n2h_core0_add_buf_pool_size __re + int nss_n2h_core1_add_buf_pool_size __read_mostly; + int nss_n2h_queue_limit[NSS_MAX_CORES] __read_mostly = {NSS_DEFAULT_QUEUE_LIMIT, NSS_DEFAULT_QUEUE_LIMIT}; + int nss_n2h_host_bp_config[NSS_MAX_CORES] __read_mostly; +-int nss_n2h_shaper_pool_size_cfg __read_mostly; + + struct nss_n2h_registered_data { + nss_n2h_msg_callback_t n2h_callback; +@@ -67,9 +60,6 @@ static struct nss_n2h_cfg_pvt nss_n2h_q_ + static struct nss_n2h_cfg_pvt nss_n2h_q_lim_pvt; + static struct nss_n2h_cfg_pvt nss_n2h_host_bp_cfg_pvt; + +-static uint32_t nss_n2h_shaper_pool_cfg_num_pages; +-static nss_tx_status_t nss_n2h_cfg_shaper_pool(struct nss_ctx_instance *nss_ctx) +-; + /* + * nss_n2h_interface_handler() + * Handle NSS -> HLOS messages for N2H node +@@ -995,24 +985,6 @@ static int nss_n2h_wifi_payloads_handler + } + + /* +- * nss_n2h_get_qos_mem_size_cfg_handler() +- * Gets the QoS memory pool size +- */ +-static int nss_n2h_get_qos_mem_size_cfg_handler(struct ctl_table *ctl, +- int write, void __user *buffer, +- size_t *lenp, loff_t *ppos) +-{ +- int ret = NSS_FAILURE; +- +- if (!write) { +- nss_n2h_shaper_pool_size_cfg = NSS_N2H_QOS_MEM_POOL_SZ_MB(nss_core_get_qos_mem_size()); +- } +- +- ret = proc_dointvec(ctl, write, buffer, lenp, ppos); +- return ret; +-} +- +-/* + * nss_n2h_update_queue_config_callback() + * Callback to handle the completion of queue config command + */ +@@ -1734,13 +1706,6 @@ static struct ctl_table nss_n2h_table_si + .mode = 0644, + .proc_handler = &nss_n2h_host_bp_cfg_core0_handler, + }, +- { +- .procname = "qos_mem_size", +- .data = &nss_n2h_shaper_pool_size_cfg, +- .maxlen = sizeof(int), +- .mode = 0644, +- .proc_handler = &nss_n2h_get_qos_mem_size_cfg_handler, +- }, + + { } + }; +@@ -1894,13 +1859,6 @@ static struct ctl_table nss_n2h_table_mu + .mode = 0644, + .proc_handler = &nss_n2h_host_bp_cfg_core1_handler, + }, +- { +- .procname = "qos_mem_size", +- .data = &nss_n2h_shaper_pool_size_cfg, +- .maxlen = sizeof(int), +- .mode = 0644, +- .proc_handler = &nss_n2h_get_qos_mem_size_cfg_handler, +- }, + { } + }; + +@@ -1977,113 +1935,6 @@ nss_tx_status_t nss_n2h_cfg_empty_pool_s + return nss_tx_status; + } + +-static inline void nss_n2h_shaper_pool_free(struct nss_n2h_shaper_mem_cfg_msg *nnsmcm, int num_blks) +-{ +- int blk_count; +- for (blk_count = 0; blk_count < num_blks; blk_count++) { +- kfree((void *)nnsmcm->pool_vaddr[blk_count]); +- } +-} +- +-/* +- * nss_n2h_cfg_qos_mem_size_callback() +- * Call back function for QoS memory pool size configuration +- */ +-static void nss_n2h_cfg_qos_mem_size_callback(void *app_data, struct nss_n2h_msg *nnm) +-{ +- struct nss_ctx_instance *nss_ctx __maybe_unused = (struct nss_ctx_instance *)app_data; +- struct nss_n2h_shaper_mem_cfg_msg *nnsmcm = &nnm->msg.shaper_mem_cfg; +- nnsmcm->num_blks = ntohl(nnsmcm->num_blks); +- +- if (nnm->cm.response != NSS_CMN_RESPONSE_ACK) { +- nss_warning("%px: Shaper pool configuration failed with error: %d\n", nss_ctx, nnm->cm.error); +- nss_n2h_shaper_pool_free(nnsmcm, nnsmcm->num_blks); +- return; +- } +- +- nss_core_update_qos_mem_size(nss_core_get_qos_mem_size() + (PAGE_SIZE * nnsmcm->num_blks)); +- nss_n2h_cfg_shaper_pool(nss_ctx); +- nss_info("%px: shaper pool configuration success\n", nss_ctx); +-} +- +-/* +- * nss_n2h_cfg_shaper_pool() +- * Config QoS memory pool in NSS FW +- */ +-static nss_tx_status_t nss_n2h_cfg_shaper_pool(struct nss_ctx_instance *nss_ctx) +-{ +- struct nss_n2h_msg nnm; +- struct nss_n2h_shaper_mem_cfg_msg *nnsmcm; +- nss_tx_status_t nss_tx_status; +- int blk_count; +- +- if (!nss_n2h_shaper_pool_cfg_num_pages) { +- return NSS_TX_SUCCESS; +- } +- +- memset(&nnm, 0, sizeof(struct nss_n2h_msg)); +- nss_n2h_msg_init(&nnm, NSS_N2H_INTERFACE, +- NSS_TX_METADATA_TYPE_N2H_SHAPER_POOL_CFG, +- sizeof(struct nss_n2h_shaper_mem_cfg_msg), +- nss_n2h_cfg_qos_mem_size_callback, +- (void *)nss_ctx); +- +- nnsmcm = &nnm.msg.shaper_mem_cfg; +- +- for (blk_count = 0; blk_count < MAX_PAGES_PER_MSG; blk_count++) { +- void *kern_addr = kzalloc(PAGE_SIZE, GFP_ATOMIC); +- if (!kern_addr) { +- nss_warning("%px: memory allocation failed for shaper pool", nss_ctx); +- return NSS_TX_FAILURE; +- } +- +- kmemleak_not_leak(kern_addr); +- nnsmcm->pool_vaddr[blk_count] = (nss_ptr_t)kern_addr; +- nnsmcm->pool_addr[blk_count] = dma_map_single(nss_ctx->dev, kern_addr, PAGE_SIZE, DMA_TO_DEVICE); +- } +- +- nnsmcm->mem_blk_size = htonl(PAGE_SIZE); +- nnsmcm->num_blks = htonl(blk_count); +- nss_tx_status = nss_n2h_tx_msg(nss_ctx, &nnm); +- +- if (nss_tx_status != NSS_TX_SUCCESS) { +- nss_n2h_shaper_pool_free(nnsmcm, blk_count); +- nss_warning("%px: nss_tx error setting shaper pool\n", nss_ctx); +- return NSS_TX_FAILURE; +- } +- +- nss_n2h_shaper_pool_cfg_num_pages--; +- return NSS_TX_SUCCESS; +-} +- +-/* +- * nss_n2h_cfg_qos_mem_size() +- * Config QoS memory pool size +- */ +-nss_tx_status_t nss_n2h_cfg_qos_mem_size(struct nss_ctx_instance *nss_ctx, uint32_t pool_sz) +-{ +- nss_info("%px: update QoS memory pool size: %dMB\n", +- nss_ctx, pool_sz); +- +- if (!pool_sz) { +- nss_info("%px: No extra memory allocated for QoS memory pool", +- nss_ctx); +- return NSS_TX_SUCCESS; +- } +- +- if (pool_sz < NSS_N2H_MIN_QOS_MEM_POOL_SZ) { +- nss_warning("%px: pool size: %d is less than minimum value allowed: %d", +- nss_ctx, pool_sz, NSS_N2H_MIN_QOS_MEM_POOL_SZ); +- return NSS_TX_FAILURE; +- } +- +- nss_n2h_shaper_pool_cfg_num_pages = ALIGN(NSS_N2H_QOS_MEM_POOL_SZ_MB(pool_sz), PAGE_SIZE)/(PAGE_SIZE * MAX_PAGES_PER_MSG); +- +- nss_info("%px: shaper pool size:%d bytes\n", nss_ctx, NSS_N2H_QOS_MEM_POOL_SZ_MB(pool_sz)); +- +- return nss_n2h_cfg_shaper_pool(nss_ctx); +-} +- + /* + * nss_n2h_paged_buf_pool_init() + * Sends a command down to NSS to initialize paged buffer pool +--- a/nss_n2h_stats.c ++++ b/nss_n2h_stats.c +@@ -38,7 +38,7 @@ static ssize_t nss_n2h_stats_read(struct + * Max output lines = #stats + few blank lines for banner printing + + * Number of Extra outputlines for future reference to add new stats + */ +- uint32_t max_output_lines = (NSS_N2H_STATS_MAX + 3) * NSS_MAX_CORES + NSS_STATS_EXTRA_OUTPUT_LINES; ++ uint32_t max_output_lines = (NSS_N2H_STATS_MAX + 3) * 2 + 5; + size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines; + size_t size_wr = 0; + ssize_t bytes_read = 0; +--- a/nss_n2h_strings.c ++++ b/nss_n2h_strings.c +@@ -38,14 +38,14 @@ struct nss_stats_info nss_n2h_strings_st + {"ticks" , NSS_STATS_TYPE_SPECIAL}, + {"worst_ticks" , NSS_STATS_TYPE_SPECIAL}, + {"iterations" , NSS_STATS_TYPE_SPECIAL}, +- {"pbuf_ocm_total_count" , NSS_STATS_TYPE_SPECIAL}, +- {"pbuf_ocm_free_count" , NSS_STATS_TYPE_SPECIAL}, + {"pbuf_ocm_alloc_fail_payload" , NSS_STATS_TYPE_SPECIAL}, ++ {"pbuf_ocm_free_count" , NSS_STATS_TYPE_SPECIAL}, ++ {"pbuf_ocm_total_count" , NSS_STATS_TYPE_SPECIAL}, + {"pbuf_ocm_alloc_fail_nopayload", NSS_STATS_TYPE_SPECIAL}, +- {"pbuf_def_total_count" , NSS_STATS_TYPE_SPECIAL}, +- {"pbuf_def_free_count" , NSS_STATS_TYPE_SPECIAL}, + {"pbuf_def_alloc_fail_payload" , NSS_STATS_TYPE_SPECIAL}, ++ {"pbuf_def_free_count" , NSS_STATS_TYPE_SPECIAL}, + {"pbuf_def_alloc_fail_nopayload", NSS_STATS_TYPE_SPECIAL}, ++ {"pbuf_def_total_count" , NSS_STATS_TYPE_SPECIAL}, + {"payload_alloc_fails" , NSS_STATS_TYPE_SPECIAL}, + {"payload_free_count" , NSS_STATS_TYPE_SPECIAL}, + {"h2n_control_pkts" , NSS_STATS_TYPE_SPECIAL}, +--- a/nss_phys_if.h ++++ b/nss_phys_if.h +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2014-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2014-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -70,12 +70,6 @@ struct nss_phys_if_estats { + uint32_t gmac_worst_case_ticks; /**< Worst case iteration of the GMAC in ticks */ + uint32_t gmac_iterations; /**< Number of iterations around the GMAC */ + uint32_t tx_pause_frames; /**< Number of pause frames sent by the GMAC */ +- +- /* +- * On IPQ50xx, we rely on the SSDK to pull the mmc stats. +- * The FAL layer does not do this on IPQ806x. +- */ +-#if defined(NSS_HAL_IPQ806X_SUPPORT) + uint32_t mmc_rx_overflow_errors; + /**< Number of RX overflow errors */ + uint32_t mmc_rx_watchdog_timeout_errors; +@@ -100,7 +94,6 @@ struct nss_phys_if_estats { + uint32_t mmc_tx_single_col; /* Number of single collisions */ + uint32_t mmc_tx_multiple_col; /* Number of multiple collisions */ + uint32_t mmc_tx_octets_gb; /* Number of good/bad octets sent*/ +-#endif + }; + + /** +--- a/nss_ppe.c ++++ b/nss_ppe.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2016-2018, 2020-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2016-2018, 2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -16,7 +16,6 @@ + + #include "nss_ppe.h" + #include "nss_ppe_stats.h" +-#include "nss_ppe_strings.h" + + DEFINE_SPINLOCK(nss_ppe_stats_lock); + +@@ -272,7 +271,6 @@ static void nss_ppe_handler(struct nss_c + * session debug stats embeded in session stats msg + */ + nss_ppe_stats_sync(nss_ctx, &msg->msg.stats, ncm->interface); +- nss_ppe_stats_notify(nss_ctx, ncm->interface); + return; + } + +@@ -311,7 +309,6 @@ void nss_ppe_register_handler(void) + + if (nss_ppe_debug_stats.valid) { + nss_ppe_stats_dentry_create(); +- nss_ppe_strings_dentry_create(); + } + } + +@@ -357,7 +354,7 @@ void nss_ppe_init(void) + /* + * Get the PPE base address + */ +- ppe_pvt.ppe_base = ioremap_nocache(PPE_BASE_ADDR, PPE_REG_SIZE); ++ ppe_pvt.ppe_base = ioremap(PPE_BASE_ADDR, PPE_REG_SIZE); + if (!ppe_pvt.ppe_base) { + nss_warning("DRV can't get PPE base address\n"); + return; +--- a/nss_ppe_stats.c ++++ b/nss_ppe_stats.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -17,12 +17,6 @@ + #include "nss_core.h" + #include "nss_ppe.h" + #include "nss_ppe_stats.h" +-#include "nss_ppe_strings.h" +- +-/* +- * Declare atomic notifier data structure for statistics. +- */ +-ATOMIC_NOTIFIER_HEAD(nss_ppe_stats_notifier); + + static uint8_t ppe_cc_nonexception[NSS_PPE_STATS_CPU_CODE_NONEXCEPTION_MAX] = { + NSS_PPE_STATS_CPU_CODE_EXP_FAKE_L2_PROT_ERR, +@@ -109,10 +103,371 @@ static uint8_t ppe_cc_nonexception[NSS_P + }; + + /* +- * nss_ppe_stats_str_sc_type +- * PPE service-code stats type ++ * nss_ppe_stats_str_conn ++ * PPE statistics strings for nss flow stats ++ */ ++static int8_t *nss_ppe_stats_str_conn[NSS_PPE_STATS_CONN_MAX] = { ++ "v4 routed flows", ++ "v4 bridge flows", ++ "v4 conn create req", ++ "v4 conn create fail", ++ "v4 conn destroy req", ++ "v4 conn destroy fail", ++ "v4 conn MC create req", ++ "v4 conn MC create fail", ++ "v4 conn MC update req", ++ "v4 conn MC update fail", ++ "v4 conn MC delete req", ++ "v4 conn MC delete fail", ++ "v4 conn unknown if", ++ ++ "v6 routed flows", ++ "v6 bridge flows", ++ "v6 conn create req", ++ "v6 conn create fail", ++ "v6 conn destroy req", ++ "v6 conn destroy fail", ++ "v6 conn MC create req", ++ "v6 conn MC create fail", ++ "v6 conn MC update req", ++ "v6 conn MC update fail", ++ "v6 conn MC delete req", ++ "v6 conn MC delete fail", ++ "v6 conn unknown if", ++ ++ "conn fail - vp full", ++ "conn fail - nexthop full", ++ "conn fail - flow full", ++ "conn fail - host full", ++ "conn fail - pub-ip full", ++ "conn fail - port not setup", ++ "conn fail - rw fifo full", ++ "conn fail - flow cmd failure", ++ "conn fail - unknown proto", ++ "conn fail - ppe not responding", ++ "conn fail - CE opaque invalid", ++ "conn fail - fqg full" ++}; ++ ++/* ++ * nss_ppe_stats_str_l3 ++ * PPE statistics strings for nss debug stats ++ */ ++static int8_t *nss_ppe_stats_str_l3[NSS_PPE_STATS_L3_MAX] = { ++ "PPE L3 dbg reg 0", ++ "PPE L3 dbg reg 1", ++ "PPE L3 dbg reg 2", ++ "PPE L3 dbg reg 3", ++ "PPE L3 dbg reg 4", ++ "PPE L3 dbg reg port", ++}; ++ ++/* ++ * nss_ppe_stats_str_code ++ * PPE statistics strings for nss debug stats ++ */ ++static int8_t *nss_ppe_stats_str_code[NSS_PPE_STATS_CODE_MAX] = { ++ "PPE CPU_CODE", ++ "PPE DROP_CODE", ++}; ++ ++/* ++ * nss_ppe_stats_str_dc ++ * PPE statistics strings for drop code + */ +-static int8_t *nss_ppe_stats_str_sc_type[NSS_PPE_SC_MAX] = { ++static int8_t *nss_ppe_stats_str_dc[NSS_PPE_STATS_DROP_CODE_MAX] = { ++ "PPE_DROP_CODE_NONE", ++ "PPE_DROP_CODE_EXP_UNKNOWN_L2_PORT", ++ "PPE_DROP_CODE_EXP_PPPOE_WRONG_VER_TYPE", ++ "PPE_DROP_CODE_EXP_PPPOE_WRONG_CODE", ++ "PPE_DROP_CODE_EXP_PPPOE_UNSUPPORTED_PPP_PROT", ++ "PPE_DROP_CODE_EXP_IPV4_WRONG_VER", ++ "PPE_DROP_CODE_EXP_IPV4_SMALL_IHL", ++ "PPE_DROP_CODE_EXP_IPV4_WITH_OPTION", ++ "PPE_DROP_CODE_EXP_IPV4_HDR_INCOMPLETE", ++ "PPE_DROP_CODE_EXP_IPV4_BAD_TOTAL_LEN", ++ "PPE_DROP_CODE_EXP_IPV4_DATA_INCOMPLETE", ++ "PPE_DROP_CODE_EXP_IPV4_FRAG", ++ "PPE_DROP_CODE_EXP_IPV4_PING_OF_DEATH", ++ "PPE_DROP_CODE_EXP_IPV4_SNALL_TTL", ++ "PPE_DROP_CODE_EXP_IPV4_UNK_IP_PROT", ++ "PPE_DROP_CODE_EXP_IPV4_CHECKSUM_ERR", ++ "PPE_DROP_CODE_EXP_IPV4_INV_SIP", ++ "PPE_DROP_CODE_EXP_IPV4_INV_DIP", ++ "PPE_DROP_CODE_EXP_IPV4_LAND_ATTACK", ++ "PPE_DROP_CODE_EXP_IPV4_AH_HDR_INCOMPLETE", ++ "PPE_DROP_CODE_EXP_IPV4_AH_HDR_CROSS_BORDER", ++ "PPE_DROP_CODE_EXP_IPV4_ESP_HDR_INCOMPLETE", ++ "PPE_DROP_CODE_EXP_IPV6_WRONG_VER", ++ "PPE_DROP_CODE_EXP_IPV6_HDR_INCOMPLETE", ++ "PPE_DROP_CODE_EXP_IPV6_BAD_PAYLOAD_LEN", ++ "PPE_DROP_CODE_EXP_IPV6_DATA_INCOMPLETE", ++ "PPE_DROP_CODE_EXP_IPV6_WITH_EXT_HDR", ++ "PPE_DROP_CODE_EXP_IPV6_SMALL_HOP_LIMIT", ++ "PPE_DROP_CODE_EXP_IPV6_INV_SIP", ++ "PPE_DROP_CODE_EXP_IPV6_INV_DIP", ++ "PPE_DROP_CODE_EXP_IPV6_LAND_ATTACK", ++ "PPE_DROP_CODE_EXP_IPV6_FRAG", ++ "PPE_DROP_CODE_EXP_IPV6_PING_OF_DEATH", ++ "PPE_DROP_CODE_EXP_IPV6_WITH_MORE_EXT_HDR", ++ "PPE_DROP_CODE_EXP_IPV6_UNK_LAST_NEXT_HDR", ++ "PPE_DROP_CODE_EXP_IPV6_MOBILITY_HDR_INCOMPLETE", ++ "PPE_DROP_CODE_EXP_IPV6_MOBILITY_HDR_CROSS_BORDER", ++ "PPE_DROP_CODE_EXP_IPV6_AH_HDR_INCOMPLETE", ++ "PPE_DROP_CODE_EXP_IPV6_AH_HDR_CROSS_BORDER", ++ "PPE_DROP_CODE_EXP_IPV6_ESP_HDR_INCOMPLETE", ++ "PPE_DROP_CODE_EXP_IPV6_ESP_HDR_CROSS_BORDER", ++ "PPE_DROP_CODE_EXP_IPV6_OTHER_EXT_HDR_INCOMPLETE", ++ "PPE_DROP_CODE_EXP_IPV6_OTHER_EXT_HDR_CROSS_BORDER", ++ "PPE_DROP_CODE_EXP_TCP_HDR_INCOMPLETE", ++ "PPE_DROP_CODE_EXP_TCP_HDR_CROSS_BORDER", ++ "PPE_DROP_CODE_EXP_TCP_SMAE_SP_DP", ++ "PPE_DROP_CODE_EXP_TCP_SMALL_DATA_OFFSET", ++ "PPE_DROP_CODE_EXP_TCP_FLAGS_0", ++ "PPE_DROP_CODE_EXP_TCP_FLAGS_1", ++ "PPE_DROP_CODE_EXP_TCP_FLAGS_2", ++ "PPE_DROP_CODE_EXP_TCP_FLAGS_3", ++ "PPE_DROP_CODE_EXP_TCP_FLAGS_4", ++ "PPE_DROP_CODE_EXP_TCP_FLAGS_5", ++ "PPE_DROP_CODE_EXP_TCP_FLAGS_6", ++ "PPE_DROP_CODE_EXP_TCP_FLAGS_7", ++ "PPE_DROP_CODE_EXP_TCP_CHECKSUM_ERR", ++ "PPE_DROP_CODE_EXP_UDP_HDR_INCOMPLETE", ++ "PPE_DROP_CODE_EXP_UDP_HDR_CROSS_BORDER", ++ "PPE_DROP_CODE_EXP_UDP_SMAE_SP_DP", ++ "PPE_DROP_CODE_EXP_UDP_BAD_LEN", ++ "PPE_DROP_CODE_EXP_UDP_DATA_INCOMPLETE", ++ "PPE_DROP_CODE_EXP_UDP_CHECKSUM_ERR", ++ "PPE_DROP_CODE_EXP_UDP_LITE_HDR_INCOMPLETE", ++ "PPE_DROP_CODE_EXP_UDP_LITE_HDR_CROSS_BORDER", ++ "PPE_DROP_CODE_EXP_UDP_LITE_SMAE_SP_DP", ++ "PPE_DROP_CODE_EXP_UDP_LITE_CSM_COV_1_TO_7", ++ "PPE_DROP_CODE_EXP_UDP_LITE_CSM_COV_TOO_LONG", ++ "PPE_DROP_CODE_EXP_UDP_LITE_CSM_COV_CROSS_BORDER", ++ "PPE_DROP_CODE_EXP_UDP_LITE_CHECKSUM_ERR", ++ "PPE_DROP_CODE_L3_MC_BRIDGE_ACTION", ++ "PPE_DROP_CODE_L3_NO_ROUTE_PREHEAD_NAT_ACTION", ++ "PPE_DROP_CODE_L3_NO_ROUTE_PREHEAD_NAT_ERROR", ++ "PPE_DROP_CODE_L3_ROUTE_ACTION", ++ "PPE_DROP_CODE_L3_NO_ROUTE_ACTION", ++ "PPE_DROP_CODE_L3_NO_ROUTE_NH_INVALID_ACTION", ++ "PPE_DROP_CODE_L3_NO_ROUTE_PREHEAD_ACTION", ++ "PPE_DROP_CODE_L3_BRIDGE_ACTION", ++ "PPE_DROP_CODE_L3_FLOW_ACTION", ++ "PPE_DROP_CODE_L3_FLOW_MISS_ACTION", ++ "PPE_DROP_CODE_L2_EXP_MRU_FAIL", ++ "PPE_DROP_CODE_L2_EXP_MTU_FAIL", ++ "PPE_DROP_CODE_L3_EXP_IP_PREFIX_BC", ++ "PPE_DROP_CODE_L3_EXP_MTU_FAIL", ++ "PPE_DROP_CODE_L3_EXP_MRU_FAIL", ++ "PPE_DROP_CODE_L3_EXP_ICMP_RDT", ++ "PPE_DROP_CODE_FAKE_MAC_HEADER_ERR", ++ "PPE_DROP_CODE_L3_EXP_IP_RT_TTL_ZERO", ++ "PPE_DROP_CODE_L3_FLOW_SERVICE_CODE_LOOP", ++ "PPE_DROP_CODE_L3_FLOW_DE_ACCELEARTE", ++ "PPE_DROP_CODE_L3_EXP_FLOW_SRC_IF_CHK_FAIL", ++ "PPE_DROP_CODE_L3_FLOW_SYNC_TOGGLE_MISMATCH", ++ "PPE_DROP_CODE_L3_EXP_MTU_DF_FAIL", ++ "PPE_DROP_CODE_L3_EXP_PPPOE_MULTICAST", ++ "PPE_DROP_CODE_IPV4_SG_UNKNOWN", ++ "PPE_DROP_CODE_IPV6_SG_UNKNOWN", ++ "PPE_DROP_CODE_ARP_SG_UNKNOWN", ++ "PPE_DROP_CODE_ND_SG_UNKNOWN", ++ "PPE_DROP_CODE_IPV4_SG_VIO", ++ "PPE_DROP_CODE_IPV6_SG_VIO", ++ "PPE_DROP_CODE_ARP_SG_VIO", ++ "PPE_DROP_CODE_ND_SG_VIO", ++ "PPE_DROP_CODE_L2_NEW_MAC_ADDRESS", ++ "PPE_DROP_CODE_L2_HASH_COLLISION", ++ "PPE_DROP_CODE_L2_STATION_MOVE", ++ "PPE_DROP_CODE_L2_LEARN_LIMIT", ++ "PPE_DROP_CODE_L2_SA_LOOKUP_ACTION", ++ "PPE_DROP_CODE_L2_DA_LOOKUP_ACTION", ++ "PPE_DROP_CODE_APP_CTRL_ACTION", ++ "PPE_DROP_CODE_IN_VLAN_FILTER_ACTION", ++ "PPE_DROP_CODE_IN_VLAN_XLT_MISS", ++ "PPE_DROP_CODE_EG_VLAN_FILTER_DROP", ++ "PPE_DROP_CODE_ACL_PRE_ACTION", ++ "PPE_DROP_CODE_ACL_POST_ACTION", ++ "PPE_DROP_CODE_MC_BC_SA", ++ "PPE_DROP_CODE_NO_DESTINATION", ++ "PPE_DROP_CODE_STG_IN_FILTER", ++ "PPE_DROP_CODE_STG_EG_FILTER", ++ "PPE_DROP_CODE_SOURCE_FILTER_FAIL", ++ "PPE_DROP_CODE_TRUNK_SEL_FAIL", ++ "PPE_DROP_CODE_TX_EN_FAIL", ++ "PPE_DROP_CODE_VLAN_TAG_FMT", ++ "PPE_DROP_CODE_CRC_ERR", ++ "PPE_DROP_CODE_PAUSE_FRAME", ++ "PPE_DROP_CODE_PROMISC", ++ "PPE_DROP_CODE_ISOLATION", ++ "PPE_DROP_CODE_MGMT_APP", ++ "PPE_DROP_CODE_FAKE_L2_PROT_ERR", ++ "PPE_DROP_CODE_POLICER", ++}; ++ ++/* ++ * nss_ppe_stats_str_cc ++ * PPE statistics strings for cpu code ++ */ ++static int8_t *nss_ppe_stats_str_cc[NSS_PPE_STATS_CPU_CODE_MAX] = { ++ "PPE_CPU_CODE_FORWARDING", ++ "PPE_CPU_CODE_EXP_UNKNOWN_L2_PROT", ++ "PPE_CPU_CODE_EXP_PPPOE_WRONG_VER_TYPE", ++ "PPE_CPU_CODE_EXP_WRONG_CODE", ++ "PPE_CPU_CODE_EXP_PPPOE_UNSUPPORTED_PPP_PROT", ++ "PPE_CPU_CODE_EXP_WRONG_VER", ++ "PPE_CPU_CODE_EXP_SMALL_IHL", ++ "PPE_CPU_CODE_EXP_WITH_OPTION", ++ "PPE_CPU_CODE_EXP_HDR_INCOMPLETE", ++ "PPE_CPU_CODE_EXP_IPV4_BAD_TOTAL_LEN", ++ "PPE_CPU_CODE_EXP_DATA_INCOMPLETE", ++ "PPE_CPU_CODE_IPV4_FRAG", ++ "PPE_CPU_CODE_EXP_IPV4_PING_OF_DEATH", ++ "PPE_CPU_CODE_EXP_SNALL_TTL", ++ "PPE_CPU_CODE_EXP_IPV4_UNK_IP_PROT", ++ "PPE_CPU_CODE_EXP_CHECKSUM_ERR", ++ "PPE_CPU_CODE_EXP_INV_SIP", ++ "PPE_CPU_CODE_EXP_INV_DIP", ++ "PPE_CPU_CODE_EXP_LAND_ATTACK", ++ "PPE_CPU_CODE_EXP_IPV4_AH_HDR_INCOMPLETE", ++ "PPE_CPU_CODE_EXP_IPV4_AH_CROSS_BORDER", ++ "PPE_CPU_CODE_EXP_IPV4_ESP_HDR_INCOMPLETE", ++ "PPE_CPU_CODE_EXP_WRONG_VER", ++ "PPE_CPU_CODE_EXP_HDR_INCOMPLETE", ++ "PPE_CPU_CODE_EXP_IPV6_BAD_PAYLOAD_LEN", ++ "PPE_CPU_CODE_EXP_DATA_INCOMPLETE", ++ "PPE_CPU_CODE_EXP_IPV6_WITH_EXT_HDR", ++ "PPE_CPU_CODE_EXP_IPV6_SMALL_HOP_LIMIT", ++ "PPE_CPU_CODE_EXP_INV_SIP", ++ "PPE_CPU_CODE_EXP_INV_DIP", ++ "PPE_CPU_CODE_EXP_LAND_ATTACK", ++ "PPE_CPU_CODE_IPV6_FRAG", ++ "PPE_CPU_CODE_EXP_IPV6_PING_OF_DEATH", ++ "PPE_CPU_CODE_EXP_IPV6_WITH_EXT_HDR", ++ "PPE_CPU_CODE_EXP_IPV6_UNK_NEXT_HDR", ++ "PPE_CPU_CODE_EXP_IPV6_MOBILITY_HDR_INCOMPLETE", ++ "PPE_CPU_CODE_EXP_IPV6_MOBILITY_CROSS_BORDER", ++ "PPE_CPU_CODE_EXP_IPV6_AH_HDR_INCOMPLETE", ++ "PPE_CPU_CODE_EXP_IPV6_AH_CROSS_BORDER", ++ "PPE_CPU_CODE_EXP_IPV6_ESP_HDR_INCOMPLETE", ++ "PPE_CPU_CODE_EXP_IPV6_ESP_CROSS_BORDER", ++ "PPE_CPU_CODE_EXP_IPV6_OTHER_HDR_INCOMPLETE", ++ "PPE_CPU_CODE_EXP_IPV6_OTHER_EXT_CROSS_BORDER", ++ "PPE_CPU_CODE_EXP_HDR_INCOMPLETE", ++ "PPE_CPU_CODE_EXP_TCP_HDR_CROSS_BORDER", ++ "PPE_CPU_CODE_EXP_TCP_SMAE_SP_DP", ++ "PPE_CPU_CODE_EXP_TCP_SMALL_DATA_OFFSET", ++ "PPE_CPU_CODE_EXP_FLAGS_0", ++ "PPE_CPU_CODE_EXP_FLAGS_1", ++ "PPE_CPU_CODE_EXP_FLAGS_2", ++ "PPE_CPU_CODE_EXP_FLAGS_3", ++ "PPE_CPU_CODE_EXP_FLAGS_4", ++ "PPE_CPU_CODE_EXP_FLAGS_5", ++ "PPE_CPU_CODE_EXP_FLAGS_6", ++ "PPE_CPU_CODE_EXP_FLAGS_7", ++ "PPE_CPU_CODE_EXP_CHECKSUM_ERR", ++ "PPE_CPU_CODE_EXP_HDR_INCOMPLETE", ++ "PPE_CPU_CODE_EXP_UDP_HDR_CROSS_BORDER", ++ "PPE_CPU_CODE_EXP_UDP_SMAE_SP_DP", ++ "PPE_CPU_CODE_EXP_BAD_LEN", ++ "PPE_CPU_CODE_EXP_DATA_INCOMPLETE", ++ "PPE_CPU_CODE_EXP_CHECKSUM_ERR", ++ "PPE_CPU_CODE_EXP_UDP_LITE_HDR_INCOMPLETE", ++ "PPE_CPU_CODE_EXP_UDP_LITE_CROSS_BORDER", ++ "PPE_CPU_CODE_EXP_UDP_LITE_SP_DP", ++ "PPE_CPU_CODE_EXP_UDP_LITE_CSM_COV_TO_7", ++ "PPE_CPU_CODE_EXP_UDP_LITE_CSM_TOO_LONG", ++ "PPE_CPU_CODE_EXP_UDP_LITE_CSM_CROSS_BORDER", ++ "PPE_CPU_CODE_EXP_UDP_LITE_CHECKSUM_ERR", ++ "PPE_CPU_CODE_EXP_FAKE_L2_PROT_ERR", ++ "PPE_CPU_CODE_EXP_FAKE_MAC_HEADER_ERR", ++ "PPE_CPU_CODE_BITMAP_MAX", ++ "PPE_CPU_CODE_L2_MRU_FAIL", ++ "PPE_CPU_CODE_L2_MTU_FAIL", ++ "PPE_CPU_CODE_L3_EXP_IP_PREFIX_BC", ++ "PPE_CPU_CODE_L3_MTU_FAIL", ++ "PPE_CPU_CODE_L3_MRU_FAIL", ++ "PPE_CPU_CODE_L3_ICMP_RDT", ++ "PPE_CPU_CODE_L3_EXP_IP_RT_TO_ME", ++ "PPE_CPU_CODE_L3_EXP_IP_TTL_ZERO", ++ "PPE_CPU_CODE_L3_FLOW_SERVICE_CODE_LOOP", ++ "PPE_CPU_CODE_L3_DE_ACCELERATE", ++ "PPE_CPU_CODE_L3_EXP_FLOW_SRC_CHK_FAIL", ++ "PPE_CPU_CODE_L3_FLOW_SYNC_TOGGLE_MISMATCH", ++ "PPE_CPU_CODE_L3_EXP_MTU_DF_FAIL", ++ "PPE_CPU_CODE_L3_PPPOE_MULTICAST", ++ "PPE_CPU_CODE_MGMT_OFFSET", ++ "PPE_CPU_CODE_MGMT_EAPOL", ++ "PPE_CPU_CODE_PPPOE_DIS", ++ "PPE_CPU_CODE_MGMT_IGMP", ++ "PPE_CPU_CODE_ARP_REQ", ++ "PPE_CPU_CODE_ARP_REP", ++ "PPE_CPU_CODE_MGMT_DHCPv4", ++ "PPE_CPU_CODE_MGMT_MLD", ++ "PPE_CPU_CODE_MGMT_NS", ++ "PPE_CPU_CODE_MGMT_NA", ++ "PPE_CPU_CODE_MGMT_DHCPv6", ++ "PPE_CPU_CODE_PTP_OFFSET", ++ "PPE_CPU_CODE_PTP_SYNC", ++ "PPE_CPU_CODE_FOLLOW_UP", ++ "PPE_CPU_CODE_DELAY_REQ", ++ "PPE_CPU_CODE_DELAY_RESP", ++ "PPE_CPU_CODE_PDELAY_REQ", ++ "PPE_CPU_CODE_PDELAY_RESP", ++ "PPE_CPU_CODE_PTP_PDELAY_RESP_FOLLOW_UP", ++ "PPE_CPU_CODE_PTP_ANNOUNCE", ++ "PPE_CPU_CODE_PTP_MANAGEMENT", ++ "PPE_CPU_CODE_PTP_SIGNALING", ++ "PPE_CPU_CODE_PTP_RSV_MSG", ++ "PPE_CPU_CODE_SG_UNKNOWN", ++ "PPE_CPU_CODE_SG_UNKNOWN", ++ "PPE_CPU_CODE_SG_UNKNOWN", ++ "PPE_CPU_CODE_SG_UNKNOWN", ++ "PPE_CPU_CODE_SG_VIO", ++ "PPE_CPU_CODE_SG_VIO", ++ "PPE_CPU_CODE_SG_VIO", ++ "PPE_CPU_CODE_SG_VIO", ++ "PPE_CPU_CODE_L3_ROUTING_IP_TO_ME", ++ "PPE_CPU_CODE_L3_SNAT_ACTION", ++ "PPE_CPU_CODE_L3_DNAT_ACTION", ++ "PPE_CPU_CODE_L3_RT_ACTION", ++ "PPE_CPU_CODE_L3_BR_ACTION", ++ "PPE_CPU_CODE_L3_BRIDGE_ACTION", ++ "PPE_CPU_CODE_L3_ROUTE_PREHEAD_RT_ACTION", ++ "PPE_CPU_CODE_L3_ROUTE_PREHEAD_SNAPT_ACTION", ++ "PPE_CPU_CODE_L3_ROUTE_PREHEAD_DNAPT_ACTION", ++ "PPE_CPU_CODE_L3_ROUTE_PREHEAD_SNAT_ACTION", ++ "PPE_CPU_CODE_L3_ROUTE_PREHEAD_DNAT_ACTION", ++ "PPE_CPU_CODE_L3_NO_ROUTE_NAT_ACTION", ++ "PPE_CPU_CODE_L3_NO_ROUTE_NAT_ERROR", ++ "PPE_CPU_CODE_ROUTE_ACTION", ++ "PPE_CPU_CODE_L3_ROUTE_ACTION", ++ "PPE_CPU_CODE_L3_NO_ROUTE_INVALID_ACTION", ++ "PPE_CPU_CODE_L3_NO_ROUTE_PREHEAD_ACTION", ++ "PPE_CPU_CODE_BRIDGE_ACTION", ++ "PPE_CPU_CODE_FLOW_ACTION", ++ "PPE_CPU_CODE_L3_MISS_ACTION", ++ "PPE_CPU_CODE_L2_MAC_ADDRESS", ++ "PPE_CPU_CODE_HASH_COLLISION", ++ "PPE_CPU_CODE_STATION_MOVE", ++ "PPE_CPU_CODE_LEARN_LIMIT", ++ "PPE_CPU_CODE_L2_LOOKUP_ACTION", ++ "PPE_CPU_CODE_L2_LOOKUP_ACTION", ++ "PPE_CPU_CODE_CTRL_ACTION", ++ "PPE_CPU_CODE_IN_FILTER_ACTION", ++ "PPE_CPU_CODE_IN_XLT_MISS", ++ "PPE_CPU_CODE_EG_FILTER_DROP", ++ "PPE_CPU_CODE_PRE_ACTION", ++ "PPE_CPU_CODE_POST_ACTION", ++ "PPE_CPU_CODE_CODE_ACTION", ++}; ++ ++/* ++ * nss_ppe_stats_str_sc ++ * PPE statistics strings for service-code stats ++ */ ++static int8_t *nss_ppe_stats_str_sc[NSS_PPE_SC_MAX] = { + "SC_NONE ", + "SC_BYPASS_ALL ", + "SC_ADV_QOS_BRIDGED", +@@ -135,8 +490,8 @@ void nss_ppe_stats_sync(struct nss_ctx_i + { + uint32_t sc; + spin_lock_bh(&nss_ppe_stats_lock); +- nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_V4_L3_FLOWS] = stats_msg->stats.nss_ppe_v4_l3_flows; +- nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_V4_L2_FLOWS] = stats_msg->stats.nss_ppe_v4_l2_flows; ++ nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_V4_L3_FLOWS] += stats_msg->stats.nss_ppe_v4_l3_flows; ++ nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_V4_L2_FLOWS] += stats_msg->stats.nss_ppe_v4_l2_flows; + nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_V4_CREATE_REQ] += stats_msg->stats.nss_ppe_v4_create_req; + nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_V4_CREATE_FAIL] += stats_msg->stats.nss_ppe_v4_create_fail; + nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_V4_DESTROY_REQ] += stats_msg->stats.nss_ppe_v4_destroy_req; +@@ -149,8 +504,8 @@ void nss_ppe_stats_sync(struct nss_ctx_i + nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_V4_MC_DESTROY_FAIL] += stats_msg->stats.nss_ppe_v4_mc_destroy_fail; + nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_V4_UNKNOWN_INTERFACE] += stats_msg->stats.nss_ppe_v4_unknown_interface; + +- nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_V6_L3_FLOWS] = stats_msg->stats.nss_ppe_v6_l3_flows; +- nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_V6_L2_FLOWS] = stats_msg->stats.nss_ppe_v6_l2_flows; ++ nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_V6_L3_FLOWS] += stats_msg->stats.nss_ppe_v6_l3_flows; ++ nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_V6_L2_FLOWS] += stats_msg->stats.nss_ppe_v6_l2_flows; + nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_V6_CREATE_REQ] += stats_msg->stats.nss_ppe_v6_create_req; + nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_V6_CREATE_FAIL] += stats_msg->stats.nss_ppe_v6_create_fail; + nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_V6_DESTROY_REQ] += stats_msg->stats.nss_ppe_v6_destroy_req; +@@ -192,7 +547,7 @@ void nss_ppe_stats_sync(struct nss_ctx_i + * nss_ppe_stats_conn_get() + * Get PPE connection statistics. + */ +-static void nss_ppe_stats_conn_get(uint64_t *stats) ++static void nss_ppe_stats_conn_get(uint32_t *stats) + { + if (!stats) { + nss_warning("No memory to copy ppe connection stats"); +@@ -203,7 +558,7 @@ static void nss_ppe_stats_conn_get(uint6 + * Get flow stats + */ + spin_lock_bh(&nss_ppe_stats_lock); +- memcpy(stats, nss_ppe_debug_stats.conn_stats, (sizeof(uint64_t) * NSS_PPE_STATS_CONN_MAX)); ++ memcpy(stats, nss_ppe_debug_stats.conn_stats, (sizeof(uint32_t) * NSS_PPE_STATS_CONN_MAX)); + spin_unlock_bh(&nss_ppe_stats_lock); + } + +@@ -214,7 +569,7 @@ static void nss_ppe_stats_conn_get(uint6 + static void nss_ppe_stats_sc_get(struct nss_ppe_sc_stats_debug *sc_stats) + { + if (!sc_stats) { +- nss_warning("No memory to copy ppe service code stats"); ++ nss_warning("No memory to copy ppe connection stats"); + return; + } + +@@ -370,9 +725,10 @@ static ssize_t nss_ppe_conn_stats_read(s + char *lbuf = NULL; + size_t size_wr = 0; + ssize_t bytes_read = 0; +- uint64_t *stats_shadow; +- uint64_t ppe_stats[NSS_PPE_STATS_CONN_MAX]; +- uint32_t max_output_lines = NSS_PPE_STATS_CONN_MAX + NSS_STATS_EXTRA_OUTPUT_LINES; ++ uint32_t ppe_stats[NSS_PPE_STATS_CONN_MAX]; ++ uint32_t max_output_lines = 2 /* header & footer for session stats */ ++ + NSS_PPE_STATS_CONN_MAX /* PPE flow counters */ ++ + 2; + size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines; + + lbuf = kzalloc(size_al, GFP_KERNEL); +@@ -381,14 +737,7 @@ static ssize_t nss_ppe_conn_stats_read(s + return 0; + } + +- stats_shadow = kzalloc(NSS_PPE_STATS_CONN_MAX * 8, GFP_KERNEL); +- if (unlikely(!stats_shadow)) { +- nss_warning("Could not allocate memory for local shadow buffer"); +- kfree(lbuf); +- return 0; +- } +- +- memset(ppe_stats, 0, sizeof(uint64_t) * NSS_PPE_STATS_CONN_MAX); ++ memset(ppe_stats, 0, sizeof(uint32_t) * NSS_PPE_STATS_CONN_MAX); + + /* + * Get all stats +@@ -398,19 +747,20 @@ static ssize_t nss_ppe_conn_stats_read(s + /* + * flow stats + */ +- spin_lock_bh(&nss_ppe_stats_lock); ++ size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\nppe flow counters start:\n\n"); ++ + for (i = 0; i < NSS_PPE_STATS_CONN_MAX; i++) { +- stats_shadow[i] = ppe_stats[i]; ++ size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, ++ "\t%s = %u\n", nss_ppe_stats_str_conn[i], ++ ppe_stats[i]); + } + +- spin_unlock_bh(&nss_ppe_stats_lock); +- size_wr += nss_stats_print("ppe", "ppe flow counters", NSS_STATS_SINGLE_INSTANCE, nss_ppe_stats_str_conn, stats_shadow, +- NSS_PPE_STATS_CONN_MAX, lbuf, size_wr, size_al); ++ size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\n"); + +- bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf)); ++ size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\nppe flow counters end\n"); ++ bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, size_wr); + + kfree(lbuf); +- kfree(stats_shadow); + return bytes_read; + } + +@@ -425,7 +775,9 @@ static ssize_t nss_ppe_sc_stats_read(str + size_t size_wr = 0; + ssize_t bytes_read = 0; + struct nss_ppe_sc_stats_debug sc_stats[NSS_PPE_SC_MAX]; +- uint32_t max_output_lines = (NSS_PPE_SC_MAX * NSS_PPE_STATS_SERVICE_CODE_MAX) + NSS_STATS_EXTRA_OUTPUT_LINES; ++ uint32_t max_output_lines = 2 /* header & footer for sc stats */ ++ + NSS_PPE_SC_MAX /* PPE service-code counters */ ++ + 2; + size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines; + + lbuf = kzalloc(size_al, GFP_KERNEL); +@@ -444,16 +796,20 @@ static ssize_t nss_ppe_sc_stats_read(str + /* + * service code stats + */ ++ size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\nppe service code counters start:\n\n"); + + for (i = 0; i < NSS_PPE_SC_MAX; i++) { +- size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "ppe service code type: %s\n", +- nss_ppe_stats_str_sc_type[i]); +- size_wr += nss_stats_print("ppe", "ppe service code counters", NSS_STATS_SINGLE_INSTANCE, +- nss_ppe_stats_str_sc, &sc_stats[i].nss_ppe_sc_cb_unregister, +- NSS_PPE_STATS_SERVICE_CODE_MAX, lbuf, size_wr, size_al); ++ size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, ++ "\t%s \tcb_unregister:%llu process_ok:%llu process_fail:%llu\n", ++ nss_ppe_stats_str_sc[i], sc_stats[i].nss_ppe_sc_cb_unregister, ++ sc_stats[i].nss_ppe_sc_cb_success, sc_stats[i].nss_ppe_sc_cb_failure); + } + +- bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf)); ++ size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\n"); ++ ++ size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\nppe service code counters end\n"); ++ bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, size_wr); ++ + kfree(lbuf); + return bytes_read; + } +@@ -468,9 +824,10 @@ static ssize_t nss_ppe_l3_stats_read(str + char *lbuf = NULL; + size_t size_wr = 0; + ssize_t bytes_read = 0; +- uint64_t *stats_shadow; + uint32_t ppe_stats[NSS_PPE_STATS_L3_MAX]; +- uint32_t max_output_lines = NSS_PPE_STATS_L3_MAX + NSS_STATS_EXTRA_OUTPUT_LINES; ++ uint32_t max_output_lines = 2 /* header & footer for session stats */ ++ + NSS_PPE_STATS_L3_MAX /* PPE flow counters */ ++ + 2; + size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines; + + lbuf = kzalloc(size_al, GFP_KERNEL); +@@ -479,13 +836,6 @@ static ssize_t nss_ppe_l3_stats_read(str + return 0; + } + +- stats_shadow = kzalloc(NSS_PPE_STATS_L3_MAX * 8, GFP_KERNEL); +- if (unlikely(!stats_shadow)) { +- nss_warning("Could not allocate memory for local shadow buffer"); +- kfree(lbuf); +- return 0; +- } +- + memset(ppe_stats, 0, sizeof(uint32_t) * NSS_PPE_STATS_L3_MAX); + + /* +@@ -496,18 +846,20 @@ static ssize_t nss_ppe_l3_stats_read(str + /* + * flow stats + */ +- spin_lock_bh(&nss_ppe_stats_lock); ++ size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\nppe l3 debug stats start:\n\n"); ++ + for (i = 0; i < NSS_PPE_STATS_L3_MAX; i++) { +- stats_shadow[i] = ppe_stats[i]; ++ size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, ++ "\t%s = 0x%x\n", nss_ppe_stats_str_l3[i], ++ ppe_stats[i]); + } + +- spin_unlock_bh(&nss_ppe_stats_lock); +- size_wr += nss_stats_print("ppe", "ppe l3 debug stats", NSS_STATS_SINGLE_INSTANCE, nss_ppe_stats_str_l3, +- stats_shadow, NSS_PPE_STATS_L3_MAX, lbuf, size_wr, size_al); ++ size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\n"); ++ ++ size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\nppe l3 debug stats end\n"); ++ bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, size_wr); + +- bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf)); + kfree(lbuf); +- kfree(stats_shadow); + return bytes_read; + } + +@@ -521,9 +873,10 @@ static ssize_t nss_ppe_code_stats_read(s + char *lbuf = NULL; + size_t size_wr = 0; + ssize_t bytes_read = 0; +- uint64_t *stats_shadow; + uint32_t ppe_stats[NSS_PPE_STATS_CODE_MAX]; +- uint32_t max_output_lines = NSS_PPE_STATS_CODE_MAX + NSS_STATS_EXTRA_OUTPUT_LINES; ++ uint32_t max_output_lines = 2 /* header & footer for session stats */ ++ + NSS_PPE_STATS_CODE_MAX /* PPE flow counters */ ++ + 2; + size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines; + + lbuf = kzalloc(size_al, GFP_KERNEL); +@@ -532,13 +885,6 @@ static ssize_t nss_ppe_code_stats_read(s + return 0; + } + +- stats_shadow = kzalloc(NSS_PPE_STATS_CODE_MAX * 8, GFP_KERNEL); +- if (unlikely(!stats_shadow)) { +- nss_warning("Could not allocate memory for local shadow buffer"); +- kfree(lbuf); +- return 0; +- } +- + memset(ppe_stats, 0, sizeof(uint32_t) * NSS_PPE_STATS_CODE_MAX); + + /* +@@ -549,19 +895,20 @@ static ssize_t nss_ppe_code_stats_read(s + /* + * flow stats + */ +- spin_lock_bh(&nss_ppe_stats_lock); ++ size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\nppe session stats start:\n\n"); ++ + for (i = 0; i < NSS_PPE_STATS_CODE_MAX; i++) { +- stats_shadow[i] = ppe_stats[i]; ++ size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, ++ "\t%s = %u\n", nss_ppe_stats_str_code[i], ++ ppe_stats[i]); + } + +- spin_unlock_bh(&nss_ppe_stats_lock); +- size_wr += nss_stats_print("ppe", "ppe session stats", NSS_STATS_SINGLE_INSTANCE, nss_ppe_stats_str_code, stats_shadow, +- NSS_PPE_STATS_CODE_MAX, lbuf, size_wr, size_al); ++ size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\n"); + +- bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf)); ++ size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\nppe session stats end\n"); ++ bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, size_wr); + + kfree(lbuf); +- kfree(stats_shadow); + return bytes_read; + } + +@@ -574,13 +921,12 @@ static ssize_t nss_ppe_port_dc_stats_rea + int32_t i; + + /* +- * max output lines = #stats + few blank lines for future reference to add new stats. ++ * max output lines = #stats + 2 start tag line + 2 end tag line + five blank lines + */ +- uint32_t max_output_lines = NSS_PPE_STATS_DROP_CODE_MAX + NSS_STATS_EXTRA_OUTPUT_LINES; ++ uint32_t max_output_lines = (NSS_PPE_STATS_DROP_CODE_MAX + 4) + 5; + size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines; + size_t size_wr = 0; + ssize_t bytes_read = 0; +- uint64_t *stats_shadow; + struct nss_stats_data *data = fp->private_data; + uint32_t *ppe_stats; + +@@ -597,35 +943,38 @@ static ssize_t nss_ppe_port_dc_stats_rea + return 0; + } + +- stats_shadow = kzalloc((NSS_PPE_STATS_DROP_CODE_MAX) * 8, GFP_KERNEL); +- if (unlikely(!stats_shadow)) { +- nss_warning("Could not allocate memory for local shadow buffer"); +- kfree(lbuf); +- kfree(ppe_stats); +- return 0; +- } +- + /* + * Get drop code counters for specific port + */ + nss_ppe_port_drop_code_get(ppe_stats, data->edma_id); ++ size_wr = scnprintf(lbuf, size_al, "ppe no drop code stats start:\n\n"); ++ size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, ++ "\t%s = %u\n", nss_ppe_stats_str_dc[0], ++ ppe_stats[0]); ++ size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\nppe no drop code stats end\n\n"); + + /* + * Drop code stats + */ +- spin_lock_bh(&nss_ppe_stats_lock); +- for (i = 0; i < NSS_PPE_STATS_DROP_CODE_MAX; i++) { +- stats_shadow[i] = ppe_stats[i]; +- } ++ size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "ppe non-zero drop code stats start:\n\n"); ++ for (i = 1; i < NSS_PPE_STATS_DROP_CODE_MAX; i++) { ++ /* ++ * Print only non-zero stats. ++ */ ++ if (!ppe_stats[i]) { ++ continue; ++ } + +- spin_unlock_bh(&nss_ppe_stats_lock); +- size_wr += nss_stats_print("ppe", "ppe drop code stats", NSS_STATS_SINGLE_INSTANCE, nss_ppe_stats_str_dc, +- stats_shadow, NSS_PPE_STATS_DROP_CODE_MAX, lbuf, size_wr, size_al); ++ size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, ++ "\t%s = %u\n", nss_ppe_stats_str_dc[i], ++ ppe_stats[i]); ++ } ++ size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\nppe non-zero drop code stats end\n\n"); + + bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf)); + kfree(ppe_stats); + kfree(lbuf); +- kfree(stats_shadow); ++ + return bytes_read; + } + +@@ -638,13 +987,12 @@ static ssize_t nss_ppe_exception_cc_stat + int32_t i; + + /* +- * max output lines = #stats + few blank lines for future reference to add new stats. ++ * max output lines = #stats + start tag line + end tag line + three blank lines + */ +- uint32_t max_output_lines = NSS_PPE_STATS_CPU_CODE_EXCEPTION_MAX + NSS_STATS_EXTRA_OUTPUT_LINES; ++ uint32_t max_output_lines = (NSS_PPE_STATS_CPU_CODE_EXCEPTION_MAX + 2) + 3; + size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines; + size_t size_wr = 0; + ssize_t bytes_read = 0; +- uint64_t *stats_shadow; + uint32_t *ppe_stats; + + char *lbuf = kzalloc(size_al, GFP_KERNEL); +@@ -660,36 +1008,34 @@ static ssize_t nss_ppe_exception_cc_stat + return 0; + } + +- stats_shadow = kzalloc(NSS_PPE_STATS_CPU_CODE_EXCEPTION_MAX * 8, GFP_KERNEL); +- if (unlikely(!stats_shadow)) { +- nss_warning("Could not allocate memory for local shadow buffer"); +- kfree(lbuf); +- kfree(ppe_stats); +- return 0; +- } +- + /* + * Get CPU code counters for flow specific exceptions + */ + nss_ppe_cpu_code_exception_get(ppe_stats); + ++ size_wr = scnprintf(lbuf, size_al, "ppe non-zero cpu code flow-exception stats start:\n\n"); ++ + /* + * CPU code stats + */ +- spin_lock_bh(&nss_ppe_stats_lock); + for (i = 0; i < NSS_PPE_STATS_CPU_CODE_EXCEPTION_MAX; i++) { +- stats_shadow[i] = ppe_stats[i]; +- } ++ /* ++ * Print only non-zero stats. ++ */ ++ if (!ppe_stats[i]) { ++ continue; ++ } + +- spin_unlock_bh(&nss_ppe_stats_lock); +- size_wr += nss_stats_print("ppe", "ppe cpu code flow-exception stats", NSS_STATS_SINGLE_INSTANCE, +- nss_ppe_stats_str_cc, stats_shadow, NSS_PPE_STATS_CPU_CODE_EXCEPTION_MAX, +- lbuf, size_wr, size_al); ++ size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, ++ "\t%s = %u\n", nss_ppe_stats_str_cc[i], ++ ppe_stats[i]); ++ } + ++ size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\nppe non-zero cpu code flow-exception stats end\n\n"); + bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf)); + kfree(ppe_stats); + kfree(lbuf); +- kfree(stats_shadow); ++ + return bytes_read; + } + +@@ -702,13 +1048,12 @@ static ssize_t nss_ppe_nonexception_cc_s + int32_t i; + + /* +- * max output lines = #stats + few blank lines for future reference to add new stats. ++ * max output lines = #stats + start tag line + end tag line + three blank lines + */ +- uint32_t max_output_lines = NSS_PPE_STATS_CPU_CODE_NONEXCEPTION_MAX + NSS_STATS_EXTRA_OUTPUT_LINES; ++ uint32_t max_output_lines = (NSS_PPE_STATS_CPU_CODE_NONEXCEPTION_MAX + 2) + 3; + size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines; + size_t size_wr = 0; + ssize_t bytes_read = 0; +- uint64_t *stats_shadow; + uint32_t *ppe_stats; + + char *lbuf = kzalloc(size_al, GFP_KERNEL); +@@ -724,14 +1069,6 @@ static ssize_t nss_ppe_nonexception_cc_s + return 0; + } + +- stats_shadow = kzalloc(NSS_PPE_STATS_CPU_CODE_NONEXCEPTION_MAX * 8, GFP_KERNEL); +- if (unlikely(!stats_shadow)) { +- nss_warning("Could not allocate memory for local shadow buffer"); +- kfree(lbuf); +- kfree(ppe_stats); +- return 0; +- } +- + /* + * Get CPU code counters for non flow exceptions + */ +@@ -740,20 +1077,23 @@ static ssize_t nss_ppe_nonexception_cc_s + /* + * CPU code stats + */ +- +- spin_lock_bh(&nss_ppe_stats_lock); ++ size_wr = scnprintf(lbuf, size_al, "ppe non-zero cpu code non-flow exception stats start:\n\n"); + for (i = 0; i < NSS_PPE_STATS_CPU_CODE_NONEXCEPTION_MAX; i++) { +- stats_shadow[i] = ppe_stats[i]; +- } ++ /* ++ * Print only non-zero stats. ++ */ ++ if (!ppe_stats[i]) { ++ continue; ++ } + +- spin_unlock_bh(&nss_ppe_stats_lock); +- size_wr += nss_stats_print("ppe", "ppe cpu code non-flow exception stats", NSS_STATS_SINGLE_INSTANCE, +- &nss_ppe_stats_str_cc[NSS_PPE_STATS_CPU_CODE_NONEXCEPTION_START], +- stats_shadow, NSS_PPE_STATS_CPU_CODE_NONEXCEPTION_MAX, lbuf, size_wr, size_al); ++ size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, ++ "\t%s = %u\n", nss_ppe_stats_str_cc[i + NSS_PPE_STATS_CPU_CODE_NONEXCEPTION_START], ++ ppe_stats[i]); ++ } + ++ size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\nppe non-zero cpu code non-flow exception stats end\n\n"); + bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf)); + kfree(ppe_stats); +- kfree(stats_shadow); + kfree(lbuf); + + return bytes_read; +@@ -801,38 +1141,49 @@ void nss_ppe_stats_dentry_create(void) + { + int i; + struct dentry *ppe_dentry = NULL; ++ struct dentry *ppe_conn_d = NULL; ++ struct dentry *ppe_sc_d = NULL; ++ struct dentry *ppe_l3_d = NULL; ++ struct dentry *ppe_ppe_code_d = NULL; + struct dentry *ppe_code_d = NULL; + struct dentry *ppe_drop_d = NULL; ++ struct dentry *ppe_port_dc_d = NULL; + struct dentry *ppe_cpu_d = NULL; ++ struct dentry *ppe_exception_d = NULL; ++ struct dentry *ppe_nonexception_d = NULL; + char file_name[10]; + + ppe_dentry = debugfs_create_dir("ppe", nss_top_main.stats_dentry); +- if (!ppe_dentry) { ++ if (unlikely(ppe_dentry == NULL)) { + nss_warning("Failed to create qca-nss-drv/stats/ppe directory"); + return; + } + +- if (!debugfs_create_file("connection", 0400, ppe_dentry, &nss_top_main, &nss_ppe_conn_stats_ops)) { ++ ppe_conn_d = debugfs_create_file("connection", 0400, ppe_dentry, ++ &nss_top_main, &nss_ppe_conn_stats_ops); ++ if (unlikely(ppe_conn_d == NULL)) { + nss_warning("Failed to create qca-nss-drv/stats/ppe/connection file"); +- debugfs_remove_recursive(ppe_dentry); + return; + } + +- if (!debugfs_create_file("sc_stats", 0400, ppe_dentry, &nss_top_main, &nss_ppe_sc_stats_ops)) { ++ ppe_sc_d = debugfs_create_file("sc_stats", 0400, ppe_dentry, ++ &nss_top_main, &nss_ppe_sc_stats_ops); ++ if (unlikely(ppe_sc_d == NULL)) { + nss_warning("Failed to create qca-nss-drv/stats/ppe/sc_stats file"); +- debugfs_remove_recursive(ppe_dentry); + return; + } + +- if (!debugfs_create_file("l3", 0400, ppe_dentry, &nss_top_main, &nss_ppe_l3_stats_ops)) { +- nss_warning("Failed to create qca-nss-drv/stats/ppe/l3 file"); +- debugfs_remove_recursive(ppe_dentry); ++ ppe_l3_d = debugfs_create_file("l3", 0400, ppe_dentry, ++ &nss_top_main, &nss_ppe_l3_stats_ops); ++ if (unlikely(ppe_l3_d == NULL)) { ++ nss_warning("Failed to create qca-nss-drv/stats/ppe/l3 filed"); + return; + } + +- if (!debugfs_create_file("ppe_code", 0400, ppe_dentry, &nss_top_main, &nss_ppe_code_stats_ops)) { ++ ppe_ppe_code_d = debugfs_create_file("ppe_code", 0400, ppe_dentry, ++ &nss_top_main, &nss_ppe_code_stats_ops); ++ if (unlikely(ppe_ppe_code_d == NULL)) { + nss_warning("Failed to create qca-nss-drv/stats/ppe/ppe_code file"); +- debugfs_remove_recursive(ppe_dentry); + return; + } + +@@ -840,31 +1191,33 @@ void nss_ppe_stats_dentry_create(void) + * ppe exception and drop code stats + */ + ppe_code_d = debugfs_create_dir("code", ppe_dentry); +- if (!ppe_code_d) { ++ if (unlikely(ppe_code_d == NULL)) { + nss_warning("Failed to create qca-nss-drv/stats/ppe/code directory"); + return; + } + + ppe_cpu_d = debugfs_create_dir("cpu", ppe_code_d); +- if (!ppe_cpu_d) { ++ if (unlikely(ppe_cpu_d == NULL)) { + nss_warning("Failed to create qca-nss-drv/stats/ppe/code/cpu directory"); + return; + } + +- if (!debugfs_create_file("exception", 0400, ppe_cpu_d, &nss_top_main, &nss_ppe_exception_cc_stats_ops)) { ++ ppe_exception_d = debugfs_create_file("exception", 0400, ppe_cpu_d, ++ &nss_top_main, &nss_ppe_exception_cc_stats_ops); ++ if (unlikely(ppe_exception_d == NULL)) { + nss_warning("Failed to create qca-nss-drv/stats/ppe/code/exception file"); +- debugfs_remove_recursive(ppe_cpu_d); + return; + } + +- if (!debugfs_create_file("non-exception", 0400, ppe_cpu_d, &nss_top_main, &nss_ppe_nonexception_cc_stats_ops)) { ++ ppe_nonexception_d = debugfs_create_file("non-exception", 0400, ppe_cpu_d, ++ &nss_top_main, &nss_ppe_nonexception_cc_stats_ops); ++ if (unlikely(ppe_nonexception_d == NULL)) { + nss_warning("Failed to create qca-nss-drv/stats/ppe/code/non-exception file"); +- debugfs_remove_recursive(ppe_cpu_d); + return; + } + + ppe_drop_d = debugfs_create_dir("drop", ppe_code_d); +- if (!ppe_drop_d) { ++ if (unlikely(ppe_drop_d == NULL)) { + nss_warning("Failed to create qca-nss-drv/stats/ppe/code/drop directory"); + return; + } +@@ -875,51 +1228,11 @@ void nss_ppe_stats_dentry_create(void) + snprintf(file_name, sizeof(file_name), "%d", i); + } + +- if (!debugfs_create_file((i == 0) ? "cpu" : file_name, 0400, ppe_drop_d, +- (void *)(nss_ptr_t)i, &nss_ppe_port_dc_stats_ops)) { ++ ppe_port_dc_d = debugfs_create_file((i == 0) ? "cpu" : file_name, 0400, ppe_drop_d, ++ (void *)(nss_ptr_t)i, &nss_ppe_port_dc_stats_ops); ++ if (unlikely(ppe_port_dc_d == NULL)) { + nss_warning("Failed to create qca-nss-drv/stats/ppe/code/drop/%d file", i); +- debugfs_remove_recursive(ppe_drop_d); + return; + } + } + } +- +-/* +- * nss_ppe_stats_notify() +- * Sends notifications to all the registered modules. +- * +- * Leverage NSS-FW statistics timing to update Netlink. +- */ +-void nss_ppe_stats_notify(struct nss_ctx_instance *nss_ctx, uint32_t if_num) +-{ +- struct nss_ppe_stats_notification ppe_stats; +- +- spin_lock_bh(&nss_ppe_stats_lock); +- ppe_stats.core_id = nss_ctx->id; +- ppe_stats.if_num = if_num; +- memcpy(ppe_stats.ppe_stats_conn, nss_ppe_debug_stats.conn_stats, sizeof(ppe_stats.ppe_stats_conn)); +- memcpy(ppe_stats.ppe_stats_sc, nss_ppe_debug_stats.sc_stats, sizeof(ppe_stats.ppe_stats_sc)); +- spin_unlock_bh(&nss_ppe_stats_lock); +- +- atomic_notifier_call_chain(&nss_ppe_stats_notifier, NSS_STATS_EVENT_NOTIFY, &ppe_stats); +-} +- +-/* +- * nss_ppe_stats_unregister_notifier() +- * Deregisters statistics notifier. +- */ +-int nss_ppe_stats_unregister_notifier(struct notifier_block *nb) +-{ +- return atomic_notifier_chain_unregister(&nss_ppe_stats_notifier, nb); +-} +-EXPORT_SYMBOL(nss_ppe_stats_unregister_notifier); +- +-/* +- * nss_ppe_stats_register_notifier() +- * Registers statistics notifier. +- */ +-int nss_ppe_stats_register_notifier(struct notifier_block *nb) +-{ +- return atomic_notifier_chain_register(&nss_ppe_stats_notifier, nb); +-} +-EXPORT_SYMBOL(nss_ppe_stats_register_notifier); +--- a/nss_ppe_stats.h ++++ b/nss_ppe_stats.h +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2017-2018, 2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -22,8 +22,6 @@ + #ifndef __NSS_PPE_STATS_H + #define __NSS_PPE_STATS_H + +-#include +- + /* + * NSS PPE connection statistics + */ +@@ -72,16 +70,6 @@ enum nss_ppe_stats_conn { + }; + + /* +- * NSS PPE SC statistics +- */ +-enum nss_ppe_stats_service_code { +- NSS_PPE_STATS_SERVICE_CODE_CB_UNREGISTER, +- NSS_PPE_STATS_SERVICE_CODE_PROCESS_OK, +- NSS_PPE_STATS_SERVICE_CODE_PROCESS_FAIL, +- NSS_PPE_STATS_SERVICE_CODE_MAX +-}; +- +-/* + * NSS PPE L3 statistics + */ + enum nss_ppe_stats_l3 { +@@ -412,7 +400,7 @@ struct nss_ppe_sc_stats_debug { + * NSS PPE statistics + */ + struct nss_ppe_stats_debug { +- uint64_t conn_stats[NSS_PPE_STATS_CONN_MAX]; ++ uint32_t conn_stats[NSS_PPE_STATS_CONN_MAX]; + uint32_t l3_stats[NSS_PPE_STATS_L3_MAX]; + uint32_t code_stats[NSS_PPE_STATS_CODE_MAX]; + struct nss_ppe_sc_stats_debug sc_stats[NSS_PPE_SC_MAX]; +@@ -426,21 +414,9 @@ struct nss_ppe_stats_debug { + */ + extern struct nss_ppe_stats_debug nss_ppe_debug_stats; + +-/** +- * nss_ppe_stats_notification +- * PPE transmission statistics structure. +- */ +-struct nss_ppe_stats_notification { +- struct nss_ppe_sc_stats_debug ppe_stats_sc[NSS_PPE_SC_MAX]; /* PPE service code stats. */ +- uint64_t ppe_stats_conn[NSS_PPE_STATS_CONN_MAX]; /* PPE connection statistics. */ +- uint32_t core_id; /* Core ID. */ +- uint32_t if_num; /* Interface number. */ +-}; +- + /* + * NSS PPE statistics APIs + */ +-extern void nss_ppe_stats_notify(struct nss_ctx_instance *nss_ctx, uint32_t if_num); + extern void nss_ppe_stats_sync(struct nss_ctx_instance *nss_ctx, struct nss_ppe_sync_stats_msg *stats_msg, uint16_t if_num); + extern void nss_ppe_stats_dentry_create(void); + +--- a/nss_ppe_strings.c ++++ /dev/null +@@ -1,532 +0,0 @@ +-/* +- *************************************************************************** +- * Copyright (c) 2021, The Linux Foundation. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- *************************************************************************** +- */ +- +-#include "nss_stats.h" +-#include "nss_core.h" +-#include "nss_ppe.h" +-#include "nss_strings.h" +-#include "nss_ppe_strings.h" +- +-/* +- * nss_ppe_stats_str_conn +- * PPE statistics strings for nss flow stats +- */ +-struct nss_stats_info nss_ppe_stats_str_conn[NSS_PPE_STATS_CONN_MAX] = { +- {"v4 routed flows", NSS_STATS_TYPE_SPECIAL}, +- {"v4 bridge flows", NSS_STATS_TYPE_SPECIAL}, +- {"v4 conn create req", NSS_STATS_TYPE_SPECIAL}, +- {"v4 conn create fail", NSS_STATS_TYPE_SPECIAL}, +- {"v4 conn destroy req", NSS_STATS_TYPE_SPECIAL}, +- {"v4 conn destroy fail", NSS_STATS_TYPE_SPECIAL}, +- {"v4 conn MC create req", NSS_STATS_TYPE_SPECIAL}, +- {"v4 conn MC create fail", NSS_STATS_TYPE_SPECIAL}, +- {"v4 conn MC update req", NSS_STATS_TYPE_SPECIAL}, +- {"v4 conn MC update fail", NSS_STATS_TYPE_SPECIAL}, +- {"v4 conn MC delete req", NSS_STATS_TYPE_SPECIAL}, +- {"v4 conn MC delete fail", NSS_STATS_TYPE_SPECIAL}, +- {"v4 conn unknown if", NSS_STATS_TYPE_SPECIAL}, +- {"v6 routed flows", NSS_STATS_TYPE_SPECIAL}, +- {"v6 bridge flows", NSS_STATS_TYPE_SPECIAL}, +- {"v6 conn create req", NSS_STATS_TYPE_SPECIAL}, +- {"v6 conn create fail", NSS_STATS_TYPE_SPECIAL}, +- {"v6 conn destroy req", NSS_STATS_TYPE_SPECIAL}, +- {"v6 conn destroy fail", NSS_STATS_TYPE_SPECIAL}, +- {"v6 conn MC create req", NSS_STATS_TYPE_SPECIAL}, +- {"v6 conn MC create fail", NSS_STATS_TYPE_SPECIAL}, +- {"v6 conn MC update req", NSS_STATS_TYPE_SPECIAL}, +- {"v6 conn MC update fail", NSS_STATS_TYPE_SPECIAL}, +- {"v6 conn MC delete req", NSS_STATS_TYPE_SPECIAL}, +- {"v6 conn MC delete fail", NSS_STATS_TYPE_SPECIAL}, +- {"v6 conn unknown if", NSS_STATS_TYPE_SPECIAL}, +- {"conn fail - vp full", NSS_STATS_TYPE_SPECIAL}, +- {"conn fail - nexthop full", NSS_STATS_TYPE_SPECIAL}, +- {"conn fail - flow full", NSS_STATS_TYPE_SPECIAL}, +- {"conn fail - host full", NSS_STATS_TYPE_SPECIAL}, +- {"conn fail - pub-ip full", NSS_STATS_TYPE_SPECIAL}, +- {"conn fail - port not setup", NSS_STATS_TYPE_SPECIAL}, +- {"conn fail - rw fifo full", NSS_STATS_TYPE_SPECIAL}, +- {"conn fail - flow cmd failure", NSS_STATS_TYPE_SPECIAL}, +- {"conn fail - unknown proto", NSS_STATS_TYPE_SPECIAL}, +- {"conn fail - ppe not responding", NSS_STATS_TYPE_SPECIAL}, +- {"conn fail - CE opaque invalid", NSS_STATS_TYPE_SPECIAL}, +- {"conn fail - fqg full", NSS_STATS_TYPE_SPECIAL} +-}; +- +-/* +- * nss_ppe_stats_str_conn_strings_read() +- * Read ppe NSS flow statistics names +- */ +-static ssize_t nss_ppe_stats_str_conn_strings_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- return nss_strings_print(ubuf, sz, ppos, nss_ppe_stats_str_conn, NSS_PPE_STATS_CONN_MAX); +-} +- +-/* +- * nss_ppe_stats_str_conn_strings_ops +- */ +-NSS_STRINGS_DECLARE_FILE_OPERATIONS(ppe_stats_str_conn); +- +-/* +- * nss_ppe_stats_str_l3 +- * PPE statistics strings for nss debug stats +- */ +-struct nss_stats_info nss_ppe_stats_str_l3[NSS_PPE_STATS_L3_MAX] = { +- {"L3 dbg reg 0", NSS_STATS_TYPE_SPECIAL}, +- {"L3 dbg reg 1", NSS_STATS_TYPE_SPECIAL}, +- {"L3 dbg reg 2", NSS_STATS_TYPE_SPECIAL}, +- {"L3 dbg reg 3", NSS_STATS_TYPE_SPECIAL}, +- {"L3 dbg reg 4", NSS_STATS_TYPE_SPECIAL}, +- {"L3 dbg reg port", NSS_STATS_TYPE_SPECIAL} +-}; +- +-/* +- * nss_ppe_stats_str_l3_strings_read() +- * Read ppe NSS debug statistics names +- */ +-static ssize_t nss_ppe_stats_str_l3_strings_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- return nss_strings_print(ubuf, sz, ppos, nss_ppe_stats_str_l3, NSS_PPE_STATS_L3_MAX); +-} +- +-/* +- * nss_ppe_stats_str_l3_strings_ops +- */ +-NSS_STRINGS_DECLARE_FILE_OPERATIONS(ppe_stats_str_l3); +- +-/* +- * nss_ppe_stats_str_code +- * PPE statistics strings for nss debug stats +- */ +-struct nss_stats_info nss_ppe_stats_str_code[NSS_PPE_STATS_CODE_MAX] = { +- {"CPU_CODE", NSS_STATS_TYPE_SPECIAL}, +- {"DROP_CODE", NSS_STATS_TYPE_SPECIAL} +-}; +- +-/* +- * nss_ppe_stats_str_code_strings_read() +- * Read ppe NSS debug statistics names +- */ +-static ssize_t nss_ppe_stats_str_code_strings_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- return nss_strings_print(ubuf, sz, ppos, nss_ppe_stats_str_code, NSS_PPE_STATS_CODE_MAX); +-} +- +-/* +- * nss_ppe_stats_str_code_strings_ops +- */ +-NSS_STRINGS_DECLARE_FILE_OPERATIONS(ppe_stats_str_code); +- +-/* +- * nss_ppe_stats_str_dc +- * PPE statistics strings for drop code +- */ +-struct nss_stats_info nss_ppe_stats_str_dc[NSS_PPE_STATS_DROP_CODE_MAX] = { +- {"DROP_CODE_NONE", NSS_STATS_TYPE_SPECIAL}, +- {"DROP_CODE_EXP_UNKNOWN_L2_PORT", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_PPPOE_WRONG_VER_TYPE", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_PPPOE_WRONG_CODE", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_PPPOE_UNSUPPORTED_PPP_PROT", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_IPV4_WRONG_VER", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_IPV4_SMALL_IHL", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_IPV4_WITH_OPTION", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_IPV4_HDR_INCOMPLETE", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_IPV4_BAD_TOTAL_LEN", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_IPV4_DATA_INCOMPLETE", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_IPV4_FRAG", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_IPV4_PING_OF_DEATH", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_IPV4_SNALL_TTL", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_IPV4_UNK_IP_PROT", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_IPV4_CHECKSUM_ERR", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_IPV4_INV_SIP", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_IPV4_INV_DIP", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_IPV4_LAND_ATTACK", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_IPV4_AH_HDR_INCOMPLETE", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_IPV4_AH_HDR_CROSS_BORDER", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_IPV4_ESP_HDR_INCOMPLETE", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_IPV6_WRONG_VER", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_IPV6_HDR_INCOMPLETE", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_IPV6_BAD_PAYLOAD_LEN", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_IPV6_DATA_INCOMPLETE", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_IPV6_WITH_EXT_HDR", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_IPV6_SMALL_HOP_LIMIT", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_IPV6_INV_SIP", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_IPV6_INV_DIP", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_IPV6_LAND_ATTACK", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_IPV6_FRAG", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_IPV6_PING_OF_DEATH", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_IPV6_WITH_MORE_EXT_HDR", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_IPV6_UNK_LAST_NEXT_HDR", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_IPV6_MOBILITY_HDR_INCOMPLETE", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_IPV6_MOBILITY_HDR_CROSS_BORDER", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_IPV6_AH_HDR_INCOMPLETE", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_IPV6_AH_HDR_CROSS_BORDER", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_IPV6_ESP_HDR_INCOMPLETE", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_IPV6_ESP_HDR_CROSS_BORDER", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_IPV6_OTHER_EXT_HDR_INCOMPLETE", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_IPV6_OTHER_EXT_HDR_CROSS_BORDER", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_TCP_HDR_INCOMPLETE", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_TCP_HDR_CROSS_BORDER", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_TCP_SMAE_SP_DP", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_TCP_SMALL_DATA_OFFSET", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_TCP_FLAGS_0", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_TCP_FLAGS_1", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_TCP_FLAGS_2", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_TCP_FLAGS_3", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_TCP_FLAGS_4", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_TCP_FLAGS_5", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_TCP_FLAGS_6", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_TCP_FLAGS_7", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_TCP_CHECKSUM_ERR", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_UDP_HDR_INCOMPLETE", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_UDP_HDR_CROSS_BORDER", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_UDP_SMAE_SP_DP", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_UDP_BAD_LEN", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_UDP_DATA_INCOMPLETE", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_UDP_CHECKSUM_ERR", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_UDP_LITE_HDR_INCOMPLETE", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_UDP_LITE_HDR_CROSS_BORDER", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_UDP_LITE_SMAE_SP_DP", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_UDP_LITE_CSM_COV_1_TO_7", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_UDP_LITE_CSM_COV_TOO_LONG", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_UDP_LITE_CSM_COV_CROSS_BORDER", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EXP_UDP_LITE_CHECKSUM_ERR", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_L3_MC_BRIDGE_ACTION", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_L3_NO_ROUTE_PREHEAD_NAT_ACTION", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_L3_NO_ROUTE_PREHEAD_NAT_ERROR", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_L3_ROUTE_ACTION", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_L3_NO_ROUTE_ACTION", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_L3_NO_ROUTE_NH_INVALID_ACTION", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_L3_NO_ROUTE_PREHEAD_ACTION", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_L3_BRIDGE_ACTION", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_L3_FLOW_ACTION", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_L3_FLOW_MISS_ACTION", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_L2_EXP_MRU_FAIL", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_L2_EXP_MTU_FAIL", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_L3_EXP_IP_PREFIX_BC", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_L3_EXP_MTU_FAIL", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_L3_EXP_MRU_FAIL", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_L3_EXP_ICMP_RDT", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_FAKE_MAC_HEADER_ERR", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_L3_EXP_IP_RT_TTL_ZERO", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_L3_FLOW_SERVICE_CODE_LOOP", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_L3_FLOW_DE_ACCELEARTE", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_L3_EXP_FLOW_SRC_IF_CHK_FAIL", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_L3_FLOW_SYNC_TOGGLE_MISMATCH", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_L3_EXP_MTU_DF_FAIL", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_L3_EXP_PPPOE_MULTICAST", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_IPV4_SG_UNKNOWN", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_IPV6_SG_UNKNOWN", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_ARP_SG_UNKNOWN", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_ND_SG_UNKNOWN", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_IPV4_SG_VIO", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_IPV6_SG_VIO", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_ARP_SG_VIO", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_ND_SG_VIO", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_L2_NEW_MAC_ADDRESS", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_L2_HASH_COLLISION", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_L2_STATION_MOVE", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_L2_LEARN_LIMIT", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_L2_SA_LOOKUP_ACTION", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_L2_DA_LOOKUP_ACTION", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_APP_CTRL_ACTION", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_IN_VLAN_FILTER_ACTION", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_IN_VLAN_XLT_MISS", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_EG_VLAN_FILTER_DROP", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_ACL_PRE_ACTION", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_ACL_POST_ACTION", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_MC_BC_SA", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_NO_DESTINATION", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_STG_IN_FILTER", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_STG_EG_FILTER", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_SOURCE_FILTER_FAIL", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_TRUNK_SEL_FAIL", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_TX_EN_FAIL", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_VLAN_TAG_FMT", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_CRC_ERR", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_PAUSE_FRAME", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_PROMISC", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_ISOLATION", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_MGMT_APP", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_FAKE_L2_PROT_ERR", NSS_STATS_TYPE_DROP}, +- {"DROP_CODE_POLICER", NSS_STATS_TYPE_DROP} +-}; +- +-/* +- * nss_ppe_stats_str_dc_strings_read() +- * Read ppe drop code statistics names +- */ +-static ssize_t nss_ppe_stats_str_dc_strings_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- return nss_strings_print(ubuf, sz, ppos, nss_ppe_stats_str_dc, NSS_PPE_STATS_DROP_CODE_MAX); +-} +- +-/* +- * nss_ppe_stats_str_dc_strings_ops +- */ +-NSS_STRINGS_DECLARE_FILE_OPERATIONS(ppe_stats_str_dc); +- +-/* +- * nss_ppe_stats_str_sc +- * PPE statistics strings for service-code stats +- */ +-struct nss_stats_info nss_ppe_stats_str_sc[NSS_PPE_STATS_SERVICE_CODE_MAX] = { +- {"cb_unregister", NSS_STATS_TYPE_SPECIAL}, +- {"process_ok", NSS_STATS_TYPE_SPECIAL}, +- {"process_fail", NSS_STATS_TYPE_ERROR} +-}; +- +-/* +- * nss_ppe_stats_str_sc_strings_read() +- * Read ppe service code statistics names +- */ +-static ssize_t nss_ppe_stats_str_sc_strings_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- return nss_strings_print(ubuf, sz, ppos, nss_ppe_stats_str_sc, NSS_PPE_STATS_SERVICE_CODE_MAX); +-} +- +-/* +- * nss_ppe_stats_str_sc_strings_ops +- */ +-NSS_STRINGS_DECLARE_FILE_OPERATIONS(ppe_stats_str_sc); +- +-/* +- * nss_ppe_stats_str_cc +- * PPE statistics strings for cpu code +- */ +-struct nss_stats_info nss_ppe_stats_str_cc[NSS_PPE_STATS_CPU_CODE_MAX] = { +- {"CPU_CODE_FORWARDING", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_UNKNOWN_L2_PROT", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_PPPOE_WRONG_VER_TYPE", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_WRONG_CODE", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_PPPOE_UNSUPPORTED_PPP_PROT", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_WRONG_VER", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_SMALL_IHL", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_WITH_OPTION", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_HDR_INCOMPLETE", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_IPV4_BAD_TOTAL_LEN", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_DATA_INCOMPLETE", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_IPV4_FRAG", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_IPV4_PING_OF_DEATH", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_SNALL_TTL", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_IPV4_UNK_IP_PROT", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_CHECKSUM_ERR", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_INV_SIP", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_INV_DIP", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_LAND_ATTACK", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_IPV4_AH_HDR_INCOMPLETE", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_IPV4_AH_CROSS_BORDER", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_IPV4_ESP_HDR_INCOMPLETE", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_WRONG_VER", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_HDR_INCOMPLETE", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_IPV6_BAD_PAYLOAD_LEN", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_DATA_INCOMPLETE", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_IPV6_WITH_EXT_HDR", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_IPV6_SMALL_HOP_LIMIT", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_INV_SIP", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_INV_DIP", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_LAND_ATTACK", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_IPV6_FRAG", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_IPV6_PING_OF_DEATH", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_IPV6_WITH_EXT_HDR", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_IPV6_UNK_NEXT_HDR", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_IPV6_MOBILITY_HDR_INCOMPLETE", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_IPV6_MOBILITY_CROSS_BORDER", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_IPV6_AH_HDR_INCOMPLETE", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_IPV6_AH_CROSS_BORDER", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_IPV6_ESP_HDR_INCOMPLETE", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_IPV6_ESP_CROSS_BORDER", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_IPV6_OTHER_HDR_INCOMPLETE", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_IPV6_OTHER_EXT_CROSS_BORDER", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_HDR_INCOMPLETE", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_TCP_HDR_CROSS_BORDER", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_TCP_SMAE_SP_DP", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_TCP_SMALL_DATA_OFFSET", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_FLAGS_0", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_FLAGS_1", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_FLAGS_2", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_FLAGS_3", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_FLAGS_4", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_FLAGS_5", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_FLAGS_6", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_FLAGS_7", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_CHECKSUM_ERR", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_HDR_INCOMPLETE", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_UDP_HDR_CROSS_BORDER", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_UDP_SMAE_SP_DP", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_BAD_LEN", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_DATA_INCOMPLETE", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_CHECKSUM_ERR", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_UDP_LITE_HDR_INCOMPLETE", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_UDP_LITE_CROSS_BORDER", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_UDP_LITE_SP_DP", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_UDP_LITE_CSM_COV_TO_7", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_UDP_LITE_CSM_TOO_LONG", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_UDP_LITE_CSM_CROSS_BORDER", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_UDP_LITE_CHECKSUM_ERR", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_FAKE_L2_PROT_ERR", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EXP_FAKE_MAC_HEADER_ERR", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_BITMAP_MAX", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_L2_MRU_FAIL", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_L2_MTU_FAIL", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_L3_EXP_IP_PREFIX_BC", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_L3_MTU_FAIL", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_L3_MRU_FAIL", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_L3_ICMP_RDT", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_L3_EXP_IP_RT_TO_ME", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_L3_EXP_IP_TTL_ZERO", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_L3_FLOW_SERVICE_CODE_LOOP", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_L3_DE_ACCELERATE", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_L3_EXP_FLOW_SRC_CHK_FAIL", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_L3_FLOW_SYNC_TOGGLE_MISMATCH", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_L3_EXP_MTU_DF_FAIL", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_L3_PPPOE_MULTICAST", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_MGMT_OFFSET", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_MGMT_EAPOL", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_PPPOE_DIS", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_MGMT_IGMP", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_ARP_REQ", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_ARP_REP", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_MGMT_DHCPv4", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_MGMT_MLD", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_MGMT_NS", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_MGMT_NA", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_MGMT_DHCPv6", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_PTP_OFFSET", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_PTP_SYNC", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_FOLLOW_UP", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_DELAY_REQ", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_DELAY_RESP", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_PDELAY_REQ", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_PDELAY_RESP", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_PTP_PDELAY_RESP_FOLLOW_UP", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_PTP_ANNOUNCE", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_PTP_MANAGEMENT", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_PTP_SIGNALING", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_PTP_RSV_MSG", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_SG_UNKNOWN", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_SG_UNKNOWN", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_SG_UNKNOWN", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_SG_UNKNOWN", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_SG_VIO", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_SG_VIO", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_SG_VIO", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_SG_VIO", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_L3_ROUTING_IP_TO_ME", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_L3_SNAT_ACTION", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_L3_DNAT_ACTION", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_L3_RT_ACTION", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_L3_BR_ACTION", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_L3_BRIDGE_ACTION", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_L3_ROUTE_PREHEAD_RT_ACTION", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_L3_ROUTE_PREHEAD_SNAPT_ACTION", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_L3_ROUTE_PREHEAD_DNAPT_ACTION", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_L3_ROUTE_PREHEAD_SNAT_ACTION", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_L3_ROUTE_PREHEAD_DNAT_ACTION", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_L3_NO_ROUTE_NAT_ACTION", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_L3_NO_ROUTE_NAT_ERROR", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_ROUTE_ACTION", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_L3_ROUTE_ACTION", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_L3_NO_ROUTE_INVALID_ACTION", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_L3_NO_ROUTE_PREHEAD_ACTION", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_BRIDGE_ACTION", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_FLOW_ACTION", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_L3_MISS_ACTION", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_L2_MAC_ADDRESS", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_HASH_COLLISION", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_STATION_MOVE", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_LEARN_LIMIT", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_L2_LOOKUP_ACTION", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_L2_LOOKUP_ACTION", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_CTRL_ACTION", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_IN_FILTER_ACTION", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_IN_XLT_MISS", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_EG_FILTER_DROP", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_PRE_ACTION", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_POST_ACTION", NSS_STATS_TYPE_EXCEPTION}, +- {"CPU_CODE_CODE_ACTION", NSS_STATS_TYPE_EXCEPTION} +-}; +- +-/* +- * nss_ppe_stats_str_cc_strings_read() +- * Read ppe cpu code statistics names +- */ +-static ssize_t nss_ppe_stats_str_cc_strings_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- return nss_strings_print(ubuf, sz, ppos, nss_ppe_stats_str_cc, NSS_PPE_STATS_CPU_CODE_MAX); +-} +- +-/* +- * nss_ppe_stats_str_cc_strings_ops +- */ +-NSS_STRINGS_DECLARE_FILE_OPERATIONS(ppe_stats_str_cc); +- +-/* +- * nss_ppe_strings_dentry_create() +- * Create ppe statistics strings debug entry. +- */ +-void nss_ppe_strings_dentry_create(void) +-{ +- struct dentry *ppe_d = NULL; +- +- if (!nss_top_main.strings_dentry) { +- nss_warning("qca-nss-drv/strings is not present"); +- return; +- } +- +- ppe_d = debugfs_create_dir("ppe", nss_top_main.strings_dentry); +- if (!ppe_d) { +- nss_warning("Failed to create qca-nss-drv/strings/ppe directory"); +- return; +- } +- +- if (!debugfs_create_file("stats_str_conn", 0400, ppe_d, &nss_top_main, &nss_ppe_stats_str_conn_strings_ops)) { +- nss_warning("Failed to create qca-nss-drv/strings/ppe/stats_str_conn file"); +- debugfs_remove_recursive(ppe_d); +- return; +- } +- +- if (!debugfs_create_file("stats_str_sc", 0400, ppe_d, &nss_top_main, &nss_ppe_stats_str_sc_strings_ops)) { +- nss_warning("Failed to create qca-nss-drv/strings/ppe/stats_str_sc file"); +- debugfs_remove_recursive(ppe_d); +- return; +- } +- +- if (!debugfs_create_file("stats_str_l3", 0400, ppe_d, &nss_top_main, &nss_ppe_stats_str_l3_strings_ops)) { +- nss_warning("Failed to create qca-nss-drv/strings/ppe/stats_str_l3 file"); +- debugfs_remove_recursive(ppe_d); +- return; +- } +- +- if (!debugfs_create_file("stats_str_code", 0400, ppe_d, &nss_top_main, &nss_ppe_stats_str_code_strings_ops)) { +- nss_warning("Failed to create qca-nss-drv/strings/ppe/stats_str_code file"); +- debugfs_remove_recursive(ppe_d); +- return; +- } +- +- if (!debugfs_create_file("stats_str_dc", 0400, ppe_d, &nss_top_main, &nss_ppe_stats_str_dc_strings_ops)) { +- nss_warning("Failed to create qca-nss-drv/strings/ppe/stats_str_dc file"); +- debugfs_remove_recursive(ppe_d); +- return; +- } +- +- if (!debugfs_create_file("stats_str_cc", 0400, ppe_d, &nss_top_main, &nss_ppe_stats_str_cc_strings_ops)) { +- nss_warning("Failed to create qca-nss-drv/strings/ppe/stats_str_cc file"); +- debugfs_remove_recursive(ppe_d); +- return; +- } +-} +--- a/nss_ppe_strings.h ++++ /dev/null +@@ -1,32 +0,0 @@ +-/* +- *************************************************************************** +- * Copyright (c) 2021, The Linux Foundation. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- *************************************************************************** +- */ +- +-#ifndef __NSS_PPE_STRINGS_H +-#define __NSS_PPE_STRINGS_H +- +-#include "nss_ppe_stats.h" +- +-extern struct nss_stats_info nss_ppe_stats_str_conn[NSS_PPE_STATS_CONN_MAX]; +-extern struct nss_stats_info nss_ppe_stats_str_sc[NSS_PPE_STATS_SERVICE_CODE_MAX]; +-extern struct nss_stats_info nss_ppe_stats_str_l3[NSS_PPE_STATS_L3_MAX]; +-extern struct nss_stats_info nss_ppe_stats_str_code[NSS_PPE_STATS_CODE_MAX]; +-extern struct nss_stats_info nss_ppe_stats_str_dc[NSS_PPE_STATS_DROP_CODE_MAX]; +-extern struct nss_stats_info nss_ppe_stats_str_cc[NSS_PPE_STATS_CPU_CODE_MAX]; +-extern void nss_ppe_strings_dentry_create(void); +- +-#endif /* __NSS_PPE_STRINGS_H */ +--- a/nss_ppe_vp.c ++++ b/nss_ppe_vp.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above +@@ -16,19 +16,11 @@ + ************************************************************************** + */ + +-/* +- * Header file for qca-ssdk APIs +- */ +-#include +- + #include "nss_ppe_vp.h" + #include "nss_ppe_vp_stats.h" + + #define NSS_PPE_VP_TX_TIMEOUT 1000 /* 1 Second */ + +-static struct nss_vp_mapping *vp_map[NSS_MAX_DYNAMIC_INTERFACES] = {NULL}; +-unsigned char nss_ppe_vp_cmd[NSS_PPE_VP_MAX_CMD_STR] __read_mostly; +- + /* + * Private data structure + */ +@@ -38,25 +30,17 @@ static struct nss_ppe_vp_pvt { + int response; + void *cb; + void *app_data; +- nss_ppe_port_t ppe_port_num; + } ppe_vp_pvt; + ++int nss_ppe_vp_enable __read_mostly = 0; ++int nss_ppe_vp_disable __read_mostly = 0; ++ + DEFINE_SPINLOCK(nss_ppe_vp_stats_lock); +-DEFINE_SPINLOCK(nss_ppe_vp_map_lock); + + struct nss_ppe_vp_stats_debug nss_ppe_vp_debug_stats; + static struct dentry *nss_ppe_vp_dentry; + + /* +- * nss_ppe_vp_get_map_index() +- * Get the index of the NSS-VP number mapping array. +- */ +-static inline int32_t nss_ppe_vp_get_map_index(nss_if_num_t if_num) +-{ +- return (if_num - NSS_DYNAMIC_IF_START); +-} +- +-/* + * nss_ppe_vp_verify_ifnum() + * Verify PPE VP interface number. + */ +@@ -66,122 +50,12 @@ static inline bool nss_ppe_vp_verify_ifn + } + + /* +- * nss_ppe_vp_map_dealloc() +- * Deallocate memory for the NSS interface number and PPE VP number mapping. +- */ +-static inline void nss_ppe_vp_map_dealloc(struct nss_vp_mapping *map) +-{ +- vfree(map); +-} +- +-/* +- * nss_ppe_vp_map_alloc() +- * Allocate memory for the NSS interface number and PPE VP number mapping. +- */ +-static inline struct nss_vp_mapping *nss_ppe_vp_map_alloc(void) +-{ +- struct nss_vp_mapping *nss_vp_info = vzalloc(sizeof(struct nss_vp_mapping)); +- if (!nss_vp_info) { +- nss_warning("No memory for allocating NSS-VP mapping instance"); +- } +- +- return nss_vp_info; +-} +- +-/* +- * nss_ppe_vp_proc_help() +- * Print usage information for ppe_vp configure sysctl. +- */ +-static void nss_ppe_vp_proc_help(void) +-{ +- nss_info_always("== for dynamic interface types read following file =="); +- nss_info_always("/sys/kernel/debug/qca-nss-drv/stats/dynamic_if/type_names"); +- nss_info_always("NSS PPE VP create: echo > /proc/sys/nss/ppe_vp/create"); +- nss_info_always("NSS PPE VP destroy: echo > /proc/sys/nss/ppe_vp/destroy"); +-} +- +-/* +- * nss_ppe_vp_del_map() +- * Delete mapping between NSS interface number and VP number. +- */ +-static bool nss_ppe_vp_del_map(struct nss_ctx_instance *nss_ctx, nss_if_num_t if_num) +-{ +- int32_t idx; +- nss_ppe_port_t ppe_port_num; +- struct nss_vp_mapping *nss_vp_info; +- uint16_t vp_index; +- +- nss_assert((if_num >= NSS_DYNAMIC_IF_START) && (if_num < (NSS_DYNAMIC_IF_START + NSS_MAX_DYNAMIC_INTERFACES))); +- +- idx = nss_ppe_vp_get_map_index(if_num); +- if ((idx < 0) || (idx >= NSS_MAX_DYNAMIC_INTERFACES)) { +- nss_warning("%px: Invalid index. Cannot delete the PPE VP mapping. idx:%u", nss_ctx, idx); +- return false; +- } +- +- spin_lock_bh(&nss_ppe_vp_map_lock); +- nss_vp_info = vp_map[idx]; +- if (!nss_vp_info) { +- spin_unlock_bh(&nss_ppe_vp_map_lock); +- nss_warning("%px: Could not find the vp num in the mapping. NSS if num:%u", nss_ctx, if_num); +- return false; +- } +- +- ppe_port_num = nss_vp_info->ppe_port_num; +- +- nss_ppe_vp_map_dealloc(nss_vp_info); +- vp_map[idx] = NULL; +- spin_unlock_bh(&nss_ppe_vp_map_lock); +- +- /* +- * Clear the PPE VP stats once PPE VP is deleted +- */ +- vp_index = ppe_port_num - NSS_PPE_VP_START; +- spin_lock_bh(&nss_ppe_vp_stats_lock); +- memset(&nss_ppe_vp_debug_stats.vp_stats[vp_index], 0, sizeof(struct nss_ppe_vp_statistics_debug)); +- spin_unlock_bh(&nss_ppe_vp_stats_lock); +- +- nss_info("%px: Deleted NSS interface number and PPE VP number mapping successfully: NSS if num:%u at index:%u", nss_ctx, if_num, idx); +- +- return true; +-} +- +-/* +- * nss_ppe_vp_add_map() +- * Add mapping between NSS interface number and VP number. ++ * nss_ppe_vp_get_context() ++ * Get NSS context instance for ppe_vp + */ +-static bool nss_ppe_vp_add_map(struct nss_ctx_instance *nss_ctx ,nss_if_num_t if_num, struct nss_vp_mapping *nss_vp_info) ++struct nss_ctx_instance *nss_ppe_vp_get_context(void) + { +- uint32_t idx; +- nss_ppe_port_t ppe_port_num; +- +- nss_assert((if_num >= NSS_DYNAMIC_IF_START) && (if_num < (NSS_DYNAMIC_IF_START + NSS_MAX_DYNAMIC_INTERFACES))); +- +- if (!nss_vp_info) { +- nss_warning("%px: Received invalid argument.", nss_ctx); +- return false; +- } +- +- idx = nss_ppe_vp_get_map_index(if_num); +- if ((idx < 0) || (idx >= NSS_MAX_DYNAMIC_INTERFACES)) { +- nss_warning("%px: Invalid index. Cannot add the PPE VP mapping. idx:%u", nss_ctx, idx); +- return false; +- } +- +- spin_lock_bh(&nss_ppe_vp_map_lock); +- if (vp_map[idx]) { +- spin_unlock_bh(&nss_ppe_vp_map_lock); +- nss_warning("%px: Mapping exists already. NSS if num:%d index:%u, VP num:%u", nss_ctx, if_num, idx, vp_map[idx]->ppe_port_num); +- return false; +- } +- +- vp_map[idx] = nss_vp_info; +- ppe_port_num = vp_map[idx]->ppe_port_num; +- spin_unlock_bh(&nss_ppe_vp_map_lock); +- +- nss_info("%px: Mapping added successfully. NSS if num:%d index:%u, VP num:%u", nss_ctx, if_num, idx, ppe_port_num); +- +- return true; ++ return (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.ppe_handler_id]; + } + + /* +@@ -191,107 +65,21 @@ static bool nss_ppe_vp_add_map(struct ns + static void nss_ppe_vp_callback(void *app_data, struct nss_ppe_vp_msg *npvm) + { + if (npvm->cm.response != NSS_CMN_RESPONSE_ACK) { +- nss_warning("ppe_vp error response %d", npvm->cm.response); +- ppe_vp_pvt.response = NSS_TX_FAILURE; +- complete(&ppe_vp_pvt.complete); +- return; ++ nss_warning("ppe_vp error response %d\n", npvm->cm.response); ++ ppe_vp_pvt.response = npvm->cm.response; + } + +- if (npvm->cm.type == NSS_IF_PPE_PORT_CREATE) { +- ppe_vp_pvt.ppe_port_num = npvm->msg.if_msg.ppe_port_create.ppe_port_num; +- nss_trace("PPE VP callback success VP num: %u", npvm->msg.if_msg.ppe_port_create.ppe_port_num); +- } + ppe_vp_pvt.response = NSS_TX_SUCCESS; +- + complete(&ppe_vp_pvt.complete); + } + + /* +- * nss_ppe_vp_parse_vp_cmd() +- * Parse PPE VP create and destroy message and return the NSS interface number. +- * Command usage: +- * echo /proc/sys/nss/ppe_vp/create> +- * echo ath0 6 > /proc/sys/nss/ppe_vp/create +- * Since ath0 has only one type i.e. ath0 is NSS_DYNAMIC_INTERFACE_TYPE_VAP, the above command can be rewritten as +- * echo ath0 > /proc/sys/nss/ppe_vp/create => Here 6 can be ignored. +- */ +-static nss_if_num_t nss_ppe_vp_parse_vp_cmd(struct ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos) +-{ +- int32_t if_num; +- struct net_device *dev; +- uint32_t dynamic_if_type = (uint32_t)NSS_DYNAMIC_INTERFACE_TYPE_NONE; +- struct nss_ctx_instance *nss_ctx = nss_ppe_vp_get_context(); +- char *pos; +- char cmd_buf[NSS_PPE_VP_MAX_CMD_STR] = {0}, dev_name[NSS_PPE_VP_MAX_CMD_STR] = {0}; +- size_t count = *lenp; +- int ret = proc_dostring(ctl, write, buffer, lenp, ppos); +- +- if (!write) { +- nss_ppe_vp_proc_help(); +- return ret; +- } +- +- if (!nss_ctx) { +- nss_warning("%px: NSS Context not found.", nss_ctx); +- return -ENODEV; +- } +- +- NSS_VERIFY_CTX_MAGIC(nss_ctx); +- +- if (count >= NSS_PPE_VP_MAX_CMD_STR) { +- nss_ppe_vp_proc_help(); +- nss_warning("%px: Input string too big", nss_ctx); +- return -E2BIG; +- } +- +- if (copy_from_user(cmd_buf, buffer, count)) { +- nss_warning("%px: Cannot copy user's entry to kernel memory", nss_ctx); +- return -EFAULT; +- } +- +- if ((pos = strrchr(cmd_buf, '\n')) != NULL) { +- *pos = '\0'; +- } +- +- if (sscanf(cmd_buf, "%s %u", dev_name, &dynamic_if_type) < 0) { +- nss_warning("%px: PPE VP command parse failed", nss_ctx); +- return -EFAULT; +- } +- +- dev = dev_get_by_name(&init_net, dev_name); +- if (!dev) { +- nss_warning("%px: Cannot find the net device", nss_ctx); +- return -ENODEV; +- } +- +- nss_info("%px: Dynamic interface type: %u", nss_ctx, dynamic_if_type); +- if ((dynamic_if_type < NSS_DYNAMIC_INTERFACE_TYPE_NONE) || (dynamic_if_type >= NSS_DYNAMIC_INTERFACE_TYPE_MAX)) { +- nss_warning("%px: Invalid dynamic interface type: %d", nss_ctx, dynamic_if_type); +- dev_put(dev); +- return -EFAULT; +- } +- +- if_num = nss_cmn_get_interface_number_by_dev_and_type(dev, dynamic_if_type); +- if (if_num < 0) { +- nss_warning("%px: Invalid interface number:%s", nss_ctx, dev_name); +- dev_put(dev); +- return -EFAULT; +- } +- +- nss_info("%px: PPE VP create/destroy for, nss_if_num:%d dev_name:%s dynamic_if_type:%u", nss_ctx, if_num, dev_name, dynamic_if_type); +- dev_put(dev); +- +- return if_num; +-} +- +-/* + * nss_ppe_vp_tx_msg() + * Transmit a ppe_vp message to NSS FW + */ + nss_tx_status_t nss_ppe_vp_tx_msg(struct nss_ctx_instance *nss_ctx, struct nss_ppe_vp_msg *msg) + { + struct nss_cmn_msg *ncm = &msg->cm; +- nss_if_num_t if_num = ncm->interface; + + /* + * Trace messages. +@@ -301,13 +89,13 @@ nss_tx_status_t nss_ppe_vp_tx_msg(struct + /* + * Sanity check the message + */ +- if (!((ncm->type == NSS_IF_PPE_PORT_CREATE) || (ncm->type == NSS_IF_PPE_PORT_DESTROY))) { +- nss_warning("%px: Invalid message type: %d", nss_ctx, ncm->type); ++ if (ncm->type >= NSS_PPE_VP_MSG_MAX) { ++ nss_warning("%px: message type out of range: %d\n", nss_ctx, ncm->type); + return NSS_TX_FAILURE; + } + +- if (!(if_num >= NSS_DYNAMIC_IF_START && (if_num < (NSS_DYNAMIC_IF_START + NSS_MAX_DYNAMIC_INTERFACES)))) { +- nss_warning("%px: invalid interface %d", nss_ctx, ncm->interface); ++ if (!nss_ppe_vp_verify_ifnum(ncm->interface)) { ++ nss_warning("%px: invalid interface %d\n", nss_ctx, ncm->interface); + return NSS_TX_FAILURE; + } + +@@ -324,294 +112,63 @@ nss_tx_status_t nss_ppe_vp_tx_msg_sync(s + int ret = 0; + + down(&ppe_vp_pvt.sem); ++ npvm->cm.cb = (nss_ptr_t)nss_ppe_vp_callback; ++ npvm->cm.app_data = (nss_ptr_t)NULL; + + status = nss_ppe_vp_tx_msg(nss_ctx, npvm); + if (status != NSS_TX_SUCCESS) { +- nss_warning("%px: ppe_tx_msg failed", nss_ctx); ++ nss_warning("%px: ppe_tx_msg failed\n", nss_ctx); + up(&ppe_vp_pvt.sem); + return status; + } + + ret = wait_for_completion_timeout(&ppe_vp_pvt.complete, msecs_to_jiffies(NSS_PPE_VP_TX_TIMEOUT)); + if (!ret) { +- nss_warning("%px: ppe_vp msg tx failed due to timeout", nss_ctx); ++ nss_warning("%px: ppe_vp msg tx failed due to timeout\n", nss_ctx); + ppe_vp_pvt.response = NSS_TX_FAILURE; + } + + status = ppe_vp_pvt.response; + up(&ppe_vp_pvt.sem); +- + return status; + } + + /* +- * nss_ppe_vp_get_context() +- * Get NSS context instance for ppe_vp +- */ +-struct nss_ctx_instance *nss_ppe_vp_get_context(void) +-{ +- return (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.ppe_handler_id]; +-} +-EXPORT_SYMBOL(nss_ppe_vp_get_context); +- +-/* +- * nss_ppe_vp_get_ppe_port_by_nssif() +- * Get vp number for a given NSS interface number. ++ * nss_ppe_vp_tx_config_msg ++ * API to send ppe_vp support configure message to NSS FW + */ +-nss_ppe_port_t nss_ppe_vp_get_ppe_port_by_nssif(struct nss_ctx_instance *nss_ctx, nss_if_num_t if_num) ++nss_tx_status_t nss_ppe_vp_tx_config_msg(enum nss_dynamic_interface_type type, bool enable) + { +- uint32_t idx; +- nss_ppe_port_t ppe_port_num; +- +- if (!((if_num >= NSS_DYNAMIC_IF_START) && (if_num < (NSS_DYNAMIC_IF_START + NSS_MAX_DYNAMIC_INTERFACES)))) { +- nss_warning("%px: NSS invalid nss if num: %u", nss_ctx, if_num); +- return -1; +- } +- +- idx = nss_ppe_vp_get_map_index(if_num); +- if (idx < 0 || idx >= NSS_MAX_DYNAMIC_INTERFACES) { +- nss_warning("%px: NSS invalid index: %d nss if num: %u",nss_ctx, idx, if_num); +- return -1; +- } +- +- spin_lock_bh(&nss_ppe_vp_map_lock); +- if (!vp_map[idx]) { +- spin_unlock_bh(&nss_ppe_vp_map_lock); +- nss_warning("%px: NSS interface and VP mapping is not present for nss if num: %u",nss_ctx, if_num); +- return -1; +- } +- ppe_port_num = vp_map[idx]->ppe_port_num; +- spin_unlock_bh(&nss_ppe_vp_map_lock); +- +- nss_info("%px: VP num %d nss_if: %d",nss_ctx, ppe_port_num, if_num); +- +- return ppe_port_num; +-} +-EXPORT_SYMBOL(nss_ppe_vp_get_ppe_port_by_nssif); +- +-/* +- * nss_ppe_vp_destroy() +- * Destroy PPE virtual port for the given nss interface number. +- */ +-nss_tx_status_t nss_ppe_vp_destroy(struct nss_ctx_instance *nss_ctx, nss_if_num_t if_num) +-{ +- nss_tx_status_t status; ++ struct nss_ctx_instance *nss_ctx = nss_ppe_vp_get_context(); ++ struct nss_ppe_vp_config_msg *npvcm; + struct nss_ppe_vp_msg *npvm; +- uint32_t idx; +- int32_t vsi_id_valid = false; +- int32_t vsi_id; +- +- NSS_VERIFY_CTX_MAGIC(nss_ctx); +- +- idx = nss_ppe_vp_get_map_index(if_num); +- if (idx < 0 || idx >= NSS_MAX_DYNAMIC_INTERFACES) { +- nss_warning("%px: Cannot destroy PPE VP. Invalid index: %d. nss_if_num: %u", nss_ctx, idx, if_num); +- return -1; +- } +- +- spin_lock_bh(&nss_ppe_vp_map_lock); +- if (vp_map[idx]) { +- vsi_id = vp_map[idx]->vsi_id; +- vsi_id_valid = vp_map[idx]->vsi_id_valid; +- } +- spin_unlock_bh(&nss_ppe_vp_map_lock); +- +- if (vsi_id_valid) { +- /* +- * Send the dettach VSI message to the Firmware. +- */ +- if (nss_if_vsi_unassign(nss_ctx, if_num, vsi_id)) { +- nss_warning("%px: PPE VP destroy failed. Failed to detach VSI to PPE VP interface %d vsi:%d", nss_ctx, if_num, vsi_id); +- return NSS_TX_FAILURE; +- } +- +- if (ppe_vsi_free(NSS_PPE_VP_SWITCH_ID, vsi_id)) { +- nss_warning("%px: PPE VP destroy failed. Failed to free PPE VSI. nss_if:%d vsi:%d", nss_ctx, if_num, vsi_id); +- return NSS_TX_FAILURE; +- } +- +- nss_info("%px: PPE VP VSI detached successfully. VSI ID freed successfully. NSS if num:%u, VSI ID:%u", nss_ctx, if_num, vsi_id); +- } +- +- npvm = kzalloc(sizeof(struct nss_ppe_vp_msg), GFP_KERNEL); +- if (!npvm) { +- nss_warning("%px: Unable to allocate memeory of PPE VP message", nss_ctx); +- return NSS_TX_FAILURE; +- } +- +- nss_trace("%px: PPE_VP will be destroyed for an interface: %d", nss_ctx, if_num); +- +- /* +- * Destroy PPE VP for a dynamic interface. +- */ +- nss_cmn_msg_init(&npvm->cm, if_num, NSS_IF_PPE_PORT_DESTROY, 0, nss_ppe_vp_callback, NULL); +- +- status = nss_ppe_vp_tx_msg_sync(nss_ctx, npvm); +- if (status != NSS_TX_SUCCESS) { +- nss_warning("%px: Unable to send PPE VP destroy message", nss_ctx); +- kfree(npvm); +- return NSS_TX_FAILURE; +- } +- +- kfree(npvm); +- +- /* +- * Delete mapping between the NSS interface number and the VP number. +- */ +- if (!nss_ppe_vp_del_map(nss_ctx, if_num)) { +- nss_warning("%px: Failed to delete the mapping for nss_if:%d", nss_ctx, if_num); +- return NSS_TX_FAILURE; +- } +- +- return status; +-} +-EXPORT_SYMBOL(nss_ppe_vp_destroy); +- +-/* +- * nss_ppe_vp_create() +- * Create PPE virtual port for the given nss interface number. +- */ +-nss_tx_status_t nss_ppe_vp_create(struct nss_ctx_instance *nss_ctx, nss_if_num_t if_num) +-{ +- uint32_t vsi_id; + nss_tx_status_t status; +- struct nss_ppe_vp_msg *npvm; +- struct nss_vp_mapping *nss_vp_info; +- +- NSS_VERIFY_CTX_MAGIC(nss_ctx); + +- /* +- * TODO: No need to create VSI for tunnel interfaces. Only for VAP interfaces VSI is needed. +- * Allocate the VSI for the dynamic interface on which VP will be created. +- */ +- if (ppe_vsi_alloc(NSS_PPE_VP_SWITCH_ID, &vsi_id)) { +- nss_warning("%px, Failed to alloc VSI ID, PPE VP create failed. nss_if:%u", nss_ctx, if_num); +- return NSS_TX_FAILURE; ++ if (type >= NSS_DYNAMIC_INTERFACE_TYPE_MAX) { ++ nss_warning("%px: Dynamic if msg drooped as type is wrong:%d\n", nss_ctx, type); ++ return -1; + } + + npvm = kzalloc(sizeof(struct nss_ppe_vp_msg), GFP_KERNEL); + if (!npvm) { +- nss_warning("%px: Unable to allocate memeory of PPE VP message", nss_ctx); +- goto free_vsi; ++ nss_warning("%px: Unable to allocate message\n", nss_ctx); ++ return -1; + } + +- nss_trace("%px: PPE_VP will be created for an interface: %d", nss_ctx, if_num); ++ nss_cmn_msg_init(&npvm->cm, NSS_PPE_VP_INTERFACE, NSS_PPE_VP_MSG_CONFIG, ++ sizeof(struct nss_ppe_vp_config_msg), NULL, NULL); + +- /* +- * Create PPE VP for a dynamic interface. +- */ +- nss_cmn_msg_init(&npvm->cm, if_num, NSS_IF_PPE_PORT_CREATE, +- sizeof(struct nss_if_ppe_port_create), nss_ppe_vp_callback, NULL); ++ npvcm = &npvm->msg.vp_config; ++ npvcm->type = type; ++ npvcm->vp_enable = enable; + + status = nss_ppe_vp_tx_msg_sync(nss_ctx, npvm); + if (status != NSS_TX_SUCCESS) { +- nss_warning("%px: Unable to send ppe_vp create message", nss_ctx); +- goto free_alloc; +- } +- +- /* +- * Send the attach VSI message to the Firmware. +- */ +- if (nss_if_vsi_assign(nss_ctx, if_num, vsi_id) != NSS_TX_SUCCESS) { +- nss_warning("%px: Failed to attach VSI to PPE VP interface. nss_if:%u vsi:%u", nss_ctx, if_num, vsi_id); +- goto destroy_vp; +- } +- +- nss_vp_info = nss_ppe_vp_map_alloc(); +- if (!nss_vp_info) { +- nss_warning("%px: No memory for allocating NSS-VP mapping instance", nss_ctx); +- goto detach_vsi; +- } +- +- nss_vp_info->vsi_id = vsi_id; +- nss_vp_info->vsi_id_valid = true; +- nss_vp_info->if_num = if_num; +- nss_vp_info->ppe_port_num = ppe_vp_pvt.ppe_port_num; +- +- nss_info("%px: PPE VP allocated VSI ID:%u NSS interface number:%u VP no from Firmware:%u", nss_ctx, vsi_id, if_num, nss_vp_info->ppe_port_num); +- +- /* +- * Add mapping between the NSS interface number and the VP number. +- */ +- if (!nss_ppe_vp_add_map(nss_ctx, if_num, nss_vp_info)) { +- nss_warning("%px: Failed to add mapping for NSS interface number: %d", nss_ctx, if_num); +- goto free_nss_vp_info; ++ nss_warning("%px: Unable to send ppe_vp config message for type:%d\n", nss_ctx, type); + } + + kfree(npvm); +- + return status; +- +-free_nss_vp_info: +- nss_ppe_vp_map_dealloc(nss_vp_info); +- +-detach_vsi: +- nss_trace("%px: Detaching VSI ID :%u NSS Interface no:%u", nss_ctx, vsi_id, if_num); +- if (nss_if_vsi_unassign(nss_ctx, if_num, vsi_id)) { +- nss_warning("%px: Failed to free PPE VP VSI. nss_if:%u vsi:%u", nss_ctx, if_num, vsi_id); +- } +- +-destroy_vp: +- nss_trace("%px: Destroy Vp for NSS Interface num:%u VP num:%u", nss_ctx, if_num, npvm->msg.if_msg.ppe_port_create.ppe_port_num); +- if (nss_ppe_vp_destroy(nss_ctx, if_num)) { +- nss_warning("%px: PPE VP destroy failed, nss_if:%u", nss_ctx, if_num); +- } +- +-free_alloc: +- kfree(npvm); +- +-free_vsi: +- nss_trace("%px: Free VSI ID :%u NSS Interface no:%u", nss_ctx, vsi_id, if_num); +- if (ppe_vsi_free(NSS_PPE_VP_SWITCH_ID, vsi_id)) { +- nss_warning("%px: Failed to free PPE VP VSI. NSS if num:%u vsi:%u", nss_ctx, if_num, vsi_id); +- } +- +- return NSS_TX_FAILURE; +-} +-EXPORT_SYMBOL(nss_ppe_vp_create); +- +-/* +- * nss_ppe_vp_destroy_notify() +- * Get PPE VP destroy notification from NSS +- */ +-static void nss_ppe_vp_destroy_notify(struct nss_ctx_instance *nss_ctx, struct nss_ppe_vp_destroy_notify_msg *destroy_notify) +-{ +- nss_if_num_t nss_if_num; +- uint32_t i; +- int32_t vsi_id; +- bool vsi_id_valid = false; +- nss_ppe_port_t ppe_port_num = destroy_notify->ppe_port_num; +- +- /* +- * Find NSS interface number corresponding to the VP num. +- */ +- spin_lock_bh(&nss_ppe_vp_map_lock); +- for (i = 0; i < NSS_MAX_DYNAMIC_INTERFACES; i++) { +- if (vp_map[i] && (ppe_port_num == vp_map[i]->ppe_port_num)) { +- nss_if_num = vp_map[i]->if_num; +- vsi_id = vp_map[i]->vsi_id; +- vsi_id_valid = vp_map[i]->vsi_id_valid; +- break; +- } +- } +- spin_unlock_bh(&nss_ppe_vp_map_lock); +- +- if (i == NSS_MAX_DYNAMIC_INTERFACES) { +- nss_warning("%px: Could not find the NSS interface number mapping for VP number: %u\n", nss_ctx, ppe_port_num); +- return; +- } +- +- /* +- * Delete the nss_if_num to VP num mapping and reset the stats entry for this VP. +- */ +- if (!nss_ppe_vp_del_map(nss_ctx, nss_if_num)) { +- nss_warning("%px: Failed to delete the mapping for nss_if: %d\n", nss_ctx, nss_if_num); +- return; +- } +- +- if (vsi_id_valid && ppe_vsi_free(NSS_PPE_VP_SWITCH_ID, vsi_id)) { +- nss_warning("%px: Failed to free PPE VSI. nss_if: %d vsi: %d\n", nss_ctx, nss_if_num, vsi_id); +- } + } + + /* +@@ -624,48 +181,34 @@ static void nss_ppe_vp_handler(struct ns + nss_ppe_vp_msg_callback_t cb; + void *ctx; + +- NSS_VERIFY_CTX_MAGIC(nss_ctx); +- +- nss_trace("%px ppe_vp msg: %px\n", nss_ctx, msg); ++ nss_trace("nss_ctx: %px ppe_vp msg: %px\n", nss_ctx, msg); + BUG_ON(!nss_ppe_vp_verify_ifnum(ncm->interface)); + + /* ++ * Trace messages. ++ */ ++ nss_ppe_vp_log_rx_msg(msg); ++ ++ /* + * Is this a valid request/response packet? + */ + if (ncm->type >= NSS_PPE_VP_MSG_MAX) { +- nss_warning("%px: received invalid message %d for PPE_VP interface", nss_ctx, ncm->type); ++ nss_warning("%px: received invalid message %d for PPE_VP interface\n", nss_ctx, ncm->type); + return; + } + + if (nss_cmn_get_msg_len(ncm) > sizeof(struct nss_ppe_vp_msg)) { +- nss_warning("%px: Length of message is greater than required: %d", nss_ctx, nss_cmn_get_msg_len(ncm)); ++ nss_warning("%px: Length of message is greater than required: %d\n", nss_ctx, nss_cmn_get_msg_len(ncm)); + return; + } + +- /* +- * Trace messages. +- */ +- nss_ppe_vp_log_rx_msg(msg); +- + switch (msg->cm.type) { + case NSS_PPE_VP_MSG_SYNC_STATS: + /* + * Per VP stats msg + */ + nss_ppe_vp_stats_sync(nss_ctx, &msg->msg.stats, ncm->interface); +- break; +- +- case NSS_PPE_VP_MSG_DESTROY_NOTIFY: +- /* +- * VP destroy notification +- */ +- nss_ppe_vp_destroy_notify(nss_ctx, &msg->msg.destroy_notify); +- break; +- } +- +- if (ncm->response == NSS_CMN_RESPONSE_NOTIFY) { +- ncm->cb = (nss_ptr_t)nss_core_get_msg_handler(nss_ctx, ncm->interface); +- ncm->app_data = (nss_ptr_t)nss_ctx->nss_rx_interface_handlers[ncm->interface].app_data; ++ return; + } + + /* +@@ -690,76 +233,83 @@ static void nss_ppe_vp_handler(struct ns + } + + /* +- * nss_ppe_vp_destroy_handler() +- * PPE VP destroy handler. ++ * nss_ppe_vp_proc_help ++ * Print usage information for ppe_vp configure sysctl. + */ +-static int nss_ppe_vp_destroy_handler(struct ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos) ++void nss_ppe_vp_proc_help(void) + { +- struct nss_ctx_instance *nss_ctx = nss_ppe_vp_get_context(); +- int32_t if_num; +- nss_tx_status_t nss_tx_status; ++ printk("== for dynamic interface types read following file ==\n"); ++ printk("/sys/kernel/debug/qca-nss-drv/stats/dynamic_if/type_names\n"); ++} + +- if (!nss_ctx) { +- nss_warning("%px: NSS Context not found.", nss_ctx); +- return -ENODEV; +- } ++/* ++ * nss_ppe_vp_enable_handler ++ * Enable VP support for specfic dynamic interface type. ++ */ ++static int nss_ppe_vp_enable_handler(struct ctl_table *table, int write, void __user *buffer, ++ size_t *lenp, loff_t *ppos) ++{ ++ nss_tx_status_t status; ++ enum nss_dynamic_interface_type type; ++ ++ int ret = proc_dointvec(table, write, buffer, lenp, ppos); ++ if (ret) ++ return ret; + +- NSS_VERIFY_CTX_MAGIC(nss_ctx); ++ nss_info("%s:%d start\n", __func__, __LINE__); + +- if_num = nss_ppe_vp_parse_vp_cmd(ctl, write, buffer, lenp, ppos); +- if (if_num < 0) { +- nss_warning("%px: Invalid interface number: %d", nss_ctx, if_num); +- return -EFAULT; ++ if (!write) { ++ nss_info("print dynamic interface type table\n"); ++ nss_ppe_vp_proc_help(); ++ return ret; + } + +- if (nss_ppe_vp_get_ppe_port_by_nssif(nss_ctx, if_num) < 0) { +- nss_warning("%px: VP is not present for interface: %d", nss_ctx, if_num); +- return -EEXIST; ++ type = nss_ppe_vp_enable; ++ if ((type <= NSS_DYNAMIC_INTERFACE_TYPE_NONE) || (type >= NSS_DYNAMIC_INTERFACE_TYPE_MAX)) { ++ nss_warning("incorrect type: %u", nss_ppe_vp_enable); ++ nss_ppe_vp_proc_help(); ++ return -EINVAL; + } + +- nss_tx_status = nss_ppe_vp_destroy(nss_ctx, if_num); +- if (nss_tx_status != NSS_TX_SUCCESS) { +- nss_warning("%px: Sending message failed, cannot destroy PPE_VP node nss_if: %u", nss_ctx, if_num); +- return -EBUSY; ++ status = nss_ppe_vp_tx_config_msg(type, true); ++ if (status != NSS_TX_SUCCESS) { ++ nss_warning("failed to enable VP support for type: %u", type); ++ return -EINVAL; + } + + return 0; + } + + /* +- * nss_ppe_vp_create_handler() +- * PPE VP create handler. ++ * nss_ppe_vp_disable_handler ++ * Disable VP support for a given dynamic interface type. + */ +-static int nss_ppe_vp_create_handler(struct ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos) ++static int nss_ppe_vp_disable_handler(struct ctl_table *table, int write, void __user *buffer, ++ size_t *lenp, loff_t *ppos) + { +- int32_t if_num; +- struct nss_ctx_instance *nss_ctx = nss_ppe_vp_get_context(); +- nss_tx_status_t nss_tx_status; +- +- if (!nss_ctx) { +- nss_warning("%px: NSS Context not found.", nss_ctx); +- return -ENODEV; +- } ++ nss_tx_status_t status; ++ enum nss_dynamic_interface_type type; + +- NSS_VERIFY_CTX_MAGIC(nss_ctx); ++ int ret = proc_dointvec(table, write, buffer, lenp, ppos); ++ if (ret) ++ return ret; + +- if_num = nss_ppe_vp_parse_vp_cmd(ctl, write, buffer, lenp, ppos); +- if (if_num < 0) { +- nss_warning("%px: Invalid interface number: %d", nss_ctx, if_num); +- return -EFAULT; ++ if (!write) { ++ nss_ppe_vp_proc_help(); ++ return ret; + } + +- nss_info("%px: NSS interface number: %d", nss_ctx, if_num); +- +- if (nss_ppe_vp_get_ppe_port_by_nssif(nss_ctx, if_num) > 0) { +- nss_warning("%px: VP is already present for nss_if_num: %d", nss_ctx, if_num); +- return -EEXIST; ++ type = nss_ppe_vp_disable; ++ if ((type <= NSS_DYNAMIC_INTERFACE_TYPE_NONE) || (type >= NSS_DYNAMIC_INTERFACE_TYPE_MAX)) { ++ nss_warning("incorrect type: %u", nss_ppe_vp_enable); ++ nss_ppe_vp_proc_help(); ++ return -EINVAL; + } + +- nss_tx_status = nss_ppe_vp_create(nss_ctx, if_num); +- if (nss_tx_status != NSS_TX_SUCCESS) { +- nss_warning("%px: Sending message failed, cannot create PPE VP node for nss_if_num: %u", nss_ctx, if_num); +- return -EBUSY; ++ status = nss_ppe_vp_tx_config_msg(type, false); ++ if (status != NSS_TX_SUCCESS) { ++ nss_warning("failed to disable VP support for type: %u", type); ++ return -EINVAL; + } + + return 0; +@@ -767,18 +317,18 @@ static int nss_ppe_vp_create_handler(str + + static struct ctl_table nss_ppe_vp_table[] = { + { +- .procname = "create", +- .data = &nss_ppe_vp_cmd, +- .maxlen = sizeof(nss_ppe_vp_cmd), ++ .procname = "enable", ++ .data = &nss_ppe_vp_enable, ++ .maxlen = sizeof(int), + .mode = 0644, +- .proc_handler = &nss_ppe_vp_create_handler, ++ .proc_handler = &nss_ppe_vp_enable_handler, + }, + { +- .procname = "destroy", +- .data = &nss_ppe_vp_cmd, +- .maxlen = sizeof(nss_ppe_vp_cmd), ++ .procname = "disable", ++ .data = &nss_ppe_vp_disable, ++ .maxlen = sizeof(int), + .mode = 0644, +- .proc_handler = &nss_ppe_vp_destroy_handler, ++ .proc_handler = &nss_ppe_vp_disable_handler, + }, + { } + }; +@@ -839,7 +389,7 @@ void nss_ppe_vp_register_handler(void) + + nss_ppe_vp_dentry = nss_ppe_vp_stats_dentry_create(); + if (nss_ppe_vp_dentry == NULL) { +- nss_warning("%px: Not able to create debugfs entry", nss_ctx); ++ nss_warning("%px: Not able to create debugfs entry\n", nss_ctx); + return; + } + +--- a/nss_ppe_vp.h ++++ b/nss_ppe_vp.h +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above +@@ -30,8 +30,7 @@ + #define NSS_PPE_VP_MAX_NUM 192 + #define NSS_PPE_VP_START 64 + #define NSS_PPE_VP_NODE_STATS_MAX 32 +-#define NSS_PPE_VP_SWITCH_ID 0 +-#define NSS_PPE_VP_MAX_CMD_STR 200 ++ + + /* + * ppe_vp nss debug stats lock +@@ -44,7 +43,7 @@ extern spinlock_t nss_ppe_vp_stats_lock; + */ + enum nss_ppe_vp_msg_error_type { + NSS_PPE_VP_MSG_ERROR_TYPE_UNKNOWN, /* Unknown message error */ +- PPE_VP_MSG_ERROR_TYPE_INVALID_DI, /* Invalid dynamic interface type */ ++ NSS_PPE_VP_MSG_ERROR_TYPE_INVALID_DI, /* Invalid dynamic interface type error */ + NSS_PPE_VP_MSG_ERROR_TYPE_MAX /* Maximum error type */ + }; + +@@ -53,18 +52,27 @@ enum nss_ppe_vp_msg_error_type { + * Message types for Packet Processing Engine (PPE) requests and responses. + */ + enum nss_ppe_vp_message_types { ++ NSS_PPE_VP_MSG_CONFIG, + NSS_PPE_VP_MSG_SYNC_STATS, +- NSS_PPE_VP_MSG_DESTROY_NOTIFY, + NSS_PPE_VP_MSG_MAX, + }; + + /* ++ * nss_ppe_vp_config_msg ++ * Message to enable/disable VP support for a specific dynamic interface type. ++ */ ++struct nss_ppe_vp_config_msg { ++ enum nss_dynamic_interface_type type; /* Interface type */ ++ bool vp_enable; /* VP support enable */ ++}; ++ ++/* + * nss_ppe_vp_statistics + * Message structure for ppe_vp statistics + */ + struct nss_ppe_vp_statistics { + uint32_t nss_if; /* NSS interface number corresponding to VP */ +- nss_ppe_port_t ppe_port_num; /* VP number */ ++ uint32_t vp_num; /* VP number */ + uint32_t rx_drop; /* Rx drops due to VP node inactive */ + uint32_t tx_drop; /* Tx drops due to VP node inactive */ + uint32_t packet_big_err; /* Number of packets not sent to PPE because packet was too large */ +@@ -83,42 +91,21 @@ struct nss_ppe_vp_sync_stats_msg { + }; + + /* +- * nss_ppe_vp_destroy_notify_msg +- * Message received as part of destroy notification from Firmware to Host. +- */ +-struct nss_ppe_vp_destroy_notify_msg { +- nss_ppe_port_t ppe_port_num; /* VP number */ +-}; +- +-/* + * nss_ppe_vp_msg + * Message for receiving ppe_vp NSS to host messages. + */ + struct nss_ppe_vp_msg { +- struct nss_cmn_msg cm; /* Common message header. */ ++ struct nss_cmn_msg cm; /**< Common message header. */ + + /* + * Payload. + */ + union { +- union nss_if_msgs if_msg; +- /* NSS interface base messages. */ ++ struct nss_ppe_vp_config_msg vp_config; ++ /**< Enable/disable VP support for specific type */ + struct nss_ppe_vp_sync_stats_msg stats; +- /* Synchronization statistics. */ +- struct nss_ppe_vp_destroy_notify_msg destroy_notify; +- /* Information for the VP destroyed in Firmware. */ +- } msg; /* Message payload. */ +-}; +- +-/* +- * nss_vp_mapping +- * Structure to maintain the one-to-one mapping between the NSS interface number and VP number. +- */ +-struct nss_vp_mapping { +- nss_if_num_t if_num; /* NSS interface number. */ +- nss_ppe_port_t ppe_port_num; /* PPE port number corresponding to the NSS interface number. */ +- uint32_t vsi_id; /* VSI ID allocated for NSS interface */ +- bool vsi_id_valid; /* Set to true if vsi_id field has a valid VSI else set to false. */ ++ /**< Synchronization statistics. */ ++ } msg; /**< Message payload. */ + }; + + typedef void (*nss_ppe_vp_msg_callback_t)(void *app_data, struct nss_ppe_vp_msg *msg); +--- a/nss_ppe_vp_log.c ++++ b/nss_ppe_vp_log.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above +@@ -25,6 +25,15 @@ + #include "nss_ppe_vp.h" + + /* ++ * nss_ppe_vp_log_message_types_str ++ * PPE message strings ++ */ ++static int8_t *nss_ppe_vp_log_message_types_str[NSS_PPE_VP_MSG_MAX] __maybe_unused = { ++ "PPE VP Config", ++ "PPE VP Stats", ++}; ++ ++/* + * nss_ppe_vp_log_error_response_types_str + * Strings for error types for PPE-VP messages + */ +@@ -34,16 +43,15 @@ static int8_t *nss_ppe_vp_log_error_resp + }; + + /* +- * nss_ppe_vp_log_destroy_notify_msg() +- * Log NSS PPE VP destroy notification message. ++ * nss_ppe_vp_log_config_msg() ++ * Log NSS PPE VP configuration message. + */ +-static void nss_ppe_vp_log_destroy_notify_msg(struct nss_ppe_vp_msg *npvm) ++static void nss_ppe_vp_log_config_msg(struct nss_ppe_vp_msg *npvm) + { +- struct nss_ppe_vp_destroy_notify_msg *npdnm __maybe_unused = &npvm->msg.destroy_notify; +- +- nss_trace("%px: NSS PPE VP destroy notification message:\n" +- "VP number: %u\n", +- npdnm, npdnm->ppe_port_num); ++ struct nss_ppe_vp_config_msg *npcm __maybe_unused = &npvm->msg.vp_config; ++ nss_trace("%px: NSS PPE VP configuration message:\n" ++ "Dynamic interface type: %d is_vp_support_enable: %d\n", ++ npcm, npcm->type, npcm->vp_enable); + } + + /* +@@ -53,25 +61,8 @@ static void nss_ppe_vp_log_destroy_notif + static void nss_ppe_vp_log_verbose(struct nss_ppe_vp_msg *npvm) + { + switch (npvm->cm.type) { +- +- case NSS_IF_PPE_PORT_CREATE: +- nss_info("%px: PPE interface create message type:%d\n", npvm, npvm->cm.type); +- break; +- +- case NSS_IF_PPE_PORT_DESTROY: +- nss_info("%px: PPE interface destroy message type:%d\n", npvm, npvm->cm.type); +- break; +- +- case NSS_IF_VSI_ASSIGN: +- nss_info("%px: PPE interface VSI assign message type:%d\n", npvm, npvm->cm.type); +- break; +- +- case NSS_IF_VSI_UNASSIGN: +- nss_info("%px: PPE interface VSI unassign message type:%d\n", npvm, npvm->cm.type); +- break; +- +- case NSS_PPE_VP_MSG_DESTROY_NOTIFY: +- nss_ppe_vp_log_destroy_notify_msg(npvm); ++ case NSS_PPE_VP_MSG_CONFIG: ++ nss_ppe_vp_log_config_msg(npvm); + break; + + case NSS_PPE_VP_MSG_SYNC_STATS: +@@ -92,13 +83,12 @@ static void nss_ppe_vp_log_verbose(struc + */ + void nss_ppe_vp_log_tx_msg(struct nss_ppe_vp_msg *npvm) + { +- +- if (!((npvm->cm.type == NSS_IF_PPE_PORT_CREATE) || (npvm->cm.type == NSS_IF_PPE_PORT_DESTROY))) { ++ if (npvm->cm.type >= NSS_PPE_VP_MSG_MAX) { + nss_warning("%px: Invalid message type\n", npvm); + return; + } + +- nss_info("%px: type:%d\n", npvm, npvm->cm.type); ++ nss_info("%px: type[%d]:%s\n", npvm, npvm->cm.type, nss_ppe_vp_log_message_types_str[npvm->cm.type]); + nss_ppe_vp_log_verbose(npvm); + } + +@@ -114,20 +104,23 @@ void nss_ppe_vp_log_rx_msg(struct nss_pp + } + + if (npvm->cm.response == NSS_CMN_RESPONSE_NOTIFY || (npvm->cm.response == NSS_CMN_RESPONSE_ACK)) { +- nss_info("%px: type: %d, response[%d]: %s\n", npvm, npvm->cm.type, ++ nss_info("%px: type[%d]:%s, response[%d]:%s\n", npvm, npvm->cm.type, ++ nss_ppe_vp_log_message_types_str[npvm->cm.type], + npvm->cm.response, nss_cmn_response_str[npvm->cm.response]); + goto verbose; + } + + if (npvm->cm.error >= NSS_PPE_VP_MSG_ERROR_TYPE_MAX) { +- nss_warning("%px: msg failure - type: %d, response[%d]: %s, error[%d]:Invalid error\n", +- npvm, npvm->cm.type, npvm->cm.response, nss_cmn_response_str[npvm->cm.response], ++ nss_warning("%px: msg failure - type[%d]:%s, response[%d]:%s, error[%d]:Invalid error\n", ++ npvm, npvm->cm.type, nss_ppe_vp_log_message_types_str[npvm->cm.type], ++ npvm->cm.response, nss_cmn_response_str[npvm->cm.response], + npvm->cm.error); + goto verbose; + } + +- nss_info("%px: msg nack - type: %d, response[%d]: %s, error[%d]: %s\n", +- npvm, npvm->cm.type, npvm->cm.response, nss_cmn_response_str[npvm->cm.response], ++ nss_info("%px: msg nack - type[%d]:%s, response[%d]:%s, error[%d]:%s\n", ++ npvm, npvm->cm.type, nss_ppe_vp_log_message_types_str[npvm->cm.type], ++ npvm->cm.response, nss_cmn_response_str[npvm->cm.response], + npvm->cm.error, nss_ppe_vp_log_error_response_types_str[npvm->cm.error]); + + verbose: +--- a/nss_ppe_vp_stats.c ++++ b/nss_ppe_vp_stats.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above +@@ -69,7 +69,7 @@ struct nss_stats_info nss_ppe_vp_stats_r + * PPE VP statistics strings + */ + struct nss_stats_info nss_ppe_vp_stats_str[NSS_PPE_VP_STATS_MAX] = { +- {"ppe_port_num" , NSS_STATS_TYPE_SPECIAL}, ++ {"vp_num" , NSS_STATS_TYPE_SPECIAL}, + {"nss_if" , NSS_STATS_TYPE_SPECIAL}, + {"rx_packets" , NSS_STATS_TYPE_COMMON}, + {"rx_bytes" , NSS_STATS_TYPE_COMMON}, +@@ -109,10 +109,17 @@ void nss_ppe_vp_stats_sync(struct nss_ct + count--; + + /* ++ * If nss interface is changed from previous entry, reset the stats. ++ */ ++ vp_index = stats_msg->vp_stats[count].vp_num - NSS_PPE_VP_START; ++ if (nss_ppe_vp_debug_stats.vp_stats[vp_index].nss_if != stats_msg->vp_stats[count].nss_if) { ++ memset(&nss_ppe_vp_debug_stats.vp_stats[vp_index], 0, sizeof(struct nss_ppe_vp_statistics_debug)); ++ } ++ ++ /* + * Update stats in global array + */ +- vp_index = stats_msg->vp_stats[count].ppe_port_num - NSS_PPE_VP_START; +- nss_ppe_vp_debug_stats.vp_stats[vp_index].ppe_port_num = stats_msg->vp_stats[count].ppe_port_num; ++ nss_ppe_vp_debug_stats.vp_stats[vp_index].vp_num = stats_msg->vp_stats[count].vp_num; + nss_ppe_vp_debug_stats.vp_stats[vp_index].nss_if = stats_msg->vp_stats[count].nss_if; + nss_ppe_vp_debug_stats.vp_stats[vp_index].rx_packets += stats_msg->vp_stats[count].stats.rx_packets; + nss_ppe_vp_debug_stats.vp_stats[vp_index].rx_bytes += stats_msg->vp_stats[count].stats.rx_bytes; +@@ -125,8 +132,8 @@ void nss_ppe_vp_stats_sync(struct nss_ct + nss_ppe_vp_debug_stats.vp_stats[vp_index].tx_dropped[i] += stats_msg->vp_stats[count].stats.rx_dropped[i]; + } + +- nss_trace("sync count:%d ppe_port_num %d rx_packets %d tx_packets %d\n", +- count, stats_msg->vp_stats[count].ppe_port_num, ++ nss_trace("sync count:%d vp_num %d rx_packets %d tx_packets %d\n", ++ count, stats_msg->vp_stats[count].vp_num, + stats_msg->vp_stats[count].stats.rx_packets, + stats_msg->vp_stats[count].stats.tx_packets); + } +--- a/nss_ppe_vp_stats.h ++++ b/nss_ppe_vp_stats.h +@@ -28,7 +28,7 @@ + * NSS PPE-VP statistics + */ + struct nss_ppe_vp_statistics_debug { +- uint64_t ppe_port_num; /* VP number */ ++ uint64_t vp_num; /* VP number */ + uint64_t nss_if; /* NSS interface number corresponding to VP */ + uint64_t rx_packets; /* Number of packets received. */ + uint64_t rx_bytes; /* Number of bytes received. */ +--- a/nss_pptp.c ++++ b/nss_pptp.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -365,7 +365,7 @@ struct nss_ctx_instance *nss_register_pp + int i = 0; + + nss_assert(nss_ctx); +- nss_assert(nss_pptp_verify_if_num(if_num)); ++ nss_assert(nss_pptp_verify_if_num()); + + nss_ctx->subsys_dp_register[if_num].type = type; + +--- a/nss_project.c ++++ b/nss_project.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2017-2018, 2020-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2017-2018, 2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -21,9 +21,6 @@ + #include "nss_tx_rx_common.h" + + static int nss_project_wt_stats_enable; +-static uint8_t nss_project_pri_mq_map[NSS_PROJECT_PRI_MQ_MAP_MAX_SIZE] = {0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}; +-module_param_array(nss_project_pri_mq_map, byte, NULL, 0); +-MODULE_PARM_DESC(nss_project_pri_mq_map, "Priority to multi-queue mapping"); + + /* + * nss_project_free_wt_stats() +@@ -267,57 +264,6 @@ static int nss_project_wt_stats_handler( + } + + /* +- * nss_project_pri_mq_map_send_cfg() +- * Sends message to firmware to configure priority to multi-queue mapping. +- */ +-static nss_tx_status_t nss_project_pri_mq_map_send_cfg(struct nss_ctx_instance *nss_ctx) +-{ +- struct nss_project_msg *npm; +- struct nss_cmn_msg *ncm; +- nss_tx_status_t ret; +- +- npm = kzalloc(sizeof(*npm), GFP_ATOMIC); +- if (!npm) { +- nss_warning("%px: Failed to allocate buffer for message\n", nss_ctx); +- return NSS_TX_FAILURE; +- } +- +- /* +- * Populate the message +- */ +- ncm = &npm->cm; +- nss_cmn_msg_init(ncm, NSS_PROJECT_INTERFACE, +- NSS_PROJECT_MSG_SET_QUEUE_PRI_MAP_CFG, +- sizeof(struct nss_project_msg_pri_mq_map_cfg), +- NULL, NULL); +- memcpy(npm->msg.pri_mq_map_cfg.pri_mq_map, nss_project_pri_mq_map, +- sizeof(nss_project_pri_mq_map)); +- ret = nss_core_send_cmd(nss_ctx, npm, sizeof(*npm), NSS_NBUF_PAYLOAD_SIZE); +- kfree(npm); +- return ret; +-} +- +-/* +- * nss_project_pri_mq_map_configure() +- * API to configure priority to multi-queue mapping. +- */ +-nss_tx_status_t nss_project_pri_mq_map_configure(struct nss_ctx_instance *nss_ctx) +-{ +- /* +- * Check if multi-queue configuration is enabled. +- */ +- if (!nss_core_is_mq_enabled()) { +- nss_warning("%px: Multi-queue is disabled. Please enable multi-queue before configuring mapping\n", nss_ctx); +- return NSS_TX_FAILURE_NOT_SUPPORTED; +- } +- +- /* +- * Send configuration message to NSS. +- */ +- return nss_project_pri_mq_map_send_cfg(nss_ctx); +-} +- +-/* + * Tree of ctl_tables used to put the wt_stats proc node in the correct place in + * the file system. Allows the command $ echo 1 > proc/sys/dev/nss/project/wt_stats + * to enable worker thread statistics (echoing 0 into the same target will disable). +--- a/nss_pvxlan.c ++++ b/nss_pvxlan.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -80,22 +80,22 @@ static bool nss_pvxlan_hdl_instance_free + { + struct nss_pvxlan_handle *h; + +- spin_lock_bh(&nss_pvxlan_spinlock); ++ spin_lock(&nss_pvxlan_spinlock); + h = nss_pvxlan_hdl[if_num - NSS_DYNAMIC_IF_START]; + if (!h) { +- spin_unlock_bh(&nss_pvxlan_spinlock); ++ spin_unlock(&nss_pvxlan_spinlock); + nss_warning("%px: Instance does not exist: %d", nss_ctx, if_num); + return false; + } + + if (h->if_num != if_num) { +- spin_unlock_bh(&nss_pvxlan_spinlock); ++ spin_unlock(&nss_pvxlan_spinlock); + nss_warning("%px: Not correct if_num: %d", nss_ctx, if_num); + return false; + } + + nss_pvxlan_hdl[if_num - NSS_DYNAMIC_IF_START] = NULL; +- spin_unlock_bh(&nss_pvxlan_spinlock); ++ spin_unlock(&nss_pvxlan_spinlock); + kfree(h); + return true; + } +@@ -119,9 +119,9 @@ static bool nss_pvxlan_hdl_instance_allo + } + h->if_num = if_num; + +- spin_lock_bh(&nss_pvxlan_spinlock); ++ spin_lock(&nss_pvxlan_spinlock); + if (nss_pvxlan_hdl[if_num - NSS_DYNAMIC_IF_START] != NULL) { +- spin_unlock_bh(&nss_pvxlan_spinlock); ++ spin_unlock(&nss_pvxlan_spinlock); + kfree(h); + nss_warning("%px: The handle has been taken by another thread :%d", nss_ctx, if_num); + return false; +@@ -130,7 +130,7 @@ static bool nss_pvxlan_hdl_instance_allo + h->msg_callback = notify_cb; + h->app_data = app_data; + nss_pvxlan_hdl[if_num - NSS_DYNAMIC_IF_START] = h; +- spin_unlock_bh(&nss_pvxlan_spinlock); ++ spin_unlock(&nss_pvxlan_spinlock); + + return true; + } +@@ -201,13 +201,13 @@ static void nss_pvxlan_msg_handler(struc + */ + if (ncm->response == NSS_CMN_RESPONSE_NOTIFY) { + uint32_t if_num = ncm->interface - NSS_DYNAMIC_IF_START; +- spin_lock_bh(&nss_pvxlan_spinlock); ++ spin_lock(&nss_pvxlan_spinlock); + h = nss_pvxlan_hdl[if_num]; + if (h) { + ncm->cb = (nss_ptr_t)h->msg_callback; + ncm->app_data = (nss_ptr_t)h->app_data; + } +- spin_unlock_bh(&nss_pvxlan_spinlock); ++ spin_unlock(&nss_pvxlan_spinlock); + + } + +--- a/nss_qrfs.c ++++ b/nss_qrfs.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. ++ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -415,65 +415,6 @@ nss_tx_status_t nss_qrfs_set_flow_rule(s + EXPORT_SYMBOL(nss_qrfs_set_flow_rule); + + /* +- * nss_qrfs_configure_flow_rule() +- * Configures a QRFS flow rule to NSS firmware +- */ +-nss_tx_status_t nss_qrfs_configure_flow_rule(uint32_t *dst_addr, uint32_t *src_addr, uint16_t dst_port, uint16_t src_port, uint32_t version, uint16_t proto, uint16_t cpu, enum nss_qrfs_msg_types type) { +- +- struct nss_qrfs_msg nqm; +- struct nss_qrfs_flow_rule_msg *nqfrm; +- nss_tx_status_t status; +- struct nss_ctx_instance *nss_ctx = NULL; +- nss_qrfs_msg_callback_t cb = NULL; +- int i; +- +- +- memset(&nqm, 0, sizeof(struct nss_qrfs_msg)); +- nss_qrfs_msg_init(&nqm, NSS_QRFS_INTERFACE, type, +- sizeof(struct nss_qrfs_flow_rule_msg), cb, (void *)nss_ctx); +- if (type == NSS_QRFS_MSG_FLOW_ADD) { +- nqfrm = &nqm.msg.flow_add; +- cb = nss_qrfs_flow_add_msg_callback; +- } else if (type == NSS_QRFS_MSG_FLOW_DELETE) { +- nqfrm = &nqm.msg.flow_delete; +- cb = nss_qrfs_flow_delete_msg_callback; +- } else { +- nss_warning("QRFS configure rule failed, not supported message type.\n"); +- return NSS_TX_FAILURE_BAD_PARAM; +- } +- +- +- nqfrm->protocol = proto; +- nqfrm->ip_version = version; +- +- if (version == 4) { +- nqfrm->src_addr[0] = src_addr[0]; +- nqfrm->dst_addr[0] = dst_addr[0]; +- } else { +- memcpy(nqfrm->src_addr, src_addr, sizeof(uint32_t) * 4); +- memcpy(nqfrm->dst_addr, dst_addr, sizeof(uint32_t) * 4); +- } +- +- nqfrm->src_port = src_port; +- nqfrm->dst_port = dst_port; +- nqfrm->cpu = cpu; +- nqfrm->if_num = 0; +- +- for(i = 0; i < NSS_CORE_MAX; i++) { +- nss_ctx = nss_qrfs_get_ctx(i); +- status = nss_qrfs_tx_msg(nss_ctx, &nqm); +- +- if (status) { +- nss_warning("%px: QRFS configure rule failed, error code: %d\n", nss_ctx, status); +- return NSS_TX_FAILURE; +- } +- } +- +- return NSS_TX_SUCCESS; +-} +-EXPORT_SYMBOL(nss_qrfs_configure_flow_rule); +- +-/* + * nss_qrfs_register_handler() + */ + void nss_qrfs_register_handler(struct nss_ctx_instance *nss_ctx) +--- a/nss_qvpn.c ++++ b/nss_qvpn.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -16,11 +16,9 @@ + + #include "nss_tx_rx_common.h" + #include "nss_qvpn_stats.h" +-#include "nss_qvpn_strings.h" + #include "nss_qvpn_log.h" + + #define NSS_QVPN_TX_TIMEOUT 1000 /* 1 Second */ +-#define NSS_QVPN_INTERFACE_MAX_LONG BITS_TO_LONGS(NSS_MAX_NET_INTERFACES) /**< QVPN interface mapping bits. */ + + /* + * Private data structure +@@ -51,6 +49,36 @@ static bool nss_qvpn_verify_if_num(uint3 + } + + /* ++ * nss_qvpn_tunnel_stats_sync ++ * Update qvpn interface statistics. ++ */ ++static void nss_qvpn_tunnel_stats_sync(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm) ++{ ++ struct nss_qvpn_msg *ndcm = (struct nss_qvpn_msg *)ncm; ++ struct nss_top_instance *nss_top = nss_ctx->nss_top; ++ struct nss_qvpn_stats_sync_msg *msg_stats = &ndcm->msg.stats; ++ uint64_t *if_stats; ++ ++ spin_lock_bh(&nss_top->stats_lock); ++ ++ /* ++ * Update common node stats ++ */ ++ if_stats = nss_top->stats_node[ncm->interface]; ++ if_stats[NSS_STATS_NODE_RX_PKTS] += msg_stats->node_stats.rx_packets; ++ if_stats[NSS_STATS_NODE_RX_BYTES] += msg_stats->node_stats.rx_bytes; ++ if_stats[NSS_STATS_NODE_RX_QUEUE_0_DROPPED] += msg_stats->node_stats.rx_dropped[0]; ++ if_stats[NSS_STATS_NODE_RX_QUEUE_1_DROPPED] += msg_stats->node_stats.rx_dropped[1]; ++ if_stats[NSS_STATS_NODE_RX_QUEUE_2_DROPPED] += msg_stats->node_stats.rx_dropped[2]; ++ if_stats[NSS_STATS_NODE_RX_QUEUE_3_DROPPED] += msg_stats->node_stats.rx_dropped[3]; ++ ++ if_stats[NSS_STATS_NODE_TX_PKTS] += msg_stats->node_stats.tx_packets; ++ if_stats[NSS_STATS_NODE_TX_BYTES] += msg_stats->node_stats.tx_bytes; ++ ++ spin_unlock_bh(&nss_top->stats_lock); ++} ++ ++/* + * nss_qvpn_handler() + * Handle NSS to HLOS messages for QVPN + */ +@@ -86,8 +114,7 @@ static void nss_qvpn_handler(struct nss_ + nss_qvpn_log_rx_msg((struct nss_qvpn_msg *)ncm); + + if (ncm->type == NSS_QVPN_MSG_TYPE_SYNC_STATS) { +- nss_qvpn_stats_tunnel_sync(nss_ctx, ncm); +- nss_qvpn_stats_notify(nss_ctx, ncm->interface); ++ nss_qvpn_tunnel_stats_sync(nss_ctx, ncm); + } + + /* +@@ -96,7 +123,7 @@ static void nss_qvpn_handler(struct nss_ + */ + if (ncm->response == NSS_CMN_RESPONSE_NOTIFY) { + ncm->cb = (nss_ptr_t)nss_core_get_msg_handler(nss_ctx, ncm->interface); +- ncm->app_data = (nss_ptr_t)nss_ctx->nss_rx_interface_handlers[ncm->interface].app_data; ++ ncm->app_data = (nss_ptr_t)nss_ctx->nss_rx_interface_handlers[nss_ctx->id][ncm->interface].app_data; + } + + /* +@@ -340,5 +367,4 @@ void nss_qvpn_register_handler(void) + sema_init(&qvpn_pvt.sem, 1); + init_completion(&qvpn_pvt.complete); + nss_qvpn_stats_dentry_create(); +- nss_qvpn_strings_dentry_create(); + } +--- a/nss_qvpn_stats.c ++++ b/nss_qvpn_stats.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2019, 2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -16,38 +16,6 @@ + + #include "nss_core.h" + #include +-#include "nss_qvpn_stats.h" +-#include "nss_qvpn_strings.h" +- +-/* +- * Declare atomic notifier data structure for statistics. +- */ +-ATOMIC_NOTIFIER_HEAD(nss_qvpn_stats_notifier); +- +-/* +- * Spinlock to protect qvpn statistics update/read +- */ +-DEFINE_SPINLOCK(nss_qvpn_stats_lock); +- +-uint64_t nss_qvpn_stats[NSS_MAX_NET_INTERFACES][NSS_STATS_NODE_MAX]; /* to store the qvpn statistics */ +- +-/* +- * nss_qvpn_stats_iface_type() +- * Return a string for each interface type. +- */ +-static const char *nss_qvpn_stats_iface_type(enum nss_dynamic_interface_type type) +-{ +- switch (type) { +- case NSS_DYNAMIC_INTERFACE_TYPE_QVPN_INNER: +- return "qvpn_inner"; +- +- case NSS_DYNAMIC_INTERFACE_TYPE_QVPN_OUTER: +- return "qvpn_outer"; +- +- default: +- return "invalid_interface"; +- } +-} + + /* + * nss_qvpn_stats_read() +@@ -55,70 +23,51 @@ static const char *nss_qvpn_stats_iface_ + */ + static ssize_t nss_qvpn_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) + { +- /* +- * Max output lines = #stats + +- * few blank lines for banner printing + Number of Extra outputlines +- * for future reference to add new stats +- */ +- uint32_t max_output_lines = NSS_STATS_NODE_MAX + NSS_STATS_EXTRA_OUTPUT_LINES; +- size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines; + struct nss_ctx_instance *nss_ctx = nss_qvpn_get_context(); + enum nss_dynamic_interface_type type; +- unsigned long *ifmap; +- uint64_t *stats_shadow; + ssize_t bytes_read = 0; +- size_t size_wr = 0; ++ size_t len = 0, size; + uint32_t if_num; +- int32_t i; +- int count; +- char *lbuf; ++ unsigned long *ifmap; ++ char *buf; + + ifmap = nss_qvpn_ifmap_get(); +- count = bitmap_weight(ifmap, NSS_MAX_NET_INTERFACES); +- if (count) { +- size_al = size_al * count; +- } ++ size = NSS_QVPN_STATS_SIZE_PER_IF * bitmap_weight(ifmap, NSS_MAX_NET_INTERFACES); + +- lbuf = vzalloc(size_al); +- if (unlikely(!lbuf)) { +- nss_warning("Could not allocate memory for local statistics buffer"); +- return -ENOMEM; +- } +- +- stats_shadow = vzalloc(NSS_STATS_NODE_MAX * 8); +- if (unlikely(!stats_shadow)) { +- nss_warning("Could not allocate memory for local shadow buffer"); +- vfree(lbuf); +- return -ENOMEM; ++ buf = kzalloc(size, GFP_KERNEL); ++ if (!buf) { ++ nss_warning("Could not allocate memory for local statistics buffer\n"); ++ return 0; + } + + /* + * Common node stats for each QVPN dynamic interface. + */ +- size_wr += nss_stats_banner(lbuf, size_wr, size_al, "qvpn stats", NSS_STATS_SINGLE_CORE); ++ len += nss_stats_banner(buf, len, size, "qvpn", NSS_STATS_SINGLE_CORE); + for_each_set_bit(if_num, ifmap, NSS_MAX_NET_INTERFACES) { +- + type = nss_dynamic_interface_get_type(nss_ctx, if_num); +- if ((type != NSS_DYNAMIC_INTERFACE_TYPE_QVPN_INNER) && +- (type != NSS_DYNAMIC_INTERFACE_TYPE_QVPN_OUTER)) { +- continue; +- } + +- spin_lock_bh(&nss_qvpn_stats_lock); +- for (i = 0; i < NSS_STATS_NODE_MAX; i++) { +- stats_shadow[i] = nss_qvpn_stats[if_num][i]; ++ switch (type) { ++ case NSS_DYNAMIC_INTERFACE_TYPE_QVPN_INNER: ++ len += scnprintf(buf + len, size - len, "\nInner if_num:%03u", if_num); ++ break; ++ ++ case NSS_DYNAMIC_INTERFACE_TYPE_QVPN_OUTER: ++ len += scnprintf(buf + len, size - len, "\nOuter if_num:%03u", if_num); ++ break; ++ ++ default: ++ len += scnprintf(buf + len, size - len, "\nUnknown(%d) if_num:%03u", type, if_num); ++ break; + } +- spin_unlock_bh(&nss_qvpn_stats_lock); + +- size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\n%s if_num:%03u\n", +- nss_qvpn_stats_iface_type(type), if_num); +- size_wr += nss_stats_print("qvpn", NULL, NSS_STATS_SINGLE_INSTANCE, nss_qvpn_strings_stats, +- stats_shadow, NSS_STATS_NODE_MAX, lbuf, size_wr, size_al); ++ len += scnprintf(buf + len, size - len, "\n-------------------\n"); ++ len += nss_stats_fill_common_stats(if_num, NSS_STATS_SINGLE_INSTANCE, buf, len, size - len, "qvpn"); + } + +- bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf)); +- vfree(lbuf); +- vfree(stats_shadow); ++ bytes_read = simple_read_from_buffer(ubuf, sz, ppos, buf, len); ++ kfree(buf); ++ + return bytes_read; + } + +@@ -128,72 +77,6 @@ static ssize_t nss_qvpn_stats_read(struc + NSS_STATS_DECLARE_FILE_OPERATIONS(qvpn) + + /* +- * nss_qvpn_stats_tunnel_sync +- * Update qvpn interface statistics. +- */ +-void nss_qvpn_stats_tunnel_sync(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm) +-{ +- struct nss_qvpn_msg *ndcm = (struct nss_qvpn_msg *)ncm; +- struct nss_qvpn_stats_sync_msg *msg_stats = &ndcm->msg.stats; +- +- spin_lock_bh(&nss_qvpn_stats_lock); +- +- /* +- * Update common node stats +- */ +- nss_qvpn_stats[ncm->interface][NSS_STATS_NODE_RX_PKTS] += msg_stats->node_stats.rx_packets; +- nss_qvpn_stats[ncm->interface][NSS_STATS_NODE_RX_BYTES] += msg_stats->node_stats.rx_bytes; +- nss_qvpn_stats[ncm->interface][NSS_STATS_NODE_RX_QUEUE_0_DROPPED] += msg_stats->node_stats.rx_dropped[0]; +- nss_qvpn_stats[ncm->interface][NSS_STATS_NODE_RX_QUEUE_1_DROPPED] += msg_stats->node_stats.rx_dropped[1]; +- nss_qvpn_stats[ncm->interface][NSS_STATS_NODE_RX_QUEUE_2_DROPPED] += msg_stats->node_stats.rx_dropped[2]; +- nss_qvpn_stats[ncm->interface][NSS_STATS_NODE_RX_QUEUE_3_DROPPED] += msg_stats->node_stats.rx_dropped[3]; +- +- nss_qvpn_stats[ncm->interface][NSS_STATS_NODE_TX_PKTS] += msg_stats->node_stats.tx_packets; +- nss_qvpn_stats[ncm->interface][NSS_STATS_NODE_TX_BYTES] += msg_stats->node_stats.tx_bytes; +- +- spin_unlock_bh(&nss_qvpn_stats_lock); +-} +- +-/* +- * nss_qvpn_stats_notify() +- * Sends notifications to all the registered modules. +- * +- * Leverage NSS-FW statistics timing to update Netlink. +- */ +-void nss_qvpn_stats_notify(struct nss_ctx_instance *nss_ctx, uint32_t if_num) +-{ +- struct nss_qvpn_stats_notification qvpn_stats; +- +- spin_lock_bh(&nss_qvpn_stats_lock); +- qvpn_stats.core_id = nss_ctx->id; +- qvpn_stats.if_num = if_num; +- memcpy(qvpn_stats.stats_ctx, nss_qvpn_stats[if_num], sizeof(qvpn_stats.stats_ctx)); +- spin_unlock_bh(&nss_qvpn_stats_lock); +- +- atomic_notifier_call_chain(&nss_qvpn_stats_notifier, NSS_STATS_EVENT_NOTIFY, &qvpn_stats); +-} +- +-/* +- * nss_qvpn_stats_unregister_notifier() +- * Deregisters statistics notifier. +- */ +-int nss_qvpn_stats_unregister_notifier(struct notifier_block *nb) +-{ +- return atomic_notifier_chain_unregister(&nss_qvpn_stats_notifier, nb); +-} +-EXPORT_SYMBOL(nss_qvpn_stats_unregister_notifier); +- +-/* +- * nss_qvpn_stats_register_notifier() +- * Registers statistics notifier. +- */ +-int nss_qvpn_stats_register_notifier(struct notifier_block *nb) +-{ +- return atomic_notifier_chain_register(&nss_qvpn_stats_notifier, nb); +-} +-EXPORT_SYMBOL(nss_qvpn_stats_register_notifier); +- +-/* + * nss_qvpn_stats_dentry_create() + * Create QVPN statistics debug entry. + */ +--- a/nss_qvpn_stats.h ++++ b/nss_qvpn_stats.h +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2019, 2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -17,8 +17,10 @@ + #ifndef _NSS_QVPN_STATS_H_ + #define _NSS_QVPN_STATS_H_ + +-extern void nss_qvpn_stats_notify(struct nss_ctx_instance *nss_ctx, uint32_t if_num); +-extern void nss_qvpn_stats_tunnel_sync(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm); +-extern void nss_qvpn_stats_dentry_create(void); ++/* ++ * nss_qvpn_stats_dentry_create ++ * Creates QVPN interface statistics debug entry. ++ */ ++void nss_qvpn_stats_dentry_create(void); + + #endif /* _NSS_QVPN_STATS_H_ */ +--- a/nss_qvpn_strings.c ++++ /dev/null +@@ -1,60 +0,0 @@ +-/* +- ***************************************************************************** +- * Copyright (c) 2021, The Linux Foundation. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- ***************************************************************************** +- */ +- +-#include "nss_stats.h" +-#include "nss_core.h" +-#include "nss_strings.h" +-#include "nss_qvpn_strings.h" +- +-/* +- * nss_qvpn_strings_stats +- * qvpn statistics strings. +- */ +-struct nss_stats_info nss_qvpn_strings_stats[NSS_STATS_NODE_MAX] = { +- {"rx_pkts", NSS_STATS_TYPE_COMMON}, +- {"rx_byts", NSS_STATS_TYPE_COMMON}, +- {"tx_pkts", NSS_STATS_TYPE_COMMON}, +- {"tx_byts", NSS_STATS_TYPE_COMMON}, +- {"rx_queue[0]_drops", NSS_STATS_TYPE_DROP}, +- {"rx_queue[1]_drops", NSS_STATS_TYPE_DROP}, +- {"rx_queue[2]_drops", NSS_STATS_TYPE_DROP}, +- {"rx_queue[3]_drops", NSS_STATS_TYPE_DROP} +-}; +- +-/* +- * nss_qvpn_strings_read() +- * Read qvpn statistics names +- */ +-static ssize_t nss_qvpn_strings_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- return nss_strings_print(ubuf, sz, ppos, nss_qvpn_strings_stats, NSS_STATS_NODE_MAX); +-} +- +-/* +- * nss_qvpn_strings_ops +- */ +-NSS_STRINGS_DECLARE_FILE_OPERATIONS(qvpn); +- +-/* +- * nss_qvpn_strings_dentry_create() +- * Create qvpn statistics strings debug entry. +- */ +-void nss_qvpn_strings_dentry_create(void) +-{ +- nss_strings_create_dentry("qvpn", &nss_qvpn_strings_ops); +-} +--- a/nss_qvpn_strings.h ++++ /dev/null +@@ -1,27 +0,0 @@ +-/* +- **************************************************************************** +- * Copyright (c) 2021, The Linux Foundation. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- **************************************************************************** +- */ +- +-#ifndef __NSS_QVPN_STRINGS_H +-#define __NSS_QVPN_STRINGS_H +- +-#include "nss_qvpn_stats.h" +- +-extern struct nss_stats_info nss_qvpn_strings_stats[NSS_STATS_NODE_MAX]; +-extern void nss_qvpn_strings_dentry_create(void); +- +-#endif /* __NSS_QVPN_STRINGS_H */ +--- a/nss_rmnet_rx.c ++++ b/nss_rmnet_rx.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above +@@ -29,7 +29,7 @@ + #define NSS_RMNET_RX_GET_INDEX(if_num) (if_num - NSS_DYNAMIC_IF_START) + + /* +- * Spinlock to protect the global data structure rmnet handle. ++ * Spinlock to protect the global data structure virt_handle. + */ + DEFINE_SPINLOCK(nss_rmnet_rx_lock); + +@@ -243,8 +243,6 @@ static int nss_rmnet_rx_handle_destroy_s + rmnet_rx_handle[index_h2n] = NULL; + spin_unlock_bh(&nss_rmnet_rx_lock); + +- kfree(handle->stats_h2n); +- kfree(handle->stats_n2h); + kfree(handle->pvt); + kfree(handle); + +@@ -527,27 +525,6 @@ error1: + EXPORT_SYMBOL(nss_rmnet_rx_create_sync_nexthop); + + /* +- * nss_rmnet_rx_create() +- * Create rmnet_n2h and rmnet_h2n interfaces with generic next hops and associate it with same netdev. +- * +- * When rmnet and eth_rx is running at the same core, we directly send packets to eth_rx node. +- * When they are running at different cores, the packets needs to arrive eth_rx through C2C. +- */ +-struct nss_rmnet_rx_handle *nss_rmnet_rx_create(struct net_device *netdev) +-{ +- uint32_t nexthop_n2h = NSS_N2H_INTERFACE; +- uint32_t nexthop_h2n = NSS_C2C_TX_INTERFACE; +- +- if (nss_top_main.rmnet_rx_handler_id == 0) { +- nexthop_h2n = NSS_ETH_RX_INTERFACE; +- } +- +- +- return nss_rmnet_rx_create_sync_nexthop(netdev, nexthop_n2h, nexthop_h2n); +-} +-EXPORT_SYMBOL(nss_rmnet_rx_create); +- +-/* + * nss_rmnet_rx_tx_buf() + * HLOS interface has received a packet which we redirect to the NSS, if appropriate to do so. + */ +--- a/nss_rps.c ++++ b/nss_rps.c +@@ -1,12 +1,9 @@ + /* + ************************************************************************** +- * Copyright (c) 2013-2017, 2019-2021 The Linux Foundation. All rights reserved. +- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. +- * ++ * Copyright (c) 2013-2017, 2019-2020 The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +- * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +@@ -281,7 +278,6 @@ static nss_tx_status_t nss_rps_cfg(struc + return NSS_SUCCESS; + } + +-#ifdef NSS_DRV_IPV4_ENABLE + /* + * nss_rps_ipv4_hash_bitmap_cfg() + * Send Message to NSS to configure hash_bitmap. +@@ -310,9 +306,7 @@ static nss_tx_status_t nss_rps_ipv4_hash + up(&nss_rps_cfg_pvt.sem); + return NSS_SUCCESS; + } +-#endif + +-#ifdef NSS_DRV_IPV6_ENABLE + /* + * nss_rps_ipv6_hash_bitmap_cfg() + * Send Message to NSS to configure hash_bitmap. +@@ -341,7 +335,6 @@ static nss_tx_status_t nss_rps_ipv6_hash + up(&nss_rps_cfg_pvt.sem); + return NSS_SUCCESS; + } +-#endif + + /* + * nss_rps_pri_map_cfg() +@@ -461,8 +454,8 @@ static int nss_rps_hash_bitmap_cfg_handl + void __user *buffer, size_t *lenp, loff_t *ppos) + { + struct nss_top_instance *nss_top = &nss_top_main; +- struct nss_ctx_instance *nss_ctx __attribute__((unused)) = &nss_top->nss[0]; +- int ret, current_state; ++ struct nss_ctx_instance *nss_ctx = &nss_top->nss[0]; ++ int ret, ret_ipv4, ret_ipv6, current_state; + + current_state = nss_rps_hash_bitmap; + ret = proc_dointvec(ctl, write, buffer, lenp, ppos); +@@ -476,45 +469,32 @@ static int nss_rps_hash_bitmap_cfg_handl + return ret; + } + +-#if !defined(NSS_DRV_IPV4_ENABLE) || !defined(NSS_DRV_IPV6_ENABLE) +- nss_info_always("%px: Feature is not supported\n", nss_ctx); +- return 0; +-#else + if (nss_rps_hash_bitmap <= (NSS_RPS_MAX_CORE_HASH_BITMAP)) { + nss_info("Configuring NSS RPS hash_bitmap\n"); +-#ifdef NSS_DRV_IPV4_ENABLE +- { +- int ret_ipv4; +- ret_ipv4 = nss_rps_ipv4_hash_bitmap_cfg(nss_ctx, nss_rps_hash_bitmap); +- +- if (ret_ipv4 != NSS_SUCCESS) { +- nss_warning("%px: ipv4 hash_bitmap config message failed\n", nss_ctx); +- nss_rps_hash_bitmap = current_state; +- return ret_ipv4; +- } ++ ret_ipv4 = nss_rps_ipv4_hash_bitmap_cfg(nss_ctx, nss_rps_hash_bitmap); ++ ++ if (ret_ipv4 != NSS_SUCCESS) { ++ nss_warning("%px: ipv4 hash_bitmap config message failed\n", nss_ctx); ++ nss_rps_hash_bitmap = current_state; ++ return ret_ipv4; + } +-#endif +-#ifdef NSS_DRV_IPV6_ENABLE +- { +- int ret_ipv6; +- ret_ipv6 = nss_rps_ipv6_hash_bitmap_cfg(nss_ctx, nss_rps_hash_bitmap); +- +- if (ret_ipv6 != NSS_SUCCESS) { +- nss_warning("%px: ipv6 hash_bitmap config message failed\n", nss_ctx); +- nss_rps_hash_bitmap = current_state; +- if (nss_rps_ipv4_hash_bitmap_cfg(nss_ctx, nss_rps_hash_bitmap != NSS_SUCCESS)) { +- nss_warning("%px: ipv4 and ipv6 have different hash_bitmaps.\n", nss_ctx); +- } +- return ret_ipv6; ++ ++ ret_ipv6 = nss_rps_ipv6_hash_bitmap_cfg(nss_ctx, nss_rps_hash_bitmap); ++ ++ if (ret_ipv6 != NSS_SUCCESS) { ++ nss_warning("%px: ipv6 hash_bitmap config message failed\n", nss_ctx); ++ nss_rps_hash_bitmap = current_state; ++ if (nss_rps_ipv4_hash_bitmap_cfg(nss_ctx, nss_rps_hash_bitmap != NSS_SUCCESS)) { ++ nss_warning("%px: ipv4 and ipv6 have different hash_bitmaps.\n", nss_ctx); + } ++ return ret_ipv6; + } +-#endif ++ + return 0; + } + + nss_info_always("Invalid input value. Valid values are less than %d\n", (NSS_RPS_MAX_CORE_HASH_BITMAP)); + return ret; +-#endif + } + + /* nss_rps_pri_map_cfg_handler() +--- a/nss_stats.c ++++ b/nss_stats.c +@@ -1,12 +1,9 @@ + /* + ************************************************************************** + * Copyright (c) 2013-2020, The Linux Foundation. All rights reserved. +- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. +- * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +- * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +@@ -392,9 +389,7 @@ void nss_stats_create_dentry(char *name, + /* + * gmac_stats_ops + */ +-#ifdef NSS_DATA_PLANE_GENERIC_SUPPORT + NSS_STATS_DECLARE_FILE_OPERATIONS(gmac); +-#endif + + /* + * wt_stats_ops +@@ -449,9 +444,7 @@ void nss_stats_init(void) + /* + * gmac_stats + */ +-#ifdef NSS_DATA_PLANE_GENERIC_SUPPORT + nss_stats_create_dentry("gmac", &nss_gmac_stats_ops); +-#endif + + /* + * Per-project stats +--- a/nss_tls.c ++++ b/nss_tls.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above +@@ -18,10 +18,10 @@ + + #include "nss_tx_rx_common.h" + #include "nss_tls_log.h" +-#include "nss_tls_stats.h" +-#include "nss_tls_strings.h" + + #define NSS_TLS_INTERFACE_MAX_LONG BITS_TO_LONGS(NSS_MAX_NET_INTERFACES) ++#define NSS_TLS_STATS_MAX_LINES (NSS_STATS_NODE_MAX + 32) ++#define NSS_TLS_STATS_SIZE_PER_IF (NSS_STATS_MAX_STR_LENGTH * NSS_TLS_STATS_MAX_LINES) + #define NSS_TLS_TX_TIMEOUT 3000 /* 3 Seconds */ + + /* +@@ -35,6 +35,93 @@ static struct nss_tls_pvt { + } tls_pvt; + + /* ++ * nss_tls_stats_sync() ++ * Update tls node statistics. ++ */ ++static void nss_tls_stats_sync(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm) ++{ ++ struct nss_tls_msg *ndcm = (struct nss_tls_msg *)ncm; ++ struct nss_top_instance *nss_top = nss_ctx->nss_top; ++ struct nss_tls_ctx_stats *msg_stats = &ndcm->msg.stats; ++ uint64_t *if_stats; ++ int i; ++ ++ spin_lock_bh(&nss_top->stats_lock); ++ ++ /* ++ * Update common node stats, ++ * Note: TLS only supports a single queue for RX ++ */ ++ if_stats = nss_top->stats_node[ncm->interface]; ++ if_stats[NSS_STATS_NODE_RX_PKTS] += msg_stats->pkt.rx_packets; ++ if_stats[NSS_STATS_NODE_RX_BYTES] += msg_stats->pkt.rx_bytes; ++ ++ for (i = 0; i < NSS_MAX_NUM_PRI; i++) ++ if_stats[NSS_STATS_NODE_RX_QUEUE_0_DROPPED + i] += msg_stats->pkt.rx_dropped[i]; ++ ++ if_stats[NSS_STATS_NODE_TX_PKTS] += msg_stats->pkt.tx_packets; ++ if_stats[NSS_STATS_NODE_TX_BYTES] += msg_stats->pkt.tx_bytes; ++ ++ spin_unlock_bh(&nss_top->stats_lock); ++} ++ ++/* ++ * nss_tls_stats_read() ++ * Read tls node statiistics. ++ */ ++static ssize_t nss_tls_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) ++{ ++ struct nss_ctx_instance *nss_ctx = nss_tls_get_context(); ++ enum nss_dynamic_interface_type type; ++ ssize_t bytes_read = 0; ++ size_t len = 0, size; ++ uint32_t if_num; ++ char *buf; ++ ++ size = NSS_TLS_STATS_SIZE_PER_IF * bitmap_weight(tls_pvt.if_map, NSS_MAX_NET_INTERFACES); ++ ++ buf = kzalloc(size, GFP_KERNEL); ++ if (!buf) { ++ nss_warning("Could not allocate memory for local statistics buffer"); ++ return 0; ++ } ++ ++ /* ++ * Common node stats for each TLS dynamic interface. ++ */ ++ for_each_set_bit(if_num, tls_pvt.if_map, NSS_MAX_NET_INTERFACES) { ++ type = nss_dynamic_interface_get_type(nss_ctx, if_num); ++ ++ switch (type) { ++ case NSS_DYNAMIC_INTERFACE_TYPE_TLS_INNER: ++ len += scnprintf(buf + len, size - len, "\nInner if_num:%03u", if_num); ++ break; ++ ++ case NSS_DYNAMIC_INTERFACE_TYPE_TLS_OUTER: ++ len += scnprintf(buf + len, size - len, "\nOuter if_num:%03u", if_num); ++ break; ++ ++ default: ++ len += scnprintf(buf + len, size - len, "\nUnknown(%d) if_num:%03u", type, if_num); ++ break; ++ } ++ ++ len += scnprintf(buf + len, size - len, "\n-------------------\n"); ++ len = nss_stats_fill_common_stats(if_num, NSS_STATS_SINGLE_INSTANCE, buf, len, size - len, "tls"); ++ } ++ ++ bytes_read = simple_read_from_buffer(ubuf, sz, ppos, buf, len); ++ kfree(buf); ++ ++ return bytes_read; ++} ++ ++/* ++ * nss_tls_stats_ops ++ */ ++NSS_STATS_DECLARE_FILE_OPERATIONS(tls) ++ ++/* + * nss_tls_verify_ifnum() + * Verify if the interface number is a TLS interface. + */ +@@ -80,17 +167,15 @@ static void nss_tls_handler(struct nss_c + return; + } + +- if (ncm->type == NSS_TLS_MSG_TYPE_CTX_SYNC) { ++ if (ncm->type == NSS_TLS_MSG_TYPE_CTX_SYNC) + nss_tls_stats_sync(nss_ctx, ncm); +- nss_tls_stats_notify(nss_ctx, ncm->interface); +- } + + /* + * Update the callback and app_data for NOTIFY messages + */ + if (ncm->response == NSS_CMN_RESPONSE_NOTIFY) { + ncm->cb = (nss_ptr_t)nss_core_get_msg_handler(nss_ctx, ncm->interface); +- ncm->app_data = (nss_ptr_t)nss_ctx->nss_rx_interface_handlers[ncm->interface].app_data; ++ ncm->app_data = (nss_ptr_t)nss_ctx->nss_rx_interface_handlers[nss_ctx->id][ncm->interface].app_data; + } + + /* +@@ -144,15 +229,6 @@ static void nss_tls_sync_resp(void *app_ + } + + /* +- * nss_tls_ifmap_get() +- * Return TLS active interfaces map. +- */ +-unsigned long *nss_tls_ifmap_get(void) +-{ +- return tls_pvt.if_map; +-} +- +-/* + * nss_tls_tx_buf() + * Transmit buffer over TLS interface + */ +@@ -470,6 +546,5 @@ void nss_tls_register_handler(void) + { + sema_init(&tls_pvt.sem, 1); + init_completion(&tls_pvt.complete); +- nss_tls_stats_dentry_create(); +- nss_tls_strings_dentry_create(); ++ nss_stats_create_dentry("tls", &nss_tls_stats_ops); + } +--- a/nss_tls_stats.c ++++ /dev/null +@@ -1,206 +0,0 @@ +-/* +- ****************************************************************************** +- * Copyright (c) 2021, The Linux Foundation. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- ****************************************************************************** +- */ +- +-#include "nss_core.h" +-#include "nss_tls.h" +-#include "nss_tls_stats.h" +-#include "nss_tls_strings.h" +- +-/* +- * Declare atomic notifier data structure for statistics. +- */ +-ATOMIC_NOTIFIER_HEAD(nss_tls_stats_notifier); +- +-/* +- * Spinlock to protect tls statistics update/read +- */ +-DEFINE_SPINLOCK(nss_tls_stats_lock); +- +-uint64_t nss_tls_stats[NSS_MAX_NET_INTERFACES][NSS_TLS_STATS_MAX]; +- +-/* +- * nss_tls_stats_iface_type() +- * Return a string for each interface type. +- */ +-static const char *nss_tls_stats_iface_type(enum nss_dynamic_interface_type type) +-{ +- switch (type) { +- case NSS_DYNAMIC_INTERFACE_TYPE_TLS_INNER: +- return "tls_inner"; +- +- case NSS_DYNAMIC_INTERFACE_TYPE_TLS_OUTER: +- return "tls_outer"; +- +- default: +- return "invalid_interface"; +- } +-} +- +-/* +- * nss_tls_stats_read() +- * Read tls node statiistics. +- */ +-static ssize_t nss_tls_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- /* +- * Max output lines = #stats + +- * few blank lines for banner printing + Number of Extra outputlines +- * for future reference to add new stats +- */ +- uint32_t max_output_lines = NSS_TLS_STATS_MAX + NSS_STATS_EXTRA_OUTPUT_LINES; +- size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines; +- struct nss_ctx_instance *nss_ctx = nss_tls_get_context(); +- enum nss_dynamic_interface_type type; +- unsigned long *ifmap; +- uint64_t *stats_shadow; +- ssize_t bytes_read = 0; +- size_t size_wr = 0; +- uint32_t if_num; +- int32_t i; +- int count; +- char *lbuf; +- +- ifmap = nss_tls_ifmap_get(); +- count = bitmap_weight(ifmap, NSS_MAX_NET_INTERFACES); +- if (count) { +- size_al = size_al * count; +- } +- +- lbuf = vzalloc(size_al); +- if (unlikely(!lbuf)) { +- nss_warning("Could not allocate memory for local statistics buffer"); +- return -ENOMEM; +- } +- +- stats_shadow = vzalloc(NSS_TLS_STATS_MAX * 8); +- if (unlikely(!stats_shadow)) { +- nss_warning("Could not allocate memory for local shadow buffer"); +- vfree(lbuf); +- return -ENOMEM; +- } +- +- /* +- * Common node stats for each TLS dynamic interface. +- */ +- size_wr += nss_stats_banner(lbuf, size_wr, size_al, "tls stats", NSS_STATS_SINGLE_CORE); +- for_each_set_bit(if_num, ifmap, NSS_MAX_NET_INTERFACES) { +- +- type = nss_dynamic_interface_get_type(nss_ctx, if_num); +- if ((type != NSS_DYNAMIC_INTERFACE_TYPE_TLS_INNER) && +- (type != NSS_DYNAMIC_INTERFACE_TYPE_TLS_OUTER)) { +- continue; +- } +- +- spin_lock_bh(&nss_tls_stats_lock); +- for (i = 0; i < NSS_TLS_STATS_MAX; i++) { +- stats_shadow[i] = nss_tls_stats[if_num][i]; +- } +- spin_unlock_bh(&nss_tls_stats_lock); +- +- size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\n%s if_num:%03u\n", +- nss_tls_stats_iface_type(type), if_num); +- size_wr += nss_stats_print("tls", NULL, NSS_STATS_SINGLE_INSTANCE, nss_tls_strings_stats, +- stats_shadow, NSS_TLS_STATS_MAX, lbuf, size_wr, size_al); +- } +- +- bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf)); +- vfree(lbuf); +- vfree(stats_shadow); +- return bytes_read; +-} +- +-/* +- * nss_tls_stats_ops +- */ +-NSS_STATS_DECLARE_FILE_OPERATIONS(tls); +- +-/* +- * nss_tls_stats_dentry_create() +- * Create tls statistics debug entry. +- */ +-void nss_tls_stats_dentry_create(void) +-{ +- nss_stats_create_dentry("tls", &nss_tls_stats_ops); +-} +- +-/* +- * nss_tls_stats_sync() +- * Update tls node statistics. +- */ +-void nss_tls_stats_sync(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm) +-{ +- struct nss_tls_msg *ndcm = (struct nss_tls_msg *)ncm; +- struct nss_tls_ctx_stats *ndccs = &ndcm->msg.stats; +- uint64_t *ctx_stats; +- uint32_t *msg_stats; +- int i; +- +- spin_lock_bh(&nss_tls_stats_lock); +- +- /* +- * Update common node stats, +- * Note: TLS only supports a single queue for RX +- */ +- msg_stats = (uint32_t *)ndccs; +- ctx_stats = nss_tls_stats[ncm->interface]; +- +- for (i = 0; i < NSS_TLS_STATS_MAX; i++, ctx_stats++, msg_stats++) { +- *ctx_stats += *msg_stats; +- } +- +- spin_unlock_bh(&nss_tls_stats_lock); +-} +- +-/* +- * nss_tls_stats_notify() +- * Sends notifications to all the registered modules. +- * +- * Leverage NSS-FW statistics timing to update Netlink. +- */ +-void nss_tls_stats_notify(struct nss_ctx_instance *nss_ctx, uint32_t if_num) +-{ +- struct nss_tls_stats_notification tls_stats; +- +- spin_lock_bh(&nss_tls_stats_lock); +- tls_stats.core_id = nss_ctx->id; +- tls_stats.if_num = if_num; +- memcpy(tls_stats.stats_ctx, nss_tls_stats[if_num], sizeof(tls_stats.stats_ctx)); +- spin_unlock_bh(&nss_tls_stats_lock); +- +- atomic_notifier_call_chain(&nss_tls_stats_notifier, NSS_STATS_EVENT_NOTIFY, &tls_stats); +-} +- +-/* +- * nss_tls_stats_unregister_notifier() +- * Deregisters statistics notifier. +- */ +-int nss_tls_stats_unregister_notifier(struct notifier_block *nb) +-{ +- return atomic_notifier_chain_unregister(&nss_tls_stats_notifier, nb); +-} +-EXPORT_SYMBOL(nss_tls_stats_unregister_notifier); +- +-/* +- * nss_tls_stats_register_notifier() +- * Registers statistics notifier. +- */ +-int nss_tls_stats_register_notifier(struct notifier_block *nb) +-{ +- return atomic_notifier_chain_register(&nss_tls_stats_notifier, nb); +-} +-EXPORT_SYMBOL(nss_tls_stats_register_notifier); +--- a/nss_tls_stats.h ++++ /dev/null +@@ -1,28 +0,0 @@ +-/* +- ****************************************************************************** +- * Copyright (c) 2021, The Linux Foundation. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- ****************************************************************************** +- */ +- +-#ifndef __NSS_TLS_STATS_H +-#define __NSS_TLS_STATS_H +- +-#include +- +-extern void nss_tls_stats_notify(struct nss_ctx_instance *nss_ctx, uint32_t if_num); +-extern void nss_tls_stats_sync(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm); +-extern void nss_tls_stats_dentry_create(void); +- +-#endif /* __NSS_TLS_STATS_H */ +--- a/nss_tls_strings.c ++++ /dev/null +@@ -1,88 +0,0 @@ +-/* +- ****************************************************************************** +- * Copyright (c) 2021, The Linux Foundation. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- ****************************************************************************** +- */ +- +-#include "nss_stats.h" +-#include "nss_core.h" +-#include "nss_strings.h" +-#include "nss_tls_strings.h" +- +-/* +- * nss_tls_strings_stats +- * tls statistics strings. +- */ +-struct nss_stats_info nss_tls_strings_stats[NSS_TLS_STATS_MAX] = { +- {"rx_pkts", NSS_STATS_TYPE_COMMON}, +- {"rx_byts", NSS_STATS_TYPE_COMMON}, +- {"tx_pkts", NSS_STATS_TYPE_COMMON}, +- {"tx_byts", NSS_STATS_TYPE_COMMON}, +- {"rx_queue[0]_drops", NSS_STATS_TYPE_DROP}, +- {"rx_queue[1]_drops", NSS_STATS_TYPE_DROP}, +- {"rx_queue[2]_drops", NSS_STATS_TYPE_DROP}, +- {"rx_queue[3]_drops", NSS_STATS_TYPE_DROP}, +- {"single_rec", NSS_STATS_TYPE_SPECIAL}, +- {"multi_rec", NSS_STATS_TYPE_SPECIAL}, +- {"tx_inval_reqs", NSS_STATS_TYPE_SPECIAL}, +- {"rx_ccs_rec", NSS_STATS_TYPE_SPECIAL}, +- {"fail_ccs", NSS_STATS_TYPE_ERROR}, +- {"eth_node_deactive", NSS_STATS_TYPE_SPECIAL}, +- {"crypto_alloc_success", NSS_STATS_TYPE_SPECIAL}, +- {"crypto_free_req", NSS_STATS_TYPE_SPECIAL}, +- {"crypto_free_success", NSS_STATS_TYPE_SPECIAL}, +- {"fail_crypto_alloc", NSS_STATS_TYPE_EXCEPTION}, +- {"fail_crypto_lookup", NSS_STATS_TYPE_EXCEPTION}, +- {"fail_req_alloc", NSS_STATS_TYPE_ERROR}, +- {"fail_pbuf_stats", NSS_STATS_TYPE_ERROR}, +- {"fail_ctx_active", NSS_STATS_TYPE_ERROR}, +- {"hw_len_error", NSS_STATS_TYPE_ERROR}, +- {"hw_token_error", NSS_STATS_TYPE_ERROR}, +- {"hw_bypass_error", NSS_STATS_TYPE_ERROR}, +- {"hw_crypto_error", NSS_STATS_TYPE_ERROR}, +- {"hw_hash_error", NSS_STATS_TYPE_ERROR}, +- {"hw_config_error", NSS_STATS_TYPE_ERROR}, +- {"hw_algo_error", NSS_STATS_TYPE_ERROR}, +- {"hw_hash_ovf_error", NSS_STATS_TYPE_ERROR}, +- {"hw_auth_error", NSS_STATS_TYPE_ERROR}, +- {"hw_pad_verify_error", NSS_STATS_TYPE_ERROR}, +- {"hw_timeout_error", NSS_STATS_TYPE_ERROR}, +- {"no_desc_in", NSS_STATS_TYPE_EXCEPTION}, +- {"no_desc_out", NSS_STATS_TYPE_EXCEPTION}, +- {"no_reqs", NSS_STATS_TYPE_EXCEPTION} +-}; +- +-/* +- * nss_tls_strings_read() +- * Read tls statistics names +- */ +-static ssize_t nss_tls_strings_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- return nss_strings_print(ubuf, sz, ppos, nss_tls_strings_stats, NSS_TLS_STATS_MAX); +-} +- +-/* +- * nss_tls_strings_ops +- */ +-NSS_STRINGS_DECLARE_FILE_OPERATIONS(tls); +- +-/* +- * nss_tls_strings_dentry_create() +- * Create tls statistics strings debug entry. +- */ +-void nss_tls_strings_dentry_create(void) +-{ +- nss_strings_create_dentry("tls", &nss_tls_strings_ops); +-} +--- a/nss_trustsec_rx.c ++++ /dev/null +@@ -1,214 +0,0 @@ +-/* +- * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for any +- * purpose with or without fee is hereby granted, provided that the above +- * copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- */ +-#include "nss_tx_rx_common.h" +-#include "nss_trustsec_rx_stats.h" +-#include "nss_trustsec_rx_log.h" +- +-#define NSS_TRUSTSEC_RX_TIMEOUT 3000 /* 3 Seconds */ +- +-/* +- * Private data structure for trustsec_rx interface +- */ +-static struct nss_trustsec_rx_pvt { +- struct semaphore sem; +- struct completion complete; +- int response; +-} ttx; +- +-/* +- * nss_trustsec_rx_handler() +- * Handle NSS -> HLOS messages for trustsec_rx +- */ +-static void nss_trustsec_rx_handler(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm, +- __attribute__((unused))void *app_data) +-{ +- nss_trustsec_rx_msg_callback_t cb; +- struct nss_trustsec_rx_msg *msg = (struct nss_trustsec_rx_msg *)ncm; +- +- BUG_ON(ncm->interface != NSS_TRUSTSEC_RX_INTERFACE); +- +- /* +- * Trace messages. +- */ +- nss_trustsec_rx_log_rx_msg(msg); +- +- /* +- * Is this a valid request/response packet? +- */ +- if (ncm->type >= NSS_TRUSTSEC_RX_MSG_MAX) { +- nss_warning("%px: received invalid message %d for trustsec_rx interface", nss_ctx, ncm->type); +- return; +- } +- +- if (nss_cmn_get_msg_len(ncm) > sizeof(struct nss_trustsec_rx_msg)) { +- nss_warning("%px: message size incorrect: %d", nss_ctx, nss_cmn_get_msg_len(ncm)); +- return; +- } +- +- /* +- * Log failures +- */ +- nss_core_log_msg_failures(nss_ctx, ncm); +- +- switch (ncm->type) { +- case NSS_TRUSTSEC_RX_MSG_STATS_SYNC: +- /* +- * Update trustsec_rx statistics. +- */ +- nss_trustsec_rx_stats_sync(nss_ctx, &msg->msg.stats_sync); +- break; +- } +- +- /* +- * Update the callback and app_data for NOTIFY messages, trustsec_rx sends all notify messages +- * to the same callback/app_data. +- */ +- if (ncm->response == NSS_CMN_RESPONSE_NOTIFY) { +- ncm->cb = (nss_ptr_t)nss_core_get_msg_handler(nss_ctx, ncm->interface); +- ncm->app_data = (nss_ptr_t)nss_ctx->subsys_dp_register[ncm->interface].ndev; +- } +- +- /* +- * Do we have a call back +- */ +- if (!ncm->cb) { +- return; +- } +- +- /* +- * callback +- */ +- cb = (nss_trustsec_rx_msg_callback_t)ncm->cb; +- +- cb((void *)ncm->app_data, msg); +-} +- +-/* +- * nss_trustsec_rx_msg() +- * Transmit a trustsec_rx message to NSSFW +- */ +-static nss_tx_status_t nss_trustsec_rx_msg(struct nss_ctx_instance *nss_ctx, struct nss_trustsec_rx_msg *msg) +-{ +- struct nss_cmn_msg *ncm = &msg->cm; +- +- /* +- * Trace messages. +- */ +- nss_trustsec_rx_log_tx_msg(msg); +- +- /* +- * Sanity check the message +- */ +- if (ncm->interface != NSS_TRUSTSEC_RX_INTERFACE) { +- nss_warning("%px: tx request for another interface: %d", nss_ctx, ncm->interface); +- return NSS_TX_FAILURE; +- } +- +- if (ncm->type > NSS_TRUSTSEC_RX_MSG_MAX) { +- nss_warning("%px: message type out of range: %d", nss_ctx, ncm->type); +- return NSS_TX_FAILURE; +- } +- +- return nss_core_send_cmd(nss_ctx, msg, sizeof(*msg), NSS_NBUF_PAYLOAD_SIZE); +-} +- +-/* +- * nss_trustsec_rx_callback +- * Callback to handle the completion of NSS ->HLOS messages. +- */ +-static void nss_trustsec_rx_callback(void *app_data, struct nss_trustsec_rx_msg *msg) +-{ +- if (msg->cm.response != NSS_CMN_RESPONSE_ACK) { +- nss_warning("trustsec_rx error response %d\n", msg->cm.response); +- ttx.response = NSS_TX_FAILURE; +- complete(&ttx.complete); +- return; +- } +- +- ttx.response = NSS_TX_SUCCESS; +- complete(&ttx.complete); +-} +- +-/* +- * nss_trustsec_rx_msg_sync() +- * Send a message to trustsec_rx interface & wait for the response. +- */ +-nss_tx_status_t nss_trustsec_rx_msg_sync(struct nss_ctx_instance *nss_ctx, struct nss_trustsec_rx_msg *msg) +-{ +- nss_tx_status_t status; +- int ret = 0; +- +- down(&ttx.sem); +- +- msg->cm.cb = (nss_ptr_t)nss_trustsec_rx_callback; +- msg->cm.app_data = (nss_ptr_t)NULL; +- +- status = nss_trustsec_rx_msg(nss_ctx, msg); +- if (status != NSS_TX_SUCCESS) { +- nss_warning("%px: nss_trustsec_rx_msg failed\n", nss_ctx); +- up(&ttx.sem); +- return status; +- } +- +- ret = wait_for_completion_timeout(&ttx.complete, msecs_to_jiffies(NSS_TRUSTSEC_RX_TIMEOUT)); +- if (!ret) { +- nss_warning("%px: trustsec_rx tx failed due to timeout\n", nss_ctx); +- ttx.response = NSS_TX_FAILURE; +- } +- +- status = ttx.response; +- up(&ttx.sem); +- +- return status; +-} +-EXPORT_SYMBOL(nss_trustsec_rx_msg_sync); +- +-/* +- * nss_trustsec_rx_get_ctx() +- * Return a TrustSec TX NSS context. +- */ +-struct nss_ctx_instance *nss_trustsec_rx_get_ctx() +-{ +- return &nss_top_main.nss[nss_top_main.trustsec_rx_handler_id]; +-} +-EXPORT_SYMBOL(nss_trustsec_rx_get_ctx); +- +-/* +- * nss_trustsec_rx_msg_init() +- * Initialize trustsec_rx message. +- */ +-void nss_trustsec_rx_msg_init(struct nss_trustsec_rx_msg *msg, uint16_t if_num, uint32_t type, uint32_t len, +- nss_trustsec_rx_msg_callback_t cb, void *app_data) +-{ +- nss_cmn_msg_init(&msg->cm, if_num, type, len, (void *)cb, app_data); +-} +-EXPORT_SYMBOL(nss_trustsec_rx_msg_init); +- +-/* +- * nss_trustsec_rx_register_handler() +- * Registering handler for sending msg to trustsec_rx node on NSS. +- */ +-void nss_trustsec_rx_register_handler(void) +-{ +- struct nss_ctx_instance *nss_ctx = nss_trustsec_rx_get_ctx(); +- +- nss_core_register_handler(nss_ctx, NSS_TRUSTSEC_RX_INTERFACE, nss_trustsec_rx_handler, NULL); +- +- nss_trustsec_rx_stats_dentry_create(); +- +- sema_init(&ttx.sem, 1); +- init_completion(&ttx.complete); +-} +--- a/nss_trustsec_rx_log.c ++++ /dev/null +@@ -1,220 +0,0 @@ +-/* +- * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for any +- * purpose with or without fee is hereby granted, provided that the above +- * copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- */ +- +-/* +- * nss_trustsec_rx_log.c +- * NSS TRUSTSEC_RX logger file. +- */ +- +-#include "nss_core.h" +- +-/* +- * nss_trustsec_rx_log_message_types_str +- * TRUSTSEC_RX message strings +- */ +-static int8_t *nss_trustsec_rx_log_message_types_str[NSS_TRUSTSEC_RX_MSG_MAX] __maybe_unused = { +- "TRUSTSEC_RX Configure Message", +- "TRUSTSEC_RX Unconfigure Message", +- "TRUSTSEC_RX Stats Sync", +- "TRUSTSEC_RX Config vp num Message", +- "TRUSTSEC_RX Unconfig vp num Message", +-}; +- +-/* +- * nss_trustsec_rx_log_error_response_types_str +- * Strings for error types for TRUSTSEC_RX messages +- */ +-static int8_t *nss_trustsec_rx_log_error_response_types_str[NSS_TRUSTSEC_RX_ERR_MAX] __maybe_unused = { +- "TRUSTSEC_RX No error", +- "TRUSTSEC_RX Destination interface is not found", +- "TRUSTSEC_RX IP version is incorrect", +- "TRUSTSEC_RX Entry already exist", +- "TRUSTSEC_RX IP rule cannot be added", +- "TRUSTSEC_RX Entry cannot be found", +- "TRUSTSEC_RX source interface is not configured", +- "TRUSTSEC_RX Unknown trustsec message", +- "TRUSTSEC_RX configure vp number failed", +- "TRUSTSEC_RX unconfigure vp number failed", +-}; +- +-/* +- * nss_trustsec_rx_log_config_vp_msg +- * Log NSS TrustSec Rx configure vp message +- */ +-static void nss_trustsec_rx_log_config_vp_msg(struct nss_trustsec_rx_msg *ntm) +-{ +- struct nss_trustsec_rx_vp_msg *vpm __maybe_unused = &ntm->msg.cfg; +- nss_trace("%px: NSS trustsec_rx message: Configure VP\n" +- "VP number: %u\n", +- vpm, +- vpm->num); +-} +- +-/* +- * nss_trustsec_rx_log_unconfig_vp_msg +- * Log NSS TrustSec Rx uncfg vp message +- */ +-static void nss_trustsec_rx_log_unconfig_vp_msg(struct nss_trustsec_rx_msg *ntm) +-{ +- struct nss_trustsec_rx_vp_msg *vpm __maybe_unused = &ntm->msg.uncfg; +- nss_trace("%px: NSS trustsec_rx message: Unconfigure VP\n" +- "VP number: %u\n", +- vpm, +- vpm->num); +-} +- +-/* +- * nss_trustsec_rx_log_configure_msg() +- * Log NSS TRUSTSEC_RX configure message. +- */ +-static void nss_trustsec_rx_log_configure_msg(struct nss_trustsec_rx_msg *ntm) +-{ +- struct nss_trustsec_rx_configure_msg *cfg __maybe_unused = &ntm->msg.configure; +- nss_trace("%px: NSS trustsec_rx message: Config\n" +- "IP version: %u\n", +- cfg, +- cfg->ip_version); +- +- if (cfg->ip_version == NSS_TRUSTSEC_RX_FLAG_IPV4) { +- nss_trace("Src IP: %pI4\n" +- "Dest IP: %pI4\n", +- &(cfg->src_ip.ip.ipv4), +- &(cfg->dest_ip.ip.ipv4)); +- } else { +- nss_trace("Src IP: %pI6\n" +- "Dest IP: %pI6\n", +- &(cfg->src_ip.ip.ipv6), +- &(cfg->dest_ip.ip.ipv6)); +- } +- +- nss_trace("Src Port: %u\n Dest Port: %u\n\n", +- cfg->src_port, cfg->dest_port); +- nss_trace("%px: Destination interface number: %u", cfg, cfg->dest); +-} +- +-/* +- * nss_trustsec_rx_log_unconfigure_msg() +- * Log NSS TRUSTSEC_RX unconfigure message. +- */ +-static void nss_trustsec_rx_log_unconfigure_msg(struct nss_trustsec_rx_msg *ntm) +-{ +- struct nss_trustsec_rx_unconfigure_msg *uncfg __maybe_unused = &ntm->msg.unconfigure; +- nss_trace("%px: NSS trustsec_rx message: Unconfig\n" +- "IP version: %u\n", +- uncfg, +- uncfg->ip_version); +- +- if (uncfg->ip_version == NSS_TRUSTSEC_RX_FLAG_IPV4) { +- nss_trace("Src IP: %pI4\n" +- "Dest IP: %pI4\n", +- &(uncfg->src_ip.ip.ipv4), +- &(uncfg->dest_ip.ip.ipv4)); +- } else { +- nss_trace("Src IP: %pI6\n" +- "Dest IP: %pI6\n", +- &(uncfg->src_ip.ip.ipv6), +- &(uncfg->dest_ip.ip.ipv6)); +- } +- +- nss_trace("Src Port: %u\n Dest Port: %u\n\n", +- uncfg->src_port, uncfg->dest_port); +- nss_trace("%px: Destination interface number: %u", uncfg, uncfg->dest); +-} +- +-/* +- * nss_trustsec_rx_log_verbose() +- * Log message contents. +- */ +-static void nss_trustsec_rx_log_verbose(struct nss_trustsec_rx_msg *ntm) +-{ +- switch (ntm->cm.type) { +- case NSS_TRUSTSEC_RX_MSG_CONFIGURE: +- nss_trustsec_rx_log_configure_msg(ntm); +- break; +- +- case NSS_TRUSTSEC_RX_MSG_UNCONFIGURE: +- nss_trustsec_rx_log_unconfigure_msg(ntm); +- break; +- +- case NSS_TRUSTSEC_RX_MSG_STATS_SYNC: +- /* +- * No log for valid stats message. +- */ +- break; +- +- case NSS_TRUSTSEC_RX_MSG_CONFIG_VP: +- nss_trustsec_rx_log_config_vp_msg(ntm); +- break; +- +- case NSS_TRUSTSEC_RX_MSG_UNCONFIG_VP: +- nss_trustsec_rx_log_unconfig_vp_msg(ntm); +- break; +- +- default: +- nss_warning("%px: Invalid message type\n", ntm); +- break; +- } +-} +- +-/* +- * nss_trustsec_rx_log_tx_msg() +- * Log messages transmitted to FW. +- */ +-void nss_trustsec_rx_log_tx_msg(struct nss_trustsec_rx_msg *ntm) +-{ +- if (ntm->cm.type >= NSS_TRUSTSEC_RX_MSG_MAX) { +- nss_warning("%px: Invalid message type\n", ntm); +- return; +- } +- +- nss_info("%px: type[%d]:%s\n", ntm, ntm->cm.type, nss_trustsec_rx_log_message_types_str[ntm->cm.type]); +- nss_trustsec_rx_log_verbose(ntm); +-} +- +-/* +- * nss_trustsec_rx_log_rx_msg() +- * Log messages received from FW. +- */ +-void nss_trustsec_rx_log_rx_msg(struct nss_trustsec_rx_msg *ntm) +-{ +- if (ntm->cm.response >= NSS_CMN_RESPONSE_LAST) { +- nss_warning("%px: Invalid response\n", ntm); +- return; +- } +- +- if (ntm->cm.response == NSS_CMN_RESPONSE_NOTIFY || (ntm->cm.response == NSS_CMN_RESPONSE_ACK)) { +- nss_info("%px: type[%d]:%s, response[%d]:%s\n", ntm, ntm->cm.type, +- nss_trustsec_rx_log_message_types_str[ntm->cm.type], +- ntm->cm.response, nss_cmn_response_str[ntm->cm.response]); +- goto verbose; +- } +- +- if (ntm->cm.error >= NSS_TRUSTSEC_RX_ERR_UNKNOWN) { +- nss_warning("%px: msg failure - type[%d]:%s, response[%d]:%s, error[%d]:Invalid error\n", +- ntm, ntm->cm.type, nss_trustsec_rx_log_message_types_str[ntm->cm.type], +- ntm->cm.response, nss_cmn_response_str[ntm->cm.response], +- ntm->cm.error); +- goto verbose; +- } +- +- nss_info("%px: msg nack - type[%d]:%s, response[%d]:%s, error[%d]:%s\n", +- ntm, ntm->cm.type, nss_trustsec_rx_log_message_types_str[ntm->cm.type], +- ntm->cm.response, nss_cmn_response_str[ntm->cm.response], +- ntm->cm.error, nss_trustsec_rx_log_error_response_types_str[ntm->cm.error]); +- +-verbose: +- nss_trustsec_rx_log_verbose(ntm); +-} +--- a/nss_trustsec_rx_log.h ++++ /dev/null +@@ -1,37 +0,0 @@ +-/* +- * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for any +- * purpose with or without fee is hereby granted, provided that the above +- * copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- */ +- +-#ifndef __NSS_TRUSTSEC_RX_LOG_H__ +-#define __NSS_TRUSTSEC_RX_LOG_H__ +- +-/* +- * nss_trustsec_rx_log.h +- * NSS TRUSTSEC_RX Log Header File +- */ +- +-/* +- * nss_trustsec_rx_log_tx_msg +- * Logs a trustsec_rx message that is sent to the NSS firmware. +- */ +-void nss_trustsec_rx_log_tx_msg(struct nss_trustsec_rx_msg *msg); +- +-/* +- * nss_trustsec_rx_log_rx_msg +- * Logs a trustsec_rx message that is received from the NSS firmware. +- */ +-void nss_trustsec_rx_log_rx_msg(struct nss_trustsec_rx_msg *msg); +- +-#endif /* __NSS_TRUSTSEC_RX_LOG_H__ */ +--- a/nss_trustsec_rx_stats.c ++++ /dev/null +@@ -1,148 +0,0 @@ +-/* +- * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for any +- * purpose with or without fee is hereby granted, provided that the above +- * copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- */ +-#include "nss_tx_rx_common.h" +-#include "nss_trustsec_rx_stats.h" +- +-/* +- * nss_trustsec_rx_stats_str +- * Trustsec TX statistics strings. +- */ +- +-struct nss_stats_info nss_trustsec_rx_stats_str[NSS_TRUSTSEC_RX_STATS_MAX] = { +- {"Unknown ethernet type", NSS_STATS_TYPE_ERROR}, +- {"Unknown packet" , NSS_STATS_TYPE_ERROR}, +- {"Unknown destination" , NSS_STATS_TYPE_ERROR}, +- {"IP parse failed" , NSS_STATS_TYPE_ERROR}, +- {"Wrong L4 type" , NSS_STATS_TYPE_ERROR}, +-}; +- +-/* +- * trustsec_rx_stats +- * Trustsec RX statistics. +- */ +-uint64_t trustsec_rx_stats[NSS_TRUSTSEC_RX_STATS_MAX]; +- +-/* +- * Trustsec RX statistics APIs +- */ +- +-/* +- * nss_trustsec_rx_stats_sync() +- * Update trustsec_rx node statistics. +- */ +-void nss_trustsec_rx_stats_sync(struct nss_ctx_instance *nss_ctx, struct nss_trustsec_rx_stats_sync_msg *ntsm) +-{ +- struct nss_top_instance *nss_top = nss_ctx->nss_top; +- int j; +- +- spin_lock_bh(&nss_top->stats_lock); +- +- /* +- * Update common node stats +- */ +- nss_top->stats_node[NSS_TRUSTSEC_RX_INTERFACE][NSS_STATS_NODE_RX_PKTS] += ntsm->node_stats.rx_packets; +- nss_top->stats_node[NSS_TRUSTSEC_RX_INTERFACE][NSS_STATS_NODE_RX_BYTES] += ntsm->node_stats.rx_bytes; +- nss_top->stats_node[NSS_TRUSTSEC_RX_INTERFACE][NSS_STATS_NODE_TX_PKTS] += ntsm->node_stats.tx_packets; +- nss_top->stats_node[NSS_TRUSTSEC_RX_INTERFACE][NSS_STATS_NODE_TX_BYTES] += ntsm->node_stats.tx_bytes; +- +- for (j = 0; j < NSS_MAX_NUM_PRI; j++) { +- nss_top->stats_node[NSS_TRUSTSEC_RX_INTERFACE][NSS_STATS_NODE_RX_QUEUE_0_DROPPED + j] += ntsm->node_stats.rx_dropped[j]; +- } +- +- /* +- * Update trustsec node stats +- */ +- trustsec_rx_stats[NSS_TRUSTSEC_RX_STATS_UNKNOWN_ETH_TYPE] += ntsm->unknown_eth_type; +- trustsec_rx_stats[NSS_TRUSTSEC_RX_STATS_UNKNOWN_PKT] += ntsm->unknown_pkt; +- trustsec_rx_stats[NSS_TRUSTSEC_RX_STATS_UNKNOWN_DEST] += ntsm->unknown_dest; +- trustsec_rx_stats[NSS_TRUSTSEC_RX_STATS_IP_PARSE_FAILED] += ntsm->ip_parse_failed; +- trustsec_rx_stats[NSS_TRUSTSEC_RX_STATS_WRONG_L4_TYPE] += ntsm->wrong_l4_type; +- +- spin_unlock_bh(&nss_top->stats_lock); +-} +- +-/* +- * nss_trustsec_rx_stats_read() +- * Read trustsec_rx statiistics. +- */ +-static ssize_t nss_trustsec_rx_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- int32_t i; +- +- /* +- * Max output lines = #stats + few blank lines for banner printing + +- * Number of Extra outputlines for future reference to add new stats. +- */ +- uint32_t max_output_lines = NSS_STATS_NODE_MAX + NSS_TRUSTSEC_RX_STATS_MAX + NSS_STATS_EXTRA_OUTPUT_LINES; +- size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines; +- size_t size_wr = 0; +- ssize_t bytes_read = 0; +- uint64_t *stats_shadow; +- +- char *lbuf = kzalloc(size_al, GFP_KERNEL); +- if (unlikely(lbuf == NULL)) { +- nss_warning("Could not allocate memory for local statistics buffer"); +- return 0; +- } +- +- stats_shadow = kzalloc(NSS_STATS_NODE_MAX * 8, GFP_KERNEL); +- if (unlikely(stats_shadow == NULL)) { +- nss_warning("Could not allocate memory for local shadow buffer"); +- kfree(lbuf); +- return 0; +- } +- +- size_wr += nss_stats_banner(lbuf, size_wr, size_al, "trustsec_rx", NSS_STATS_SINGLE_CORE); +- +- /* +- * Common node stats +- */ +- size_wr += nss_stats_fill_common_stats(NSS_TRUSTSEC_RX_INTERFACE, NSS_STATS_SINGLE_INSTANCE, lbuf, size_wr, size_al, "trustsec_rx"); +- +- /* +- * TrustSec TX node stats +- */ +- spin_lock_bh(&nss_top_main.stats_lock); +- for (i = 0; (i < NSS_TRUSTSEC_RX_STATS_MAX); i++) { +- stats_shadow[i] = trustsec_rx_stats[i]; +- } +- +- spin_unlock_bh(&nss_top_main.stats_lock); +- size_wr += nss_stats_print("trustsec_rx", NULL, NSS_STATS_SINGLE_INSTANCE +- , nss_trustsec_rx_stats_str +- , stats_shadow +- , NSS_TRUSTSEC_RX_STATS_MAX +- , lbuf, size_wr, size_al); +- bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf)); +- kfree(lbuf); +- kfree(stats_shadow); +- +- return bytes_read; +-} +- +-/* +- * nss_trustsec_rx_stats_ops +- */ +-NSS_STATS_DECLARE_FILE_OPERATIONS(trustsec_rx) +- +-/* +- * nss_trustsec_rx_stats_dentry_create() +- * Create trustsec_rx statistics debug entry. +- */ +-void nss_trustsec_rx_stats_dentry_create(void) +-{ +- nss_stats_create_dentry("trustsec_rx", &nss_trustsec_rx_stats_ops); +-} +--- a/nss_trustsec_rx_stats.h ++++ /dev/null +@@ -1,47 +0,0 @@ +-/* +- * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for any +- * purpose with or without fee is hereby granted, provided that the above +- * copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- */ +-/* +- * nss_trustsec_rx_stats.h +- * NSS TRUSTSEC RX statistics header file. +- */ +- +-#ifndef __NSS_TRUSTSEC_RX_STATS_H +-#define __NSS_TRUSTSEC_RX_STATS_H +- +-/* +- * Trustsec TX statistics +- */ +-enum nss_trustsec_rx_stats { +- NSS_TRUSTSEC_RX_STATS_UNKNOWN_ETH_TYPE, +- /* Number of packets with unknown ethernet type */ +- NSS_TRUSTSEC_RX_STATS_UNKNOWN_PKT, +- /* Number of packets with unknown IP packet*/ +- NSS_TRUSTSEC_RX_STATS_UNKNOWN_DEST, +- /* Number of packets with unknown destination */ +- NSS_TRUSTSEC_RX_STATS_IP_PARSE_FAILED, +- /* Number of packets with IP parse failed */ +- NSS_TRUSTSEC_RX_STATS_WRONG_L4_TYPE, +- /* Number of packets with wrong L4 type */ +- NSS_TRUSTSEC_RX_STATS_MAX +-}; +- +-/* +- * Trustsec TX statistics APIs +- */ +-extern void nss_trustsec_rx_stats_sync(struct nss_ctx_instance *nss_ctx, struct nss_trustsec_rx_stats_sync_msg *ntsm); +-extern void nss_trustsec_rx_stats_dentry_create(void); +- +-#endif /* __NSS_TRUSTSEC_RX_STATS_H */ +--- a/nss_tunipip6.c ++++ b/nss_tunipip6.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2014-2018, 2020, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -16,20 +16,6 @@ + + #include "nss_tx_rx_common.h" + #include "nss_tunipip6_log.h" +-#include "nss_tunipip6_stats.h" +- +-#define NSS_TUNIPIP6_TX_TIMEOUT 3000 +- +-/* +- * Data structure used to handle sync message. +- */ +-static struct nss_tunipip6_pvt { +- struct semaphore sem; /* Semaphore structure. */ +- struct completion complete; /* Completion structure. */ +- int response; /* Response from FW. */ +- void *cb; /* Original cb for msgs. */ +- void *app_data; /* Original app_data for msgs. */ +-} tunipip6_pvt; + + /* + * nss_tunipip6_verify_if_num +@@ -71,24 +57,15 @@ static void nss_tunipip6_handler(struct + * Is this a valid request/response packet? + */ + if (ncm->type >= NSS_TUNIPIP6_MAX) { +- nss_warning("%px: received invalid message %d for DS-Lite interface", nss_ctx, ncm->type); ++ nss_warning("%p: received invalid message %d for DS-Lite interface", nss_ctx, ncm->type); + return; + } + + if (nss_cmn_get_msg_len(ncm) > sizeof(struct nss_tunipip6_msg)) { +- nss_warning("%px: Length of message is greater than required: %d", nss_ctx, nss_cmn_get_msg_len(ncm)); ++ nss_warning("%p: Length of message is greater than required: %d", nss_ctx, nss_cmn_get_msg_len(ncm)); + return; + } + +- switch (ntm->cm.type) { +- case NSS_TUNIPIP6_STATS_SYNC: +- /* +- * Sync common node stats. +- */ +- nss_tunipip6_stats_sync(nss_ctx, ntm); +- break; +- } +- + /* + * Update the callback and app_data for NOTIFY messages, tunipip6 sends all notify messages + * to the same callback/app_data. +@@ -119,7 +96,7 @@ static void nss_tunipip6_handler(struct + * call ipip6 tunnel callback + */ + if (!ctx) { +- nss_warning("%px: Event received for DS-Lite tunnel interface %d before registration", nss_ctx, ncm->interface); ++ nss_warning("%p: Event received for DS-Lite tunnel interface %d before registration", nss_ctx, ncm->interface); + return; + } + +@@ -143,12 +120,12 @@ nss_tx_status_t nss_tunipip6_tx(struct n + * Sanity check the message + */ + if (!nss_tunipip6_verify_if_num(ncm->interface)) { +- nss_warning("%px: tx request for another interface: %d", nss_ctx, ncm->interface); ++ nss_warning("%p: tx request for another interface: %d", nss_ctx, ncm->interface); + return NSS_TX_FAILURE; + } + + if (ncm->type > NSS_TUNIPIP6_MAX) { +- nss_warning("%px: message type out of range: %d", nss_ctx, ncm->type); ++ nss_warning("%p: message type out of range: %d", nss_ctx, ncm->type); + return NSS_TX_FAILURE; + } + +@@ -157,60 +134,6 @@ nss_tx_status_t nss_tunipip6_tx(struct n + EXPORT_SYMBOL(nss_tunipip6_tx); + + /* +- * nss_tunipip6_callback() +- * Callback to handle the completion of NSS->HLOS messages. +- */ +-static void nss_tunipip6_callback(void *app_data, struct nss_tunipip6_msg *nclm) +-{ +- tunipip6_pvt.response = NSS_TX_SUCCESS; +- tunipip6_pvt.cb = NULL; +- tunipip6_pvt.app_data = NULL; +- +- if (nclm->cm.response != NSS_CMN_RESPONSE_ACK) { +- nss_warning("%px: tunipip6 Error response %d Error: %d\n", app_data, nclm->cm.response, nclm->cm.error); +- tunipip6_pvt.response = nclm->cm.response; +- } +- +- /* +- * Write memory barrier. +- */ +- smp_wmb(); +- complete(&tunipip6_pvt.complete); +-} +- +-/* +- * nss_tunipip6_tx_sync() +- * Transmit a tunipip6 message to NSSFW synchronously. +- */ +-nss_tx_status_t nss_tunipip6_tx_sync(struct nss_ctx_instance *nss_ctx, struct nss_tunipip6_msg *msg) +-{ +- nss_tx_status_t status; +- int ret; +- +- down(&tunipip6_pvt.sem); +- msg->cm.cb = (nss_ptr_t)nss_tunipip6_callback; +- msg->cm.app_data = (nss_ptr_t)NULL; +- +- status = nss_tunipip6_tx(nss_ctx, msg); +- if (status != NSS_TX_SUCCESS) { +- nss_warning("%px: tunipip6_tx_msg failed\n", nss_ctx); +- up(&tunipip6_pvt.sem); +- return status; +- } +- +- ret = wait_for_completion_timeout(&tunipip6_pvt.complete, msecs_to_jiffies(NSS_TUNIPIP6_TX_TIMEOUT)); +- if (!ret) { +- nss_warning("%px: tunipip6 tx sync failed due to timeout\n", nss_ctx); +- tunipip6_pvt.response = NSS_TX_FAILURE; +- } +- +- status = tunipip6_pvt.response; +- up(&tunipip6_pvt.sem); +- return status; +-} +-EXPORT_SYMBOL(nss_tunipip6_tx_sync); +- +-/* + * ********************************** + * Register/Unregister/Miscellaneous APIs + * ********************************** +@@ -250,7 +173,6 @@ void nss_unregister_tunipip6_if(uint32_t + nss_assert(nss_ctx); + nss_assert(nss_tunipip6_verify_if_num(if_num)); + +- nss_stats_reset_common_stats(if_num); + nss_core_unregister_handler(nss_ctx, if_num); + nss_core_unregister_subsys_dp(nss_ctx, if_num); + +@@ -275,9 +197,6 @@ void nss_tunipip6_register_handler() + struct nss_ctx_instance *nss_ctx = nss_tunipip6_get_context(); + + nss_core_register_handler(nss_ctx, NSS_TUNIPIP6_INTERFACE, nss_tunipip6_handler, NULL); +- nss_tunipip6_stats_dentry_create(); +- sema_init(&tunipip6_pvt.sem, 1); +- init_completion(&tunipip6_pvt.complete); + } + + /* +--- a/nss_tunipip6_log.c ++++ b/nss_tunipip6_log.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2018, 2020, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -26,83 +26,47 @@ + * NSS TUNIPIP6 message strings + */ + static int8_t *nss_tunipip6_log_message_types_str[NSS_TUNIPIP6_MAX] __maybe_unused = { +- "TUNIPIP6 Encap Interface Create", +- "TUNIPIP6 Decap Interface Create", ++ "TUNIPIP6 Interface Create", + "TUNIPIP6 Stats", +- "TUNIPIP6 FMR add", +- "TUNIPIP6 FMR delete", +- "TUNIPIP6 FMR flush", +- "TUNIPIP6 BMR add", +- "TUNIPIP6 BMR delete", + }; + + /* +- * nss_tunipip6_log_error_types_str +- * Strings for error types for TUNIPIP6 messages +- */ +-static char *nss_tunipip6_log_error_types_str[NSS_TUNIPIP6_ERROR_MAX] __maybe_unused = { +- "TUNIPIP6 maximum tunnel reached", +- "TUNIPIP6 tunnel already exists", +- "TUNIPIP6 configuration parameters are incorrect", +- "TUNIPIP6 FMR already exists ", +- "TUNIPIP6 no FMR configured", +- "TUNIPIP6 FMR table is full", +- "TUNIPIP6 invalid FMR", +- "TUNIPIP6 BMR already exists", +- "TUNIPIP6 no BMR configured", +- "TUNIPIP6 memory allocation for FMR failed", +- "TUNIPIP6 unknown error", +-}; +- +-/* +- * nss_tunipip6_log_map_rule() +- * Log NSS TUNIPIP6 map rule. +- */ +-static void nss_tunipip6_log_map_rule(struct nss_tunipip6_msg *ntm) +-{ +- struct nss_tunipip6_map_rule *nmr __maybe_unused = &ntm->msg.map_rule; +- nss_trace("%px: NSS TUNIPIP6 Interface Create message \n" +- "TUNIPIP6 Map Rule IPv6 prefix: %pI6\n" +- "TUNIPIP6 Map Rule IPv6 prefix length: %d\n" +- "TUNIPIP6 Map Rule IPv4 prefix: %pI4\n" +- "TUNIPIP6 Map Rule IPv4 prefix length: %d\n" +- "TUNIPIP6 Map Rule IPv6 suffix: %pI6\n" +- "TUNIPIP6 Map Rule IPv6 suffix length: %d\n" +- "TUNIPIP6 Map Rule EA length: %d\n" +- "TUNIPIP6 Map Rule PSID offset: %d\n", +- nmr, nmr->ip6_prefix, +- nmr->ip6_prefix_len,&nmr->ip4_prefix, +- nmr->ip4_prefix_len, nmr->ip6_suffix, +- nmr->ip6_suffix_len, nmr->ea_len, +- nmr->psid_offset); +-} +- +-/* + * nss_tunipip6_log_if_create_msg() + * Log NSS TUNIPIP6 Interface Create + */ + static void nss_tunipip6_log_if_create_msg(struct nss_tunipip6_msg *ntm) + { + struct nss_tunipip6_create_msg *ntcm __maybe_unused = &ntm->msg.tunipip6_create; +- nss_trace("%px: NSS TUNIPIP6 Interface Create message \n" ++ int32_t i; ++ nss_trace("%p: NSS TUNIPIP6 Interface Create message \n" + "TUNIPIP6 Source Address: %pI6\n" + "TUNIPIP6 Destination Address: %pI6\n" + "TUNIPIP6 Flow Label: %d\n" + "TUNIPIP6 Flags: %d\n" + "TUNIPIP6 Hop Limit: %d\n" + "TUNIPIP6 Draft03 Specification: %d\n" +- "TUNIPIP6 TTL inherit: %u\n" +- "TUNIPIP6 TOS inherit: %u\n" +- "TUNIPIP6 Frag ID Update: %u\n" +- "TUNIPIP6 Max FMR: %u\n", ++ "TUNIPIP6 FMR Number: %d\n", + ntcm, ntcm->saddr, + ntcm->daddr, ntcm->flowlabel, + ntcm->flags, ntcm->hop_limit, +- ntcm->draft03, +- ntcm->ttl_inherit, +- ntcm->tos_inherit, +- ntcm->frag_id_update, +- ntcm->fmr_max); ++ ntcm->draft03, ntcm->fmr_number); ++ /* ++ * Continuation of the log. ++ */ ++ for (i = 0; i < NSS_TUNIPIP6_MAX_FMR_NUMBER; i++) { ++ nss_trace("TUNIPIP6 FMR[%d] IPv6 Prefix: %pI6\n" ++ "TUNIPIP6 FMR[%d] IPv4 Prefix: %pI4\n" ++ "TUNIPIP6 FMR[%d] IPv6 Prefix Length: %d\n" ++ "TUNIPIP6 FMR[%d] IPv4 Prefix Length: %d\n" ++ "TUNIPIP6 FMR[%d] Embedded Address Length: %d\n" ++ "TUNIPIP6 FMR[%d] offset: %d", ++ i, ntcm->fmr[i].ip6_prefix, ++ i, &ntcm->fmr[i].ip4_prefix, ++ i, ntcm->fmr[i].ip6_prefix_len, ++ i, ntcm->fmr[i].ip4_prefix_len, ++ i, ntcm->fmr[i].ea_len, ++ i, ntcm->fmr[i].offset); ++ } + } + + /* +@@ -117,23 +81,14 @@ static void nss_tunipip6_log_verbose(str + nss_tunipip6_log_if_create_msg(ntm); + break; + +- case NSS_TUNIPIP6_STATS_SYNC: ++ case NSS_TUNIPIP6_RX_STATS_SYNC: + /* + * No log for valid stats message. + */ + break; + +- case NSS_TUNIPIP6_BMR_RULE_ADD: +- case NSS_TUNIPIP6_BMR_RULE_DEL: +- case NSS_TUNIPIP6_FMR_RULE_ADD: +- case NSS_TUNIPIP6_FMR_RULE_DEL: +- nss_tunipip6_log_map_rule(ntm); +- break; +- case NSS_TUNIPIP6_FMR_RULE_FLUSH: +- nss_trace("%px: FMR rule flush.\n", ntm); +- break; + default: +- nss_trace("%px: Invalid message type\n", ntm); ++ nss_trace("%p: Invalid message type\n", ntm); + break; + } + } +@@ -145,11 +100,11 @@ static void nss_tunipip6_log_verbose(str + void nss_tunipip6_log_tx_msg(struct nss_tunipip6_msg *ntm) + { + if (ntm->cm.type >= NSS_TUNIPIP6_MAX) { +- nss_warning("%px: Invalid message type\n", ntm); ++ nss_warning("%p: Invalid message type\n", ntm); + return; + } + +- nss_info("%px: type[%d]:%s\n", ntm, ntm->cm.type, nss_tunipip6_log_message_types_str[ntm->cm.type]); ++ nss_info("%p: type[%d]:%s\n", ntm, ntm->cm.type, nss_tunipip6_log_message_types_str[ntm->cm.type]); + nss_tunipip6_log_verbose(ntm); + } + +@@ -160,29 +115,20 @@ void nss_tunipip6_log_tx_msg(struct nss_ + void nss_tunipip6_log_rx_msg(struct nss_tunipip6_msg *ntm) + { + if (ntm->cm.response >= NSS_CMN_RESPONSE_LAST) { +- nss_warning("%px: Invalid response\n", ntm); ++ nss_warning("%p: Invalid response\n", ntm); + return; + } + + if (ntm->cm.response == NSS_CMN_RESPONSE_NOTIFY || (ntm->cm.response == NSS_CMN_RESPONSE_ACK)) { +- nss_info("%px: type[%d]:%s, response[%d]:%s\n", ntm, ntm->cm.type, ++ nss_info("%p: type[%d]:%s, response[%d]:%s\n", ntm, ntm->cm.type, + nss_tunipip6_log_message_types_str[ntm->cm.type], + ntm->cm.response, nss_cmn_response_str[ntm->cm.response]); + goto verbose; + } + +- if (ntm->cm.error >= NSS_TUNIPIP6_ERROR_MAX) { +- nss_warning("%px: msg failure - type[%d]:%s, response[%d]:%s, error[%d]:Invalid error\n", +- ntm, ntm->cm.type, nss_tunipip6_log_message_types_str[ntm->cm.type], +- ntm->cm.response, nss_cmn_response_str[ntm->cm.response], +- ntm->cm.error); +- goto verbose; +- } +- +- nss_info("%px: msg nack - type[%d]:%s, response[%d]:%s, error[%d]:%s\n", ++ nss_info("%p: msg nack - type[%d]:%s, response[%d]:%s\n", + ntm, ntm->cm.type, nss_tunipip6_log_message_types_str[ntm->cm.type], +- ntm->cm.response, nss_cmn_response_str[ntm->cm.response], +- ntm->cm.error, nss_tunipip6_log_error_types_str[ntm->cm.error]); ++ ntm->cm.response, nss_cmn_response_str[ntm->cm.response]); + + verbose: + nss_tunipip6_log_verbose(ntm); +--- a/nss_tunipip6_stats.c ++++ /dev/null +@@ -1,124 +0,0 @@ +-/* +- ************************************************************************** +- * Copyright (c) 2020, The Linux Foundation. All rights reserved. +- +- * Permission to use, copy, modify, and/or distribute this software for any +- * purpose with or without fee is hereby granted, provided that the above +- * copyright notice and this permission notice appear in all copies. +- +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- ************************************************************************** +- */ +- +-#include "nss_core.h" +-#include "nss_tunipip6.h" +-#include "nss_stats.h" +-#include "nss_tunipip6_stats.h" +- +-#define NSS_TUNIPIP6_STATS_MAX_LINES (NSS_STATS_NODE_MAX + 32) +- /**< Maximum number of lines for tunipip6 statistics dump. */ +-#define NSS_TUNIPIP6_STATS_SIZE_PER_IF (NSS_STATS_MAX_STR_LENGTH * NSS_TUNIPIP6_STATS_MAX_LINES) +- /**< Total number of statistics per tunipip6 interface. */ +- +-/* +- * nss_tunipip6_stats_read() +- * Read tunipip6 common node statistics +- */ +-static ssize_t nss_tunipip6_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- struct nss_ctx_instance *nss_ctx = nss_tunipip6_get_context(); +- enum nss_dynamic_interface_type type; +- ssize_t bytes_read = 0; +- size_t len = 0, size; +- uint32_t if_num; +- char *buf; +- +- /* +- * Allocate memory for NSS_TUNIPIP6_TUNNEL_MAX tunnels and one +- * static interface. +- */ +- size = NSS_TUNIPIP6_STATS_SIZE_PER_IF * (NSS_TUNIPIP6_TUNNEL_MAX << 1) + 1; +- buf = vzalloc(size); +- if (!buf) { +- nss_warning("tunipip6: Could not allocate memory for local statistics buffer\n"); +- return 0; +- } +- +- len += nss_stats_banner(buf, len, size, "tunipip6", NSS_STATS_SINGLE_CORE); +- +- len += scnprintf(buf + len, size - len, "\nBase node if_num:%03u", NSS_TUNIPIP6_INTERFACE); +- len += scnprintf(buf + len, size - len, "\n-------------------\n"); +- len += nss_stats_fill_common_stats(NSS_TUNIPIP6_INTERFACE, NSS_STATS_SINGLE_INSTANCE, buf, len, size - len, "tunipip6"); +- +- /* +- * Common node stats for each tunipip6 dynamic interface. +- */ +- for (if_num = NSS_DYNAMIC_IF_START; if_num < NSS_DYNAMIC_IF_START + NSS_MAX_DYNAMIC_INTERFACES; if_num++) { +- type = nss_dynamic_interface_get_type(nss_ctx, if_num); +- switch (type) { +- case NSS_DYNAMIC_INTERFACE_TYPE_TUNIPIP6_INNER: +- len += scnprintf(buf + len, size - len, "\nInner if_num:%03u", if_num); +- break; +- +- case NSS_DYNAMIC_INTERFACE_TYPE_TUNIPIP6_OUTER: +- len += scnprintf(buf + len, size - len, "\nOuter if_num:%03u", if_num); +- break; +- +- default: +- continue; +- } +- +- len += scnprintf(buf + len, size - len, "\n-------------------\n"); +- len += nss_stats_fill_common_stats(if_num, NSS_STATS_SINGLE_INSTANCE, buf, len, size - len, "tunipip6"); +- } +- +- bytes_read = simple_read_from_buffer(ubuf, sz, ppos, buf, len); +- vfree(buf); +- return bytes_read; +-} +- +-/* +- * nss_tunipip6_stats_sync() +- * Update tunipip6 common node statistics. +- */ +-void nss_tunipip6_stats_sync(struct nss_ctx_instance *nss_ctx, struct nss_tunipip6_msg *ntm) +-{ +- struct nss_top_instance *nss_top = nss_ctx->nss_top; +- struct nss_tunipip6_stats_sync_msg *msg_stats = &ntm->msg.stats; +- uint64_t i, *dest; +- uint32_t *src; +- +- spin_lock_bh(&nss_top->stats_lock); +- +- /* +- * Update common node stats +- */ +- dest = nss_top->stats_node[ntm->cm.interface]; +- src = &msg_stats->node_stats.rx_packets; +- for (i = NSS_STATS_NODE_RX_PKTS; i <= NSS_STATS_NODE_RX_QUEUE_3_DROPPED; i++) { +- *dest++ = *src++; +- } +- +- spin_unlock_bh(&nss_top->stats_lock); +- +-} +- +-/* +- * nss_tunipip6_stats_ops +- */ +-NSS_STATS_DECLARE_FILE_OPERATIONS(tunipip6) +- +-/* +- * nss_tunipip6_stats_dentry_create() +- * Create tunipip6 statistics debug entry. +- */ +-void nss_tunipip6_stats_dentry_create(void) +-{ +- nss_stats_create_dentry("tunipip6", &nss_tunipip6_stats_ops); +-} +--- a/nss_tunipip6_stats.h ++++ /dev/null +@@ -1,34 +0,0 @@ +-/* +- ****************************************************************************** +- * Copyright (c) 2020, The Linux Foundation. All rights reserved. +- +- * Permission to use, copy, modify, and/or distribute this software for any +- * purpose with or without fee is hereby granted, provided that the above +- * copyright notice and this permission notice appear in all copies. +- +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- * **************************************************************************** +- */ +- +-#ifndef __NSS_TUNIPIP6_STATS_H +-#define __NSS_TUNIPIP6_STATS_H +- +-/* +- * nss_tunipip6_stats_dentry_create() +- * Creates tunipip6 interface statistics debug entry. +- */ +-void nss_tunipip6_stats_dentry_create(void); +- +-/* +- * nss_tunipip6_stats_sync() +- * Update tunipip6 common node statistics. +- */ +-void nss_tunipip6_stats_sync(struct nss_ctx_instance *nss_ctx, struct nss_tunipip6_msg *ntm); +- +-#endif /* __NSS_TUNIPIP6_STATS_H */ +--- a/nss_tx_rx_common.h ++++ b/nss_tx_rx_common.h +@@ -92,15 +92,13 @@ extern void nss_dtls_cmn_register_handle + extern void nss_tls_register_handler(void); + extern void nss_gre_tunnel_register_handler(void); + extern void nss_trustsec_tx_register_handler(void); +-extern void nss_trustsec_rx_register_handler(void); + extern void nss_wifili_register_handler(void); + extern void nss_ppe_register_handler(void); + extern void nss_gre_redir_mark_register_handler(void); + extern void nss_ppe_vp_register_handler(void); ++#if (NSS_FW_VERSION_CODE > NSS_FW_VERSION(11,0)) + extern void nss_wifi_mac_db_register_handler(void); +-extern void nss_wifi_ext_vdev_register_handler(void); +-extern void nss_wifili_thread_scheme_db_init(uint8_t core_id); +-extern void nss_wifi_mesh_init(void); ++#endif + + /* + * nss_if_msg_handler() +--- a/nss_udp_st.c ++++ /dev/null +@@ -1,238 +0,0 @@ +-/* +- ************************************************************************** +- * Copyright (c) 2021, The Linux Foundation. All rights reserved. +- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- ************************************************************************** +- */ +- +-/* +- * nss_udp_st.c +- * NSS UDP_ST APIs +- */ +- +-#include "nss_core.h" +-#include "nss_udp_st_stats.h" +-#include "nss_udp_st_strings.h" +-#include "nss_udp_st_log.h" +- +-#define NSS_UDP_ST_TX_MSG_TIMEOUT 1000 /* 1 sec timeout for udp_st messages */ +- +-/* +- * Private data structure for udp_st configuration +- */ +-struct nss_udp_st_pvt { +- struct semaphore sem; /* Semaphore structure */ +- struct completion complete; /* completion structure */ +- int response; /* Response from FW */ +- void *cb; /* Original cb for sync msgs */ +- void *app_data; /* Original app_data for sync msgs */ +-} nss_udp_st_pvt; +- +-/* +- * nss_udp_st_msg_handler() +- * Handle NSS -> HLOS messages for UDP_ST node +- */ +-static void nss_udp_st_msg_handler(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm, __attribute__((unused))void *app_data) +-{ +- struct nss_udp_st_msg *num = (struct nss_udp_st_msg *)ncm; +- nss_udp_st_msg_callback_t cb; +- +- /* +- * Is this a valid message type? +- */ +- if (num->cm.type >= NSS_UDP_ST_MAX_MSG_TYPES) { +- nss_warning("%px: received invalid message %d for udp_st interface", nss_ctx, num->cm.type); +- return; +- } +- +- /* +- * Log messages. +- */ +- nss_udp_st_log_rx_msg(num); +- +- switch (num->cm.type) { +- case NSS_UDP_ST_STATS_SYNC_MSG: +- /* +- * Update driver statistics and send stats notifications to the registered modules. +- */ +- nss_udp_st_stats_sync(nss_ctx, &num->msg.stats); +- break; +- +- case NSS_UDP_ST_RESET_STATS_MSG: +- /* +- * This is a response to the statistics reset message. +- */ +- nss_udp_st_stats_reset(NSS_UDP_ST_INTERFACE); +- break; +- default: +- if (ncm->response != NSS_CMN_RESPONSE_ACK) { +- /* +- * Check response. +- */ +- nss_info("%px: Received response %d for type %d, interface %d", +- nss_ctx, ncm->response, ncm->type, ncm->interface); +- } +- } +- +- /* +- * Return for NOTIFY messages because there is no notifier functions. +- */ +- if (num->cm.response == NSS_CMN_RESPONSE_NOTIFY) { +- return; +- } +- +- /* +- * Do we have a callback? +- */ +- if (!ncm->cb) { +- return; +- } +- +- /* +- * Callback +- */ +- cb = (nss_udp_st_msg_callback_t)ncm->cb; +- cb((void *)ncm->app_data, num); +-} +- +-/* +- * nss_udp_st_tx_sync_callback() +- * Callback to handle the completion of synchronous tx messages. +- */ +-static void nss_udp_st_tx_sync_callback(void *app_data, struct nss_udp_st_msg *num) +-{ +- nss_udp_st_msg_callback_t callback = (nss_udp_st_msg_callback_t)nss_udp_st_pvt.cb; +- void *data = nss_udp_st_pvt.app_data; +- +- nss_udp_st_pvt.cb = NULL; +- nss_udp_st_pvt.app_data = NULL; +- +- if (num->cm.response != NSS_CMN_RESPONSE_ACK) { +- nss_warning("udp_st error response %d\n", num->cm.response); +- nss_udp_st_pvt.response = NSS_TX_FAILURE; +- } else { +- nss_udp_st_pvt.response = NSS_TX_SUCCESS; +- } +- +- if (callback) { +- callback(data, num); +- } +- +- complete(&nss_udp_st_pvt.complete); +-} +- +-/* +- * nss_udp_st_tx() +- * Transmit a udp_st message to the FW. +- * +- * This API should not be called from interrupt or softirq context. +- */ +-nss_tx_status_t nss_udp_st_tx(struct nss_ctx_instance *nss_ctx, struct nss_udp_st_msg *num) +-{ +- struct nss_cmn_msg *ncm = &num->cm; +- +- /* +- * Sanity check the message +- */ +- if (ncm->interface != NSS_UDP_ST_INTERFACE) { +- nss_warning("%px: tx request for another interface: %d", nss_ctx, ncm->interface); +- return NSS_TX_FAILURE; +- } +- +- if (ncm->type >= NSS_UDP_ST_MAX_MSG_TYPES) { +- nss_warning("%px: message type out of range: %d", nss_ctx, ncm->type); +- return NSS_TX_FAILURE; +- } +- +- /* +- * Trace messages. +- */ +- nss_udp_st_log_tx_msg(num); +- +- return nss_core_send_cmd(nss_ctx, num, sizeof(*num), NSS_NBUF_PAYLOAD_SIZE); +-} +-EXPORT_SYMBOL(nss_udp_st_tx); +- +-/* +- * nss_udp_st_tx_sync() +- * Transmit a synchronous udp_st message to the FW. +- * +- * This API should not be called from interrupt or softirq context. +- */ +-nss_tx_status_t nss_udp_st_tx_sync(struct nss_ctx_instance *nss_ctx, struct nss_udp_st_msg *num) +-{ +- nss_tx_status_t status; +- int ret = 0; +- +- down(&nss_udp_st_pvt.sem); +- nss_udp_st_pvt.cb = (void *)num->cm.cb; +- nss_udp_st_pvt.app_data = (void *)num->cm.app_data; +- +- num->cm.cb = (nss_ptr_t)nss_udp_st_tx_sync_callback; +- num->cm.app_data = (nss_ptr_t)NULL; +- +- status = nss_udp_st_tx(nss_ctx, num); +- if (status != NSS_TX_SUCCESS) { +- nss_warning("%px: nss udp_st msg tx failed\n", nss_ctx); +- up(&nss_udp_st_pvt.sem); +- return status; +- } +- +- ret = wait_for_completion_timeout(&nss_udp_st_pvt.complete, msecs_to_jiffies(NSS_UDP_ST_TX_MSG_TIMEOUT)); +- if (!ret) { +- nss_warning("%px: udp_st tx sync failed due to timeout\n", nss_ctx); +- nss_udp_st_pvt.response = NSS_TX_FAILURE; +- } +- +- status = nss_udp_st_pvt.response; +- up(&nss_udp_st_pvt.sem); +- return status; +-} +-EXPORT_SYMBOL(nss_udp_st_tx_sync); +- +-/* +- * nss_udp_st_msg_init() +- * Initialize udp_st message. +- */ +-void nss_udp_st_msg_init(struct nss_udp_st_msg *num, uint16_t if_num, uint32_t type, uint32_t len, +- nss_udp_st_msg_callback_t cb, void *app_data) +-{ +- nss_cmn_msg_init(&num->cm, if_num, type, len, (void *)cb, app_data); +-} +-EXPORT_SYMBOL(nss_udp_st_msg_init); +- +-/* +- * nss_udp_st_register_handler() +- */ +-void nss_udp_st_register_handler(struct nss_ctx_instance *nss_ctx) +-{ +- nss_core_register_handler(nss_ctx, NSS_UDP_ST_INTERFACE, nss_udp_st_msg_handler, NULL); +- +- nss_udp_st_stats_dentry_create(); +- nss_udp_st_strings_dentry_create(); +- +- sema_init(&nss_udp_st_pvt.sem, 1); +- init_completion(&nss_udp_st_pvt.complete); +-} +- +-/* +- * nss_udp_st_get_mgr() +- * +- */ +-struct nss_ctx_instance *nss_udp_st_get_mgr(void) +-{ +- return (void *)&nss_top_main.nss[nss_top_main.udp_st_handler_id]; +-} +-EXPORT_SYMBOL(nss_udp_st_get_mgr); +--- a/nss_udp_st_log.c ++++ /dev/null +@@ -1,297 +0,0 @@ +-/* +- ************************************************************************** +- * Copyright (c) 2020, The Linux Foundation. All rights reserved. +- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- ************************************************************************** +- */ +- +-/* +- * nss_udp_st_log.c +- * NSS UDP Speedtest logger file. +- */ +- +-#include "nss_core.h" +- +-/* +- * nss_udp_st_log_message_types_str +- * udp_st message strings +- */ +-static int8_t *nss_udp_st_log_message_types_str[NSS_UDP_ST_MAX_MSG_TYPES] __maybe_unused = { +- "UDP_ST Start Msg", +- "UDP_ST Stop Msg", +- "UDP_ST Configure Rule Msg", +- "UDP_ST Unconfigure Rule Msg", +- "UDP_ST Stats Sync Msg", +- "UDP_ST TX Create Msg", +- "UDP_ST TX Destroy Msg", +- "UDP_ST TX Update Rate Msg", +- "UDP_ST RX Mode Set Msg", +- "UDP_ST Time Sync Msg", +- "UDP_ST Reset Stats Msg", +-}; +- +-/* +- * nss_udp_st_log_error_response_types_str +- * Strings for error types for udp_st messages +- */ +-static int8_t *nss_udp_st_log_error_response_types_str[NSS_UDP_ST_ERROR_MAX] __maybe_unused = { +- "UDP_ST No Error", +- "UDP_ST Incorrect Rate", +- "UDP_ST Incorrect Buffer Size", +- "UDP_ST Memory Failure", +- "UDP_ST Incorrect State", +- "UDP_ST Incorrect Flags", +- "UDP_ST Entry Exist", +- "UDP_ST Entry Add Failed", +- "UDP_ST Entry Not Exist", +- "UDP_ST Wrong Start Msg Type", +- "UDP_ST Wrong Stop Msg Type", +- "UDP_ST Too Many Users", +- "UDP_ST Unknown Msg Type", +- "UDP_ST Pbuf Alloc Failure", +- "UDP_ST Pbuf Size Failure", +- "UDP_ST Drop Queue", +- "UDP_ST Timer call missed", +- "UDP_ST Encap Entry Lookup Failed", +-}; +- +-/* +- * nss_udp_st_log_tx_create_destroy_msg() +- * Log NSS udp_st Tx create/destroy message. +- */ +-static void nss_udp_st_log_tx_create_destroy_msg(struct nss_udp_st_msg *num, uint8_t *msg_type) +-{ +- struct nss_udp_st_tx_create *create __maybe_unused = &num->msg.create; +- nss_trace("%px: NSS udp_st message: %s\n" +- "Rate: %u\n" +- "Buffer Size: %u\n" +- "DSCP: %u\n" +- "Mode: %d\n" +- "Timestamp: %llu", +- create, +- msg_type, +- create->rate, +- create->buffer_size, +- create->dscp, +- create->mode, +- create->timestamp); +-} +- +-/* +- * nss_udp_st_log_uncfg_rule_msg() +- * Log NSS udp_st unconfig rule message. +- */ +-static void nss_udp_st_log_uncfg_rule_msg(struct nss_udp_st_msg *num) +-{ +- struct nss_udp_st_cfg *uncfg __maybe_unused = &num->msg.uncfg; +- nss_trace("%px: NSS udp_st message: Unconfig\n" +- "IP version: %u\n", +- uncfg, +- uncfg->ip_version); +- +- if (uncfg->ip_version == NSS_UDP_ST_FLAG_IPV4) { +- nss_trace("Src IP: %pI4\n" +- "Dest IP: %pI4\n", +- &(uncfg->src_ip.ip.ipv4), +- &(uncfg->dest_ip.ip.ipv4)); +- } else { +- nss_trace("Src IP: %pI6\n" +- "Dest IP: %pI6\n", +- &(uncfg->src_ip.ip.ipv6), +- &(uncfg->dest_ip.ip.ipv6)); +- } +- +- nss_trace("Src Port: %u\n Dest Port: %u\n Type: %u\n", +- uncfg->src_port, uncfg->dest_port, uncfg->type); +-} +- +-/* +- * nss_udp_st_log_tx_update_rate_msg() +- * Log NSS udp_st udpate Tx rate message. +- */ +-static void nss_udp_st_log_tx_update_rate_msg(struct nss_udp_st_msg *num) +-{ +- struct nss_udp_st_tx_update_rate *update_rate __maybe_unused = &num->msg.update_rate; +- nss_trace("%px: NSS udp_st message: Update Tx Rate\n" +- "Rate : %u\n", +- update_rate, +- update_rate->rate); +-} +- +-/* +- * nss_udp_st_log_rx_mode_set_msg() +- * Log NSS udp_st Rx mode set message. +- */ +-static void nss_udp_st_log_rx_mode_set_msg(struct nss_udp_st_msg *num) +-{ +- struct nss_udp_st_rx_mode *mode __maybe_unused = &num->msg.mode; +- nss_trace("%px: NSS udp_st message: Rx mode set\n" +- "Mode : %u\n" +- "Timestamp : %llu\n", +- mode, +- mode->mode, +- mode->timestamp); +-} +- +-/* +- * nss_udp_st_log_cfg_rule_msg() +- * Log NSS udp_st config rule message. +- */ +-static void nss_udp_st_log_cfg_rule_msg(struct nss_udp_st_msg *num) +-{ +- struct nss_udp_st_cfg *cfg __maybe_unused = &num->msg.cfg; +- nss_trace("%px: NSS udp_st message: Config\n" +- "IP version: %u\n", +- cfg, +- cfg->ip_version); +- +- if (cfg->ip_version == NSS_UDP_ST_FLAG_IPV4) { +- nss_trace("Src IP: %pI4\n" +- "Dest IP: %pI4\n", +- &(cfg->src_ip.ip.ipv4), +- &(cfg->dest_ip.ip.ipv4)); +- } else { +- nss_trace("Src IP: %pI6\n" +- "Dest IP: %pI6\n", +- &(cfg->src_ip.ip.ipv6), +- &(cfg->dest_ip.ip.ipv6)); +- } +- +- nss_trace("Src Port: %u\n Dest Port: %u\n Type: %u\n", +- cfg->src_port, cfg->dest_port, cfg->type); +-} +- +-/* +- * nss_udp_st_log_stop_msg() +- * Log NSS udp_st stop message. +- */ +-static void nss_udp_st_log_stop_msg(struct nss_udp_st_msg *num) +-{ +- struct nss_udp_st_stop *stop __maybe_unused = &num->msg.stop; +- nss_trace("%px: NSS udp_st message: Stop\n" +- "Type: %u\n", +- stop, +- stop->type); +-} +- +-/* +- * nss_udp_st_log_start_msg() +- * Log NSS udp_st start message. +- */ +-static void nss_udp_st_log_start_msg(struct nss_udp_st_msg *num) +-{ +- struct nss_udp_st_start *start __maybe_unused = &num->msg.start; +- nss_trace("%px: NSS udp_st message: Start\n" +- "Type: %u\n", +- start, +- start->type); +-} +- +-/* +- * nss_udp_st_log_verbose() +- * Log message contents. +- */ +-static void nss_udp_st_log_verbose(struct nss_udp_st_msg *num) +-{ +- switch (num->cm.type) { +- case NSS_UDP_ST_START_MSG: +- nss_udp_st_log_start_msg(num); +- break; +- +- case NSS_UDP_ST_STOP_MSG: +- nss_udp_st_log_stop_msg(num); +- break; +- +- case NSS_UDP_ST_CFG_RULE_MSG: +- nss_udp_st_log_cfg_rule_msg(num); +- break; +- +- case NSS_UDP_ST_UNCFG_RULE_MSG: +- nss_udp_st_log_uncfg_rule_msg(num); +- break; +- +- case NSS_UDP_ST_TX_CREATE_MSG: +- nss_udp_st_log_tx_create_destroy_msg(num, "Create"); +- break; +- +- case NSS_UDP_ST_TX_DESTROY_MSG: +- nss_udp_st_log_tx_create_destroy_msg(num, "Destroy"); +- break; +- case NSS_UDP_ST_TX_UPDATE_RATE_MSG: +- nss_udp_st_log_tx_update_rate_msg(num); +- break; +- case NSS_UDP_ST_RX_MODE_SET_MSG: +- nss_udp_st_log_rx_mode_set_msg(num); +- break; +- case NSS_UDP_ST_RESET_STATS_MSG: +- case NSS_UDP_ST_STATS_SYNC_MSG: +- case NSS_UDP_ST_TIME_SYNC_MSG: +- break; +- +- default: +- nss_trace("%px: Invalid message type\n", num); +- break; +- } +-} +- +-/* +- * nss_udp_st_log_tx_msg() +- * Log messages transmitted to FW. +- */ +-void nss_udp_st_log_tx_msg(struct nss_udp_st_msg *num) +-{ +- if (num->cm.type >= NSS_UDP_ST_MAX_MSG_TYPES) { +- nss_warning("%px: Invalid message type\n", num); +- return; +- } +- +- nss_info("%px: type[%d]:%s\n", num, num->cm.type, nss_udp_st_log_message_types_str[num->cm.type]); +- nss_udp_st_log_verbose(num); +-} +- +-/* +- * nss_udp_st_log_rx_msg() +- * Log messages received from FW. +- */ +-void nss_udp_st_log_rx_msg(struct nss_udp_st_msg *num) +-{ +- if (num->cm.response >= NSS_CMN_RESPONSE_LAST) { +- nss_warning("%px: Invalid response\n", num); +- return; +- } +- +- if (num->cm.response == NSS_CMN_RESPONSE_NOTIFY || (num->cm.response == NSS_CMN_RESPONSE_ACK)) { +- nss_info("%px: type[%d]:%s, response[%d]:%s\n", num, num->cm.type, +- nss_udp_st_log_message_types_str[num->cm.type], +- num->cm.response, nss_cmn_response_str[num->cm.response]); +- goto verbose; +- } +- +- if (num->cm.error >= NSS_UDP_ST_ERROR_MAX) { +- nss_warning("%px: msg failure - type[%d]:%s, response[%d]:%s, error[%d]:Invalid error\n", +- num, num->cm.type, nss_udp_st_log_message_types_str[num->cm.type], +- num->cm.response, nss_cmn_response_str[num->cm.response], +- num->cm.error); +- goto verbose; +- } +- +- nss_info("%px: msg nack - type[%d]:%s, response[%d]:%s, error[%d]:%s\n", +- num, num->cm.type, nss_udp_st_log_message_types_str[num->cm.type], +- num->cm.response, nss_cmn_response_str[num->cm.response], +- num->cm.error, nss_udp_st_log_error_response_types_str[num->cm.error]); +- +-verbose: +- nss_udp_st_log_verbose(num); +-} +--- a/nss_udp_st_log.h ++++ /dev/null +@@ -1,39 +0,0 @@ +-/* +- ****************************************************************************** +- * Copyright (c) 2021, The Linux Foundation. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- * **************************************************************************** +- */ +- +-#ifndef __NSS_UDP_ST_LOG_H__ +-#define __NSS_UDP_ST_LOG_H__ +- +-/* +- * nss_udp_st_log.h +- * NSS UDP Speedtest Log Header File. +- */ +- +-/* +- * nss_udp_st_log_tx_msg +- * Logs a udp_st message that is sent to the NSS firmware. +- */ +-void nss_udp_st_log_tx_msg(struct nss_udp_st_msg *num); +- +-/* +- * nss_udp_st_log_rx_msg +- * Logs a udp_st message that is received from the NSS firmware. +- */ +-void nss_udp_st_log_rx_msg(struct nss_udp_st_msg *num); +- +-#endif /* __NSS_UDP_ST_LOG_H__*/ +--- a/nss_udp_st_stats.c ++++ /dev/null +@@ -1,216 +0,0 @@ +-/* +- ************************************************************************** +- * Copyright (c) 2021, The Linux Foundation. All rights reserved. +- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- ************************************************************************** +- */ +- +-#include "nss_core.h" +-#include "nss_udp_st_stats.h" +-#include "nss_udp_st_strings.h" +- +-uint32_t nss_udp_st_errors[NSS_UDP_ST_ERROR_MAX]; +-uint32_t nss_udp_st_stats_time[NSS_UDP_ST_TEST_MAX][NSS_UDP_ST_STATS_TIME_MAX]; +-uint64_t nss_udp_st_stats_timestamp[NSS_UDP_ST_STATS_TIMESTAMP_MAX]; +- +-/* +- * nss_udp_st_stats_read() +- * Read UDP_ST stats. +- */ +-static ssize_t nss_udp_st_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- /* +- * Max output lines = #stats * NSS_MAX_CORES + +- * few blank lines for banner printing + Number of Extra outputlines for future reference to add new stats +- */ +- uint32_t max_output_lines = NSS_STATS_NODE_MAX + NSS_UDP_ST_ERROR_MAX + NSS_UDP_ST_STATS_TIMESTAMP_MAX + NSS_STATS_EXTRA_OUTPUT_LINES; +- size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines; +- size_t size_wr = 0; +- ssize_t bytes_read = 0; +- uint64_t *stats_shadow; +- uint32_t i; +- +- char *lbuf = kzalloc(size_al, GFP_KERNEL); +- if (unlikely(lbuf == NULL)) { +- nss_warning("Could not allocate memory for local statistics buffer"); +- return 0; +- } +- +- /* +- * Note: The assumption here is that we do not have more than 64 stats. +- */ +- stats_shadow = kzalloc(64 * 8, GFP_KERNEL); +- if (unlikely(stats_shadow == NULL)) { +- nss_warning("Could not allocate memory for local shadow buffer"); +- kfree(lbuf); +- return 0; +- } +- +- size_wr += nss_stats_banner(lbuf, size_wr, size_al, "udp_st", NSS_STATS_SINGLE_CORE); +- +- size_wr += nss_stats_fill_common_stats(NSS_UDP_ST_INTERFACE, NSS_STATS_SINGLE_INSTANCE, lbuf, size_wr, size_al, "udp_st"); +- +- /* +- * Error stats +- */ +- spin_lock_bh(&nss_top_main.stats_lock); +- for (i = 0; (i < NSS_UDP_ST_ERROR_MAX); i++) { +- stats_shadow[i] = nss_udp_st_errors[i]; +- } +- spin_unlock_bh(&nss_top_main.stats_lock); +- size_wr += nss_stats_print("udp_st", "udp_st error stats" +- , NSS_STATS_SINGLE_INSTANCE +- , nss_udp_st_strings_error_stats +- , stats_shadow +- , NSS_UDP_ST_ERROR_MAX +- , lbuf, size_wr, size_al); +- +- /* +- * Rx time stats +- */ +- spin_lock_bh(&nss_top_main.stats_lock); +- for (i = 0; (i < NSS_UDP_ST_STATS_TIME_MAX); i++) { +- stats_shadow[i] = nss_udp_st_stats_time[NSS_UDP_ST_TEST_RX][i]; +- } +- spin_unlock_bh(&nss_top_main.stats_lock); +- size_wr += nss_stats_print("udp_st", "udp_st Rx time stats (ms)" +- , NSS_STATS_SINGLE_INSTANCE +- , nss_udp_st_strings_rx_time_stats +- , stats_shadow +- , NSS_UDP_ST_STATS_TIME_MAX +- , lbuf, size_wr, size_al); +- +- /* +- * Tx time stats +- */ +- spin_lock_bh(&nss_top_main.stats_lock); +- for (i = 0; (i < NSS_UDP_ST_STATS_TIME_MAX); i++) { +- stats_shadow[i] = nss_udp_st_stats_time[NSS_UDP_ST_TEST_TX][i]; +- } +- spin_unlock_bh(&nss_top_main.stats_lock); +- size_wr += nss_stats_print("udp_st", "udp_st Tx time stats (ms)" +- , NSS_STATS_SINGLE_INSTANCE +- , nss_udp_st_strings_tx_time_stats +- , stats_shadow +- , NSS_UDP_ST_STATS_TIME_MAX +- , lbuf, size_wr, size_al); +- +- /* +- * Timestamp mode stats. +- */ +- spin_lock_bh(&nss_top_main.stats_lock); +- for (i = 0; (i < NSS_UDP_ST_STATS_TIMESTAMP_MAX); i++) { +- stats_shadow[i] = nss_udp_st_stats_timestamp[i]; +- } +- spin_unlock_bh(&nss_top_main.stats_lock); +- size_wr += nss_stats_print("udp_st", "udp_st timestamp mode stats" +- , NSS_STATS_SINGLE_INSTANCE +- , nss_udp_st_strings_timestamp_stats +- , stats_shadow +- , NSS_UDP_ST_STATS_TIMESTAMP_MAX +- , lbuf, size_wr, size_al); +- +- bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf)); +- kfree(lbuf); +- kfree(stats_shadow); +- +- +- return bytes_read; +-} +- +-/* +- * nss_udp_st_stats_ops. +- */ +-NSS_STATS_DECLARE_FILE_OPERATIONS(udp_st); +- +-/* +- * nss_udp_st_stats_dentry_create() +- * Create udp_st statistics debug entry. +- */ +-void nss_udp_st_stats_dentry_create(void) +-{ +- nss_stats_create_dentry("udp_st", &nss_udp_st_stats_ops); +-} +- +-/* +- * nss_udp_st_stats_reset() +- * Reset the udp_st statistics. +- */ +-void nss_udp_st_stats_reset(uint32_t if_num) +-{ +- uint32_t i; +- +- /* +- * Reset common node stats. +- */ +- nss_stats_reset_common_stats(if_num); +- +- /* +- * Reset error stats. +- */ +- spin_lock_bh(&nss_top_main.stats_lock); +- for (i = 0; i < NSS_UDP_ST_ERROR_MAX; i++) { +- nss_udp_st_errors[i] = 0; +- } +- +- /* +- * Reset timestamp mode stats. +- */ +- for(i = 0; i < NSS_UDP_ST_STATS_TIMESTAMP_MAX; i++){ +- nss_udp_st_stats_timestamp[i] = 0; +- } +- spin_unlock_bh(&nss_top_main.stats_lock); +-} +- +-/* +- * nss_udp_st_stats_sync() +- * Handle the syncing of UDP_ST node statistics. +- */ +-void nss_udp_st_stats_sync(struct nss_ctx_instance *nss_ctx, struct nss_udp_st_stats *nus) +-{ +- struct nss_top_instance *nss_top = nss_ctx->nss_top; +- uint32_t i, j; +- +- spin_lock_bh(&nss_top->stats_lock); +- +- nss_top->stats_node[NSS_UDP_ST_INTERFACE][NSS_STATS_NODE_RX_PKTS] += nus->nstats.node_stats.rx_packets; +- nss_top->stats_node[NSS_UDP_ST_INTERFACE][NSS_STATS_NODE_RX_BYTES] += nus->nstats.node_stats.rx_bytes; +- nss_top->stats_node[NSS_UDP_ST_INTERFACE][NSS_STATS_NODE_TX_PKTS] += nus->nstats.node_stats.tx_packets; +- nss_top->stats_node[NSS_UDP_ST_INTERFACE][NSS_STATS_NODE_TX_BYTES] += nus->nstats.node_stats.tx_bytes; +- +- for (i = 0; i < NSS_UDP_ST_ERROR_MAX; i++) { +- nss_udp_st_errors[i] += nus->nstats.errors[i]; +- } +- +- for (i = 0; i < NSS_UDP_ST_TEST_MAX; i++) { +- for (j = 0; j < NSS_UDP_ST_STATS_TIME_MAX; j++) { +- nss_udp_st_stats_time[i][j] = nus->time_stats[i][j]; +- } +- } +- +- nss_udp_st_stats_timestamp[NSS_UDP_ST_STATS_TIMESTAMP_PACKET_LOSS] += nus->tstats[NSS_UDP_ST_STATS_TIMESTAMP_PACKET_LOSS]; +- nss_udp_st_stats_timestamp[NSS_UDP_ST_STATS_TIMESTAMP_OOO_PACKETS] += nus->tstats[NSS_UDP_ST_STATS_TIMESTAMP_OOO_PACKETS]; +- nss_udp_st_stats_timestamp[NSS_UDP_ST_STATS_TIMESTAMP_DELAY_SUM] += nus->tstats[NSS_UDP_ST_STATS_TIMESTAMP_DELAY_SUM]; +- nss_udp_st_stats_timestamp[NSS_UDP_ST_STATS_TIMESTAMP_DELAY_NUM] += nus->tstats[NSS_UDP_ST_STATS_TIMESTAMP_DELAY_NUM]; +- +- /* +- * Maximum and Minimum delay is maintained in fw and we just copy it here as it is. +- */ +- nss_udp_st_stats_timestamp[NSS_UDP_ST_STATS_TIMESTAMP_DELAY_MAX] = nus->tstats[NSS_UDP_ST_STATS_TIMESTAMP_DELAY_MAX]; +- nss_udp_st_stats_timestamp[NSS_UDP_ST_STATS_TIMESTAMP_DELAY_MIN] = nus->tstats[NSS_UDP_ST_STATS_TIMESTAMP_DELAY_MIN]; +- +- nss_udp_st_stats_timestamp[NSS_UDP_ST_STATS_TIMESTAMP_PACKET_LOSS] -= nus->tstats[NSS_UDP_ST_STATS_TIMESTAMP_OOO_PACKETS]; +- spin_unlock_bh(&nss_top->stats_lock); +-} +--- a/nss_udp_st_stats.h ++++ /dev/null +@@ -1,36 +0,0 @@ +-/* +- ************************************************************************** +- * Copyright (c) 2021, The Linux Foundation. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- ************************************************************************** +- */ +- +-#ifndef __NSS_UDP_ST_STATS_H +-#define __NSS_UDP_ST_STATS_H +- +-#include +- +-/* +- * nss_udp_st_stats.h +- * NSS driver UDP_ST statistics header file. +- */ +- +-/* +- * udp_st statistics APIs +- */ +-extern void nss_udp_st_stats_reset(uint32_t if_num); +-extern void nss_udp_st_stats_sync(struct nss_ctx_instance *nss_ctx, struct nss_udp_st_stats *nus); +-extern void nss_udp_st_stats_dentry_create(void); +- +-#endif /* __NSS_UDP_ST_STATS_H */ +--- a/nss_udp_st_strings.c ++++ /dev/null +@@ -1,185 +0,0 @@ +-/* +- ************************************************************************** +- * Copyright (c) 2021, The Linux Foundation. All rights reserved. +- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- ************************************************************************** +- */ +- +-#include "nss_stats.h" +-#include "nss_core.h" +-#include +-#include "nss_strings.h" +- +-/* +- * nss_udp_st_strings_error_stats +- * Statistics strings for udp_st errors. +- */ +-struct nss_stats_info nss_udp_st_strings_error_stats[NSS_UDP_ST_ERROR_MAX] = { +- {"error_none" , NSS_STATS_TYPE_SPECIAL}, +- {"incorrect_rate" , NSS_STATS_TYPE_DROP}, +- {"incorrect_buffer_size" , NSS_STATS_TYPE_DROP}, +- {"memory_failure" , NSS_STATS_TYPE_DROP}, +- {"incorrect_state" , NSS_STATS_TYPE_DROP}, +- {"incorrect_flags" , NSS_STATS_TYPE_DROP}, +- {"entry_exist" , NSS_STATS_TYPE_DROP}, +- {"entry_add_failed" , NSS_STATS_TYPE_DROP}, +- {"entry_not_exist" , NSS_STATS_TYPE_DROP}, +- {"wrong_start_msg_type" , NSS_STATS_TYPE_DROP}, +- {"wrong_stop_msg_type" , NSS_STATS_TYPE_DROP}, +- {"too_many_users" , NSS_STATS_TYPE_DROP}, +- {"unknown_msg_type" , NSS_STATS_TYPE_DROP}, +- {"pb_alloc_failure" , NSS_STATS_TYPE_DROP}, +- {"pb_size_failure" , NSS_STATS_TYPE_DROP}, +- {"drop_queue_failure" , NSS_STATS_TYPE_DROP}, +- {"timer_call_is_missed" , NSS_STATS_TYPE_SPECIAL}, +- {"encap_entry_lookup_failed" ,NSS_STATS_TYPE_DROP}, +-}; +- +-/* +- * nss_udp_st_strings_rx_time_stats +- * Statistics strings for Rx udp_st time. +- */ +-struct nss_stats_info nss_udp_st_strings_rx_time_stats[NSS_UDP_ST_STATS_TIME_MAX] = { +- {"rx_start_time" , NSS_STATS_TYPE_SPECIAL}, +- {"rx_current_time" , NSS_STATS_TYPE_SPECIAL}, +- {"rx_elapsed_time" , NSS_STATS_TYPE_SPECIAL} +-}; +- +-/* +- * nss_udp_st_strings_tx_time_stats +- * Statistics strings for Tx udp_st time. +- */ +-struct nss_stats_info nss_udp_st_strings_tx_time_stats[NSS_UDP_ST_STATS_TIME_MAX] = { +- {"tx_start_time" , NSS_STATS_TYPE_SPECIAL}, +- {"tx_current_time" , NSS_STATS_TYPE_SPECIAL}, +- {"tx_elapsed_time" , NSS_STATS_TYPE_SPECIAL} +-}; +- +-/* +- * nss_udp_st_strings_timestamp_stats +- * Statistics strings for timestamp mode stats. +- */ +-struct nss_stats_info nss_udp_st_strings_timestamp_stats[NSS_UDP_ST_STATS_TIMESTAMP_MAX] = { +- {"Packet_Lost" , NSS_STATS_TYPE_SPECIAL}, +- {"Out_of_order_packets" , NSS_STATS_TYPE_SPECIAL}, +- {"Delay_sum" , NSS_STATS_TYPE_SPECIAL}, +- {"Delay_num" , NSS_STATS_TYPE_SPECIAL}, +- {"Delay_max" , NSS_STATS_TYPE_SPECIAL}, +- {"Delay_min" , NSS_STATS_TYPE_SPECIAL}, +-}; +- +-/* +- * nss_udp_st_error_stats_strings_read() +- * Read udp_st error statistics names. +- */ +-static ssize_t nss_udp_st_error_stats_strings_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- return nss_strings_print(ubuf, sz, ppos, nss_udp_st_strings_error_stats, NSS_UDP_ST_ERROR_MAX); +-} +- +-/* +- * nss_udp_st_rx_time_stats_strings_read() +- * Read Rx udp_st time statistics names. +- */ +-static ssize_t nss_udp_st_rx_time_stats_strings_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- return nss_strings_print(ubuf, sz, ppos, nss_udp_st_strings_rx_time_stats, NSS_UDP_ST_STATS_TIME_MAX); +-} +- +-/* +- * nss_udp_st_tx_time_stats_strings_read() +- * Read Tx udp_st time statistics names. +- */ +-static ssize_t nss_udp_st_tx_time_stats_strings_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- return nss_strings_print(ubuf, sz, ppos, nss_udp_st_strings_tx_time_stats, NSS_UDP_ST_STATS_TIME_MAX); +-} +- +-/* +- * nss_udp_st_timestamp_stats_strings_read() +- * Read udp_st timestamp mode statistics names. +- */ +-static ssize_t nss_udp_st_timestamp_stats_strings_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- return nss_strings_print(ubuf, sz, ppos, nss_udp_st_strings_timestamp_stats, NSS_UDP_ST_STATS_TIMESTAMP_MAX); +-} +- +-/* +- * nss_udp_st_error_stats_strings_ops +- */ +-NSS_STRINGS_DECLARE_FILE_OPERATIONS(udp_st_error_stats); +- +-/* +- * nss_udp_st_rx_time_stats_strings_ops +- */ +-NSS_STRINGS_DECLARE_FILE_OPERATIONS(udp_st_rx_time_stats); +- +-/* +- * nss_udp_st_tx_time_stats_strings_ops +- */ +-NSS_STRINGS_DECLARE_FILE_OPERATIONS(udp_st_tx_time_stats); +- +-/* +- * nss_udp_st_timestamp_stats_strings_ops +- */ +-NSS_STRINGS_DECLARE_FILE_OPERATIONS(udp_st_timestamp_stats); +- +-/* +- * nss_udp_st_strings_dentry_create() +- * Create udp_st statistics strings debug entry. +- */ +-void nss_udp_st_strings_dentry_create(void) +-{ +- struct dentry *dir_d; +- struct dentry *file_d; +- +- if (!nss_top_main.strings_dentry) { +- nss_warning("qca-nss-drv/strings is not present"); +- return; +- } +- +- dir_d = debugfs_create_dir("udp_st", nss_top_main.strings_dentry); +- if (!dir_d) { +- nss_warning("Failed to create qca-nss-drv/strings/udp_st directory"); +- return; +- } +- +- file_d = debugfs_create_file("error_stats_str", 0400, dir_d, &nss_top_main, &nss_udp_st_error_stats_strings_ops); +- if (!file_d) { +- nss_warning("Failed to create qca-nss-drv/stats/udp_st/error_stats_str file"); +- goto fail; +- } +- +- file_d = debugfs_create_file("rx_time_stats_str", 0400, dir_d, &nss_top_main, &nss_udp_st_rx_time_stats_strings_ops); +- if (!file_d) { +- nss_warning("Failed to create qca-nss-drv/stats/udp_st/rx_time_stats_str file"); +- goto fail; +- } +- +- file_d = debugfs_create_file("tx_time_stats_str", 0400, dir_d, &nss_top_main, &nss_udp_st_tx_time_stats_strings_ops); +- if (!file_d) { +- nss_warning("Failed to create qca-nss-drv/stats/udp_st/tx_time_stats_str file"); +- goto fail; +- } +- +- file_d = debugfs_create_file("timestamp_stats_str", 0400, dir_d, &nss_top_main, &nss_udp_st_timestamp_stats_strings_ops); +- if (!file_d) { +- nss_warning("Failed to create qca-nss-drv/stats/udp_st/timestamp_stats_str file"); +- goto fail; +- } +- return; +-fail: +- debugfs_remove_recursive(dir_d); +-} +--- a/nss_udp_st_strings.h ++++ /dev/null +@@ -1,29 +0,0 @@ +-/* +- ************************************************************************** +- * Copyright (c) 2021, The Linux Foundation. All rights reserved. +- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- ************************************************************************** +- */ +- +-#ifndef __NSS_UDP_ST_STRINGS_H +-#define __NSS_UDP_ST_STRINGS_H +- +-extern struct nss_stats_info nss_udp_st_strings_error_stats[NSS_UDP_ST_ERROR_MAX]; +-extern struct nss_stats_info nss_udp_st_strings_rx_time_stats[NSS_UDP_ST_STATS_TIME_MAX]; +-extern struct nss_stats_info nss_udp_st_strings_tx_time_stats[NSS_UDP_ST_STATS_TIME_MAX]; +-extern struct nss_stats_info nss_udp_st_strings_timestamp_stats[NSS_UDP_ST_STATS_TIMESTAMP_MAX]; +-extern void nss_udp_st_strings_dentry_create(void); +- +-#endif /* __NSS_UDP_ST_STRINGS_H */ +--- a/nss_vxlan.c ++++ b/nss_vxlan.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -226,7 +226,6 @@ bool nss_vxlan_unregister_if(uint32_t if + } + + nss_core_unregister_handler(nss_ctx, if_num); +- nss_core_unregister_msg_handler(nss_ctx, if_num); + nss_core_unregister_subsys_dp(nss_ctx, if_num); + return true; + } +--- a/nss_wifi_ext_vdev.c ++++ /dev/null +@@ -1,338 +0,0 @@ +-/* +- ************************************************************************** +- * Copyright (c) 2020, The Linux Foundation. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for any +- * purpose with or without fee is hereby granted, provided that the above +- * copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- ************************************************************************** +- */ +- +-#include "nss_tx_rx_common.h" +-#include "nss_wifi_ext_vdev_stats.h" +-#include "nss_wifi_ext_vdev_log.h" +- +-#define NSS_WIFI_EXT_VDEV_TX_TIMEOUT 3000 /* 3 seconds */ +- +-/* +- * Private data structure +- */ +-static struct nss_wifi_ext_vdev_pvt { +- struct semaphore sem; +- struct completion complete; +- int response; +- void *cb; +- void *app_data; +-} wifi_ext_vdev_pvt; +- +-/* +- * nss_wifi_ext_vdev_verify_if_num() +- * Verify if_num passed to us. +- */ +-static bool nss_wifi_ext_vdev_verify_if_num(uint32_t if_num) +-{ +- uint32_t type = nss_dynamic_interface_get_type(nss_wifi_ext_vdev_get_ctx(), if_num); +- +- switch (type) { +- case NSS_DYNAMIC_INTERFACE_TYPE_WIFI_EXT_VDEV_WDS: +- case NSS_DYNAMIC_INTERFACE_TYPE_WIFI_EXT_VDEV_VLAN: +- return true; +- default: +- return false; +- } +-} +- +-/* +- * nss_wifi_ext_vdev_handler() +- * Handle NSS -> HLOS messages for wifi_ext_vdev +- */ +-static void nss_wifi_ext_vdev_handler(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm, void *app_data) +-{ +- struct nss_wifi_ext_vdev_msg *nwevm = (struct nss_wifi_ext_vdev_msg *)ncm; +- void *ctx; +- +- nss_wifi_ext_vdev_msg_callback_t cb; +- +- NSS_VERIFY_CTX_MAGIC(nss_ctx); +- BUG_ON(!nss_wifi_ext_vdev_verify_if_num(ncm->interface)); +- +- /* +- * Trace Messages +- */ +- nss_wifi_ext_vdev_log_rx_msg(nwevm); +- +- /* +- * Is this a valid request/response packet? +- */ +- if (ncm->type >= NSS_WIFI_EXT_VDEV_MSG_MAX) { +- nss_warning("%px: received invalid message %d for WiFi extended VAP interface %d", nss_ctx, ncm->type, ncm->interface); +- return; +- } +- +- if (nss_cmn_get_msg_len(ncm) > sizeof(struct nss_wifi_ext_vdev_msg)) { +- nss_warning("%px: wifi_ext_vdev message length is invalid: %d", nss_ctx, ncm->len); +- return; +- } +- +- /* +- * Check messages +- */ +- switch (nwevm->cm.type) { +- case NSS_WIFI_EXT_VDEV_MSG_STATS_SYNC: +- nss_wifi_ext_vdev_stats_sync(nss_ctx, &nwevm->msg.stats, ncm->interface); +- break; +- } +- +- /* +- * Update the callback and app_data for NOTIFY messages +- */ +- if (ncm->response == NSS_CMN_RESPONSE_NOTIFY) { +- ncm->cb = (nss_ptr_t)nss_core_get_msg_handler(nss_ctx, ncm->interface); +- ncm->app_data = (nss_ptr_t)nss_ctx->subsys_dp_register[ncm->interface].app_data; +- } +- +- nss_core_log_msg_failures(nss_ctx, ncm); +- +- /* +- * callback +- */ +- cb = (nss_wifi_ext_vdev_msg_callback_t)ncm->cb; +- ctx = (void *)ncm->app_data; +- +- /* +- * call the callback +- */ +- if (!cb) { +- return; +- } +- +- cb(ctx, ncm); +-} +- +-/* +- * nss_wifi_ext_vdev_msg_init() +- * Initialize wifi message. +- */ +-void nss_wifi_ext_vdev_msg_init(struct nss_wifi_ext_vdev_msg *nim, uint32_t if_num, +- uint32_t type, uint32_t len, +- nss_wifi_ext_vdev_msg_callback_t cb, void *app_data) +-{ +- nss_cmn_msg_init(&nim->cm, if_num, type, len, cb, app_data); +-} +-EXPORT_SYMBOL(nss_wifi_ext_vdev_msg_init); +- +-/* +- * nss_wifi_ext_vdev_tx_msg() +- * Transmit a wifi vdev message to NSSFW +- */ +-nss_tx_status_t nss_wifi_ext_vdev_tx_msg(struct nss_ctx_instance *nss_ctx, struct nss_wifi_ext_vdev_msg *msg) +-{ +- struct nss_cmn_msg *ncm = &msg->cm; +- +- /* +- * Trace Messages +- */ +- nss_wifi_ext_vdev_log_tx_msg(msg); +- +- if (ncm->type >= NSS_WIFI_EXT_VDEV_MSG_MAX) { +- nss_warning("%px: wifi vdev message type out of range: %d", nss_ctx, ncm->type); +- return NSS_TX_FAILURE; +- } +- +- BUG_ON(!nss_wifi_ext_vdev_verify_if_num(ncm->interface)); +- +- return nss_core_send_cmd(nss_ctx, msg, sizeof(*msg), NSS_NBUF_PAYLOAD_SIZE); +-} +-EXPORT_SYMBOL(nss_wifi_ext_vdev_tx_msg); +- +-/* +- * nss_wifi_ext_vdev_callback() +- * Callback to handle the completion of NSS->HLOS messages. +- */ +-static void nss_wifi_ext_vdev_callback(void *app_data, struct nss_cmn_msg *ncm) +-{ +- nss_wifi_ext_vdev_msg_callback_t callback = (nss_wifi_ext_vdev_msg_callback_t)wifi_ext_vdev_pvt.cb; +- void *data = wifi_ext_vdev_pvt.app_data; +- +- wifi_ext_vdev_pvt.response = NSS_TX_SUCCESS; +- wifi_ext_vdev_pvt.cb = NULL; +- wifi_ext_vdev_pvt.app_data = NULL; +- +- if (ncm->response != NSS_CMN_RESPONSE_ACK) { +- nss_warning("WiFi extension vap Error response %d\n", ncm->response); +- wifi_ext_vdev_pvt.response = NSS_TX_FAILURE; +- } +- +- if (callback) { +- callback(data, ncm); +- } +- complete(&wifi_ext_vdev_pvt.complete); +-} +- +-/* +- * nss_wifi_ext_vdev_tx_msg() +- * Transmit a WiFi extended virtual interface to NSS firmware synchronously. +- */ +-nss_tx_status_t nss_wifi_ext_vdev_tx_msg_sync(struct nss_ctx_instance *nss_ctx, struct nss_wifi_ext_vdev_msg *nwevm) +-{ +- nss_tx_status_t status; +- int ret = 0; +- +- down(&wifi_ext_vdev_pvt.sem); +- wifi_ext_vdev_pvt.cb = (void *)nwevm->cm.cb; +- wifi_ext_vdev_pvt.app_data = (void *)nwevm->cm.app_data; +- +- nwevm->cm.cb = (nss_ptr_t)nss_wifi_ext_vdev_callback; +- nwevm->cm.app_data = (nss_ptr_t)NULL; +- +- status = nss_wifi_ext_vdev_tx_msg(nss_ctx, nwevm); +- if (status != NSS_TX_SUCCESS) { +- nss_warning("%px: wifi_ext_vdev_tx_msg failed\n", nss_ctx); +- up(&wifi_ext_vdev_pvt.sem); +- return status; +- } +- +- /* +- * Wait for the acknowledgement +- */ +- ret = wait_for_completion_timeout(&wifi_ext_vdev_pvt.complete, msecs_to_jiffies(NSS_WIFI_EXT_VDEV_TX_TIMEOUT)); +- if (!ret) { +- nss_warning("%px: WiFi extended vap msg tx failed due to timeout\n", nss_ctx); +- wifi_ext_vdev_pvt.response = NSS_TX_FAILURE; +- } +- +- status = wifi_ext_vdev_pvt.response; +- up(&wifi_ext_vdev_pvt.sem); +- return status; +-} +-EXPORT_SYMBOL(nss_wifi_ext_vdev_tx_msg_sync); +- +-/* +- * nss_wifi_ext_vdev_tx_buf +- * Send data packet for vap processing +- */ +-nss_tx_status_t nss_wifi_ext_vdev_tx_buf(struct nss_ctx_instance *nss_ctx, struct sk_buff *skb, uint32_t if_num) +-{ +- BUG_ON(!nss_wifi_ext_vdev_verify_if_num(if_num)); +- +- return nss_core_send_packet(nss_ctx, skb, if_num, H2N_BIT_FLAG_BUFFER_REUSABLE); +-} +-EXPORT_SYMBOL(nss_wifi_ext_vdev_tx_buf); +- +-/* +- * nss_wifi_ext_vdev_set_next_hop() +- * Set the WiFI extended vap next hop. +- */ +-nss_tx_status_t nss_wifi_ext_vdev_set_next_hop(struct nss_ctx_instance *ctx, int if_num, int next_hop) +-{ +- struct nss_wifi_ext_vdev_msg *nwevm = kzalloc(sizeof(struct nss_wifi_ext_vdev_msg), GFP_KERNEL); +- struct nss_wifi_ext_vdev_set_next_hop_msg *nhm = NULL; +- nss_tx_status_t status; +- +- if (!nwevm) { +- nss_warning("%px: Unable to allocate next hop message", ctx); +- return NSS_TX_FAILURE; +- } +- +- nhm = &nwevm->msg.wnhm; +- +- nhm->if_num = next_hop; +- nss_wifi_ext_vdev_msg_init(nwevm, if_num, NSS_WIFI_EXT_VDEV_SET_NEXT_HOP, +- sizeof(struct nss_wifi_ext_vdev_set_next_hop_msg), NULL, NULL); +- +- status = nss_wifi_ext_vdev_tx_msg(ctx, nwevm); +- if (status != NSS_TX_SUCCESS) { +- nss_warning("%px: Unable to send next hop message", ctx); +- } +- +- kfree(nwevm); +- return status; +-} +-EXPORT_SYMBOL(nss_wifi_ext_vdev_set_next_hop); +- +-/* +- * nss_get_wifi_ext_vdev_ext_context() +- * Return the core ctx which the feature is on +- */ +-struct nss_ctx_instance *nss_wifi_ext_vdev_get_ctx(void) +-{ +- return (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.wifi_handler_id]; +-} +-EXPORT_SYMBOL(nss_wifi_ext_vdev_get_ctx); +- +-/* +- * nss_wifi_ext_vdev_register_if() +- */ +-struct nss_ctx_instance *nss_wifi_ext_vdev_register_if(uint32_t if_num, +- nss_wifi_ext_vdev_data_callback_t data_callback, +- nss_wifi_ext_vdev_ext_data_callback_t ext_callback, +- nss_wifi_ext_vdev_msg_callback_t event_callback, +- struct net_device *netdev, +- uint32_t features, void *app_data) +-{ +- struct nss_ctx_instance *nss_ctx = nss_wifi_ext_vdev_get_ctx(); +- +- BUG_ON(!nss_wifi_ext_vdev_verify_if_num(if_num)); +- +- nss_core_register_subsys_dp(nss_ctx, if_num, data_callback, ext_callback, app_data, netdev, features); +- +- nss_core_register_msg_handler(nss_ctx, if_num, event_callback); +- +- nss_core_register_handler(nss_ctx, if_num, nss_wifi_ext_vdev_handler, app_data); +- +- nss_wifi_ext_vdev_stats_register(if_num, netdev); +- +- return nss_ctx; +-} +-EXPORT_SYMBOL(nss_wifi_ext_vdev_register_if); +- +-/* +- * nss_wifi_ext_vdev_unregister_if() +- */ +-bool nss_wifi_ext_vdev_unregister_if(uint32_t if_num) +-{ +- struct nss_ctx_instance *nss_ctx = nss_wifi_ext_vdev_get_ctx(); +- struct net_device *netdev; +- +- BUG_ON(!nss_wifi_ext_vdev_verify_if_num(if_num)); +- +- nss_assert(nss_ctx); +- +- netdev = nss_cmn_get_interface_dev(nss_ctx, if_num); +- if (!netdev) { +- nss_warning("%px: Unable to find net device for the interface %d\n", nss_ctx, if_num); +- return false; +- } +- nss_core_unregister_subsys_dp(nss_ctx, if_num); +- +- nss_core_unregister_msg_handler(nss_ctx, if_num); +- +- nss_core_unregister_handler(nss_ctx, if_num); +- +- nss_wifi_ext_vdev_stats_unregister(if_num, netdev); +- return true; +-} +-EXPORT_SYMBOL(nss_wifi_ext_vdev_unregister_if); +- +-/* +- * nss_wifi_ext_vdev_register_handler() +- * Register debugfs handler received on base interface +- */ +-void nss_wifi_ext_vdev_register_handler(void) +-{ +- struct nss_ctx_instance *nss_ctx = nss_wifi_ext_vdev_get_ctx(); +- +- nss_info("nss_wifi_ext_vdev_handler"); +- sema_init(&wifi_ext_vdev_pvt.sem, 1); +- init_completion(&wifi_ext_vdev_pvt.complete); +- nss_core_register_handler(nss_ctx, NSS_WIFI_EXT_VDEV_INTERFACE, nss_wifi_ext_vdev_handler, NULL); +- nss_wifi_ext_vdev_stats_dentry_create(); +-} +--- a/nss_wifi_ext_vdev_log.c ++++ /dev/null +@@ -1,220 +0,0 @@ +-/* +- ************************************************************************** +- * Copyright (c) 2020, The Linux Foundation. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for any +- * purpose with or without fee is hereby granted, provided that the above +- * copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- ************************************************************************** +- */ +- +-/* +- * nss_wifi_ext_vdev_log.c +- * NSS WiFi extended VAP logger file. +- */ +- +-#include "nss_core.h" +- +-#define NSS_WIFI_EXT_VDEV_LOG_MESSAGE_TYPE_INDEX(type) ((type) - NSS_IF_MAX_MSG_TYPES) +- +-/* +- * nss_wifi_ext_vdev_log_message_types_str +- * NSS WiFi extended VAP message strings +- */ +-static int8_t *nss_wifi_ext_vdev_log_message_types_str[NSS_WIFI_EXT_VDEV_MSG_MAX] __maybe_unused = { +- "WiFi Common I/F Message", +- "WiFi Extendev VAP configure", +- "WiFi Extendev VAP configure wds", +- "WiFi Extendev VAP configure next hop", +- "WiFi Extendev VAP stats", +- "WiFi Extended VAP configure VLAN" +-}; +- +-/* +- * nss_wifi_ext_vdev_log_configure_msg() +- * Log NSS WiFi extended vap configure message. +- */ +-static void nss_wifi_ext_vdev_log_configure_if_msg(struct nss_wifi_ext_vdev_msg *nwevm) +-{ +- struct nss_wifi_ext_vdev_configure_if_msg *cmsg __maybe_unused = &nwevm->msg.cmsg; +- nss_trace("%px: WiFi extended VAP configure message \n" +- "Mac address: %pM\n" +- "Radio interface num: %d\n" +- "Parent VAP interface num: %d\n", +- cmsg, cmsg->mac_addr, cmsg->radio_ifnum, +- cmsg->pvap_ifnum); +- +-} +- +-/* +- * nss_wifi_ext_vdev_log_wds_msg() +- * Log NSS WiFi extended vap wds message. +- */ +-static void nss_wifi_ext_vdev_log_wds_msg(struct nss_wifi_ext_vdev_msg *nwevm) +-{ +- struct nss_wifi_ext_vdev_wds_msg *wmsg __maybe_unused = &nwevm->msg.wmsg; +- nss_trace("%px: NSS WiFi extended VAP wds message: \n" +- "WDS sta ID: %d\n" +- "WDS sta macaddr: %pM\n", +- wmsg, wmsg->wds_peer_id, +- wmsg->mac_addr); +-} +- +-/* +- * nss_wifi_ext_vdev_set_nxt_hop_msg() +- * Set the next hop message. +- */ +-static void nss_wifi_ext_vdev_set_nxt_hop_msg(struct nss_wifi_ext_vdev_msg *nwevm) +-{ +- struct nss_wifi_ext_vdev_set_next_hop_msg *wnhm __maybe_unused = &nwevm->msg.wnhm; +- nss_trace("%px: NSS WiFi extended vap set next hop message: \n" +- "Next hop if num: %d\n", +- wnhm, wnhm->if_num); +- +-} +- +-/* +- * nss_wifi_ext_vdev_linkup_msg() +- * Log NSS linkup message. +- */ +-static void nss_wifi_ext_vdev_linkup_msg(struct nss_wifi_ext_vdev_msg *nwevm) +-{ +- union nss_if_msgs *if_msg __maybe_unused = &nwevm->msg.if_msg; +- nss_trace("%px: NSS WiFi ext linkup message\n", if_msg); +-} +- +-/* +- * nss_wifi_ext_vdev_linkdown_msg() +- * Log NSS linkdown message. +- */ +-static void nss_wifi_ext_vdev_linkdown_msg(struct nss_wifi_ext_vdev_msg *nwevm) +-{ +- union nss_if_msgs *if_msg __maybe_unused = &nwevm->msg.if_msg; +- nss_trace("%px: NSS WiFi ext linkdown message\n", if_msg); +-} +- +-/* +- * nss_wifi_ext_vdev_macaddr_set_msg() +- * Set/Change the mac address +- */ +-static void nss_wifi_ext_vdev_macaddr_set_msg(struct nss_wifi_ext_vdev_msg *nwevm) +-{ +- union nss_if_msgs *if_msg = &nwevm->msg.if_msg; +- struct nss_if_mac_address_set *nimas __maybe_unused = &if_msg->mac_address_set; +- nss_trace("%px: NSS WiFi ext change mac addr: \n" +- "mac addr %pM\n", +- nimas, nimas->mac_addr); +-} +- +-/* +- * nss_wifi_ext_vdev_log_vlan_msg() +- * Configure vlan message. +- */ +-static void nss_wifi_ext_vdev_log_vlan_msg(struct nss_wifi_ext_vdev_msg *nwevm) +-{ +- struct nss_wifi_ext_vdev_vlan_msg *vmsg __maybe_unused = &nwevm->msg.vmsg; +- nss_trace("%px: NSS WiFi extended VAP vlan message: \n" +- "vlan ID %hu\n", +- vmsg, vmsg->vlan_id); +-} +- +-/* +- * nss_wifi_ext_vdev_log_verbose() +- * Log message contents. +- */ +-static void nss_wifi_ext_vdev_log_verbose(struct nss_wifi_ext_vdev_msg *nwevm) +-{ +- switch (nwevm->cm.type) { +- case NSS_WIFI_EXT_VDEV_MSG_CONFIGURE_IF: +- nss_wifi_ext_vdev_log_configure_if_msg(nwevm); +- break; +- +- case NSS_WIFI_EXT_VDEV_MSG_CONFIGURE_WDS : +- nss_wifi_ext_vdev_log_wds_msg(nwevm); +- break; +- +- case NSS_WIFI_EXT_VDEV_SET_NEXT_HOP: +- nss_wifi_ext_vdev_set_nxt_hop_msg(nwevm); +- break; +- +- case NSS_WIFI_EXT_VDEV_MSG_STATS_SYNC: +- break; +- +- case NSS_IF_OPEN: +- nss_wifi_ext_vdev_linkup_msg(nwevm); +- break; +- +- case NSS_IF_CLOSE: +- nss_wifi_ext_vdev_linkdown_msg(nwevm); +- break; +- +- case NSS_IF_MAC_ADDR_SET: +- nss_wifi_ext_vdev_macaddr_set_msg(nwevm); +- break; +- +- case NSS_WIFI_EXT_VDEV_MSG_CONFIGURE_VLAN: +- nss_wifi_ext_vdev_log_vlan_msg(nwevm); +- break; +- +- default: +- nss_trace("%px: Invalid message type\n", nwevm); +- break; +- } +-} +- +-/* +- * nss_wifi_ext_vdev_log_tx_msg() +- * Log messages transmitted to FW. +- */ +-void nss_wifi_ext_vdev_log_tx_msg(struct nss_wifi_ext_vdev_msg *nwevm) +-{ +- uint32_t type_idx = 0; +- if (nwevm->cm.type >= NSS_WIFI_EXT_VDEV_MSG_MAX) { +- nss_warning("%px: Invalid message type\n", nwevm); +- return; +- } +- +- type_idx = (nwevm->cm.type > NSS_IF_MAX_MSG_TYPES) ? +- (NSS_WIFI_EXT_VDEV_LOG_MESSAGE_TYPE_INDEX(nwevm->cm.type)) : 0; +- +- nss_info("%px: type[%d]:%s\n", nwevm, nwevm->cm.type, nss_wifi_ext_vdev_log_message_types_str[type_idx]); +- nss_wifi_ext_vdev_log_verbose(nwevm); +-} +- +-/* +- * nss_wifi_ext_vdev_log_rx_msg() +- * Log messages received from FW. +- */ +-void nss_wifi_ext_vdev_log_rx_msg(struct nss_wifi_ext_vdev_msg *nwevm) +-{ +- uint32_t type_idx = 0; +- if (nwevm->cm.response >= NSS_CMN_RESPONSE_LAST) { +- nss_warning("%px: Invalid response\n", nwevm); +- return; +- } +- +- type_idx = (nwevm->cm.type > NSS_IF_MAX_MSG_TYPES) ? +- (NSS_WIFI_EXT_VDEV_LOG_MESSAGE_TYPE_INDEX(nwevm->cm.type)) : 0; +- +- if (nwevm->cm.response == NSS_CMN_RESPONSE_NOTIFY || (nwevm->cm.response == NSS_CMN_RESPONSE_ACK)) { +- nss_info("%px: type[%d]:%s, response[%d]:%s\n", nwevm, nwevm->cm.type, +- nss_wifi_ext_vdev_log_message_types_str[type_idx], +- nwevm->cm.response, nss_cmn_response_str[nwevm->cm.response]); +- goto verbose; +- } +- +- nss_info("%px: msg nack - type[%d]:%s, response[%d]:%s\n", +- nwevm, nwevm->cm.type, nss_wifi_ext_vdev_log_message_types_str[type_idx], +- nwevm->cm.response, nss_cmn_response_str[nwevm->cm.response]); +- +-verbose: +- nss_wifi_ext_vdev_log_verbose(nwevm); +-} +--- a/nss_wifi_ext_vdev_log.h ++++ /dev/null +@@ -1,34 +0,0 @@ +-/* +- ************************************************************************** +- * Copyright (c) 2020, The Linux Foundation. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for any +- * purpose with or without fee is hereby granted, provided that the above +- * copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- ************************************************************************** +- */ +- +-#ifndef __NSS_WIFI_EXT_VDEV_LOG_H +-#define __NSS_WIFI_EXT_VDEV_LOG_H +- +-/* +- * nss_wifi_ext_vdev_log_tx_msg +- * Logs a wifi_ext_vdev message that is sent to the NSS firmware. +- */ +-void nss_wifi_ext_vdev_log_tx_msg(struct nss_wifi_ext_vdev_msg *nwevm); +- +-/* +- * nss_wifi_ext_vdev_log_rx_msg +- * Logs a wifi_ext_vdev message that is received from the NSS firmware. +- */ +-void nss_wifi_ext_vdev_log_rx_msg(struct nss_wifi_ext_vdev_msg *nwevm); +- +-#endif /* __NSS_WIFI_EXT_VDEV_LOG_H */ +--- a/nss_wifi_ext_vdev_stats.c ++++ /dev/null +@@ -1,234 +0,0 @@ +-/* +- ************************************************************************** +- * Copyright (c) 2020, The Linux Foundation. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for any +- * purpose with or without fee is hereby granted, provided that the above +- * copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- ************************************************************************** +- */ +- +-#include "nss_tx_rx_common.h" +-#include "nss_wifi_ext_vdev_stats.h" +- +-DEFINE_SPINLOCK(nss_wifi_ext_vdev_debug_lock); +-struct nss_wifi_ext_vdev_debug nss_wifi_ext_vdev_debug_stats[NSS_WIFI_EXT_VDEV_MAX]; +- +-/* +- * nss_wifi_ext_vdev_debug_str +- * WiFi extended VAP statistics strings. +- */ +-struct nss_stats_info nss_wifi_ext_vdev_debug_str[NSS_WIFI_EXT_VDEV_STATS_MAX] = { +- {"node_rx_pkts" , NSS_STATS_TYPE_COMMON}, +- {"node_rx_bytes" , NSS_STATS_TYPE_COMMON}, +- {"node_tx_pkts" , NSS_STATS_TYPE_COMMON}, +- {"node_tx_bytes" , NSS_STATS_TYPE_COMMON}, +- {"node_rx_dropped" , NSS_STATS_TYPE_DROP}, +- {"mc_count" , NSS_STATS_TYPE_SPECIAL}, +- {"uc_count" , NSS_STATS_TYPE_SPECIAL}, +- {"nxt_hop_drop" , NSS_STATS_TYPE_DROP}, +-}; +- +-/* +- * WiFi extended vdev statistics APIs +- */ +- +-/* +- * nss_wifi_ext_vdev_stats_register() +- * Register debug statistic for WiFi extended VAP. +- */ +-void nss_wifi_ext_vdev_stats_register(uint32_t if_num, struct net_device *netdev) +-{ +- int i; +- +- spin_lock_bh(&nss_wifi_ext_vdev_debug_lock); +- for (i = 0; i < NSS_WIFI_EXT_VDEV_MAX; i++) { +- if (!nss_wifi_ext_vdev_debug_stats[i].valid) { +- nss_wifi_ext_vdev_debug_stats[i].valid = true; +- nss_wifi_ext_vdev_debug_stats[i].if_num = if_num; +- nss_wifi_ext_vdev_debug_stats[i].if_index = netdev->ifindex; +- break; +- } +- } +- +- spin_unlock_bh(&nss_wifi_ext_vdev_debug_lock); +-} +- +-/* +- * nss_wifi_ext_vdev_stats_unregister() +- * Register debug statistic for WiFi extended vap. +- */ +-void nss_wifi_ext_vdev_stats_unregister(uint32_t if_num, struct net_device *netdev) +-{ +- int i; +- +- spin_lock_bh(&nss_wifi_ext_vdev_debug_lock); +- for (i = 0; i < NSS_WIFI_EXT_VDEV_MAX; i++) { +- if (nss_wifi_ext_vdev_debug_stats[i].if_num == if_num) { +- memset(&nss_wifi_ext_vdev_debug_stats[i], 0, +- sizeof(struct nss_wifi_ext_vdev_debug)); +- break; +- } +- } +- spin_unlock_bh(&nss_wifi_ext_vdev_debug_lock); +-} +- +-/* +- * nss_wifi_ext_vdev_stats_sync() +- * Sync function for WiFi extendev vap statistics. +- */ +-void nss_wifi_ext_vdev_stats_sync(struct nss_ctx_instance *nss_ctx, struct nss_wifi_ext_vdev_stats *stats_msg, +- uint16_t if_num) +-{ +- int i; +- struct nss_wifi_ext_vdev_debug *s = NULL; +- +- NSS_VERIFY_CTX_MAGIC(nss_ctx); +- +- spin_lock_bh(&nss_wifi_ext_vdev_debug_lock); +- for (i = 0; i < NSS_WIFI_EXT_VDEV_MAX; i++) { +- if (nss_wifi_ext_vdev_debug_stats[i].if_num == if_num) { +- s = &nss_wifi_ext_vdev_debug_stats[i]; +- break; +- } +- } +- +- if (!s) { +- spin_unlock_bh(&nss_wifi_ext_vdev_debug_lock); +- nss_warning("%px: Interface:%u not found", nss_ctx, if_num); +- return; +- } +- +- s->stats[NSS_WIFI_EXT_VDEV_STATS_NODE_RX_PKTS ] += stats_msg->node_stats.rx_packets; +- s->stats[NSS_WIFI_EXT_VDEV_STATS_NODE_RX_BYTES] += stats_msg->node_stats.rx_bytes; +- s->stats[NSS_WIFI_EXT_VDEV_STATS_NODE_TX_PKTS] += stats_msg->node_stats.tx_packets; +- s->stats[NSS_WIFI_EXT_VDEV_STATS_NODE_TX_BYTES] += stats_msg->node_stats.tx_bytes; +- for (i = 0; i < NSS_MAX_NUM_PRI; i++) { +- s->stats[NSS_WIFI_EXT_VDEV_STATS_NODE_TOTAL_DROPPED] += stats_msg->node_stats.rx_dropped[i]; +- } +- s->stats[NSS_WIFI_EXT_VDEV_STATS_MULTICAST_COUNT] += stats_msg->mc_count; +- s->stats[NSS_WIFI_EXT_VDEV_STATS_UNICAST_COUNT] += stats_msg->node_stats.rx_packets - stats_msg->mc_count; +- s->stats[NSS_WIFI_EXT_VDEV_STATS_NEXT_HOP_DROP_COUNT] += stats_msg->nxt_hop_drp; +- spin_unlock_bh(&nss_wifi_ext_vdev_debug_lock); +-} +- +-/* +- * nss_wifi_ext_vdev_debug_get() +- * Get WiFi extendev vap debug statitics. +- */ +-static void nss_wifi_ext_vdev_debug_get(struct nss_wifi_ext_vdev_debug *stats) +-{ +- int i; +- +- if (!stats) { +- nss_warning("No memory to copy WiFi extended VAP stats"); +- return; +- } +- +- spin_lock_bh(&nss_wifi_ext_vdev_debug_lock); +- for (i = 0; i < NSS_WIFI_EXT_VDEV_MAX; i++) { +- if (nss_wifi_ext_vdev_debug_stats[i].valid) { +- memcpy(stats, &nss_wifi_ext_vdev_debug_stats[i], +- sizeof(struct nss_wifi_ext_vdev_debug)); +- stats++; +- } +- } +- spin_unlock_bh(&nss_wifi_ext_vdev_debug_lock); +-} +- +-/* +- * nss_wifi_ext_vdev_read() +- * Read WiFi extended VAP statistics +- */ +-static ssize_t nss_wifi_ext_vdev_stats_read(struct file *fp, char __user *ubuf, +- size_t sz, loff_t *ppos) +-{ +- uint32_t max_output_lines = 2 /* header and footer of the interface stats*/ +- + (NSS_WIFI_EXT_VDEV_STATS_MAX * (NSS_WIFI_EXT_VDEV_MAX + 2)) /* Interface stats */ +- + 2; +- +- size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines; +- size_t size_wr = 0; +- size_t bytes_read = 0; +- struct net_device *dev; +- int id; +- struct nss_wifi_ext_vdev_debug *wifi_ext_vdev_stats = NULL; +- +- char *lbuf = kzalloc(size_al, GFP_KERNEL); +- if (unlikely(lbuf == NULL)) { +- nss_warning("Could not allocate memory for local statistics buffer"); +- return 0; +- } +- +- wifi_ext_vdev_stats = kzalloc((sizeof(struct nss_wifi_ext_vdev_debug) * NSS_WIFI_EXT_VDEV_MAX), GFP_KERNEL); +- if (unlikely(wifi_ext_vdev_stats == NULL)) { +- nss_warning("Could not allocate memory for populating stats"); +- kfree(lbuf); +- return 0; +- } +- +- /* +- * Get all stats +- */ +- nss_wifi_ext_vdev_debug_get(wifi_ext_vdev_stats); +- +- /* +- * WiFi extended vap stats. +- */ +- size_wr += nss_stats_banner(lbuf, size_wr, size_al, "WiFi extended VAP stats", NSS_STATS_SINGLE_CORE); +- +- for (id = 0; id < NSS_WIFI_EXT_VDEV_MAX; id++) { +- if (!wifi_ext_vdev_stats[id].valid) { +- continue; +- } +- +- dev = dev_get_by_index(&init_net, wifi_ext_vdev_stats[id].if_index); +- if (likely(dev)) { +- size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, +- "%d. nss interface id=%d, netdevice=%s\n", +- id, wifi_ext_vdev_stats[id].if_num, +- dev->name); +- dev_put(dev); +- } else { +- size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, +- "%d. nss interface id=%d\n", id, +- wifi_ext_vdev_stats[id].if_num); +- } +- +- size_wr += nss_stats_print("vdev", "debug", id +- , nss_wifi_ext_vdev_debug_str +- , wifi_ext_vdev_stats[id].stats +- , NSS_WIFI_EXT_VDEV_STATS_MAX +- , lbuf, size_wr, size_al); +- +- size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\n"); +- } +- +- bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, size_wr); +- +- kfree(wifi_ext_vdev_stats); +- kfree(lbuf); +- return bytes_read; +-} +- +-/* +- * nss_wifi_ext_vdev_ops +- */ +-NSS_STATS_DECLARE_FILE_OPERATIONS(wifi_ext_vdev); +- +-/* +- * nss_wifi_ext_vdev_dentry_create() +- * Create wifi extension vap statistics debug entry. +- */ +-void nss_wifi_ext_vdev_stats_dentry_create(void) +-{ +- nss_stats_create_dentry("wifi_ext_vdev", &nss_wifi_ext_vdev_stats_ops); +-} +--- a/nss_wifi_ext_vdev_stats.h ++++ /dev/null +@@ -1,60 +0,0 @@ +-/* +- ****************************************************************************** +- * Copyright (c) 2020, The Linux Foundation. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for any +- * purpose with or without fee is hereby granted, provided that the above +- * copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- * **************************************************************************** +- */ +- +-#ifndef __NSS_WIFI_EXT_VDEV_STATS_H +-#define __NSS_WIFI_EXT_VDEV_STATS_H +- +-/* +- * WiFi extendev vap debug statistic counters. +- */ +-enum nss_wifi_ext_vdev_stats_types { +- NSS_WIFI_EXT_VDEV_STATS_NODE_RX_PKTS, +- NSS_WIFI_EXT_VDEV_STATS_NODE_RX_BYTES, +- NSS_WIFI_EXT_VDEV_STATS_NODE_TX_PKTS, +- NSS_WIFI_EXT_VDEV_STATS_NODE_TX_BYTES, +- NSS_WIFI_EXT_VDEV_STATS_NODE_TOTAL_DROPPED, +- NSS_WIFI_EXT_VDEV_STATS_MULTICAST_COUNT, +- NSS_WIFI_EXT_VDEV_STATS_UNICAST_COUNT, +- NSS_WIFI_EXT_VDEV_STATS_NEXT_HOP_DROP_COUNT, +- NSS_WIFI_EXT_VDEV_STATS_MAX, +-}; +- +-/* +- * WiFi extendev vap debug statistics. +- */ +-struct nss_wifi_ext_vdev_debug { +- uint64_t stats[NSS_WIFI_EXT_VDEV_STATS_MAX]; +- int32_t if_index; /**< Netdevice's ifindex. */ +- uint32_t if_num; /**< NSS interface number. */ +- bool valid; /**< Is node valid ? */ +-}; +- +-/* +- * Data structures to store WiFi extended VAP debug stats. +- */ +-extern struct nss_wifi_ext_vdev_debug nss_wifi_ext_vdev_debug_stats[NSS_WIFI_EXT_VDEV_MAX]; +- +-/* +- * WiFi extendev vap statistics APIs +- */ +-extern void nss_wifi_ext_vdev_stats_register(uint32_t if_num, struct net_device *netdev); +-extern void nss_wifi_ext_vdev_stats_unregister(uint32_t if_num, struct net_device *netdev); +-extern void nss_wifi_ext_vdev_stats_sync(struct nss_ctx_instance *nss_ctx, struct nss_wifi_ext_vdev_stats *stats_msg, uint16_t if_num); +-extern void nss_wifi_ext_vdev_stats_dentry_create(void); +- +-#endif /* __NSS_WIFI_EXT_VDEV_STATS_H */ +--- /dev/null ++++ b/nss_wifi_if.c +@@ -0,0 +1,516 @@ ++/* ++ ************************************************************************** ++ * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. ++ * Permission to use, copy, modify, and/or distribute this software for ++ * any purpose with or without fee is hereby granted, provided that the ++ * above copyright notice and this permission notice appear in all copies. ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT ++ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ************************************************************************** ++ */ ++ ++/* ++ * nss_wifi_if.c ++ * NSS wifi/redirect handler APIs ++ */ ++ ++#include "nss_tx_rx_common.h" ++#include "nss_wifi_if_stats.h" ++#include ++ ++#define NSS_WIFI_IF_TX_TIMEOUT 3000 /* 3 Seconds */ ++#define NSS_WIFI_IF_GET_INDEX(if_num) (if_num-NSS_DYNAMIC_IF_START) ++ ++extern int nss_ctl_redirect; ++ ++/* ++ * Data structure that holds the wifi interface context. ++ */ ++struct nss_wifi_if_handle *wifi_handle[NSS_MAX_DYNAMIC_INTERFACES]; ++ ++/* ++ * Spinlock to protect the global data structure wifi_handle. ++ */ ++DEFINE_SPINLOCK(wifi_if_lock); ++ ++/* ++ * nss_wifi_if_msg_handler() ++ * Handle NSS -> HLOS messages for wifi interface ++ */ ++static void nss_wifi_if_msg_handler(struct nss_ctx_instance *nss_ctx, ++ struct nss_cmn_msg *ncm, ++ __attribute__((unused))void *app_data) ++{ ++ struct nss_wifi_if_msg *nwim = (struct nss_wifi_if_msg *)ncm; ++ int32_t if_num; ++ ++ nss_wifi_if_msg_callback_t cb; ++ struct nss_wifi_if_handle *handle = NULL; ++ ++ /* ++ * Sanity check the message type ++ */ ++ if (ncm->type >= NSS_WIFI_IF_MAX_MSG_TYPES) { ++ nss_warning("%px: message type out of range: %d", ++ nss_ctx, ncm->type); ++ return; ++ } ++ ++ if (nss_cmn_get_msg_len(ncm) > sizeof(struct nss_wifi_if_msg)) { ++ nss_warning("%px: Length of message is greater than required: %d", nss_ctx, nss_cmn_get_msg_len(ncm)); ++ return; ++ } ++ ++ if (!NSS_IS_IF_TYPE(DYNAMIC, ncm->interface)) { ++ nss_warning("%px: response for another interface: %d", nss_ctx, ncm->interface); ++ return; ++ } ++ ++ /* ++ * Log failures ++ */ ++ nss_core_log_msg_failures(nss_ctx, ncm); ++ ++ if_num = NSS_WIFI_IF_GET_INDEX(ncm->interface); ++ ++ spin_lock_bh(&wifi_if_lock); ++ if (!wifi_handle[if_num]) { ++ spin_unlock_bh(&wifi_if_lock); ++ nss_warning("%px: wifi_if handle is NULL\n", nss_ctx); ++ return; ++ } ++ ++ handle = wifi_handle[if_num]; ++ spin_unlock_bh(&wifi_if_lock); ++ ++ switch (nwim->cm.type) { ++ case NSS_WIFI_IF_STATS_SYNC_MSG: ++ nss_wifi_if_stats_sync(handle, &nwim->msg.stats); ++ break; ++ } ++ ++ /* ++ * Update the callback and app_data for NOTIFY messages. ++ */ ++ if (nwim->cm.response == NSS_CMN_RESPONSE_NOTIFY) { ++ ncm->cb = (nss_ptr_t)handle->cb; ++ ncm->app_data = (nss_ptr_t)handle->app_data; ++ } ++ ++ /* ++ * Do we have a callback? ++ */ ++ if (!ncm->cb) { ++ nss_warning("cb is NULL\n"); ++ return; ++ } ++ ++ /* ++ * Callback ++ */ ++ cb = (nss_wifi_if_msg_callback_t)ncm->cb; ++ cb((void *)ncm->app_data, ncm); ++} ++ ++/* ++ * nss_wifi_if_register_handler() ++ * Register the message handler & initialize semaphore & completion for the * interface if_num ++ */ ++static uint32_t nss_wifi_if_register_handler(struct nss_wifi_if_handle *handle) ++{ ++ struct nss_ctx_instance *nss_ctx = &nss_top_main.nss[nss_top_main.wlan_handler_id]; ++ uint32_t ret; ++ struct nss_wifi_if_pvt *nwip = NULL; ++ int32_t if_num = handle->if_num; ++ ++ ret = nss_core_register_handler(nss_ctx, if_num, nss_wifi_if_msg_handler, NULL); ++ ++ if (ret != NSS_CORE_STATUS_SUCCESS) { ++ nss_warning("%d: Message handler failed to be registered for interface ret %d\n", if_num, ret); ++ return NSS_WIFI_IF_CORE_FAILURE; ++ } ++ ++ nwip = handle->pvt; ++ if (!nwip->sem_init_done) { ++ sema_init(&nwip->sem, 1); ++ init_completion(&nwip->complete); ++ nwip->sem_init_done = 1; ++ } ++ ++ nss_wifi_if_stats_dentry_create(); ++ return NSS_WIFI_IF_SUCCESS; ++} ++ ++/* ++ * nss_wifi_if_callback ++ * Callback to handle the completion of NSS->HLOS messages. ++ */ ++static void nss_wifi_if_callback(void *app_data, struct nss_cmn_msg *ncm) ++{ ++ struct nss_wifi_if_handle *handle = (struct nss_wifi_if_handle *)app_data; ++ struct nss_wifi_if_pvt *nwip = handle->pvt; ++ ++ if (ncm->response != NSS_CMN_RESPONSE_ACK) { ++ nss_warning("%px: wifi_if Error response %d\n", ++ handle->nss_ctx, ncm->response); ++ nwip->response = NSS_TX_FAILURE; ++ complete(&nwip->complete); ++ return; ++ } ++ ++ nwip->response = NSS_TX_SUCCESS; ++ complete(&nwip->complete); ++} ++ ++/* ++ * nss_wifi_if_tx_msg() ++ * Send a message from HLOS to NSS asynchronously. ++ */ ++nss_tx_status_t nss_wifi_if_tx_msg(struct nss_ctx_instance *nss_ctx, struct nss_wifi_if_msg *nwim) ++{ ++ struct nss_cmn_msg *ncm = &nwim->cm; ++ ++ if (ncm->type > NSS_WIFI_IF_MAX_MSG_TYPES) { ++ nss_warning("%px: message type out of range: %d\n", nss_ctx, ncm->type); ++ return NSS_TX_FAILURE; ++ } ++ ++ return nss_core_send_cmd(nss_ctx, nwim, sizeof(*nwim), NSS_NBUF_PAYLOAD_SIZE); ++} ++ ++/* ++ * nss_wifi_if_tx_msg_sync ++ * Send a message from HLOS to NSS synchronously. ++ */ ++static nss_tx_status_t nss_wifi_if_tx_msg_sync(struct nss_wifi_if_handle *handle, ++ struct nss_wifi_if_msg *nwim) ++{ ++ nss_tx_status_t status; ++ int ret = 0; ++ struct nss_wifi_if_pvt *nwip = handle->pvt; ++ struct nss_ctx_instance *nss_ctx = handle->nss_ctx; ++ ++ down(&nwip->sem); ++ ++ status = nss_wifi_if_tx_msg(nss_ctx, nwim); ++ if (status != NSS_TX_SUCCESS) { ++ nss_warning("%px: nss_wifi_if_msg failed\n", nss_ctx); ++ up(&nwip->sem); ++ return status; ++ } ++ ++ ret = wait_for_completion_timeout(&nwip->complete, ++ msecs_to_jiffies(NSS_WIFI_IF_TX_TIMEOUT)); ++ if (!ret) { ++ nss_warning("%px: wifi_if tx failed due to timeout\n", nss_ctx); ++ nwip->response = NSS_TX_FAILURE; ++ } ++ ++ status = nwip->response; ++ up(&nwip->sem); ++ ++ return status; ++} ++ ++/* ++ * nss_wifi_if_handle_destroy() ++ * Destroy the wifi handle either due to request from WLAN or due to error. ++ */ ++static int nss_wifi_if_handle_destroy(struct nss_wifi_if_handle *handle) ++{ ++ int32_t if_num; ++ int32_t index; ++ struct nss_ctx_instance *nss_ctx; ++ nss_tx_status_t status; ++ ++ if (!handle) { ++ nss_warning("Destroy failed as wifi_if handle is NULL\n"); ++ return NSS_TX_FAILURE_BAD_PARAM; ++ } ++ ++ if_num = handle->if_num; ++ index = NSS_WIFI_IF_GET_INDEX(if_num); ++ nss_ctx = handle->nss_ctx; ++ ++ spin_lock_bh(&wifi_if_lock); ++ wifi_handle[index] = NULL; ++ spin_unlock_bh(&wifi_if_lock); ++ ++ status = nss_dynamic_interface_dealloc_node(if_num, NSS_DYNAMIC_INTERFACE_TYPE_WIFI); ++ if (status != NSS_TX_SUCCESS) { ++ nss_warning("%px: Dynamic interface destroy failed status %d\n", nss_ctx, status); ++ return status; ++ } ++ ++ kfree(handle->pvt); ++ kfree(handle); ++ ++ return status; ++} ++ ++/* ++ * nss_wifi_if_handle_init() ++ * Initialize wifi handle which holds the if_num and stats per interface. ++ */ ++static struct nss_wifi_if_handle *nss_wifi_if_handle_create(struct nss_ctx_instance *nss_ctx, ++ int32_t *cmd_rsp) ++{ ++ int32_t index; ++ int32_t if_num = 0; ++ struct nss_wifi_if_handle *handle; ++ ++ if_num = nss_dynamic_interface_alloc_node(NSS_DYNAMIC_INTERFACE_TYPE_WIFI); ++ if (if_num < 0) { ++ nss_warning("%px:failure allocating wifi if\n", nss_ctx); ++ *cmd_rsp = NSS_WIFI_IF_DYNAMIC_IF_FAILURE; ++ return NULL; ++ } ++ ++ index = NSS_WIFI_IF_GET_INDEX(if_num); ++ ++ handle = (struct nss_wifi_if_handle *)kzalloc(sizeof(struct nss_wifi_if_handle), ++ GFP_KERNEL); ++ if (!handle) { ++ nss_warning("%px: handle memory alloc failed\n", nss_ctx); ++ *cmd_rsp = NSS_WIFI_IF_ALLOC_FAILURE; ++ goto error1; ++ } ++ ++ handle->nss_ctx = nss_ctx; ++ handle->if_num = if_num; ++ handle->pvt = (struct nss_wifi_if_pvt *)kzalloc(sizeof(struct nss_wifi_if_pvt), ++ GFP_KERNEL); ++ if (!handle->pvt) { ++ nss_warning("%px: failure allocating memory for nss_wifi_if_pvt\n", nss_ctx); ++ *cmd_rsp = NSS_WIFI_IF_ALLOC_FAILURE; ++ goto error2; ++ } ++ ++ handle->cb = NULL; ++ handle->app_data = NULL; ++ ++ spin_lock_bh(&wifi_if_lock); ++ wifi_handle[index] = handle; ++ spin_unlock_bh(&wifi_if_lock); ++ ++ *cmd_rsp = NSS_WIFI_IF_SUCCESS; ++ ++ return handle; ++ ++error2: ++ kfree(handle); ++error1: ++ nss_dynamic_interface_dealloc_node(if_num, NSS_DYNAMIC_INTERFACE_TYPE_WIFI); ++ return NULL; ++} ++ ++/* nss_wifi_if_msg_init() ++ * Initialize wifi specific message structure. ++ */ ++static void nss_wifi_if_msg_init(struct nss_wifi_if_msg *nwim, ++ uint16_t if_num, ++ uint32_t type, ++ uint32_t len, ++ nss_wifi_if_msg_callback_t cb, ++ struct nss_wifi_if_handle *app_data) ++{ ++ nss_cmn_msg_init(&nwim->cm, if_num, type, len, (void *)cb, (void *)app_data); ++} ++ ++/* ++ * nss_wifi_if_create_sync() ++ * Create a wifi interface and associate it with the netdev ++ */ ++struct nss_wifi_if_handle *nss_wifi_if_create_sync(struct net_device *netdev) ++{ ++ struct nss_ctx_instance *nss_ctx = &nss_top_main.nss[nss_top_main.wlan_handler_id]; ++ struct nss_wifi_if_msg nwim; ++ struct nss_wifi_if_create_msg *nwcm; ++ uint32_t ret; ++ struct nss_wifi_if_handle *handle = NULL; ++ ++ if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) { ++ nss_warning("%px: Interface could not be created as core not ready\n", nss_ctx); ++ return NULL; ++ } ++ ++ handle = nss_wifi_if_handle_create(nss_ctx, &ret); ++ if (!handle) { ++ nss_warning("%px:wifi_if handle creation failed ret %d\n", nss_ctx, ret); ++ return NULL; ++ } ++ ++ /* Initializes the semaphore and also sets the msg handler for if_num */ ++ ret = nss_wifi_if_register_handler(handle); ++ if (ret != NSS_WIFI_IF_SUCCESS) { ++ nss_warning("%px: Registration handler failed reason: %d\n", nss_ctx, ret); ++ goto error; ++ } ++ ++ nss_wifi_if_msg_init(&nwim, handle->if_num, NSS_WIFI_IF_TX_CREATE_MSG, ++ sizeof(struct nss_wifi_if_create_msg), nss_wifi_if_callback, handle); ++ ++ nwcm = &nwim.msg.create; ++ nwcm->flags = 0; ++ memcpy(nwcm->mac_addr, netdev->dev_addr, ETH_ALEN); ++ ++ ret = nss_wifi_if_tx_msg_sync(handle, &nwim); ++ if (ret != NSS_TX_SUCCESS) { ++ nss_warning("%px: nss_wifi_if_tx_msg_sync failed %u\n", nss_ctx, ret); ++ goto error; ++ } ++ ++ nss_core_register_subsys_dp(nss_ctx, handle->if_num, NULL, NULL, NULL, netdev, 0); ++ ++ /* ++ * Hold a reference to the net_device ++ */ ++ dev_hold(netdev); ++ ++ /* ++ * The context returned is the interface # which is, essentially, the index into the if_ctx ++ * array that is holding the net_device pointer ++ */ ++ ++ return handle; ++ ++error: ++ nss_wifi_if_handle_destroy(handle); ++ return NULL; ++} ++EXPORT_SYMBOL(nss_wifi_if_create_sync); ++ ++/* ++ * nss_wifi_if_destroy_sync() ++ * Destroy the wifi interface associated with the interface number. ++ */ ++nss_tx_status_t nss_wifi_if_destroy_sync(struct nss_wifi_if_handle *handle) ++{ ++ nss_tx_status_t status; ++ struct net_device *dev; ++ int32_t if_num = handle->if_num; ++ struct nss_ctx_instance *nss_ctx = handle->nss_ctx; ++ ++ if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) { ++ nss_warning("%px: Interface could not be destroyed as core not ready\n", nss_ctx); ++ return NSS_TX_FAILURE_NOT_READY; ++ } ++ ++ spin_lock_bh(&nss_top_main.lock); ++ if (!nss_ctx->subsys_dp_register[if_num].ndev) { ++ spin_unlock_bh(&nss_top_main.lock); ++ nss_warning("%px: Unregister wifi interface %d: no context\n", nss_ctx, if_num); ++ return NSS_TX_FAILURE_BAD_PARAM; ++ } ++ ++ dev = nss_ctx->subsys_dp_register[if_num].ndev; ++ nss_core_unregister_subsys_dp(nss_ctx, if_num); ++ spin_unlock_bh(&nss_top_main.lock); ++ dev_put(dev); ++ ++ status = nss_wifi_if_handle_destroy(handle); ++ return status; ++} ++EXPORT_SYMBOL(nss_wifi_if_destroy_sync); ++ ++/* ++ * nss_wifi_if_register() ++ * Register cb, netdev associated with the if_num to the nss data plane ++ * to receive data packets. ++ */ ++void nss_wifi_if_register(struct nss_wifi_if_handle *handle, ++ nss_wifi_if_data_callback_t rx_callback, ++ struct net_device *netdev) ++{ ++ struct nss_ctx_instance *nss_ctx; ++ int32_t if_num; ++ ++ if (!handle) { ++ nss_warning("nss_wifi_if_register handle is NULL\n"); ++ return; ++ } ++ ++ nss_ctx = handle->nss_ctx; ++ if_num = handle->if_num; ++ nss_assert(NSS_IS_IF_TYPE(DYNAMIC, if_num)); ++ ++ nss_core_register_subsys_dp(nss_ctx, if_num, rx_callback, NULL, NULL, netdev, netdev->features); ++} ++EXPORT_SYMBOL(nss_wifi_if_register); ++ ++/* ++ * nss_wifi_if_unregister() ++ * Unregister the cb, netdev associated with the if_num. ++ */ ++void nss_wifi_if_unregister(struct nss_wifi_if_handle *handle) ++{ ++ struct nss_ctx_instance *nss_ctx; ++ int32_t if_num; ++ ++ if (!handle) { ++ nss_warning("nss_wifi_if_unregister handle is NULL\n"); ++ return; ++ } ++ ++ nss_ctx = handle->nss_ctx; ++ if_num = handle->if_num; ++ ++ nss_core_unregister_subsys_dp(nss_ctx, if_num); ++} ++EXPORT_SYMBOL(nss_wifi_if_unregister); ++ ++/* ++ * nss_wifi_if_tx_buf() ++ * HLOS interface has received a packet which we redirect to the NSS. ++ */ ++nss_tx_status_t nss_wifi_if_tx_buf(struct nss_wifi_if_handle *handle, ++ struct sk_buff *skb) ++{ ++ struct nss_ctx_instance *nss_ctx; ++ int32_t if_num; ++ int cpu = 0; ++ ++ if (!handle) { ++ nss_warning("nss_wifi_if_tx_buf handle is NULL\n"); ++ return NSS_TX_FAILURE; ++ } ++ ++ nss_ctx = handle->nss_ctx; ++ if_num = handle->if_num; ++ ++ /* ++ * redirect should be turned on in /proc/ ++ */ ++ if (unlikely(nss_ctl_redirect == 0)) { ++ return NSS_TX_FAILURE_NOT_ENABLED; ++ } ++ ++ if (unlikely(skb->vlan_tci)) { ++ return NSS_TX_FAILURE_NOT_SUPPORTED; ++ } ++ ++ nss_assert(NSS_IS_IF_TYPE(DYNAMIC, if_num)); ++ ++ /* ++ * Sanity check the SKB to ensure that it's suitable for us ++ */ ++ if (unlikely(skb->len <= ETH_HLEN)) { ++ nss_warning("%px: Rx packet: %px too short", nss_ctx, skb); ++ return NSS_TX_FAILURE_TOO_SHORT; ++ } ++ ++ /* ++ * set skb queue mapping ++ */ ++ cpu = get_cpu(); ++ put_cpu(); ++ skb_set_queue_mapping(skb, cpu); ++ ++ return nss_core_send_packet(nss_ctx, skb, if_num, H2N_BIT_FLAG_VIRTUAL_BUFFER); ++} ++EXPORT_SYMBOL(nss_wifi_if_tx_buf); +--- /dev/null ++++ b/nss_wifi_if_stats.c +@@ -0,0 +1,210 @@ ++/* ++ ************************************************************************** ++ * Copyright (c) 2016-2017, 2019 The Linux Foundation. All rights reserved. ++ * Permission to use, copy, modify, and/or distribute this software for ++ * any purpose with or without fee is hereby granted, provided that the ++ * above copyright notice and this permission notice appear in all copies. ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT ++ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ************************************************************************** ++ */ ++ ++#include "nss_core.h" ++#include "nss_wifi_if.h" ++ ++/* ++ * Data structure that holds the wifi interface context. ++ */ ++extern struct nss_wifi_if_handle *wifi_handle[]; ++ ++/* ++ * Spinlock to protect the global data structure wifi_handle. ++ */ ++extern spinlock_t wifi_if_lock; ++ ++/* ++ * nss_wifi_if_stats_get() ++ * Get the stats from wifi handle to buffer(line) for if_num. ++ */ ++static int32_t nss_wifi_if_stats_get(int32_t if_num, int i, char *line) ++{ ++ int32_t bytes = 0; ++ struct nss_wifi_if_stats *stats; ++ int32_t ifnum; ++ uint32_t len = 80; ++ struct nss_wifi_if_handle *handle = NULL; ++ ++ ifnum = if_num - NSS_DYNAMIC_IF_START; ++ ++ spin_lock_bh(&wifi_if_lock); ++ if (!wifi_handle[ifnum]) { ++ spin_unlock_bh(&wifi_if_lock); ++ goto end; ++ } ++ ++ handle = wifi_handle[ifnum]; ++ spin_unlock_bh(&wifi_if_lock); ++ stats = &handle->stats; ++ ++ switch (i) { ++ case 0: ++ bytes = scnprintf(line, len, "rx_packets=%d\n", ++ stats->node_stats.rx_packets); ++ break; ++ ++ case 1: ++ bytes = scnprintf(line, len, "rx_bytes=%d\n", ++ stats->node_stats.rx_bytes); ++ break; ++ ++ case 2: ++ bytes = scnprintf(line, len, "rx_dropped=%d\n", ++ nss_cmn_rx_dropped_sum(&stats->node_stats)); ++ break; ++ ++ case 3: ++ bytes = scnprintf(line, len, "tx_packets=%d\n", ++ stats->node_stats.tx_packets); ++ break; ++ ++ case 4: ++ bytes = scnprintf(line, len, "tx_bytes=%d\n", ++ stats->node_stats.tx_bytes); ++ break; ++ ++ case 5: ++ bytes = scnprintf(line, len, "tx_enqueue_failed=%d\n", ++ stats->tx_enqueue_failed); ++ break; ++ ++ case 6: ++ bytes = scnprintf(line, len, "shaper_enqueue_failed=%d\n", ++ stats->shaper_enqueue_failed); ++ break; ++ } ++ ++end: ++ return bytes; ++} ++ ++/* ++ * nss_wifi_if_stats_read() ++ * Read wifi_if statistics ++ */ ++static ssize_t nss_wifi_if_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) ++{ ++ struct nss_stats_data *data = fp->private_data; ++ struct nss_ctx_instance *nss_ctx = (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.wifi_handler_id]; ++ int32_t if_num = NSS_DYNAMIC_IF_START; ++ int32_t max_if_num = if_num + NSS_MAX_DYNAMIC_INTERFACES; ++ size_t bytes = 0; ++ ssize_t bytes_read = 0; ++ char line[80]; ++ int start, end; ++ ++ if (data) { ++ if_num = data->if_num; ++ } ++ ++ if (if_num > max_if_num) { ++ return 0; ++ } ++ ++ for (; if_num < max_if_num; if_num++) { ++ if (nss_dynamic_interface_get_type(nss_ctx, if_num) != NSS_DYNAMIC_INTERFACE_TYPE_WIFI) ++ continue; ++ ++ bytes = scnprintf(line, sizeof(line), "if_num %d stats start:\n\n", if_num); ++ if ((bytes_read + bytes) > sz) ++ break; ++ ++ if (copy_to_user(ubuf + bytes_read, line, bytes) != 0) { ++ bytes_read = -EFAULT; ++ goto end; ++ } ++ ++ bytes_read += bytes; ++ ++ start = 0; ++ end = 7; ++ while (bytes_read < sz && start < end) { ++ bytes = nss_wifi_if_stats_get(if_num, start, line); ++ if (!bytes) ++ break; ++ ++ if ((bytes_read + bytes) > sz) ++ break; ++ ++ if (copy_to_user(ubuf + bytes_read, line, bytes) != 0) { ++ bytes_read = -EFAULT; ++ goto end; ++ } ++ ++ bytes_read += bytes; ++ start++; ++ } ++ ++ bytes = scnprintf(line, sizeof(line), "if_num %d stats end:\n\n", if_num); ++ if (bytes_read > (sz - bytes)) ++ break; ++ ++ if (copy_to_user(ubuf + bytes_read, line, bytes) != 0) { ++ bytes_read = -EFAULT; ++ goto end; ++ } ++ ++ bytes_read += bytes; ++ } ++ ++ if (bytes_read > 0) { ++ *ppos = bytes_read; ++ } ++ ++ if (data) { ++ data->if_num = if_num; ++ } ++ ++end: ++ return bytes_read; ++} ++ ++/* ++ * nss_wifi_if_stats_ops ++ */ ++NSS_STATS_DECLARE_FILE_OPERATIONS(wifi_if) ++ ++/* ++ * nss_wifi_if_stats_dentry_create() ++ * Create wifi_if statistics debug entry. ++ */ ++void nss_wifi_if_stats_dentry_create(void) ++{ ++ nss_stats_create_dentry("wifi_if", &nss_wifi_if_stats_ops); ++} ++ ++/* ++ * nss_wifi_if_stats_sync() ++ * Sync stats from the NSS FW ++ */ ++void nss_wifi_if_stats_sync(struct nss_wifi_if_handle *handle, ++ struct nss_wifi_if_stats *nwis) ++{ ++ struct nss_wifi_if_stats *stats = &handle->stats; ++ int i; ++ ++ stats->node_stats.rx_packets += nwis->node_stats.rx_packets; ++ stats->node_stats.rx_bytes += nwis->node_stats.rx_bytes; ++ ++ for (i = 0; i < NSS_MAX_NUM_PRI; i++) { ++ stats->node_stats.rx_dropped[i] += nwis->node_stats.rx_dropped[i]; ++ } ++ stats->node_stats.tx_packets += nwis->node_stats.tx_packets; ++ stats->node_stats.tx_bytes += nwis->node_stats.tx_bytes; ++ stats->tx_enqueue_failed += nwis->tx_enqueue_failed; ++ stats->shaper_enqueue_failed += nwis->shaper_enqueue_failed; ++} +--- a/nss_tls_strings.h ++++ /dev/null +@@ -1,27 +0,0 @@ +-/* +- ****************************************************************************** +- * Copyright (c) 2021, The Linux Foundation. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- ****************************************************************************** +- */ +- +-#ifndef __NSS_TLS_STRINGS_H +-#define __NSS_TLS_STRINGS_H +- +-#include "nss_tls_stats.h" +- +-extern struct nss_stats_info nss_tls_strings_stats[NSS_TLS_STATS_MAX]; +-extern void nss_tls_strings_dentry_create(void); +- +-#endif /* __NSS_TLS_STRINGS_H */ +--- /dev/null ++++ b/nss_wifi_if_stats.h +@@ -0,0 +1,26 @@ ++/* ++ ****************************************************************************** ++ * Copyright (c) 2017, The Linux Foundation. All rights reserved. ++ * Permission to use, copy, modify, and/or distribute this software for ++ * any purpose with or without fee is hereby granted, provided that the ++ * above copyright notice and this permission notice appear in all copies. ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT ++ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ * **************************************************************************** ++ */ ++ ++#ifndef __NSS_WIFI_IF_STATS_H ++#define __NSS_WIFI_IF_STATS_H ++ ++/* ++ * wifi interface statistics APIs ++ */ ++extern void nss_wifi_if_stats_sync(struct nss_wifi_if_handle *handle, struct nss_wifi_if_stats *nwis); ++extern void nss_wifi_if_stats_dentry_create(void); ++ ++#endif /* __NSS_WIFI_IF_STATS_H */ +--- a/nss_wifi_mac_db.c ++++ b/nss_wifi_mac_db.c +@@ -19,21 +19,9 @@ + #include "nss_core.h" + #include "nss_wifi_mac_db_if.h" + +-/* +- * Compile time assertion. +- */ +-#define NSS_WIFI_MAC_DB_COMPILE_TIME_ASSERT(assertion_name, predicate) \ +- typedef char assertion_name[(predicate) ? 1 : -1] +- + #define NSS_WIFI_MAC_DB_TX_TIMEOUT 1000 /* Millisecond to jiffies*/ + + /* +- * Validate the Wi-Fi MAC database message size not exceeding buffer size. +- */ +-NSS_WIFI_MAC_DB_COMPILE_TIME_ASSERT(NSS_WIFI_MAC_DB_MAX_BUF_MSG, +- (sizeof(struct nss_wifi_mac_db_msg) < NSS_NBUF_PAYLOAD_SIZE)); +- +-/* + * nss_wifi_mac_db_get_context() + */ + struct nss_ctx_instance *nss_wifi_mac_db_get_context(void) +--- a/nss_wifi_mesh.c ++++ /dev/null +@@ -1,242 +0,0 @@ +-/* +- ************************************************************************** +- * Copyright (c) 2021, The Linux Foundation. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for any +- * purpose with or without fee is hereby granted, provided that the above +- * copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- ************************************************************************** +- */ +- +-#include "nss_tx_rx_common.h" +-#include "nss_core.h" +-#include "nss_cmn.h" +-#include "nss_wifi_mesh.h" +-#include "nss_wifi_mesh_log.h" +-#include "nss_wifi_mesh_strings.h" +- +-/* +- * nss_wifi_mesh_verify_if_num() +- * Verify interface number. +- */ +-bool nss_wifi_mesh_verify_if_num(nss_if_num_t if_num) +-{ +- enum nss_dynamic_interface_type if_type = nss_dynamic_interface_get_type(nss_wifi_mesh_get_context(), if_num); +- +- return ((if_type == NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER) || +- (if_type == NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_OUTER)); +-} +-EXPORT_SYMBOL(nss_wifi_mesh_verify_if_num); +- +-/* nss_wifi_mesh_handler() +- * Handles Wi-Fi mesh messages from NSS to HLOS. +- */ +-static void nss_wifi_mesh_handler(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm, void *app_data) +-{ +- nss_wifi_mesh_msg_callback_t cb; +- struct nss_wifi_mesh_msg *nwmm = (struct nss_wifi_mesh_msg *)ncm; +- +- NSS_VERIFY_CTX_MAGIC(nss_ctx); +- nss_assert(nss_is_dynamic_interface(ncm->interface)); +- nss_assert(nss_wifi_mesh_verify_if_num(ncm->interface)); +- +- /* +- * Is this a valid request/response packet? +- */ +- if (ncm->type >= NSS_WIFI_MESH_MSG_MAX) { +- nss_warning("%px: Received invalid message %d for wifi_mesh interface\n", nss_ctx, ncm->type); +- return; +- } +- +- +- /* +- * For variable array the size of the common length will be greater the nss_wifi_mesh_msg +- * length. Add conditional checking for messages where length check will fail. +- */ +- if ((nss_cmn_get_msg_len(ncm) > sizeof(struct nss_wifi_mesh_msg)) && +- (ncm->type != NSS_WIFI_MESH_MSG_PATH_TABLE_DUMP) && +- (ncm->type != NSS_WIFI_MESH_MSG_PROXY_PATH_TABLE_DUMP)) { +- nss_warning("%px: Length of message is greater than expected, type: %d, len: %d", +- nss_ctx, ncm->type, ncm->len); +- return; +- } +- +- /* +- * Log failures +- */ +- nss_core_log_msg_failures(nss_ctx, ncm); +- +- /* +- * Trace Messages +- */ +- nss_wifi_mesh_log_rx_msg(nwmm); +- +- /* +- * Update the stats and send statistics notifications to the registered modules. +- */ +- if (nwmm->cm.type == NSS_WIFI_MESH_MSG_STATS_SYNC) { +- nss_wifi_mesh_update_stats(ncm->interface, &nwmm->msg.stats_sync_msg); +- nss_wifi_mesh_stats_notify(ncm->interface, nss_ctx->id); +- } +- +- if (ncm->response == NSS_CMN_RESPONSE_NOTIFY) { +- ncm->cb = (nss_ptr_t)nss_core_get_msg_handler(nss_ctx, ncm->interface); +- ncm->app_data = (nss_ptr_t)app_data; +- } +- +- if (!ncm->cb) { +- return; +- } +- +- cb = (nss_wifi_mesh_msg_callback_t)ncm->cb; +- cb((void *)ncm->app_data, ncm); +-} +- +-/* +- * nss_wifi_mesh_msg_init() +- * Initiliaze a Wi-Fi mesh message. +- */ +-void nss_wifi_mesh_msg_init(struct nss_wifi_mesh_msg *nwm, nss_if_num_t if_num, uint32_t type, uint32_t len, +- nss_wifi_mesh_msg_callback_t cb, void *app_data) +-{ +- nss_assert(nss_wifi_mesh_verify_if_num(if_num)); +- nss_cmn_msg_init(&nwm->cm, if_num, type, len, cb, app_data); +-} +-EXPORT_SYMBOL(nss_wifi_mesh_msg_init); +- +-/* +- * nss_wifi_mesh_tx_buf +- * Send data packet for vap processing asynchronously. +- */ +-nss_tx_status_t nss_wifi_mesh_tx_buf(struct nss_ctx_instance *nss_ctx, struct sk_buff *os_buf, nss_if_num_t if_num) +-{ +- nss_assert(nss_is_dynamic_interface(if_num)); +- return nss_core_send_packet(nss_ctx, os_buf, if_num, H2N_BIT_FLAG_BUFFER_REUSABLE); +-} +-EXPORT_SYMBOL(nss_wifi_mesh_tx_buf); +- +-/* +- * nss_wifi_mesh_tx_msg +- * Transmit a Wi-Fi mesh message to the NSS firmware asynchronously. +- * +- * NOTE: The caller is expected to handle synchronous waiting for message +- * response if needed. +- */ +-nss_tx_status_t nss_wifi_mesh_tx_msg(struct nss_ctx_instance *nss_ctx, struct nss_wifi_mesh_msg *msg) +-{ +- struct nss_cmn_msg *ncm = &msg->cm; +- +- NSS_VERIFY_CTX_MAGIC(nss_ctx); +- +- if (ncm->type >= NSS_WIFI_MESH_MSG_MAX) { +- nss_warning("%px: wifi_mesh message type out of range: %d\n", nss_ctx, ncm->type); +- return NSS_TX_FAILURE; +- } +- +- /* +- * Log messages. +- */ +- nss_wifi_mesh_log_tx_msg(msg); +- +- /* +- * The interface number shall be one of the Wi-Fi mesh socket interfaces. +- */ +- nss_assert(nss_is_dynamic_interface(ncm->interface)); +- +- return nss_core_send_cmd(nss_ctx, msg, sizeof(*msg), NSS_NBUF_PAYLOAD_SIZE); +-} +-EXPORT_SYMBOL(nss_wifi_mesh_tx_msg); +- +-/* +- **************************************** +- * Register/Unregister/Miscellaneous APIs +- **************************************** +- */ +- +-/* +- * nss_wifi_mesh_get_context() +- * Return the core ctx which the feature is on. +- */ +-struct nss_ctx_instance *nss_wifi_mesh_get_context(void) +-{ +- return (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.wifi_handler_id]; +-} +-EXPORT_SYMBOL(nss_wifi_mesh_get_context); +- +-/* +- * nss_unregister_wifi_mesh_if() +- * Unregister Wi-Fi mesh from the NSS driver. +- */ +-void nss_unregister_wifi_mesh_if(nss_if_num_t if_num) +-{ +- struct nss_ctx_instance *nss_ctx = nss_wifi_mesh_get_context(); +- +- NSS_VERIFY_CTX_MAGIC(nss_ctx); +- +- nss_core_unregister_subsys_dp(nss_ctx, if_num); +- nss_core_unregister_msg_handler(nss_ctx, if_num); +- nss_core_unregister_handler(nss_ctx, if_num); +- nss_wifi_mesh_stats_handle_free(if_num); +-} +-EXPORT_SYMBOL(nss_unregister_wifi_mesh_if); +- +-/* +- * nss_register_wifi_mesh_if() +- * Register wifi_mesh with nss driver. +- */ +-uint32_t nss_register_wifi_mesh_if(nss_if_num_t if_num, +- nss_wifi_mesh_data_callback_t mesh_data_callback, +- nss_wifi_mesh_ext_data_callback_t mesh_ext_data_callback, +- nss_wifi_mesh_msg_callback_t mesh_event_callback, +- uint32_t dp_type, struct net_device *netdev, uint32_t features) +-{ +- struct nss_ctx_instance *nss_ctx = nss_wifi_mesh_get_context(); +- uint32_t status; +- +- NSS_VERIFY_CTX_MAGIC(nss_ctx); +- nss_assert(netdev); +- nss_assert(nss_wifi_mesh_verify_if_num(if_num)); +- +- if (!nss_wifi_mesh_stats_handle_alloc(if_num, netdev->ifindex)) { +- nss_warning("%px: couldn't allocate stats handle for device name: %s, if_num: 0x%x\n", nss_ctx, netdev->name, if_num); +- return NSS_CORE_STATUS_FAILURE; +- } +- +- nss_core_register_handler(nss_ctx, if_num, nss_wifi_mesh_handler, netdev); +- +- status = nss_core_register_msg_handler(nss_ctx, if_num, mesh_event_callback); +- if (status != NSS_CORE_STATUS_SUCCESS) { +- nss_warning("%px: unable to register event handler for interface(%u)\n", nss_ctx, if_num); +- nss_core_unregister_handler(nss_ctx, if_num); +- nss_wifi_mesh_stats_handle_free(if_num); +- return status; +- } +- +- nss_core_register_subsys_dp(nss_ctx, if_num, mesh_data_callback, mesh_ext_data_callback, NULL, netdev, features); +- nss_core_set_subsys_dp_type(nss_ctx, netdev, if_num, dp_type); +- return NSS_CORE_STATUS_SUCCESS; +-} +-EXPORT_SYMBOL(nss_register_wifi_mesh_if); +- +-/* +- * nss_wifi_mesh_init() +- * Initialize the mesh stats dentries. +- */ +-void nss_wifi_mesh_init(void) +-{ +- if (!nss_wifi_mesh_strings_dentry_create()) { +- nss_warning("Unable to create dentry for Wi-Fi mesh strings\n"); +- } +- +- if (!nss_wifi_mesh_stats_dentry_create()) { +- nss_warning("Unable to create dentry for Wi-Fi mesh stats\n"); +- } +-} +--- a/nss_wifi_mesh_log.c ++++ /dev/null +@@ -1,387 +0,0 @@ +-/* +- ************************************************************************** +- * Copyright (c) 2021, The Linux Foundation. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for any +- * purpose with or without fee is hereby granted, provided that the above +- * copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- ************************************************************************** +- */ +- +-/* +- * nss_wifi_mesh_log.c +- * NSS WiFi Mesh logger file. +- */ +- +-#include "nss_core.h" +-#include "nss_wifi_mesh.h" +- +-#define NSS_WIFI_MESH_LOG_MESSAGE_TYPE_INDEX(type) ((type) - NSS_IF_MAX_MSG_TYPES) +- +-/* +- * nss_wifi_mesh_log_message_types_str +- * NSS Wi-Fi mesh message strings. +- */ +-static uint8_t *nss_wifi_mesh_log_message_types_str[NSS_WIFI_MESH_LOG_MESSAGE_TYPE_INDEX(NSS_WIFI_MESH_MSG_MAX)] __maybe_unused = { +- "WiFi Mesh configure", +- "WiFi Mesh configure Mpath Add", +- "WiFi Mesh configure Mpath Delete", +- "WiFi Mesh configure Mpath Update", +- "WiFi Mesh configure Proxy Learn", +- "WiFi Mesh configure Proxy Add", +- "WiFi Mesh configure Proxy Update", +- "WiFi Mesh configure Proxy Delete", +- "WiFi Mesh configure Mpath Not Found", +- "WiFi Mesh configure Refresh" +- "WiFi Mesh configure Mpath Table Dump", +- "WiFi Mesh configure Proxy Path Table Dump", +- "WiFi Mesh configure Assoc Link Vap", +- "WiFi Mesh configure Exception Message", +- "WiFi Mesh configure Rate limit message", +- "WiFi Mesh configure Stats Sync" +-}; +- +-/* +- * nss_wifi_mesh_log_configure_msg() +- * Log a NSS Wi-Fi mesh interface configure message. +- */ +-static void nss_wifi_mesh_log_configure_if_msg(struct nss_wifi_mesh_msg *nwmm) +-{ +- struct nss_wifi_mesh_config_msg *cmsg __maybe_unused = &nwmm->msg.mesh_config; +- nss_trace("%px: WiFi Mesh configure message\n" +- "Local Mac address: %pM\n" +- "TTL: %d\n" +- "Mesh Path Refresh Time: %d\n" +- "Mpp Learning Mode: %d\n" +- "Block Mesh Forwarding: %d\n" +- "Configs Flags: 0x%x\n", +- cmsg, cmsg->local_mac_addr, cmsg->ttl, +- cmsg->mesh_path_refresh_time, +- cmsg->mpp_learning_mode, +- cmsg->block_mesh_forwarding, +- cmsg->config_flags); +-} +- +-/* +- * nss_wifi_mesh_log_mpath_add_msg() +- * Log a NSS Wi-Fi mesh mpath add message. +- */ +-static void nss_wifi_mesh_log_mpath_add_msg(struct nss_wifi_mesh_msg *nwmm) +-{ +- struct nss_wifi_mesh_mpath_add_msg *mamsg __maybe_unused = &nwmm->msg.mpath_add; +- nss_trace("%px: NSS WiFi Mesh Mpath add message:\n" +- "Dest Mac address: %pM\n" +- "Next Hop Mac address: %pM\n" +- "Metric: %d\n" +- "Expiry Time: %d\n" +- "Hop Count: %d\n" +- "Flags: 0x%x\n" +- "Link Vap id: %d\n" +- "Is Mesh Gate: %d\n", +- mamsg, mamsg->dest_mac_addr, mamsg->next_hop_mac_addr, +- mamsg->metric, mamsg->expiry_time, mamsg->hop_count, +- mamsg->path_flags, mamsg->link_vap_id, mamsg->is_mesh_gate); +-} +- +-/* +- * nss_wifi_mesh_log_mpath_delete_msg() +- * Log a NSS Wi-Fi mesh mpath delete message. +- */ +-static void nss_wifi_mesh_log_mpath_delete_msg(struct nss_wifi_mesh_msg *nwmm) +-{ +- struct nss_wifi_mesh_mpath_del_msg *mdmsg __maybe_unused = &nwmm->msg.mpath_del; +- nss_trace("%px: NSS WiFi Mesh Mpath delete message:\n" +- "Dest Mac Address: %pM\n" +- "Link Vap id: %d\n" +- "Next Hop Mac address: %pM\n", +- mdmsg, mdmsg->mesh_dest_mac_addr, mdmsg->link_vap_id, mdmsg->next_hop_mac_addr); +-} +- +-/* +- * nss_wifi_mesh_log_mpath_update_msg() +- * Log a NSS Wi-Fi mesh mpath update message. +- */ +-static void nss_wifi_mesh_log_mpath_update_msg(struct nss_wifi_mesh_msg *nwmm) +-{ +- struct nss_wifi_mesh_mpath_update_msg *mumsg __maybe_unused = &nwmm->msg.mpath_update; +- nss_trace("%px: NSS WiFi Mesh Mpath update message:\n" +- "Dest Mac address: %pM\n" +- "Next Hop Mac address: %pM\n" +- "Metric: %d\n" +- "Expiry Time: %d\n" +- "Hop Count: %d\n" +- "Flags: 0x%x\n" +- "Link Vap id: %d\n" +- "Is Mesh Gate: %d\n" +- "Update Flags: %d\n", +- mumsg, mumsg->dest_mac_addr, mumsg->next_hop_mac_addr, +- mumsg->metric, mumsg->expiry_time, mumsg->hop_count, +- mumsg->path_flags, mumsg->link_vap_id, mumsg->is_mesh_gate, +- mumsg->update_flags); +-} +- +-/* +- * nss_wifi_mesh_log_proxy_path_learn_msg() +- * Log a NSS Wi-Fi mesh proxy path learn message. +- */ +-static void nss_wifi_mesh_log_proxy_path_learn_msg(struct nss_wifi_mesh_msg *nwmm) +-{ +- struct nss_wifi_mesh_proxy_path_learn_msg *pplm __maybe_unused = &nwmm->msg.proxy_learn_msg; +- nss_trace("%px: NSS WiFi Mesh Proxy Path Learn message:\n" +- "Mesh Dest Mac address: %pM\n" +- "Destination Mac address: %pM\n" +- "flags: 0x%x\n", +- pplm, pplm->mesh_dest_mac, pplm->dest_mac_addr, +- pplm->path_flags); +-} +- +-/* +- * nss_wifi_mesh_log_proxy_path_add_msg() +- * Log a NSS Wi-Fi Mesh proxy path add message. +- */ +-static void nss_wifi_mesh_log_proxy_path_add_msg(struct nss_wifi_mesh_msg *nwmm) +-{ +- struct nss_wifi_mesh_proxy_path_add_msg *ppam __maybe_unused = &nwmm->msg.proxy_add_msg; +- nss_trace("%px: NSS WiFi Mesh Proxy Path Add message:\n" +- "Mesh Dest Mac address: %pM\n" +- "Destination Mac address: %pM\n" +- "flags: 0x%x\n", +- ppam, ppam->mesh_dest_mac, ppam->dest_mac_addr, +- ppam->path_flags); +-} +- +-/* +- * nss_wifi_mesh_log_proxy_path_delete_msg() +- * Log a NSS Wi-Fi proxy path delete message. +- */ +-static void nss_wifi_mesh_log_proxy_path_delete_msg(struct nss_wifi_mesh_msg *nwmm) +-{ +- struct nss_wifi_mesh_proxy_path_del_msg *ppdm __maybe_unused = &nwmm->msg.proxy_del_msg; +- nss_trace("%px: NSS WiFi Mesh Proxy Path Delete message:\n" +- "Mesh Dest Mac address: %pM\n" +- "Destination Mac address: %pM\n", +- ppdm, ppdm->mesh_dest_mac_addr, ppdm->dest_mac_addr); +-} +- +-/* +- * nss_wifi_mesh_log_proxy_path_update_msg() +- * Log a NSS Wi-Fi mesh proxy path update message. +- */ +-static void nss_wifi_mesh_log_proxy_path_update_msg(struct nss_wifi_mesh_msg *nwmm) +-{ +- struct nss_wifi_mesh_proxy_path_update_msg *ppum __maybe_unused = &nwmm->msg.proxy_update_msg; +- nss_trace("%px: NSS WiFi Mesh Proxy Path Add message:\n" +- "Mesh Dest Mac address: %pM\n" +- "Destination Mac address: %pM\n" +- "flags: 0x%x\n" +- "Bitmap: %d\n", +- ppum, ppum->mesh_dest_mac, ppum->dest_mac_addr, +- ppum->path_flags, ppum->bitmap); +-} +- +-/* +- * nss_wifi_mesh_log_mpath_not_found_msg() +- * Log a NSS Wi-Fi mesh mpath not found message. +- */ +-static void nss_wifi_mesh_log_mpath_not_found_msg(struct nss_wifi_mesh_msg *nwmm) +-{ +- struct nss_wifi_mesh_mpath_not_found_msg *mnfm __maybe_unused = &nwmm->msg.mpath_not_found_msg; +- nss_trace("%px: NSS WiFi Mesh Mpath not found message:\n" +- "Destination Mac address: %pM\n" +- "Transmitter Mac address: %pM\n" +- "Link Vap Id: %d\n" +- "Is Mesh Forwarding Path: %d\n", +- mnfm, mnfm->dest_mac_addr, mnfm->transmitter_mac_addr, +- mnfm->link_vap_id, mnfm->is_mesh_forward_path); +-} +- +-/* +- * nss_wifi_mesh_log_mpath_refresh_msg() +- * Log a NSS Wi-Fi mesh mpath refresh message. +- */ +-static void nss_wifi_mesh_log_mpath_refresh_msg(struct nss_wifi_mesh_msg *nwmm) +-{ +- struct nss_wifi_mesh_path_refresh_msg *mprm __maybe_unused = &nwmm->msg.path_refresh_msg; +- nss_trace("%px: NSS WiFi Mesh Mpath refresh message:\n" +- "Destination Mac address: %pM\n" +- "Next Hop Mac address: %pM\n" +- "Flags: 0x%x\n" +- "Link Vap Id: %d\n", +- mprm, mprm->dest_mac_addr, mprm->next_hop_mac_addr, +- mprm->path_flags, mprm->link_vap_id); +-} +- +-/* +- * nss_wifi_mesh_log_mpath_expiry_msg() +- * Log a NSS Wi-Fi mesh mpath expiry message. +- */ +-static void nss_wifi_mesh_log_mpath_expiry_msg(struct nss_wifi_mesh_msg *nwmm) +-{ +- struct nss_wifi_mesh_path_expiry_msg *mpem __maybe_unused = &nwmm->msg.path_expiry_msg; +- nss_trace("%px: NSS WiFi Mesh Mpath expiry message:\n" +- "Destination Mac address: %pM\n" +- "Next Hop Mac address: %pM\n" +- "Flags: 0x%x\n" +- "Link Vap Id: %d\n", +- mpem, mpem->mesh_dest_mac_addr, mpem->next_hop_mac_addr, +- mpem->path_flags, mpem->link_vap_id); +-} +- +-/* +- * nss_wifi_mesh_log_exception_flag_msg() +- * Log a NSS Wi-Fi mesh exception flag message. +- */ +-static void nss_wifi_mesh_log_exception_flag_msg(struct nss_wifi_mesh_msg *nwmm) +-{ +- struct nss_wifi_mesh_exception_flag_msg *efm __maybe_unused = &nwmm->msg.exception_msg; +- nss_trace("%px: NSS WiFi Mesh Exception Flag message:\n" +- "Destination Mac address: %pM\n", +- efm, efm->dest_mac_addr); +-} +- +-/* +- * nss_wifi_mesh_log_rate_limit_config() +- * Log a NSS Wi-Fi mesh rate limit config message. +- */ +-static void nss_wifi_mesh_log_rate_limit_config(struct nss_wifi_mesh_msg *nwmm) +-{ +- struct nss_wifi_mesh_rate_limit_config *rlcm __maybe_unused = &nwmm->msg.exc_cfg; +- nss_trace("%px: NSS WiFi Mesh rate limit config message:\n" +- "exception_num : %d\n" +- "enable : %d\n" +- "rate_limit : %d\n", +- rlcm, rlcm->exception_num, rlcm->enable, rlcm->rate_limit); +-} +- +-/* +- * nss_wifi_mesh_log_verbose() +- * Log message contents. +- */ +-static void nss_wifi_mesh_log_verbose(struct nss_wifi_mesh_msg *nwmm) +-{ +- switch (nwmm->cm.type) { +- case NSS_WIFI_MESH_MSG_INTERFACE_CONFIGURE: +- nss_wifi_mesh_log_configure_if_msg(nwmm); +- break; +- +- case NSS_WIFI_MESH_MSG_MPATH_ADD: +- nss_wifi_mesh_log_mpath_add_msg(nwmm); +- break; +- +- case NSS_WIFI_MESH_MSG_MPATH_DELETE: +- nss_wifi_mesh_log_mpath_delete_msg(nwmm); +- break; +- +- case NSS_WIFI_MESH_MSG_MPATH_UPDATE: +- nss_wifi_mesh_log_mpath_update_msg(nwmm); +- break; +- +- case NSS_WIFI_MESH_MSG_PROXY_PATH_LEARN: +- nss_wifi_mesh_log_proxy_path_learn_msg(nwmm); +- break; +- +- case NSS_WIFI_MESH_MSG_PROXY_PATH_ADD: +- nss_wifi_mesh_log_proxy_path_add_msg(nwmm); +- break; +- +- case NSS_WIFI_MESH_MSG_PROXY_PATH_DELETE: +- nss_wifi_mesh_log_proxy_path_delete_msg(nwmm); +- break; +- +- case NSS_WIFI_MESH_MSG_PROXY_PATH_UPDATE: +- nss_wifi_mesh_log_proxy_path_update_msg(nwmm); +- break; +- +- case NSS_WIFI_MESH_MSG_PATH_NOT_FOUND: +- nss_wifi_mesh_log_mpath_not_found_msg(nwmm); +- break; +- +- case NSS_WIFI_MESH_MSG_PATH_REFRESH: +- nss_wifi_mesh_log_mpath_refresh_msg(nwmm); +- break; +- +- case NSS_WIFI_MESH_MSG_PATH_EXPIRY: +- nss_wifi_mesh_log_mpath_expiry_msg(nwmm); +- break; +- +- case NSS_WIFI_MESH_MSG_PATH_TABLE_DUMP: +- break; +- +- case NSS_WIFI_MESH_MSG_PROXY_PATH_TABLE_DUMP: +- break; +- +- case NSS_WIFI_MESH_MSG_STATS_SYNC: +- break; +- +- case NSS_WIFI_MESH_MSG_EXCEPTION_FLAG: +- nss_wifi_mesh_log_exception_flag_msg(nwmm); +- break; +- +- case NSS_WIFI_MESH_CONFIG_EXCEPTION: +- nss_wifi_mesh_log_rate_limit_config(nwmm); +- break; +- +- default: +- nss_trace("%px: Invalid message, type: %d\n", nwmm, nwmm->cm.type); +- break; +- } +-} +- +-/* +- * nss_wifi_mesh_log_tx_msg() +- * Log messages transmitted to firmware. +- */ +-void nss_wifi_mesh_log_tx_msg(struct nss_wifi_mesh_msg *nwmm) +-{ +- uint32_t index; +- if ((nwmm->cm.type >= NSS_WIFI_MESH_MSG_MAX) || (nwmm->cm.type <= NSS_IF_MAX_MSG_TYPES)) { +- nss_warning("%px: Invalid message, type: %d\n", nwmm, nwmm->cm.type); +- return; +- } +- +- index = NSS_WIFI_MESH_LOG_MESSAGE_TYPE_INDEX(nwmm->cm.type); +- +- nss_info("%px: type[%d]:%s\n", nwmm, nwmm->cm.type, nss_wifi_mesh_log_message_types_str[index - 1]); +- nss_wifi_mesh_log_verbose(nwmm); +-} +- +-/* +- * nss_wifi_mesh_log_rx_msg() +- * Log messages received from firmware. +- */ +-void nss_wifi_mesh_log_rx_msg(struct nss_wifi_mesh_msg *nwmm) +-{ +- uint32_t index; +- if (nwmm->cm.response >= NSS_CMN_RESPONSE_LAST) { +- nss_warning("%px: Invalid response, message type: %d\n", nwmm, nwmm->cm.type); +- return; +- } +- +- if (nwmm->cm.type <= NSS_IF_MAX_MSG_TYPES) { +- return; +- } +- +- index = NSS_WIFI_MESH_LOG_MESSAGE_TYPE_INDEX(nwmm->cm.type); +- +- if (nwmm->cm.response == NSS_CMN_RESPONSE_NOTIFY || (nwmm->cm.response == NSS_CMN_RESPONSE_ACK)) { +- nss_info("%px: type[%d]:%s, response[%d]:%s\n", nwmm, nwmm->cm.type, +- nss_wifi_mesh_log_message_types_str[index - 1], +- nwmm->cm.response, nss_cmn_response_str[nwmm->cm.response]); +- goto verbose; +- } +- +- nss_info("%px: msg nack - type[%d]:%s, response[%d]:%s\n", +- nwmm, nwmm->cm.type, nss_wifi_mesh_log_message_types_str[index - 1], +- nwmm->cm.response, nss_cmn_response_str[nwmm->cm.response]); +- +-verbose: +- nss_wifi_mesh_log_verbose(nwmm); +-} +--- a/nss_wifi_mesh_log.h ++++ /dev/null +@@ -1,34 +0,0 @@ +-/* +- ************************************************************************** +- * Copyright (c) 2021, The Linux Foundation. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for any +- * purpose with or without fee is hereby granted, provided that the above +- * copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- ************************************************************************** +- */ +- +-#ifndef __NSS_WIFI_MESH_LOG_H +-#define __NSS_WIFI_MESH_LOG_H +- +-/* +- * nss_wifi_mesh_log_tx_msg +- * Logs a Wi-Fi mesh message that was sent to the NSS firmware. +- */ +-void nss_wifi_mesh_log_tx_msg(struct nss_wifi_mesh_msg *nwmm); +- +-/* +- * nss_wifi_mesh_log_rx_msg +- * Logs a Wi-Fi mesh message that was received from the NSS firmware. +- */ +-void nss_wifi_mesh_log_rx_msg(struct nss_wifi_mesh_msg *nwmm); +- +-#endif /* __NSS_WIFI_MESH_LOG_H */ +--- a/nss_wifi_mesh_stats.c ++++ /dev/null +@@ -1,662 +0,0 @@ +-/* +- ************************************************************************** +- * Copyright (c) 2021, The Linux Foundation. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for any +- * purpose with or without fee is hereby granted, provided that the above +- * copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- ************************************************************************** +- */ +- +-#include "nss_core.h" +-#include "nss_tx_rx_common.h" +-#include "nss_wifi_mesh.h" +-#include "nss_wifi_mesh_stats.h" +-#include "nss_wifi_mesh_strings.h" +- +-#define NSS_WIFI_MESH_OUTER_STATS 0 +-#define NSS_WIFI_MESH_INNER_STATS 1 +-#define NSS_WIFI_MESH_PATH_STATS 2 +-#define NSS_WIFI_MESH_PROXY_PATH_STATS 3 +-#define NSS_WIFI_MESH_EXCEPTION_STATS 4 +- +-/* +- * Wi-Fi mesh stats dentry file size. +- */ +-#define NSS_WIFI_MESH_DENTRY_FILE_SIZE 19 +- +-/* +- * Spinlock for protecting tunnel operations colliding with a tunnel destroy +- */ +-static DEFINE_SPINLOCK(nss_wifi_mesh_stats_lock); +- +-/* +- * Declare atomic notifier data structure for statistics. +- */ +-static ATOMIC_NOTIFIER_HEAD(nss_wifi_mesh_stats_notifier); +- +-/* +- * Declare an array of Wi-Fi mesh stats handle. +- */ +-struct nss_wifi_mesh_stats_handle *nss_wifi_mesh_stats_hdl[NSS_WIFI_MESH_MAX_DYNAMIC_INTERFACE]; +- +-/* +- * nss_wifi_mesh_max_statistics() +- * Wi-Fi mesh maximum statistics. +- */ +-static uint32_t nss_wifi_mesh_max_statistics(void) +-{ +- uint32_t max1; +- uint32_t exception_stats_max = NSS_WIFI_MESH_EXCEPTION_STATS_TYPE_MAX; +- uint32_t encap_stats_max = NSS_WIFI_MESH_ENCAP_STATS_TYPE_MAX; +- uint32_t decap_stats_max = NSS_WIFI_MESH_DECAP_STATS_TYPE_MAX; +- uint32_t path_stats_max = NSS_WIFI_MESH_PATH_STATS_TYPE_MAX; +- uint32_t proxy_path_stats_max = NSS_WIFI_MESH_PROXY_PATH_STATS_TYPE_MAX; +- +- max1 = max(max(encap_stats_max, decap_stats_max), max(path_stats_max, proxy_path_stats_max)); +- +- return (max(max1, exception_stats_max)); +-} +- +-/* +- * nss_wifi_mesh_stats_handle_alloc() +- * Allocate Wi-Fi mesh tunnel instance +- */ +-bool nss_wifi_mesh_stats_handle_alloc(nss_if_num_t if_num, int32_t ifindex) +-{ +- struct nss_wifi_mesh_stats_handle *h; +- uint32_t idx; +- +- /* +- * Allocate a handle +- */ +- h = kzalloc(sizeof(struct nss_wifi_mesh_stats_handle), GFP_ATOMIC); +- if (!h) { +- nss_warning("Failed to allocate memory for Wi-Fi mesh instance for interface : 0x%x\n", if_num); +- return false; +- } +- +- spin_lock(&nss_wifi_mesh_stats_lock); +- for (idx = 0; idx < NSS_WIFI_MESH_MAX_DYNAMIC_INTERFACE; idx++) { +- if (nss_wifi_mesh_stats_hdl[idx] && nss_wifi_mesh_stats_hdl[idx]->if_num == if_num) { +- spin_unlock(&nss_wifi_mesh_stats_lock); +- nss_warning("Already a handle present for this interface number: 0x%x\n", if_num); +- kfree(h); +- return false; +- } +- } +- +- for (idx = 0; idx < NSS_WIFI_MESH_MAX_DYNAMIC_INTERFACE; idx++) { +- if (nss_wifi_mesh_stats_hdl[idx]) { +- continue; +- } +- +- h->if_num = if_num; +- h->mesh_idx = idx; +- h->ifindex = ifindex; +- nss_wifi_mesh_stats_hdl[idx] = h; +- spin_unlock(&nss_wifi_mesh_stats_lock); +- return true; +- } +- spin_unlock(&nss_wifi_mesh_stats_lock); +- nss_warning("No free index available for handle with ifnum: 0x%x\n", if_num); +- kfree(h); +- return false; +-} +- +-/* +- * nss_wifi_mesh_stats_handle_free() +- * Free Wi-Fi mesh tunnel handle instance. +- */ +-bool nss_wifi_mesh_stats_handle_free(nss_if_num_t if_num) +-{ +- struct nss_wifi_mesh_stats_handle *h; +- +- spin_lock(&nss_wifi_mesh_stats_lock); +- h = nss_wifi_mesh_get_stats_handle(if_num); +- if (!h) { +- spin_unlock(&nss_wifi_mesh_stats_lock); +- nss_warning("Unable to free Wi-Fi mesh stats handle instance for interface number: 0x%x\n", if_num); +- return false; +- } +- +- nss_wifi_mesh_stats_hdl[h->mesh_idx] = NULL; +- spin_unlock(&nss_wifi_mesh_stats_lock); +- kfree(h); +- return true; +-} +- +-/** +- * nss_wifi_mesh_get_stats_handle() +- * Get Wi-Fi mesh stats handle from interface number. +- */ +-struct nss_wifi_mesh_stats_handle *nss_wifi_mesh_get_stats_handle(nss_if_num_t if_num) +-{ +- uint32_t idx; +- +- assert_spin_locked(&nss_wifi_mesh_stats_lock); +- +- for (idx = 0; idx < NSS_WIFI_MESH_MAX_DYNAMIC_INTERFACE; idx++) { +- if (nss_wifi_mesh_stats_hdl[idx]) { +- if (nss_wifi_mesh_stats_hdl[idx]->if_num == if_num) { +- struct nss_wifi_mesh_stats_handle *h = nss_wifi_mesh_stats_hdl[idx]; +- return h; +- } +- } +- } +- return NULL; +-} +- +-/* +- * nss_wifi_mesh_get_stats() +- * API for getting stats from a Wi-Fi mesh interface stats +- */ +-static bool nss_wifi_mesh_get_stats(nss_if_num_t if_num, struct nss_wifi_mesh_hdl_stats_sync_msg *stats) +-{ +- struct nss_wifi_mesh_stats_handle *h; +- +- if (!nss_wifi_mesh_verify_if_num(if_num)) { +- return false; +- } +- +- spin_lock(&nss_wifi_mesh_stats_lock); +- h = nss_wifi_mesh_get_stats_handle(if_num); +- if (!h) { +- spin_unlock(&nss_wifi_mesh_stats_lock); +- nss_warning("Invalid Wi-Fi mesh stats handle for interface number: %d\n", if_num); +- return false; +- } +- +- memcpy(stats, &h->stats, sizeof(*stats)); +- spin_unlock(&nss_wifi_mesh_stats_lock); +- return true; +-} +- +-/* +- * nss_wifi_mesh_get_valid_interface_count() +- * Get count of valid Wi-Fi mesh interfaces up. +- */ +-static uint32_t nss_wifi_mesh_get_valid_interface_count(uint16_t type, uint32_t if_num, uint32_t max_if_num) +-{ +- uint32_t interface_count = 0; +- enum nss_dynamic_interface_type dtype; +- +- for (; if_num <= max_if_num; if_num++) { +- if (!nss_is_dynamic_interface(if_num)) { +- continue; +- } +- +- dtype = nss_dynamic_interface_get_type(nss_wifi_mesh_get_context(), if_num); +- +- if ((type == NSS_WIFI_MESH_OUTER_STATS) && (dtype != NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_OUTER)) { +- continue; +- } +- +- if ((type == NSS_WIFI_MESH_INNER_STATS) && (dtype != NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER)) { +- continue; +- } +- +- if ((type == NSS_WIFI_MESH_PATH_STATS) && (dtype != NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER)) { +- continue; +- } +- +- if ((type == NSS_WIFI_MESH_PROXY_PATH_STATS) && (dtype != NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER)) { +- continue; +- } +- interface_count++; +- } +- return interface_count; +-} +- +-/** +- * nss_wifi_mesh_stats_read() +- * Read Wi-Fi Mesh stats. +- */ +-static ssize_t nss_wifi_mesh_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos, uint16_t type) +-{ +- uint32_t max_output_lines, max_stats; +- size_t size_al, size_wr = 0; +- ssize_t bytes_read = 0; +- struct nss_stats_data *data = fp->private_data; +- int ifindex; +- uint32_t if_num = NSS_DYNAMIC_IF_START; +- uint32_t interface_count = 0; +- uint32_t max_if_num = NSS_DYNAMIC_IF_START + NSS_MAX_DYNAMIC_INTERFACES; +- struct nss_wifi_mesh_hdl_stats_sync_msg *stats; +- struct net_device *ndev; +- struct nss_wifi_mesh_stats_handle *handle; +- char *lbuf; +- enum nss_dynamic_interface_type dtype; +- +- if (data) { +- if_num = data->if_num; +- } +- +- /* +- * If we are done accomodating all the Wi-Fi mesh interfaces. +- */ +- if (if_num > max_if_num) { +- return 0; +- } +- +- /* +- * Get number of Wi-Fi mesh interfaces up. +- */ +- interface_count = nss_wifi_mesh_get_valid_interface_count(type, if_num, max_if_num); +- if (!interface_count) { +- nss_warning("%px: Invalid number of valid interface for if_num: 0x%x\n", data, if_num); +- return 0; +- } +- +- /* +- * max output lines = #stats + Number of Extra outputlines for future reference to add new stats + +- * Maximum node stats + Maximum of all the stats + three blank lines. +- */ +- max_stats = nss_wifi_mesh_max_statistics(); +- max_output_lines = max_stats + NSS_STATS_NODE_MAX + NSS_STATS_EXTRA_OUTPUT_LINES; +- size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines * interface_count; +- +- lbuf = kzalloc(size_al, GFP_KERNEL); +- if (unlikely(lbuf == NULL)) { +- nss_warning("Could not allocate memory for local statistics buffer\n"); +- return 0; +- } +- +- size_wr += nss_stats_banner(lbuf, size_wr, size_al, "wifi_mesh", NSS_STATS_SINGLE_CORE); +- +- stats = kzalloc(sizeof(struct nss_wifi_mesh_hdl_stats_sync_msg), GFP_KERNEL); +- if (!stats) { +- nss_warning("%px: Failed to allocate stats memory for if_num: 0x%x\n", data, if_num); +- kfree(lbuf); +- return 0; +- } +- +- for (; if_num <= max_if_num; if_num++) { +- bool ret; +- +- if (!nss_is_dynamic_interface(if_num)) { +- continue; +- } +- +- dtype = nss_dynamic_interface_get_type(nss_wifi_mesh_get_context(), if_num); +- +- if ((type == NSS_WIFI_MESH_OUTER_STATS) && (dtype != NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_OUTER)) { +- continue; +- } +- +- if ((type == NSS_WIFI_MESH_INNER_STATS) && (dtype != NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER)) { +- continue; +- } +- +- if ((type == NSS_WIFI_MESH_PATH_STATS) && (dtype != NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER)) { +- continue; +- } +- +- if ((type == NSS_WIFI_MESH_PROXY_PATH_STATS) && (dtype != NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER)) { +- continue; +- } +- +- /* +- * If Wi-Fi mesh stats handle does not exists, then ret will be false. +- */ +- ret = nss_wifi_mesh_get_stats(if_num, stats); +- if (!ret) { +- continue; +- } +- +- spin_lock(&nss_wifi_mesh_stats_lock); +- handle = nss_wifi_mesh_get_stats_handle(if_num); +- if (!handle) { +- spin_unlock(&nss_wifi_mesh_stats_lock); +- nss_warning("Invalid Wi-Fi mesh stats handle, if_num: %d\n", if_num); +- continue; +- } +- ifindex = handle->ifindex; +- spin_unlock(&nss_wifi_mesh_stats_lock); +- +- ndev = dev_get_by_index(&init_net, ifindex); +- if (!ndev) { +- continue; +- } +- +- size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\n%s if_num:%03u\n", +- ndev->name, if_num); +- dev_put(ndev); +- +- /* +- * Read encap stats, path stats, proxy path stats from inner node and decap stats from outer node. +- */ +- switch (type) { +- case NSS_WIFI_MESH_INNER_STATS: +- size_wr += nss_stats_print("wifi_mesh", "encap stats", NSS_STATS_SINGLE_INSTANCE +- , nss_wifi_mesh_strings_encap_stats +- , stats->encap_stats +- , NSS_WIFI_MESH_ENCAP_STATS_TYPE_MAX +- , lbuf, size_wr, size_al); +- break; +- +- case NSS_WIFI_MESH_PATH_STATS: +- size_wr += nss_stats_print("wifi_mesh", "path stats", NSS_STATS_SINGLE_INSTANCE +- , nss_wifi_mesh_strings_path_stats +- , stats->path_stats +- , NSS_WIFI_MESH_PATH_STATS_TYPE_MAX +- , lbuf, size_wr, size_al); +- break; +- +- case NSS_WIFI_MESH_PROXY_PATH_STATS: +- size_wr += nss_stats_print("wifi_mesh", "proxy path stats", NSS_STATS_SINGLE_INSTANCE +- , nss_wifi_mesh_strings_proxy_path_stats +- , stats->proxy_path_stats +- , NSS_WIFI_MESH_PROXY_PATH_STATS_TYPE_MAX +- , lbuf, size_wr, size_al); +- break; +- +- case NSS_WIFI_MESH_OUTER_STATS: +- size_wr += nss_stats_print("wifi_mesh", "decap stats", NSS_STATS_SINGLE_INSTANCE +- , nss_wifi_mesh_strings_decap_stats +- , stats->decap_stats +- , NSS_WIFI_MESH_DECAP_STATS_TYPE_MAX +- , lbuf, size_wr, size_al); +- break; +- +- case NSS_WIFI_MESH_EXCEPTION_STATS: +- size_wr += nss_stats_print("wifi_mesh", "exception stats", NSS_STATS_SINGLE_INSTANCE +- , nss_wifi_mesh_strings_exception_stats +- , stats->except_stats +- , NSS_WIFI_MESH_EXCEPTION_STATS_TYPE_MAX +- , lbuf, size_wr, size_al); +- break; +- +- default: +- nss_warning("%px: Invalid stats type: %d\n", stats, type); +- nss_assert(0); +- kfree(stats); +- kfree(lbuf); +- return 0; +- } +- } +- +- bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, size_wr); +- kfree(stats); +- kfree(lbuf); +- return bytes_read; +-} +- +-/** +- * nss_wifi_mesh_decap_stats_read() +- * Read Wi-Fi Mesh decap stats. +- */ +-static ssize_t nss_wifi_mesh_decap_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- return nss_wifi_mesh_stats_read(fp, ubuf, sz, ppos, NSS_WIFI_MESH_OUTER_STATS); +-} +- +-/** +- * nss_wifi_mesh_encap_stats_read() +- * Read Wi-Fi Mesh encap stats +- */ +-static ssize_t nss_wifi_mesh_encap_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- return nss_wifi_mesh_stats_read(fp, ubuf, sz, ppos, NSS_WIFI_MESH_INNER_STATS); +-} +- +-/** +- * nss_wifi_mesh_path_stats_read() +- * Read Wi-Fi Mesh path stats +- */ +-static ssize_t nss_wifi_mesh_path_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- return nss_wifi_mesh_stats_read(fp, ubuf, sz, ppos, NSS_WIFI_MESH_PATH_STATS); +-} +- +-/** +- * nss_wifi_mesh_proxy_path_stats_read() +- * Read Wi-Fi Mesh proxy path stats +- */ +-static ssize_t nss_wifi_mesh_proxy_path_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- return nss_wifi_mesh_stats_read(fp, ubuf, sz, ppos, NSS_WIFI_MESH_PROXY_PATH_STATS); +-} +- +-/** +- * nss_wifi_mesh_exception_stats_read() +- * Read Wi-Fi Mesh exception stats +- */ +-static ssize_t nss_wifi_mesh_exception_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- return nss_wifi_mesh_stats_read(fp, ubuf, sz, ppos, NSS_WIFI_MESH_EXCEPTION_STATS); +-} +- +-/* +- * nss_wifi_mesh_stats_ops +- */ +-NSS_STATS_DECLARE_FILE_OPERATIONS(wifi_mesh_encap); +-NSS_STATS_DECLARE_FILE_OPERATIONS(wifi_mesh_decap); +-NSS_STATS_DECLARE_FILE_OPERATIONS(wifi_mesh_path); +-NSS_STATS_DECLARE_FILE_OPERATIONS(wifi_mesh_proxy_path); +-NSS_STATS_DECLARE_FILE_OPERATIONS(wifi_mesh_exception); +- +-/* +- * nss_wifi_mesh_get_interface_type() +- * Function to get the type of dynamic interface. +- */ +-static enum nss_dynamic_interface_type nss_wifi_mesh_get_interface_type(nss_if_num_t if_num) +-{ +- struct nss_ctx_instance *nss_ctx = &nss_top_main.nss[nss_top_main.wifi_handler_id]; +- NSS_VERIFY_CTX_MAGIC(nss_ctx); +- return nss_dynamic_interface_get_type(nss_ctx, if_num); +-} +- +-/* +- * nss_wifi_mesh_update_stats() +- * Update stats for Wi-Fi mesh interface. +- */ +-void nss_wifi_mesh_update_stats(nss_if_num_t if_num, struct nss_wifi_mesh_stats_sync_msg *mstats) +-{ +- struct nss_wifi_mesh_stats_handle *handle; +- struct nss_wifi_mesh_hdl_stats_sync_msg *stats; +- enum nss_dynamic_interface_type type; +- uint64_t *dst; +- uint32_t *src; +- int i; +- +- spin_lock(&nss_wifi_mesh_stats_lock); +- handle = nss_wifi_mesh_get_stats_handle(if_num); +- if (!handle) { +- spin_unlock(&nss_wifi_mesh_stats_lock); +- nss_warning("Invalid Wi-Fi mesh stats handle, if_num: %d\n", if_num); +- return; +- } +- +- type = nss_wifi_mesh_get_interface_type(handle->if_num);; +- stats = &handle->stats; +- +- switch (type) { +- case NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER: +- /* +- * Update pnode Rx stats. +- */ +- stats->encap_stats[NSS_WIFI_MESH_ENCAP_STATS_TYPE_PNODE_RX_PACKETS] += mstats->pnode_stats.rx_packets; +- stats->encap_stats[NSS_WIFI_MESH_ENCAP_STATS_TYPE_PNODE_RX_BYTES] += mstats->pnode_stats.rx_bytes; +- stats->encap_stats[NSS_WIFI_MESH_ENCAP_STATS_TYPE_PNODE_RX_DROPPED] += nss_cmn_rx_dropped_sum(&mstats->pnode_stats); +- +- /* +- * Update pnode Tx stats. +- */ +- stats->encap_stats[NSS_WIFI_MESH_ENCAP_STATS_TYPE_PNODE_TX_PACKETS] += mstats->pnode_stats.tx_packets; +- stats->encap_stats[NSS_WIFI_MESH_ENCAP_STATS_TYPE_PNODE_TX_BYTES] += mstats->pnode_stats.tx_bytes; +- +- /* +- * Update encap stats. +- */ +- dst = &stats->encap_stats[NSS_WIFI_MESH_ENCAP_STATS_TYPE_EXPIRY_NOTIFY_SENT]; +- src = &mstats->mesh_encap_stats.expiry_notify_sent; +- for (i = NSS_WIFI_MESH_ENCAP_STATS_TYPE_EXPIRY_NOTIFY_SENT; i < NSS_WIFI_MESH_ENCAP_STATS_TYPE_MAX; i++) { +- *dst++ += *src++; +- } +- +- /* +- * Update mesh path stats. +- */ +- dst = &stats->path_stats[NSS_WIFI_MESH_PATH_STATS_TYPE_ALLOC_FAILURES]; +- src = &mstats->mesh_path_stats.alloc_failures; +- for (i = NSS_WIFI_MESH_PATH_STATS_TYPE_ALLOC_FAILURES; i < NSS_WIFI_MESH_PATH_STATS_TYPE_MAX; i++) { +- *dst++ += *src++; +- } +- +- /* +- * Update mesh proxy path stats. +- */ +- dst = &stats->proxy_path_stats[NSS_WIFI_MESH_PROXY_PATH_STATS_TYPE_ALLOC_FAILURES]; +- src = &mstats->mesh_proxy_path_stats.alloc_failures; +- for (i = NSS_WIFI_MESH_PROXY_PATH_STATS_TYPE_ALLOC_FAILURES; i < NSS_WIFI_MESH_PROXY_PATH_STATS_TYPE_MAX; i++) { +- *dst++ += *src++; +- } +- +- /* +- * Update exception stats. +- */ +- dst = &stats->except_stats[NSS_WIFI_MESH_EXCEPTION_STATS_TYPE_PACKETS_SUCCESS]; +- src = &mstats->mesh_except_stats.packets_success; +- for (i = NSS_WIFI_MESH_EXCEPTION_STATS_TYPE_PACKETS_SUCCESS; i < NSS_WIFI_MESH_EXCEPTION_STATS_TYPE_MAX; i++) { +- *dst++ += *src++; +- } +- spin_unlock(&nss_wifi_mesh_stats_lock); +- break; +- +- case NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_OUTER: +- /* +- * Update pnode Rx stats. +- */ +- stats->decap_stats[NSS_WIFI_MESH_DECAP_STATS_TYPE_PNODE_RX_PACKETS] += mstats->pnode_stats.rx_packets; +- stats->decap_stats[NSS_WIFI_MESH_DECAP_STATS_TYPE_PNODE_RX_BYTES] += mstats->pnode_stats.rx_bytes; +- stats->decap_stats[NSS_WIFI_MESH_DECAP_STATS_TYPE_PNODE_RX_DROPPED] += nss_cmn_rx_dropped_sum(&mstats->pnode_stats); +- +- /* +- * Update pnode Tx stats. +- */ +- stats->decap_stats[NSS_WIFI_MESH_DECAP_STATS_TYPE_PNODE_TX_PACKETS] += mstats->pnode_stats.tx_packets; +- stats->decap_stats[NSS_WIFI_MESH_DECAP_STATS_TYPE_PNODE_TX_BYTES] += mstats->pnode_stats.tx_bytes; +- +- /* +- * Update decap stats. +- */ +- dst = &stats->decap_stats[NSS_WIFI_MESH_DECAP_STATS_TYPE_PATH_REFRESH_SENT]; +- src = &mstats->mesh_decap_stats.path_refresh_sent; +- for (i = NSS_WIFI_MESH_DECAP_STATS_TYPE_PATH_REFRESH_SENT; i < NSS_WIFI_MESH_DECAP_STATS_TYPE_MAX; i++) { +- *dst++ += *src++; +- } +- spin_unlock(&nss_wifi_mesh_stats_lock); +- break; +- +- default: +- spin_unlock(&nss_wifi_mesh_stats_lock); +- nss_warning("%px: Received invalid dynamic interface type: %d\n", handle, type); +- nss_assert(0); +- } +-} +- +-/* +- * nss_wifi_mesh_stats_notify() +- * Sends notifications to the registered modules. +- * +- * Leverage NSS-FW statistics timing to update Netlink. +- */ +-void nss_wifi_mesh_stats_notify(nss_if_num_t if_num, uint32_t core_id) +-{ +- struct nss_wifi_mesh_stats_notification wifi_mesh_stats; +- +- if (!nss_wifi_mesh_get_stats(if_num, &wifi_mesh_stats.stats)) { +- nss_warning("No handle is present with ifnum: 0x%x\n", if_num); +- return; +- } +- +- wifi_mesh_stats.core_id = core_id; +- wifi_mesh_stats.if_num = if_num; +- atomic_notifier_call_chain(&nss_wifi_mesh_stats_notifier, NSS_STATS_EVENT_NOTIFY, (void *)&wifi_mesh_stats); +-} +- +-/* +- * nss_wifi_mesh_stats_dentry_create() +- * Create Wi-Fi Mesh statistics debug entry +- */ +-struct dentry *nss_wifi_mesh_stats_dentry_create(void) +-{ +- struct dentry *stats_dentry_dir; +- struct dentry *stats_file; +- char dir_name[NSS_WIFI_MESH_DENTRY_FILE_SIZE] = {0}; +- +- if (!nss_top_main.stats_dentry) { +- nss_warning("qca-nss-drv/stats is not present\n"); +- return NULL; +- } +- +- snprintf(dir_name, sizeof(dir_name), "wifi_mesh"); +- +- stats_dentry_dir = debugfs_create_dir(dir_name, nss_top_main.stats_dentry); +- if (!stats_dentry_dir) { +- nss_warning("Failed to create qca-nss-drv/stats/wifi_mesh directory\n"); +- return NULL; +- } +- +- stats_file = debugfs_create_file("encap_stats", 0400, stats_dentry_dir, &nss_top_main, &nss_wifi_mesh_encap_stats_ops); +- if (!stats_file) { +- nss_warning("Failed to create qca-nss-drv/stats/wifi_mesh/encap_stats file\n"); +- goto fail; +- } +- +- stats_file = debugfs_create_file("decap_stats", 0400, stats_dentry_dir, &nss_top_main, &nss_wifi_mesh_decap_stats_ops); +- if (!stats_file) { +- nss_warning("Failed to create qca-nss-drv/stats/wifi_mesh/decap_stats file\n"); +- goto fail; +- } +- +- stats_file = debugfs_create_file("path_stats", 0400, stats_dentry_dir, &nss_top_main, &nss_wifi_mesh_path_stats_ops); +- if (!stats_file) { +- nss_warning("Failed to create qca-nss-drv/stats/wifi_mesh/path_stats file\n"); +- goto fail; +- } +- +- stats_file = debugfs_create_file("proxy_path_stats", 0400, stats_dentry_dir, &nss_top_main, &nss_wifi_mesh_proxy_path_stats_ops); +- if (!stats_file) { +- nss_warning("Failed to create qca-nss-drv/stats/wifi_mesh/proxy_path_stats file\n"); +- goto fail; +- } +- stats_file = debugfs_create_file("exception_stats", 0400, stats_dentry_dir, &nss_top_main, &nss_wifi_mesh_exception_stats_ops); +- if (!stats_file) { +- nss_warning("Failed to create qca-nss-drv/stats/wifi_mesh/exception_stats file\n"); +- goto fail; +- } +- return stats_dentry_dir; +-fail: +- debugfs_remove_recursive(stats_dentry_dir); +- return NULL; +-} +- +-/** +- * nss_wifi_mesh_stats_register_notifier() +- * Registers statistics notifier. +- */ +-int nss_wifi_mesh_stats_register_notifier(struct notifier_block *nb) +-{ +- return atomic_notifier_chain_register(&nss_wifi_mesh_stats_notifier, nb); +-} +-EXPORT_SYMBOL(nss_wifi_mesh_stats_register_notifier); +- +-/** +- * nss_wifi_mesh_stats_unregister_notifier() +- * Deregisters statistics notifier. +- */ +-int nss_wifi_mesh_stats_unregister_notifier(struct notifier_block *nb) +-{ +- return atomic_notifier_chain_unregister(&nss_wifi_mesh_stats_notifier, nb); +-} +-EXPORT_SYMBOL(nss_wifi_mesh_stats_unregister_notifier); +--- a/nss_wifi_mesh_stats.h ++++ /dev/null +@@ -1,42 +0,0 @@ +-/* +- ************************************************************************** +- * Copyright (c) 2021, The Linux Foundation. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for any +- * purpose with or without fee is hereby granted, provided that the above +- * copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- ************************************************************************** +- */ +- +-#ifndef __NSS_WIFI_MESH_STATS_H__ +-#define __NSS_WIFI_MESH_STATS_H__ +- +-/** +- * Array of pointer for NSS Wi-Fi mesh handles. +- * Each handle has per-tunnel statistics based on the interface number which is an index. +- */ +-struct nss_wifi_mesh_stats_handle { +- nss_if_num_t if_num; /**< Interface number. */ +- uint32_t ifindex; /**< Netdev index. */ +- uint32_t mesh_idx; /**< Mesh index. */ +- struct nss_wifi_mesh_hdl_stats_sync_msg stats; /**< Stats per-interface number. */ +-}; +- +-/* +- * Wi-Fi Mesh statistics APIs +- */ +-extern void nss_wifi_mesh_update_stats(nss_if_num_t if_num, struct nss_wifi_mesh_stats_sync_msg *mstats); +-extern void nss_wifi_mesh_stats_notify(nss_if_num_t if_num, uint32_t core_id); +-extern struct dentry *nss_wifi_mesh_stats_dentry_create(void); +-extern struct nss_wifi_mesh_stats_handle *nss_wifi_mesh_get_stats_handle(nss_if_num_t if_num); +-extern bool nss_wifi_mesh_stats_handle_alloc(nss_if_num_t if_num, int32_t ifindex); +-extern bool nss_wifi_mesh_stats_handle_free(nss_if_num_t if_num); +-#endif /* __NSS_WIFI_MESH_STATS_H__ */ +--- a/nss_wifi_mesh_strings.c ++++ /dev/null +@@ -1,284 +0,0 @@ +-/* +- ************************************************************************** +- * Copyright (c) 2021, The Linux Foundation. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- ************************************************************************** +- */ +- +-#include "nss_stats.h" +-#include "nss_core.h" +-#include +-#include "nss_wifi_mesh_stats.h" +-#include "nss_strings.h" +-#include "nss_wifi_mesh_strings.h" +- +-/* +- * nss_wifi_mesh_strings_encap_stats +- * Wi-Fi mesh encap statistics string. +- */ +-struct nss_stats_info nss_wifi_mesh_strings_encap_stats[NSS_WIFI_MESH_ENCAP_STATS_TYPE_MAX] = { +- {"rx_packets", NSS_STATS_TYPE_COMMON}, +- {"rx_bytes", NSS_STATS_TYPE_COMMON}, +- {"tx_packets", NSS_STATS_TYPE_COMMON}, +- {"tx_bytes", NSS_STATS_TYPE_COMMON}, +- {"rx_dropped", NSS_STATS_TYPE_COMMON}, +- {"expiry_notify_sent", NSS_STATS_TYPE_SPECIAL}, +- {"mc_count", NSS_STATS_TYPE_SPECIAL}, +- {"mp_not_found", NSS_STATS_TYPE_SPECIAL}, +- {"mp_active", NSS_STATS_TYPE_SPECIAL}, +- {"mpp_not_found", NSS_STATS_TYPE_SPECIAL}, +- {"mpp_found", NSS_STATS_TYPE_SPECIAL}, +- {"encap_hdr_fail", NSS_STATS_TYPE_SPECIAL}, +- {"mp_del_notify_fail", NSS_STATS_TYPE_SPECIAL}, +- {"link_enqueue", NSS_STATS_TYPE_SPECIAL}, +- {"link_enq_fail", NSS_STATS_TYPE_SPECIAL}, +- {"ra_lup_fail", NSS_STATS_TYPE_SPECIAL}, +- {"dummy_add_count", NSS_STATS_TYPE_SPECIAL}, +- {"encap_mp_add_notify_fail", NSS_STATS_TYPE_SPECIAL}, +- {"dummy_add_fail", NSS_STATS_TYPE_SPECIAL}, +- {"dummy_lup_fail", NSS_STATS_TYPE_SPECIAL}, +- {"send_to_host_failed", NSS_STATS_TYPE_SPECIAL}, +- {"sent_to_host", NSS_STATS_TYPE_SPECIAL}, +- {"expiry_notify_fail", NSS_STATS_TYPE_SPECIAL}, +- {"no_headroom", NSS_STATS_TYPE_SPECIAL}, +- {"path_refresh_sent", NSS_STATS_TYPE_SPECIAL}, +- {"linearise_failed", NSS_STATS_TYPE_SPECIAL}, +- {"mp_exc_event_rl_dropped", NSS_STATS_TYPE_SPECIAL} +-}; +- +-/* +- * nss_wifi_mesh_encap_strings_read() +- * Read Wi-Fi mesh encap statistics names. +- */ +-static ssize_t nss_wifi_mesh_encap_stats_strings_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- return nss_strings_print(ubuf, sz, ppos, nss_wifi_mesh_strings_encap_stats, NSS_WIFI_MESH_ENCAP_STATS_TYPE_MAX); +-} +- +-/* +- * nss_wifi_mesh_strings_path_stats +- * Wi-Fi mesh path statistics string. +- */ +-struct nss_stats_info nss_wifi_mesh_strings_path_stats[NSS_WIFI_MESH_PATH_STATS_TYPE_MAX] = { +- {"alloc_failures", NSS_STATS_TYPE_SPECIAL}, +- {"error_max_radio_count", NSS_STATS_TYPE_SPECIAL}, +- {"invalid_interface_failures", NSS_STATS_TYPE_SPECIAL}, +- {"add_success", NSS_STATS_TYPE_SPECIAL}, +- {"table_full_errors", NSS_STATS_TYPE_SPECIAL}, +- {"insert_failures", NSS_STATS_TYPE_SPECIAL}, +- {"not_found", NSS_STATS_TYPE_SPECIAL}, +- {"delete_success", NSS_STATS_TYPE_SPECIAL}, +- {"update_success", NSS_STATS_TYPE_SPECIAL}, +- {"mesh_path_expired", NSS_STATS_TYPE_SPECIAL}, +- {"mesh_path_refresh_needed", NSS_STATS_TYPE_SPECIAL}, +- {"add_requests", NSS_STATS_TYPE_SPECIAL}, +- {"del_requests", NSS_STATS_TYPE_SPECIAL}, +- {"update_requests", NSS_STATS_TYPE_SPECIAL}, +- {"next_hop_updations", NSS_STATS_TYPE_SPECIAL}, +- {"hop_count_updations", NSS_STATS_TYPE_SPECIAL}, +- {"flag_updations", NSS_STATS_TYPE_SPECIAL}, +- {"metric_updations", NSS_STATS_TYPE_SPECIAL}, +- {"block_mesh_fwd_updations", NSS_STATS_TYPE_SPECIAL}, +- {"delete_failures", NSS_STATS_TYPE_SPECIAL}, +- {"mesh_path_dummy_add_failures",NSS_STATS_TYPE_SPECIAL}, +- {"mesh_path_dummy_add_success", NSS_STATS_TYPE_SPECIAL} +- +-}; +- +-/* +- * nss_wifi_mesh_path_strings_read() +- * Read Wi-Fi mesh path statistics names. +- */ +-static ssize_t nss_wifi_mesh_path_stats_strings_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- return nss_strings_print(ubuf, sz, ppos, nss_wifi_mesh_strings_path_stats, NSS_WIFI_MESH_PATH_STATS_TYPE_MAX); +-} +- +-/* +- * nss_wifi_mesh_strings_proxy_path_stats +- * Wi-Fi mesh proxy path statistics string. +- */ +-struct nss_stats_info nss_wifi_mesh_strings_proxy_path_stats[NSS_WIFI_MESH_PROXY_PATH_STATS_TYPE_MAX] = { +- {"alloc_failures", NSS_STATS_TYPE_SPECIAL}, +- {"entry_exist_failures", NSS_STATS_TYPE_SPECIAL}, +- {"add_success", NSS_STATS_TYPE_SPECIAL}, +- {"table_full_errors", NSS_STATS_TYPE_SPECIAL}, +- {"insert_failures", NSS_STATS_TYPE_SPECIAL}, +- {"not_found", NSS_STATS_TYPE_SPECIAL}, +- {"unhashed_errors", NSS_STATS_TYPE_SPECIAL}, +- {"delete_failures", NSS_STATS_TYPE_SPECIAL}, +- {"delete_success", NSS_STATS_TYPE_SPECIAL}, +- {"update_success", NSS_STATS_TYPE_SPECIAL}, +- {"lookup_success", NSS_STATS_TYPE_SPECIAL}, +- {"add_requests", NSS_STATS_TYPE_SPECIAL}, +- {"del_requests", NSS_STATS_TYPE_SPECIAL}, +- {"update_requests", NSS_STATS_TYPE_SPECIAL}, +- {"mda_updations", NSS_STATS_TYPE_SPECIAL}, +- {"flag_updations", NSS_STATS_TYPE_SPECIAL}, +- {"mesh_proxy_path_dummy_lookup_success", NSS_STATS_TYPE_SPECIAL}, +- {"mesh_proxy_path_dummy_lookup_failures", NSS_STATS_TYPE_SPECIAL}, +- {"mesh_proxy_path_dummy_add_failures", NSS_STATS_TYPE_SPECIAL}, +- {"mesh_proxy_path_dummy_add_success", NSS_STATS_TYPE_SPECIAL} +-}; +- +-/* +- * nss_wifi_mesh_proxy_path_strings_read() +- * Read Wi-Fi mesh proxy path statistics names. +- */ +-static ssize_t nss_wifi_mesh_proxy_path_stats_strings_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- return nss_strings_print(ubuf, sz, ppos, nss_wifi_mesh_strings_proxy_path_stats, NSS_WIFI_MESH_PROXY_PATH_STATS_TYPE_MAX); +-} +- +-/* +- * nss_wifi_mesh_strings_decap_stats +- * Wi-Fi mesh decap statistics string. +- */ +-struct nss_stats_info nss_wifi_mesh_strings_decap_stats[NSS_WIFI_MESH_DECAP_STATS_TYPE_MAX] = { +- {"rx_packets", NSS_STATS_TYPE_COMMON}, +- {"rx_bytes", NSS_STATS_TYPE_COMMON}, +- {"tx_packets", NSS_STATS_TYPE_COMMON}, +- {"tx_bytes", NSS_STATS_TYPE_COMMON}, +- {"rx_dropped", NSS_STATS_TYPE_COMMON}, +- {"path_refresh_sent", NSS_STATS_TYPE_SPECIAL}, +- {"reserved", NSS_STATS_TYPE_SPECIAL}, +- {"mc_drop", NSS_STATS_TYPE_DROP}, +- {"ttl_0", NSS_STATS_TYPE_SPECIAL}, +- {"mpp_lup_fail", NSS_STATS_TYPE_SPECIAL}, +- {"decap_hdr_fail", NSS_STATS_TYPE_SPECIAL}, +- {"rx_fwd_fail", NSS_STATS_TYPE_SPECIAL}, +- {"rx_fwd_success", NSS_STATS_TYPE_SPECIAL}, +- {"mp_fwd_lookup_fail", NSS_STATS_TYPE_SPECIAL}, +- {"mp_fwd_inactive", NSS_STATS_TYPE_SPECIAL}, +- {"nxt_mnode_fwd_success", NSS_STATS_TYPE_SPECIAL}, +- {"nxt_mnode_fwd_fail", NSS_STATS_TYPE_SPECIAL}, +- {"mpp_add_fail", NSS_STATS_TYPE_SPECIAL}, +- {"mpp_add_event2host_fail", NSS_STATS_TYPE_SPECIAL}, +- {"mpp_upate_fail", NSS_STATS_TYPE_SPECIAL}, +- {"mpp_update_even2host_fail", NSS_STATS_TYPE_SPECIAL}, +- {"mpp_learn2host_fail", NSS_STATS_TYPE_SPECIAL}, +- {"block_mesh_fwd_packets", NSS_STATS_TYPE_SPECIAL}, +- {"no_headroom", NSS_STATS_TYPE_SPECIAL}, +- {"linearise_failed", NSS_STATS_TYPE_SPECIAL}, +- {"mpp_learn_event_rl_dropped", NSS_STATS_TYPE_DROP}, +- {"mp_missging_event_rl_dropped", NSS_STATS_TYPE_DROP} +-}; +- +-/* +- * nss_wifi_mesh_decap_strings_read() +- * Read Wi-Fi mesh decap statistics names. +- */ +-static ssize_t nss_wifi_mesh_decap_stats_strings_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- return nss_strings_print(ubuf, sz, ppos, nss_wifi_mesh_strings_decap_stats, NSS_WIFI_MESH_DECAP_STATS_TYPE_MAX); +-} +- +-/* +- * nss_wifi_mesh_strings_exception_stats +- * Wi-Fi mesh exception statistics string. +- */ +-struct nss_stats_info nss_wifi_mesh_strings_exception_stats[NSS_WIFI_MESH_EXCEPTION_STATS_TYPE_MAX] = { +- {"packets_success", NSS_STATS_TYPE_SPECIAL}, +- {"packets_failure", NSS_STATS_TYPE_DROP} +-}; +- +-/* +- * nss_wifi_mesh_exception_strings_read() +- * Read Wi-Fi mesh exception statistics names. +- */ +-static ssize_t nss_wifi_mesh_exception_stats_strings_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos) +-{ +- return nss_strings_print(ubuf, sz, ppos, nss_wifi_mesh_strings_exception_stats, NSS_WIFI_MESH_EXCEPTION_STATS_TYPE_MAX); +-} +- +-/* +- * nss_wifi_mesh_decap_strings_ops +- */ +-NSS_STRINGS_DECLARE_FILE_OPERATIONS(wifi_mesh_decap_stats); +- +-/* +- * nss_wifi_mesh_encap_strings_ops +- */ +-NSS_STRINGS_DECLARE_FILE_OPERATIONS(wifi_mesh_encap_stats); +- +-/* +- * nss_wifi_mesh_path_strings_ops +- */ +-NSS_STRINGS_DECLARE_FILE_OPERATIONS(wifi_mesh_path_stats); +- +-/* +- * nss_wifi_mesh_proxy_path_strings_ops +- */ +-NSS_STRINGS_DECLARE_FILE_OPERATIONS(wifi_mesh_proxy_path_stats); +- +-/* +- * nss_wifi_mesh_exception_strings_ops +- */ +-NSS_STRINGS_DECLARE_FILE_OPERATIONS(wifi_mesh_exception_stats); +- +-/* +- * nss_wifi_mesh_strings_dentry_create() +- * Create Wi-Fi mesh statistics strings debug entry. +- */ +-struct dentry *nss_wifi_mesh_strings_dentry_create(void) +-{ +- struct dentry *str_dentry_dir; +- struct dentry *str_file; +- +- if (!nss_top_main.strings_dentry) { +- nss_warning("qca-nss-drv/strings is not present\n"); +- return NULL; +- } +- +- str_dentry_dir = debugfs_create_dir("wifi_mesh", nss_top_main.strings_dentry); +- if (!str_dentry_dir) { +- nss_warning("Failed to create qca-nss-drv/string/wifi_mesh directory\n"); +- return NULL; +- } +- +- str_file = debugfs_create_file("encap_stats", 0400, str_dentry_dir, &nss_top_main, &nss_wifi_mesh_encap_stats_strings_ops); +- if (!str_file) { +- nss_warning("Failed to create qca-nss-drv/string/wifi_mesh/encap_stats file\n"); +- goto fail; +- } +- +- str_file = debugfs_create_file("decap_stats", 0400, str_dentry_dir, &nss_top_main, &nss_wifi_mesh_decap_stats_strings_ops); +- if (!str_file) { +- nss_warning("Failed to create qca-nss-drv/string/wifi_mesh/decap_stats file\n"); +- goto fail; +- } +- +- str_file = debugfs_create_file("path_stats", 0400, str_dentry_dir, &nss_top_main, &nss_wifi_mesh_path_stats_strings_ops); +- if (!str_file) { +- nss_warning("Failed to create qca-nss-drv/string/wifi_mesh/path_stats file\n"); +- goto fail; +- } +- +- str_file = debugfs_create_file("proxy_path_stats", 0400, str_dentry_dir, &nss_top_main, &nss_wifi_mesh_proxy_path_stats_strings_ops); +- if (!str_file) { +- nss_warning("Failed to create qca-nss-drv/string/wifi_mesh/proxy_path_stats file\n"); +- goto fail; +- } +- +- str_file = debugfs_create_file("exception_stats", 0400, str_dentry_dir, &nss_top_main, &nss_wifi_mesh_exception_stats_strings_ops); +- if (!str_file) { +- nss_warning("Failed to create qca-nss-drv/string/wifi_mesh/exception_stats file\n"); +- goto fail; +- } +- +- return str_dentry_dir; +-fail: +- debugfs_remove_recursive(str_dentry_dir); +- return NULL; +-} +--- a/nss_wifi_mesh_strings.h ++++ /dev/null +@@ -1,32 +0,0 @@ +-/* +- ************************************************************************** +- * Copyright (c) 2021, The Linux Foundation. All rights reserved. +- * +- * Permission to use, copy, modify, and/or distribute this software for +- * any purpose with or without fee is hereby granted, provided that the +- * above copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- ************************************************************************** +- */ +- +-#ifndef __NSS_WIFI_MESH_STRINGS_H +-#define __NSS_WIFI_MESH_STRINGS_H +- +-#include "nss_wifi_mesh_stats.h" +-#include "nss_strings.h" +- +-extern struct nss_stats_info nss_wifi_mesh_strings_encap_stats[NSS_WIFI_MESH_ENCAP_STATS_TYPE_MAX]; +-extern struct nss_stats_info nss_wifi_mesh_strings_decap_stats[NSS_WIFI_MESH_DECAP_STATS_TYPE_MAX]; +-extern struct nss_stats_info nss_wifi_mesh_strings_path_stats[NSS_WIFI_MESH_PATH_STATS_TYPE_MAX]; +-extern struct nss_stats_info nss_wifi_mesh_strings_proxy_path_stats[NSS_WIFI_MESH_PROXY_PATH_STATS_TYPE_MAX]; +-extern struct nss_stats_info nss_wifi_mesh_strings_exception_stats[NSS_WIFI_MESH_EXCEPTION_STATS_TYPE_MAX]; +-extern struct dentry *nss_wifi_mesh_strings_dentry_create(void); +- +-#endif /* __NSS_WIFI_MESH_STRINGS_H */ +--- a/nss_wifi_stats.c ++++ b/nss_wifi_stats.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2016-2017, 2019-2021 The Linux Foundation. All rights reserved. ++ * Copyright (c) 2016-2017, 2019-2020 The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -86,8 +86,7 @@ struct nss_stats_info nss_wifi_stats_str + {"rx_htt_fetch_cnt" , NSS_STATS_TYPE_SPECIAL}, + {"total_tidq_bypass_cnt" , NSS_STATS_TYPE_SPECIAL}, + {"global_q_full_cnt" , NSS_STATS_TYPE_SPECIAL}, +- {"tidq_full_cnt" , NSS_STATS_TYPE_SPECIAL}, +- {"peer_unauth_rx_pkt_drop" , NSS_STATS_TYPE_DROP} ++ {"tidq_full_cnt" , NSS_STATS_TYPE_SPECIAL} + }; + + uint64_t nss_wifi_stats[NSS_MAX_WIFI_RADIO_INTERFACES][NSS_WIFI_STATS_MAX]; /* WIFI statistics */ +@@ -209,7 +208,6 @@ void nss_wifi_stats_sync(struct nss_ctx_ + nss_wifi_stats[radio_id][NSS_WIFI_STATS_TOTAL_TIDQ_BYPASS_CNT] += stats->total_tidq_bypass_cnt; + nss_wifi_stats[radio_id][NSS_WIFI_STATS_GLOBAL_Q_FULL_CNT] += stats->global_q_full_cnt; + nss_wifi_stats[radio_id][NSS_WIFI_STATS_TIDQ_FULL_CNT] += stats->tidq_full_cnt; +- nss_wifi_stats[radio_id][NSS_WIFI_STATS_UNATH_RX_PKT_DROP] += stats->peer_unauth_rx_pkt_drop; + + spin_unlock_bh(&nss_top->stats_lock); + } +--- a/nss_wifi_stats.h ++++ b/nss_wifi_stats.h +@@ -50,7 +50,6 @@ enum nss_wifi_stats_types { + NSS_WIFI_STATS_TOTAL_TIDQ_BYPASS_CNT, + NSS_WIFI_STATS_GLOBAL_Q_FULL_CNT, + NSS_WIFI_STATS_TIDQ_FULL_CNT, +- NSS_WIFI_STATS_UNATH_RX_PKT_DROP, + NSS_WIFI_STATS_MAX, + }; + +--- a/nss_wifi_vdev.c ++++ b/nss_wifi_vdev.c +@@ -199,16 +199,8 @@ EXPORT_SYMBOL(nss_wifi_vdev_tx_msg_ext); + */ + nss_tx_status_t nss_wifi_vdev_tx_buf(struct nss_ctx_instance *nss_ctx, struct sk_buff *os_buf, uint32_t if_num) + { +- enum nss_dynamic_interface_type if_type; +- + BUG_ON(((if_num < NSS_DYNAMIC_IF_START) || (if_num >= (NSS_DYNAMIC_IF_START + NSS_MAX_DYNAMIC_INTERFACES)))); + +- if_type = nss_dynamic_interface_get_type(nss_ctx, if_num); +- if (if_type != NSS_DYNAMIC_INTERFACE_TYPE_VAP) { +- nss_warning("%px: non vap %d packet tx not allowed", nss_ctx, if_num); +- return NSS_TX_FAILURE_NOT_SUPPORTED; +- } +- + return nss_core_send_packet(nss_ctx, os_buf, if_num, H2N_BIT_FLAG_BUFFER_REUSABLE); + } + EXPORT_SYMBOL(nss_wifi_vdev_tx_buf); +--- a/nss_wifili.c ++++ b/nss_wifili.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -20,56 +20,6 @@ + #include "nss_wifili_strings.h" + + #define NSS_WIFILI_TX_TIMEOUT 1000 /* Millisecond to jiffies*/ +-#define NSS_WIFILI_INVALID_SCHEME_ID -1 +-#define NSS_WIFILI_THREAD_SCHEME_ENTRY_MAX 4 /* Maximum number of thread scheme entries. */ +-#define NSS_WIFILI_EXTERNAL_INTERFACE_MAX 2 /* Maximum external I/F supported */ +- +-/* +- * NSS external interface number table +- */ +-nss_if_num_t nss_wifili_external_tbl[NSS_WIFILI_EXTERNAL_INTERFACE_MAX] = +- {NSS_WIFILI_EXTERNAL_INTERFACE0, NSS_WIFILI_EXTERNAL_INTERFACE1}; +- +-/* +- * nss_wifili_thread_scheme_entry +- * Details of thread scheme. +- */ +-struct nss_wifili_thread_scheme_entry { +- int32_t radio_ifnum; /* Radio interface number. */ +- uint32_t radio_priority; /* Priority of radio. */ +- uint32_t scheme_priority; /* Priority of scheme. */ +- uint8_t scheme_index; /* Scheme index allocated to radio. */ +- bool allocated; /* Flag to check if scheme is allocated. */ +-}; +- +-/* +- * nss_wifili_thread_scheme_db +- * Wifili thread scheme database. +- */ +-struct nss_wifili_thread_scheme_db { +- spinlock_t lock; /* Lock to protect from simultaneous access. */ +- uint32_t radio_count; /* Radio counter. */ +- struct nss_wifili_thread_scheme_entry nwtse[NSS_WIFILI_THREAD_SCHEME_ENTRY_MAX]; +- /* Metadata for each of scheme. */ +-}; +- +-/* +- * nss_wifili_external_if_state_tbl +- * External interface state table +- */ +-struct nss_wifili_external_if_state_tbl { +- nss_if_num_t ifnum; +- bool in_use; +-}; +- +-/* +- * nss_wifili_external_if_info +- * Wifili external interface info +- */ +-struct nss_wifili_external_if_info { +- spinlock_t lock; +- struct nss_wifili_external_if_state_tbl state_tbl[NSS_WIFILI_EXTERNAL_INTERFACE_MAX]; +-} nss_wifi_eif_info; + + /* + * nss_wifili_pvt +@@ -84,11 +34,6 @@ static struct nss_wifili_pvt { + } wifili_pvt; + + /* +- * Scheme to radio mapping database +- */ +-static struct nss_wifili_thread_scheme_db ts_db[NSS_MAX_CORES]; +- +-/* + * nss_wifili_handler() + * Handle NSS -> HLOS messages for wifi + */ +@@ -105,8 +50,11 @@ static void nss_wifili_handler(struct ns + */ + BUG_ON((nss_is_dynamic_interface(ncm->interface)) + || ((ncm->interface != NSS_WIFILI_INTERNAL_INTERFACE) ++#if (NSS_FW_VERSION_CODE > NSS_FW_VERSION(11,0)) + && (ncm->interface != NSS_WIFILI_EXTERNAL_INTERFACE0) +- && (ncm->interface != NSS_WIFILI_EXTERNAL_INTERFACE1))); ++ && (ncm->interface != NSS_WIFILI_EXTERNAL_INTERFACE1) ++#endif ++ )); + + /* + * Trace messages. +@@ -122,9 +70,7 @@ static void nss_wifili_handler(struct ns + } + + if ((nss_cmn_get_msg_len(ncm) > sizeof(struct nss_wifili_msg)) && +- ntm->cm.type != NSS_WIFILI_PEER_EXT_STATS_MSG && +- ntm->cm.type != NSS_WIFILI_ASTENTRY_SYNC_MSG && +- ntm->cm.type != NSS_WIFILI_MECENTRY_SYNC_MSG) { ++ ntm->cm.type != NSS_WIFILI_PEER_EXT_STATS_MSG) { + nss_warning("%px: Length of message is greater than required: %d", nss_ctx, nss_cmn_get_msg_len(ncm)); + return; + } +@@ -229,8 +175,13 @@ nss_tx_status_t nss_wifili_tx_msg(struct + * The interface number shall be one of the wifili soc interfaces + */ + if ((ncm->interface != NSS_WIFILI_INTERNAL_INTERFACE) ++#if (NSS_FW_VERSION_CODE > NSS_FW_VERSION(11,0)) + && (ncm->interface != NSS_WIFILI_EXTERNAL_INTERFACE0) +- && (ncm->interface != NSS_WIFILI_EXTERNAL_INTERFACE1)) { ++ && (ncm->interface != NSS_WIFILI_EXTERNAL_INTERFACE1)) ++#else ++ ) ++#endif ++ { + nss_warning("%px: tx request for interface that is not a wifili: %d", nss_ctx, ncm->interface); + return NSS_TX_FAILURE; + } +@@ -284,261 +235,31 @@ struct nss_ctx_instance *nss_wifili_get_ + EXPORT_SYMBOL(nss_wifili_get_context); + + /* +- * nss_wifili_release_external_if() +- * Release the external interface. +- */ +-void nss_wifili_release_external_if(nss_if_num_t ifnum) +-{ +- uint32_t idx; +- +- spin_lock_bh(&nss_wifi_eif_info.lock); +- for (idx = 0; idx < NSS_WIFILI_EXTERNAL_INTERFACE_MAX; idx++) { +- if (nss_wifi_eif_info.state_tbl[idx].ifnum != ifnum) { +- continue; +- } +- +- if (!nss_wifi_eif_info.state_tbl[idx].in_use) { +- spin_unlock_bh(&nss_wifi_eif_info.lock); +- nss_warning("%px: I/F num:%d is not in use\n", &nss_wifi_eif_info, ifnum); +- return; +- } +- +- nss_wifi_eif_info.state_tbl[idx].in_use = false; +- break; +- } +- +- spin_unlock_bh(&nss_wifi_eif_info.lock); +- +- if (idx == NSS_WIFILI_EXTERNAL_INTERFACE_MAX) { +- nss_warning("%px: Trying to release invalid ifnum:%d\n", &nss_wifi_eif_info, ifnum); +- } +-} +-EXPORT_SYMBOL(nss_wifili_release_external_if); +- +-/* + * nss_get_available_wifili_external_if() + * Check and return the available external interface + */ +-nss_if_num_t nss_get_available_wifili_external_if(void) ++#if (NSS_FW_VERSION_CODE > NSS_FW_VERSION(11,0)) ++uint32_t nss_get_available_wifili_external_if(void) + { +- nss_if_num_t ifnum = -1; +- uint32_t idx; +- ++ struct nss_ctx_instance *nss_ctx = (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.wifi_handler_id]; + /* + * Check if the external interface is registered. + * Return the interface number if not registered. + */ +- spin_lock_bh(&nss_wifi_eif_info.lock); +- for (idx = 0; idx < NSS_WIFILI_EXTERNAL_INTERFACE_MAX; idx++) { +- if (nss_wifi_eif_info.state_tbl[idx].in_use) { +- continue; +- } +- +- nss_wifi_eif_info.state_tbl[idx].in_use = true; +- ifnum = nss_wifi_eif_info.state_tbl[idx].ifnum; +- break; ++ if (!(nss_ctx->subsys_dp_register[NSS_WIFILI_EXTERNAL_INTERFACE0].ndev)) { ++ return NSS_WIFILI_EXTERNAL_INTERFACE0; + } + +- spin_unlock_bh(&nss_wifi_eif_info.lock); +- +- BUG_ON(idx == NSS_WIFILI_EXTERNAL_INTERFACE_MAX); +- return ifnum; +-} +-EXPORT_SYMBOL(nss_get_available_wifili_external_if); +- +-/* +- * nss_wifili_get_radio_num() +- * Get NSS wifili radio count. +- * +- * Wi-Fi host driver needs to know the current radio count +- * to extract the radio priority from ini file. +- */ +-uint32_t nss_wifili_get_radio_num(struct nss_ctx_instance *nss_ctx) +-{ +- uint8_t core_id; +- uint32_t radio_count; +- +- nss_assert(nss_ctx); +- nss_assert(nss_ctx->id < nss_top_main.num_nss); +- +- core_id = nss_ctx->id; +- +- spin_lock_bh(&ts_db[core_id].lock); +- radio_count = ts_db[core_id].radio_count; +- spin_unlock_bh(&ts_db[core_id].lock); +- +- return radio_count; +-} +-EXPORT_SYMBOL(nss_wifili_get_radio_num); +- +-/* +- * nss_wifili_thread_scheme_alloc() +- * Allocate NSS worker thread scheme index. +- * +- * API does search on scheme database and returns scheme index based on +- * priority of radio and free entry available. +- * Wi-Fi driver fetches radio priority from ini file and calls this API +- * to get the scheme index based on radio priority. +- * +- */ +-uint8_t nss_wifili_thread_scheme_alloc(struct nss_ctx_instance *nss_ctx, +- int32_t radio_ifnum, +- enum nss_wifili_thread_scheme_priority radio_priority) +-{ +- uint8_t i; +- uint8_t scheme_idx; +- uint8_t core_id; +- uint8_t next_avail_entry_idx = NSS_WIFILI_THREAD_SCHEME_ENTRY_MAX; +- +- nss_assert(nss_ctx); +- nss_assert(nss_ctx->id < nss_top_main.num_nss); +- +- core_id = nss_ctx->id; +- +- /* +- * Iterate through scheme database and allocate +- * scheme_id matching the priority requested. +- */ +- spin_lock_bh(&ts_db[core_id].lock); +- for (i = 0; i < NSS_WIFILI_THREAD_SCHEME_ENTRY_MAX; i++) { +- if (ts_db[core_id].nwtse[i].allocated) { +- continue; +- } +- +- if (radio_priority == +- ts_db[core_id].nwtse[i].scheme_priority) { +- ts_db[core_id].nwtse[i].radio_ifnum = radio_ifnum; +- ts_db[core_id].nwtse[i].radio_priority = radio_priority; +- ts_db[core_id].nwtse[i].allocated = true; +- ts_db[core_id].radio_count++; +- scheme_idx = ts_db[core_id].nwtse[i].scheme_index; +- spin_unlock_bh(&ts_db[core_id].lock); +- +- nss_info("%px: Allocated scheme index:%d radio_ifnum:%d", +- nss_ctx, +- scheme_idx, +- radio_ifnum); +- +- return scheme_idx; +- } +- +- next_avail_entry_idx = i; +- } +- +- /* +- * When radio priority does not match any of scheme entry priority +- * and database has unallocated entries, provide available unallocated entry. +- * This prevents any catastrophic failure during attach of Wi-Fi radio. +- */ +- if (next_avail_entry_idx != NSS_WIFILI_THREAD_SCHEME_ENTRY_MAX) { +- +- ts_db[core_id].nwtse[next_avail_entry_idx].radio_ifnum = radio_ifnum; +- ts_db[core_id].nwtse[next_avail_entry_idx].radio_priority = radio_priority; +- ts_db[core_id].nwtse[next_avail_entry_idx].allocated = true; +- ts_db[core_id].radio_count++; +- scheme_idx = ts_db[core_id].nwtse[next_avail_entry_idx].scheme_index; +- spin_unlock_bh(&ts_db[core_id].lock); +- +- nss_info("%px: Priority did not match for radio_ifnum:%d, allocated a next available scheme:%d", +- nss_ctx, +- radio_ifnum, +- scheme_idx); +- +- return scheme_idx; ++ if (!(nss_ctx->subsys_dp_register[NSS_WIFILI_EXTERNAL_INTERFACE1].ndev)) { ++ return NSS_WIFILI_EXTERNAL_INTERFACE1; + } +- spin_unlock_bh(&ts_db[core_id].lock); + +- nss_warning("%px: Could not find scheme - radio_ifnum:%d radio_map:%d\n", +- nss_ctx, +- radio_ifnum, +- radio_priority); ++ nss_warning("%px: No available external intefaces\n", nss_ctx); + +- return NSS_WIFILI_INVALID_SCHEME_ID; ++ return NSS_MAX_NET_INTERFACES; + } +-EXPORT_SYMBOL(nss_wifili_thread_scheme_alloc); +- +-/* +- * nss_wifili_thread_scheme_dealloc() +- * Reset thread scheme metadata. +- */ +-void nss_wifili_thread_scheme_dealloc(struct nss_ctx_instance *nss_ctx, +- int32_t radio_ifnum) +-{ +- uint32_t id; +- uint8_t core_id; +- +- nss_assert(nss_ctx); +- nss_assert(nss_ctx->id < nss_top_main.num_nss); +- +- core_id = nss_ctx->id; +- +- /* +- * Radio count cannot be zero here. +- */ +- nss_assert(ts_db[core_id].radio_count); +- +- spin_lock_bh(&ts_db[core_id].lock); +- for (id = 0; id < NSS_WIFILI_THREAD_SCHEME_ENTRY_MAX; id++) { +- if (ts_db[core_id].nwtse[id].radio_ifnum != radio_ifnum) { +- continue; +- } +- +- ts_db[core_id].nwtse[id].radio_priority = 0; +- ts_db[core_id].nwtse[id].allocated = false; +- ts_db[core_id].nwtse[id].radio_ifnum = 0; +- ts_db[core_id].radio_count--; +- break; +- } +- spin_unlock_bh(&ts_db[core_id].lock); +- +- if (id == NSS_WIFILI_THREAD_SCHEME_ENTRY_MAX) { +- nss_warning("%px: Could not find scheme database with radio_ifnum:%d", +- nss_ctx, +- radio_ifnum); +- } +-} +-EXPORT_SYMBOL(nss_wifili_thread_scheme_dealloc); +- +-/* +- * nss_wifili_thread_scheme_db_init() +- * Initialize thread scheme database. +- */ +-void nss_wifili_thread_scheme_db_init(uint8_t core_id) +-{ +- uint32_t id; +- +- spin_lock_init(&ts_db[core_id].lock); +- +- /* +- * Iterate through scheme database and assign +- * scheme_id and priority for each entry +- */ +- ts_db[core_id].radio_count = 0; +- for (id = 0; id < NSS_WIFILI_THREAD_SCHEME_ENTRY_MAX; id++) { +- ts_db[core_id].nwtse[id].radio_priority = 0; +- ts_db[core_id].nwtse[id].radio_ifnum = 0; +- ts_db[core_id].nwtse[id].allocated = false; +- +- switch (id) { +- case 0: +- ts_db[core_id].nwtse[id].scheme_priority = NSS_WIFILI_HIGH_PRIORITY_SCHEME; +- ts_db[core_id].nwtse[id].scheme_index = NSS_WIFILI_THREAD_SCHEME_ID_0; +- break; +- case 1: +- ts_db[core_id].nwtse[id].scheme_priority = NSS_WIFILI_LOW_PRIORITY_SCHEME; +- ts_db[core_id].nwtse[id].scheme_index = NSS_WIFILI_THREAD_SCHEME_ID_1; +- break; +- case 2: +- case 3: +- ts_db[core_id].nwtse[id].scheme_priority = NSS_WIFILI_HIGH_PRIORITY_SCHEME; +- ts_db[core_id].nwtse[id].scheme_index = NSS_WIFILI_THREAD_SCHEME_ID_2; +- break; +- default: +- nss_warning("Invalid scheme index:%d", id); +- } +- } +-} +- ++EXPORT_SYMBOL(nss_get_available_wifili_external_if); ++#endif + /* + * nss_wifili_msg_init() + * Initialize nss_wifili_msg. +@@ -598,7 +319,6 @@ void nss_unregister_wifili_if(uint32_t i + || (if_num == NSS_WIFILI_EXTERNAL_INTERFACE1)); + + nss_core_unregister_subsys_dp(nss_ctx, if_num); +- nss_wifili_release_external_if(if_num); + } + EXPORT_SYMBOL(nss_unregister_wifili_if); + +@@ -648,25 +368,16 @@ EXPORT_SYMBOL(nss_unregister_wifili_radi + void nss_wifili_register_handler(void) + { + struct nss_ctx_instance *nss_ctx = (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.wifi_handler_id]; +- uint32_t idx; + + nss_info("nss_wifili_register_handler"); + nss_core_register_handler(nss_ctx, NSS_WIFILI_INTERNAL_INTERFACE, nss_wifili_handler, NULL); ++#if (NSS_FW_VERSION_CODE > NSS_FW_VERSION(11,0)) + nss_core_register_handler(nss_ctx, NSS_WIFILI_EXTERNAL_INTERFACE0, nss_wifili_handler, NULL); + nss_core_register_handler(nss_ctx, NSS_WIFILI_EXTERNAL_INTERFACE1, nss_wifili_handler, NULL); +- ++#endif + nss_wifili_stats_dentry_create(); + nss_wifili_strings_dentry_create(); + + sema_init(&wifili_pvt.sem, 1); + init_completion(&wifili_pvt.complete); +- +- /* +- * Intialize the external interfaces info. +- */ +- spin_lock_init(&nss_wifi_eif_info.lock); +- for (idx = 0; idx < NSS_WIFILI_EXTERNAL_INTERFACE_MAX; idx++) { +- nss_wifi_eif_info.state_tbl[idx].ifnum = nss_wifili_external_tbl[idx]; +- nss_wifi_eif_info.state_tbl[idx].in_use = false; +- } + } +--- a/nss_wifili_stats.c ++++ b/nss_wifili_stats.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. +@@ -37,37 +37,6 @@ ATOMIC_NOTIFIER_HEAD(nss_wifili_stats_no + struct nss_wifili_soc_stats soc_stats[NSS_WIFILI_MAX_SOC_NUM]; + + /* +- * nss_wifili_target_type_string() +- * Convert Target Type Integer to String +- */ +-void nss_wifili_target_type_to_string(uint32_t target_type, char *target_type_str) +-{ +- switch (target_type) { +- +- case NSS_WIFILI_TARGET_TYPE_QCA8074: +- snprintf(target_type_str, NSS_WIFILI_SOC_STRING_SIZE_MAX, "IPQ8074 V1"); +- break; +- case NSS_WIFILI_TARGET_TYPE_QCA8074V2: +- snprintf(target_type_str, NSS_WIFILI_SOC_STRING_SIZE_MAX, "IPQ8074 V2"); +- break; +- case NSS_WIFILI_TARGET_TYPE_QCA6018: +- snprintf(target_type_str, NSS_WIFILI_SOC_STRING_SIZE_MAX, "IPQ6018"); +- break; +- case NSS_WIFILI_TARGET_TYPE_QCN9000: +- snprintf(target_type_str, NSS_WIFILI_SOC_STRING_SIZE_MAX, "QCN9000"); +- break; +- case NSS_WIFILI_TARGET_TYPE_QCA5018: +- snprintf(target_type_str, NSS_WIFILI_SOC_STRING_SIZE_MAX, "IPQ5018"); +- break; +- case NSS_WIFILI_TARGET_TYPE_QCN6122: +- snprintf(target_type_str, NSS_WIFILI_SOC_STRING_SIZE_MAX, "QCN6122"); +- break; +- default : +- snprintf(target_type_str, NSS_WIFILI_SOC_STRING_SIZE_MAX, "Unknown"); +- } +-} +- +-/* + * nss_wifili_stats_read() + * Read wifili statistics + */ +@@ -87,7 +56,6 @@ static ssize_t nss_wifili_stats_read(str + char *lbuf = NULL; + uint32_t soc_idx; + struct nss_wifili_stats *stats_wifili = NULL; +- char pdev_tag[NSS_WIFILI_SOC_STRING_SIZE_MAX]; + + /* + * Max number of pdev depends on type of soc (Internal/Attached). +@@ -115,17 +83,12 @@ static ssize_t nss_wifili_stats_read(str + return 0; + } + ++ size_wr += nss_stats_banner(lbuf, size_wr, size_al, "wifili", NSS_STATS_SINGLE_CORE); + + for (soc_idx = 0; soc_idx < NSS_WIFILI_MAX_SOC_NUM; soc_idx++) { +- if (soc_stats[soc_idx].soc_maxpdev == 0) { +- continue; +- } +- +- size_wr += nss_stats_banner(lbuf, size_wr, size_al, soc_stats[soc_idx].soc_type, NSS_STATS_SINGLE_CORE); + stats_wifili = &(soc_stats[soc_idx].stats_wifili); + for (i = 0; i < soc_stats[soc_idx].soc_maxpdev; i++) { +- snprintf(pdev_tag, NSS_WIFILI_SOC_STRING_SIZE_MAX, "PDEV %d", i); +- size_wr += nss_stats_banner(lbuf, size_wr, size_al, pdev_tag, NSS_STATS_SINGLE_CORE); ++ + spin_lock_bh(&nss_top_main.stats_lock); + size_wr += nss_stats_print("wifili", "txrx", i + , nss_wifili_strings_stats_txrx +@@ -275,9 +238,6 @@ void nss_wifili_stats_sync(struct nss_ct + struct nss_wifili_stats *stats = NULL; + struct nss_wifili_device_stats *devstats = &wlsoc_stats->stats; + uint32_t index; +- char target_type_str[NSS_WIFILI_SOC_STRING_SIZE_MAX]; +- +- nss_wifili_target_type_to_string(wlsoc_stats->target_type, target_type_str); + + /* + * Max number of pdev depends on type of soc (Internal/Attached). +@@ -286,20 +246,19 @@ void nss_wifili_stats_sync(struct nss_ct + case NSS_WIFILI_INTERNAL_INTERFACE: + nwss = &soc_stats[0]; + nwss->soc_maxpdev = NSS_WIFILI_MAX_PDEV_NUM_MSG; +- snprintf(nwss->soc_type, NSS_WIFILI_SOC_STRING_SIZE_MAX, "INTERNAL: %s", target_type_str); + break; + ++#if (NSS_FW_VERSION_CODE > NSS_FW_VERSION(11,0)) + case NSS_WIFILI_EXTERNAL_INTERFACE0: + nwss = &soc_stats[1]; + nwss->soc_maxpdev = NSS_WIFILI_SOC_ATTACHED_MAX_PDEV_NUM; +- snprintf(nwss->soc_type, NSS_WIFILI_SOC_STRING_SIZE_MAX, "ATTACH 0: %s", target_type_str); + break; + + case NSS_WIFILI_EXTERNAL_INTERFACE1: + nwss = &soc_stats[2]; + nwss->soc_maxpdev = NSS_WIFILI_SOC_ATTACHED_MAX_PDEV_NUM; +- snprintf(nwss->soc_type, NSS_WIFILI_SOC_STRING_SIZE_MAX, "ATTACH 1: %s", target_type_str); + break; ++#endif + + default: + nss_warning("%px: Invalid wifili interface\n", nss_ctx); +@@ -402,10 +361,6 @@ void nss_wifili_stats_sync(struct nss_ct + devstats->txcomp_stats[index].hw_ring_empty; + stats->stats_tx_comp[index][NSS_WIFILI_STATS_TX_DESC_FREE_REAPED] += + devstats->txcomp_stats[index].ring_reaped; +- stats->stats_tx_comp[index][NSS_WIFILI_STATS_TX_CAPTURE_ENQUEUE] += +- devstats->txcomp_stats[index].tx_cap_enqueue_count; +- stats->stats_tx_comp[index][NSS_WIFILI_STATS_TX_CAPTURE_ENQUEUE_FAIL] += +- devstats->txcomp_stats[index].tx_cap_enqueue_fail_count; + } + + /* +@@ -505,7 +460,7 @@ void nss_wifili_stats_notify(struct nss_ + struct nss_wifili_stats_notification *wifili_stats; + uint32_t index = 0; + +- wifili_stats = kzalloc(sizeof(struct nss_wifili_stats_notification), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); ++ wifili_stats = kzalloc(sizeof(struct nss_wifili_stats_notification), GFP_KERNEL); + if (!wifili_stats) { + nss_warning("%px: Failed to allocate memory for wifili stats\n", nss_ctx); + return; +@@ -517,6 +472,7 @@ void nss_wifili_stats_notify(struct nss_ + index = 0; + break; + ++#if (NSS_FW_VERSION_CODE > NSS_FW_VERSION(11,0)) + case NSS_WIFILI_EXTERNAL_INTERFACE0: + index = 1; + break; +@@ -524,6 +480,7 @@ void nss_wifili_stats_notify(struct nss_ + case NSS_WIFILI_EXTERNAL_INTERFACE1: + index = 2; + break; ++#endif + + default: + nss_warning("%px: Invalid wifili interface\n", nss_ctx); +--- a/nss_wifili_stats.h ++++ b/nss_wifili_stats.h +@@ -22,13 +22,6 @@ + #ifndef __NSS_WIFILI_STATS_H + #define __NSS_WIFILI_STATS_H + +-#define NSS_WIFILI_TARGET_TYPE_QCA8074 20 +-#define NSS_WIFILI_TARGET_TYPE_QCA8074V2 24 +-#define NSS_WIFILI_TARGET_TYPE_QCA6018 25 +-#define NSS_WIFILI_TARGET_TYPE_QCN9000 26 +-#define NSS_WIFILI_TARGET_TYPE_QCA5018 29 +-#define NSS_WIFILI_TARGET_TYPE_QCN6122 30 +- + #include "nss_core.h" + #include "nss_wifili_if.h" + +--- a/nss_wifili_strings.c ++++ b/nss_wifili_strings.c +@@ -1,6 +1,6 @@ + /* + ************************************************************************** +- * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the +@@ -71,12 +71,10 @@ struct nss_stats_info nss_wifili_strings + * wifili tx comp stats + */ + struct nss_stats_info nss_wifili_strings_stats_tx_comp[NSS_WIFILI_STATS_TX_DESC_FREE_MAX] = { +- {"tx_desc_free_inv_bufsrc" , NSS_STATS_TYPE_ERROR}, +- {"tx_desc_free_inv_cookie" , NSS_STATS_TYPE_SPECIAL}, +- {"tx_desc_free_hw_ring_empty" , NSS_STATS_TYPE_SPECIAL}, +- {"tx_desc_free_reaped" , NSS_STATS_TYPE_SPECIAL}, +- {"tx_capture_enqueue_count" , NSS_STATS_TYPE_SPECIAL}, +- {"tx_capture_enqueue_fail_count" , NSS_STATS_TYPE_ERROR} ++ {"tx_desc_free_inv_bufsrc" , NSS_STATS_TYPE_ERROR}, ++ {"tx_desc_free_inv_cookie" , NSS_STATS_TYPE_SPECIAL}, ++ {"tx_desc_free_hw_ring_empty" , NSS_STATS_TYPE_SPECIAL}, ++ {"tx_desc_free_reaped" , NSS_STATS_TYPE_SPECIAL} + }; + + /* diff --git a/package/qca-nss/qca-nss-drv/patches/110-kernel-6.x-support.patch b/package/qca-nss/qca-nss-drv/patches/110-kernel-6.x-support.patch new file mode 100644 index 0000000000..6d869e05de --- /dev/null +++ b/package/qca-nss/qca-nss-drv/patches/110-kernel-6.x-support.patch @@ -0,0 +1,654 @@ +--- a/nss_c2c_tx.c ++++ b/nss_c2c_tx.c +@@ -334,6 +334,7 @@ static struct ctl_table nss_c2c_tx_table + { } + }; + ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0)) + static struct ctl_table nss_c2c_tx_dir[] = { + { + .procname = "c2c_tx", +@@ -360,6 +361,7 @@ static struct ctl_table nss_c2c_tx_root[ + }, + { } + }; ++#endif + + static struct ctl_table_header *nss_c2c_tx_header; + +@@ -378,7 +380,11 @@ void nss_c2c_tx_register_sysctl(void) + /* + * Register sysctl table. + */ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ nss_c2c_tx_header = register_sysctl("dev/nss/c2c_tx", nss_c2c_tx_table); ++#else + nss_c2c_tx_header = register_sysctl_table(nss_c2c_tx_root); ++#endif + } + + /* +--- a/nss_core.c ++++ b/nss_core.c +@@ -44,7 +44,7 @@ + * following kernel versions. Before enabling the driver in new kernels, + * the skb recycle code must be checked against Linux skb handling. + * +- * Tested on: 3.4, 3.10, 3.14, 3.18, 4.4 and 5.4 ++ * Tested on: 3.4, 3.10, 3.14, 3.18, 4.4, 5.4, 5.10, 5.15 and 6.6 + */ + #if (!( \ + (((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0)))) || \ +@@ -54,7 +54,9 @@ + (((LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0)))) || \ + (((LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(5, 5, 0)))) || \ + (((LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(5, 11, 0)))) || \ +-(((LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(5, 16, 0)))))) ++(((LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(5, 16, 0)))) || \ ++(((LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(6, 2, 0)))) || \ ++(((LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(6, 7, 0)))))) + #error "Check skb recycle code in this file to match Linux version" + #endif + +--- a/nss_dma.c ++++ b/nss_dma.c +@@ -378,6 +378,7 @@ static struct ctl_table nss_dma_table[] + { } + }; + ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0)) + static struct ctl_table nss_dma_dir[] = { + { + .procname = "dma", +@@ -404,6 +405,7 @@ static struct ctl_table nss_dma_root[] = + }, + { } + }; ++#endif + + static struct ctl_table_header *nss_dma_header; + +@@ -422,7 +424,11 @@ void nss_dma_register_sysctl(void) + /* + * Register sysctl table. + */ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ nss_dma_header = register_sysctl("dev/nss/dma", nss_dma_table); ++#else + nss_dma_header = register_sysctl_table(nss_dma_root); ++#endif + } + + /* +--- a/nss_hal/fsm9010/nss_hal_pvt.c ++++ b/nss_hal/fsm9010/nss_hal_pvt.c +@@ -290,7 +290,11 @@ static int __nss_hal_request_irq(struct + } + + int_ctx->irq = npd->irq[irq_num]; ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ netif_napi_add_weight(&nss_ctx->napi_ndev, &int_ctx->napi, nss_core_handle_napi, 64); ++#else + netif_napi_add(&nss_ctx->napi_ndev, &int_ctx->napi, nss_core_handle_napi, 64); ++#endif + return 0; + } + +--- a/nss_hal/ipq50xx/nss_hal_pvt.c ++++ b/nss_hal/ipq50xx/nss_hal_pvt.c +@@ -598,7 +598,11 @@ static int __nss_hal_request_irq(struct + return err; + } + ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ netif_napi_add_weight(&nss_ctx->napi_ndev, &int_ctx->napi, napi_poll_cb, napi_wgt); ++#else + netif_napi_add(&nss_ctx->napi_ndev, &int_ctx->napi, napi_poll_cb, napi_wgt); ++#endif + int_ctx->cause = cause; + err = request_irq(irq, nss_hal_handle_irq, 0, irq_name, int_ctx); + if (err) { +--- a/nss_hal/ipq60xx/nss_hal_pvt.c ++++ b/nss_hal/ipq60xx/nss_hal_pvt.c +@@ -614,62 +614,102 @@ static int __nss_hal_request_irq(struct + irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY); + + if (irq_num == NSS_HAL_N2H_INTR_PURPOSE_EMPTY_BUFFER_SOS) { ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ netif_napi_add_weight(&nss_ctx->napi_ndev, &int_ctx->napi, nss_core_handle_napi_non_queue, NSS_EMPTY_BUFFER_SOS_PROCESSING_WEIGHT); ++#else + netif_napi_add(&nss_ctx->napi_ndev, &int_ctx->napi, nss_core_handle_napi_non_queue, NSS_EMPTY_BUFFER_SOS_PROCESSING_WEIGHT); ++#endif + int_ctx->cause = NSS_N2H_INTR_EMPTY_BUFFERS_SOS; + err = request_irq(irq, nss_hal_handle_irq, 0, "nss_empty_buf_sos", int_ctx); + } + + if (irq_num == NSS_HAL_N2H_INTR_PURPOSE_EMPTY_BUFFER_QUEUE) { ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ netif_napi_add_weight(&nss_ctx->napi_ndev, &int_ctx->napi, nss_core_handle_napi_queue, NSS_EMPTY_BUFFER_RETURN_PROCESSING_WEIGHT); ++#else + netif_napi_add(&nss_ctx->napi_ndev, &int_ctx->napi, nss_core_handle_napi_queue, NSS_EMPTY_BUFFER_RETURN_PROCESSING_WEIGHT); ++#endif + int_ctx->cause = NSS_N2H_INTR_EMPTY_BUFFER_QUEUE; + err = request_irq(irq, nss_hal_handle_irq, 0, "nss_empty_buf_queue", int_ctx); + } + + if (irq_num == NSS_HAL_N2H_INTR_PURPOSE_TX_UNBLOCKED) { ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ netif_napi_add_weight(&nss_ctx->napi_ndev, &int_ctx->napi, nss_core_handle_napi_non_queue, NSS_TX_UNBLOCKED_PROCESSING_WEIGHT); ++#else + netif_napi_add(&nss_ctx->napi_ndev, &int_ctx->napi, nss_core_handle_napi_non_queue, NSS_TX_UNBLOCKED_PROCESSING_WEIGHT); ++#endif + int_ctx->cause = NSS_N2H_INTR_TX_UNBLOCKED; + err = request_irq(irq, nss_hal_handle_irq, 0, "nss-tx-unblock", int_ctx); + } + + if (irq_num == NSS_HAL_N2H_INTR_PURPOSE_DATA_QUEUE_0) { ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ netif_napi_add_weight(&nss_ctx->napi_ndev, &int_ctx->napi, nss_core_handle_napi_queue, NSS_DATA_COMMAND_BUFFER_PROCESSING_WEIGHT); ++#else + netif_napi_add(&nss_ctx->napi_ndev, &int_ctx->napi, nss_core_handle_napi_queue, NSS_DATA_COMMAND_BUFFER_PROCESSING_WEIGHT); ++#endif + int_ctx->cause = NSS_N2H_INTR_DATA_QUEUE_0; + err = request_irq(irq, nss_hal_handle_irq, 0, "nss_queue0", int_ctx); + } + + if (irq_num == NSS_HAL_N2H_INTR_PURPOSE_DATA_QUEUE_1) { + int_ctx->cause = NSS_N2H_INTR_DATA_QUEUE_1; ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ netif_napi_add_weight(&nss_ctx->napi_ndev, &int_ctx->napi, nss_core_handle_napi_queue, NSS_DATA_COMMAND_BUFFER_PROCESSING_WEIGHT); ++#else + netif_napi_add(&nss_ctx->napi_ndev, &int_ctx->napi, nss_core_handle_napi_queue, NSS_DATA_COMMAND_BUFFER_PROCESSING_WEIGHT); ++#endif + err = request_irq(irq, nss_hal_handle_irq, 0, "nss_queue1", int_ctx); + } + + if (irq_num == NSS_HAL_N2H_INTR_PURPOSE_DATA_QUEUE_2) { + int_ctx->cause = NSS_N2H_INTR_DATA_QUEUE_2; ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ netif_napi_add_weight(&nss_ctx->napi_ndev, &int_ctx->napi, nss_core_handle_napi_queue, NSS_DATA_COMMAND_BUFFER_PROCESSING_WEIGHT); ++#else + netif_napi_add(&nss_ctx->napi_ndev, &int_ctx->napi, nss_core_handle_napi_queue, NSS_DATA_COMMAND_BUFFER_PROCESSING_WEIGHT); ++#endif + err = request_irq(irq, nss_hal_handle_irq, 0, "nss_queue2", int_ctx); + } + + if (irq_num == NSS_HAL_N2H_INTR_PURPOSE_DATA_QUEUE_3) { + int_ctx->cause = NSS_N2H_INTR_DATA_QUEUE_3; ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ netif_napi_add_weight(&nss_ctx->napi_ndev, &int_ctx->napi, nss_core_handle_napi_queue, NSS_DATA_COMMAND_BUFFER_PROCESSING_WEIGHT); ++#else + netif_napi_add(&nss_ctx->napi_ndev, &int_ctx->napi, nss_core_handle_napi_queue, NSS_DATA_COMMAND_BUFFER_PROCESSING_WEIGHT); ++#endif + err = request_irq(irq, nss_hal_handle_irq, 0, "nss_queue3", int_ctx); + } + + if (irq_num == NSS_HAL_N2H_INTR_PURPOSE_COREDUMP_COMPLETE) { + int_ctx->cause = NSS_N2H_INTR_COREDUMP_COMPLETE; ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ netif_napi_add_weight(&nss_ctx->napi_ndev, &int_ctx->napi, nss_core_handle_napi_emergency, NSS_DATA_COMMAND_BUFFER_PROCESSING_WEIGHT); ++#else + netif_napi_add(&nss_ctx->napi_ndev, &int_ctx->napi, nss_core_handle_napi_emergency, NSS_DATA_COMMAND_BUFFER_PROCESSING_WEIGHT); ++#endif + err = request_irq(irq, nss_hal_handle_irq, 0, "nss_coredump_complete", int_ctx); + } + + if (irq_num == NSS_HAL_N2H_INTR_PURPOSE_PAGED_EMPTY_BUFFER_SOS) { ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ netif_napi_add_weight(&nss_ctx->napi_ndev, &int_ctx->napi, nss_core_handle_napi_non_queue, NSS_EMPTY_BUFFER_SOS_PROCESSING_WEIGHT); ++#else + netif_napi_add(&nss_ctx->napi_ndev, &int_ctx->napi, nss_core_handle_napi_non_queue, NSS_EMPTY_BUFFER_SOS_PROCESSING_WEIGHT); ++#endif + int_ctx->cause = NSS_N2H_INTR_PAGED_EMPTY_BUFFERS_SOS; + err = request_irq(irq, nss_hal_handle_irq, 0, "nss_paged_empty_buf_sos", int_ctx); + } + + if (irq_num == NSS_HAL_N2H_INTR_PURPOSE_PROFILE_DMA) { + int_ctx->cause = NSS_N2H_INTR_PROFILE_DMA; ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ netif_napi_add_weight(&nss_ctx->napi_ndev, &int_ctx->napi, nss_core_handle_napi_sdma, NSS_DATA_COMMAND_BUFFER_PROCESSING_WEIGHT); ++#else + netif_napi_add(&nss_ctx->napi_ndev, &int_ctx->napi, nss_core_handle_napi_sdma, NSS_DATA_COMMAND_BUFFER_PROCESSING_WEIGHT); ++#endif + err = request_irq(irq, nss_hal_handle_irq, 0, "nss_profile_dma", int_ctx); + } + +--- a/nss_hal/ipq806x/nss_hal_pvt.c ++++ b/nss_hal/ipq806x/nss_hal_pvt.c +@@ -1183,7 +1183,11 @@ static int __nss_hal_request_irq(struct + } + + int_ctx->irq = npd->irq[irq_num]; ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ netif_napi_add_weight(&nss_ctx->napi_ndev, &int_ctx->napi, nss_core_handle_napi, 64); ++#else + netif_napi_add(&nss_ctx->napi_ndev, &int_ctx->napi, nss_core_handle_napi, 64); ++#endif + + return 0; + } +--- a/nss_hal/ipq807x/nss_hal_pvt.c ++++ b/nss_hal/ipq807x/nss_hal_pvt.c +@@ -656,62 +656,102 @@ static int __nss_hal_request_irq(struct + irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY); + + if (irq_num == NSS_HAL_N2H_INTR_PURPOSE_EMPTY_BUFFER_SOS) { ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ netif_napi_add_weight(&nss_ctx->napi_ndev, &int_ctx->napi, nss_core_handle_napi_non_queue, NSS_EMPTY_BUFFER_SOS_PROCESSING_WEIGHT); ++#else + netif_napi_add(&nss_ctx->napi_ndev, &int_ctx->napi, nss_core_handle_napi_non_queue, NSS_EMPTY_BUFFER_SOS_PROCESSING_WEIGHT); ++#endif + int_ctx->cause = NSS_N2H_INTR_EMPTY_BUFFERS_SOS; + err = request_irq(irq, nss_hal_handle_irq, 0, "nss_empty_buf_sos", int_ctx); + } + + if (irq_num == NSS_HAL_N2H_INTR_PURPOSE_EMPTY_BUFFER_QUEUE) { ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ netif_napi_add_weight(&nss_ctx->napi_ndev, &int_ctx->napi, nss_core_handle_napi_queue, NSS_EMPTY_BUFFER_RETURN_PROCESSING_WEIGHT); ++#else + netif_napi_add(&nss_ctx->napi_ndev, &int_ctx->napi, nss_core_handle_napi_queue, NSS_EMPTY_BUFFER_RETURN_PROCESSING_WEIGHT); ++#endif + int_ctx->cause = NSS_N2H_INTR_EMPTY_BUFFER_QUEUE; + err = request_irq(irq, nss_hal_handle_irq, 0, "nss_empty_buf_queue", int_ctx); + } + + if (irq_num == NSS_HAL_N2H_INTR_PURPOSE_TX_UNBLOCKED) { ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ netif_napi_add_weight(&nss_ctx->napi_ndev, &int_ctx->napi, nss_core_handle_napi_non_queue, NSS_TX_UNBLOCKED_PROCESSING_WEIGHT); ++#else + netif_napi_add(&nss_ctx->napi_ndev, &int_ctx->napi, nss_core_handle_napi_non_queue, NSS_TX_UNBLOCKED_PROCESSING_WEIGHT); ++#endif + int_ctx->cause = NSS_N2H_INTR_TX_UNBLOCKED; + err = request_irq(irq, nss_hal_handle_irq, 0, "nss-tx-unblock", int_ctx); + } + + if (irq_num == NSS_HAL_N2H_INTR_PURPOSE_DATA_QUEUE_0) { ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ netif_napi_add_weight(&nss_ctx->napi_ndev, &int_ctx->napi, nss_core_handle_napi_queue, NSS_DATA_COMMAND_BUFFER_PROCESSING_WEIGHT); ++#else + netif_napi_add(&nss_ctx->napi_ndev, &int_ctx->napi, nss_core_handle_napi_queue, NSS_DATA_COMMAND_BUFFER_PROCESSING_WEIGHT); ++#endif + int_ctx->cause = NSS_N2H_INTR_DATA_QUEUE_0; + err = request_irq(irq, nss_hal_handle_irq, 0, "nss_queue0", int_ctx); + } + + if (irq_num == NSS_HAL_N2H_INTR_PURPOSE_DATA_QUEUE_1) { + int_ctx->cause = NSS_N2H_INTR_DATA_QUEUE_1; ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ netif_napi_add_weight(&nss_ctx->napi_ndev, &int_ctx->napi, nss_core_handle_napi_queue, NSS_DATA_COMMAND_BUFFER_PROCESSING_WEIGHT); ++#else + netif_napi_add(&nss_ctx->napi_ndev, &int_ctx->napi, nss_core_handle_napi_queue, NSS_DATA_COMMAND_BUFFER_PROCESSING_WEIGHT); ++#endif + err = request_irq(irq, nss_hal_handle_irq, 0, "nss_queue1", int_ctx); + } + + if (irq_num == NSS_HAL_N2H_INTR_PURPOSE_DATA_QUEUE_2) { + int_ctx->cause = NSS_N2H_INTR_DATA_QUEUE_2; ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ netif_napi_add_weight(&nss_ctx->napi_ndev, &int_ctx->napi, nss_core_handle_napi_queue, NSS_DATA_COMMAND_BUFFER_PROCESSING_WEIGHT); ++#else + netif_napi_add(&nss_ctx->napi_ndev, &int_ctx->napi, nss_core_handle_napi_queue, NSS_DATA_COMMAND_BUFFER_PROCESSING_WEIGHT); ++#endif + err = request_irq(irq, nss_hal_handle_irq, 0, "nss_queue2", int_ctx); + } + + if (irq_num == NSS_HAL_N2H_INTR_PURPOSE_DATA_QUEUE_3) { + int_ctx->cause = NSS_N2H_INTR_DATA_QUEUE_3; ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ netif_napi_add_weight(&nss_ctx->napi_ndev, &int_ctx->napi, nss_core_handle_napi_queue, NSS_DATA_COMMAND_BUFFER_PROCESSING_WEIGHT); ++#else + netif_napi_add(&nss_ctx->napi_ndev, &int_ctx->napi, nss_core_handle_napi_queue, NSS_DATA_COMMAND_BUFFER_PROCESSING_WEIGHT); ++#endif + err = request_irq(irq, nss_hal_handle_irq, 0, "nss_queue3", int_ctx); + } + + if (irq_num == NSS_HAL_N2H_INTR_PURPOSE_COREDUMP_COMPLETE) { + int_ctx->cause = NSS_N2H_INTR_COREDUMP_COMPLETE; ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ netif_napi_add_weight(&nss_ctx->napi_ndev, &int_ctx->napi, nss_core_handle_napi_emergency, NSS_DATA_COMMAND_BUFFER_PROCESSING_WEIGHT); ++#else + netif_napi_add(&nss_ctx->napi_ndev, &int_ctx->napi, nss_core_handle_napi_emergency, NSS_DATA_COMMAND_BUFFER_PROCESSING_WEIGHT); ++#endif + err = request_irq(irq, nss_hal_handle_irq, 0, "nss_coredump_complete", int_ctx); + } + + if (irq_num == NSS_HAL_N2H_INTR_PURPOSE_PAGED_EMPTY_BUFFER_SOS) { ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ netif_napi_add_weight(&nss_ctx->napi_ndev, &int_ctx->napi, nss_core_handle_napi_non_queue, NSS_EMPTY_BUFFER_SOS_PROCESSING_WEIGHT); ++#else + netif_napi_add(&nss_ctx->napi_ndev, &int_ctx->napi, nss_core_handle_napi_non_queue, NSS_EMPTY_BUFFER_SOS_PROCESSING_WEIGHT); ++#endif + int_ctx->cause = NSS_N2H_INTR_PAGED_EMPTY_BUFFERS_SOS; + err = request_irq(irq, nss_hal_handle_irq, 0, "nss_paged_empty_buf_sos", int_ctx); + } + + if (irq_num == NSS_HAL_N2H_INTR_PURPOSE_PROFILE_DMA) { + int_ctx->cause = NSS_N2H_INTR_PROFILE_DMA; ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ netif_napi_add_weight(&nss_ctx->napi_ndev, &int_ctx->napi, nss_core_handle_napi_sdma, NSS_DATA_COMMAND_BUFFER_PROCESSING_WEIGHT); ++#else + netif_napi_add(&nss_ctx->napi_ndev, &int_ctx->napi, nss_core_handle_napi_sdma, NSS_DATA_COMMAND_BUFFER_PROCESSING_WEIGHT); ++#endif + err = request_irq(irq, nss_hal_handle_irq, 0, "nss_profile_dma", int_ctx); + } + +--- a/nss_init.c ++++ b/nss_init.c +@@ -584,6 +584,11 @@ static struct ctl_table nss_general_tabl + { } + }; + ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++static struct ctl_table_header *nss_clock_header; ++static struct ctl_table_header *nss_skb_header; ++static struct ctl_table_header *nss_general_header; ++#else + static struct ctl_table nss_init_dir[] = { + #if (NSS_FREQ_SCALE_SUPPORT == 1) + { +@@ -626,6 +631,7 @@ static struct ctl_table nss_root[] = { + }; + + static struct ctl_table_header *nss_dev_header; ++#endif + + /* + * nss_init() +@@ -734,7 +740,19 @@ static int __init nss_init(void) + /* + * Register sysctl table. + */ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ nss_general_header = register_sysctl("dev/nss/general", nss_general_table); ++ ++#if (NSS_SKB_REUSE_SUPPORT == 1) ++ nss_skb_header = register_sysctl("dev/nss/skb_reuse", nss_skb_reuse_table); ++#endif ++ ++#if (NSS_FREQ_SCALE_SUPPORT == 1) ++ nss_clock_header = register_sysctl("dev/nss/clock", nss_freq_table); ++#endif ++#else + nss_dev_header = register_sysctl_table(nss_root); ++#endif + + /* + * Registering sysctl for ipv4/6 specific config. +@@ -887,8 +905,23 @@ static void __exit nss_cleanup(void) + { + nss_info("Exit NSS driver"); + ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ if (nss_general_header) ++ unregister_sysctl_table(nss_general_header); ++ ++#if (NSS_SKB_REUSE_SUPPORT == 1) ++ if (nss_skb_header) ++ unregister_sysctl_table(nss_skb_header); ++#endif ++ ++#if (NSS_FREQ_SCALE_SUPPORT == 1) ++ if (nss_clock_header) ++ unregister_sysctl_table(nss_clock_header); ++#endif ++#else + if (nss_dev_header) + unregister_sysctl_table(nss_dev_header); ++#endif + + /* + * Unregister n2h specific sysctl +--- a/nss_ipv4.c ++++ b/nss_ipv4.c +@@ -697,6 +697,7 @@ static struct ctl_table nss_ipv4_table[] + { } + }; + ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0)) + static struct ctl_table nss_ipv4_dir[] = { + { + .procname = "ipv4cfg", +@@ -723,6 +724,7 @@ static struct ctl_table nss_ipv4_root[] + }, + { } + }; ++#endif + + static struct ctl_table_header *nss_ipv4_header; + +@@ -738,7 +740,11 @@ void nss_ipv4_register_sysctl(void) + /* + * Register sysctl table. + */ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ nss_ipv4_header = register_sysctl("dev/nss/ipv4cfg", nss_ipv4_table); ++#else + nss_ipv4_header = register_sysctl_table(nss_ipv4_root); ++#endif + } + + /* +--- a/nss_ipv6.c ++++ b/nss_ipv6.c +@@ -706,6 +706,7 @@ static struct ctl_table nss_ipv6_table[] + { } + }; + ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0)) + static struct ctl_table nss_ipv6_dir[] = { + { + .procname = "ipv6cfg", +@@ -732,6 +733,7 @@ static struct ctl_table nss_ipv6_root[] + }, + { } + }; ++#endif + + static struct ctl_table_header *nss_ipv6_header; + +@@ -747,7 +749,11 @@ void nss_ipv6_register_sysctl(void) + /* + * Register sysctl table. + */ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ nss_ipv6_header = register_sysctl("dev/nss/ipv6cfg", nss_ipv6_table); ++#else + nss_ipv6_header = register_sysctl_table(nss_ipv6_root); ++#endif + } + + /* +--- a/nss_n2h.c ++++ b/nss_n2h.c +@@ -1862,6 +1862,7 @@ static struct ctl_table nss_n2h_table_mu + { } + }; + ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0)) + /* + * This table will be overwritten during single-core registration + */ +@@ -1891,6 +1892,7 @@ static struct ctl_table nss_n2h_root[] = + }, + { } + }; ++#endif + + static struct ctl_table_header *nss_n2h_header; + +@@ -2133,8 +2135,12 @@ void nss_n2h_single_core_register_sysctl + /* + * Register sysctl table. + */ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ nss_n2h_header = register_sysctl("dev/nss/n2hcfg", nss_n2h_table_single_core); ++#else + nss_n2h_dir[0].child = nss_n2h_table_single_core; + nss_n2h_header = register_sysctl_table(nss_n2h_root); ++#endif + } + + /* +@@ -2232,7 +2238,11 @@ void nss_n2h_multi_core_register_sysctl( + /* + * Register sysctl table. + */ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ nss_n2h_header = register_sysctl("dev/nss/n2hcfg", nss_n2h_table_multi_core); ++#else + nss_n2h_header = register_sysctl_table(nss_n2h_root); ++#endif + } + + /* +--- a/nss_ppe_vp.c ++++ b/nss_ppe_vp.c +@@ -333,6 +333,7 @@ static struct ctl_table nss_ppe_vp_table + { } + }; + ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0)) + static struct ctl_table nss_ppe_vp_dir[] = { + { + .procname = "ppe_vp", +@@ -350,6 +351,7 @@ static struct ctl_table nss_ppe_vp_root_ + }, + { } + }; ++#endif + + static struct ctl_table_header *nss_ppe_vp_procfs_header; + +@@ -362,7 +364,11 @@ void nss_ppe_vp_procfs_register(void) + /* + * Register sysctl table. + */ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ nss_ppe_vp_procfs_header = register_sysctl("dev/nss/ppe_vp", nss_ppe_vp_table); ++#else + nss_ppe_vp_procfs_header = register_sysctl_table(nss_ppe_vp_root_dir); ++#endif + } + + /* +--- a/nss_pppoe.c ++++ b/nss_pppoe.c +@@ -353,6 +353,7 @@ static struct ctl_table nss_pppoe_table[ + { } + }; + ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0)) + static struct ctl_table nss_pppoe_dir[] = { + { + .procname = "pppoe", +@@ -379,6 +380,7 @@ static struct ctl_table nss_pppoe_root[] + }, + { } + }; ++#endif + + static struct ctl_table_header *nss_pppoe_header; + +@@ -391,7 +393,11 @@ void nss_pppoe_register_sysctl(void) + /* + * Register sysctl table. + */ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ nss_pppoe_header = register_sysctl("dev/nss/pppoe", nss_pppoe_table); ++#else + nss_pppoe_header = register_sysctl_table(nss_pppoe_root); ++#endif + } + + /* +--- a/nss_project.c ++++ b/nss_project.c +@@ -279,6 +279,7 @@ static struct ctl_table nss_project_tabl + { } + }; + ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0)) + static struct ctl_table nss_project_dir[] = { + { + .procname = "project", +@@ -305,6 +306,7 @@ static struct ctl_table nss_project_root + }, + { } + }; ++#endif + + static struct ctl_table_header *nss_project_header; + +@@ -314,7 +316,11 @@ static struct ctl_table_header *nss_proj + */ + void nss_project_register_sysctl(void) + { ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ nss_project_header = register_sysctl("dev/nss/project", nss_project_table); ++#else + nss_project_header = register_sysctl_table(nss_project_root); ++#endif + } + + /* +--- a/nss_rps.c ++++ b/nss_rps.c +@@ -557,6 +557,7 @@ static struct ctl_table nss_rps_table[] + { } + }; + ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0)) + static struct ctl_table nss_rps_dir[] = { + { + .procname = "rps", +@@ -583,6 +584,7 @@ static struct ctl_table nss_rps_root[] = + }, + { } + }; ++#endif + + static struct ctl_table_header *nss_rps_header; + +@@ -620,7 +622,11 @@ void nss_rps_register_sysctl(void) + /* + * Register sysctl table. + */ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ nss_rps_header = register_sysctl("dev/nss/rps", nss_rps_table); ++#else + nss_rps_header = register_sysctl_table(nss_rps_root); ++#endif + } + + /* +--- a/nss_stats.c ++++ b/nss_stats.c +@@ -85,6 +85,7 @@ static struct ctl_table nss_stats_table[ + { } + }; + ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0)) + static struct ctl_table nss_stats_dir[] = { + { + .procname = "stats", +@@ -111,6 +112,8 @@ static struct ctl_table nss_stats_root[] + }, + { } + }; ++#endif ++ + static struct ctl_table_header *nss_stats_header; + + /* +@@ -122,7 +125,11 @@ void nss_stats_register_sysctl(void) + /* + * Register sysctl table. + */ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ nss_stats_header = register_sysctl("dev/nss/stats", nss_stats_table); ++#else + nss_stats_header = register_sysctl_table(nss_stats_root); ++#endif + } + + /* diff --git a/package/qca-nss/qca-nss-drv/patches/120-fix-conversion.patch b/package/qca-nss/qca-nss-drv/patches/120-fix-conversion.patch new file mode 100644 index 0000000000..459121fc38 --- /dev/null +++ b/package/qca-nss/qca-nss-drv/patches/120-fix-conversion.patch @@ -0,0 +1,237 @@ +--- a/nss_dynamic_interface.c ++++ b/nss_dynamic_interface.c +@@ -226,7 +226,7 @@ int nss_dynamic_interface_alloc_node(enu + core_id = nss_top_main.dynamic_interface_table[type]; + nss_ctx = (struct nss_ctx_instance *)&nss_top_main.nss[core_id]; + di_data.if_num = -1; +- di_data.response = false; ++ di_data.response = -1; + init_completion(&di_data.complete); + + nss_dynamic_interface_msg_init(&ndim, NSS_DYNAMIC_INTERFACE, NSS_DYNAMIC_INTERFACE_ALLOC_NODE, +@@ -285,7 +285,7 @@ nss_tx_status_t nss_dynamic_interface_de + + core_id = nss_top_main.dynamic_interface_table[type]; + nss_ctx = (struct nss_ctx_instance *)&nss_top_main.nss[core_id]; +- di_data.response = false; ++ di_data.response = -1; + init_completion(&di_data.complete); + + if (nss_is_dynamic_interface(if_num) == false) { +--- a/nss_ipv6.c ++++ b/nss_ipv6.c +@@ -377,7 +377,7 @@ EXPORT_SYMBOL(nss_ipv6_get_mgr); + * nss_ipv6_register_handler() + * Register our handler to receive messages for this interface + */ +-void nss_ipv6_register_handler() ++void nss_ipv6_register_handler(void) + { + struct nss_ctx_instance *nss_ctx = nss_ipv6_get_mgr(); + +--- a/nss_lag.c ++++ b/nss_lag.c +@@ -237,7 +237,7 @@ nss_tx_status_t nss_lag_tx_slave_state(u + struct nss_lag_pvt lag_msg_state; + + init_completion(&lag_msg_state.complete); +- lag_msg_state.response = false; ++ lag_msg_state.response = -1; + + /* + * Construct a message to the NSS to update it +@@ -268,6 +268,6 @@ nss_tx_status_t nss_lag_tx_slave_state(u + return NSS_TX_FAILURE; + } + +- return lag_msg_state.response; ++ return status; + } + EXPORT_SYMBOL(nss_lag_tx_slave_state); +--- a/nss_n2h.c ++++ b/nss_n2h.c +@@ -1153,16 +1153,16 @@ static nss_tx_status_t nss_n2h_mitigatio + /* + * ACK/NACK received from NSS FW + */ +- if (NSS_FAILURE == nss_n2h_mitigationcp[core_num].response) { ++ if (NSS_TX_FAILURE == nss_n2h_mitigationcp[core_num].response) { + goto failure; + } + + up(&nss_n2h_mitigationcp[core_num].sem); +- return NSS_SUCCESS; ++ return NSS_TX_SUCCESS; + + failure: + up(&nss_n2h_mitigationcp[core_num].sem); +- return NSS_FAILURE; ++ return NSS_TX_FAILURE; + } + + static inline void nss_n2h_buf_pool_free(struct nss_n2h_buf_pool *buf_pool) +@@ -1234,7 +1234,7 @@ static nss_tx_status_t nss_n2h_buf_pool_ + /* + * ACK/NACK received from NSS FW + */ +- if (NSS_FAILURE == nss_n2h_bufcp[core_num].response) { ++ if (NSS_TX_FAILURE == nss_n2h_bufcp[core_num].response) { + + nss_n2h_buf_pool_free(buf_pool); + goto failure; +@@ -1243,10 +1243,10 @@ static nss_tx_status_t nss_n2h_buf_pool_ + up(&nss_n2h_bufcp[core_num].sem); + } while(num_pages); + +- return NSS_SUCCESS; ++ return NSS_TX_SUCCESS; + failure: + up(&nss_n2h_bufcp[core_num].sem); +- return NSS_FAILURE; ++ return NSS_TX_FAILURE; + } + + /* +@@ -1545,7 +1545,7 @@ static nss_tx_status_t nss_n2h_host_bp_c + if (nss_tx_status != NSS_TX_SUCCESS) { + nss_warning("%px: nss_tx error setting back pressure\n", nss_ctx); + up(&nss_n2h_host_bp_cfg_pvt.sem); +- return NSS_FAILURE; ++ return NSS_TX_FAILURE; + } + + /* +@@ -1555,7 +1555,7 @@ static nss_tx_status_t nss_n2h_host_bp_c + if (ret == 0) { + nss_warning("%px: Waiting for ack timed out\n", nss_ctx); + up(&nss_n2h_host_bp_cfg_pvt.sem); +- return NSS_FAILURE; ++ return NSS_TX_FAILURE; + } + + /* +@@ -1563,11 +1563,11 @@ static nss_tx_status_t nss_n2h_host_bp_c + */ + if (nss_n2h_host_bp_cfg_pvt.response == NSS_FAILURE) { + up(&nss_n2h_host_bp_cfg_pvt.sem); +- return NSS_FAILURE; ++ return NSS_TX_FAILURE; + } + + up(&nss_n2h_host_bp_cfg_pvt.sem); +- return NSS_SUCCESS; ++ return NSS_TX_SUCCESS; + } + + /* +--- a/nss_pm.c ++++ b/nss_pm.c +@@ -335,7 +335,7 @@ nss_pm_interface_status_t nss_pm_set_per + break; + + default: +- index = NSS_PM_PERF_LEVEL_IDLE; ++ index = (nss_freq_scales_t)NSS_PM_PERF_LEVEL_IDLE; + } + + #if !defined(NSS_HAL_IPQ807x_SUPPORT) +--- a/nss_rps.c ++++ b/nss_rps.c +@@ -251,7 +251,7 @@ static nss_tx_status_t nss_rps_cfg(struc + nss_warning("%px: nss_tx error setting rps\n", nss_ctx); + + up(&nss_rps_cfg_pvt.sem); +- return NSS_FAILURE; ++ return NSS_TX_FAILURE; + } + + /* +@@ -261,7 +261,7 @@ static nss_tx_status_t nss_rps_cfg(struc + if (ret == 0) { + nss_warning("%px: Waiting for ack timed out\n", nss_ctx); + up(&nss_rps_cfg_pvt.sem); +- return NSS_FAILURE; ++ return NSS_TX_FAILURE; + } + + /* +@@ -269,13 +269,13 @@ static nss_tx_status_t nss_rps_cfg(struc + * If NACK: Handler function will restore nss_rps_config + * to previous state. + */ +- if (NSS_FAILURE == nss_rps_cfg_pvt.response) { ++ if (NSS_TX_FAILURE == nss_rps_cfg_pvt.response) { + up(&nss_rps_cfg_pvt.sem); +- return NSS_FAILURE; ++ return NSS_TX_FAILURE; + } + + up(&nss_rps_cfg_pvt.sem); +- return NSS_SUCCESS; ++ return NSS_TX_SUCCESS; + } + + /* +@@ -300,11 +300,11 @@ static nss_tx_status_t nss_rps_ipv4_hash + nss_warning("%px: nss_tx error setting rps\n", nss_ctx); + + up(&nss_rps_cfg_pvt.sem); +- return NSS_FAILURE; ++ return NSS_TX_FAILURE; + } + + up(&nss_rps_cfg_pvt.sem); +- return NSS_SUCCESS; ++ return NSS_TX_SUCCESS; + } + + /* +@@ -329,11 +329,11 @@ static nss_tx_status_t nss_rps_ipv6_hash + nss_warning("%px: nss_tx error setting rps\n", nss_ctx); + + up(&nss_rps_cfg_pvt.sem); +- return NSS_FAILURE; ++ return NSS_TX_FAILURE; + } + + up(&nss_rps_cfg_pvt.sem); +- return NSS_SUCCESS; ++ return NSS_TX_SUCCESS; + } + + /* +@@ -368,7 +368,7 @@ static nss_tx_status_t nss_rps_pri_map_c + nss_warning("%px: nss_tx error setting rps\n", nss_ctx); + + up(&nss_rps_cfg_pvt.sem); +- return NSS_FAILURE; ++ return NSS_TX_FAILURE; + } + + /* +@@ -378,7 +378,7 @@ static nss_tx_status_t nss_rps_pri_map_c + if (ret == 0) { + nss_warning("%px: Waiting for ack timed out\n", nss_ctx); + up(&nss_rps_cfg_pvt.sem); +- return NSS_FAILURE; ++ return NSS_TX_FAILURE; + } + + /* +@@ -386,13 +386,13 @@ static nss_tx_status_t nss_rps_pri_map_c + * If NACK: Handler function will restore nss_rps_config + * to previous state. + */ +- if (NSS_FAILURE == nss_rps_cfg_pvt.response) { ++ if (NSS_TX_FAILURE == nss_rps_cfg_pvt.response) { + up(&nss_rps_cfg_pvt.sem); +- return NSS_FAILURE; ++ return NSS_TX_FAILURE; + } + + up(&nss_rps_cfg_pvt.sem); +- return NSS_SUCCESS; ++ return NSS_TX_SUCCESS; + } + + /* diff --git a/package/qca-nss/qca-nss-ecm/Makefile b/package/qca-nss/qca-nss-ecm/Makefile new file mode 100644 index 0000000000..55c1174abd --- /dev/null +++ b/package/qca-nss/qca-nss-ecm/Makefile @@ -0,0 +1,362 @@ +# NHSS.QSDK.12.4.5.r2 +# by SqTER + +include $(TOPDIR)/rules.mk +include $(INCLUDE_DIR)/kernel.mk + +PKG_NAME:=qca-nss-ecm +PKG_RELEASE:=1 + +PKG_SOURCE_URL:=https://git.codelinaro.org/clo/qsdk/oss/lklm/qca-nss-ecm.git +PKG_SOURCE_DATE:=2023-07-25 +PKG_SOURCE_PROTO:=git +PKG_SOURCE_VERSION:=9acdcb05c04ae177a79c4c34cef0487fbcedbfaa +PKG_MIRROR_HASH:=f36f5b5318e23b0efe38097751f44c7a05b208b1884294eb8aab15d2a1e33677 +PKG_BUILD_PARALLEL:=1 + +include $(INCLUDE_DIR)/package.mk + +LOCAL_VARIANT=$(patsubst qca-nss-ecm-%,%,$(patsubst qca-nss-ecm-%,%,$(BUILD_VARIANT))) + +ifeq ($(CONFIG_QCA_NSS_ECM_EXAMPLES_PCC),y) + ECM_MAKE_OPTS+=ECM_CLASSIFIER_PCC_ENABLE=y + FILES_EXAMPLES=$(PKG_BUILD_DIR)/examples/ecm_pcc_test.ko +endif + +ifeq ($(CONFIG_QCA_NSS_ECM_EXAMPLES_MARK),y) + FILES_EXAMPLES+=$(PKG_BUILD_DIR)/examples/ecm_mark_test.ko +endif + +#Explicitly enable OVS external module, if ovsmgr is enabled. +ifneq ($(CONFIG_PACKAGE_kmod-qca-ovsmgr),) +CONFIG_QCA_NSS_ECM_OVS=y +endif + +ifeq ($(CONFIG_QCA_NSS_ECM_OVS),y) + FILES_EXAMPLES+=$(PKG_BUILD_DIR)/examples/ecm_ovs.ko +endif + +define KernelPackage/qca-nss-ecm/Default + SECTION:=kernel + CATEGORY:=Kernel modules + SUBMENU:=Network Support + TITLE:=QCA NSS Enhanced Connection Manager (ECM) + FILES:=$(PKG_BUILD_DIR)/*.ko $(FILES_EXAMPLES) + KCONFIG:=CONFIG_BRIDGE_NETFILTER=y \ + CONFIG_NF_CONNTRACK_EVENTS=y \ + CONFIG_NF_CONNTRACK_CHAIN_EVENTS=y \ + CONFIG_NF_CONNTRACK_DSCPREMARK_EXT=y + MENU:=1 + PROVIDES:=kmod-qca-nss-ecm + $(call AddDepends/qca-nss-ecm/Default) +endef + +define KernelPackage/qca-nss-ecm/Description/Default +This package contains the QCA NSS Enhanced Connection Manager +endef + +define AddDepends/qca-nss-ecm/Default + SUBMENU:=Network Support + DEPENDS:= \ + +@NSS_DRV_IPV6_ENABLE \ + +@NSS_DRV_VIRT_IF_ENABLE \ + +@NSS_DRV_WIFI_ENABLE \ + +@NSS_DRV_PPPOE_ENABLE \ + +@NSS_DRV_PPTP_ENABLE \ + +PACKAGE_kmod-qca-nss-drv:kmod-qca-nss-drv \ + +kmod-nf-conntrack \ + +kmod-ipt-physdev \ + +iptables-mod-physdev \ + +kmod-ppp +kmod-pppoe +kmod-pptp +endef + +define KernelPackage/qca-nss-ecm/Default/install + $(INSTALL_DIR) $(1)/etc/firewall.d $(1)/etc/init.d $(1)/usr/bin $(1)/lib/netifd/offload $(1)/etc/config $(1)/etc/uci-defaults $(1)/etc/sysctl.d + $(INSTALL_DATA) ./files/qca-nss-ecm.firewall $(1)/etc/firewall.d/qca-nss-ecm + $(INSTALL_BIN) ./files/qca-nss-ecm.init $(1)/etc/init.d/qca-nss-ecm + $(INSTALL_BIN) ./files/ecm_dump.sh $(1)/usr/bin/ + $(INSTALL_BIN) ./files/on-demand-down $(1)/lib/netifd/offload/on-demand-down + $(INSTALL_DATA) ./files/qca-nss-ecm.uci $(1)/etc/config/ecm + $(INSTALL_DATA) ./files/qca-nss-ecm.defaults $(1)/etc/uci-defaults/99-qca-nss-ecm + $(INSTALL_BIN) ./files/qca-nss-ecm.sysctl $(1)/etc/sysctl.d/99-qca-nss-ecm.conf +ifeq ($(CONFIG_KERNEL_IPQ_MEM_PROFILE),256) + echo 'net.netfilter.nf_conntrack_max=2048' >> $(1)/etc/sysctl.d/99-qca-nss-ecm.conf +endif +ifeq ($(CONFIG_KERNEL_IPQ_MEM_PROFILE),512) + echo 'net.netfilter.nf_conntrack_max=8192' >> $(1)/etc/sysctl.d/99-qca-nss-ecm.conf +endif +endef + +define KernelPackage/qca-nss-ecm-standard + $(call KernelPackage/qca-nss-ecm/Default) +ifneq ($(CONFIG_PACKAGE_kmod-pppol2tp),) + DEPENDS+=+PACKAGE_kmod-pppol2tp:kmod-pppol2tp +endif +ifneq ($(CONFIG_PACKAGE_kmod-qca-mcs),) + DEPENDS+=+kmod-qca-mcs +endif + VARIANT:=standard +endef + +define KernelPackage/qca-nss-ecm-standard/description + $(call KernelPackage/qca-nss-ecm/Description/Default) +endef + +define KernelPackage/qca-nss-ecm-standard/install +$(call KernelPackage/qca-nss-ecm/Default/install, $(1)) +endef + +# Variant with additional features enabled for premium profile +define KernelPackage/qca-nss-ecm-premium/Default +$(call KernelPackage/qca-nss-ecm/Default) + TITLE+:= (with premium features) + VARIANT:=premium + DEPENDS+:=+kmod-qca-hyfi-bridge +kmod-qca-mcs +ifeq ($(CONFIG_TARGET_ipq_ipq40xx)$(CONFIG_TARGET_ipq40xx),) + DEPENDS+=+kmod-bonding +endif +endef + +define KernelPackage/qca-nss-ecm-premium/Description/Default +$(call KernelPackage/qca-nss-ecm/Description/Default) +with the premium features enabled +endef + +define KernelPackage/qca-nss-ecm-premium/Default/install +$(call KernelPackage/qca-nss-ecm/install) +endef + +define KernelPackage/qca-nss-ecm-premium +$(call KernelPackage/qca-nss-ecm-premium/Default) +endef + +define KernelPackage/qca-nss-ecm-premium/description +$(call KernelPackage/qca-nss-ecm-premium/Description/Default) +endef + +define KernelPackage/qca-nss-ecm-premium/install +$(call KernelPackage/qca-nss-ecm-standard/install, $(1)) +endef + +# Variant with additional features enabled for noload profile +define KernelPackage/qca-nss-ecm-noload + $(call KernelPackage/qca-nss-ecm/Default) + TITLE+:= (with noload features) + PROVIDES:=kmod-qca-nss-ecm + VARIANT:=noload +ifeq ($(CONFIG_TARGET_ipq_ipq40xx)$(CONFIG_TARGET_ipq40xx),) + DEPENDS+=+kmod-bonding +endif +endef + +define KernelPackage/qca-nss-ecm-noload/description + $(call KernelPackage/qca-nss-ecm/Description/Default) + When selected, this package installs the driver but does not load it at init. +endef + +define KernelPackage/qca-nss-ecm-noload/install +$(call KernelPackage/qca-nss-ecm/Default/install, $(1)) + # + # Remove the START line from the init script, so that the symlink + # in the /etc/rc.d directory is not created. + # + sed -i '/START=/d' $(1)/etc/init.d/qca-nss-ecm +endef + +define KernelPackage/qca-nss-ecm-premium-noload + $(call KernelPackage/qca-nss-ecm-premium/Default) + TITLE+:= (noload) + PROVIDES:=kmod-qca-nss-ecm-premium + VARIANT:=premium-noload +endef + +define KernelPackage/qca-nss-ecm-premium-noload/description + $(call KernelPackage/qca-nss-ecm-premium/Description/Default) + When selected, this package installs the driver but does not load it at init. +endef + +define KernelPackage/qca-nss-ecm-premium-noload/install +$(call KernelPackage/qca-nss-ecm-premium/Default/install, $(1)) +endef + +define Build/InstallDev/qca-nss-ecm + $(INSTALL_DIR) $(1)/usr/include/qca-nss-ecm + $(CP) $(PKG_BUILD_DIR)/exports/* $(1)/usr/include/qca-nss-ecm/ +endef + +define Build/InstallDev + $(call Build/InstallDev/qca-nss-ecm,$(1)) +endef + +EXTRA_CFLAGS+= \ + -I$(STAGING_DIR)/usr/include/hyfibr \ + -I$(STAGING_DIR)/usr/include/qca-mcs \ + -I$(STAGING_DIR)/usr/include/qca-nss-drv \ + -I$(STAGING_DIR)/usr/include/shortcut-fe + +ECM_MAKE_OPTS:=ECM_CLASSIFIER_HYFI_ENABLE=n +ifeq ($(LOCAL_VARIANT),standard) +ECM_MAKE_OPTS+=ECM_NON_PORTED_SUPPORT_ENABLE=y \ + ECM_STATE_OUTPUT_ENABLE=y \ + ECM_INTERFACE_VLAN_ENABLE=y \ + ECM_CLASSIFIER_DSCP_ENABLE=y \ + ECM_CLASSIFIER_MARK_ENABLE=y \ + ECM_CLASSIFIER_NL_ENABLE=y \ + ECM_TRACKER_DPI_SUPPORT_ENABLE=y \ + ECM_DB_ADVANCED_STATS_ENABLE=y \ + ECM_CLASSIFIER_EMESH_ENABLE=n + +ifeq ($(CONFIG_TARGET_ipq_ipq40xx)$(CONFIG_TARGET_ipq40xx),) +ECM_MAKE_OPTS+=ECM_INTERFACE_BOND_ENABLE=n +endif +endif + +ifneq ($(CONFIG_PACKAGE_kmod-qca-nss-drv-ovpn-link),) +ECM_MAKE_OPTS+=ECM_INTERFACE_OVPN_ENABLE=y +else +ECM_MAKE_OPTS+=ECM_INTERFACE_OVPN_ENABLE=n +endif + +ifneq ($(CONFIG_PACKAGE_kmod-qca-nss-drv-vxlanmgr),) +ECM_MAKE_OPTS+=ECM_INTERFACE_VXLAN_ENABLE=y +else +ECM_MAKE_OPTS+=ECM_INTERFACE_VXLAN_ENABLE=n +endif + +ifneq ($(CONFIG_PACKAGE_kmod-qca-ovsmgr),) +ECM_MAKE_OPTS+=ECM_INTERFACE_OVS_BRIDGE_ENABLE=y \ + ECM_CLASSIFIER_OVS_ENABLE=y +EXTRA_CFLAGS+= -I$(STAGING_DIR)/usr/include/qca-ovsmgr +else +ECM_MAKE_OPTS+=ECM_INTERFACE_OVS_BRIDGE_ENABLE=n \ + ECM_CLASSIFIER_OVS_ENABLE=n +endif + +ifneq ($(CONFIG_PACKAGE_kmod-macvlan),) +ECM_MAKE_OPTS+=ECM_INTERFACE_MACVLAN_ENABLE=y +else +ECM_MAKE_OPTS+=ECM_INTERFACE_MACVLAN_ENABLE=n +endif + +ifneq ($(CONFIG_PACKAGE_kmod-qca-mcs),) +ECM_MAKE_OPTS+=ECM_MULTICAST_ENABLE=y +else +ECM_MAKE_OPTS+=ECM_MULTICAST_ENABLE=n +endif + +ifneq ($(CONFIG_PACKAGE_kmod-ipsec),) +ECM_MAKE_OPTS+=ECM_INTERFACE_IPSEC_ENABLE=y +else +ECM_MAKE_OPTS+=ECM_INTERFACE_IPSEC_ENABLE=n +endif + +ifneq ($(CONFIG_PACKAGE_kmod-pppoe),) +ECM_MAKE_OPTS+= ECM_INTERFACE_PPPOE_ENABLE=y \ + ECM_INTERFACE_PPTP_ENABLE=y \ + ECM_INTERFACE_PPP_ENABLE=y +else +ECM_MAKE_OPTS+= ECM_INTERFACE_PPPOE_ENABLE=n \ + ECM_INTERFACE_PPTP_ENABLE=n \ + ECM_INTERFACE_PPP_ENABLE=n +endif + +ifneq ($(CONFIG_PACKAGE_kmod-pppol2tp),) +ECM_MAKE_OPTS+=ECM_INTERFACE_L2TPV2_ENABLE=y +else +ECM_MAKE_OPTS+=ECM_INTERFACE_L2TPV2_ENABLE=n +endif + +ifneq ($(CONFIG_PACKAGE_kmod-gre)$(CONFIG_PACKAGE_kmod-gre6),) +ECM_MAKE_OPTS+=ECM_INTERFACE_GRE_TAP_ENABLE=y \ + ECM_INTERFACE_GRE_TUN_ENABLE=y +else +ECM_MAKE_OPTS+=ECM_INTERFACE_GRE_TAP_ENABLE=n \ + ECM_INTERFACE_GRE_TUN_ENABLE=n +endif + +ifneq ($(CONFIG_PACKAGE_kmod-sit),) +ECM_MAKE_OPTS+=ECM_INTERFACE_SIT_ENABLE=y +else +ECM_MAKE_OPTS+=ECM_INTERFACE_SIT_ENABLE=n +endif + +ifneq ($(CONFIG_PACKAGE_kmod-ip6-tunnel),) +ECM_MAKE_OPTS+=ECM_INTERFACE_TUNIPIP6_ENABLE=y +else +ECM_MAKE_OPTS+=ECM_INTERFACE_TUNIPIP6_ENABLE=n +endif + +ifneq ($(CONFIG_PACKAGE_kmod-qca-nss-drv-mscs),) +ECM_MAKE_OPTS+=ECM_CLASSIFIER_MSCS_ENABLE=y +else +ECM_MAKE_OPTS+=ECM_CLASSIFIER_MSCS_ENABLE=n +endif + +# Disable ECM IPv6 support when global IPv6 support is disabled. +ifneq ($(CONFIG_IPV6),) +ECM_MAKE_OPTS+=ECM_IPV6_ENABLE=y +endif + +# Enable NSS frontend for all the platforms except ipq40xx +ifeq ($(CONFIG_TARGET_ipq_ipq40xx)$(CONFIG_TARGET_ipq40xx),) +ifneq ($(BUILD_VARIANT), nonss) +ECM_MAKE_OPTS+=ECM_FRONT_END_NSS_ENABLE=y +endif +endif + +# Keeping default as ipq806x for branches that does not have subtarget framework +ifeq ($(CONFIG_TARGET_ipq),y) +subtarget:=$(SUBTARGET) +else +subtarget:=$(CONFIG_TARGET_BOARD) +endif + +define Build/InstallDev + $(INSTALL_DIR) $(1)/usr/include/qca-nss-ecm + $(CP) $(PKG_BUILD_DIR)/exports/* $(1)/usr/include/qca-nss-ecm +endef + +define Build/Compile + +$(MAKE) $(PKG_JOBS) -C "$(LINUX_DIR)" $(strip $(ECM_MAKE_OPTS)) \ + $(KERNEL_MAKE_FLAGS) \ + $(PKG_MAKE_FLAGS) \ + M="$(PKG_BUILD_DIR)" \ + EXTRA_CFLAGS="$(EXTRA_CFLAGS)" SoC="$(subtarget)" \ + EXAMPLES_BUILD_PCC="$(CONFIG_QCA_NSS_ECM_EXAMPLES_PCC)" \ + EXAMPLES_BUILD_MARK="$(CONFIG_QCA_NSS_ECM_EXAMPLES_MARK)" \ + EXAMPLES_BUILD_OVS="$(CONFIG_QCA_NSS_ECM_OVS)" \ + ECM_FRONT_END_SFE_ENABLE="$(CONFIG_QCA_ECM_SFE_SUPPORT)" \ + modules +endef + +define KernelPackage/qca-nss-ecm-standard/config +menu "ECM Configuration" + + config QCA_NSS_ECM_EXAMPLES_PCC + bool "Build PCC usage example" + help + Selecting this will build the PCC classifier usage example module. + default n + + config QCA_NSS_ECM_EXAMPLES_MARK + bool "Build Mark classifier usage example" + help + Selecting this will build the Mark classifier usage example module. + default n + + config QCA_NSS_ECM_OVS + bool "Build OVS classifier external module" + help + Selecting this will build the OVS classifier external module. + default n + + config QCA_ECM_SFE_SUPPORT + bool "Add SFE support to ECM driver" + default n +endmenu +endef + +$(eval $(call KernelPackage,qca-nss-ecm-noload)) +$(eval $(call KernelPackage,qca-nss-ecm-standard)) +$(eval $(call KernelPackage,qca-nss-ecm-premium-noload)) +$(eval $(call KernelPackage,qca-nss-ecm-premium)) diff --git a/package/qca-nss/qca-nss-ecm/files/ecm_dump.sh b/package/qca-nss/qca-nss-ecm/files/ecm_dump.sh new file mode 100644 index 0000000000..dbf7de753f --- /dev/null +++ b/package/qca-nss/qca-nss-ecm/files/ecm_dump.sh @@ -0,0 +1,95 @@ +#!/bin/sh +# +# Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# + +ECM_MODULE=${1:-ecm_state} +MOUNT_ROOT=/dev/ecm + +# +# usage: ecm_dump.sh [module=ecm_db] +# +# with no parameters, ecm_dump.sh will attempt to mount the +# ecm_db state file and cat its contents. +# +# example with a parameter: ecm_dump.sh ecm_classifier_default +# +# this will cause ecm_dump to attempt to find and mount the state +# file for the ecm_classifier_default module, and if successful +# cat the contents. +# + +# this is one of the state files, which happens to be the +# last module started in ecm +ECM_STATE=/sys/kernel/debug/ecm/ecm_state/state_dev_major + +# tests to see if ECM is up and ready to receive commands. +# returns 0 if ECM is fully up and ready, else 1 +ecm_is_ready() { + if [ ! -e "${ECM_STATE}" ] + then + return 1 + fi + return 0 +} + +# +# module_state_mount(module_name) +# Mounts the state file of the module, if supported +# +module_state_mount() { + local module_name=$1 + local mount_dir=$2 + local state_file="/sys/kernel/debug/ecm/${module_name}/state_dev_major" + + if [ -e "${mount_dir}/${module_name}" ] + then + # already mounted + return 0 + fi + + #echo "Mount state file for $module_name ..." + if [ ! -e "$state_file" ] + then + #echo "... $module_name does not support state" + return 1 + fi + + local major="`cat $state_file`" + #echo "... Mounting state $state_file with major: $major" + mknod "${mount_dir}/${module_name}" c $major 0 +} + +# +# main +# +ecm_is_ready || { + #echo "ECM is not running" + exit 1 +} + +# all state files are mounted under MOUNT_ROOT, so make sure it exists +mkdir -p ${MOUNT_ROOT} + +# +# attempt to mount state files for the requested module and cat it +# if the mount succeeded +# +module_state_mount ${ECM_MODULE} ${MOUNT_ROOT} && { + cat ${MOUNT_ROOT}/${ECM_MODULE} + exit 0 +} + +exit 2 diff --git a/package/qca-nss/qca-nss-ecm/files/on-demand-down b/package/qca-nss/qca-nss-ecm/files/on-demand-down new file mode 100644 index 0000000000..02d708e03b --- /dev/null +++ b/package/qca-nss/qca-nss-ecm/files/on-demand-down @@ -0,0 +1,6 @@ +#!/bin/sh +# Copyright (c) 2016 The Linux Foundation. All rights reserved. + +[ -e "/sys/kernel/debug/ecm/ecm_db/defunct_all" ] && { + echo 1 > /sys/kernel/debug/ecm/ecm_db/defunct_all +} diff --git a/package/qca-nss/qca-nss-ecm/files/qca-nss-ecm.defaults b/package/qca-nss/qca-nss-ecm/files/qca-nss-ecm.defaults new file mode 100644 index 0000000000..39c2099a45 --- /dev/null +++ b/package/qca-nss/qca-nss-ecm/files/qca-nss-ecm.defaults @@ -0,0 +1,13 @@ +#!/bin/sh + +uci -q batch << EOF + delete firewall.nss_ecm + set firewall.nss_ecm=include + set firewall.nss_ecm.type=script + set firewall.nss_ecm.path=/etc/firewall.d/qca-nss-ecm + set firewall.nss_ecm.family=any + set firewall.nss_ecm.reload=1 + commit firewall +EOF + +exit 0 diff --git a/package/qca-nss/qca-nss-ecm/files/qca-nss-ecm.firewall b/package/qca-nss/qca-nss-ecm/files/qca-nss-ecm.firewall new file mode 100644 index 0000000000..7cbd46dbb7 --- /dev/null +++ b/package/qca-nss/qca-nss-ecm/files/qca-nss-ecm.firewall @@ -0,0 +1,33 @@ +#!/bin/sh +# +# Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +# Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# + +iptables -nvL FORWARD | grep -q "physdev" && iptables -Z FORWARD 1 +iptables -nvL FORWARD | grep -q "physdev" || iptables -I FORWARD -m physdev --physdev-is-bridged -j ACCEPT + +if grep -q "fw3" /etc/init.d/firewall; then + iptables -nvL | grep -q "Chain RATE-LIMIT" && iptables -F RATE-LIMIT + iptables -nvL | grep -q "Chain RATE-LIMIT" || iptables -N RATE-LIMIT + iptables -A RATE-LIMIT --match limit --limit 1000/sec --limit-burst 1000 -j RETURN + iptables -A RATE-LIMIT -j DROP + iptables -I zone_wan_forward 5 --match conntrack --ctstate NEW -j RATE-LIMIT +elif grep -q "fw4" /etc/init.d/firewall; then + nft add chain inet fw4 RATE-LIMIT + nft add rule inet fw4 RATE-LIMIT limit rate 1000/second burst 1000 packets counter return + nft add rule inet fw4 RATE-LIMIT counter drop + nft add rule inet fw4 forward_wan ct state new counter jump RATE-LIMIT +fi diff --git a/package/qca-nss/qca-nss-ecm/files/qca-nss-ecm.init b/package/qca-nss/qca-nss-ecm/files/qca-nss-ecm.init new file mode 100644 index 0000000000..77dea24605 --- /dev/null +++ b/package/qca-nss/qca-nss-ecm/files/qca-nss-ecm.init @@ -0,0 +1,122 @@ +#!/bin/sh /etc/rc.common +# +# Copyright (c) 2014, 2019 The Linux Foundation. All rights reserved. +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +# The shebang above has an extra space intentially to avoid having +# openwrt build scripts automatically enable this package starting +# at boot. + +START=19 + +get_front_end_mode() { + config_load "ecm" + config_get front_end global acceleration_engine "nss" + + case $front_end in + auto) + echo '0' + ;; + nss) + echo '1' + ;; + sfe) + echo '2' + ;; + *) + echo 'uci_option_acceleration_engine is invalid' + esac +} + +support_bridge() { + #NSS support bridge acceleration + [ -d /sys/kernel/debug/ecm/ecm_nss_ipv4 ] && return 0 + #SFE doesn't support bridge acceleration + [ -d /sys/kernel/debug/ecm/ecm_sfe_ipv4 ] && return 1 +} + +load_sfe() { + [ -d /sys/module/shortcut_fe ] || insmod shortcut-fe + [ -d /sys/module/shortcut_fe_ipv6 ] || insmod shortcut-fe-ipv6 + [ -d /sys/module/shortcut_fe_drv ] || insmod shortcut-fe-drv +} + +load_ecm() { + [ -d /sys/module/ecm ] || { + insmod ecm front_end_selection=$(get_front_end_mode) + echo 1 > /sys/kernel/debug/ecm/ecm_classifier_default/accel_delay_pkts + } + + support_bridge && { + sysctl -w net.bridge.bridge-nf-call-ip6tables=1 + sysctl -w net.bridge.bridge-nf-call-iptables=1 + } +} + +unload_ecm() { + sysctl -w net.bridge.bridge-nf-call-ip6tables=0 + sysctl -w net.bridge.bridge-nf-call-iptables=0 + + if [ -d /sys/module/ecm ]; then + # + # Stop ECM frontends + # + echo 1 > /sys/kernel/debug/ecm/front_end_ipv4_stop + echo 1 > /sys/kernel/debug/ecm/front_end_ipv6_stop + + # + # Defunct the connections + # + echo 1 > /sys/kernel/debug/ecm/ecm_db/defunct_all + sleep 5; + + rmmod ecm + sleep 1 + fi +} + +start() { + load_ecm + + # If the acceleration engine is NSS, enable wifi redirect. + [ -d /sys/kernel/debug/ecm/ecm_nss_ipv4 ] && sysctl -w dev.nss.general.redirect=1 + + support_bridge && { + # Delete original configuration before appending new + sed '/net.bridge.bridge-nf-call-ip6tables/d' -i /etc/sysctl.d/qca-nss-ecm.conf + sed '/net.bridge.bridge-nf-call-iptables/d' -i /etc/sysctl.d/qca-nss-ecm.conf + + echo 'net.bridge.bridge-nf-call-ip6tables=1' >> /etc/sysctl.d/qca-nss-ecm.conf + echo 'net.bridge.bridge-nf-call-iptables=1' >> /etc/sysctl.d/qca-nss-ecm.conf + } + + if [ -d /sys/module/qca_ovsmgr ]; then + insmod ecm_ovs + fi + +} + +stop() { + # If the acceleration engine is NSS, disable wifi redirect. + [ -d /sys/kernel/debug/ecm/ecm_nss_ipv4 ] && sysctl -w dev.nss.general.redirect=0 + + sed '/net.bridge.bridge-nf-call-ip6tables=1/d' -i /etc/sysctl.d/qca-nss-ecm.conf + sed '/net.bridge.bridge-nf-call-iptables=1/d' -i /etc/sysctl.d/qca-nss-ecm.conf + + if [ -d /sys/module/ecm_ovs ]; then + rmmod ecm_ovs + fi + + unload_ecm +} diff --git a/package/qca-nss/qca-nss-ecm/files/qca-nss-ecm.sysctl b/package/qca-nss/qca-nss-ecm/files/qca-nss-ecm.sysctl new file mode 100644 index 0000000000..1a3d76b189 --- /dev/null +++ b/package/qca-nss/qca-nss-ecm/files/qca-nss-ecm.sysctl @@ -0,0 +1,2 @@ +# nf_conntrack_tcp_no_window_check is 0 by default, set it to 1 +net.netfilter.nf_conntrack_tcp_no_window_check=1 diff --git a/package/qca-nss/qca-nss-ecm/files/qca-nss-ecm.uci b/package/qca-nss/qca-nss-ecm/files/qca-nss-ecm.uci new file mode 100644 index 0000000000..4f2de68771 --- /dev/null +++ b/package/qca-nss/qca-nss-ecm/files/qca-nss-ecm.uci @@ -0,0 +1,2 @@ +config ecm 'global' + option acceleration_engine 'auto' diff --git a/package/qca-nss/qca-nss-ecm/patches/100-kernel-5.15-support.patch b/package/qca-nss/qca-nss-ecm/patches/100-kernel-5.15-support.patch new file mode 100644 index 0000000000..6d74b253f2 --- /dev/null +++ b/package/qca-nss/qca-nss-ecm/patches/100-kernel-5.15-support.patch @@ -0,0 +1,1418 @@ +--- a/Makefile ++++ b/Makefile +@@ -17,9 +17,7 @@ + # ################################################### + # Makefile for the QCA NSS ECM + # ################################################### +-ifneq ($(findstring 6.1., $(KERNELVERSION)),) +-include $(obj)/Makefile_61.mk +-else ++ + ifeq ($(ECM_FRONT_END_SFE_ENABLE), y) + obj-m += examples/ecm_sfe_l2.o + endif +@@ -76,12 +74,12 @@ ecm-$(ECM_NON_PORTED_SUPPORT_ENABLE) += + ifeq ($(ECM_NON_PORTED_SUPPORT_ENABLE), y) + ecm-$(ECM_IPV6_ENABLE) += frontends/cmn/ecm_non_ported_ipv6.o + endif +- +-#SFE Multicast is enabled in case NSS disabled ++ifeq ($(ECM_FRONT_END_NSS_ENABLE), y) + ecm-$(ECM_MULTICAST_ENABLE) += frontends/cmn/ecm_multicast_ipv4.o + ifeq ($(ECM_IPV6_ENABLE), y) + ecm-$(ECM_MULTICAST_ENABLE) += frontends/cmn/ecm_multicast_ipv6.o + endif ++endif + + # ############################################################################# + # Define ECM_FRONT_END_NSS_ENABLE=y in order to select +@@ -111,11 +109,6 @@ ecm-$(ECM_FRONT_END_PPE_ENABLE) += front + ccflags-$(ECM_FRONT_END_PPE_ENABLE) += -DECM_FRONT_END_PPE_ENABLE + + # ############################################################################# +-# Define ECM_FRONT_END_PPE_QOS_ENABLE=y in order to enable PPE QoS +-# ############################################################################# +-ccflags-$(ECM_FRONT_END_PPE_QOS_ENABLE) += -DECM_FRONT_END_PPE_QOS_ENABLE +- +-# ############################################################################# + # Define ECM_FRONT_END_CONN_LIMIT_ENABLE=y in order to limit accelerated + # connections for low-memory profiles. + # ############################################################################# +@@ -132,10 +125,18 @@ ccflags-$(ECM_INTERFACE_BOND_ENABLE) += + # Define ECM_INTERFACE_PPPOE_ENABLE=y in order + # to enable support for PPPoE acceleration. + # ############################################################################# +-ECM_INTERFACE_PPPOE_ENABLE=y ++ifndef $(ECM_INTERFACE_PPPOE_ENABLE) ++ ECM_INTERFACE_PPPOE_ENABLE=y ++endif + ccflags-$(ECM_INTERFACE_PPPOE_ENABLE) += -DECM_INTERFACE_PPPOE_ENABLE + + # ############################################################################# ++# Define ECM_INTERFACE_L2TPV2_PPTP_ENABLE=y in order ++# to enable support for l2tpv2 or PPTP detection. ++# ############################################################################# ++ccflags-$(ECM_INTERFACE_L2TPV2_PPTP_ENABLE) += -DECM_INTERFACE_L2TPV2_PPTP_ENABLE ++ ++# ############################################################################# + # Define ECM_INTERFACE_L2TPV2_ENABLE=y in order + # to enable support for l2tpv2 acceleration. + # ############################################################################# +@@ -162,6 +163,12 @@ endif + ccflags-$(ECM_INTERFACE_PPP_ENABLE) += -DECM_INTERFACE_PPP_ENABLE + + # ############################################################################# ++# Define ECM_INTERFACE_GRE_ENABLE=y in order ++# to enable support for GRE detection. ++# ############################################################################# ++ccflags-$(ECM_INTERFACE_GRE_ENABLE) += -DECM_INTERFACE_GRE_ENABLE ++ ++# ############################################################################# + # Define ECM_INTERFACE_GRE_TAP_ENABLE=y in order + # to enable support for GRE TAP interface. + # ############################################################################# +@@ -212,23 +219,14 @@ ccflags-$(ECM_IPV6_ENABLE) += -DECM_IPV6 + + # ############################################################################# + # Define ECM_MULTICAST_ENABLE=y in order to enable support for ECM Multicast +-# NSS is enabled, using NSS multicast acceleration, otherwise using SFE +-# multicast acceleration. + # ############################################################################# +- +-ecm-$(ECM_MULTICAST_ENABLE) += ecm_db/ecm_db_multicast.o +-ccflags-$(ECM_MULTICAST_ENABLE) += -DECM_MULTICAST_ENABLE +- + ifeq ($(ECM_FRONT_END_NSS_ENABLE), y) + ecm-$(ECM_MULTICAST_ENABLE) += frontends/nss/ecm_nss_multicast_ipv4.o + ifeq ($(ECM_IPV6_ENABLE), y) + ecm-$(ECM_MULTICAST_ENABLE) += frontends/nss/ecm_nss_multicast_ipv6.o + endif +-else +-ecm-$(ECM_MULTICAST_ENABLE) += frontends/sfe/ecm_sfe_multicast_ipv4.o +-ifeq ($(ECM_IPV6_ENABLE), y) +-ecm-$(ECM_MULTICAST_ENABLE) += frontends/sfe/ecm_sfe_multicast_ipv6.o +-endif ++ecm-$(ECM_MULTICAST_ENABLE) += ecm_db/ecm_db_multicast.o ++ccflags-$(ECM_MULTICAST_ENABLE) += -DECM_MULTICAST_ENABLE + endif + + # ############################################################################# +@@ -244,7 +242,9 @@ ccflags-$(ECM_INTERFACE_OVS_BRIDGE_ENABL + # ############################################################################# + # Define ECM_INTERFACE_VLAN_ENABLE=y in order to enable support for VLAN + # ############################################################################# +-ECM_INTERFACE_VLAN_ENABLE=y ++ifndef $(ECM_INTERFACE_VLAN_ENABLE) ++ ECM_INTERFACE_VLAN_ENABLE=y ++endif + ccflags-$(ECM_INTERFACE_VLAN_ENABLE) += -DECM_INTERFACE_VLAN_ENABLE + + # ############################################################################# +@@ -258,8 +258,7 @@ ccflags-$(ECM_INTERFACE_MACVLAN_ENABLE) + ccflags-$(ECM_INTERFACE_IPSEC_ENABLE) += -DECM_INTERFACE_IPSEC_ENABLE + + ECM_INTERFACE_IPSEC_GLUE_LAYER_SUPPORT_ENABLE=n +-ifeq ($(SoC),$(filter $(SoC), ipq807x ipq807x_64 ipq60xx ipq60xx_64 ipq50xx \ +- ipq50xx_64 ipq95xx_32 ipq95xx ipq53xx_32 ipq53xx)) ++ifeq ($(SoC),$(filter $(SoC), ipq807x ipq807x_64 ipq60xx ipq60xx_64 ipq50xx ipq50xx_64 ipq95xx_32 ipq95xx)) + ECM_INTERFACE_IPSEC_GLUE_LAYER_SUPPORT_ENABLE=$(ECM_INTERFACE_IPSEC_ENABLE) + ccflags-$(ECM_INTERFACE_IPSEC_GLUE_LAYER_SUPPORT_ENABLE) += -DECM_INTERFACE_IPSEC_GLUE_LAYER_SUPPORT_ENABLE + endif +@@ -286,7 +285,9 @@ ccflags-$(ECM_CLASSIFIER_OVS_ENABLE) += + # ############################################################################# + # Define ECM_CLASSIFIER_MARK_ENABLE=y in order to enable mark classifier. + # ############################################################################# +-ECM_CLASSIFIER_MARK_ENABLE=y ++ifndef $(ECM_CLASSIFIER_MARK_ENABLE) ++ ECM_CLASSIFIER_MARK_ENABLE=y ++endif + ecm-$(ECM_CLASSIFIER_MARK_ENABLE) += ecm_classifier_mark.o + ccflags-$(ECM_CLASSIFIER_MARK_ENABLE) += -DECM_CLASSIFIER_MARK_ENABLE + +@@ -310,21 +311,14 @@ ccflags-$(ECM_CLASSIFIER_NL_ENABLE) += - + # ############################################################################# + # Define ECM_CLASSIFIER_DSCP_ENABLE=y in order to enable DSCP classifier. + # ############################################################################# +-ECM_CLASSIFIER_DSCP_ENABLE=y ++ifndef $(ECM_CLASSIFIER_DSCP_ENABLE) ++ ECM_CLASSIFIER_DSCP_ENABLE=y ++endif + ecm-$(ECM_CLASSIFIER_DSCP_ENABLE) += ecm_classifier_dscp.o + ccflags-$(ECM_CLASSIFIER_DSCP_ENABLE) += -DECM_CLASSIFIER_DSCP_ENABLE + ccflags-$(ECM_CLASSIFIER_DSCP_IGS) += -DECM_CLASSIFIER_DSCP_IGS + + # ############################################################################# +-# Define ECM_CLASSIFIER_HYFI_ENABLE=y in order to enable +-# the Hy-Fi classifier in ECM. Currently disabled until the integration +-# with Hy-Fi is completed. +-# ############################################################################# +-# +-ecm-$(ECM_CLASSIFIER_HYFI_ENABLE) += ecm_classifier_hyfi.o +-ccflags-$(ECM_CLASSIFIER_HYFI_ENABLE) += -DECM_CLASSIFIER_HYFI_ENABLE +- +-# ############################################################################# + # Define ECM_CLASSIFIER_PCC_ENABLE=y in order to enable + # the Parental Controls subsystem classifier in ECM. Currently disabled until + # customers require it / if they need to integrate their Parental Controls with it. +@@ -334,6 +328,15 @@ ecm-$(ECM_CLASSIFIER_PCC_ENABLE) += ecm_ + ccflags-$(ECM_CLASSIFIER_PCC_ENABLE) += -DECM_CLASSIFIER_PCC_ENABLE + + # ############################################################################# ++# Define ECM_CLASSIFIER_HYFI_ENABLE=y in order to enable ++# the Hy-Fi classifier in ECM. Currently disabled until the integration ++# with Hy-Fi is completed. ++# ############################################################################# ++# ++ecm-$(ECM_CLASSIFIER_HYFI_ENABLE) += ecm_classifier_hyfi.o ++ccflags-$(ECM_CLASSIFIER_HYFI_ENABLE) += -DECM_CLASSIFIER_HYFI_ENABLE ++ ++# ############################################################################# + # Define ECM_CLASSIFIER_EMESH_ENABLE=y in order to enable E-Mesh classifier. + # ############################################################################# + ecm-$(ECM_CLASSIFIER_EMESH_ENABLE) += ecm_classifier_emesh.o +@@ -370,27 +373,36 @@ ccflags-$(ECM_NON_PORTED_SUPPORT_ENABLE) + # ############################################################################# + # Define ECM_STATE_OUTPUT_ENABLE=y to support XML state output + # ############################################################################# +-ECM_STATE_OUTPUT_ENABLE=y ++ifndef $(ECM_STATE_OUTPUT_ENABLE) ++ ECM_STATE_OUTPUT_ENABLE=y ++endif + ecm-$(ECM_STATE_OUTPUT_ENABLE) += ecm_state.o + ccflags-$(ECM_STATE_OUTPUT_ENABLE) += -DECM_STATE_OUTPUT_ENABLE + + # ############################################################################# + # Define ECM_DB_ADVANCED_STATS_ENABLE to support XML state output + # ############################################################################# +-ECM_DB_ADVANCED_STATS_ENABLE=y ++ifndef $(ECM_DB_ADVANCED_STATS_ENABLE) ++ ECM_DB_ADVANCED_STATS_ENABLE=y ++endif + ccflags-$(ECM_DB_ADVANCED_STATS_ENABLE) += -DECM_DB_ADVANCED_STATS_ENABLE + + # ############################################################################# + # Define ECM_DB_CONNECTION_CROSS_REFERENCING_ENABLE=y in order to enable + # the database to track relationships between objects. + # ############################################################################# +-ECM_DB_CONNECTION_CROSS_REFERENCING_ENABLE=y ++ifndef $(ECM_DB_CONNECTION_CROSS_REFERENCING_ENABLE) ++ ECM_DB_CONNECTION_CROSS_REFERENCING_ENABLE=y ++endif + ccflags-$(ECM_DB_CONNECTION_CROSS_REFERENCING_ENABLE) += -DECM_DB_XREF_ENABLE + + # ############################################################################# + # Define ECM_TRACKER_DPI_SUPPORT_ENABLE=y in order to enable support for + # deep packet inspection and tracking of data with the trackers. + # ############################################################################# ++ifndef $(ECM_TRACKER_DPI_SUPPORT_ENABLE) ++ ECM_TRACKER_DPI_SUPPORT_ENABLE=y ++endif + ccflags-$(ECM_TRACKER_DPI_SUPPORT_ENABLE) += -DECM_TRACKER_DPI_SUPPORT_ENABLE + + # ############################################################################# +@@ -398,14 +410,18 @@ ccflags-$(ECM_TRACKER_DPI_SUPPORT_ENABLE + # support for the database keeping lists of connections that are assigned + # on a per TYPE of classifier basis. + # ############################################################################# +-ECM_DB_CLASSIFIER_TYPE_ASSIGNMENTS_TRACK_ENABLE=y ++ifndef $(ECM_DB_CLASSIFIER_TYPE_ASSIGNMENTS_TRACK_ENABLE) ++ ECM_DB_CLASSIFIER_TYPE_ASSIGNMENTS_TRACK_ENABLE=y ++endif + ccflags-$(ECM_DB_CLASSIFIER_TYPE_ASSIGNMENTS_TRACK_ENABLE) += -DECM_DB_CTA_TRACK_ENABLE + + # ############################################################################# + # Define ECM_BAND_STEERING_ENABLE=y in order to enable + # band steering feature. + # ############################################################################# +-ECM_BAND_STEERING_ENABLE=y ++ifndef $(ECM_BAND_STEERING_ENABLE) ++ ECM_BAND_STEERING_ENABLE=y ++endif + ccflags-$(ECM_BAND_STEERING_ENABLE) += -DECM_BAND_STEERING_ENABLE + + # ############################################################################# +@@ -415,17 +431,6 @@ ccflags-$(ECM_BAND_STEERING_ENABLE) += - + ccflags-$(ECM_INTERFACE_OVPN_ENABLE) += -DECM_INTERFACE_OVPN_ENABLE + + # ############################################################################# +-# Define ECM_BRIDGE_VLAN_FILTERING_ENABLE=y in order +-# to enable support for bridge VLAN filter acceleration. +-# ############################################################################# +-ccflags-$(ECM_BRIDGE_VLAN_FILTERING_ENABLE) += -DECM_BRIDGE_VLAN_FILTERING_ENABLE +- +-# ############################################################################# +-# Define ECM_FRONT_END_FSE_ENABLE=y in order to enable FSE rule push from ECM frontend. +-# ############################################################################# +-ccflags-$(ECM_FRONT_END_FSE_ENABLE) += -DECM_FRONT_END_FSE_ENABLE +- +-# ############################################################################# + # Debug flags, set these to = 0 if you want to disable all debugging for that + # file. + # By turning off debugs you gain maximum ECM performance. +@@ -466,11 +471,9 @@ ccflags-y += -DECM_SFE_COMMON_DEBUG_LEVE + ccflags-y += -DECM_SFE_IPV4_DEBUG_LEVEL=1 + ccflags-y += -DECM_SFE_PORTED_IPV4_DEBUG_LEVEL=1 + ccflags-y += -DECM_SFE_NON_PORTED_IPV4_DEBUG_LEVEL=1 +-ccflags-y += -DECM_SFE_MULTICAST_IPV4_DEBUG_LEVEL=1 + ccflags-y += -DECM_SFE_IPV6_DEBUG_LEVEL=1 + ccflags-y += -DECM_SFE_PORTED_IPV6_DEBUG_LEVEL=1 + ccflags-y += -DECM_SFE_NON_PORTED_IPV6_DEBUG_LEVEL=1 +-ccflags-y += -DECM_SFE_MULTICAST_IPV6_DEBUG_LEVEL=1 + ccflags-y += -DECM_PPE_COMMON_DEBUG_LEVEL=1 + ccflags-y += -DECM_PPE_IPV4_DEBUG_LEVEL=1 + ccflags-y += -DECM_PPE_PORTED_IPV4_DEBUG_LEVEL=1 +@@ -494,16 +497,8 @@ ccflags-y += -I$(obj)/ -I$(obj)/ecm_db - + + ifeq ($(ECM_FRONT_END_PPE_ENABLE), y) + ccflags-y += -I$(obj)/frontends/ppe +-ifeq ($(SoC),$(filter $(SoC), ipq53xx_32 ipq53xx)) +-# ############################################################################# +-# Define ECM_PPE_SOURCE_INTERFACE_CHECK_ENABLE=y in order +-# to enable support for source interface check in PPE. +-# ############################################################################# +-ccflags-y += -DECM_PPE_SOURCE_INTERFACE_CHECK_ENABLE=1 +-endif + endif + + ccflags-y += -Wall -Werror + + obj ?= . +-endif +--- a/Makefile_61.mk ++++ /dev/null +@@ -1,480 +0,0 @@ +-# ################################################### +-# Makefile for the QCA NSS ECM +-# ################################################### +- +-ifeq ($(ECM_FRONT_END_SFE_ENABLE), y) +-obj-m += examples/ecm_sfe_l2.o +-endif +-obj-m +=examples/ecm_ae_select.o +- +-obj-m += ecm.o +-#ifeq ($(BUILD_ECM_WIFI_PLUGIN),y) +-#obj-m += ecm_wifi_plugins/ +-#endif +- +-# ##################################################### +-# Example builds. +-# Enable example build by using the menuconfig options. +-# ##################################################### +-ifeq ($(EXAMPLES_BUILD_PCC),y) +-obj-m += examples/ecm_pcc_test.o +-endif +-ifeq ($(EXAMPLES_BUILD_MARK),y) +-obj-m += examples/ecm_mark_test.o +-endif +-#ifeq ($(EXAMPLES_BUILD_OVS),y) +-#obj-m += examples/ecm_ovs.o +-#endif +- +-ecm-y := \ +- frontends/cmn/ecm_ae_classifier.o \ +- frontends/cmn/ecm_ipv4.o \ +- frontends/cmn/ecm_ported_ipv4.o \ +- ecm_tracker_udp.o \ +- ecm_tracker_tcp.o \ +- ecm_tracker_datagram.o \ +- ecm_tracker.o \ +- frontends/ecm_front_end_ipv4.o \ +- frontends/ecm_front_end_common.o \ +- ecm_db/ecm_db.o \ +- ecm_db/ecm_db_connection.o \ +- ecm_db/ecm_db_mapping.o \ +- ecm_db/ecm_db_host.o \ +- ecm_db/ecm_db_node.o \ +- ecm_db/ecm_db_iface.o \ +- ecm_db/ecm_db_listener.o \ +- ecm_db/ecm_db_timer.o \ +- ecm_classifier.o \ +- ecm_classifier_default.o \ +- ecm_interface.o \ +- ecm_conntrack_notifier.o \ +- ecm_init.o \ +- ecm_notifier.o +- +-ecm-$(ECM_IPV6_ENABLE) += frontends/ecm_front_end_ipv6.o +-ecm-$(ECM_IPV6_ENABLE) += frontends/cmn/ecm_ipv6.o +-ecm-$(ECM_IPV6_ENABLE) += frontends/cmn/ecm_ported_ipv6.o +-ecm-$(ECM_NON_PORTED_SUPPORT_ENABLE) += frontends/cmn/ecm_non_ported_ipv4.o +-ifeq ($(ECM_NON_PORTED_SUPPORT_ENABLE), y) +-ecm-$(ECM_IPV6_ENABLE) += frontends/cmn/ecm_non_ported_ipv6.o +-endif +- +-#SFE Multicast is enabled in case NSS disabled +-#ecm-$(ECM_MULTICAST_ENABLE) += frontends/cmn/ecm_multicast_ipv4.o +-#ifeq ($(ECM_IPV6_ENABLE), y) +-#ecm-$(ECM_MULTICAST_ENABLE) += frontends/cmn/ecm_multicast_ipv6.o +-#endif +- +-# ############################################################################# +-# Define ECM_FRONT_END_NSS_ENABLE=y in order to select +-# nss as ECM's front end. +-# ############################################################################# +-ecm-$(ECM_FRONT_END_NSS_ENABLE) += frontends/nss/ecm_nss_common.o +-ecm-$(ECM_FRONT_END_NSS_ENABLE) += frontends/nss/ecm_nss_ipv4.o +-ecm-$(ECM_FRONT_END_NSS_ENABLE) += frontends/nss/ecm_nss_ported_ipv4.o +-ccflags-$(ECM_FRONT_END_NSS_ENABLE) += -DECM_FRONT_END_NSS_ENABLE +- +-# ############################################################################# +-# Define ECM_FRONT_END_SFE_ENABLE=y in order to select +-# sfe as ECM's front end. +-# ############################################################################# +-ecm-$(ECM_FRONT_END_SFE_ENABLE) += frontends/sfe/ecm_sfe_common.o +-ecm-$(ECM_FRONT_END_SFE_ENABLE) += frontends/sfe/ecm_sfe_ipv4.o +-ecm-$(ECM_FRONT_END_SFE_ENABLE) += frontends/sfe/ecm_sfe_ported_ipv4.o +-ccflags-$(ECM_FRONT_END_SFE_ENABLE) += -DECM_FRONT_END_SFE_ENABLE +- +-# ############################################################################# +-# Define ECM_FRONT_END_PPE_ENABLE=y in order to select +-# ppe as ECM's front end. +-# ############################################################################# +-ecm-$(ECM_FRONT_END_PPE_ENABLE) += frontends/ppe/ecm_ppe_common.o +-ecm-$(ECM_FRONT_END_PPE_ENABLE) += frontends/ppe/ecm_ppe_ipv4.o +-ecm-$(ECM_FRONT_END_PPE_ENABLE) += frontends/ppe/ecm_ppe_ported_ipv4.o +-ccflags-$(ECM_FRONT_END_PPE_ENABLE) += -DECM_FRONT_END_PPE_ENABLE +- +-# ############################################################################# +-# Define ECM_FRONT_END_CONN_LIMIT_ENABLE=y in order to limit accelerated +-# connections for low-memory profiles. +-# ############################################################################# +-ccflags-$(ECM_FRONT_END_CONN_LIMIT_ENABLE) += -DECM_FRONT_END_CONN_LIMIT_ENABLE +- +-# ############################################################################# +-# Define ECM_INTERFACE_BOND_ENABLE=y in order to enable +-# Bonding / Link Aggregation support. +-# ############################################################################# +-ecm-$(ECM_INTERFACE_BOND_ENABLE) += frontends/cmn/ecm_bond_notifier.o +-ccflags-$(ECM_INTERFACE_BOND_ENABLE) += -DECM_INTERFACE_BOND_ENABLE +- +-# ############################################################################# +-# Define ECM_INTERFACE_PPPOE_ENABLE=y in order +-# to enable support for PPPoE acceleration. +-# ############################################################################# +-ECM_INTERFACE_PPPOE_ENABLE=y +-ccflags-$(ECM_INTERFACE_PPPOE_ENABLE) += -DECM_INTERFACE_PPPOE_ENABLE +- +-# ############################################################################# +-# Define ECM_INTERFACE_L2TPV2_ENABLE=y in order +-# to enable support for l2tpv2 acceleration. +-# ############################################################################# +-ccflags-$(ECM_INTERFACE_L2TPV2_ENABLE) += -DECM_INTERFACE_L2TPV2_ENABLE +- +-# ############################################################################# +-# Define ECM_INTERFACE_PPTP_ENABLE=y in order +-# to enable support for pptp acceleration. +-# ############################################################################# +-ccflags-$(ECM_INTERFACE_PPTP_ENABLE) += -DECM_INTERFACE_PPTP_ENABLE +- +-# ############################################################################# +-# if pppoe, l2tpv2, pptp acceleration is enabled, ppp should +-# be enabled automatically +-# ############################################################################# +-ECM_INTERFACE_PPP_ENABLE=y +-ifeq "$(ECM_INTERFACE_PPPOE_ENABLE)" "n" +-ifeq "$(ECM_INTERFACE_L2TPV2_ENABLE)" "n" +-ifeq "$(ECM_INTERFACE_PPTP_ENABLE)" "n" +-ECM_INTERFACE_PPP_ENABLE=n +-endif +-endif +-endif +-ccflags-$(ECM_INTERFACE_PPP_ENABLE) += -DECM_INTERFACE_PPP_ENABLE +- +-# ############################################################################# +-# Define ECM_INTERFACE_GRE_TAP_ENABLE=y in order +-# to enable support for GRE TAP interface. +-# ############################################################################# +-ccflags-$(ECM_INTERFACE_GRE_TAP_ENABLE) += -DECM_INTERFACE_GRE_TAP_ENABLE +- +-# ############################################################################# +-# Define ECM_INTERFACE_GRE_TUN_ENABLE=y in order +-# to enable support for GRE TUN interface. +-# ############################################################################# +-ccflags-$(ECM_INTERFACE_GRE_TUN_ENABLE) += -DECM_INTERFACE_GRE_TUN_ENABLE +- +-ifeq ($(ECM_IPV6_ENABLE), y) +-# ############################################################################# +-# Define ECM_INTERFACE_SIT_ENABLE=y in order +-# to enable support for SIT interface. +-# ############################################################################# +-#ccflags-$(ECM_INTERFACE_SIT_ENABLE) += -DECM_INTERFACE_SIT_ENABLE +- +-# ############################################################################# +-# Define ECM_INTERFACE_TUNIPIP6_ENABLE=y in order +-# to enable support for TUNIPIP6 interface. +-# ############################################################################# +-#ccflags-$(ECM_INTERFACE_TUNIPIP6_ENABLE) += -DECM_INTERFACE_TUNIPIP6_ENABLE +- +-# ############################################################################# +-# Define ECM_INTERFACE_MAP_T_ENABLE=y in order +-# to enable support for MAP-T interface. +-# ############################################################################# +-#ccflags-$(ECM_INTERFACE_MAP_T_ENABLE) += -DECM_INTERFACE_MAP_T_ENABLE +-endif +- +-# ############################################################################# +-# Define ECM_INTERFACE_RAWIP_ENABLE=y in order +-# to enable support for RAWIP interface. +-# ############################################################################# +-#ccflags-$(ECM_INTERFACE_RAWIP_ENABLE) += -DECM_INTERFACE_RAWIP_ENABLE +- +-# ############################################################################# +-# Define ECM_INTERFACE_VXLAN_ENABLE=y in order +-# to enable support for VxLAN interface. +-# ############################################################################# +-ccflags-$(ECM_INTERFACE_VXLAN_ENABLE) += -DECM_INTERFACE_VXLAN_ENABLE +- +-# ############################################################################# +-# Define ECM_IPV6_ENABLE=y in order to enable IPv6 support in the ECM. +-# ############################################################################# +-ccflags-$(ECM_IPV6_ENABLE) += -DECM_IPV6_ENABLE +- +-# ############################################################################# +-# Define ECM_MULTICAST_ENABLE=y in order to enable support for ECM Multicast +-# NSS is enabled, using NSS multicast acceleration, otherwise using SFE +-# multicast acceleration. +-# ############################################################################# +- +-ecm-$(ECM_MULTICAST_ENABLE) += ecm_db/ecm_db_multicast.o +-#ccflags-$(ECM_MULTICAST_ENABLE) += -DECM_MULTICAST_ENABLE +- +-ifeq ($(ECM_FRONT_END_NSS_ENABLE), y) +-ecm-$(ECM_MULTICAST_ENABLE) += frontends/nss/ecm_nss_multicast_ipv4.o +-ifeq ($(ECM_IPV6_ENABLE), y) +-ecm-$(ECM_MULTICAST_ENABLE) += frontends/nss/ecm_nss_multicast_ipv6.o +-endif +-else +-#ecm-$(ECM_MULTICAST_ENABLE) += frontends/sfe/ecm_sfe_multicast_ipv4.o +-ifeq ($(ECM_IPV6_ENABLE), y) +-#ecm-$(ECM_MULTICAST_ENABLE) += frontends/sfe/ecm_sfe_multicast_ipv6.o +-endif +-endif +- +-# ############################################################################# +-# Define ECM_XFRM_ENABLE=y in order to enable +-# ############################################################################# +-#ccflags-$(ECM_XFRM_ENABLE) += -DECM_XFRM_ENABLE +- +-# ############################################################################# +-# Define ECM_INTERFACE_OVS_BRIDGE_ENABLE=y in order to enable support for OVS +-# ############################################################################# +-#ccflags-$(ECM_INTERFACE_OVS_BRIDGE_ENABLE) += -DECM_INTERFACE_OVS_BRIDGE_ENABLE +- +-# ############################################################################# +-# Define ECM_INTERFACE_VLAN_ENABLE=y in order to enable support for VLAN +-# ############################################################################# +-ECM_INTERFACE_VLAN_ENABLE=y +-ccflags-$(ECM_INTERFACE_VLAN_ENABLE) += -DECM_INTERFACE_VLAN_ENABLE +- +-# ############################################################################# +-# Define ECM_INTERFACE_MACVLAN_ENABLE=y in order to enable support for MACVLAN +-# ############################################################################# +-#ccflags-$(ECM_INTERFACE_MACVLAN_ENABLE) += -DECM_INTERFACE_MACVLAN_ENABLE +- +-# ############################################################################# +-# Define ECM_INTERFACE_IPSEC_ENABLE=y in order to enable support for IPSEC +-# ############################################################################# +-#ccflags-$(ECM_INTERFACE_IPSEC_ENABLE) += -DECM_INTERFACE_IPSEC_ENABLE +- +-ECM_INTERFACE_IPSEC_GLUE_LAYER_SUPPORT_ENABLE=n +-ifeq ($(SoC),$(filter $(SoC), ipq807x ipq807x_64 ipq60xx ipq60xx_64 ipq50xx \ +- ipq50xx_64 ipq95xx_32 ipq95xx ipq53xx_32 ipq53xx)) +-ECM_INTERFACE_IPSEC_GLUE_LAYER_SUPPORT_ENABLE=$(ECM_INTERFACE_IPSEC_ENABLE) +-#ccflags-$(ECM_INTERFACE_IPSEC_GLUE_LAYER_SUPPORT_ENABLE) += -DECM_INTERFACE_IPSEC_GLUE_LAYER_SUPPORT_ENABLE +-endif +- +-ifeq ($(ECM_FRONT_END_NSS_ENABLE), y) +-ecm-$(ECM_IPV6_ENABLE) += frontends/nss/ecm_nss_ipv6.o +-ecm-$(ECM_IPV6_ENABLE) += frontends/nss/ecm_nss_ported_ipv6.o +-endif +-ifeq ($(ECM_FRONT_END_SFE_ENABLE), y) +-ecm-$(ECM_IPV6_ENABLE) += frontends/sfe/ecm_sfe_ipv6.o +-ecm-$(ECM_IPV6_ENABLE) += frontends/sfe/ecm_sfe_ported_ipv6.o +-endif +-ifeq ($(ECM_FRONT_END_PPE_ENABLE), y) +-ecm-$(ECM_IPV6_ENABLE) += frontends/ppe/ecm_ppe_ipv6.o +-ecm-$(ECM_IPV6_ENABLE) += frontends/ppe/ecm_ppe_ported_ipv6.o +-endif +- +-# ############################################################################# +-# Define ECM_CLASSIFIER_OVS_ENABLE=y in order to enable ovs classifier. +-# ############################################################################# +-#ecm-$(ECM_CLASSIFIER_OVS_ENABLE) += ecm_classifier_ovs.o +-#ccflags-$(ECM_CLASSIFIER_OVS_ENABLE) += -DECM_CLASSIFIER_OVS_ENABLE +- +-# ############################################################################# +-# Define ECM_CLASSIFIER_MARK_ENABLE=y in order to enable mark classifier. +-# ############################################################################# +-ECM_CLASSIFIER_MARK_ENABLE=y +-ecm-$(ECM_CLASSIFIER_MARK_ENABLE) += ecm_classifier_mark.o +-ccflags-$(ECM_CLASSIFIER_MARK_ENABLE) += -DECM_CLASSIFIER_MARK_ENABLE +- +-# ############################################################################# +-# Define ECM_CLASSIFIER_MSCS_ENABLE=y in order to enable mscs flow classifier. +-# ############################################################################# +-#ecm-$(ECM_CLASSIFIER_MSCS_ENABLE) += ecm_classifier_mscs.o +-#ccflags-$(ECM_CLASSIFIER_MSCS_ENABLE) += -DECM_CLASSIFIER_MSCS_ENABLE +- +-# ############################################################################# +-# Define ECM_CLASSIFIER_MSCS_SCS_ENABLE=y in order to enable SCS classifier. +-# ############################################################################# +-#ccflags-$(ECM_CLASSIFIER_MSCS_SCS_ENABLE) += -DECM_CLASSIFIER_MSCS_SCS_ENABLE +- +-# ############################################################################# +-# Define ECM_CLASSIFIER_NL_ENABLE=y in order to enable NL classifier. +-# ############################################################################# +-#ecm-$(ECM_CLASSIFIER_NL_ENABLE) += ecm_classifier_nl.o +-#ccflags-$(ECM_CLASSIFIER_NL_ENABLE) += -DECM_CLASSIFIER_NL_ENABLE +- +-# ############################################################################# +-# Define ECM_CLASSIFIER_DSCP_ENABLE=y in order to enable DSCP classifier. +-# ############################################################################# +-ECM_CLASSIFIER_DSCP_ENABLE=y +-ecm-$(ECM_CLASSIFIER_DSCP_ENABLE) += ecm_classifier_dscp.o +-ccflags-$(ECM_CLASSIFIER_DSCP_ENABLE) += -DECM_CLASSIFIER_DSCP_ENABLE +-#ccflags-$(ECM_CLASSIFIER_DSCP_IGS) += -DECM_CLASSIFIER_DSCP_IGS +- +-# ############################################################################# +-# Define ECM_CLASSIFIER_HYFI_ENABLE=y in order to enable +-# the Hy-Fi classifier in ECM. Currently disabled until the integration +-# with Hy-Fi is completed. +-# ############################################################################# +-# +-#ecm-$(ECM_CLASSIFIER_HYFI_ENABLE) += ecm_classifier_hyfi.o +-#ccflags-$(ECM_CLASSIFIER_HYFI_ENABLE) += -DECM_CLASSIFIER_HYFI_ENABLE +- +-# ############################################################################# +-# Define ECM_CLASSIFIER_PCC_ENABLE=y in order to enable +-# the Parental Controls subsystem classifier in ECM. Currently disabled until +-# customers require it / if they need to integrate their Parental Controls with it. +-# ############################################################################# +-ECM_CLASSIFIER_PCC_ENABLE=y +-ecm-$(ECM_CLASSIFIER_PCC_ENABLE) += ecm_classifier_pcc.o +-ccflags-$(ECM_CLASSIFIER_PCC_ENABLE) += -DECM_CLASSIFIER_PCC_ENABLE +- +-# ############################################################################# +-# Define ECM_CLASSIFIER_EMESH_ENABLE=y in order to enable E-Mesh classifier. +-# ############################################################################# +-#ecm-$(ECM_CLASSIFIER_EMESH_ENABLE) += ecm_classifier_emesh.o +-#ccflags-$(ECM_CLASSIFIER_EMESH_ENABLE) += -DECM_CLASSIFIER_EMESH_ENABLE +- +-# ############################################################################# +-# Define ECM_NON_PORTED_SUPPORT_ENABLE=y in order to enable non-ported protocol. +-# ############################################################################# +- +- +-ifeq ($(ECM_FRONT_END_NSS_ENABLE), y) +-ecm-$(ECM_NON_PORTED_SUPPORT_ENABLE) += frontends/nss/ecm_nss_non_ported_ipv4.o +-ifeq ($(ECM_IPV6_ENABLE), y) +-ecm-$(ECM_NON_PORTED_SUPPORT_ENABLE) += frontends/nss/ecm_nss_non_ported_ipv6.o +-endif +-endif +- +-ifeq ($(ECM_FRONT_END_SFE_ENABLE), y) +-ecm-$(ECM_NON_PORTED_SUPPORT_ENABLE) += frontends/sfe/ecm_sfe_non_ported_ipv4.o +-ifeq ($(ECM_IPV6_ENABLE), y) +-ecm-$(ECM_NON_PORTED_SUPPORT_ENABLE) += frontends/sfe/ecm_sfe_non_ported_ipv6.o +-endif +-endif +- +-ifeq ($(ECM_FRONT_END_PPE_ENABLE), y) +-ecm-$(ECM_NON_PORTED_SUPPORT_ENABLE) += frontends/ppe/ecm_ppe_non_ported_ipv4.o +-ifeq ($(ECM_IPV6_ENABLE), y) +-ecm-$(ECM_NON_PORTED_SUPPORT_ENABLE) += frontends/ppe/ecm_ppe_non_ported_ipv6.o +-endif +-endif +- +-ccflags-$(ECM_NON_PORTED_SUPPORT_ENABLE) += -DECM_NON_PORTED_SUPPORT_ENABLE +- +-# ############################################################################# +-# Define ECM_STATE_OUTPUT_ENABLE=y to support XML state output +-# ############################################################################# +-ECM_STATE_OUTPUT_ENABLE=y +-ecm-$(ECM_STATE_OUTPUT_ENABLE) += ecm_state.o +-ccflags-$(ECM_STATE_OUTPUT_ENABLE) += -DECM_STATE_OUTPUT_ENABLE +- +-# ############################################################################# +-# Define ECM_DB_ADVANCED_STATS_ENABLE to support XML state output +-# ############################################################################# +-ECM_DB_ADVANCED_STATS_ENABLE=y +-ccflags-$(ECM_DB_ADVANCED_STATS_ENABLE) += -DECM_DB_ADVANCED_STATS_ENABLE +- +-# ############################################################################# +-# Define ECM_DB_CONNECTION_CROSS_REFERENCING_ENABLE=y in order to enable +-# the database to track relationships between objects. +-# ############################################################################# +-ECM_DB_CONNECTION_CROSS_REFERENCING_ENABLE=y +-ccflags-$(ECM_DB_CONNECTION_CROSS_REFERENCING_ENABLE) += -DECM_DB_XREF_ENABLE +- +-# ############################################################################# +-# Define ECM_TRACKER_DPI_SUPPORT_ENABLE=y in order to enable support for +-# deep packet inspection and tracking of data with the trackers. +-# ############################################################################# +-ccflags-$(ECM_TRACKER_DPI_SUPPORT_ENABLE) += -DECM_TRACKER_DPI_SUPPORT_ENABLE +- +-# ############################################################################# +-# Define ECM_DB_CLASSIFIER_TYPE_ASSIGNMENTS_TRACK_ENABLE=y in order to enable +-# support for the database keeping lists of connections that are assigned +-# on a per TYPE of classifier basis. +-# ############################################################################# +-ECM_DB_CLASSIFIER_TYPE_ASSIGNMENTS_TRACK_ENABLE=y +-ccflags-$(ECM_DB_CLASSIFIER_TYPE_ASSIGNMENTS_TRACK_ENABLE) += -DECM_DB_CTA_TRACK_ENABLE +- +-# ############################################################################# +-# Define ECM_BAND_STEERING_ENABLE=y in order to enable +-# band steering feature. +-# ############################################################################# +-ECM_BAND_STEERING_ENABLE=y +-ccflags-$(ECM_BAND_STEERING_ENABLE) += -DECM_BAND_STEERING_ENABLE +- +-# ############################################################################# +-# Define ECM_INTERFACE_OVPN_ENABLE=y in order +-# to enable support for OVPN acceleration. +-# ############################################################################# +-#ccflags-$(ECM_INTERFACE_OVPN_ENABLE) += -DECM_INTERFACE_OVPN_ENABLE +- +-# ############################################################################# +-# Define ECM_BRIDGE_VLAN_FILTERING_ENABLE=y in order +-# to enable support for bridge VLAN filter acceleration. +-# ############################################################################# +-ccflags-$(ECM_BRIDGE_VLAN_FILTERING_ENABLE) += -DECM_BRIDGE_VLAN_FILTERING_ENABLE +- +-# ############################################################################# +-# Debug flags, set these to = 0 if you want to disable all debugging for that +-# file. +-# By turning off debugs you gain maximum ECM performance. +-# ############################################################################# +-ccflags-y += -DECM_CLASSIFIER_DEBUG_LEVEL=1 +-ccflags-y += -DECM_CLASSIFIER_OVS_DEBUG_LEVEL=1 +-ccflags-y += -DECM_CLASSIFIER_MARK_DEBUG_LEVEL=1 +-ccflags-y += -DECM_CLASSIFIER_DSCP_DEBUG_LEVEL=1 +-ccflags-y += -DECM_CLASSIFIER_HYFI_DEBUG_LEVEL=1 +-ccflags-y += -DECM_CLASSIFIER_PCC_DEBUG_LEVEL=1 +-ccflags-y += -DECM_CLASSIFIER_NL_DEBUG_LEVEL=1 +-ccflags-y += -DECM_CLASSIFIER_EMESH_DEBUG_LEVEL=1 +-ccflags-y += -DECM_CLASSIFIER_MSCS_DEBUG_LEVEL=1 +-ccflags-y += -DECM_CLASSIFIER_DEFAULT_DEBUG_LEVEL=1 +-ccflags-y += -DECM_DB_DEBUG_LEVEL=1 +-ccflags-y += -DECM_INIT_DEBUG_LEVEL=3 +-ccflags-y += -DECM_FRONT_END_IPV4_DEBUG_LEVEL=1 +-ccflags-y += -DECM_FRONT_END_IPV6_DEBUG_LEVEL=1 +-ccflags-y += -DECM_FRONT_END_COMMON_DEBUG_LEVEL=1 +-ccflags-y += -DECM_CMN_IPV4_DEBUG_LEVEL=1 +-ccflags-y += -DECM_CMN_IPV6_DEBUG_LEVEL=1 +-ccflags-y += -DECM_CMN_PORTED_IPV4_DEBUG_LEVEL=1 +-ccflags-y += -DECM_CMN_PORTED_IPV6_DEBUG_LEVEL=1 +-ccflags-y += -DECM_CMN_NON_PORTED_IPV4_DEBUG_LEVEL=1 +-ccflags-y += -DECM_CMN_NON_PORTED_IPV6_DEBUG_LEVEL=1 +-ccflags-y += -DECM_CMN_MULTICAST_IPV4_DEBUG_LEVEL=1 +-ccflags-y += -DECM_CMN_MULTICAST_IPV6_DEBUG_LEVEL=1 +-ccflags-y += -DECM_NSS_COMMON_DEBUG_LEVEL=1 +-ccflags-y += -DECM_NSS_IPV4_DEBUG_LEVEL=1 +-ccflags-y += -DECM_NSS_PORTED_IPV4_DEBUG_LEVEL=1 +-ccflags-y += -DECM_NSS_NON_PORTED_IPV4_DEBUG_LEVEL=1 +-ccflags-y += -DECM_NSS_MULTICAST_IPV4_DEBUG_LEVEL=1 +-ccflags-y += -DECM_NSS_IPV6_DEBUG_LEVEL=1 +-ccflags-y += -DECM_NSS_PORTED_IPV6_DEBUG_LEVEL=1 +-ccflags-y += -DECM_NSS_NON_PORTED_IPV6_DEBUG_LEVEL=1 +-ccflags-y += -DECM_NSS_MULTICAST_IPV6_DEBUG_LEVEL=1 +-ccflags-y += -DECM_SFE_COMMON_DEBUG_LEVEL=1 +-ccflags-y += -DECM_SFE_IPV4_DEBUG_LEVEL=1 +-ccflags-y += -DECM_SFE_PORTED_IPV4_DEBUG_LEVEL=1 +-ccflags-y += -DECM_SFE_NON_PORTED_IPV4_DEBUG_LEVEL=1 +-ccflags-y += -DECM_SFE_MULTICAST_IPV4_DEBUG_LEVEL=1 +-ccflags-y += -DECM_SFE_IPV6_DEBUG_LEVEL=1 +-ccflags-y += -DECM_SFE_PORTED_IPV6_DEBUG_LEVEL=1 +-ccflags-y += -DECM_SFE_NON_PORTED_IPV6_DEBUG_LEVEL=1 +-ccflags-y += -DECM_SFE_MULTICAST_IPV6_DEBUG_LEVEL=1 +-ccflags-y += -DECM_PPE_COMMON_DEBUG_LEVEL=1 +-ccflags-y += -DECM_PPE_IPV4_DEBUG_LEVEL=1 +-ccflags-y += -DECM_PPE_PORTED_IPV4_DEBUG_LEVEL=1 +-ccflags-y += -DECM_PPE_NON_PORTED_IPV4_DEBUG_LEVEL=1 +-ccflags-y += -DECM_PPE_IPV6_DEBUG_LEVEL=1 +-ccflags-y += -DECM_PPE_PORTED_IPV6_DEBUG_LEVEL=1 +-ccflags-y += -DECM_PPE_NON_PORTED_IPV6_DEBUG_LEVEL=1 +-ccflags-y += -DECM_CONNTRACK_NOTIFIER_DEBUG_LEVEL=1 +-ccflags-y += -DECM_TRACKER_DEBUG_LEVEL=1 +-ccflags-y += -DECM_TRACKER_DATAGRAM_DEBUG_LEVEL=1 +-ccflags-y += -DECM_TRACKER_TCP_DEBUG_LEVEL=1 +-ccflags-y += -DECM_TRACKER_UDP_DEBUG_LEVEL=1 +-ccflags-y += -DECM_BOND_NOTIFIER_DEBUG_LEVEL=1 +-ccflags-y += -DECM_INTERFACE_DEBUG_LEVEL=1 +-ccflags-y += -DECM_STATE_DEBUG_LEVEL=1 +-ccflags-y += -DECM_OPENWRT_SUPPORT=1 +-ccflags-y += -DECM_NOTIFIER_DEBUG_LEVEL=1 +-ccflags-y += -DECM_AE_CLASSIFIER_DEBUG_LEVEL=1 +- +-ccflags-y += -I$(obj)/ -I$(obj)/ecm_db -I$(obj)/frontends/include -I$(obj)/frontends/nss -I$(obj)/frontends/sfe -I$(obj)/frontends/cmn -I$(obj)/exports +- +-ifeq ($(ECM_FRONT_END_PPE_ENABLE), y) +- ccflags-y += -I$(obj)/frontends/ppe +-ifeq ($(SoC),$(filter $(SoC), ipq53xx_32 ipq53xx)) +-# ############################################################################# +-# Define ECM_PPE_SOURCE_INTERFACE_CHECK_ENABLE=y in order +-# to enable support for source interface check in PPE. +-# ############################################################################# +-ccflags-y += -DECM_PPE_SOURCE_INTERFACE_CHECK_ENABLE=1 +-endif +-endif +- +-ccflags-y += -Wall -Werror +- +-obj ?= . +--- a/ecm_classifier_nl.c ++++ b/ecm_classifier_nl.c +@@ -70,6 +70,7 @@ + #include "ecm_tracker_tcp.h" + #include "ecm_classifier_nl.h" + #include "ecm_db.h" ++#include "ecm_front_end_common.h" + #include "ecm_front_end_ipv4.h" + #ifdef ECM_IPV6_ENABLE + #include "ecm_front_end_ipv6.h" +@@ -144,12 +145,55 @@ static struct genl_multicast_group ecm_c + }, + }; + ++/* ++ * Generic Netlink attr checking policies ++ */ ++static struct nla_policy ++ecm_cl_nl_genl_policy[ECM_CL_NL_GENL_ATTR_COUNT] = { ++ [ECM_CL_NL_GENL_ATTR_TUPLE] = { ++ .type = NLA_UNSPEC, ++ .len = sizeof(struct ecm_cl_nl_genl_attr_tuple), }, ++}; ++ ++static int ecm_classifier_nl_genl_msg_ACCEL(struct sk_buff *skb, struct genl_info *info); ++static int ecm_classifier_nl_genl_msg_DUMP(struct sk_buff *skb, struct netlink_callback *cb); ++ ++/* ++ * Generic Netlink message-to-handler mapping ++ */ ++static struct genl_ops ecm_cl_nl_genl_ops[] = { ++ { ++ .cmd = ECM_CL_NL_GENL_CMD_ACCEL, ++ .flags = 0, ++ .policy = ecm_cl_nl_genl_policy, ++ .doit = ecm_classifier_nl_genl_msg_ACCEL, ++ .dumpit = NULL, ++ }, ++ { ++ .cmd = ECM_CL_NL_GENL_CMD_ACCEL_OK, ++ .flags = 0, ++ .policy = ecm_cl_nl_genl_policy, ++ .doit = NULL, ++ .dumpit = ecm_classifier_nl_genl_msg_DUMP, ++ }, ++ { ++ .cmd = ECM_CL_NL_GENL_CMD_CONNECTION_CLOSED, ++ .flags = 0, ++ .policy = ecm_cl_nl_genl_policy, ++ .doit = NULL, ++ .dumpit = ecm_classifier_nl_genl_msg_DUMP, ++ }, ++}; ++ + static struct genl_family ecm_cl_nl_genl_family = { +- .id = GENL_ID_GENERATE, + .hdrsize = 0, + .name = ECM_CL_NL_GENL_NAME, + .version = ECM_CL_NL_GENL_VERSION, + .maxattr = ECM_CL_NL_GENL_ATTR_MAX, ++ .ops = ecm_cl_nl_genl_ops, ++ .n_ops = ARRAY_SIZE(ecm_cl_nl_genl_ops), ++ .mcgrps = ecm_cl_nl_genl_mcgrp, ++ .n_mcgrps = ARRAY_SIZE(ecm_cl_nl_genl_mcgrp), + }; + + /* +@@ -213,12 +257,7 @@ ecm_classifier_nl_send_genl_msg(enum ECM + return ret; + } + +- ret = genlmsg_end(skb, msg_head); +- if (ret < 0) { +- DEBUG_WARN("failed to finalize genl msg: %d\n", ret); +- nlmsg_free(skb); +- return ret; +- } ++ genlmsg_end(skb, msg_head); + + /* genlmsg_multicast frees the skb in both success and error cases */ + ret = genlmsg_multicast(&ecm_cl_nl_genl_family, +@@ -1366,49 +1405,14 @@ static struct file_operations ecm_classi + .write = ecm_classifier_nl_set_command, + }; + +-/* +- * Generic Netlink attr checking policies +- */ +-static struct nla_policy +-ecm_cl_nl_genl_policy[ECM_CL_NL_GENL_ATTR_COUNT] = { +- [ECM_CL_NL_GENL_ATTR_TUPLE] = { +- .type = NLA_UNSPEC, +- .len = sizeof(struct ecm_cl_nl_genl_attr_tuple), }, +-}; +- +-/* +- * Generic Netlink message-to-handler mapping +- */ +-static struct genl_ops ecm_cl_nl_genl_ops[] = { +- { +- .cmd = ECM_CL_NL_GENL_CMD_ACCEL, +- .flags = 0, +- .policy = ecm_cl_nl_genl_policy, +- .doit = ecm_classifier_nl_genl_msg_ACCEL, +- .dumpit = NULL, +- }, +- { +- .cmd = ECM_CL_NL_GENL_CMD_ACCEL_OK, +- .flags = 0, +- .policy = ecm_cl_nl_genl_policy, +- .doit = NULL, +- .dumpit = ecm_classifier_nl_genl_msg_DUMP, +- }, +- { +- .cmd = ECM_CL_NL_GENL_CMD_CONNECTION_CLOSED, +- .flags = 0, +- .policy = ecm_cl_nl_genl_policy, +- .doit = NULL, +- .dumpit = ecm_classifier_nl_genl_msg_DUMP, +- }, +-}; +- + static int ecm_classifier_nl_register_genl(void) + { +- +- return genl_register_family_with_ops_groups(&ecm_cl_nl_genl_family, +- ecm_cl_nl_genl_ops, +- ecm_cl_nl_genl_mcgrp); ++ int result; ++ result = genl_register_family(&ecm_cl_nl_genl_family); ++ if(result!=0){ ++ DEBUG_ERROR("failed to register genl family: %d\n", result); ++ } ++ return result; + } + + static void ecm_classifier_nl_unregister_genl(void) +--- a/ecm_conntrack_notifier.c ++++ b/ecm_conntrack_notifier.c +@@ -401,7 +401,11 @@ static struct notifier_block ecm_conntra + * Netfilter conntrack event system to monitor connection tracking changes + */ + static struct nf_ct_event_notifier ecm_conntrack_notifier = { ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0)) + .fcn = ecm_conntrack_event, ++#else ++ .ct_event = ecm_conntrack_event, ++#endif + }; + #endif + #endif +--- a/ecm_db/ecm_db.c ++++ b/ecm_db/ecm_db.c +@@ -242,11 +242,13 @@ static int ecm_db_ipv6_route_table_updat + unsigned long event, + void *ptr) + { ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0)) + struct fib6_config *cfg = (struct fib6_config *)ptr; + struct ecm_db_connection_instance *ci; +- ++#endif + DEBUG_TRACE("route table update event v6\n"); + ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0)) + if ((event != RTM_DELROUTE) && (event != RTM_NEWROUTE)) { + DEBUG_WARN("%px: Unhandled route table event: %lu\n", cfg, event); + return NOTIFY_DONE; +@@ -262,12 +264,13 @@ static int ecm_db_ipv6_route_table_updat + ecm_db_connection_defunct_ip_version(6); + return NOTIFY_DONE; + } +- ++#endif + /* + * Disable IPv6 frontend processing until defunct function call is completed. + */ + ecm_front_end_ipv6_stop(1); + ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0)) + /* + * Iterate all connections + */ +@@ -298,7 +301,7 @@ static int ecm_db_ipv6_route_table_updat + * Compute ECM connection's prefix destination address by masking it with the + * route config's destination address prefix length. + */ +- ipv6_addr_prefix(&prefix_addr, &ecm_in6, cfg->fc_dst_len); ++ ipv6_addr_prefix(&prefix_addr, &ecm_in6, min(128, cfg->fc_dst_len)); + + DEBUG_TRACE("dest addr prefix: %pI6 prefix_len: %d ecm_in6: %pI6\n", &prefix_addr, cfg->fc_dst_len, &ecm_in6); + +@@ -326,7 +329,7 @@ static int ecm_db_ipv6_route_table_updat + * Compute ECM connection's prefix source address by masking it with the + * route config's destination address prefix length. + */ +- ipv6_addr_prefix(&prefix_addr, &ecm_in6, cfg->fc_dst_len); ++ ipv6_addr_prefix(&prefix_addr, &ecm_in6, min(128, cfg->fc_dst_len)); + + DEBUG_TRACE("src addr prefix: %pI6 prefix_len: %d ecm_in6: %pI6\n", &prefix_addr, cfg->fc_dst_len, &ecm_in6); + +@@ -402,11 +405,12 @@ next: + ecm_db_connection_deref(ci); + ci = cin; + } +- ++#else + /* + * Re-enable IPv6 frontend processing. + */ + ecm_front_end_ipv6_stop(0); ++#endif + return NOTIFY_DONE; + } + +--- a/ecm_db/ecm_db_connection.c ++++ b/ecm_db/ecm_db_connection.c +@@ -446,7 +446,9 @@ EXPORT_SYMBOL(ecm_db_connection_make_def + */ + void ecm_db_connection_data_totals_update(struct ecm_db_connection_instance *ci, bool is_from, uint64_t size, uint64_t packets) + { ++#ifdef ECM_DB_ADVANCED_STATS_ENABLE + int32_t i; ++#endif + + DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%px: magic failed\n", ci); + +@@ -545,7 +547,9 @@ EXPORT_SYMBOL(ecm_db_connection_data_tot + */ + void ecm_db_connection_data_totals_update_dropped(struct ecm_db_connection_instance *ci, bool is_from, uint64_t size, uint64_t packets) + { ++#ifdef ECM_DB_ADVANCED_STATS_ENABLE + int32_t i; ++#endif + + DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%px: magic failed\n", ci); + +@@ -1539,6 +1543,7 @@ void ecm_db_connection_defunct_all(void) + } + EXPORT_SYMBOL(ecm_db_connection_defunct_all); + ++#ifdef ECM_INTERFACE_OVS_BRIDGE_ENABLE + /* + * ecm_db_connection_defunct_by_classifier() + * Make defunct based on masked fields +@@ -1705,6 +1710,7 @@ next_ci: + ECM_IP_ADDR_TO_OCTAL(dest_addr_mask), dest_port_mask, proto_mask, cnt); + } + } ++#endif + + /* + * ecm_db_connection_defunct_by_port() +@@ -1994,6 +2000,7 @@ struct ecm_db_node_instance *ecm_db_conn + } + EXPORT_SYMBOL(ecm_db_connection_node_get_and_ref); + ++#ifdef ECM_DB_XREF_ENABLE + /* + * ecm_db_connection_mapping_get_and_ref_next() + * Return reference to next connection in the mapping chain in the specified direction. +@@ -2035,6 +2042,7 @@ struct ecm_db_connection_instance *ecm_d + return nci; + } + EXPORT_SYMBOL(ecm_db_connection_iface_get_and_ref_next); ++#endif + + /* + * ecm_db_connection_mapping_get_and_ref() +--- a/ecm_db/ecm_db_node.c ++++ b/ecm_db/ecm_db_node.c +@@ -227,9 +227,11 @@ EXPORT_SYMBOL(ecm_db_node_get_and_ref_ne + */ + int ecm_db_node_deref(struct ecm_db_node_instance *ni) + { ++#ifdef ECM_DB_XREF_ENABLE + #if (DEBUG_LEVEL >= 1) + int dir; + #endif ++#endif + DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%px: magic failed\n", ni); + + spin_lock_bh(&ecm_db_lock); +@@ -489,9 +491,11 @@ EXPORT_SYMBOL(ecm_db_node_iface_get_and_ + void ecm_db_node_add(struct ecm_db_node_instance *ni, struct ecm_db_iface_instance *ii, uint8_t *address, + ecm_db_node_final_callback_t final, void *arg) + { ++#ifdef ECM_DB_XREF_ENABLE + #if (DEBUG_LEVEL >= 1) + int dir; + #endif ++#endif + ecm_db_node_hash_t hash_index; + struct ecm_db_listener_instance *li; + +--- a/ecm_init.c ++++ b/ecm_init.c +@@ -122,7 +122,7 @@ static int __init ecm_init(void) + { + int ret; + +- printk(KERN_INFO "ECM init\n"); ++ printk(KERN_INFO "ECM init ( NHSS.QSDK.12.4.5.r2 2023-07-25 )\n"); + + selected_front_end = ecm_front_end_type_select(); + if (selected_front_end == ECM_FRONT_END_TYPE_MAX) { +--- a/ecm_interface.c ++++ b/ecm_interface.c +@@ -1509,6 +1509,7 @@ struct neighbour *ecm_interface_ipv6_nei + */ + bool ecm_interface_is_pptp(struct sk_buff *skb, const struct net_device *out) + { ++#ifdef ECM_INTERFACE_PPTP_ENABLE + struct net_device *in; + + /* +@@ -1533,6 +1534,7 @@ bool ecm_interface_is_pptp(struct sk_buf + } + + dev_put(in); ++#endif + return false; + } + +@@ -1545,6 +1547,7 @@ bool ecm_interface_is_pptp(struct sk_buf + */ + bool ecm_interface_is_l2tp_packet_by_version(struct sk_buff *skb, const struct net_device *out, int ver) + { ++#ifdef ECM_INTERFACE_L2TPV2_PPTP_ENABLE + uint32_t flag = 0; + struct net_device *in; + +@@ -1577,6 +1580,7 @@ bool ecm_interface_is_l2tp_packet_by_ver + } + + dev_put(in); ++#endif + return false; + } + +@@ -1589,6 +1593,7 @@ bool ecm_interface_is_l2tp_packet_by_ver + */ + bool ecm_interface_is_l2tp_pptp(struct sk_buff *skb, const struct net_device *out) + { ++#ifdef ECM_INTERFACE_L2TPV2_PPTP_ENABLE + struct net_device *in; + + /* +@@ -1611,6 +1616,7 @@ bool ecm_interface_is_l2tp_pptp(struct s + } + + dev_put(in); ++#endif + return false; + } + +@@ -4811,7 +4817,7 @@ static inline bool ecm_interface_is_tunn + return true; + } + +- if (protocol == IPPROTO_GRE || protocol == IPPROTO_ESP || protocol == IPPROTO_ETHERIP) { ++ if (protocol == IPPROTO_GRE || protocol == IPPROTO_ESP) { + return true; + } + +@@ -7159,6 +7165,7 @@ static void ecm_interface_regenerate_con + return; + } + ++#ifdef ECM_DB_XREF_ENABLE + for (dir = 0; dir < ECM_DB_OBJ_DIR_MAX; dir++) { + /* + * Re-generate all connections associated with this interface +@@ -7174,6 +7181,7 @@ static void ecm_interface_regenerate_con + ci[dir] = cin; + } + } ++#endif + + #ifdef ECM_MULTICAST_ENABLE + /* +@@ -8077,7 +8085,7 @@ static int ecm_interface_wifi_event_rx(s + { + struct msghdr msg; + struct iovec iov; +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0)) ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 11, 0)) + mm_segment_t oldfs = get_fs(); + #endif + int size; +@@ -8090,12 +8098,12 @@ static int ecm_interface_wifi_event_rx(s + msg.msg_namelen = sizeof(struct sockaddr_nl); + msg.msg_control = NULL; + msg.msg_controllen = 0; +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0)) ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 11, 0)) + set_fs(KERNEL_DS); + #endif + iov_iter_init(&msg.msg_iter, READ, &iov, 1, len); + size = sock_recvmsg(sock, &msg, msg.msg_flags); +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0)) ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 11, 0)) + set_fs(oldfs); + #endif + +--- a/ecm_tracker_datagram.c ++++ b/ecm_tracker_datagram.c +@@ -203,7 +203,7 @@ static void ecm_tracker_datagram_datagra + * ecm_tracker_datagram_discard_all() + * Discard all tracked data + */ +-static void ecm_tracker_datagram_discard_all(struct ecm_tracker_datagram_internal_instance *dtii) ++void ecm_tracker_datagram_discard_all(struct ecm_tracker_datagram_internal_instance *dtii) + { + int32_t src_count; + int32_t dest_count; +@@ -364,7 +364,7 @@ static void ecm_tracker_datagram_datagra + * ecm_tracker_datagram_datagram_size_get() + * Return size in bytes of datagram at index i that was sent to the target + */ +-static int32_t ecm_tracker_datagram_datagram_size_get(struct ecm_tracker_datagram_instance *uti, ecm_tracker_sender_type_t sender, int32_t i) ++int32_t ecm_tracker_datagram_datagram_size_get(struct ecm_tracker_datagram_instance *uti, ecm_tracker_sender_type_t sender, int32_t i) + { + struct ecm_tracker_datagram_internal_instance *dtii = (struct ecm_tracker_datagram_internal_instance *)uti; + +@@ -412,7 +412,7 @@ static int32_t ecm_tracker_datagram_data + * ecm_tracker_datagram_datagram_read() + * Read size bytes from datagram at index i into the buffer + */ +-static int ecm_tracker_datagram_datagram_read(struct ecm_tracker_datagram_instance *uti, ecm_tracker_sender_type_t sender, int32_t i, int32_t offset, int32_t size, void *buffer) ++int ecm_tracker_datagram_datagram_read(struct ecm_tracker_datagram_instance *uti, ecm_tracker_sender_type_t sender, int32_t i, int32_t offset, int32_t size, void *buffer) + { + struct ecm_tracker_datagram_internal_instance *dtii = (struct ecm_tracker_datagram_internal_instance *)uti; + int res; +@@ -466,7 +466,7 @@ static int ecm_tracker_datagram_datagram + * ecm_tracker_datagram_datagram_add() + * Append the datagram onto the tracker queue for the given target + */ +-static bool ecm_tracker_datagram_datagram_add(struct ecm_tracker_datagram_instance *uti, ecm_tracker_sender_type_t sender, struct sk_buff *skb) ++bool ecm_tracker_datagram_datagram_add(struct ecm_tracker_datagram_instance *uti, ecm_tracker_sender_type_t sender, struct sk_buff *skb) + { + struct ecm_tracker_datagram_internal_instance *dtii = (struct ecm_tracker_datagram_internal_instance *)uti; + struct sk_buff *skbc; +--- a/frontends/ecm_front_end_common.c ++++ b/frontends/ecm_front_end_common.c +@@ -511,6 +511,7 @@ bool ecm_front_end_gre_proto_is_accel_al + struct nf_conntrack_tuple *reply_tuple, + int ip_version, uint16_t offset) + { ++#ifdef ECM_INTERFACE_GRE_ENABLE + struct net_device *dev; + struct gre_base_hdr *greh; + +@@ -522,10 +523,12 @@ bool ecm_front_end_gre_proto_is_accel_al + /* + * Case 1: PPTP locally terminated + */ ++#ifdef ECM_INTERFACE_PPTP_ENABLE + if (ecm_interface_is_pptp(skb, outdev)) { + DEBUG_TRACE("%px: PPTP GRE locally terminated - allow acceleration\n", skb); + return true; + } ++#endif + + /* + * Case 2: PPTP pass through +@@ -651,6 +654,10 @@ bool ecm_front_end_gre_proto_is_accel_al + */ + DEBUG_TRACE("%px: GRE IPv%d pass through non NAT - allow acceleration\n", skb, ip_version); + return true; ++#else ++ DEBUG_TRACE("%px: GRE%d feature is disabled - do not allow acceleration\n", skb, ip_version); ++ return false; ++#endif + } + + #ifdef ECM_CLASSIFIER_DSCP_ENABLE +--- a/frontends/nss/ecm_nss_common.h ++++ b/frontends/nss/ecm_nss_common.h +@@ -310,6 +310,7 @@ static inline bool ecm_nss_common_igs_ac + } + #endif + ++#if (NSS_FW_VERSION_CODE > NSS_FW_VERSION(11,2)) + #ifdef ECM_CLASSIFIER_PCC_ENABLE + /* + * ecm_nss_common_fill_mirror_info() +@@ -363,6 +364,7 @@ static inline bool ecm_nss_common_fill_m + return true; + } + #endif ++#endif + + bool ecm_nss_ipv6_is_conn_limit_reached(void); + bool ecm_nss_ipv4_is_conn_limit_reached(void); +--- a/frontends/nss/ecm_nss_ipv4.c ++++ b/frontends/nss/ecm_nss_ipv4.c +@@ -700,7 +700,7 @@ static void ecm_nss_ipv4_stats_sync_req_ + } + spin_unlock_bh(&ecm_nss_ipv4_lock); + +- usleep_range(ECM_NSS_IPV4_STATS_SYNC_UDELAY - 100, ECM_NSS_IPV4_STATS_SYNC_UDELAY); ++ msleep_interruptible(ECM_NSS_IPV4_STATS_SYNC_UDELAY / 1000); + + /* + * If index is 0, we are starting a new round, but if we still have time remain +@@ -714,7 +714,7 @@ static void ecm_nss_ipv4_stats_sync_req_ + } + + if (time_after(ecm_nss_ipv4_next_req_time, current_jiffies)) { +- msleep(jiffies_to_msecs(ecm_nss_ipv4_next_req_time - current_jiffies)); ++ msleep_interruptible(jiffies_to_msecs(ecm_nss_ipv4_next_req_time - current_jiffies)); + } + ecm_nss_ipv4_roll_check_jiffies = jiffies; + ecm_nss_ipv4_next_req_time = ecm_nss_ipv4_roll_check_jiffies + ECM_NSS_IPV4_STATS_SYNC_PERIOD; +--- a/frontends/nss/ecm_nss_ipv6.c ++++ b/frontends/nss/ecm_nss_ipv6.c +@@ -676,7 +676,7 @@ static void ecm_nss_ipv6_stats_sync_req_ + } + spin_unlock_bh(&ecm_nss_ipv6_lock); + +- usleep_range(ECM_NSS_IPV6_STATS_SYNC_UDELAY - 100, ECM_NSS_IPV6_STATS_SYNC_UDELAY); ++ msleep_interruptible(ECM_NSS_IPV6_STATS_SYNC_UDELAY / 1000); + + /* + * If index is 0, we are starting a new round, but if we still have time remain +@@ -690,7 +690,7 @@ static void ecm_nss_ipv6_stats_sync_req_ + } + + if (time_after(ecm_nss_ipv6_next_req_time, current_jiffies)) { +- msleep(jiffies_to_msecs(ecm_nss_ipv6_next_req_time - current_jiffies)); ++ msleep_interruptible(jiffies_to_msecs(ecm_nss_ipv6_next_req_time - current_jiffies)); + } + ecm_nss_ipv6_roll_check_jiffies = jiffies; + ecm_nss_ipv6_next_req_time = ecm_nss_ipv6_roll_check_jiffies + ECM_NSS_IPV6_STATS_SYNC_PERIOD; +--- a/frontends/nss/ecm_nss_ported_ipv4.c ++++ b/frontends/nss/ecm_nss_ported_ipv4.c +@@ -1045,6 +1045,7 @@ static void ecm_nss_ported_ipv4_connecti + } + #endif + ++#if (NSS_FW_VERSION_CODE > NSS_FW_VERSION(11,2)) + #ifdef ECM_CLASSIFIER_PCC_ENABLE + /* + * Set up the interfaces for mirroring. +@@ -1069,6 +1070,7 @@ static void ecm_nss_ported_ipv4_connecti + nircm->valid_flags |= NSS_IPV4_RULE_CREATE_MIRROR_VALID; + } + #endif ++#endif + + if (ecm_nss_ipv4_vlan_passthrough_enable && !ecm_db_connection_is_routed_get(feci->ci) && + (nircm->vlan_primary_rule.ingress_vlan_tag == ECM_FRONT_END_VLAN_ID_NOT_CONFIGURED) && +--- a/frontends/nss/ecm_nss_ported_ipv6.c ++++ b/frontends/nss/ecm_nss_ported_ipv6.c +@@ -1014,6 +1014,7 @@ static void ecm_nss_ported_ipv6_connecti + } + #endif + ++#if (NSS_FW_VERSION_CODE > NSS_FW_VERSION(11,2)) + #ifdef ECM_CLASSIFIER_PCC_ENABLE + /* + * Set up the interfaces for mirroring. +@@ -1038,6 +1039,7 @@ static void ecm_nss_ported_ipv6_connecti + nircm->valid_flags |= NSS_IPV6_RULE_CREATE_MIRROR_VALID; + } + #endif ++#endif + + if (ecm_nss_ipv6_vlan_passthrough_enable && !ecm_db_connection_is_routed_get(feci->ci) && + (nircm->vlan_primary_rule.ingress_vlan_tag == ECM_FRONT_END_VLAN_ID_NOT_CONFIGURED) && +--- a/ecm_types.h ++++ b/ecm_types.h +@@ -464,7 +464,7 @@ static inline bool ecm_string_to_ip_addr + static inline bool ecm_debugfs_create_u32(const char *name, umode_t mode, + struct dentry *parent, u32 *value) + { +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0)) ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) + struct dentry *d = debugfs_create_u32(name, mode, parent, value); + if (!d) { + return false; +--- a/ecm_tracker.c ++++ b/ecm_tracker.c +@@ -84,7 +84,6 @@ static bool ecm_tracker_ip_header_helper + static bool ecm_tracker_ip_header_helper_icmp(struct ecm_tracker_ip_protocols *etip, struct ecm_tracker_ip_protocol_header *etiph, struct ecm_tracker_ip_header *ip_hdr, struct sk_buff *skb, uint8_t protocol, ecm_tracker_ip_protocol_type_t ecm_ip_protocol, uint32_t offset, uint32_t remain, int16_t *next_hdr); + static bool ecm_tracker_ip_header_helper_unknown(struct ecm_tracker_ip_protocols *etip, struct ecm_tracker_ip_protocol_header *etiph, struct ecm_tracker_ip_header *ip_hdr, struct sk_buff *skb, uint8_t protocol, ecm_tracker_ip_protocol_type_t ecm_ip_protocol, uint32_t offset, uint32_t remain, int16_t *next_hdr); + static bool ecm_tracker_ip_header_helper_gre(struct ecm_tracker_ip_protocols *etip, struct ecm_tracker_ip_protocol_header *etiph, struct ecm_tracker_ip_header *ip_hdr, struct sk_buff *skb, uint8_t protocol, ecm_tracker_ip_protocol_type_t ecm_ip_protocol, uint32_t offset, uint32_t remain, int16_t *next_hdr); +-static bool ecm_tracker_ip_header_helper_etherip(struct ecm_tracker_ip_protocols *etip, struct ecm_tracker_ip_protocol_header *etiph, struct ecm_tracker_ip_header *ip_hdr, struct sk_buff *skb, uint8_t protocol, ecm_tracker_ip_protocol_type_t ecm_ip_protocol, uint32_t offset, uint32_t remain, int16_t *next_hdr); + #ifdef ECM_IPV6_ENABLE + static bool ecm_tracker_ip_header_helper_ipv6_generic(struct ecm_tracker_ip_protocols *etip, struct ecm_tracker_ip_protocol_header *etiph, struct ecm_tracker_ip_header *ip_hdr, struct sk_buff *skb, uint8_t protocol, ecm_tracker_ip_protocol_type_t ecm_ip_protocol, uint32_t offset, uint32_t remain, int16_t *next_hdr); + static bool ecm_tracker_ip_header_helper_ipv6_fragment(struct ecm_tracker_ip_protocols *etip, struct ecm_tracker_ip_protocol_header *etiph, struct ecm_tracker_ip_header *ip_hdr, struct sk_buff *skb, uint8_t protocol, ecm_tracker_ip_protocol_type_t ecm_ip_protocol, uint32_t offset, uint32_t remain, int16_t *next_hdr); +@@ -223,7 +222,7 @@ static struct ecm_tracker_ip_protocols { + {94, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "94", ecm_tracker_ip_header_helper_unknown}, + {95, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "95", ecm_tracker_ip_header_helper_unknown}, + {96, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "96", ecm_tracker_ip_header_helper_unknown}, +- {97, ECM_TRACKER_IP_PROTOCOL_TYPE_ETHERIP, "etherip", ecm_tracker_ip_header_helper_etherip}, ++ {97, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "97", ecm_tracker_ip_header_helper_unknown}, + {98, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "98", ecm_tracker_ip_header_helper_unknown}, + {99, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "99", ecm_tracker_ip_header_helper_unknown}, + {100, ECM_TRACKER_IP_PROTOCOL_TYPE_UNKNOWN, "100", ecm_tracker_ip_header_helper_unknown}, +@@ -971,33 +970,6 @@ static bool ecm_tracker_ip_header_helper + */ + *next_hdr = -1; + return true; +-} +- +-/* +- * ecm_tracker_ip_header_helper_etherip() +- * Interpret an Etherip header +- */ +-static bool ecm_tracker_ip_header_helper_etherip(struct ecm_tracker_ip_protocols *etip, struct ecm_tracker_ip_protocol_header *etiph, struct ecm_tracker_ip_header *ip_hdr, +- struct sk_buff *skb, uint8_t protocol, ecm_tracker_ip_protocol_type_t ecm_ip_protocol, uint32_t offset, uint32_t remain, int16_t *next_hdr) +-{ +- DEBUG_ASSERT((protocol == IPPROTO_ETHERIP) && (ecm_ip_protocol == ECM_TRACKER_IP_PROTOCOL_TYPE_ETHERIP), "Bad protocol: %u or ecm_ip_protocol: %d", protocol, ecm_ip_protocol); +- +- DEBUG_TRACE("etherip helper skb: %px, protocol: %u, ecm_ip_proto: %d, offset: %u, remain: %u\n", skb, protocol, ecm_ip_protocol, offset, remain); +- if (remain < 16) { +- DEBUG_TRACE("not enough Etherip header: %u\n", remain); +- return false; +- } +- +- etiph->protocol_number = protocol; +- etiph->header_size = 16; +- etiph->size = remain; +- etiph->offset = offset; +- +- /* +- * There is no header following an Etherip header +- */ +- *next_hdr = -1; +- return true; + } + + /* +--- a/ecm_tracker.h ++++ b/ecm_tracker.h +@@ -108,7 +108,6 @@ enum ecm_tracker_ip_protocol_types { + ECM_TRACKER_IP_PROTOCOL_TYPE_IPV6_DO, + ECM_TRACKER_IP_PROTOCOL_TYPE_IPV6_HBH, /* IPv6 hop-by-hop header */ + #endif +- ECM_TRACKER_IP_PROTOCOL_TYPE_ETHERIP, + ECM_TRACKER_IP_PROTOCOL_TYPE_COUNT /* Must be last, do not use */ + }; + typedef enum ecm_tracker_ip_protocol_types ecm_tracker_ip_protocol_type_t; +--- a/frontends/cmn/ecm_non_ported_ipv6.c ++++ b/frontends/cmn/ecm_non_ported_ipv6.c +@@ -121,7 +121,6 @@ static inline bool ecm_non_ported_ipv6_i + #if defined(ECM_INTERFACE_GRE_TAP_ENABLE) || defined(ECM_INTERFACE_GRE_TUN_ENABLE) + case IPPROTO_GRE: + #endif +- case IPPROTO_ETHERIP: + case IPPROTO_RAW: + return true; + } diff --git a/package/qca-nss/qca-nss-ecm/patches/115-Fix_dev_put-issue-for-6.x-kernel-in-ecm-module.patch b/package/qca-nss/qca-nss-ecm/patches/115-Fix_dev_put-issue-for-6.x-kernel-in-ecm-module.patch new file mode 100644 index 0000000000..4f98be1b54 --- /dev/null +++ b/package/qca-nss/qca-nss-ecm/patches/115-Fix_dev_put-issue-for-6.x-kernel-in-ecm-module.patch @@ -0,0 +1,51 @@ +From 7d7289cbe10bac309db3cc792f2bb13b3befdc07 Mon Sep 17 00:00:00 2001 +From: Amruth S +Date: Tue, 5 Dec 2023 21:47:37 -0800 +Subject: [PATCH] [qca-nss-ecm]: Fix_dev_put issue for 6.x kernel in ecm module + +Explicitly hold netdev refs for 6.1 and above kernels. The API +doesn't hold it in these kernels. + +Signed-off-by: Amruth S +Change-Id: I54594dae664610e2a5703b71c1430e325d04aeaa +--- + ecm_interface.c | 2 ++ + frontends/ecm_front_end_common.c | 2 ++ + 2 files changed, 4 insertions(+) + +--- a/ecm_interface.c ++++ b/ecm_interface.c +@@ -342,6 +342,7 @@ static struct net_device *ecm_interface_ + dev = (struct net_device *)ipv6_dev_find(&init_net, &addr6, 1); + #else + dev = (struct net_device *)ipv6_dev_find(&init_net, &addr6, NULL); ++ dev_hold(dev); + #endif + return dev; + } +@@ -805,6 +806,7 @@ static bool ecm_interface_mac_addr_get_i + local_dev = ipv6_dev_find(&init_net, &daddr, 1); + #else + local_dev = ipv6_dev_find(&init_net, &daddr, NULL); ++ dev_hold(local_dev); + #endif + if (local_dev) { + DEBUG_TRACE("%pi6 is a local address\n", &daddr); +--- a/frontends/ecm_front_end_common.c ++++ b/frontends/ecm_front_end_common.c +@@ -611,6 +611,7 @@ bool ecm_front_end_gre_proto_is_accel_al + dev = ipv6_dev_find(&init_net, &(orig_tuple->src.u3.in6), 1); + #else + dev = ipv6_dev_find(&init_net, &(orig_tuple->src.u3.in6), NULL); ++ dev_hold(dev); + #endif + if (dev) { + /* +@@ -625,6 +626,7 @@ bool ecm_front_end_gre_proto_is_accel_al + dev = ipv6_dev_find(&init_net, &(orig_tuple->dst.u3.in6), 1); + #else + dev = ipv6_dev_find(&init_net, &(orig_tuple->dst.u3.in6), NULL); ++ dev_hold(dev); + #endif + if (dev) { + /* diff --git a/package/qca-nss/qca-nss-ecm/patches/200-Passing-structure-as-params-for-sawf-hdl-query.patch b/package/qca-nss/qca-nss-ecm/patches/200-Passing-structure-as-params-for-sawf-hdl-query.patch new file mode 100644 index 0000000000..25106d8799 --- /dev/null +++ b/package/qca-nss/qca-nss-ecm/patches/200-Passing-structure-as-params-for-sawf-hdl-query.patch @@ -0,0 +1,178 @@ +From 85d8656de0a22dc5b45a5f8810e5863726bd5a9b Mon Sep 17 00:00:00 2001 +From: Swati Singh +Date: Mon, 26 Jun 2023 16:33:51 +0530 +Subject: [PATCH] [qca-nss-ecm]: Passing structure as params for sawf_hdl + query. + +The wifi driver call to get sawf hdl info will have +struct ecm_classifier_sawf_flow_info as params. + +Also, the wifi driver signature will be 32 bits to +return sawf_mark. + +Change-Id: I5f49be2938887a8c0669e9b760e5fee24b8bd290 +Signed-off-by: Swati Singh +--- + ecm_classifier_emesh.c | 41 +++++++++++++++++++++--- + ecm_wifi_plugins/ecm_wifi_plugin_emesh.c | 19 ++++++++++- + exports/ecm_classifier_emesh_public.h | 22 +++++++++++-- + 3 files changed, 74 insertions(+), 8 deletions(-) + +--- a/ecm_classifier_emesh.c ++++ b/ecm_classifier_emesh.c +@@ -91,6 +91,7 @@ + #define ECM_CLASSIFIER_EMESH_SAWF_TAG_GET(sawf_meta) ((sawf_meta >> 24) & 0xFF) + #define ECM_CLASSIFIER_EMESH_SAWF_TAG_IS_VALID(sawf_meta) \ + ((ECM_CLASSIFIER_EMESH_SAWF_TAG_GET(sawf_meta) == ECM_CLASSIFIER_EMESH_SAWF_VALID_TAG) ? true : false) ++#define ECM_CLASSIFIER_EMESH_SAWF_VALID_MSDUQ_MASK 0xffff + + /* + * EMESH classifier type. +@@ -244,6 +245,7 @@ static void ecm_classifier_emesh_sawf_fl + uint16_t msduq_reverse = ECM_CLASSIFIER_EMESH_SAWF_INVALID_MSDUQ; + uint8_t dmac[ETH_ALEN]; + uint8_t smac[ETH_ALEN]; ++ struct ecm_classifier_emesh_sawf_flow_info sawf_flow_info = {0}; + + if (msg->ip_version == 4) { + DEBUG_TRACE("%px: flow/return service_class_id=%u/%u %pI4n:%u -> %pI4n:%u protocol=%d\n", msg, +@@ -298,10 +300,25 @@ static void ecm_classifier_emesh_sawf_fl + */ + if (ecm_emesh.update_service_id_get_msduq) { + if (dest_dev) { +- msduq_forward = ecm_emesh.update_service_id_get_msduq(dest_dev, dmac, msg->flow_service_class_id, 0, 0, SP_SAWF_RULE_TYPE_DEFAULT); ++ sawf_flow_info.netdev = dest_dev; ++ sawf_flow_info.peer_mac = dmac; ++ sawf_flow_info.service_id = msg->flow_service_class_id; ++ sawf_flow_info.dscp = 0; ++ sawf_flow_info.rule_id = 0; ++ sawf_flow_info.sawf_rule_type = SP_SAWF_RULE_TYPE_DEFAULT; ++ ++ msduq_forward = ecm_emesh.update_service_id_get_msduq(&sawf_flow_info) & ECM_CLASSIFIER_EMESH_SAWF_VALID_MSDUQ_MASK; + } ++ + if (src_dev) { +- msduq_reverse = ecm_emesh.update_service_id_get_msduq(src_dev, smac, msg->return_service_class_id, 0, 0, SP_SAWF_RULE_TYPE_DEFAULT); ++ sawf_flow_info.netdev = src_dev; ++ sawf_flow_info.peer_mac = smac; ++ sawf_flow_info.service_id = msg->return_service_class_id; ++ sawf_flow_info.dscp = 0; ++ sawf_flow_info.rule_id = 0; ++ sawf_flow_info.sawf_rule_type = SP_SAWF_RULE_TYPE_DEFAULT; ++ ++ msduq_reverse = ecm_emesh.update_service_id_get_msduq(&sawf_flow_info) & ECM_CLASSIFIER_EMESH_SAWF_VALID_MSDUQ_MASK; + } + } + +@@ -1136,7 +1153,7 @@ static void ecm_classifier_emesh_sawf_pr + struct sp_rule_output_params flow_output_params; + struct sp_rule_output_params return_output_params; + bool is_sawf_relevant = false; +- ++ struct ecm_classifier_emesh_sawf_flow_info sawf_flow_info = {0}; + cemi = (struct ecm_classifier_emesh_sawf_instance *)aci; + DEBUG_CHECK_MAGIC(cemi, ECM_CLASSIFIER_EMESH_INSTANCE_MAGIC, "%px: magic failed\n", cemi); + +@@ -1290,7 +1307,14 @@ static void ecm_classifier_emesh_sawf_pr + */ + if (ecm_emesh.update_service_id_get_msduq) { + if (dest_dev) { +- msduq_forward = ecm_emesh.update_service_id_get_msduq(dest_dev, dmac, flow_output_params.service_class_id, cemi->dscp[ECM_CONN_DIR_FLOW], flow_output_params.rule_id, flow_output_params.sawf_rule_type); ++ sawf_flow_info.netdev = dest_dev; ++ sawf_flow_info.peer_mac = dmac; ++ sawf_flow_info.service_id = flow_output_params.service_class_id; ++ sawf_flow_info.dscp = cemi->dscp[ECM_CONN_DIR_FLOW]; ++ sawf_flow_info.rule_id = flow_output_params.rule_id; ++ sawf_flow_info.sawf_rule_type = flow_output_params.sawf_rule_type; ++ ++ msduq_forward = ecm_emesh.update_service_id_get_msduq(&sawf_flow_info) & ECM_CLASSIFIER_EMESH_SAWF_VALID_MSDUQ_MASK; + + /* + * Mark the skb with SAWF meta data for flow creation packet. +@@ -1300,7 +1324,14 @@ static void ecm_classifier_emesh_sawf_pr + msduq_forward); + } + if (src_dev) { +- msduq_reverse = ecm_emesh.update_service_id_get_msduq(src_dev, smac, return_output_params.service_class_id, cemi->dscp[ECM_CONN_DIR_RETURN], return_output_params.rule_id, return_output_params.sawf_rule_type); ++ sawf_flow_info.netdev = src_dev; ++ sawf_flow_info.peer_mac = smac; ++ sawf_flow_info.service_id = return_output_params.service_class_id; ++ sawf_flow_info.dscp = cemi->dscp[ECM_CONN_DIR_RETURN]; ++ sawf_flow_info.rule_id = return_output_params.rule_id; ++ sawf_flow_info.sawf_rule_type = return_output_params.sawf_rule_type; ++ ++ msduq_reverse = ecm_emesh.update_service_id_get_msduq(&sawf_flow_info) & ECM_CLASSIFIER_EMESH_SAWF_VALID_MSDUQ_MASK; + } + } + +--- a/ecm_wifi_plugins/ecm_wifi_plugin_emesh.c ++++ b/ecm_wifi_plugins/ecm_wifi_plugin_emesh.c +@@ -48,12 +48,29 @@ static inline void ecm_wifi_plugin_emesh + } + + /* ++ * ecm_wifi_plugin_emesh_sawf_get_mark_data() ++ * get skb mark callback for EMESH-SAWF classifier. ++ */ ++static inline uint32_t ecm_wifi_plugin_emesh_sawf_get_mark_data(struct ecm_classifier_emesh_sawf_flow_info *sawf_flow_info) ++{ ++ struct qca_sawf_metadata_param sawf_params = {0}; ++ ++ sawf_params.netdev = sawf_flow_info->netdev; ++ sawf_params.peer_mac = sawf_flow_info->peer_mac; ++ sawf_params.service_id = sawf_flow_info->service_id; ++ sawf_params.dscp = sawf_flow_info->dscp; ++ sawf_params.rule_id = sawf_flow_info->rule_id; ++ sawf_params.sawf_rule_type = sawf_flow_info->sawf_rule_type; ++ ++ return qca_sawf_get_mark_metadata(&sawf_params); ++} ++/* + * ecm_wifi_plugin_emesh + * Register EMESH client callback with ECM EMSH classifier to update peer mesh latency parameters. + */ + static struct ecm_classifier_emesh_sawf_callbacks ecm_wifi_plugin_emesh = { + .update_peer_mesh_latency_params = qca_mesh_latency_update_peer_parameter, +- .update_service_id_get_msduq = qca_sawf_get_msduq_v2, ++ .update_service_id_get_msduq = ecm_wifi_plugin_emesh_sawf_get_mark_data, + .sawf_conn_sync = ecm_wifi_plugin_emesh_sawf_conn_sync, + }; + +--- a/exports/ecm_classifier_emesh_public.h ++++ b/exports/ecm_classifier_emesh_public.h +@@ -61,6 +61,25 @@ struct ecm_classifier_fse_info { + }; + + /** ++ * ecm_classifier_emesh_sawf_flow_info ++ * ++ * @netdev : Netdevice ++ * @peer_mac : Destination peer mac address ++ * @service_id : Service class id ++ * @dscp : Differentiated Services Code Point ++ * @rule_id : Rule id ++ * @sawf_rule_type: Rule type ++ */ ++struct ecm_classifier_emesh_sawf_flow_info { ++ struct net_device *netdev; ++ uint8_t *peer_mac; ++ uint32_t service_id; ++ uint32_t dscp; ++ uint32_t rule_id; ++ uint8_t sawf_rule_type; ++}; ++ ++/** + * Mesh latency configuration update callback function to which MSCS client will register. + */ + typedef int (*ecm_classifier_emesh_callback_t)(uint8_t dest_mac[], +@@ -71,8 +90,7 @@ typedef int (*ecm_classifier_emesh_callb + /** + * MSDUQ callback to which emesh-sawf will register. + */ +-typedef uint16_t (*ecm_classifier_emesh_msduq_callback_t)(struct net_device *out_dev, +- uint8_t dest_mac[], uint32_t service_class_id, uint32_t dscp, uint32_t rule_id, uint8_t sawf_rule_type); ++typedef uint32_t (*ecm_classifier_emesh_msduq_callback_t)(struct ecm_classifier_emesh_sawf_flow_info *sawf_flow_info); + + /** + * SAWF params sync callback function pointer. diff --git a/package/qca-nss/qca-nss-ecm/patches/210-ECM-to-wlan-driver-callback-signature-changes.patch b/package/qca-nss/qca-nss-ecm/patches/210-ECM-to-wlan-driver-callback-signature-changes.patch new file mode 100644 index 0000000000..3728a1cf38 --- /dev/null +++ b/package/qca-nss/qca-nss-ecm/patches/210-ECM-to-wlan-driver-callback-signature-changes.patch @@ -0,0 +1,335 @@ +From 12cdc396ed57835c2056f9d524e3661745ac7d57 Mon Sep 17 00:00:00 2001 +From: Parikshit Gune +Date: Fri, 28 Jul 2023 11:04:45 +0530 +Subject: [PATCH] [qca-nss-ecm] ECM to wlan driver callback signature changes. + +1. Signature change to pack the information into structures instead of +individual fields for EMESH, SCS, MSCS wlan callbacks. +2. Add src and dest net devices in the EMESH param sync callback. + +Change-Id: Iafbde3f0bbe073a8720ab86371c344d4941158ec +Signed-off-by: Parikshit Gune +--- + ecm_classifier_emesh.c | 70 ++++++++++++++++++++---- + ecm_classifier_mscs.c | 11 +++- + ecm_wifi_plugins/ecm_wifi_plugin_emesh.c | 23 +++++++- + ecm_wifi_plugins/ecm_wifi_plugin_mscs.c | 33 ++++++++++- + exports/ecm_classifier_emesh_public.h | 21 +++++-- + exports/ecm_classifier_mscs_public.h | 26 ++++++++- + 6 files changed, 161 insertions(+), 23 deletions(-) + +--- a/ecm_classifier_emesh.c ++++ b/ecm_classifier_emesh.c +@@ -1747,7 +1747,10 @@ void ecm_classifier_emesh_sawf_params_sy + void ecm_classifier_emesh_sawf_update_latency_param_on_conn_decel(struct ecm_classifier_instance *aci, struct ecm_classifier_rule_sync *sync) + { + struct ecm_classifier_emesh_sawf_instance *cemi; ++ struct ecm_classifer_emesh_sawf_mesh_latency_params mesh_params = {0}; + struct ecm_db_connection_instance *ci; ++ struct net_device *src_dev = NULL; ++ struct net_device *dest_dev = NULL; + uint8_t peer_mac[ETH_ALEN]; + + cemi = (struct ecm_classifier_emesh_sawf_instance *)aci; +@@ -1775,21 +1778,40 @@ void ecm_classifier_emesh_sawf_update_la + return; + } + ++ ecm_db_netdevs_get_and_hold(ci, ECM_TRACKER_SENDER_TYPE_SRC, &src_dev, &dest_dev); ++ + /* + * Get mac address for destination node + */ + ecm_db_connection_node_address_get(ci, ECM_DB_OBJ_DIR_TO, peer_mac); +- ecm_emesh.update_peer_mesh_latency_params(peer_mac, +- cemi->service_interval_dl, cemi->burst_size_dl, cemi->service_interval_ul, cemi->burst_size_ul, +- cemi->pcp[ECM_CONN_DIR_FLOW], ECM_CLASSIFIER_EMESH_SUB_LATENCY_PARAMS); ++ ++ mesh_params.peer_mac = peer_mac; ++ mesh_params.dst_dev = dest_dev; ++ mesh_params.src_dev = src_dev; ++ mesh_params.service_interval_dl = cemi->service_interval_dl; ++ mesh_params.service_interval_ul = cemi->service_interval_ul; ++ mesh_params.burst_size_dl = cemi->burst_size_dl; ++ mesh_params.burst_size_ul = cemi->burst_size_ul; ++ mesh_params.priority = cemi->pcp[ECM_CONN_DIR_FLOW]; ++ mesh_params.accel_or_decel = ECM_CLASSIFIER_EMESH_SUB_LATENCY_PARAMS; ++ ++ ecm_emesh.update_peer_mesh_latency_params(&mesh_params); + + /* + * Get mac address for source node + */ + ecm_db_connection_node_address_get(ci, ECM_DB_OBJ_DIR_FROM, peer_mac); +- ecm_emesh.update_peer_mesh_latency_params(peer_mac, +- cemi->service_interval_dl, cemi->burst_size_dl, cemi->service_interval_ul, cemi->burst_size_ul, +- cemi->pcp[ECM_CONN_DIR_FLOW], ECM_CLASSIFIER_EMESH_SUB_LATENCY_PARAMS); ++ ++ mesh_params.peer_mac = peer_mac; ++ mesh_params.dst_dev = src_dev; ++ mesh_params.src_dev = dest_dev; ++ ecm_emesh.update_peer_mesh_latency_params(&mesh_params); ++ ++ if (src_dev) ++ dev_put(src_dev); ++ ++ if (dest_dev) ++ dev_put(dest_dev); + + ecm_db_connection_deref(ci); + } +@@ -1895,6 +1917,8 @@ static void ecm_classifier_emesh_sawf_up + uint8_t service_interval_ul; + uint32_t burst_size_ul; + struct sk_buff *skb; ++ struct net_device *src_dev, *dest_dev = NULL; ++ struct ecm_classifer_emesh_sawf_mesh_latency_params mesh_params = {0}; + uint8_t dmac[ETH_ALEN]; + uint8_t smac[ETH_ALEN]; + +@@ -1933,6 +1957,8 @@ static void ecm_classifier_emesh_sawf_up + return; + } + ++ ecm_db_netdevs_get_and_hold(ci, ECM_TRACKER_SENDER_TYPE_SRC, &src_dev, &dest_dev); ++ + /* + * Invoke SPM rule lookup API to update skb priority + * When latency config is enabled, fetch latency parameter +@@ -1966,9 +1992,16 @@ static void ecm_classifier_emesh_sawf_up + /* + * Send destination mac address of this connection + */ +- ecm_emesh.update_peer_mesh_latency_params(dmac, +- service_interval_dl, burst_size_dl, service_interval_ul, burst_size_ul, +- skb->priority, ECM_CLASSIFIER_EMESH_ADD_LATENCY_PARAMS); ++ mesh_params.dst_dev = dest_dev; ++ mesh_params.src_dev = src_dev; ++ mesh_params.peer_mac = dmac; ++ mesh_params.service_interval_dl = service_interval_dl; ++ mesh_params.service_interval_ul = service_interval_ul; ++ mesh_params.burst_size_dl = burst_size_dl; ++ mesh_params.burst_size_ul = burst_size_ul; ++ mesh_params.priority = skb->priority; ++ mesh_params.accel_or_decel = ECM_CLASSIFIER_EMESH_ADD_LATENCY_PARAMS; ++ ecm_emesh.update_peer_mesh_latency_params(&mesh_params); + } + + /* +@@ -1981,11 +2014,24 @@ static void ecm_classifier_emesh_sawf_up + /* + * Send source mac address of this connection + */ +- ecm_emesh.update_peer_mesh_latency_params(smac, +- service_interval_dl, burst_size_dl, service_interval_ul, burst_size_ul, +- skb->priority, ECM_CLASSIFIER_EMESH_ADD_LATENCY_PARAMS); ++ mesh_params.peer_mac = smac; ++ mesh_params.dst_dev = src_dev; ++ mesh_params.src_dev = dest_dev; ++ mesh_params.service_interval_dl = service_interval_dl; ++ mesh_params.service_interval_ul = service_interval_ul; ++ mesh_params.burst_size_dl = burst_size_dl; ++ mesh_params.burst_size_ul = burst_size_ul; ++ mesh_params.priority = skb->priority; ++ mesh_params.accel_or_decel = ECM_CLASSIFIER_EMESH_ADD_LATENCY_PARAMS; ++ ecm_emesh.update_peer_mesh_latency_params(&mesh_params); + } + ++ if (src_dev) ++ dev_put(src_dev); ++ ++ if (dest_dev) ++ dev_put(dest_dev); ++ + ecm_db_connection_deref(ci); + } + +--- a/ecm_classifier_mscs.c ++++ b/ecm_classifier_mscs.c +@@ -425,6 +425,8 @@ static void ecm_classifier_mscs_process( + #ifdef ECM_CLASSIFIER_MSCS_SCS_ENABLE + struct sp_rule_input_params flow_input_params; + struct sp_rule_output_params flow_output_params; ++ struct ecm_classifier_mscs_get_priority_info get_priority_info = {0}; ++ struct ecm_classifier_mscs_rule_match_info rule_match_info = {0}; + ecm_classifier_mscs_scs_priority_callback_t scs_cb = NULL; + #endif + #ifdef ECM_MULTICAST_ENABLE +@@ -545,7 +547,9 @@ static void ecm_classifier_mscs_process( + goto check_mscs_classifier; + } + +- result = scs_cb(flow_output_params.rule_id, dmac); ++ rule_match_info.rule_id = flow_output_params.rule_id; ++ rule_match_info.dst_mac = dmac; ++ result = scs_cb(&rule_match_info); + } + } + +@@ -617,7 +621,10 @@ static void ecm_classifier_mscs_process( + /* + * Invoke callback registered to classifier for peer look up + */ +- result = cb(smac, dmac, skb); ++ get_priority_info.src_mac = smac; ++ get_priority_info.dst_mac = dmac; ++ get_priority_info.skb = skb; ++ result = cb(&get_priority_info); + + if (result == ECM_CLASSIFIER_MSCS_RESULT_UPDATE_PRIORITY) { + cmscsi->mscs_priority_update = true; +--- a/ecm_wifi_plugins/ecm_wifi_plugin_emesh.c ++++ b/ecm_wifi_plugins/ecm_wifi_plugin_emesh.c +@@ -26,6 +26,27 @@ + #include "ecm_wifi_plugin.h" + + /* ++ * ecm_wifi_plugin_emesh_sawf_update_peer_mesh_params() ++ * Update mesh latency params. ++ */ ++static inline void ecm_wifi_plugin_emesh_sawf_update_peer_mesh_params(struct ecm_classifer_emesh_sawf_mesh_latency_params *mesh_params) ++{ ++ struct qca_mesh_latency_update_peer_param wlan_mesh_params = {0}; ++ ++ wlan_mesh_params.dest_mac = mesh_params->peer_mac; ++ wlan_mesh_params.src_dev = mesh_params->src_dev; ++ wlan_mesh_params.dst_dev = mesh_params->dst_dev; ++ wlan_mesh_params.service_interval_dl = mesh_params->service_interval_dl; ++ wlan_mesh_params.service_interval_ul = mesh_params->service_interval_ul; ++ wlan_mesh_params.burst_size_dl = mesh_params->burst_size_dl; ++ wlan_mesh_params.burst_size_ul = mesh_params->burst_size_ul; ++ wlan_mesh_params.priority = mesh_params->priority; ++ wlan_mesh_params.add_or_sub = mesh_params->accel_or_decel; ++ ++ qca_mesh_latency_update_peer_parameter_v2(&wlan_mesh_params); ++} ++ ++/* + * ecm_wifi_plugin_emesh_sawf_conn_sync() + * Connection sync callback for EMESH-SAWF classifier. + */ +@@ -69,7 +90,7 @@ static inline uint32_t ecm_wifi_plugin_e + * Register EMESH client callback with ECM EMSH classifier to update peer mesh latency parameters. + */ + static struct ecm_classifier_emesh_sawf_callbacks ecm_wifi_plugin_emesh = { +- .update_peer_mesh_latency_params = qca_mesh_latency_update_peer_parameter, ++ .update_peer_mesh_latency_params = ecm_wifi_plugin_emesh_sawf_update_peer_mesh_params, + .update_service_id_get_msduq = ecm_wifi_plugin_emesh_sawf_get_mark_data, + .sawf_conn_sync = ecm_wifi_plugin_emesh_sawf_conn_sync, + }; +--- a/ecm_wifi_plugins/ecm_wifi_plugin_mscs.c ++++ b/ecm_wifi_plugins/ecm_wifi_plugin_mscs.c +@@ -26,13 +26,42 @@ + #include "ecm_wifi_plugin.h" + + /* ++ * ecm_wifi_plugin_get_peer_priority() ++ * Get peer priority callback into wlan driver. ++ */ ++static inline int ecm_wifi_plugin_get_peer_priority(struct ecm_classifier_mscs_get_priority_info *get_priority_info) ++{ ++ struct qca_mscs_get_priority_param wlan_get_priority_param = {0}; ++ ++ wlan_get_priority_param.dst_mac = get_priority_info->dst_mac; ++ wlan_get_priority_param.src_mac = get_priority_info->src_mac; ++ wlan_get_priority_param.skb = get_priority_info->skb; ++ ++ return qca_mscs_peer_lookup_n_get_priority_v2(&wlan_get_priority_param); ++} ++ ++/* ++ * ecm_wifi_plugin_update_skb_priority() ++ * Update skb priority callback into wlan driver. ++ */ ++static inline bool ecm_wifi_plugin_update_skb_priority(struct ecm_classifier_mscs_rule_match_info *match_info) ++{ ++ struct qca_scs_peer_lookup_n_rule_match rule_match_param = {0}; ++ ++ rule_match_param.dst_mac_addr = match_info->dst_mac; ++ rule_match_param.rule_id = match_info->rule_id; ++ ++ return qca_scs_peer_lookup_n_rule_match_v2(&rule_match_param); ++} ++ ++/* + * ecm_wifi_plugin + * Register MSCS client callback with ECM MSCS classifier to support MSCS wifi peer lookup. + */ + static struct ecm_classifier_mscs_callbacks ecm_wifi_plugin_mscs = { +- .get_peer_priority = qca_mscs_peer_lookup_n_get_priority, ++ .get_peer_priority = ecm_wifi_plugin_get_peer_priority, + #ifdef ECM_CLASSIFIER_MSCS_SCS_ENABLE +- .update_skb_priority = qca_scs_peer_lookup_n_rule_match, ++ .update_skb_priority = ecm_wifi_plugin_update_skb_priority, + #endif + }; + +--- a/exports/ecm_classifier_emesh_public.h ++++ b/exports/ecm_classifier_emesh_public.h +@@ -80,12 +80,25 @@ struct ecm_classifier_emesh_sawf_flow_in + }; + + /** ++ * Structure collecting mesh latency params to send it to wlan driver ++ * via registered callback. ++ */ ++struct ecm_classifer_emesh_sawf_mesh_latency_params { ++ struct net_device *dst_dev; /**< Destination net dev. */ ++ struct net_device *src_dev; /**< Source net dev. */ ++ uint8_t *peer_mac; /**< Peer MAC. */ ++ uint32_t service_interval_dl; /**< Service interval DL. */ ++ uint32_t burst_size_dl; /**< Burst size DL. */ ++ uint32_t service_interval_ul; /**< Service interval UL. */ ++ uint32_t burst_size_ul; /**< Burst size UL. */ ++ uint16_t priority; /**< Priority. */ ++ uint8_t accel_or_decel; /**< Time of the callback. */ ++}; ++ ++/** + * Mesh latency configuration update callback function to which MSCS client will register. + */ +-typedef int (*ecm_classifier_emesh_callback_t)(uint8_t dest_mac[], +- uint32_t service_interval_dl, uint32_t burst_size_dl, +- uint32_t service_interval_ul, uint32_t burst_size_ul, +- uint16_t priority, uint8_t add_or_sub); ++typedef void (*ecm_classifier_emesh_callback_t)(struct ecm_classifer_emesh_sawf_mesh_latency_params *mesh_params); + + /** + * MSDUQ callback to which emesh-sawf will register. +--- a/exports/ecm_classifier_mscs_public.h ++++ b/exports/ecm_classifier_mscs_public.h +@@ -43,10 +43,32 @@ enum ecm_classifier_mscs_results { + typedef enum /** @cond */ ecm_classifier_mscs_results /** @endcond */ ecm_classifier_mscs_result_t; + + /** ++ * Structure containing params to get MSCS priority. ++ */ ++struct ecm_classifier_mscs_get_priority_info { ++ struct net_device *dst_dev; /**< Destination net dev. */ ++ struct net_device *src_dev; /**< Source net dev. */ ++ uint8_t *src_mac; /**< Source MAC address. */ ++ uint8_t *dst_mac; /**< Destination MAC address. */ ++ struct sk_buff *skb; /**< SKB pointer. */ ++}; ++ ++/** ++ * Structure containing params for SCS rule match info. ++ */ ++struct ecm_classifier_mscs_rule_match_info { ++ struct net_device *dst_dev; /**< Destination net dev. */ ++ struct net_device *src_dev; /**< Source net dev. */ ++ uint8_t *src_mac; /**< Source MAC. */ ++ uint8_t *dst_mac; /**< Destination MAC. */ ++ uint32_t rule_id; /**< Rule ID. */ ++}; ++ ++/** + * Callback to which MSCS clients will register. + */ +-typedef int (*ecm_classifier_mscs_process_callback_t)(uint8_t src_mac[], uint8_t dst_mac[], struct sk_buff* skb); +-typedef bool (*ecm_classifier_mscs_scs_priority_callback_t)(uint32_t rule_id, uint8_t *dst_mac_addr); ++typedef int (*ecm_classifier_mscs_process_callback_t)(struct ecm_classifier_mscs_get_priority_info *priority_info); ++typedef bool (*ecm_classifier_mscs_scs_priority_callback_t)(struct ecm_classifier_mscs_rule_match_info *rule_match_info); + + /** + * Data structure for MSCS classifier callbacks. diff --git a/package/qca-nss/qca-nss-ecm/patches/215-Adding-src-and-dest-dev-in-MSCS-and-SCS-callbacks.patch b/package/qca-nss/qca-nss-ecm/patches/215-Adding-src-and-dest-dev-in-MSCS-and-SCS-callbacks.patch new file mode 100644 index 0000000000..8b0f722fd7 --- /dev/null +++ b/package/qca-nss/qca-nss-ecm/patches/215-Adding-src-and-dest-dev-in-MSCS-and-SCS-callbacks.patch @@ -0,0 +1,84 @@ +From 5a87f3b9acb7a85958ef220a8f83c3cf24bfba4d Mon Sep 17 00:00:00 2001 +From: Parikshit Gune +Date: Wed, 2 Aug 2023 10:28:53 +0530 +Subject: [PATCH] [qca-nss-ecm] Adding src and dest dev in MSCS and SCS + callbacks. + +Change-Id: Ia3a097606efb875fbe459fe4cbdfc851d0fa24ec +Signed-off-by: Parikshit Gune +--- + ecm_classifier_mscs.c | 14 ++++++++++++++ + ecm_wifi_plugins/ecm_wifi_plugin_mscs.c | 4 ++++ + 2 files changed, 18 insertions(+) + +--- a/ecm_classifier_mscs.c ++++ b/ecm_classifier_mscs.c +@@ -421,6 +421,8 @@ static void ecm_classifier_mscs_process( + uint8_t dmac[ETH_ALEN]; + bool mscs_rule_match = false; + bool scs_rule_match = false; ++ struct net_device *src_dev = NULL; ++ struct net_device *dest_dev = NULL; + uint64_t slow_pkts; + #ifdef ECM_CLASSIFIER_MSCS_SCS_ENABLE + struct sp_rule_input_params flow_input_params; +@@ -507,6 +509,8 @@ static void ecm_classifier_mscs_process( + ecm_db_connection_node_address_get(ci, ECM_DB_OBJ_DIR_FROM, dmac); + } + ++ ecm_db_netdevs_get_and_hold(ci, sender, &src_dev, &dest_dev); ++ + /* + * Set the invalid SCS rule id, in case if we do not find any SCS rule. + */ +@@ -549,6 +553,8 @@ static void ecm_classifier_mscs_process( + + rule_match_info.rule_id = flow_output_params.rule_id; + rule_match_info.dst_mac = dmac; ++ rule_match_info.src_dev = src_dev; ++ rule_match_info.dst_dev = dest_dev; + result = scs_cb(&rule_match_info); + } + } +@@ -623,6 +629,8 @@ static void ecm_classifier_mscs_process( + */ + get_priority_info.src_mac = smac; + get_priority_info.dst_mac = dmac; ++ get_priority_info.src_dev = src_dev; ++ get_priority_info.dst_dev = dest_dev; + get_priority_info.skb = skb; + result = cb(&get_priority_info); + +@@ -713,6 +721,12 @@ mscs_classifier_out: + /* + * Return our process response + */ ++ if(src_dev) ++ dev_put(src_dev); ++ ++ if(dest_dev) ++ dev_put(dest_dev); ++ + *process_response = cmscsi->process_response; + spin_unlock_bh(&ecm_classifier_mscs_lock); + } +--- a/ecm_wifi_plugins/ecm_wifi_plugin_mscs.c ++++ b/ecm_wifi_plugins/ecm_wifi_plugin_mscs.c +@@ -35,6 +35,8 @@ static inline int ecm_wifi_plugin_get_pe + + wlan_get_priority_param.dst_mac = get_priority_info->dst_mac; + wlan_get_priority_param.src_mac = get_priority_info->src_mac; ++ wlan_get_priority_param.src_dev = get_priority_info->src_dev; ++ wlan_get_priority_param.dst_dev = get_priority_info->dst_dev; + wlan_get_priority_param.skb = get_priority_info->skb; + + return qca_mscs_peer_lookup_n_get_priority_v2(&wlan_get_priority_param); +@@ -50,6 +52,8 @@ static inline bool ecm_wifi_plugin_updat + + rule_match_param.dst_mac_addr = match_info->dst_mac; + rule_match_param.rule_id = match_info->rule_id; ++ rule_match_param.src_dev = match_info->src_dev; ++ rule_match_param.dst_dev = match_info->dst_dev; + + return qca_scs_peer_lookup_n_rule_match_v2(&rule_match_param); + } diff --git a/package/qca-nss/qca-nss-ecm/patches/220-Fixes-for-kernel-6.6.patch b/package/qca-nss/qca-nss-ecm/patches/220-Fixes-for-kernel-6.6.patch new file mode 100644 index 0000000000..4f5b2a39c0 --- /dev/null +++ b/package/qca-nss/qca-nss-ecm/patches/220-Fixes-for-kernel-6.6.patch @@ -0,0 +1,212 @@ +From 8cfad2eeed8d410f3f9943c535fad002b0b74073 Mon Sep 17 00:00:00 2001 +From: Amitesh Anand +Date: Sat, 23 Dec 2023 23:29:45 +0530 +Subject: [PATCH] [qca-nss-ecm] Fixes for kernel 6.6 + +1) Fix mscs classifier to avoid setting bool values to enum +variables. + +2) Change sysctl registration from register_sysctl_table() to +register_sysctl and avoid deprecated method. + +3) Kernel v6.6 removed dev->miniq_ingress. Use dev->tcx_ingress +field selectively for v6.6. + +Change-Id: I9250a3082811df1917fdfa1fb1e398125871b811 +Signed-off-by: Amitesh Anand +--- + ecm_classifier_mscs.c | 14 +++++++------ + ecm_interface.c | 22 ++------------------ + frontends/ecm_front_end_common.c | 35 ++++++++++++++------------------ + 3 files changed, 25 insertions(+), 46 deletions(-) + +--- a/ecm_classifier_mscs.c ++++ b/ecm_classifier_mscs.c +@@ -1,7 +1,7 @@ + /* + ************************************************************************** + * Copyright (c) 2020-2021 The Linux Foundation. All rights reserved. +- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. ++ * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the +@@ -416,7 +416,7 @@ static void ecm_classifier_mscs_process( + int protocol; + uint32_t became_relevant = 0; + ecm_classifier_mscs_process_callback_t cb = NULL; +- ecm_classifier_mscs_result_t result = 0; ++ bool scs_result = false; + uint8_t smac[ETH_ALEN]; + uint8_t dmac[ETH_ALEN]; + bool mscs_rule_match = false; +@@ -538,7 +538,8 @@ static void ecm_classifier_mscs_process( + /* + * Set result true for Multi AP mode. + */ +- result = true; ++ scs_result = true; ++ + /* + * Invoke the WiFi datapath callback registered with MSCS client to check + * if SCS priority is valid for WiFi peer corresponding to +@@ -555,7 +556,7 @@ static void ecm_classifier_mscs_process( + rule_match_info.dst_mac = dmac; + rule_match_info.src_dev = src_dev; + rule_match_info.dst_dev = dest_dev; +- result = scs_cb(&rule_match_info); ++ scs_result = scs_cb(&rule_match_info); + } + } + +@@ -563,7 +564,7 @@ static void ecm_classifier_mscs_process( + * Check the result of the callback. If we have a valid priority and peer is SCS + * capable, we set the priority (we do not check MSCS as SCS have higher precedence). + */ +- if (result) { ++ if (scs_result) { + /* + * Update skb priority. + */ +@@ -606,13 +607,14 @@ static void ecm_classifier_mscs_process( + * Check MSCS classifer. + */ + if (ecm_classifier_mscs_enabled) { +- result = false; + /* + * Check if MSCS multi AP mode is enabled or not - + * If yes, we need to query SPM database for rule match. + * Else legacy MSCS should work for single AP mode. + */ + if (!ecm_classifier_mscs_scs_multi_ap_enabled) { ++ ecm_classifier_mscs_result_t result; ++ + /* + * Get the WiFi datapath callback registered with MSCS client to check + * if MSCS QoS tag is valid for WiFi peer corresponding to +--- a/ecm_interface.c ++++ b/ecm_interface.c +@@ -1,7 +1,7 @@ + /* + ************************************************************************** + * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved. +- * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. ++ * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the +@@ -8306,24 +8306,6 @@ static struct ctl_table ecm_interface_ta + { } + }; + +-static struct ctl_table ecm_interface_root_dir[] = { +- { +- .procname = "ecm", +- .mode = 0555, +- .child = ecm_interface_table, +- }, +- { } +-}; +- +-static struct ctl_table ecm_interface_root[] = { +- { +- .procname = "net", +- .mode = 0555, +- .child = ecm_interface_root_dir, +- }, +- { } +-}; +- + #ifdef ECM_INTERFACE_IPSEC_GLUE_LAYER_SUPPORT_ENABLE + /* + * ecm_interface_ipsec_register_callbacks() +@@ -8820,7 +8802,7 @@ int ecm_interface_init(void) + /* + * Register sysctl table. + */ +- ecm_interface_ctl_table_header = register_sysctl_table(ecm_interface_root); ++ ecm_interface_ctl_table_header = register_sysctl("net/ecm", ecm_interface_table); + + result = register_netdevice_notifier(&ecm_interface_netdev_notifier); + if (result != 0) { +--- a/frontends/ecm_front_end_common.c ++++ b/frontends/ecm_front_end_common.c +@@ -1,7 +1,7 @@ + /* + ************************************************************************** + * Copyright (c) 2015, 2016, 2020-2021, The Linux Foundation. All rights reserved. +- * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. ++ * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the +@@ -35,6 +35,9 @@ + #include + #include + #include ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 6, 0)) ++#include ++#endif + #include + #include + #ifdef ECM_FRONT_END_PPE_ENABLE +@@ -1157,24 +1160,6 @@ static struct ctl_table ecm_front_end_sy + {} + }; + +-static struct ctl_table ecm_front_end_common_root[] = { +- { +- .procname = "ecm", +- .mode = 0555, +- .child = ecm_front_end_sysctl_tbl, +- }, +- { } +-}; +- +-static struct ctl_table ecm_front_end_common_root_dir[] = { +- { +- .procname = "net", +- .mode = 0555, +- .child = ecm_front_end_common_root, +- }, +- { } +-}; +- + /* + * ecm_front_end_common_sysctl_register() + * Function to register sysctl node during front end init +@@ -1184,7 +1169,7 @@ void ecm_front_end_common_sysctl_registe + /* + * Register sysctl table. + */ +- ecm_front_end_ctl_tbl_hdr = register_sysctl_table(ecm_front_end_common_root_dir); ++ ecm_front_end_ctl_tbl_hdr = register_sysctl("net/ecm", ecm_front_end_sysctl_tbl); + #ifdef ECM_FRONT_END_SFE_ENABLE + if (ecm_front_end_ctl_tbl_hdr) { + ecm_sfe_sysctl_tbl_init(); +@@ -1704,7 +1689,12 @@ bool ecm_front_end_common_intf_ingress_q + } + + BUG_ON(!rcu_read_lock_bh_held()); ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0)) + miniq = rcu_dereference_bh(dev->miniq_ingress); ++#else ++ struct bpf_mprog_entry *entry = rcu_dereference_bh(dev->tcx_ingress); ++ miniq = entry ? tcx_entry(entry)->miniq : NULL; ++#endif + if (miniq) { + DEBUG_INFO("Ingress Qdisc is present for device[%s]\n", dev->name); + dev_put(dev); +@@ -1759,7 +1749,12 @@ bool ecm_front_end_common_intf_qdisc_che + } + + #if defined(CONFIG_NET_CLS_ACT) && defined(CONFIG_NET_EGRESS) ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0)) + miniq = rcu_dereference_bh(dev->miniq_egress); ++#else ++ struct bpf_mprog_entry *entry = rcu_dereference_bh(dev->tcx_egress); ++ miniq = entry ? tcx_entry(entry)->miniq : NULL; ++#endif + if (miniq) { + DEBUG_INFO("Egress needed\n"); + dev_put(dev); diff --git a/package/qca-nss/qca-nss-gmac/Makefile b/package/qca-nss/qca-nss-gmac/Makefile new file mode 100644 index 0000000000..29526c07b2 --- /dev/null +++ b/package/qca-nss/qca-nss-gmac/Makefile @@ -0,0 +1,51 @@ +# NHSS.QSDK.12.1.r5_CS1 +# by SqTER + +include $(TOPDIR)/rules.mk +include $(INCLUDE_DIR)/kernel.mk + +PKG_NAME:=qca-nss-gmac +PKG_RELEASE:=1 + +PKG_SOURCE_URL:=https://git.codelinaro.org/clo/qsdk/oss/lklm/nss-gmac.git +PKG_SOURCE_PROTO:=git +PKG_SOURCE_DATE:=2023-06-01 +PKG_SOURCE_VERSION:=171767947467662f2407d0cfff26dfb136c3fb4a +PKG_MIRROR_HASH:=3c59139b20bc607f71e8a20e14ea63e6520b2f321347cfa7b3532c15120c9947 + +include $(INCLUDE_DIR)/package.mk + +define KernelPackage/qca-nss-gmac + SECTION:=kernel + CATEGORY:=Kernel modules + SUBMENU:=Network Devices + DEPENDS:=@TARGET_ipq806x||TARGET_ipq_ipq806x + TITLE:=Kernel driver for NSS gmac + FILES:=$(PKG_BUILD_DIR)/ipq806x/qca-nss-gmac.ko + AUTOLOAD:=$(call AutoLoad,31,qca-nss-gmac,1) +endef + +define KernelPackage/qca-nss-gmac/Description +This package contains a NSS driver for QCA chipset +endef + +define Build/InstallDev + mkdir -p $(1)/usr/include/qca-nss-gmac + $(CP) $(PKG_BUILD_DIR)/ipq806x/exports/* $(1)/usr/include/qca-nss-gmac/ +endef + +EXTRA_CFLAGS+= \ + -DCONFIG_NSS_DEBUG_LEVEL=0 \ + -I$(PKG_BUILD_DIR)/nss_hal/include \ + -I$(PKG_BUILD_DIR)/nss_hal/$(BOARD) + +define Build/Compile + $(MAKE) $(PKG_JOBS) -C "$(LINUX_DIR)" \ + $(KERNEL_MAKE_FLAGS) \ + $(PKG_MAKE_FLAGS) \ + M="$(PKG_BUILD_DIR)" \ + EXTRA_CFLAGS="$(EXTRA_CFLAGS)" \ + modules +endef + +$(eval $(call KernelPackage,qca-nss-gmac)) diff --git a/package/qca-nss/qca-nss-gmac/patches/00-irq_of_parse_and_map-retcode.patch b/package/qca-nss/qca-nss-gmac/patches/00-irq_of_parse_and_map-retcode.patch new file mode 100644 index 0000000000..0e8738490c --- /dev/null +++ b/package/qca-nss/qca-nss-gmac/patches/00-irq_of_parse_and_map-retcode.patch @@ -0,0 +1,11 @@ +--- a/ipq806x/nss_gmac_ctrl.c ++++ b/ipq806x/nss_gmac_ctrl.c +@@ -1024,7 +1024,7 @@ static int32_t nss_gmac_of_get_pdata(str + + gmaccfg->phy_mii_type = of_get_phy_mode(np); + netdev->irq = irq_of_parse_and_map(np, 0); +- if (netdev->irq == NO_IRQ) { ++ if (netdev->irq <= 0) { + pr_err("%s: Can't map interrupt\n", np->name); + return -EFAULT; + } diff --git a/package/qca-nss/qca-nss-gmac/patches/01-kernel-5.4-support.patch b/package/qca-nss/qca-nss-gmac/patches/01-kernel-5.4-support.patch new file mode 100644 index 0000000000..89ea66674b --- /dev/null +++ b/package/qca-nss/qca-nss-gmac/patches/01-kernel-5.4-support.patch @@ -0,0 +1,345 @@ +--- a/ipq806x/nss_gmac_ctrl.c ++++ b/ipq806x/nss_gmac_ctrl.c +@@ -322,16 +322,15 @@ void nss_gmac_tx_rx_desc_init(struct nss + * (for example "ifconfig eth0"). + * @param[in] pointer to net_device structure. + * @param[in] pointer to net_device_stats64 structure. +- * @return Returns pointer to net_device_stats64 structure. + */ +-struct rtnl_link_stats64 *nss_gmac_get_stats64(struct net_device *netdev, ++void nss_gmac_get_stats64(struct net_device *netdev, + struct rtnl_link_stats64 *stats) + { + struct nss_gmac_dev *gmacdev = (struct nss_gmac_dev *)netdev_priv(netdev); + BUG_ON(gmacdev == NULL); + + if (!gmacdev->data_plane_ops) +- return stats; ++ return; + + spin_lock_bh(&gmacdev->stats_lock); + gmacdev->data_plane_ops->get_stats(gmacdev->data_plane_ctx, &gmacdev->nss_stats); +@@ -354,8 +353,6 @@ struct rtnl_link_stats64 *nss_gmac_get_s + stats->tx_fifo_errors = gmacdev->nss_stats.tx_underflow_errors; + stats->tx_window_errors = gmacdev->nss_stats.tx_late_collision_errors; + spin_unlock_bh(&gmacdev->stats_lock); +- +- return stats; + } + + +@@ -439,7 +436,7 @@ static int nss_gmac_mtnp_show(struct dev + static int nss_gmac_tstamp_show(struct device *dev, struct device_attribute *attr, char *buf) + { + struct nss_gmac_dev *gmacdev = (struct nss_gmac_dev *)netdev_priv(to_net_dev(dev)); +- struct timeval tv; ++ struct timespec64 ts64; + uint32_t ret, timeout; + uint32_t ts_hi, ts_lo; + +@@ -459,11 +456,12 @@ static int nss_gmac_tstamp_show(struct d + return -1; + } + +- do_gettimeofday(&tv); ++ ktime_get_real_ts64(&ts64); + + ret = snprintf( + buf, PAGE_SIZE, +- "sec:%u nsec:%u time-of-day: %12d.%06d \n", ts_hi, ts_lo, (int)tv.tv_sec, (int)tv.tv_usec); ++ "sec:%u nsec:%u time-of-day: %12d.%06d \n", \ ++ ts_hi, ts_lo, (int)ts64.tv_sec, (int)(ts64.tv_nsec / NSEC_PER_USEC)); + + return ret; + } +@@ -761,6 +759,7 @@ static uint32_t nss_gmac_tstamp_ioctl(st + { + struct hwtstamp_config cfg; + struct nss_gmac_dev *gmacdev = (struct nss_gmac_dev *)netdev_priv(netdev); ++ int ret = -EINVAL; + + /* + * Return if NSS FW is not up +@@ -769,9 +768,11 @@ static uint32_t nss_gmac_tstamp_ioctl(st + netdev_dbg(netdev, "%s: NSS Firmware is not up. Cannot enable Timestamping \n", __func__); + return -EINVAL; + } +- +- copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)); +- ++ ret = copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)); ++ if (ret) { ++ netdev_err(netdev, "%s: Unable to copy NSS Firmware into memory \n", __func__); ++ return -EINVAL; ++ } + /* + * Enable Timestamping if not already enabled + */ +@@ -951,7 +952,7 @@ static const struct net_device_ops nss_g + * @param[in] pointer to advertised features + * @return void + */ +-static void nss_gmac_update_features(uint32_t *supp, uint32_t *adv) ++static void nss_gmac_update_features(long unsigned int *supp, long unsigned int *adv) + { + *supp |= NSS_GMAC_SUPPORTED_FEATURES; + *adv |= NSS_GMAC_ADVERTISED_FEATURES; +@@ -1100,7 +1101,7 @@ static int32_t nss_gmac_do_common_init(s + ctx.msm_clk_ctl_enabled = true; + #endif + +- ctx.nss_base = (uint8_t *)ioremap_nocache(res_nss_base.start, ++ ctx.nss_base = (uint8_t *)ioremap(res_nss_base.start, + resource_size(&res_nss_base)); + if (!ctx.nss_base) { + pr_info("Error mapping NSS GMAC registers\n"); +@@ -1109,7 +1110,7 @@ static int32_t nss_gmac_do_common_init(s + } + pr_debug("%s: NSS base ioremap OK.\n", __func__); + +- ctx.qsgmii_base = (uint32_t *)ioremap_nocache(res_qsgmii_base.start, ++ ctx.qsgmii_base = (uint32_t *)ioremap(res_qsgmii_base.start, + resource_size(&res_qsgmii_base)); + if (!ctx.qsgmii_base) { + pr_info("Error mapping QSGMII registers\n"); +@@ -1119,7 +1120,7 @@ static int32_t nss_gmac_do_common_init(s + pr_debug("%s: QSGMII base ioremap OK, vaddr = 0x%p\n", + __func__, ctx.qsgmii_base); + +- ctx.clk_ctl_base = (uint32_t *)ioremap_nocache(res_clk_ctl_base.start, ++ ctx.clk_ctl_base = (uint32_t *)ioremap(res_clk_ctl_base.start, + resource_size(&res_clk_ctl_base)); + if (!ctx.clk_ctl_base) { + pr_info("Error mapping Clk control registers\n"); +@@ -1409,8 +1410,8 @@ static int32_t nss_gmac_probe(struct pla + goto nss_gmac_phy_attach_fail; + } + +- nss_gmac_update_features(&(gmacdev->phydev->supported), +- &(gmacdev->phydev->advertising)); ++ nss_gmac_update_features(gmacdev->phydev->supported, ++ gmacdev->phydev->advertising); + gmacdev->phydev->irq = PHY_POLL; + netdev_dbg(netdev, "PHY %s attach OK\n", phy_id); + +@@ -1440,6 +1441,8 @@ static int32_t nss_gmac_probe(struct pla + netdev_dbg(netdev, "%s MII_PHYSID2 - 0x%04x\n", netdev->name, + nss_gmac_mii_rd_reg(gmacdev, gmacdev->phy_base, MII_PHYSID2)); + } else if (gmacdev->phy_base != NSS_GMAC_NO_MDIO_PHY) { ++ SET_NETDEV_DEV(netdev, gmacdev->miibus->parent); ++ + /* + * Issue a phy_attach for the interface connected to a switch + */ +--- a/ipq806x/nss_gmac_ethtool.c ++++ b/ipq806x/nss_gmac_ethtool.c +@@ -143,7 +143,8 @@ static const struct nss_gmac_ethtool_sta + /** + * @brief Array of strings describing private flag names + */ +-static const char *gmac_strings_priv_flags[] = { ++ ++static const char gmac_strings_priv_flags[][ETH_GSTRING_LEN] = { + "linkpoll", + "tstamp", + "ignore_rx_csum_err", +@@ -290,6 +291,7 @@ static int nss_gmac_set_pauseparam(struc + { + struct nss_gmac_dev *gmacdev = (struct nss_gmac_dev *)netdev_priv(netdev); + struct phy_device *phydev; ++ long unsigned int *advertising; + + BUG_ON(gmacdev == NULL); + BUG_ON(gmacdev->netdev != netdev); +@@ -325,14 +327,15 @@ static int nss_gmac_set_pauseparam(struc + phydev = gmacdev->phydev; + + /* Update flow control advertisment */ +- phydev->advertising &= ~(ADVERTISED_Pause | ADVERTISED_Asym_Pause); ++ advertising = phydev->advertising; ++ *advertising &= ~(ADVERTISED_Pause | ADVERTISED_Asym_Pause); + + if (gmacdev->pause & FLOW_CTRL_RX) +- phydev->advertising |= ++ *advertising |= + (ADVERTISED_Pause | ADVERTISED_Asym_Pause); + + if (gmacdev->pause & FLOW_CTRL_TX) +- phydev->advertising |= ADVERTISED_Asym_Pause; ++ *advertising |= ADVERTISED_Asym_Pause; + + genphy_config_aneg(gmacdev->phydev); + +@@ -392,12 +395,13 @@ static uint32_t nss_gmac_get_msglevel(st + * @param[in] pointer to struct net_device. + * @param[in] pointer to struct ethtool_cmd. + */ +-static int32_t nss_gmac_get_settings(struct net_device *netdev, +- struct ethtool_cmd *ecmd) ++static int nss_gmac_get_settings(struct net_device *netdev, ++ struct ethtool_link_ksettings *elk) + { + struct nss_gmac_dev *gmacdev = (struct nss_gmac_dev *)netdev_priv(netdev); + struct phy_device *phydev = NULL; + uint16_t phyreg; ++ u32 lp_advertising = 0; + + BUG_ON(gmacdev == NULL); + +@@ -409,10 +413,10 @@ static int32_t nss_gmac_get_settings(str + */ + if (!test_bit(__NSS_GMAC_LINKPOLL, &gmacdev->flags)) { + if (gmacdev->forced_speed != SPEED_UNKNOWN) { +- ethtool_cmd_speed_set(ecmd, gmacdev->forced_speed); +- ecmd->duplex = gmacdev->forced_duplex; +- ecmd->mdio_support = 0; +- ecmd->lp_advertising = 0; ++ elk->base.speed = gmacdev->forced_speed; ++ elk->base.duplex = gmacdev->forced_duplex; ++ elk->base.mdio_support = 0; ++ ethtool_convert_legacy_u32_to_link_mode(elk->link_modes.lp_advertising, 0); + return 0; + } else { + /* Non-link polled interfaced must have a forced +@@ -426,56 +430,59 @@ static int32_t nss_gmac_get_settings(str + + /* update PHY status */ + if (phydev->is_c45 == true) { +- ecmd->mdio_support = ETH_MDIO_SUPPORTS_C45; ++ elk->base.mdio_support = ETH_MDIO_SUPPORTS_C45; + } else { + if (genphy_read_status(phydev) != 0) { + return -EIO; + } +- ecmd->mdio_support = ETH_MDIO_SUPPORTS_C22; ++ elk->base.mdio_support = ETH_MDIO_SUPPORTS_C22; + } + + /* Populate capabilities advertised by self */ +- ecmd->advertising = phydev->advertising; ++ bitmap_copy(elk->link_modes.advertising, phydev->advertising, __ETHTOOL_LINK_MODE_MASK_NBITS); + +- ecmd->autoneg = phydev->autoneg; +- ethtool_cmd_speed_set(ecmd, phydev->speed); +- ecmd->duplex = phydev->duplex; +- ecmd->port = PORT_TP; +- ecmd->phy_address = gmacdev->phy_base; +- ecmd->transceiver = XCVR_EXTERNAL; ++ elk->base.autoneg = phydev->autoneg; ++ elk->base.speed = phydev->speed; ++ elk->base.duplex = phydev->duplex; ++ elk->base.port = PORT_TP; ++ elk->base.phy_address = gmacdev->phy_base; ++ elk->base.transceiver = XCVR_EXTERNAL; + + /* Populate supported capabilities */ +- ecmd->supported = phydev->supported; ++ bitmap_copy(elk->link_modes.supported, phydev->supported, __ETHTOOL_LINK_MODE_MASK_NBITS); + + if (phydev->is_c45 == true) + return 0; + + /* Populate capabilities advertised by link partner */ ++ ethtool_convert_link_mode_to_legacy_u32(&lp_advertising, elk->link_modes.lp_advertising); + phyreg = nss_gmac_mii_rd_reg(gmacdev, gmacdev->phy_base, MII_LPA); + if (phyreg & LPA_10HALF) +- ecmd->lp_advertising |= ADVERTISED_10baseT_Half; ++ lp_advertising |= ADVERTISED_10baseT_Half; + + if (phyreg & LPA_10FULL) +- ecmd->lp_advertising |= ADVERTISED_10baseT_Full; ++ lp_advertising |= ADVERTISED_10baseT_Full; + + if (phyreg & LPA_100HALF) +- ecmd->lp_advertising |= ADVERTISED_100baseT_Half; ++ lp_advertising |= ADVERTISED_100baseT_Half; + + if (phyreg & LPA_100FULL) +- ecmd->lp_advertising |= ADVERTISED_100baseT_Full; ++ lp_advertising |= ADVERTISED_100baseT_Full; + + if (phyreg & LPA_PAUSE_CAP) +- ecmd->lp_advertising |= ADVERTISED_Pause; ++ lp_advertising |= ADVERTISED_Pause; + + if (phyreg & LPA_PAUSE_ASYM) +- ecmd->lp_advertising |= ADVERTISED_Asym_Pause; ++ lp_advertising |= ADVERTISED_Asym_Pause; + + phyreg = nss_gmac_mii_rd_reg(gmacdev, gmacdev->phy_base, MII_STAT1000); + if (phyreg & LPA_1000HALF) +- ecmd->lp_advertising |= ADVERTISED_1000baseT_Half; ++ lp_advertising |= ADVERTISED_1000baseT_Half; + + if (phyreg & LPA_1000FULL) +- ecmd->lp_advertising |= ADVERTISED_1000baseT_Full; ++ lp_advertising |= ADVERTISED_1000baseT_Full; ++ ++ ethtool_convert_legacy_u32_to_link_mode(elk->link_modes.lp_advertising, lp_advertising); + + return 0; + } +@@ -485,8 +492,8 @@ static int32_t nss_gmac_get_settings(str + * @param[in] pointer to struct net_device. + * @param[in] pointer to struct ethtool_cmd. + */ +-static int32_t nss_gmac_set_settings(struct net_device *netdev, +- struct ethtool_cmd *ecmd) ++static int nss_gmac_set_settings(struct net_device *netdev, ++ const struct ethtool_link_ksettings *elk) + { + struct nss_gmac_dev *gmacdev = (struct nss_gmac_dev *)netdev_priv(netdev); + struct phy_device *phydev = NULL; +@@ -508,13 +515,13 @@ static int32_t nss_gmac_set_settings(str + return -EPERM; + } + +- if (ecmd->autoneg == AUTONEG_ENABLE) { ++ if (elk->base.autoneg == AUTONEG_ENABLE) { + set_bit(__NSS_GMAC_AUTONEG, &gmacdev->flags); + } else { + clear_bit(__NSS_GMAC_AUTONEG, &gmacdev->flags); + } + +- return phy_ethtool_sset(phydev, ecmd); ++ return phy_ethtool_ksettings_set(phydev, elk); + } + + /** +@@ -592,8 +599,8 @@ struct ethtool_ops nss_gmac_ethtool_ops + .set_pauseparam = &nss_gmac_set_pauseparam, + .nway_reset = &nss_gmac_nway_reset, + .get_wol = &nss_gmac_get_wol, +- .get_settings = &nss_gmac_get_settings, +- .set_settings = &nss_gmac_set_settings, ++ .get_link_ksettings = &nss_gmac_get_settings, ++ .set_link_ksettings = &nss_gmac_set_settings, + .get_strings = &nss_gmac_get_strings, + .get_sset_count = &nss_gmac_get_strset_count, + .get_ethtool_stats = &nss_gmac_get_ethtool_stats, +--- a/ipq806x/nss_gmac_dev.c ++++ b/ipq806x/nss_gmac_dev.c +@@ -1585,7 +1585,7 @@ int32_t nss_gmac_attach(struct nss_gmac_ + } + + /* ioremap addresses */ +- gmacdev->mac_base = ioremap_nocache(reg_base, ++ gmacdev->mac_base = ioremap(reg_base, + NSS_GMAC_REG_BLOCK_LEN); + if (!gmacdev->mac_base) { + netdev_dbg(netdev, "ioremap fail.\n"); +--- a/ipq806x/nss_gmac_tx_rx_offload.c ++++ b/ipq806x/nss_gmac_tx_rx_offload.c +@@ -1027,8 +1027,10 @@ int nss_gmac_close(struct net_device *ne + nss_gmac_disable_interrupt_all(gmacdev); + gmacdev->data_plane_ops->link_state(gmacdev->data_plane_ctx, 0); + +- if (!IS_ERR(gmacdev->phydev)) +- phy_stop(gmacdev->phydev); ++ if (!IS_ERR(gmacdev->phydev)) { ++ if (test_bit(__NSS_GMAC_LINKPOLL, &gmacdev->flags)) ++ phy_stop(gmacdev->phydev); ++ } + + clear_bit(__NSS_GMAC_UP, &gmacdev->flags); + clear_bit(__NSS_GMAC_CLOSING, &gmacdev->flags); diff --git a/package/qca-nss/qca-nss-gmac/patches/02-kernel-5.15-support.patch b/package/qca-nss/qca-nss-gmac/patches/02-kernel-5.15-support.patch new file mode 100644 index 0000000000..53ec2483de --- /dev/null +++ b/package/qca-nss/qca-nss-gmac/patches/02-kernel-5.15-support.patch @@ -0,0 +1,95 @@ +--- a/ipq806x/include/msm_nss_gmac.h ++++ b/ipq806x/include/msm_nss_gmac.h +@@ -317,7 +317,7 @@ struct msm_nss_gmac_platform_data { + uint32_t phy_mdio_addr; /* MDIO address of the connected PHY */ + uint32_t poll_required; /* [0/1] Link status poll? */ + uint32_t rgmii_delay; +- uint32_t phy_mii_type; ++ phy_interface_t phy_mii_type; + uint8_t mac_addr[6]; + int32_t forced_speed; /* Forced speed. Values used from + ethtool.h. 0 = Speed not forced */ +--- a/ipq806x/include/nss_gmac_dev.h ++++ b/ipq806x/include/nss_gmac_dev.h +@@ -234,7 +234,7 @@ struct nss_gmac_dev { + uint32_t duplex_mode; /* Duplex mode of the Phy */ + uint32_t speed; /* Speed of the Phy */ + uint32_t loop_back_mode;/* Loopback status of the Phy */ +- uint32_t phy_mii_type; /* RGMII/SGMII/QSGMII */ ++ phy_interface_t phy_mii_type; /* RGMII/SGMII/QSGMII */ + uint32_t rgmii_delay; /* RGMII delay settings */ + uint32_t pause; /* Current flow control settings */ + uint32_t first_linkup_done; /* when set, it indicates that first +--- a/ipq806x/include/nss_gmac_network_interface.h ++++ b/ipq806x/include/nss_gmac_network_interface.h +@@ -41,7 +41,7 @@ int32_t nss_gmac_xmit_frames(struct sk_b + int32_t nss_gmac_close(struct net_device *netdev); + int32_t nss_gmac_open(struct net_device *netdev); + int32_t nss_gmac_change_mtu(struct net_device *netdev, int32_t newmtu); +-void nss_gmac_tx_timeout(struct net_device *netdev); ++void nss_gmac_tx_timeout(struct net_device *netdev, unsigned int txqueue); + + /* NSS driver interface APIs */ + void nss_gmac_receive(struct net_device *netdev, struct sk_buff *skb, +--- a/ipq806x/nss_gmac_ctrl.c ++++ b/ipq806x/nss_gmac_ctrl.c +@@ -995,7 +995,6 @@ static int32_t nss_gmac_of_get_pdata(str + struct net_device *netdev, + struct msm_nss_gmac_platform_data *gmaccfg) + { +- uint8_t *maddr = NULL; + struct nss_gmac_dev *gmacdev = (struct nss_gmac_dev *)netdev_priv(netdev); + struct resource memres_devtree = {0}; + +@@ -1023,15 +1022,14 @@ static int32_t nss_gmac_of_get_pdata(str + + of_property_read_u32(np, "qcom,aux-clk-freq", &gmacdev->aux_clk_freq); + +- gmaccfg->phy_mii_type = of_get_phy_mode(np); ++ of_get_phy_mode(np, &gmaccfg->phy_mii_type); + netdev->irq = irq_of_parse_and_map(np, 0); + if (netdev->irq <= 0) { + pr_err("%s: Can't map interrupt\n", np->name); + return -EFAULT; + } +- maddr = (uint8_t *)of_get_mac_address(np); +- if (maddr) +- memcpy(gmaccfg->mac_addr, maddr, ETH_ALEN); ++ ++ of_get_mac_address(np, gmaccfg->mac_addr); + + if (of_address_to_resource(np, 0, &memres_devtree) != 0) + return -EFAULT; +--- a/ipq806x/nss_gmac_dev.c ++++ b/ipq806x/nss_gmac_dev.c +@@ -1526,7 +1526,7 @@ void nss_gmac_set_mac_addr(struct nss_gm + { + uint32_t data; + +- netdev_dbg(gmacdev->netdev, "Set addr %02x:%02x:%02x:%02x:%02x:%02x\n", ++ netdev_info(gmacdev->netdev, "Set addr %02x:%02x:%02x:%02x:%02x:%02x\n", + mac_addr[0], mac_addr[1], mac_addr[2], + mac_addr[3], mac_addr[4], mac_addr[5]); + +--- a/ipq806x/nss_gmac_init.c ++++ b/ipq806x/nss_gmac_init.c +@@ -940,6 +940,8 @@ void nss_gmac_dev_init(struct nss_gmac_d + case PHY_INTERFACE_MODE_QSGMII: + div = clk_div_qsgmii(gmacdev); + break; ++ default: ++ netdev_err(gmacdev->netdev, "NO interface defined!\n"); + } + val = nss_gmac_read_reg(nss_base, NSS_ETH_CLK_DIV0); + val &= ~GMACn_CLK_DIV(id, GMACn_CLK_DIV_SIZE); +--- a/ipq806x/nss_gmac_tx_rx_offload.c ++++ b/ipq806x/nss_gmac_tx_rx_offload.c +@@ -1046,7 +1046,7 @@ int nss_gmac_close(struct net_device *ne + * @param[in] pointer to net_device structure + * @return void. + */ +-void nss_gmac_tx_timeout(struct net_device *netdev) ++void nss_gmac_tx_timeout(struct net_device *netdev, unsigned int txqueue) + { + struct nss_gmac_dev *gmacdev = (struct nss_gmac_dev *)netdev_priv(netdev); + BUG_ON(gmacdev == NULL); diff --git a/package/qca-nss/qca-nss-gmac/patches/03-add-tstamp-enable-func-ethtool.patch b/package/qca-nss/qca-nss-gmac/patches/03-add-tstamp-enable-func-ethtool.patch new file mode 100644 index 0000000000..b06f95874e --- /dev/null +++ b/package/qca-nss/qca-nss-gmac/patches/03-add-tstamp-enable-func-ethtool.patch @@ -0,0 +1,109 @@ +From 39e953886e9a4c66bd70315ae6c27699b0af31d4 Mon Sep 17 00:00:00 2001 +From: Qosmio +Date: Sat, 10 Sep 2022 01:53:36 -0400 +Subject: [PATCH] nss-gmac: add timestamping feature and extra logging +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +requires an entry in dts: + +example: + +qcom,tstamp-enabled; + +use ethtool to enable: +root@R7800 ~ +➤ ethtool --set-priv-flags eth1 tstamp on +[Sat Sep 10 01:24:22 2022] ipq8064-mdio 37000000.mdio eth0: nss_gmac_ts_enable: Timestamp enabled +[Sat Sep 10 01:24:22 2022] ipq8064-mdio 37000000.mdio eth0: nss_gmac_set_priv_flags: Enabled 'Timestamp' flag (needed_headroom: 32) + +root@R7800 ~ +➤ cat /sys/devices/platform/soc/37000000.mdio/net/eth*/tstamp +sec:1084 nsec:752452290 time-of-day: 1662789199.391664 +sec:1087 nsec:309864290 time-of-day: 1662789199.391799 + +--- a/ipq806x/include/nss_gmac_dev.h ++++ b/ipq806x/include/nss_gmac_dev.h +@@ -1342,6 +1342,9 @@ void nss_gmac_disable_rx_chksum_offload( + void nss_gmac_rx_tcpip_chksum_drop_enable(struct nss_gmac_dev *gmacdev); + void nss_gmac_rx_tcpip_chksum_drop_disable(struct nss_gmac_dev *gmacdev); + ++void nss_gmac_tstamp_sysfs_create(struct net_device *dev); ++void nss_gmac_tstamp_sysfs_remove(struct net_device *dev); ++ + /** + * The check summ offload engine is enabled to do complete checksum computation. + * Hardware computes the tcp ip checksum including the pseudo header checksum. +--- a/ipq806x/nss_gmac_ctrl.c ++++ b/ipq806x/nss_gmac_ctrl.c +@@ -651,7 +651,7 @@ static DEVICE_ATTR(fadj, 0220, NULL, nss + static DEVICE_ATTR(mtnp, 0444, nss_gmac_mtnp_show, NULL); + static DEVICE_ATTR(tstamp, 0444, nss_gmac_tstamp_show, NULL); + +-static void nss_gmac_tstamp_sysfs_create(struct net_device *dev) ++void nss_gmac_tstamp_sysfs_create(struct net_device *dev) + { + if (device_create_file(&(dev->dev), &dev_attr_slam) || + device_create_file(&(dev->dev), &dev_attr_cadj) || +@@ -662,7 +662,7 @@ static void nss_gmac_tstamp_sysfs_create + return; + } + +-static void nss_gmac_tstamp_sysfs_remove(struct net_device *dev) ++void nss_gmac_tstamp_sysfs_remove(struct net_device *dev) + { + device_remove_file(&(dev->dev), &dev_attr_slam); + device_remove_file(&(dev->dev), &dev_attr_cadj); +--- a/ipq806x/nss_gmac_ethtool.c ++++ b/ipq806x/nss_gmac_ethtool.c +@@ -559,6 +559,49 @@ static int32_t nss_gmac_set_priv_flags(s + } + + /* ++ * Set timestamp ++ */ ++ if (changed & NSS_GMAC_PRIV_FLAG(TSTAMP)) { ++ if (flags & NSS_GMAC_PRIV_FLAG(TSTAMP)) { ++ if (!test_bit(__NSS_GMAC_TSTAMP, &gmacdev->flags)) { ++ /* ++ * Increase headroom for PTP/NTP timestamps ++ */ ++ netdev->needed_headroom += 32; ++ ++ /* ++ * Create sysfs entries for timestamp registers ++ */ ++ nss_gmac_tstamp_sysfs_create(netdev); ++ ++ if (nss_gmac_ts_enable(gmacdev)) { ++ netdev_info(netdev, "%s: Reg write error. Cannot enable Timestamping \n", __func__); ++ return -EINVAL; ++ } ++ ++ gmacdev->drv_flags |= NSS_GMAC_PRIV_FLAG(TSTAMP); ++ netdev_info(netdev, "%s: Enabled 'Timestamp' flag (needed_headroom: %dx)", __func__, netdev->needed_headroom); ++ } else { ++ netdev_warn(netdev, "%s: Already enabled 'Timestamp' flag", __func__); ++ } ++ } else { ++ /* ++ * Disable Timestamping if not already disabled ++ */ ++ if (!test_bit(__NSS_GMAC_TSTAMP, &gmacdev->flags)) { ++ netdev_warn(netdev, "%s: Timestamp is already disabled \n", __func__); ++ return -EINVAL; ++ } ++ ++ nss_gmac_ts_disable(gmacdev); ++ gmacdev->drv_flags &= ~NSS_GMAC_PRIV_FLAG(TSTAMP); ++ nss_gmac_tstamp_sysfs_remove(gmacdev->netdev); ++ // netdev->needed_headroom -= 32; ++ netdev_info(netdev, "%s: Disabled 'Timestamp' flag (needed_headroom: %dx)", __func__, netdev->needed_headroom); ++ } ++ } ++ ++ /* + * Set ignore rx csum flag + */ + if (changed & NSS_GMAC_PRIV_FLAG(IGNORE_RX_CSUM_ERR)) { diff --git a/package/qca-nss/qca-nss-gmac/patches/04-fix-poll-enabled.patch b/package/qca-nss/qca-nss-gmac/patches/04-fix-poll-enabled.patch new file mode 100644 index 0000000000..352ce52f4a --- /dev/null +++ b/package/qca-nss/qca-nss-gmac/patches/04-fix-poll-enabled.patch @@ -0,0 +1,32 @@ +--- a/ipq806x/nss_gmac_ctrl.c ++++ b/ipq806x/nss_gmac_ctrl.c +@@ -1390,6 +1390,9 @@ static int32_t nss_gmac_probe(struct pla + } + } + ++ /* workaround for tplink,onhub eth0 phy_attach_direct panic with poll enabled */ ++ SET_NETDEV_DEV(netdev, gmacdev->miibus->parent); /* (netdev, &pdev->dev) ? */ ++ + /* + * Connect PHY + */ +@@ -1439,8 +1442,6 @@ static int32_t nss_gmac_probe(struct pla + netdev_dbg(netdev, "%s MII_PHYSID2 - 0x%04x\n", netdev->name, + nss_gmac_mii_rd_reg(gmacdev, gmacdev->phy_base, MII_PHYSID2)); + } else if (gmacdev->phy_base != NSS_GMAC_NO_MDIO_PHY) { +- SET_NETDEV_DEV(netdev, gmacdev->miibus->parent); +- + /* + * Issue a phy_attach for the interface connected to a switch + */ +@@ -1485,8 +1486,8 @@ static int32_t nss_gmac_probe(struct pla + netdev_change_features(netdev); + rtnl_unlock(); + +- netdev_dbg(netdev, "Initialized NSS GMAC%d interface %s: (base = 0x%lx, irq = %d, PhyId = %d, PollLink = %d)\n" +- , gmacdev->macid, netdev->name, netdev->base_addr ++ netdev_info(netdev, "Initialized NSS GMAC%d mode: %s, interface %s: (base = 0x%lx, irq = %d, PhyId = %d, PollLink = %d)\n" ++ , gmacdev->macid, phy_modes(gmacdev->phy_mii_type), netdev->name, netdev->base_addr + , netdev->irq, gmacdev->phy_base + , test_bit(__NSS_GMAC_LINKPOLL, &gmacdev->flags)); + diff --git a/package/qca-nss/qca-nss-gmac/patches/05-kernel-6.x-support.patch b/package/qca-nss/qca-nss-gmac/patches/05-kernel-6.x-support.patch new file mode 100644 index 0000000000..4c609cd4ba --- /dev/null +++ b/package/qca-nss/qca-nss-gmac/patches/05-kernel-6.x-support.patch @@ -0,0 +1,108 @@ +--- a/ipq806x/include/msm_nss_gmac.h ++++ b/ipq806x/include/msm_nss_gmac.h +@@ -19,6 +19,7 @@ + #ifndef __MSM_NSS_GMAC_H + #define __MSM_NSS_GMAC_H + ++#include + #include + + #include +@@ -318,7 +319,11 @@ struct msm_nss_gmac_platform_data { + uint32_t poll_required; /* [0/1] Link status poll? */ + uint32_t rgmii_delay; + phy_interface_t phy_mii_type; ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ const uint8_t mac_addr[6]; ++#else + uint8_t mac_addr[6]; ++#endif + int32_t forced_speed; /* Forced speed. Values used from + ethtool.h. 0 = Speed not forced */ + int32_t forced_duplex; /* Forced duplex. Values used from +--- a/ipq806x/nss_gmac_ctrl.c ++++ b/ipq806x/nss_gmac_ctrl.c +@@ -379,10 +379,20 @@ static int32_t nss_gmac_set_mac_address( + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ nss_gmac_set_mac_addr(gmacdev, gmac_addr0_high, gmac_addr0_low, ++ (uint8_t *)addr->sa_data); ++#else + nss_gmac_set_mac_addr(gmacdev, gmac_addr0_high, gmac_addr0_low, + addr->sa_data); ++#endif ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ nss_gmac_get_mac_addr(gmacdev, gmac_addr0_high, gmac_addr0_low, ++ (uint8_t *)netdev->dev_addr); ++#else + nss_gmac_get_mac_addr(gmacdev, gmac_addr0_high, gmac_addr0_low, + netdev->dev_addr); ++#endif + + return 0; + } +@@ -1029,7 +1039,11 @@ static int32_t nss_gmac_of_get_pdata(str + return -EFAULT; + } + ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ of_get_mac_address(np, (uint8_t *)gmaccfg->mac_addr); ++#else + of_get_mac_address(np, gmaccfg->mac_addr); ++#endif + + if (of_address_to_resource(np, 0, &memres_devtree) != 0) + return -EFAULT; +@@ -1349,9 +1363,18 @@ static int32_t nss_gmac_probe(struct pla + * This just fill in some default MAC address + */ + if (is_valid_ether_addr(gmaccfg->mac_addr)) { ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ //__dev_addr_set(netdev, &gmaccfg->mac_addr, ETH_ALEN); ++ eth_hw_addr_set(netdev, (uint8_t *)gmaccfg->mac_addr); ++#else + memcpy(netdev->dev_addr, &gmaccfg->mac_addr, ETH_ALEN); ++#endif + } else { ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ eth_random_addr((uint8_t *)netdev->dev_addr); ++#else + random_ether_addr(netdev->dev_addr); ++#endif + pr_info("GMAC%d(%p) Invalid MAC@ - using %02x:%02x:%02x:%02x:%02x:%02x\n", + gmacdev->macid, gmacdev, + *netdev->dev_addr, *netdev->dev_addr+1, +--- a/ipq806x/nss_gmac_dev.c ++++ b/ipq806x/nss_gmac_dev.c +@@ -1166,8 +1166,13 @@ void nss_gmac_mac_init(struct nss_gmac_d + nss_gmac_back_off_limit(gmacdev, gmac_backoff_limit0); + nss_gmac_deferral_check_disable(gmacdev); + ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ nss_gmac_set_mac_addr(gmacdev, gmac_addr0_high, ++ gmac_addr0_low, (uint8_t *)gmacdev->netdev->dev_addr); ++#else + nss_gmac_set_mac_addr(gmacdev, gmac_addr0_high, + gmac_addr0_low, gmacdev->netdev->dev_addr); ++#endif + + /*Frame Filter Configuration */ + nss_gmac_frame_filter_enable(gmacdev); +--- a/ipq806x/nss_gmac_tx_rx_offload.c ++++ b/ipq806x/nss_gmac_tx_rx_offload.c +@@ -945,8 +945,13 @@ int nss_gmac_open(struct net_device *net + netdev_dbg(netdev, "%s: offload is not enabled, bring up gmac with slowpath\n", + __func__); + ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)) ++ netif_napi_add_weight(netdev, &gmacdev->napi, nss_gmac_poll, ++ NSS_GMAC_NAPI_BUDGET); ++#else + netif_napi_add(netdev, &gmacdev->napi, nss_gmac_poll, + NSS_GMAC_NAPI_BUDGET); ++#endif + /* Initial the RX/TX ring */ + dma_set_coherent_mask(dev, 0xffffffff); + nss_gmac_setup_rx_desc_queue(gmacdev, dev, diff --git a/package/qca-nss/qca-nss-gmac/patches/06-enable-threaded-napi.patch b/package/qca-nss/qca-nss-gmac/patches/06-enable-threaded-napi.patch new file mode 100644 index 0000000000..10185690a0 --- /dev/null +++ b/package/qca-nss/qca-nss-gmac/patches/06-enable-threaded-napi.patch @@ -0,0 +1,10 @@ +--- a/ipq806x/nss_gmac_tx_rx_offload.c ++++ b/ipq806x/nss_gmac_tx_rx_offload.c +@@ -952,6 +952,7 @@ int nss_gmac_open(struct net_device *net + netif_napi_add(netdev, &gmacdev->napi, nss_gmac_poll, + NSS_GMAC_NAPI_BUDGET); + #endif ++ dev_set_threaded(netdev, true); + /* Initial the RX/TX ring */ + dma_set_coherent_mask(dev, 0xffffffff); + nss_gmac_setup_rx_desc_queue(gmacdev, dev,