diff --git a/package/qca/qca-rfs/Makefile b/package/qca/qca-rfs/Makefile new file mode 100644 index 000000000..197545dbf --- /dev/null +++ b/package/qca/qca-rfs/Makefile @@ -0,0 +1,51 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=qca-rfs +PKG_RELEASE:=1 + +PKG_SOURCE_PROTO:=git +PKG_SOURCE_URL:=https://source.codeaurora.org/quic/qsdk/oss/lklm/qca-rfs +PKG_SOURCE_DATE:=2021-03-17 +PKG_SOURCE_VERSION:=75197c386f477c7b3a6f02489d9903a9409fd5cc +PKG_MIRROR_HASH:=90f1c3ec2e984cf8efa79c85d715ebd8a21e347ab57adbd9695de23e64eea1ec + +include $(INCLUDE_DIR)/kernel.mk +include $(INCLUDE_DIR)/package.mk + +define KernelPackage/qca-rfs + SECTION:=kernel + CATEGORY:=Kernel modules + SUBMENU:=Network Support + DEPENDS:=@TARGET_ipq40xx +kmod-ipt-conntrack + TITLE:=Kernel module for QCA Receiving Flow Steering + FILES:=$(PKG_BUILD_DIR)/qrfs.ko + KCONFIG:=\ + CONFIG_NF_CONNTRACK_EVENTS=y \ + CONFIG_NF_CONNTRACK_CHAIN_EVENTS=y + AUTOLOAD:=$(call AutoLoad,29,qrfs) +endef + +define KernelPackage/qca-rfs/Description +QCA-RFS is a kernel module for ESS Receive Flow Steering. +endef + +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 + +define Build/InstallDev + $(INSTALL_DIR) $(1)/usr/include/qca-rfs + $(CP) -rf $(PKG_BUILD_DIR)/rfs_dev.h $(1)/usr/include/qca-rfs +endef + +define KernelPackage/qca-rfs/install + $(INSTALL_DIR) $(1)/etc/init.d + $(INSTALL_BIN) ./files/qrfs.init $(1)/etc/init.d/qrfs +endef + +$(eval $(call KernelPackage,qca-rfs)) diff --git a/package/qca/qca-rfs/files/qrfs.init b/package/qca/qca-rfs/files/qrfs.init new file mode 100755 index 000000000..f3f8a38c8 --- /dev/null +++ b/package/qca/qca-rfs/files/qrfs.init @@ -0,0 +1,27 @@ +#!/bin/sh /etc/rc.common +# +# 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. +# +# 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 + +start() { + echo "1" > /proc/qrfs/enable + ip neigh flush all +} + +stop() { + echo "0" > /proc/qrfs/enable +} diff --git a/package/qca/qca-rfs/patches/100-add-kernel-5.4-support.patch b/package/qca/qca-rfs/patches/100-add-kernel-5.4-support.patch new file mode 100644 index 000000000..b7b2db559 --- /dev/null +++ b/package/qca/qca-rfs/patches/100-add-kernel-5.4-support.patch @@ -0,0 +1,57 @@ +--- a/rfs_cm.c ++++ b/rfs_cm.c +@@ -462,14 +462,6 @@ static int rfs_cm_conntrack_event(unsign + } + + /* +- * If this is an untracked connection then we can't have any state either. +- */ +- if (unlikely(ct == &nf_conntrack_untracked)) { +- RFS_TRACE("ignoring untracked conn\n"); +- return NOTIFY_DONE; +- } +- +- /* + * Ignore anything other than IPv4 connections. + */ + if (unlikely(nf_ct_l3num(ct) != AF_INET)) { +--- a/rfs_rule.c ++++ b/rfs_rule.c +@@ -702,7 +702,7 @@ int rfs_rule_init(void) + + RFS_DEBUG("RFS Rule init\n"); + spin_lock_init(&rr->hash_lock); +- memset(&rr->hash, 0, RFS_RULE_HASH_SIZE); ++ memset(&rr->hash, 0, sizeof(rr->hash)); + + rr->proc_rule = proc_create("rule", S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH, + rfs_proc_entry, &rule_proc_fops); +@@ -717,7 +717,7 @@ void rfs_rule_exit(void) + struct rfs_rule *rr = &__rr; + + RFS_DEBUG("RFS Rule exit\n"); +- if (rr->proc_rule); ++ if (rr->proc_rule) + remove_proc_entry("rule", rfs_proc_entry); + rfs_rule_destroy_all(); + } +--- a/rfs_wxt.c ++++ b/rfs_wxt.c +@@ -422,7 +422,7 @@ static int rfs_wxt_rx(struct socket *soc + #else + iov_iter_init(&msg.msg_iter, READ, &iov, 1, len); + #endif +- size = sock_recvmsg(sock, &msg, len, msg.msg_flags); ++ size = sock_recvmsg(sock, &msg, msg.msg_flags); + set_fs(oldfs); + + return size; +@@ -510,7 +510,7 @@ int rfs_wxt_stop(void) + } + + RFS_DEBUG("kill rfs_wxt thread"); +- force_sig(SIGKILL, __rwn.thread); ++ send_sig(SIGKILL, __rwn.thread, 1); + if (__rwn.thread) + err = kthread_stop(__rwn.thread); + __rwn.thread = NULL; diff --git a/package/nss/qca/qca-rfs/patches/200-rework-nfct-notification.patch b/package/qca/qca-rfs/patches/200-rework-nfct-notification.patch similarity index 100% rename from package/nss/qca/qca-rfs/patches/200-rework-nfct-notification.patch rename to package/qca/qca-rfs/patches/200-rework-nfct-notification.patch diff --git a/package/nss/qca/qca-ssdk-shell/Makefile b/package/qca/qca-ssdk-shell/Makefile similarity index 67% rename from package/nss/qca/qca-ssdk-shell/Makefile rename to package/qca/qca-ssdk-shell/Makefile index e6bd6a3f7..90e2c2e64 100644 --- a/package/nss/qca/qca-ssdk-shell/Makefile +++ b/package/qca/qca-ssdk-shell/Makefile @@ -1,10 +1,10 @@ include $(TOPDIR)/rules.mk PKG_NAME:=qca-ssdk-shell -PKG_RELEASE:=$(AUTORELEASE) +PKG_RELEASE:=1 -PKG_SOURCE_URL:=https://source.codeaurora.org/quic/cc-qrdk/oss/ssdk-shell PKG_SOURCE_PROTO:=git +PKG_SOURCE_URL:=https://source.codeaurora.org/quic/qsdk/oss/ssdk-shell PKG_SOURCE_DATE:=2021-01-27 PKG_SOURCE_VERSION:=5661366d471a78314bc7010f985ad8cc15be832a PKG_MIRROR_HASH:=73111e09e896f0abbe3ee1c358aea7ec14fe5e668ce8753b8968e03c78f9599b @@ -13,12 +13,12 @@ include $(INCLUDE_DIR)/kernel.mk include $(INCLUDE_DIR)/package.mk define Package/qca-ssdk-shell - SECTION:=QCA + SECTION:=utils CATEGORY:=Utilities TITLE:=Shell application for QCA SSDK + DEPENDS:=@(TARGET_ipq40xx||TARGET_ipq806x||TARGET_ipq807x) endef - define Package/qca-ssdk-shell/Description This package contains a qca-ssdk shell application for QCA chipset endef @@ -27,13 +27,14 @@ ifndef CONFIG_TOOLCHAIN_BIN_PATH CONFIG_TOOLCHAIN_BIN_PATH=$(TOOLCHAIN_DIR)/bin endif -QCASSDK_CONFIG_OPTS+= TOOL_PATH=$(CONFIG_TOOLCHAIN_BIN_PATH) \ - SYS_PATH=$(LINUX_DIR) \ - TOOLPREFIX=$(TARGET_CROSS) \ - KVER=$(LINUX_VERSION) \ - CFLAGS="$(TARGET_CFLAGS)" \ - LDFLAGS="$(TARGET_LDFLAGS)" \ - ARCH=$(LINUX_KARCH) +QCASSDK_CONFIG_OPTS+= \ + TOOL_PATH=$(CONFIG_TOOLCHAIN_BIN_PATH) \ + SYS_PATH=$(LINUX_DIR) \ + TOOLPREFIX=$(TARGET_CROSS) \ + KVER=$(LINUX_VERSION) \ + CFLAGS="$(TARGET_CFLAGS)" \ + LDFLAGS="$(TARGET_LDFLAGS)" \ + ARCH=$(LINUX_KARCH) define Build/Compile $(MAKE) -C $(PKG_BUILD_DIR) $(strip $(QCASSDK_CONFIG_OPTS)) @@ -44,5 +45,4 @@ define Package/qca-ssdk-shell/install $(INSTALL_BIN) $(PKG_BUILD_DIR)/build/bin/ssdk_sh $(1)/usr/sbin/ endef - $(eval $(call BuildPackage,qca-ssdk-shell)) diff --git a/package/nss/qca/qca-ssdk/Makefile b/package/qca/qca-ssdk/Makefile similarity index 64% rename from package/nss/qca/qca-ssdk/Makefile rename to package/qca/qca-ssdk/Makefile index 204bf2d39..62883a91d 100644 --- a/package/nss/qca/qca-ssdk/Makefile +++ b/package/qca/qca-ssdk/Makefile @@ -1,34 +1,52 @@ include $(TOPDIR)/rules.mk PKG_NAME:=qca-ssdk -PKG_RELEASE:=$(AUTORELEASE) +PKG_RELEASE:=1 -PKG_SOURCE_URL:=https://source.codeaurora.org/quic/cc-qrdk/oss/lklm/qca-ssdk PKG_SOURCE_PROTO:=git +PKG_SOURCE_URL:=https://source.codeaurora.org/quic/qsdk/oss/lklm/qca-ssdk PKG_SOURCE_DATE:=2021-04-28 PKG_SOURCE_VERSION:=c9bc3bc34eaaac78083573524097356e2dcc1b66 PKG_MIRROR_HASH:=29db78529be32427b8b96fcbfec22a016a243676781ec96d9d65b810944fa405 PKG_BUILD_PARALLEL:=1 +LOCAL_VARIANT=$(patsubst qca-ssdk-%,%,$(patsubst qca-ssdk-%,%,$(BUILD_VARIANT))) + include $(INCLUDE_DIR)/kernel.mk include $(INCLUDE_DIR)/package.mk -define KernelPackage/qca-ssdk-nohnat +define KernelPackage/qca-ssdk/default-nohnat SECTION:=kernel CATEGORY:=Kernel modules SUBMENU:=Network Devices TITLE:=Kernel driver for QCA SSDK - DEPENDS:=@(TARGET_ipq807x) FILES:=$(PKG_BUILD_DIR)/build/bin/qca-ssdk.ko AUTOLOAD:=$(call AutoLoad,30,qca-ssdk) + PROVIDES:=qca-ssdk +endef + +define KernelPackage/qca-ssdk-nohnat +$(call KernelPackage/qca-ssdk/default-nohnat) + DEPENDS:=@(TARGET_ipq806x||TARGET_ipq807x) + VARIANT:=nohnat endef define KernelPackage/qca-ssdk-nohnat/Description This package contains a qca-ssdk driver for QCA chipset endef -GCC_VERSION=$(shell echo "$(CONFIG_GCC_VERSION)" | sed 's/[^0-9.]*\([0-9.]*\).*/\1/') +define KernelPackage/qca-ssdk-hnat +$(call KernelPackage/qca-ssdk/default-nohnat) + DEPENDS:=@TARGET_ipq40xx +kmod-ipt-extra +kmod-ipt-filter \ + +kmod-ppp +TARGET_ipq40xx:kmod-qca-rfs + TITLE+= (hnat) + VARIANT:=hnat +endef + +define KernelPackage/qca-ssdk-hnat/Description +This package contains a qca-ssdk-hnat driver for QCA chipset +endef ifdef CONFIG_TOOLCHAIN_BIN_PATH TOOLCHAIN_BIN_PATH=$(CONFIG_TOOLCHAIN_BIN_PATH) @@ -36,8 +54,7 @@ else TOOLCHAIN_BIN_PATH=$(TOOLCHAIN_DIR)/bin endif -MAKE_FLAGS+= \ - TARGET_NAME=$(CONFIG_TARGET_NAME) \ +QCASSDK_CONFIG_OPTS+= \ TOOL_PATH=$(TOOLCHAIN_BIN_PATH) \ SYS_PATH=$(LINUX_DIR) \ TOOLPREFIX=$(TARGET_CROSS) \ @@ -45,19 +62,24 @@ MAKE_FLAGS+= \ ARCH=$(LINUX_KARCH) \ TARGET_SUFFIX=$(CONFIG_TARGET_SUFFIX) \ GCC_VERSION=$(GCC_VERSION) \ - EXTRA_CFLAGS=-I$(STAGING_DIR)/usr/include \ - $(KERNEL_MAKE_FLAGS) + CFLAGS=-I$(STAGING_DIR)/usr/include -ifneq (, $(findstring $(CONFIG_TARGET_BOARD), "ipq60xx" "ipq807x")) - MAKE_FLAGS+= PTP_FEATURE=disable SWCONFIG_FEATURE=disable +ifeq ($(LOCAL_VARIANT),hnat) + QCASSDK_CONFIG_OPTS+= HNAT_FEATURE=enable endif -ifeq ($(CONFIG_TARGET_BOARD), "ipq807x") - MAKE_FLAGS+= CHIP_TYPE=HPPE -else ifeq ($(CONFIG_TARGET_BOARD), "ipq60xx") - MAKE_FLAGS+= CHIP_TYPE=CPPE +ifeq ($(BOARD),ipq40xx) + QCASSDK_CONFIG_OPTS+= HK_CHIP=enable +else ifeq ($(BOARD),ipq60xx) + QCASSDK_CONFIG_OPTS+= CHIP_TYPE=CPPE PTP_FEATURE=disable SWCONFIG_FEATURE=disable +else ifeq ($(BOARD),ipq807x) + QCASSDK_CONFIG_OPTS+= CHIP_TYPE=HPPE PTP_FEATURE=disable SWCONFIG_FEATURE=disable endif +define Build/Compile + $(MAKE) -C $(PKG_BUILD_DIR) $(strip $(QCASSDK_CONFIG_OPTS)) +endef + define Build/InstallDev $(INSTALL_DIR) $(1)/usr/include/qca-ssdk $(INSTALL_DIR) $(1)/usr/include/qca-ssdk/api @@ -82,7 +104,6 @@ define Build/InstallDev $(CP) -rf $(PKG_BUILD_DIR)/include/common/*.h $(1)/usr/include/qca-ssdk $(CP) -rf $(PKG_BUILD_DIR)/include/sal/os/linux/*.h $(1)/usr/include/qca-ssdk $(CP) -rf $(PKG_BUILD_DIR)/include/sal/os/*.h $(1)/usr/include/qca-ssdk - endef define KernelPackage/qca-ssdk-nohnat/install @@ -90,4 +111,10 @@ define KernelPackage/qca-ssdk-nohnat/install $(INSTALL_BIN) ./files/qca-ssdk $(1)/etc/init.d/qca-ssdk endef +define KernelPackage/qca-ssdk-hnat/install + $(INSTALL_DIR) $(1)/etc/init.d + $(INSTALL_BIN) ./files/qca-ssdk $(1)/etc/init.d/qca-ssdk +endef + $(eval $(call KernelPackage,qca-ssdk-nohnat)) +$(eval $(call KernelPackage,qca-ssdk-hnat)) diff --git a/package/nss/qca/qca-ssdk/files/qca-ssdk b/package/qca/qca-ssdk/files/qca-ssdk similarity index 100% rename from package/nss/qca/qca-ssdk/files/qca-ssdk rename to package/qca/qca-ssdk/files/qca-ssdk diff --git a/package/nss/qca/qca-ssdk/patches/0001-SSDK-config-add-kernel-5.10.patch b/package/qca/qca-ssdk/patches/0001-SSDK-config-add-kernel-5.10.patch similarity index 100% rename from package/nss/qca/qca-ssdk/patches/0001-SSDK-config-add-kernel-5.10.patch rename to package/qca/qca-ssdk/patches/0001-SSDK-config-add-kernel-5.10.patch diff --git a/package/nss/qca/qca-ssdk/patches/0002-SSDK-replace-ioremap_nocache-with-ioremap.patch b/package/qca/qca-ssdk/patches/0002-SSDK-replace-ioremap_nocache-with-ioremap.patch similarity index 100% rename from package/nss/qca/qca-ssdk/patches/0002-SSDK-replace-ioremap_nocache-with-ioremap.patch rename to package/qca/qca-ssdk/patches/0002-SSDK-replace-ioremap_nocache-with-ioremap.patch diff --git a/package/nss/qca/qca-ssdk/patches/0004-platform-use-of_mdio_find_bus-to-get-MDIO-bus.patch b/package/qca/qca-ssdk/patches/0004-platform-use-of_mdio_find_bus-to-get-MDIO-bus.patch similarity index 100% rename from package/nss/qca/qca-ssdk/patches/0004-platform-use-of_mdio_find_bus-to-get-MDIO-bus.patch rename to package/qca/qca-ssdk/patches/0004-platform-use-of_mdio_find_bus-to-get-MDIO-bus.patch diff --git a/package/qca/qca-ssdk/patches/0005-add-kernel-5.4-support.patch b/package/qca/qca-ssdk/patches/0005-add-kernel-5.4-support.patch new file mode 100644 index 000000000..6b08b05ae --- /dev/null +++ b/package/qca/qca-ssdk/patches/0005-add-kernel-5.4-support.patch @@ -0,0 +1,108 @@ +--- a/app/nathelper/linux/lib/nat_helper_dt.c ++++ b/app/nathelper/linux/lib/nat_helper_dt.c +@@ -721,7 +721,7 @@ napt_ct_counter_sync(a_uint32_t hw_index) + } + + if (!test_bit(IPS_FIXED_TIMEOUT_BIT, &ct->status)) { +- ct->timeout.expires += delta_jiffies; ++ ct->timeout += delta_jiffies; + } + + if((cct != NULL) && (napt_hw_get_by_index(&napt, hw_index) == 0)) +@@ -770,7 +770,7 @@ napt_ct_timer_update(a_uint32_t hw_index) + } + + if (!test_bit(IPS_FIXED_TIMEOUT_BIT, &ct->status)) { +- ct->timeout.expires += delta_jiffies; ++ ct->timeout += delta_jiffies; + } + + return 0; +--- a/app/nathelper/linux/napt_helper.c ++++ b/app/nathelper/linux/napt_helper.c +@@ -64,11 +64,6 @@ napt_ct_aging_disable(uint32_t ct_addr) + } + + ct = (struct nf_conn *)ct_addr; +- +- if (timer_pending(&ct->timeout)) +- { +- del_timer(&ct->timeout); +- } + } + + int +@@ -85,7 +80,7 @@ napt_ct_aging_is_enable(uint32_t ct_addr) + + ct = (struct nf_conn *)ct_addr; + +- return timer_pending(&(((struct nf_conn *)ct)->timeout)); ++ return (nf_ct_is_expired(ct)); + } + + void +@@ -111,18 +106,17 @@ napt_ct_aging_enable(uint32_t ct_addr) + l3num = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; + protonum = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum; + +- ct->timeout.expires = jiffies+10*HZ; ++ ct->timeout = jiffies+10*HZ; + + if ((l3num == AF_INET) && (protonum == IPPROTO_TCP)) + { + if (ct->proto.tcp.state == TCP_CONNTRACK_ESTABLISHED) + { +- ct->timeout.expires = jiffies+(5*24*60*60*HZ); ++ ct->timeout = jiffies+(5*24*60*60*HZ); + } + } + + HNAT_PRINTK(" ct:[%x] add timeout again\n", ct_addr); +- add_timer(&ct->timeout); + } + + void +@@ -339,7 +333,6 @@ napt_ct_list_unlock(void) + uint32_t + napt_ct_list_iterate(uint32_t *hash, uint32_t *iterate) + { +- struct net *net = &init_net; + struct nf_conntrack_tuple_hash *h = NULL; + struct nf_conn *ct = NULL; + struct hlist_nulls_node *pos = (struct hlist_nulls_node *) (*iterate); +@@ -349,7 +342,7 @@ napt_ct_list_iterate(uint32_t *hash, uint32_t *iterate) + if(pos == 0) + { + /*get head for list*/ +- pos = rcu_dereference((&net->ct.hash[*hash])->first); ++ pos = rcu_dereference(hlist_nulls_first_rcu(&nf_conntrack_hash[*hash])); + } + + hlist_nulls_for_each_entry_from(h, pos, hnnode) +--- a/app/nathelper/linux/nat_ipt_helper.c ++++ b/app/nathelper/linux/nat_ipt_helper.c +@@ -534,10 +534,10 @@ nat_ipt_data_init(void) + memset(&old_replace, 0, sizeof (old_replace)); + + /*record ipt rule(SNAT) sequence for hw nat*/ +- memset(hw_nat_ipt_seq, 0, NAT_HW_NUM); ++ memset(hw_nat_ipt_seq, 0, sizeof(hw_nat_ipt_seq)); + + /*record ipt rule(SNAT) pubip index for hw nat*/ +- memset(hw_nat_pip_idx, 0, NAT_HW_NUM); ++ memset(hw_nat_pip_idx, 0, sizeof(hw_nat_pip_idx)); + } + + static void +--- a/make/linux_opt.mk ++++ b/make/linux_opt.mk +@@ -449,9 +449,6 @@ ifeq (KSLIB, $(MODULE_TYPE)) + else ifeq ($(ARCH), arm) + MODULE_INC += -I$(SYS_PATH) \ + -I$(TOOL_PATH)/../lib/gcc/$(TARGET_NAME)/$(GCC_VERSION)/include/ \ +- -I$(TOOL_PATH)/../lib/gcc/$(TARGET_NAME)/7.5.0/include/ \ +- -I$(TOOL_PATH)/../../lib/armv7a-vfp-neon-rdk-linux-gnueabi/gcc/arm-rdk-linux-gnueabi/4.8.4/include/ \ +- -I$(TOOL_PATH)/../../lib/arm-rdk-linux-musleabi/gcc/arm-rdk-linux-musleabi/6.4.0/include/ \ + -I$(SYS_PATH)/include \ + -I$(SYS_PATH)/source \ + -I$(SYS_PATH)/source/include \ diff --git a/package/qca/qca-ssdk/patches/0006-fix-mdio-probe-on-ipq806x.patch b/package/qca/qca-ssdk/patches/0006-fix-mdio-probe-on-ipq806x.patch new file mode 100644 index 000000000..8e802fe2a --- /dev/null +++ b/package/qca/qca-ssdk/patches/0006-fix-mdio-probe-on-ipq806x.patch @@ -0,0 +1,11 @@ +--- a/src/init/ssdk_plat.c ++++ b/src/init/ssdk_plat.c +@@ -568,7 +568,7 @@ static int miibus_get(a_uint32_t dev_id) + if(reg_mode == HSL_REG_LOCAL_BUS) + mdio_node = of_find_compatible_node(NULL, NULL, "qcom,ipq40xx-mdio"); + else +- mdio_node = of_find_compatible_node(NULL, NULL, "virtual,mdio-gpio"); ++ mdio_node = of_find_compatible_node(NULL, NULL, "qcom,ipq8064-mdio"); + + if (!mdio_node) { + SSDK_ERROR("No MDIO node found in DTS!\n"); diff --git a/target/linux/ipq40xx/Makefile b/target/linux/ipq40xx/Makefile index d20424598..8f1027146 100644 --- a/target/linux/ipq40xx/Makefile +++ b/target/linux/ipq40xx/Makefile @@ -16,9 +16,10 @@ include $(INCLUDE_DIR)/target.mk DEFAULT_PACKAGES += \ kmod-usb-dwc3-qcom \ kmod-leds-gpio kmod-gpio-button-hotplug swconfig \ - kmod-ath10k-ct wpad-openssl \ + kmod-ath10k-ct wpad-openssl uboot-envtools \ kmod-usb3 kmod-usb-dwc3 ath10k-firmware-qca4019-ct \ - autocore-arm automount autosamba luci-app-adbyby-plus luci-app-ipsec-vpnd luci-app-unblockmusic luci-app-cpufreq luci-app-zerotier \ - htop ethtool + autocore-arm automount autosamba ethtool htop \ + luci-app-adbyby-plus luci-app-cpufreq luci-app-ipsec-vpnd \ + luci-app-unblockmusic luci-app-zerotier $(eval $(call BuildTarget)) diff --git a/target/linux/ipq40xx/patches-5.4/995-add-qca-rfs-support.patch b/target/linux/ipq40xx/patches-5.4/995-add-qca-rfs-support.patch new file mode 100644 index 000000000..788c09b52 --- /dev/null +++ b/target/linux/ipq40xx/patches-5.4/995-add-qca-rfs-support.patch @@ -0,0 +1,695 @@ +--- a/include/linux/if_bridge.h ++++ b/include/linux/if_bridge.h +@@ -149,4 +149,37 @@ br_port_flag_is_set(const struct net_dev + } + #endif + ++extern struct net_device *br_port_dev_get(struct net_device *dev, ++ unsigned char *addr, ++ struct sk_buff *skb, ++ unsigned int cookie); ++extern void br_refresh_fdb_entry(struct net_device *dev, const char *addr); ++extern struct net_bridge_fdb_entry *br_fdb_has_entry(struct net_device *dev, ++ const char *addr, ++ __u16 vid); ++extern void br_fdb_update_register_notify(struct notifier_block *nb); ++extern void br_fdb_update_unregister_notify(struct notifier_block *nb); ++ ++typedef struct net_bridge_port *br_port_dev_get_hook_t(struct net_device *dev, ++ struct sk_buff *skb, ++ unsigned char *addr, ++ unsigned int cookie); ++extern br_port_dev_get_hook_t __rcu *br_port_dev_get_hook; ++ ++#define BR_FDB_EVENT_ADD 0x01 ++#define BR_FDB_EVENT_DEL 0x02 ++ ++struct br_fdb_event { ++ struct net_device *dev; ++ unsigned char addr[6]; ++ unsigned char is_local; ++}; ++extern void br_fdb_register_notify(struct notifier_block *nb); ++extern void br_fdb_unregister_notify(struct notifier_block *nb); ++ ++typedef struct net_bridge_port *br_get_dst_hook_t( ++ const struct net_bridge_port *src, ++ struct sk_buff **skb); ++extern br_get_dst_hook_t __rcu *br_get_dst_hook; ++ + #endif +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -2595,6 +2595,8 @@ enum netdev_cmd { + NETDEV_CVLAN_FILTER_DROP_INFO, + NETDEV_SVLAN_FILTER_PUSH_INFO, + NETDEV_SVLAN_FILTER_DROP_INFO, ++ NETDEV_BR_JOIN, ++ NETDEV_BR_LEAVE, + }; + const char *netdev_cmd_to_name(enum netdev_cmd cmd); + +--- a/include/linux/ppp_channel.h ++++ b/include/linux/ppp_channel.h +@@ -32,6 +32,17 @@ struct ppp_channel_ops { + #if IS_ENABLED(CONFIG_NF_FLOW_TABLE) + int (*flow_offload_check)(struct ppp_channel *, struct flow_offload_hw_path *); + #endif ++ ++ /* Get channel protocol type, one of PX_PROTO_XYZ or specific to ++ * the channel subtype ++ */ ++ int (*get_channel_protocol)(struct ppp_channel *); ++ /* Get channel protocol version */ ++ int (*get_channel_protocol_ver)(struct ppp_channel *); ++ /* Hold the channel from being destroyed */ ++ void (*hold)(struct ppp_channel *); ++ /* Release hold on the channel */ ++ void (*release)(struct ppp_channel *); + }; + + struct ppp_channel { +@@ -84,5 +95,53 @@ extern char *ppp_dev_name(struct ppp_cha + * that ppp_unregister_channel returns. + */ + ++/* Call this to obtain the underlying protocol of the PPP channel, ++ * e.g. PX_PROTO_OE ++ */ ++extern int ppp_channel_get_protocol(struct ppp_channel *); ++ ++/* Call this get protocol version */ ++extern int ppp_channel_get_proto_version(struct ppp_channel *); ++ ++/* Call this to hold a channel */ ++extern bool ppp_channel_hold(struct ppp_channel *); ++ ++/* Call this to release a hold you have upon a channel */ ++extern void ppp_channel_release(struct ppp_channel *); ++ ++/* Release hold on PPP channels */ ++extern void ppp_release_channels(struct ppp_channel *channels[], ++ unsigned int chan_sz); ++ ++/* Hold PPP channels for the PPP device */ ++extern int ppp_hold_channels(struct net_device *dev, ++ struct ppp_channel *channels[], ++ unsigned int chan_sz); ++/* Test if ppp xmit lock is locked */ ++extern bool ppp_is_xmit_locked(struct net_device *dev); ++ ++/* Hold PPP channels for the PPP device */ ++extern int __ppp_hold_channels(struct net_device *dev, ++ struct ppp_channel *channels[], ++ unsigned int chan_sz); ++ ++/* Test if the ppp device is a multi-link ppp device */ ++extern int ppp_is_multilink(struct net_device *dev); ++ ++/* Test if the ppp device is a multi-link ppp device */ ++extern int __ppp_is_multilink(struct net_device *dev); ++ ++/* Update statistics of the PPP net_device by incrementing related ++ * statistics field value with corresponding parameter ++ */ ++extern void ppp_update_stats(struct net_device *dev, unsigned long rx_packets, ++ unsigned long rx_bytes, unsigned long tx_packets, ++ unsigned long tx_bytes, unsigned long rx_errors, ++ unsigned long tx_errors, unsigned long rx_dropped, ++ unsigned long tx_dropped); ++ ++/* Get the device index associated with a channel, or 0, if none */ ++extern int ppp_dev_index(struct ppp_channel *); ++ + #endif /* __KERNEL__ */ + #endif +--- a/drivers/net/phy/phy.c ++++ b/drivers/net/phy/phy.c +@@ -703,6 +703,7 @@ void phy_stop_machine(struct phy_device *phydev) + phydev->state = PHY_UP; + mutex_unlock(&phydev->lock); + } ++EXPORT_SYMBOL_GPL(phy_stop_machine); + + /** + * phy_error - enter HALTED state for this PHY device +--- a/drivers/net/ppp/ppp_generic.c ++++ b/drivers/net/ppp/ppp_generic.c +@@ -3341,6 +3341,318 @@ static void *unit_find(struct idr *p, int n) + return idr_find(p, n); + } + ++/* Return the PPP net device index */ ++int ppp_dev_index(struct ppp_channel *chan) ++{ ++ struct channel *pch = chan->ppp; ++ int ifindex = 0; ++ ++ if (pch) { ++ read_lock_bh(&pch->upl); ++ if (pch->ppp && pch->ppp->dev) ++ ifindex = pch->ppp->dev->ifindex; ++ read_unlock_bh(&pch->upl); ++ } ++ return ifindex; ++} ++EXPORT_SYMBOL(ppp_dev_index); ++ ++/* Updates the PPP interface statistics. */ ++void ppp_update_stats(struct net_device *dev, unsigned long rx_packets, ++ unsigned long rx_bytes, unsigned long tx_packets, ++ unsigned long tx_bytes, unsigned long rx_errors, ++ unsigned long tx_errors, unsigned long rx_dropped, ++ unsigned long tx_dropped) ++{ ++ struct ppp *ppp; ++ ++ if (!dev) ++ return; ++ ++ if (dev->type != ARPHRD_PPP) ++ return; ++ ++ ppp = netdev_priv(dev); ++ ++ ppp_xmit_lock(ppp); ++ ppp->stats64.tx_packets += tx_packets; ++ ppp->stats64.tx_bytes += tx_bytes; ++ ppp->dev->stats.tx_errors += tx_errors; ++ ppp->dev->stats.tx_dropped += tx_dropped; ++ if (tx_packets) ++ ppp->last_xmit = jiffies; ++ ppp_xmit_unlock(ppp); ++ ++ ppp_recv_lock(ppp); ++ ppp->stats64.rx_packets += rx_packets; ++ ppp->stats64.rx_bytes += rx_bytes; ++ ppp->dev->stats.rx_errors += rx_errors; ++ ppp->dev->stats.rx_dropped += rx_dropped; ++ if (rx_packets) ++ ppp->last_recv = jiffies; ++ ppp_recv_unlock(ppp); ++} ++EXPORT_SYMBOL(ppp_update_stats); ++ ++/* Returns >0 if the device is a multilink PPP netdevice, 0 if not or < 0 if ++ * the device is not PPP. ++ */ ++int ppp_is_multilink(struct net_device *dev) ++{ ++ struct ppp *ppp; ++ unsigned int flags; ++ ++ if (!dev) ++ return -1; ++ ++ if (dev->type != ARPHRD_PPP) ++ return -1; ++ ++ ppp = netdev_priv(dev); ++ ppp_lock(ppp); ++ flags = ppp->flags; ++ ppp_unlock(ppp); ++ ++ if (flags & SC_MULTILINK) ++ return 1; ++ ++ return 0; ++} ++EXPORT_SYMBOL(ppp_is_multilink); ++ ++/* __ppp_is_multilink() ++ * Returns >0 if the device is a multilink PPP netdevice, 0 if not or < 0 ++ * if the device is not PPP. Caller should acquire ppp_lock before calling ++ * this function ++ */ ++int __ppp_is_multilink(struct net_device *dev) ++{ ++ struct ppp *ppp; ++ unsigned int flags; ++ ++ if (!dev) ++ return -1; ++ ++ if (dev->type != ARPHRD_PPP) ++ return -1; ++ ++ ppp = netdev_priv(dev); ++ flags = ppp->flags; ++ ++ if (flags & SC_MULTILINK) ++ return 1; ++ ++ return 0; ++} ++EXPORT_SYMBOL(__ppp_is_multilink); ++ ++/* ppp_channel_get_protocol() ++ * Call this to obtain the underlying protocol of the PPP channel, ++ * e.g. PX_PROTO_OE ++ * ++ * NOTE: Some channels do not use PX sockets so the protocol value may be very ++ * different for them. ++ * NOTE: -1 indicates failure. ++ * NOTE: Once you know the channel protocol you may then either cast 'chan' to ++ * its sub-class or use the channel protocol specific API's as provided by that ++ * channel sub type. ++ */ ++int ppp_channel_get_protocol(struct ppp_channel *chan) ++{ ++ if (!chan->ops->get_channel_protocol) ++ return -1; ++ ++ return chan->ops->get_channel_protocol(chan); ++} ++EXPORT_SYMBOL(ppp_channel_get_protocol); ++ ++/* ppp_channel_get_proto_version() ++ * Call this to get channel protocol version ++ */ ++int ppp_channel_get_proto_version(struct ppp_channel *chan) ++{ ++ if (!chan->ops->get_channel_protocol_ver) ++ return -1; ++ ++ return chan->ops->get_channel_protocol_ver(chan); ++} ++EXPORT_SYMBOL(ppp_channel_get_proto_version); ++ ++/* ppp_channel_hold() ++ * Call this to hold a channel. ++ * ++ * Returns true on success or false if the hold could not happen. ++ * ++ * NOTE: chan must be protected against destruction during this call - ++ * either by correct locking etc. or because you already have an implicit ++ * or explicit hold to the channel already and this is an additional hold. ++ */ ++bool ppp_channel_hold(struct ppp_channel *chan) ++{ ++ if (!chan->ops->hold) ++ return false; ++ ++ chan->ops->hold(chan); ++ return true; ++} ++EXPORT_SYMBOL(ppp_channel_hold); ++ ++/* ppp_channel_release() ++ * Call this to release a hold you have upon a channel ++ */ ++void ppp_channel_release(struct ppp_channel *chan) ++{ ++ chan->ops->release(chan); ++} ++EXPORT_SYMBOL(ppp_channel_release); ++ ++/* ppp_hold_channels() ++ * Returns the PPP channels of the PPP device, storing each one into ++ * channels[]. ++ * ++ * channels[] has chan_sz elements. ++ * This function returns the number of channels stored, up to chan_sz. ++ * It will return < 0 if the device is not PPP. ++ * ++ * You MUST release the channels using ppp_release_channels(). ++ */ ++int ppp_hold_channels(struct net_device *dev, struct ppp_channel *channels[], ++ unsigned int chan_sz) ++{ ++ struct ppp *ppp; ++ int c; ++ struct channel *pch; ++ ++ if (!dev) ++ return -1; ++ ++ if (dev->type != ARPHRD_PPP) ++ return -1; ++ ++ ppp = netdev_priv(dev); ++ ++ c = 0; ++ ppp_lock(ppp); ++ list_for_each_entry(pch, &ppp->channels, clist) { ++ struct ppp_channel *chan; ++ ++ if (!pch->chan) { ++ /* Channel is going / gone away */ ++ continue; ++ } ++ ++ if (c == chan_sz) { ++ /* No space to record channel */ ++ ppp_unlock(ppp); ++ return c; ++ } ++ ++ /* Hold the channel, if supported */ ++ chan = pch->chan; ++ if (!chan->ops->hold) ++ continue; ++ ++ chan->ops->hold(chan); ++ ++ /* Record the channel */ ++ channels[c++] = chan; ++ } ++ ppp_unlock(ppp); ++ return c; ++} ++EXPORT_SYMBOL(ppp_hold_channels); ++ ++/* __ppp_hold_channels() ++ * Returns the PPP channels of the PPP device, storing each one ++ * into channels[]. ++ * ++ * channels[] has chan_sz elements. ++ * This function returns the number of channels stored, up to chan_sz. ++ * It will return < 0 if the device is not PPP. ++ * ++ * You MUST acquire ppp_lock and release the channels using ++ * ppp_release_channels(). ++ */ ++int __ppp_hold_channels(struct net_device *dev, struct ppp_channel *channels[], ++ unsigned int chan_sz) ++{ ++ struct ppp *ppp; ++ int c; ++ struct channel *pch; ++ ++ if (!dev) ++ return -1; ++ ++ if (dev->type != ARPHRD_PPP) ++ return -1; ++ ++ ppp = netdev_priv(dev); ++ ++ c = 0; ++ list_for_each_entry(pch, &ppp->channels, clist) { ++ struct ppp_channel *chan; ++ ++ if (!pch->chan) { ++ /* Channel is going / gone away*/ ++ continue; ++ } ++ if (c == chan_sz) { ++ /* No space to record channel */ ++ return c; ++ } ++ ++ /* Hold the channel, if supported */ ++ chan = pch->chan; ++ if (!chan->ops->hold) ++ continue; ++ ++ chan->ops->hold(chan); ++ ++ /* Record the channel */ ++ channels[c++] = chan; ++ } ++ return c; ++} ++EXPORT_SYMBOL(__ppp_hold_channels); ++ ++/* ppp_release_channels() ++ * Releases channels ++ */ ++void ppp_release_channels(struct ppp_channel *channels[], unsigned int chan_sz) ++{ ++ unsigned int c; ++ ++ for (c = 0; c < chan_sz; ++c) { ++ struct ppp_channel *chan; ++ ++ chan = channels[c]; ++ chan->ops->release(chan); ++ } ++} ++EXPORT_SYMBOL(ppp_release_channels); ++ ++/* Check if ppp xmit lock is on hold */ ++bool ppp_is_xmit_locked(struct net_device *dev) ++{ ++ struct ppp *ppp; ++ ++ if (!dev) ++ return false; ++ ++ if (dev->type != ARPHRD_PPP) ++ return false; ++ ++ ppp = netdev_priv(dev); ++ if (!ppp) ++ return false; ++ ++ if (spin_is_locked(&(ppp)->wlock)) ++ return true; ++ ++ return false; ++} ++EXPORT_SYMBOL(ppp_is_xmit_locked); ++ + /* Module/initialization stuff */ + + module_init(ppp_init); +--- a/net/bridge/br_if.c ++++ b/net/bridge/br_if.c +@@ -26,6 +26,10 @@ + + #include "br_private.h" + ++/* Hook for external forwarding logic */ ++br_port_dev_get_hook_t __rcu *br_port_dev_get_hook __read_mostly; ++EXPORT_SYMBOL_GPL(br_port_dev_get_hook); ++ + /* + * Determine initial path cost based on speed. + * using recommendations from 802.1d standard +@@ -681,6 +685,8 @@ int br_add_if(struct net_bridge *br, struct net_device *dev, + + kobject_uevent(&p->kobj, KOBJ_ADD); + ++ call_netdevice_notifiers(NETDEV_BR_JOIN, dev); ++ + return 0; + + err7: +@@ -714,6 +720,8 @@ int br_del_if(struct net_bridge *br, struct net_device *dev) + if (!p || p->br != br) + return -EINVAL; + ++ call_netdevice_notifiers(NETDEV_BR_LEAVE, dev); ++ + /* Since more than one interface can be attached to a bridge, + * there still maybe an alternate path for netconsole to use; + * therefore there is no reason for a NETDEV_RELEASE event. +@@ -768,6 +776,65 @@ void br_dev_update_stats(struct net_device *dev, + } + EXPORT_SYMBOL_GPL(br_dev_update_stats); + ++/* br_port_dev_get() ++ * If a skb is provided, and the br_port_dev_get_hook_t hook exists, ++ * use that to try and determine the egress port for that skb. ++ * If not, or no egress port could be determined, use the given addr ++ * to identify the port to which it is reachable, ++ * returing a reference to the net device associated with that port. ++ * ++ * NOTE: Return NULL if given dev is not a bridge or the mac has no ++ * associated port. ++ */ ++struct net_device *br_port_dev_get(struct net_device *dev, unsigned char *addr, ++ struct sk_buff *skb, ++ unsigned int cookie) ++{ ++ struct net_bridge_fdb_entry *fdbe; ++ struct net_bridge *br; ++ struct net_device *netdev = NULL; ++ ++ /* Is this a bridge? */ ++ if (!(dev->priv_flags & IFF_EBRIDGE)) ++ return NULL; ++ ++ rcu_read_lock(); ++ ++ /* If the hook exists and the skb isn't NULL, try and get the port */ ++ if (skb) { ++ br_port_dev_get_hook_t *port_dev_get_hook; ++ ++ port_dev_get_hook = rcu_dereference(br_port_dev_get_hook); ++ if (port_dev_get_hook) { ++ struct net_bridge_port *pdst = ++ __br_get(port_dev_get_hook, NULL, dev, skb, ++ addr, cookie); ++ if (pdst) { ++ dev_hold(pdst->dev); ++ netdev = pdst->dev; ++ goto out; ++ } ++ } ++ } ++ ++ /* Either there is no hook, or can't ++ * determine the port to use - fall back to using FDB ++ */ ++ ++ br = netdev_priv(dev); ++ ++ /* Lookup the fdb entry and get reference to the port dev */ ++ fdbe = br_fdb_find_rcu(br, addr, 0); ++ if (fdbe && fdbe->dst) { ++ netdev = fdbe->dst->dev; /* port device */ ++ dev_hold(netdev); ++ } ++out: ++ rcu_read_unlock(); ++ return netdev; ++} ++EXPORT_SYMBOL_GPL(br_port_dev_get); ++ + bool br_port_flag_is_set(const struct net_device *dev, unsigned long flag) + { + struct net_bridge_port *p; +--- a/net/bridge/br_fdb.c ++++ b/net/bridge/br_fdb.c +@@ -37,6 +37,33 @@ static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source, + static void fdb_notify(struct net_bridge *br, + const struct net_bridge_fdb_entry *, int, bool); + ++ATOMIC_NOTIFIER_HEAD(br_fdb_notifier_list); ++ATOMIC_NOTIFIER_HEAD(br_fdb_update_notifier_list); ++ ++void br_fdb_register_notify(struct notifier_block *nb) ++{ ++ atomic_notifier_chain_register(&br_fdb_notifier_list, nb); ++} ++EXPORT_SYMBOL_GPL(br_fdb_register_notify); ++ ++void br_fdb_unregister_notify(struct notifier_block *nb) ++{ ++ atomic_notifier_chain_unregister(&br_fdb_notifier_list, nb); ++} ++EXPORT_SYMBOL_GPL(br_fdb_unregister_notify); ++ ++void br_fdb_update_register_notify(struct notifier_block *nb) ++{ ++ atomic_notifier_chain_register(&br_fdb_update_notifier_list, nb); ++} ++EXPORT_SYMBOL_GPL(br_fdb_update_register_notify); ++ ++void br_fdb_update_unregister_notify(struct notifier_block *nb) ++{ ++ atomic_notifier_chain_unregister(&br_fdb_update_notifier_list, nb); ++} ++EXPORT_SYMBOL_GPL(br_fdb_update_unregister_notify); ++ + int __init br_fdb_init(void) + { + br_fdb_cache = kmem_cache_create("bridge_fdb_cache", +@@ -337,6 +364,7 @@ void br_fdb_cleanup(struct work_struct *work) + unsigned long delay = hold_time(br); + unsigned long work_delay = delay; + unsigned long now = jiffies; ++ u8 mac_addr[6]; + + /* this part is tricky, in order to avoid blocking learning and + * consequently forwarding, we rely on rcu to delete objects with +@@ -353,8 +381,11 @@ void br_fdb_cleanup(struct work_struct *work) + work_delay = min(work_delay, this_timer - now); + } else { + spin_lock_bh(&br->hash_lock); +- if (!hlist_unhashed(&f->fdb_node)) ++ if (!hlist_unhashed(&f->fdb_node)) { + fdb_delete(br, f, true); ++ atomic_notifier_call_chain( ++ &br_fdb_update_notifier_list, 0, (void *)mac_addr); ++ } + spin_unlock_bh(&br->hash_lock); + } + } +@@ -587,6 +618,8 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source, + /* Take over HW learned entry */ + if (unlikely(fdb->added_by_external_learn)) + fdb->added_by_external_learn = 0; ++ atomic_notifier_call_chain( ++ &br_fdb_update_notifier_list, 0, (void *)addr); + } + if (now != fdb->updated) + fdb->updated = now; +@@ -696,6 +729,23 @@ static void fdb_notify(struct net_bridge *br, + struct sk_buff *skb; + int err = -ENOBUFS; + ++ if (fdb->dst) { ++ int event; ++ struct br_fdb_event fdb_event; ++ ++ if (type == RTM_NEWNEIGH) ++ event = BR_FDB_EVENT_ADD; ++ else ++ event = BR_FDB_EVENT_DEL; ++ ++ fdb_event.dev = fdb->dst->dev; ++ ether_addr_copy(fdb_event.addr, fdb->key.addr.addr); ++ fdb_event.is_local = fdb->is_local; ++ atomic_notifier_call_chain(&br_fdb_notifier_list, ++ event, ++ (void *)&fdb_event); ++ } ++ + if (swdev_notify) + br_switchdev_fdb_notify(br, fdb, type); + +@@ -1212,3 +1262,41 @@ void br_fdb_clear_offload(const struct net_device *dev, u16 vid) + spin_unlock_bh(&p->br->hash_lock); + } + EXPORT_SYMBOL_GPL(br_fdb_clear_offload); ++ ++/* Refresh FDB entries for bridge packets being forwarded by offload engines */ ++void br_refresh_fdb_entry(struct net_device *dev, const char *addr) ++{ ++ struct net_bridge_port *p = br_port_get_rcu(dev); ++ ++ if (!p || p->state == BR_STATE_DISABLED) ++ return; ++ ++ if (!is_valid_ether_addr(addr)) { ++ pr_info("bridge: Attempt to refresh with invalid ether address %pM\n", ++ addr); ++ return; ++ } ++ ++ rcu_read_lock(); ++ br_fdb_update(p->br, p, addr, 0, true); ++ rcu_read_unlock(); ++} ++EXPORT_SYMBOL_GPL(br_refresh_fdb_entry); ++ ++/* Look up the MAC address in the device's bridge fdb table */ ++struct net_bridge_fdb_entry *br_fdb_has_entry(struct net_device *dev, ++ const char *addr, __u16 vid) ++{ ++ struct net_bridge_port *p = br_port_get_rcu(dev); ++ struct net_bridge_fdb_entry *fdb; ++ ++ if (!p || p->state == BR_STATE_DISABLED) ++ return NULL; ++ ++ rcu_read_lock(); ++ fdb = fdb_find_rcu(&p->br->fdb_hash_tbl, addr, vid); ++ rcu_read_unlock(); ++ ++ return fdb; ++} ++EXPORT_SYMBOL_GPL(br_fdb_has_entry); +--- a/net/bridge/br_private.h ++++ b/net/bridge/br_private.h +@@ -1269,4 +1269,7 @@ void br_do_proxy_suppress_arp(struct sk_ + void br_do_suppress_nd(struct sk_buff *skb, struct net_bridge *br, + u16 vid, struct net_bridge_port *p, struct nd_msg *msg); + struct nd_msg *br_is_nd_neigh_msg(struct sk_buff *skb, struct nd_msg *m); ++ ++#define __br_get(__hook, __default, __args ...) \ ++ (__hook ? (__hook(__args)) : (__default)) + #endif diff --git a/target/linux/ipq40xx/patches-5.4/996-add-qca-ssdk-support.patch b/target/linux/ipq40xx/patches-5.4/996-add-qca-ssdk-support.patch new file mode 100644 index 000000000..412b6a271 --- /dev/null +++ b/target/linux/ipq40xx/patches-5.4/996-add-qca-ssdk-support.patch @@ -0,0 +1,109 @@ +--- a/include/linux/switch.h ++++ b/include/linux/switch.h +@@ -45,6 +45,9 @@ enum switch_port_speed { + SWITCH_PORT_SPEED_10 = 10, + SWITCH_PORT_SPEED_100 = 100, + SWITCH_PORT_SPEED_1000 = 1000, ++ SWITCH_PORT_SPEED_2500 = 2500, ++ SWITCH_PORT_SPEED_5000 = 5000, ++ SWITCH_PORT_SPEED_10000 = 10000, + }; + + struct switch_port_link { +@@ -83,6 +86,10 @@ struct switch_port_stats { + */ + struct switch_dev_ops { + struct switch_attrlist attr_global, attr_port, attr_vlan; ++ struct switch_attrlist attr_reg; ++ ++ int (*get_reg_val)(struct switch_dev *dev, int reg, int *val); ++ int (*set_reg_val)(struct switch_dev *dev, int reg, int val); + + int (*get_vlan_ports)(struct switch_dev *dev, struct switch_val *val); + int (*set_vlan_ports)(struct switch_dev *dev, struct switch_val *val); +@@ -146,6 +153,12 @@ struct switch_portmap { + const char *s; + }; + ++struct switch_ext { ++ const char *option_name; ++ const char *option_value; ++ struct switch_ext *next; ++}; ++ + struct switch_val { + const struct switch_attr *attr; + unsigned int port_vlan; +@@ -155,6 +168,7 @@ struct switch_val { + u32 i; + struct switch_port *ports; + struct switch_port_link *link; ++ struct switch_ext *ext_val; + } value; + }; + +--- a/include/uapi/linux/switch.h ++++ b/include/uapi/linux/switch.h +@@ -47,13 +47,17 @@ enum { + SWITCH_ATTR_OP_NAME, + SWITCH_ATTR_OP_PORT, + SWITCH_ATTR_OP_VLAN, ++ SWITCH_ATTR_OP_REG, + SWITCH_ATTR_OP_VALUE_INT, + SWITCH_ATTR_OP_VALUE_STR, + SWITCH_ATTR_OP_VALUE_PORTS, + SWITCH_ATTR_OP_VALUE_LINK, ++ SWITCH_ATTR_OP_VALUE_EXT, + SWITCH_ATTR_OP_DESCRIPTION, + /* port lists */ + SWITCH_ATTR_PORT, ++ /* switch_ext attribute */ ++ SWITCH_ATTR_EXT, + SWITCH_ATTR_MAX + }; + +@@ -78,7 +82,10 @@ enum { + SWITCH_CMD_SET_PORT, + SWITCH_CMD_LIST_VLAN, + SWITCH_CMD_GET_VLAN, +- SWITCH_CMD_SET_VLAN ++ SWITCH_CMD_SET_VLAN, ++ SWITCH_CMD_LIST_REG, ++ SWITCH_CMD_GET_REG, ++ SWITCH_CMD_SET_REG, + }; + + /* data types */ +@@ -88,6 +95,7 @@ enum switch_val_type { + SWITCH_TYPE_STRING, + SWITCH_TYPE_PORTS, + SWITCH_TYPE_LINK, ++ SWITCH_TYPE_EXT, + SWITCH_TYPE_NOVAL, + }; + +@@ -113,6 +121,14 @@ enum { + SWITCH_LINK_ATTR_MAX, + }; + ++/* switch_ext nested attributes */ ++enum { ++ SWITCH_EXT_UNSPEC, ++ SWITCH_EXT_NAME, ++ SWITCH_EXT_VALUE, ++ SWITCH_EXT_ATTR_MAX ++}; ++ + #define SWITCH_ATTR_DEFAULTS_OFFSET 0x1000 + + +--- a/include/net/ip_fib.h ++++ b/include/net/ip_fib.h +@@ -107,6 +107,7 @@ struct fib_nh { + #ifdef CONFIG_IP_ROUTE_CLASSID + __u32 nh_tclassid; + #endif ++ __be32 nh_gw; /* QCA SSDK Support */ + __be32 nh_saddr; + int nh_saddr_genid; + #define fib_nh_family nh_common.nhc_family