diff options
Diffstat (limited to 'target/linux/layerscape/patches-4.9/202-core-linux-support-layerscape.patch')
-rw-r--r-- | target/linux/layerscape/patches-4.9/202-core-linux-support-layerscape.patch | 982 |
1 files changed, 964 insertions, 18 deletions
diff --git a/target/linux/layerscape/patches-4.9/202-core-linux-support-layerscape.patch b/target/linux/layerscape/patches-4.9/202-core-linux-support-layerscape.patch index 3484fc398e..06777a3769 100644 --- a/target/linux/layerscape/patches-4.9/202-core-linux-support-layerscape.patch +++ b/target/linux/layerscape/patches-4.9/202-core-linux-support-layerscape.patch @@ -1,7 +1,7 @@ -From 67a2eceebe9dcd92a1a5f3e912340c8975c84434 Mon Sep 17 00:00:00 2001 +From f339945a8e81fff22df95284e142b79c37fd2333 Mon Sep 17 00:00:00 2001 From: Yangbo Lu <yangbo.lu@nxp.com> -Date: Wed, 17 Jan 2018 14:50:41 +0800 -Subject: [PATCH 02/30] core-linux: support layerscape +Date: Thu, 5 Jul 2018 16:07:09 +0800 +Subject: [PATCH 02/32] core-linux: support layerscape This is an integrated patch for layerscape core-linux support. @@ -17,21 +17,43 @@ Signed-off-by: stephen hemminger <stephen@networkplumber.org> Signed-off-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> --- - drivers/base/devres.c | 66 ++++++++++++++++++++++++++++ - drivers/base/soc.c | 70 +++++++++++++++++++++++++++++ - include/linux/device.h | 19 ++++++++ - include/linux/fsl/svr.h | 97 +++++++++++++++++++++++++++++++++++++++++ - include/linux/fsl_devices.h | 3 ++ - include/linux/netdev_features.h | 2 + - include/linux/netdevice.h | 4 ++ - include/linux/skbuff.h | 2 + - include/linux/sys_soc.h | 3 ++ - include/uapi/linux/if_ether.h | 1 + - net/core/dev.c | 13 +++++- - net/core/skbuff.c | 29 +++++++++++- - net/sched/sch_generic.c | 7 +++ - 13 files changed, 313 insertions(+), 3 deletions(-) + drivers/base/devres.c | 66 ++++++ + drivers/base/soc.c | 70 ++++++ + .../net/ethernet/mellanox/mlxsw/spectrum.c | 2 +- + .../mellanox/mlxsw/spectrum_switchdev.c | 2 +- + drivers/net/ethernet/rocker/rocker_ofdpa.c | 4 +- + include/linux/device.h | 19 ++ + include/linux/dma-mapping.h | 5 + + include/linux/fsl/svr.h | 97 ++++++++ + include/linux/fsl_devices.h | 3 + + include/linux/irqdesc.h | 4 + + include/linux/irqdomain.h | 13 +- + include/linux/netdev_features.h | 2 + + include/linux/netdevice.h | 10 +- + include/linux/skbuff.h | 2 + + include/linux/sys_soc.h | 3 + + include/net/switchdev.h | 8 +- + include/uapi/linux/if_ether.h | 1 + + kernel/irq/Kconfig | 11 + + kernel/irq/Makefile | 1 + + kernel/irq/debugfs.c | 215 ++++++++++++++++++ + kernel/irq/internals.h | 22 ++ + kernel/irq/irqdesc.c | 1 + + kernel/irq/irqdomain.c | 171 ++++++++++---- + kernel/irq/manage.c | 1 + + kernel/irq/msi.c | 2 +- + net/bridge/br.c | 4 +- + net/bridge/br_fdb.c | 2 + + net/bridge/br_private.h | 7 + + net/bridge/br_switchdev.c | 33 +++ + net/core/dev.c | 30 ++- + net/core/net-sysfs.c | 20 +- + net/core/rtnetlink.c | 4 +- + net/core/skbuff.c | 29 ++- + net/sched/sch_generic.c | 7 + + 34 files changed, 809 insertions(+), 62 deletions(-) create mode 100644 include/linux/fsl/svr.h + create mode 100644 kernel/irq/debugfs.c --- a/drivers/base/devres.c +++ b/drivers/base/devres.c @@ -195,6 +217,43 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + return NULL; +} +EXPORT_SYMBOL_GPL(soc_device_match); +--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +@@ -859,7 +859,7 @@ mlxsw_sp_port_get_sw_stats64(const struc + return 0; + } + +-static bool mlxsw_sp_port_has_offload_stats(int attr_id) ++static bool mlxsw_sp_port_has_offload_stats(const struct net_device *dev, int attr_id) + { + switch (attr_id) { + case IFLA_OFFLOAD_XSTATS_CPU_HIT: +--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +@@ -1405,7 +1405,7 @@ static void mlxsw_sp_fdb_call_notifiers( + if (learning_sync) { + info.addr = mac; + info.vid = vid; +- notifier_type = adding ? SWITCHDEV_FDB_ADD : SWITCHDEV_FDB_DEL; ++ notifier_type = adding ? SWITCHDEV_FDB_ADD_TO_BRIDGE : SWITCHDEV_FDB_DEL_TO_BRIDGE; + call_switchdev_notifiers(notifier_type, dev, &info.info); + } + } +--- a/drivers/net/ethernet/rocker/rocker_ofdpa.c ++++ b/drivers/net/ethernet/rocker/rocker_ofdpa.c +@@ -1939,10 +1939,10 @@ static void ofdpa_port_fdb_learn_work(st + + rtnl_lock(); + if (learned && removing) +- call_switchdev_notifiers(SWITCHDEV_FDB_DEL, ++ call_switchdev_notifiers(SWITCHDEV_FDB_DEL_TO_BRIDGE, + lw->ofdpa_port->dev, &info.info); + else if (learned && !removing) +- call_switchdev_notifiers(SWITCHDEV_FDB_ADD, ++ call_switchdev_notifiers(SWITCHDEV_FDB_ADD_TO_BRIDGE, + lw->ofdpa_port->dev, &info.info); + rtnl_unlock(); + --- a/include/linux/device.h +++ b/include/linux/device.h @@ -688,6 +688,25 @@ void __iomem *devm_ioremap_resource(stru @@ -223,6 +282,20 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> static inline int devm_add_action_or_reset(struct device *dev, void (*action)(void *), void *data) { +--- a/include/linux/dma-mapping.h ++++ b/include/linux/dma-mapping.h +@@ -164,6 +164,11 @@ int dma_mmap_from_coherent(struct device + + #ifdef CONFIG_HAS_DMA + #include <asm/dma-mapping.h> ++static inline void set_dma_ops(struct device *dev, ++ struct dma_map_ops *dma_ops) ++{ ++ dev->archdata.dma_ops = dma_ops; ++} + #else + /* + * Define the dma api to allow compilation but not linking of --- /dev/null +++ b/include/linux/fsl/svr.h @@ -0,0 +1,97 @@ @@ -336,6 +409,76 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> unsigned check_phy_clk_valid:1; /* register save area for suspend/resume */ +--- a/include/linux/irqdesc.h ++++ b/include/linux/irqdesc.h +@@ -46,6 +46,7 @@ struct pt_regs; + * @rcu: rcu head for delayed free + * @kobj: kobject used to represent this struct in sysfs + * @dir: /proc/irq/ procfs entry ++ * @debugfs_file: dentry for the debugfs file + * @name: flow handler name for /proc/interrupts output + */ + struct irq_desc { +@@ -88,6 +89,9 @@ struct irq_desc { + #ifdef CONFIG_PROC_FS + struct proc_dir_entry *dir; + #endif ++#ifdef CONFIG_GENERIC_IRQ_DEBUGFS ++ struct dentry *debugfs_file; ++#endif + #ifdef CONFIG_SPARSE_IRQ + struct rcu_head rcu; + struct kobject kobj; +--- a/include/linux/irqdomain.h ++++ b/include/linux/irqdomain.h +@@ -138,6 +138,7 @@ struct irq_domain_chip_generic; + * setting up one or more generic chips for interrupt controllers + * drivers using the generic chip library which uses this pointer. + * @parent: Pointer to parent irq_domain to support hierarchy irq_domains ++ * @debugfs_file: dentry for the domain debugfs file + * + * Revmap data, used internally by irq_domain + * @revmap_direct_max_irq: The largest hwirq that can be set for controllers that +@@ -160,6 +161,9 @@ struct irq_domain { + #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY + struct irq_domain *parent; + #endif ++#ifdef CONFIG_GENERIC_IRQ_DEBUGFS ++ struct dentry *debugfs_file; ++#endif + + /* reverse map data. The linear map gets appended to the irq_domain */ + irq_hw_number_t hwirq_max; +@@ -174,8 +178,8 @@ enum { + /* Irq domain is hierarchical */ + IRQ_DOMAIN_FLAG_HIERARCHY = (1 << 0), + +- /* Core calls alloc/free recursive through the domain hierarchy. */ +- IRQ_DOMAIN_FLAG_AUTO_RECURSIVE = (1 << 1), ++ /* Irq domain name was allocated in __irq_domain_add() */ ++ IRQ_DOMAIN_NAME_ALLOCATED = (1 << 6), + + /* Irq domain is an IPI domain with virq per cpu */ + IRQ_DOMAIN_FLAG_IPI_PER_CPU = (1 << 2), +@@ -231,6 +235,9 @@ static inline bool is_fwnode_irqchip(str + return fwnode && fwnode->type == FWNODE_IRQCHIP; + } + ++extern void irq_domain_update_bus_token(struct irq_domain *domain, ++ enum irq_domain_bus_token bus_token); ++ + static inline + struct irq_domain *irq_find_matching_fwnode(struct fwnode_handle *fwnode, + enum irq_domain_bus_token bus_token) +@@ -403,7 +410,7 @@ static inline int irq_domain_alloc_irqs( + NULL); + } + +-extern int irq_domain_alloc_irqs_recursive(struct irq_domain *domain, ++extern int irq_domain_alloc_irqs_hierarchy(struct irq_domain *domain, + unsigned int irq_base, + unsigned int nr_irqs, void *arg); + extern int irq_domain_set_hwirq_and_chip(struct irq_domain *domain, --- a/include/linux/netdev_features.h +++ b/include/linux/netdev_features.h @@ -74,6 +74,7 @@ enum { @@ -356,6 +499,24 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> for_each_set_bit(bit, (unsigned long *)mask_addr, NETDEV_FEATURE_COUNT) --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h +@@ -930,7 +930,7 @@ struct netdev_xdp { + * 3. Update dev->stats asynchronously and atomically, and define + * neither operation. + * +- * bool (*ndo_has_offload_stats)(int attr_id) ++ * bool (*ndo_has_offload_stats)(const struct net_device *dev, int attr_id) + * Return true if this device supports offload stats of this attr_id. + * + * int (*ndo_get_offload_stats)(int attr_id, const struct net_device *dev, +@@ -1167,7 +1167,7 @@ struct net_device_ops { + + struct rtnl_link_stats64* (*ndo_get_stats64)(struct net_device *dev, + struct rtnl_link_stats64 *storage); +- bool (*ndo_has_offload_stats)(int attr_id); ++ bool (*ndo_has_offload_stats)(const struct net_device *dev, int attr_id); + int (*ndo_get_offload_stats)(int attr_id, + const struct net_device *dev, + void *attr_data); @@ -1509,6 +1509,8 @@ enum netdev_priv_flags { * @if_port: Selectable AUI, TP, ... * @dma: DMA channel @@ -374,6 +535,15 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> unsigned short type; unsigned short hard_header_len; unsigned short min_header_len; +@@ -1938,6 +1942,8 @@ int netdev_set_prio_tc_map(struct net_de + return 0; + } + ++int netdev_txq_to_tc(struct net_device *dev, unsigned int txq); ++ + static inline + void netdev_reset_tc(struct net_device *dev) + { --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -903,6 +903,7 @@ void kfree_skb(struct sk_buff *skb); @@ -409,6 +579,37 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> +const struct soc_device_attribute *soc_device_match( + const struct soc_device_attribute *matches); #endif /* __SOC_BUS_H */ +--- a/include/net/switchdev.h ++++ b/include/net/switchdev.h +@@ -46,6 +46,7 @@ enum switchdev_attr_id { + SWITCHDEV_ATTR_ID_PORT_PARENT_ID, + SWITCHDEV_ATTR_ID_PORT_STP_STATE, + SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS, ++ SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS_SUPPORT, + SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME, + SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING, + }; +@@ -60,6 +61,7 @@ struct switchdev_attr { + struct netdev_phys_item_id ppid; /* PORT_PARENT_ID */ + u8 stp_state; /* PORT_STP_STATE */ + unsigned long brport_flags; /* PORT_BRIDGE_FLAGS */ ++ unsigned long brport_flags_support; /* PORT_BRIDGE_FLAGS_SUPPORT */ + clock_t ageing_time; /* BRIDGE_AGEING_TIME */ + bool vlan_filtering; /* BRIDGE_VLAN_FILTERING */ + } u; +@@ -149,8 +151,10 @@ struct switchdev_ops { + }; + + enum switchdev_notifier_type { +- SWITCHDEV_FDB_ADD = 1, +- SWITCHDEV_FDB_DEL, ++ SWITCHDEV_FDB_ADD_TO_BRIDGE = 1, ++ SWITCHDEV_FDB_DEL_TO_BRIDGE, ++ SWITCHDEV_FDB_ADD_TO_DEVICE, ++ SWITCHDEV_FDB_DEL_TO_DEVICE, + }; + + struct switchdev_notifier_info { --- a/include/uapi/linux/if_ether.h +++ b/include/uapi/linux/if_ether.h @@ -36,6 +36,7 @@ @@ -419,9 +620,684 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> /* * These are the defined Ethernet Protocol ID's. +--- a/kernel/irq/Kconfig ++++ b/kernel/irq/Kconfig +@@ -108,4 +108,15 @@ config SPARSE_IRQ + + If you don't know what to do here, say N. + ++config GENERIC_IRQ_DEBUGFS ++ bool "Expose irq internals in debugfs" ++ depends on DEBUG_FS ++ default n ++ ---help--- ++ ++ Exposes internal state information through debugfs. Mostly for ++ developers and debugging of hard to diagnose interrupt problems. ++ ++ If you don't know what to do here, say N. ++ + endmenu +--- a/kernel/irq/Makefile ++++ b/kernel/irq/Makefile +@@ -10,3 +10,4 @@ obj-$(CONFIG_PM_SLEEP) += pm.o + obj-$(CONFIG_GENERIC_MSI_IRQ) += msi.o + obj-$(CONFIG_GENERIC_IRQ_IPI) += ipi.o + obj-$(CONFIG_SMP) += affinity.o ++obj-$(CONFIG_GENERIC_IRQ_DEBUGFS) += debugfs.o +--- /dev/null ++++ b/kernel/irq/debugfs.c +@@ -0,0 +1,215 @@ ++/* ++ * Copyright 2017 Thomas Gleixner <tglx@linutronix.de> ++ * ++ * This file is licensed under the GPL V2. ++ */ ++#include <linux/debugfs.h> ++#include <linux/irqdomain.h> ++#include <linux/irq.h> ++ ++#include "internals.h" ++ ++static struct dentry *irq_dir; ++ ++struct irq_bit_descr { ++ unsigned int mask; ++ char *name; ++}; ++#define BIT_MASK_DESCR(m) { .mask = m, .name = #m } ++ ++static void irq_debug_show_bits(struct seq_file *m, int ind, unsigned int state, ++ const struct irq_bit_descr *sd, int size) ++{ ++ int i; ++ ++ for (i = 0; i < size; i++, sd++) { ++ if (state & sd->mask) ++ seq_printf(m, "%*s%s\n", ind + 12, "", sd->name); ++ } ++} ++ ++#ifdef CONFIG_SMP ++static void irq_debug_show_masks(struct seq_file *m, struct irq_desc *desc) ++{ ++ struct irq_data *data = irq_desc_get_irq_data(desc); ++ struct cpumask *msk; ++ ++ msk = irq_data_get_affinity_mask(data); ++ seq_printf(m, "affinity: %*pbl\n", cpumask_pr_args(msk)); ++#ifdef CONFIG_GENERIC_PENDING_IRQ ++ msk = desc->pending_mask; ++ seq_printf(m, "pending: %*pbl\n", cpumask_pr_args(msk)); ++#endif ++} ++#else ++static void irq_debug_show_masks(struct seq_file *m, struct irq_desc *desc) { } ++#endif ++ ++static const struct irq_bit_descr irqchip_flags[] = { ++ BIT_MASK_DESCR(IRQCHIP_SET_TYPE_MASKED), ++ BIT_MASK_DESCR(IRQCHIP_EOI_IF_HANDLED), ++ BIT_MASK_DESCR(IRQCHIP_MASK_ON_SUSPEND), ++ BIT_MASK_DESCR(IRQCHIP_ONOFFLINE_ENABLED), ++ BIT_MASK_DESCR(IRQCHIP_SKIP_SET_WAKE), ++ BIT_MASK_DESCR(IRQCHIP_ONESHOT_SAFE), ++ BIT_MASK_DESCR(IRQCHIP_EOI_THREADED), ++}; ++ ++static void ++irq_debug_show_chip(struct seq_file *m, struct irq_data *data, int ind) ++{ ++ struct irq_chip *chip = data->chip; ++ ++ if (!chip) { ++ seq_printf(m, "chip: None\n"); ++ return; ++ } ++ seq_printf(m, "%*schip: %s\n", ind, "", chip->name); ++ seq_printf(m, "%*sflags: 0x%lx\n", ind + 1, "", chip->flags); ++ irq_debug_show_bits(m, ind, chip->flags, irqchip_flags, ++ ARRAY_SIZE(irqchip_flags)); ++} ++ ++static void ++irq_debug_show_data(struct seq_file *m, struct irq_data *data, int ind) ++{ ++ seq_printf(m, "%*sdomain: %s\n", ind, "", ++ data->domain ? data->domain->name : ""); ++ seq_printf(m, "%*shwirq: 0x%lx\n", ind + 1, "", data->hwirq); ++ irq_debug_show_chip(m, data, ind + 1); ++#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY ++ if (!data->parent_data) ++ return; ++ seq_printf(m, "%*sparent:\n", ind + 1, ""); ++ irq_debug_show_data(m, data->parent_data, ind + 4); ++#endif ++} ++ ++static const struct irq_bit_descr irqdata_states[] = { ++ BIT_MASK_DESCR(IRQ_TYPE_EDGE_RISING), ++ BIT_MASK_DESCR(IRQ_TYPE_EDGE_FALLING), ++ BIT_MASK_DESCR(IRQ_TYPE_LEVEL_HIGH), ++ BIT_MASK_DESCR(IRQ_TYPE_LEVEL_LOW), ++ BIT_MASK_DESCR(IRQD_LEVEL), ++ ++ BIT_MASK_DESCR(IRQD_ACTIVATED), ++ BIT_MASK_DESCR(IRQD_IRQ_STARTED), ++ BIT_MASK_DESCR(IRQD_IRQ_DISABLED), ++ BIT_MASK_DESCR(IRQD_IRQ_MASKED), ++ BIT_MASK_DESCR(IRQD_IRQ_INPROGRESS), ++ ++ BIT_MASK_DESCR(IRQD_PER_CPU), ++ BIT_MASK_DESCR(IRQD_NO_BALANCING), ++ ++ BIT_MASK_DESCR(IRQD_MOVE_PCNTXT), ++ BIT_MASK_DESCR(IRQD_AFFINITY_SET), ++ BIT_MASK_DESCR(IRQD_SETAFFINITY_PENDING), ++ BIT_MASK_DESCR(IRQD_AFFINITY_MANAGED), ++ BIT_MASK_DESCR(IRQD_MANAGED_SHUTDOWN), ++ ++ BIT_MASK_DESCR(IRQD_FORWARDED_TO_VCPU), ++ ++ BIT_MASK_DESCR(IRQD_WAKEUP_STATE), ++ BIT_MASK_DESCR(IRQD_WAKEUP_ARMED), ++}; ++ ++static const struct irq_bit_descr irqdesc_states[] = { ++ BIT_MASK_DESCR(_IRQ_NOPROBE), ++ BIT_MASK_DESCR(_IRQ_NOREQUEST), ++ BIT_MASK_DESCR(_IRQ_NOTHREAD), ++ BIT_MASK_DESCR(_IRQ_NOAUTOEN), ++ BIT_MASK_DESCR(_IRQ_NESTED_THREAD), ++ BIT_MASK_DESCR(_IRQ_PER_CPU_DEVID), ++ BIT_MASK_DESCR(_IRQ_IS_POLLED), ++ BIT_MASK_DESCR(_IRQ_DISABLE_UNLAZY), ++}; ++ ++static const struct irq_bit_descr irqdesc_istates[] = { ++ BIT_MASK_DESCR(IRQS_AUTODETECT), ++ BIT_MASK_DESCR(IRQS_SPURIOUS_DISABLED), ++ BIT_MASK_DESCR(IRQS_POLL_INPROGRESS), ++ BIT_MASK_DESCR(IRQS_ONESHOT), ++ BIT_MASK_DESCR(IRQS_REPLAY), ++ BIT_MASK_DESCR(IRQS_WAITING), ++ BIT_MASK_DESCR(IRQS_PENDING), ++ BIT_MASK_DESCR(IRQS_SUSPENDED), ++}; ++ ++ ++static int irq_debug_show(struct seq_file *m, void *p) ++{ ++ struct irq_desc *desc = m->private; ++ struct irq_data *data; ++ ++ raw_spin_lock_irq(&desc->lock); ++ data = irq_desc_get_irq_data(desc); ++ seq_printf(m, "handler: %pf\n", desc->handle_irq); ++ seq_printf(m, "status: 0x%08x\n", desc->status_use_accessors); ++ irq_debug_show_bits(m, 0, desc->status_use_accessors, irqdesc_states, ++ ARRAY_SIZE(irqdesc_states)); ++ seq_printf(m, "istate: 0x%08x\n", desc->istate); ++ irq_debug_show_bits(m, 0, desc->istate, irqdesc_istates, ++ ARRAY_SIZE(irqdesc_istates)); ++ seq_printf(m, "ddepth: %u\n", desc->depth); ++ seq_printf(m, "wdepth: %u\n", desc->wake_depth); ++ seq_printf(m, "dstate: 0x%08x\n", irqd_get(data)); ++ irq_debug_show_bits(m, 0, irqd_get(data), irqdata_states, ++ ARRAY_SIZE(irqdata_states)); ++ seq_printf(m, "node: %d\n", irq_data_get_node(data)); ++ irq_debug_show_masks(m, desc); ++ irq_debug_show_data(m, data, 0); ++ raw_spin_unlock_irq(&desc->lock); ++ return 0; ++} ++ ++static int irq_debug_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, irq_debug_show, inode->i_private); ++} ++ ++static const struct file_operations dfs_irq_ops = { ++ .open = irq_debug_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++}; ++ ++void irq_add_debugfs_entry(unsigned int irq, struct irq_desc *desc) ++{ ++ char name [10]; ++ ++ if (!irq_dir || !desc || desc->debugfs_file) ++ return; ++ ++ sprintf(name, "%d", irq); ++ desc->debugfs_file = debugfs_create_file(name, 0444, irq_dir, desc, ++ &dfs_irq_ops); ++} ++ ++void irq_remove_debugfs_entry(struct irq_desc *desc) ++{ ++ if (desc->debugfs_file) ++ debugfs_remove(desc->debugfs_file); ++} ++ ++static int __init irq_debugfs_init(void) ++{ ++ struct dentry *root_dir; ++ int irq; ++ ++ root_dir = debugfs_create_dir("irq", NULL); ++ if (!root_dir) ++ return -ENOMEM; ++ ++ irq_domain_debugfs_init(root_dir); ++ ++ irq_dir = debugfs_create_dir("irqs", root_dir); ++ ++ irq_lock_sparse(); ++ for_each_active_irq(irq) ++ irq_add_debugfs_entry(irq, irq_to_desc(irq)); ++ irq_unlock_sparse(); ++ ++ return 0; ++} ++__initcall(irq_debugfs_init); +--- a/kernel/irq/internals.h ++++ b/kernel/irq/internals.h +@@ -169,6 +169,11 @@ irq_put_desc_unlock(struct irq_desc *des + + #define __irqd_to_state(d) ACCESS_PRIVATE((d)->common, state_use_accessors) + ++static inline unsigned int irqd_get(struct irq_data *d) ++{ ++ return __irqd_to_state(d); ++} ++ + /* + * Manipulation functions for irq_data.state + */ +@@ -226,3 +231,20 @@ irq_pm_install_action(struct irq_desc *d + static inline void + irq_pm_remove_action(struct irq_desc *desc, struct irqaction *action) { } + #endif ++ ++#ifdef CONFIG_GENERIC_IRQ_DEBUGFS ++void irq_add_debugfs_entry(unsigned int irq, struct irq_desc *desc); ++void irq_remove_debugfs_entry(struct irq_desc *desc); ++# ifdef CONFIG_IRQ_DOMAIN ++void irq_domain_debugfs_init(struct dentry *root); ++# else ++static inline void irq_domain_debugfs_init(struct dentry *root); ++# endif ++#else /* CONFIG_GENERIC_IRQ_DEBUGFS */ ++static inline void irq_add_debugfs_entry(unsigned int irq, struct irq_desc *d) ++{ ++} ++static inline void irq_remove_debugfs_entry(struct irq_desc *d) ++{ ++} ++#endif /* CONFIG_GENERIC_IRQ_DEBUGFS */ +--- a/kernel/irq/irqdesc.c ++++ b/kernel/irq/irqdesc.c +@@ -394,6 +394,7 @@ static void free_desc(unsigned int irq) + { + struct irq_desc *desc = irq_to_desc(irq); + ++ irq_remove_debugfs_entry(desc); + unregister_irq_proc(irq, desc); + + /* +--- a/kernel/irq/irqdomain.c ++++ b/kernel/irq/irqdomain.c +@@ -31,6 +31,14 @@ struct irqchip_fwid { + void *data; + }; + ++#ifdef CONFIG_GENERIC_IRQ_DEBUGFS ++static void debugfs_add_domain_dir(struct irq_domain *d); ++static void debugfs_remove_domain_dir(struct irq_domain *d); ++#else ++static inline void debugfs_add_domain_dir(struct irq_domain *d) { } ++static inline void debugfs_remove_domain_dir(struct irq_domain *d) { } ++#endif ++ + /** + * irq_domain_alloc_fwnode - Allocate a fwnode_handle suitable for + * identifying an irq domain +@@ -117,6 +125,7 @@ struct irq_domain *__irq_domain_add(stru + irq_domain_check_hierarchy(domain); + + mutex_lock(&irq_domain_mutex); ++ debugfs_add_domain_dir(domain); + list_add(&domain->link, &irq_domain_list); + mutex_unlock(&irq_domain_mutex); + +@@ -136,6 +145,7 @@ EXPORT_SYMBOL_GPL(__irq_domain_add); + void irq_domain_remove(struct irq_domain *domain) + { + mutex_lock(&irq_domain_mutex); ++ debugfs_remove_domain_dir(domain); + + WARN_ON(!radix_tree_empty(&domain->revmap_tree)); + +@@ -156,6 +166,37 @@ void irq_domain_remove(struct irq_domain + } + EXPORT_SYMBOL_GPL(irq_domain_remove); + ++void irq_domain_update_bus_token(struct irq_domain *domain, ++ enum irq_domain_bus_token bus_token) ++{ ++ char *name; ++ ++ if (domain->bus_token == bus_token) ++ return; ++ ++ mutex_lock(&irq_domain_mutex); ++ ++ domain->bus_token = bus_token; ++ ++ name = kasprintf(GFP_KERNEL, "%s-%d", domain->name, bus_token); ++ if (!name) { ++ mutex_unlock(&irq_domain_mutex); ++ return; ++ } ++ ++ debugfs_remove_domain_dir(domain); ++ ++ if (domain->flags & IRQ_DOMAIN_NAME_ALLOCATED) ++ kfree(domain->name); ++ else ++ domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED; ++ ++ domain->name = name; ++ debugfs_add_domain_dir(domain); ++ ++ mutex_unlock(&irq_domain_mutex); ++} ++ + /** + * irq_domain_add_simple() - Register an irq_domain and optionally map a range of irqs + * @of_node: pointer to interrupt controller's device tree node. +@@ -1164,43 +1205,18 @@ void irq_domain_free_irqs_top(struct irq + irq_domain_free_irqs_common(domain, virq, nr_irqs); + } + +-static bool irq_domain_is_auto_recursive(struct irq_domain *domain) +-{ +- return domain->flags & IRQ_DOMAIN_FLAG_AUTO_RECURSIVE; +-} +- +-static void irq_domain_free_irqs_recursive(struct irq_domain *domain, ++static void irq_domain_free_irqs_hierarchy(struct irq_domain *domain, + unsigned int irq_base, + unsigned int nr_irqs) + { + domain->ops->free(domain, irq_base, nr_irqs); +- if (irq_domain_is_auto_recursive(domain)) { +- BUG_ON(!domain->parent); +- irq_domain_free_irqs_recursive(domain->parent, irq_base, +- nr_irqs); +- } + } + +-int irq_domain_alloc_irqs_recursive(struct irq_domain *domain, ++int irq_domain_alloc_irqs_hierarchy(struct irq_domain *domain, + unsigned int irq_base, + unsigned int nr_irqs, void *arg) + { +- int ret = 0; +- struct irq_domain *parent = domain->parent; +- bool recursive = irq_domain_is_auto_recursive(domain); +- +- BUG_ON(recursive && !parent); +- if (recursive) +- ret = irq_domain_alloc_irqs_recursive(parent, irq_base, +- nr_irqs, arg); +- if (ret < 0) +- return ret; +- +- ret = domain->ops->alloc(domain, irq_base, nr_irqs, arg); +- if (ret < 0 && recursive) +- irq_domain_free_irqs_recursive(parent, irq_base, nr_irqs); +- +- return ret; ++ return domain->ops->alloc(domain, irq_base, nr_irqs, arg); + } + + /** +@@ -1261,7 +1277,7 @@ int __irq_domain_alloc_irqs(struct irq_d + } + + mutex_lock(&irq_domain_mutex); +- ret = irq_domain_alloc_irqs_recursive(domain, virq, nr_irqs, arg); ++ ret = irq_domain_alloc_irqs_hierarchy(domain, virq, nr_irqs, arg); + if (ret < 0) { + mutex_unlock(&irq_domain_mutex); + goto out_free_irq_data; +@@ -1296,7 +1312,7 @@ void irq_domain_free_irqs(unsigned int v + mutex_lock(&irq_domain_mutex); + for (i = 0; i < nr_irqs; i++) + irq_domain_remove_irq(virq + i); +- irq_domain_free_irqs_recursive(data->domain, virq, nr_irqs); ++ irq_domain_free_irqs_hierarchy(data->domain, virq, nr_irqs); + mutex_unlock(&irq_domain_mutex); + + irq_domain_free_irq_data(virq, nr_irqs); +@@ -1316,15 +1332,11 @@ int irq_domain_alloc_irqs_parent(struct + unsigned int irq_base, unsigned int nr_irqs, + void *arg) + { +- /* irq_domain_alloc_irqs_recursive() has called parent's alloc() */ +- if (irq_domain_is_auto_recursive(domain)) +- return 0; ++ if (!domain->parent) ++ return -ENOSYS; + +- domain = domain->parent; +- if (domain) +- return irq_domain_alloc_irqs_recursive(domain, irq_base, +- nr_irqs, arg); +- return -ENOSYS; ++ return irq_domain_alloc_irqs_hierarchy(domain->parent, irq_base, ++ nr_irqs, arg); + } + EXPORT_SYMBOL_GPL(irq_domain_alloc_irqs_parent); + +@@ -1339,10 +1351,10 @@ EXPORT_SYMBOL_GPL(irq_domain_alloc_irqs_ + void irq_domain_free_irqs_parent(struct irq_domain *domain, + unsigned int irq_base, unsigned int nr_irqs) + { +- /* irq_domain_free_irqs_recursive() will call parent's free */ +- if (!irq_domain_is_auto_recursive(domain) && domain->parent) +- irq_domain_free_irqs_recursive(domain->parent, irq_base, +- nr_irqs); ++ if (!domain->parent) ++ return; ++ ++ irq_domain_free_irqs_hierarchy(domain->parent, irq_base, nr_irqs); + } + EXPORT_SYMBOL_GPL(irq_domain_free_irqs_parent); + +@@ -1448,3 +1460,78 @@ static void irq_domain_check_hierarchy(s + { + } + #endif /* CONFIG_IRQ_DOMAIN_HIERARCHY */ ++ ++#ifdef CONFIG_GENERIC_IRQ_DEBUGFS ++static struct dentry *domain_dir; ++ ++static void ++irq_domain_debug_show_one(struct seq_file *m, struct irq_domain *d, int ind) ++{ ++ seq_printf(m, "%*sname: %s\n", ind, "", d->name); ++ seq_printf(m, "%*ssize: %u\n", ind + 1, "", ++ d->revmap_size + d->revmap_direct_max_irq); ++ seq_printf(m, "%*smapped: %u\n", ind + 1, "", d->mapcount); ++ seq_printf(m, "%*sflags: 0x%08x\n", ind +1 , "", d->flags); ++#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY ++ if (!d->parent) ++ return; ++ seq_printf(m, "%*sparent: %s\n", ind + 1, "", d->parent->name); ++ irq_domain_debug_show_one(m, d->parent, ind + 4); ++#endif ++} ++ ++static int irq_domain_debug_show(struct seq_file *m, void *p) ++{ ++ struct irq_domain *d = m->private; ++ ++ /* Default domain? Might be NULL */ ++ if (!d) { ++ if (!irq_default_domain) ++ return 0; ++ d = irq_default_domain; ++ } ++ irq_domain_debug_show_one(m, d, 0); ++ return 0; ++} ++ ++static int irq_domain_debug_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, irq_domain_debug_show, inode->i_private); ++} ++ ++static const struct file_operations dfs_domain_ops = { ++ .open = irq_domain_debug_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++}; ++ ++static void debugfs_add_domain_dir(struct irq_domain *d) ++{ ++ if (!d->name || !domain_dir || d->debugfs_file) ++ return; ++ d->debugfs_file = debugfs_create_file(d->name, 0444, domain_dir, d, ++ &dfs_domain_ops); ++} ++ ++static void debugfs_remove_domain_dir(struct irq_domain *d) ++{ ++ if (d->debugfs_file) ++ debugfs_remove(d->debugfs_file); ++} ++ ++void __init irq_domain_debugfs_init(struct dentry *root) ++{ ++ struct irq_domain *d; ++ ++ domain_dir = debugfs_create_dir("domains", root); ++ if (!domain_dir) ++ return; ++ ++ debugfs_create_file("default", 0444, domain_dir, NULL, &dfs_domain_ops); ++ mutex_lock(&irq_domain_mutex); ++ list_for_each_entry(d, &irq_domain_list, link) ++ debugfs_add_domain_dir(d); ++ mutex_unlock(&irq_domain_mutex); ++} ++#endif +--- a/kernel/irq/manage.c ++++ b/kernel/irq/manage.c +@@ -1387,6 +1387,7 @@ __setup_irq(unsigned int irq, struct irq + wake_up_process(new->secondary->thread); + + register_irq_proc(irq, desc); ++ irq_add_debugfs_entry(irq, desc); + new->dir = NULL; + register_handler_proc(irq, new); + free_cpumask_var(mask); +--- a/kernel/irq/msi.c ++++ b/kernel/irq/msi.c +@@ -310,7 +310,7 @@ int msi_domain_populate_irqs(struct irq_ + + ops->set_desc(arg, desc); + /* Assumes the domain mutex is held! */ +- ret = irq_domain_alloc_irqs_recursive(domain, virq, 1, arg); ++ ret = irq_domain_alloc_irqs_hierarchy(domain, virq, 1, arg); + if (ret) + break; + +--- a/net/bridge/br.c ++++ b/net/bridge/br.c +@@ -138,14 +138,14 @@ static int br_switchdev_event(struct not + br = p->br; + + switch (event) { +- case SWITCHDEV_FDB_ADD: ++ case SWITCHDEV_FDB_ADD_TO_BRIDGE: + fdb_info = ptr; + err = br_fdb_external_learn_add(br, p, fdb_info->addr, + fdb_info->vid); + if (err) + err = notifier_from_errno(err); + break; +- case SWITCHDEV_FDB_DEL: ++ case SWITCHDEV_FDB_DEL_TO_BRIDGE: + fdb_info = ptr; + err = br_fdb_external_learn_del(br, p, fdb_info->addr, + fdb_info->vid); +--- a/net/bridge/br_fdb.c ++++ b/net/bridge/br_fdb.c +@@ -688,6 +688,8 @@ static void fdb_notify(struct net_bridge + struct sk_buff *skb; + int err = -ENOBUFS; + ++ br_switchdev_fdb_notify(fdb, type); ++ + skb = nlmsg_new(fdb_nlmsg_size(), GFP_ATOMIC); + if (skb == NULL) + goto errout; +--- a/net/bridge/br_private.h ++++ b/net/bridge/br_private.h +@@ -1060,6 +1060,8 @@ void nbp_switchdev_frame_mark(const stru + struct sk_buff *skb); + bool nbp_switchdev_allowed_egress(const struct net_bridge_port *p, + const struct sk_buff *skb); ++void br_switchdev_fdb_notify(const struct net_bridge_fdb_entry *fdb, ++ int type); + #else + static inline int nbp_switchdev_mark_set(struct net_bridge_port *p) + { +@@ -1076,6 +1078,11 @@ static inline bool nbp_switchdev_allowed + { + return true; + } ++ ++static inline void ++br_switchdev_fdb_notify(const struct net_bridge_fdb_entry *fdb, int type) ++{ ++} + #endif /* CONFIG_NET_SWITCHDEV */ + + #endif +--- a/net/bridge/br_switchdev.c ++++ b/net/bridge/br_switchdev.c +@@ -55,3 +55,36 @@ bool nbp_switchdev_allowed_egress(const + return !skb->offload_fwd_mark || + BR_INPUT_SKB_CB(skb)->offload_fwd_mark != p->offload_fwd_mark; + } ++ ++static void ++br_switchdev_fdb_call_notifiers(bool adding, const unsigned char *mac, ++ u16 vid, struct net_device *dev) ++{ ++ struct switchdev_notifier_fdb_info info; ++ unsigned long notifier_type; ++ ++ info.addr = mac; ++ info.vid = vid; ++ notifier_type = adding ? SWITCHDEV_FDB_ADD_TO_DEVICE : SWITCHDEV_FDB_DEL_TO_DEVICE; ++ call_switchdev_notifiers(notifier_type, dev, &info.info); ++} ++ ++void ++br_switchdev_fdb_notify(const struct net_bridge_fdb_entry *fdb, int type) ++{ ++ if (!fdb->added_by_user) ++ return; ++ ++ switch (type) { ++ case RTM_DELNEIGH: ++ br_switchdev_fdb_call_notifiers(false, fdb->addr.addr, ++ fdb->vlan_id, ++ fdb->dst->dev); ++ break; ++ case RTM_NEWNEIGH: ++ br_switchdev_fdb_call_notifiers(true, fdb->addr.addr, ++ fdb->vlan_id, ++ fdb->dst->dev); ++ break; ++ } ++} --- a/net/core/dev.c +++ b/net/core/dev.c -@@ -6630,9 +6630,18 @@ int dev_set_mtu(struct net_device *dev, +@@ -1968,6 +1968,23 @@ static void netif_setup_tc(struct net_de + } + } + ++int netdev_txq_to_tc(struct net_device *dev, unsigned int txq) ++{ ++ if (dev->num_tc) { ++ struct netdev_tc_txq *tc = &dev->tc_to_txq[0]; ++ int i; ++ ++ for (i = 0; i < TC_MAX_QUEUE; i++, tc++) { ++ if ((txq - tc->offset) < tc->count) ++ return i; ++ } ++ ++ return -1; ++ } ++ ++ return 0; ++} ++ + #ifdef CONFIG_XPS + static DEFINE_MUTEX(xps_map_mutex); + #define xmap_dereference(P) \ +@@ -6630,9 +6647,18 @@ int dev_set_mtu(struct net_device *dev, if (new_mtu == dev->mtu) return 0; @@ -442,6 +1318,76 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> if (!netif_device_present(dev)) return -ENODEV; +--- a/net/core/net-sysfs.c ++++ b/net/core/net-sysfs.c +@@ -1021,7 +1021,6 @@ static ssize_t show_trans_timeout(struct + return sprintf(buf, "%lu", trans_timeout); + } + +-#ifdef CONFIG_XPS + static unsigned int get_netdev_queue_index(struct netdev_queue *queue) + { + struct net_device *dev = queue->dev; +@@ -1033,6 +1032,21 @@ static unsigned int get_netdev_queue_ind + return i; + } + ++static ssize_t show_traffic_class(struct netdev_queue *queue, ++ struct netdev_queue_attribute *attribute, ++ char *buf) ++{ ++ struct net_device *dev = queue->dev; ++ int index = get_netdev_queue_index(queue); ++ int tc = netdev_txq_to_tc(dev, index); ++ ++ if (tc < 0) ++ return -EINVAL; ++ ++ return sprintf(buf, "%u\n", tc); ++} ++ ++#ifdef CONFIG_XPS + static ssize_t show_tx_maxrate(struct netdev_queue *queue, + struct netdev_queue_attribute *attribute, + char *buf) +@@ -1075,6 +1089,9 @@ static struct netdev_queue_attribute que + static struct netdev_queue_attribute queue_trans_timeout = + __ATTR(tx_timeout, S_IRUGO, show_trans_timeout, NULL); + ++static struct netdev_queue_attribute queue_traffic_class = ++ __ATTR(traffic_class, S_IRUGO, show_traffic_class, NULL); ++ + #ifdef CONFIG_BQL + /* + * Byte queue limits sysfs structures and functions. +@@ -1260,6 +1277,7 @@ static struct netdev_queue_attribute xps + + static struct attribute *netdev_queue_default_attrs[] = { + &queue_trans_timeout.attr, ++ &queue_traffic_class.attr, + #ifdef CONFIG_XPS + &xps_cpus_attribute.attr, + &queue_tx_maxrate.attr, +--- a/net/core/rtnetlink.c ++++ b/net/core/rtnetlink.c +@@ -3690,7 +3690,7 @@ static int rtnl_get_offload_stats(struct + if (!size) + continue; + +- if (!dev->netdev_ops->ndo_has_offload_stats(attr_id)) ++ if (!dev->netdev_ops->ndo_has_offload_stats(dev, attr_id)) + continue; + + attr = nla_reserve_64bit(skb, attr_id, size, +@@ -3731,7 +3731,7 @@ static int rtnl_get_offload_stats_size(c + + for (attr_id = IFLA_OFFLOAD_XSTATS_FIRST; + attr_id <= IFLA_OFFLOAD_XSTATS_MAX; attr_id++) { +- if (!dev->netdev_ops->ndo_has_offload_stats(attr_id)) ++ if (!dev->netdev_ops->ndo_has_offload_stats(dev, attr_id)) + continue; + size = rtnl_get_offload_stats_attr_size(attr_id); + nla_size += nla_total_size_64bit(size); --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -842,6 +842,32 @@ void napi_consume_skb(struct sk_buff *sk |