From a3e52ec5d07d6d59eee7b5bb84463872e2916c35 Mon Sep 17 00:00:00 2001 From: suyuan168 <175338101@qq.com> Date: Fri, 24 Jun 2022 11:01:39 +0800 Subject: [PATCH] add qca --- ...essedma-disable-default-vlan-tagging.patch | 45 ++ .../patches-5.4/995-add-qca-rfs-support.patch | 695 ++++++++++++++++++ .../996-add-qca-ssdk-support.patch | 109 +++ .../999-ipq40xx-unlock-cpu-frequency.patch | 53 ++ 4 files changed, 902 insertions(+) create mode 100644 root/target/linux/ipq40xx/patches-5.4/901-essedma-disable-default-vlan-tagging.patch create mode 100644 root/target/linux/ipq40xx/patches-5.4/995-add-qca-rfs-support.patch create mode 100644 root/target/linux/ipq40xx/patches-5.4/996-add-qca-ssdk-support.patch create mode 100644 root/target/linux/ipq40xx/patches-5.4/999-ipq40xx-unlock-cpu-frequency.patch diff --git a/root/target/linux/ipq40xx/patches-5.4/901-essedma-disable-default-vlan-tagging.patch b/root/target/linux/ipq40xx/patches-5.4/901-essedma-disable-default-vlan-tagging.patch new file mode 100644 index 00000000..824ba8a8 --- /dev/null +++ b/root/target/linux/ipq40xx/patches-5.4/901-essedma-disable-default-vlan-tagging.patch @@ -0,0 +1,45 @@ +From 42b508d91b7f51b054f383e3aa42089ccab9300d Mon Sep 17 00:00:00 2001 +From: Chen Minqiang +Date: Thu, 15 Mar 2018 05:33:46 +0800 +Subject: [PATCH] essedma: disable default vlan tagging + +The essedma driver has its own unique take on VLAN management +and its configuration. In the original SDK, each VLAN is +assigned one virtual ethernet netdev. + +However, this is non-standard. So, this patch does away +with the default_vlan_tag property the driver is using +and therefore forces the user to use the kernel's vlan +feature. + +This patch also removes the "qcom,poll_required = <1>;" from +the essedma node. + +Signed-off-by: Christian Lamparter +Signed-off-by: Chen Minqiang +--- + arch/arm/boot/dts/qcom-ipq4019.dtsi | 5 ++--- + drivers/net/ethernet/qualcomm/essedma/edma.c | 14 +++++--------- + 2 files changed, 7 insertions(+), 12 deletions(-) + +--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi +@@ -666,8 +666,7 @@ + qcom,page-mode = <0>; + qcom,rx_head_buf_size = <1540>; + qcom,mdio_supported; +- qcom,poll_required = <1>; +- qcom,num_gmac = <2>; ++ qcom,num_gmac = <1>; + interrupts = <0 65 IRQ_TYPE_EDGE_RISING + 0 66 IRQ_TYPE_EDGE_RISING + 0 67 IRQ_TYPE_EDGE_RISING +@@ -705,7 +704,7 @@ + + gmac0: gmac0 { + local-mac-address = [00 00 00 00 00 00]; +- vlan_tag = <1 0x1f>; ++ vlan_tag = <1 0x3f>; + }; + + gmac1: gmac1 { diff --git a/root/target/linux/ipq40xx/patches-5.4/995-add-qca-rfs-support.patch b/root/target/linux/ipq40xx/patches-5.4/995-add-qca-rfs-support.patch new file mode 100644 index 00000000..fd20c624 --- /dev/null +++ b/root/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 +@@ -2596,6 +2596,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 +@@ -728,6 +728,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 +@@ -3357,6 +3357,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 +@@ -695,6 +699,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: +@@ -731,6 +737,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. +@@ -785,6 +793,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/root/target/linux/ipq40xx/patches-5.4/996-add-qca-ssdk-support.patch b/root/target/linux/ipq40xx/patches-5.4/996-add-qca-ssdk-support.patch new file mode 100644 index 00000000..412b6a27 --- /dev/null +++ b/root/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 diff --git a/root/target/linux/ipq40xx/patches-5.4/999-ipq40xx-unlock-cpu-frequency.patch b/root/target/linux/ipq40xx/patches-5.4/999-ipq40xx-unlock-cpu-frequency.patch new file mode 100644 index 00000000..cc5e195d --- /dev/null +++ b/root/target/linux/ipq40xx/patches-5.4/999-ipq40xx-unlock-cpu-frequency.patch @@ -0,0 +1,53 @@ +From: William +Subject: [PATCH] ipq40xx: improve CPU clock +Date: Tue, 15 Dec 2020 15:26:35 +0800 + +This patch will match the clock-latency-ns values in the device tree +for those found inside the OEM device tree and kernel source code and +unlock 896Mhz CPU operating points. + +Signed-off-by: William +--- +--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi +@@ -124,20 +124,24 @@ + + opp-48000000 { + opp-hz = /bits/ 64 <48000000>; +- clock-latency-ns = <256000>; ++ clock-latency-ns = <100000>; + }; + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; +- clock-latency-ns = <256000>; ++ clock-latency-ns = <100000>; + }; + opp-500000000 { + opp-hz = /bits/ 64 <500000000>; +- clock-latency-ns = <256000>; ++ clock-latency-ns = <100000>; + }; + opp-716000000 { + opp-hz = /bits/ 64 <716000000>; +- clock-latency-ns = <256000>; ++ clock-latency-ns = <100000>; + }; ++ opp-896000000 { ++ opp-hz = /bits/ 64 <896000000>; ++ clock-latency-ns = <100000>; ++ }; + }; + + memory { +--- a/drivers/clk/qcom/gcc-ipq4019.c ++++ b/drivers/clk/qcom/gcc-ipq4019.c +@@ -579,6 +579,9 @@ static const struct freq_tbl ftbl_gcc_ap + F(632000000, P_DDRPLLAPSS, 1, 0, 0), + F(672000000, P_DDRPLLAPSS, 1, 0, 0), + F(716000000, P_DDRPLLAPSS, 1, 0, 0), ++ F(768000000, P_DDRPLLAPSS, 1, 0, 0), ++ F(823000000, P_DDRPLLAPSS, 1, 0, 0), ++ F(896000000, P_DDRPLLAPSS, 1, 0, 0), + { } + }; +