1
0
Fork 0
mirror of https://github.com/Ysurac/openmptcprouter.git synced 2025-03-09 15:40:20 +00:00
This commit is contained in:
suyuan168 2022-06-24 11:01:39 +08:00
parent 281533d007
commit a3e52ec5d0
4 changed files with 902 additions and 0 deletions

View file

@ -0,0 +1,45 @@
From 42b508d91b7f51b054f383e3aa42089ccab9300d Mon Sep 17 00:00:00 2001
From: Chen Minqiang <ptpt52@gmail.com>
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 <chunkeey@googlemail.com>
Signed-off-by: Chen Minqiang <ptpt52@gmail.com>
---
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 {

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,53 @@
From: William <gw826943555@qq.com>
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 <gw826943555@qq.com>
---
--- 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),
{ }
};