kernel: bump 4.9 to 4.9.146
[openwrt/openwrt.git] / target / linux / layerscape / patches-4.9 / 202-core-linux-support-layerscape.patch
index 026fce7dc94019af34f31394537c9a34db6a7347..1e33604f6ad13ccb0ee572558267ff92cd56861d 100644 (file)
@@ -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,9 +535,18 @@ 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);
+@@ -908,6 +908,7 @@ void kfree_skb(struct sk_buff *skb);
  void kfree_skb_list(struct sk_buff *segs);
  void skb_tx_error(struct sk_buff *skb);
  void consume_skb(struct sk_buff *skb);
@@ -384,7 +554,7 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
  void  __kfree_skb(struct sk_buff *skb);
  extern struct kmem_cache *skbuff_head_cache;
  
-@@ -3057,6 +3058,7 @@ static inline void skb_free_datagram_loc
+@@ -3081,6 +3082,7 @@ static inline void skb_free_datagram_loc
  }
  int skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags);
  int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len);
@@ -409,9 +579,40 @@ 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
-@@ -35,6 +35,7 @@
+@@ -36,6 +36,7 @@
  #define ETH_DATA_LEN  1500            /* Max. octets in payload        */
  #define ETH_FRAME_LEN 1514            /* Max. octets in frame sans FCS */
  #define ETH_FCS_LEN   4               /* Octets in the FCS             */
@@ -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
+@@ -1391,6 +1391,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,
+@@ -1990,6 +1990,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)           \
+@@ -6656,9 +6673,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
+@@ -3709,7 +3709,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,
+@@ -3750,7 +3750,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
@@ -477,7 +1423,7 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
  /* Make sure a field is enclosed inside headers_start/headers_end section */
  #define CHECK_SKB_FIELD(field) \
        BUILD_BUG_ON(offsetof(struct sk_buff, field) <          \
-@@ -1074,7 +1100,7 @@ static void skb_headers_offset_update(st
+@@ -1075,7 +1101,7 @@ static void skb_headers_offset_update(st
        skb->inner_mac_header += off;
  }
  
@@ -486,7 +1432,7 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
  {
        __copy_skb_header(new, old);
  
-@@ -1082,6 +1108,7 @@ static void copy_skb_header(struct sk_bu
+@@ -1083,6 +1109,7 @@ static void copy_skb_header(struct sk_bu
        skb_shinfo(new)->gso_segs = skb_shinfo(old)->gso_segs;
        skb_shinfo(new)->gso_type = skb_shinfo(old)->gso_type;
  }