|
@@ -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 <[email protected]>
|
|
|
-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 <[email protected]>
|
|
|
Signed-off-by: Arnd Bergmann <[email protected]>
|
|
|
Signed-off-by: Yangbo Lu <[email protected]>
|
|
|
---
|
|
|
- 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 <[email protected]>
|
|
|
+ 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 <[email protected]>
|
|
|
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 <[email protected]>
|
|
|
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 <[email protected]>
|
|
|
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 <[email protected]>
|
|
|
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 <[email protected]>
|
|
|
+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 <[email protected]>
|
|
|
|
|
|
/*
|
|
|
* 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 <[email protected]>
|
|
|
++ *
|
|
|
++ * 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 <[email protected]>
|
|
|
|
|
|
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
|